Skip to content

Commit 7ab0a87

Browse files
authored
[InstCombine] Try to freely invert phi nodes (#80804)
This patch tries to invert phi nodes if all incoming values are either constants or nots.
1 parent b0c6fc8 commit 7ab0a87

File tree

2 files changed

+217
-2
lines changed

2 files changed

+217
-2
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,33 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
23602360
}
23612361
}
23622362

2363+
if (PHINode *PN = dyn_cast<PHINode>(V)) {
2364+
SmallVector<std::pair<Value *, BasicBlock *>, 8> IncomingValues;
2365+
for (Use &U : PN->operands()) {
2366+
BasicBlock *IncomingBlock = PN->getIncomingBlock(U);
2367+
Value *NewIncomingVal = getFreelyInvertedImpl(
2368+
U.get(), /*WillInvertAllUses=*/false,
2369+
/*Builder=*/nullptr, DoesConsume, MaxAnalysisRecursionDepth - 1);
2370+
if (NewIncomingVal == nullptr)
2371+
return nullptr;
2372+
// Make sure that we can safely erase the original PHI node.
2373+
if (NewIncomingVal == V)
2374+
return nullptr;
2375+
if (Builder != nullptr)
2376+
IncomingValues.emplace_back(NewIncomingVal, IncomingBlock);
2377+
}
2378+
if (Builder != nullptr) {
2379+
IRBuilderBase::InsertPointGuard Guard(*Builder);
2380+
Builder->SetInsertPoint(PN);
2381+
PHINode *NewPN =
2382+
Builder->CreatePHI(PN->getType(), PN->getNumIncomingValues());
2383+
for (auto [Val, Pred] : IncomingValues)
2384+
NewPN->addIncoming(Val, Pred);
2385+
return NewPN;
2386+
}
2387+
return NonNull;
2388+
}
2389+
23632390
return nullptr;
23642391
}
23652392

llvm/test/Transforms/InstCombine/free-inversion.ll

+190-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare i8 @llvm.umax.i8(i8, i8)
99
declare void @llvm.assume(i1)
1010

1111
declare void @use.i8(i8)
12+
declare void @use.i1(i1)
1213

1314
define i8 @xor_1(i8 %a, i1 %c, i8 %x, i8 %y) {
1415
; CHECK-LABEL: @xor_1(
@@ -544,11 +545,198 @@ define i8 @lshr_not_nneg(i8 %x, i8 %y) {
544545
define i8 @lshr_not_nneg2(i8 %x) {
545546
; CHECK-LABEL: @lshr_not_nneg2(
546547
; CHECK-NEXT: [[SHR:%.*]] = lshr i8 [[X:%.*]], 1
547-
; CHECK-NEXT: [[SHR_NOT1:%.*]] = or disjoint i8 [[SHR]], -128
548-
; CHECK-NEXT: ret i8 [[SHR_NOT1]]
548+
; CHECK-NEXT: [[SHR_NOT:%.*]] = or disjoint i8 [[SHR]], -128
549+
; CHECK-NEXT: ret i8 [[SHR_NOT]]
549550
;
550551
%x.not = xor i8 %x, -1
551552
%shr = lshr i8 %x.not, 1
552553
%shr.not = xor i8 %shr, -1
553554
ret i8 %shr.not
554555
}
556+
557+
define i1 @test_inv_free(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
558+
; CHECK-LABEL: @test_inv_free(
559+
; CHECK-NEXT: entry:
560+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
561+
; CHECK: b1:
562+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
563+
; CHECK: b2:
564+
; CHECK-NEXT: br label [[EXIT]]
565+
; CHECK: b3:
566+
; CHECK-NEXT: br label [[EXIT]]
567+
; CHECK: exit:
568+
; CHECK-NEXT: [[VAL_NOT:%.*]] = phi i1 [ false, [[B1]] ], [ true, [[B2]] ], [ [[C3:%.*]], [[B3]] ]
569+
; CHECK-NEXT: [[COND_NOT:%.*]] = and i1 [[VAL_NOT]], [[C4:%.*]]
570+
; CHECK-NEXT: br i1 [[COND_NOT]], label [[B5:%.*]], label [[B4:%.*]]
571+
; CHECK: b4:
572+
; CHECK-NEXT: ret i1 true
573+
; CHECK: b5:
574+
; CHECK-NEXT: ret i1 false
575+
;
576+
entry:
577+
br i1 %c1, label %b1, label %b2
578+
b1:
579+
br i1 %c2, label %exit, label %b3
580+
b2:
581+
br label %exit
582+
b3:
583+
%invc3 = xor i1 %c3, true
584+
br label %exit
585+
exit:
586+
%val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ]
587+
%inv = xor i1 %c4, true
588+
%cond = or i1 %val, %inv
589+
br i1 %cond, label %b4, label %b5
590+
b4:
591+
ret i1 true
592+
b5:
593+
ret i1 false
594+
}
595+
596+
define i32 @test_inv_free_i32(i1 %c1, i1 %c2, i32 %c3, i32 %c4) {
597+
; CHECK-LABEL: @test_inv_free_i32(
598+
; CHECK-NEXT: entry:
599+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
600+
; CHECK: b1:
601+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
602+
; CHECK: b2:
603+
; CHECK-NEXT: br label [[EXIT]]
604+
; CHECK: b3:
605+
; CHECK-NEXT: br label [[EXIT]]
606+
; CHECK: exit:
607+
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[B1]] ], [ -1, [[B2]] ], [ [[C3:%.*]], [[B3]] ]
608+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[TMP0]], [[C4:%.*]]
609+
; CHECK-NEXT: ret i32 [[COND]]
610+
;
611+
entry:
612+
br i1 %c1, label %b1, label %b2
613+
b1:
614+
br i1 %c2, label %exit, label %b3
615+
b2:
616+
br label %exit
617+
b3:
618+
%invc3 = xor i32 %c3, -1
619+
br label %exit
620+
exit:
621+
%val = phi i32 [ -1, %b1 ], [ 0, %b2 ], [ %invc3, %b3 ]
622+
%inv = xor i32 %c4, -1
623+
%cond = xor i32 %val, %inv
624+
ret i32 %cond
625+
}
626+
627+
; Negative tests
628+
629+
define i1 @test_inv_free_multiuse(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
630+
; CHECK-LABEL: @test_inv_free_multiuse(
631+
; CHECK-NEXT: entry:
632+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
633+
; CHECK: b1:
634+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
635+
; CHECK: b2:
636+
; CHECK-NEXT: br label [[EXIT]]
637+
; CHECK: b3:
638+
; CHECK-NEXT: [[INVC3:%.*]] = xor i1 [[C3:%.*]], true
639+
; CHECK-NEXT: br label [[EXIT]]
640+
; CHECK: exit:
641+
; CHECK-NEXT: [[VAL:%.*]] = phi i1 [ true, [[B1]] ], [ false, [[B2]] ], [ [[INVC3]], [[B3]] ]
642+
; CHECK-NEXT: call void @use.i1(i1 [[VAL]])
643+
; CHECK-NEXT: [[INV:%.*]] = xor i1 [[C4:%.*]], true
644+
; CHECK-NEXT: [[COND:%.*]] = or i1 [[VAL]], [[INV]]
645+
; CHECK-NEXT: br i1 [[COND]], label [[B4:%.*]], label [[B5:%.*]]
646+
; CHECK: b4:
647+
; CHECK-NEXT: ret i1 true
648+
; CHECK: b5:
649+
; CHECK-NEXT: ret i1 false
650+
;
651+
entry:
652+
br i1 %c1, label %b1, label %b2
653+
b1:
654+
br i1 %c2, label %exit, label %b3
655+
b2:
656+
br label %exit
657+
b3:
658+
%invc3 = xor i1 %c3, true
659+
br label %exit
660+
exit:
661+
%val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ]
662+
call void @use.i1(i1 %val)
663+
%inv = xor i1 %c4, true
664+
%cond = or i1 %val, %inv
665+
br i1 %cond, label %b4, label %b5
666+
b4:
667+
ret i1 true
668+
b5:
669+
ret i1 false
670+
}
671+
672+
define i32 @test_inv_free_i32_newinst(i1 %c1, i1 %c2, i32 %c3, i32 %c4) {
673+
; CHECK-LABEL: @test_inv_free_i32_newinst(
674+
; CHECK-NEXT: entry:
675+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
676+
; CHECK: b1:
677+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
678+
; CHECK: b2:
679+
; CHECK-NEXT: br label [[EXIT]]
680+
; CHECK: b3:
681+
; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 -8, [[C3:%.*]]
682+
; CHECK-NEXT: br label [[EXIT]]
683+
; CHECK: exit:
684+
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ -1, [[B1]] ], [ 0, [[B2]] ], [ [[ASHR]], [[B3]] ]
685+
; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[VAL]], [[C4:%.*]]
686+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[TMP0]], -1
687+
; CHECK-NEXT: ret i32 [[COND]]
688+
;
689+
entry:
690+
br i1 %c1, label %b1, label %b2
691+
b1:
692+
br i1 %c2, label %exit, label %b3
693+
b2:
694+
br label %exit
695+
b3:
696+
%ashr = ashr i32 -8, %c3
697+
br label %exit
698+
exit:
699+
%val = phi i32 [ -1, %b1 ], [ 0, %b2 ], [ %ashr, %b3 ]
700+
%inv = xor i32 %c4, -1
701+
%cond = xor i32 %val, %inv
702+
ret i32 %cond
703+
}
704+
705+
define i1 @test_inv_free_loop(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
706+
; CHECK-LABEL: @test_inv_free_loop(
707+
; CHECK-NEXT: entry:
708+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
709+
; CHECK: b1:
710+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
711+
; CHECK: b2:
712+
; CHECK-NEXT: br label [[EXIT]]
713+
; CHECK: b3:
714+
; CHECK-NEXT: [[INVC3:%.*]] = xor i1 [[C3:%.*]], true
715+
; CHECK-NEXT: br label [[EXIT]]
716+
; CHECK: exit:
717+
; CHECK-NEXT: [[VAL:%.*]] = phi i1 [ true, [[B1]] ], [ false, [[B2]] ], [ [[INVC3]], [[B3]] ], [ [[NOT:%.*]], [[EXIT]] ]
718+
; CHECK-NEXT: [[INV:%.*]] = xor i1 [[C4:%.*]], true
719+
; CHECK-NEXT: [[COND:%.*]] = or i1 [[VAL]], [[INV]]
720+
; CHECK-NEXT: [[NOT]] = xor i1 [[VAL]], true
721+
; CHECK-NEXT: br i1 [[COND]], label [[EXIT]], label [[B4:%.*]]
722+
; CHECK: b4:
723+
; CHECK-NEXT: ret i1 true
724+
;
725+
entry:
726+
br i1 %c1, label %b1, label %b2
727+
b1:
728+
br i1 %c2, label %exit, label %b3
729+
b2:
730+
br label %exit
731+
b3:
732+
%invc3 = xor i1 %c3, true
733+
br label %exit
734+
exit:
735+
%val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ], [ %not, %exit ]
736+
%inv = xor i1 %c4, true
737+
%cond = or i1 %val, %inv
738+
%not = xor i1 %val, true
739+
br i1 %cond, label %exit, label %b4
740+
b4:
741+
ret i1 true
742+
}

0 commit comments

Comments
 (0)