Skip to content

Commit 00d0e75

Browse files
committed
[InstCombine] Support and/or in getFreelyInvertedImpl using DeMorgan's Law
1 parent c697d80 commit 00d0e75

File tree

4 files changed

+82
-53
lines changed

4 files changed

+82
-53
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,6 +2596,45 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
25962596
return nullptr;
25972597
}
25982598

2599+
// De Morgan's Laws:
2600+
// (~(A | B)) -> (~A & ~B)
2601+
// (~(A & B)) -> (~A | ~B)
2602+
auto TryInvertAndOrUsingDeMorgan = [&](Instruction::BinaryOps Opcode,
2603+
bool IsLogical, Value *A,
2604+
Value *B) -> Value * {
2605+
bool LocalDoesConsume = DoesConsume;
2606+
if (!getFreelyInvertedImpl(B, B->hasOneUse(), /*Builder=*/nullptr,
2607+
LocalDoesConsume, Depth))
2608+
return nullptr;
2609+
if (auto *NotA = getFreelyInvertedImpl(A, A->hasOneUse(), Builder,
2610+
LocalDoesConsume, Depth)) {
2611+
auto *NotB = getFreelyInvertedImpl(B, B->hasOneUse(), Builder,
2612+
LocalDoesConsume, Depth);
2613+
DoesConsume = LocalDoesConsume;
2614+
if (IsLogical)
2615+
return Builder ? Builder->CreateLogicalOp(Opcode, NotA, NotB) : NonNull;
2616+
return Builder ? Builder->CreateBinOp(Opcode, NotA, NotB) : NonNull;
2617+
}
2618+
2619+
return nullptr;
2620+
};
2621+
2622+
if (match(V, m_Or(m_Value(A), m_Value(B))))
2623+
return TryInvertAndOrUsingDeMorgan(Instruction::And, /*IsLogical=*/false, A,
2624+
B);
2625+
2626+
if (match(V, m_And(m_Value(A), m_Value(B))))
2627+
return TryInvertAndOrUsingDeMorgan(Instruction::Or, /*IsLogical=*/false, A,
2628+
B);
2629+
2630+
if (match(V, m_LogicalOr(m_Value(A), m_Value(B))))
2631+
return TryInvertAndOrUsingDeMorgan(Instruction::And, /*IsLogical=*/true, A,
2632+
B);
2633+
2634+
if (match(V, m_LogicalAnd(m_Value(A), m_Value(B))))
2635+
return TryInvertAndOrUsingDeMorgan(Instruction::Or, /*IsLogical=*/true, A,
2636+
B);
2637+
25992638
return nullptr;
26002639
}
26012640

llvm/test/Transforms/InstCombine/icmp-and-lowbit-mask.ll

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,11 @@ define i1 @src_is_mask_shl_lshr(i8 %x_in, i8 %y, i1 %cond) {
226226

227227
define i1 @src_is_mask_shl_lshr_fail_not_allones(i8 %x_in, i8 %y, i1 %cond) {
228228
; CHECK-LABEL: @src_is_mask_shl_lshr_fail_not_allones(
229-
; CHECK-NEXT: [[X:%.*]] = xor i8 [[X_IN:%.*]], 123
230229
; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 -1, [[Y:%.*]]
231230
; CHECK-NEXT: [[MASK:%.*]] = and i8 [[TMP1]], -2
232-
; CHECK-NEXT: [[NOTMASK:%.*]] = xor i8 [[MASK]], -1
233-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[NOTMASK]]
234-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND]], 0
231+
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[X_IN:%.*]], -124
232+
; CHECK-NEXT: [[TMP3:%.*]] = or i8 [[TMP2]], [[MASK]]
233+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[TMP3]], -1
235234
; CHECK-NEXT: ret i1 [[R]]
236235
;
237236
%x = xor i8 %x_in, 123
@@ -572,11 +571,10 @@ define i1 @src_is_notmask_neg_p2(i8 %x_in, i8 %y) {
572571

573572
define i1 @src_is_notmask_neg_p2_fail_not_invertable(i8 %x_in, i8 %y) {
574573
; CHECK-LABEL: @src_is_notmask_neg_p2_fail_not_invertable(
575-
; CHECK-NEXT: [[X:%.*]] = xor i8 [[X_IN:%.*]], 123
576-
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], -1
577-
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[Y]], -1
578-
; CHECK-NEXT: [[TMP3:%.*]] = and i8 [[TMP1]], [[TMP2]]
579-
; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[X]], [[TMP3]]
574+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X_IN:%.*]], -124
575+
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 0, [[Y:%.*]]
576+
; CHECK-NEXT: [[TMP3:%.*]] = or i8 [[TMP2]], [[Y]]
577+
; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[TMP1]], [[TMP3]]
580578
; CHECK-NEXT: ret i1 [[R]]
581579
;
582580
%x = xor i8 %x_in, 123

llvm/test/Transforms/InstCombine/not.ll

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -864,11 +864,10 @@ define i32 @test_zext(i32 %a, i32 %b){
864864
define void @test_invert_demorgan_or(i32 %a, i32 %b, i1 %cond) {
865865
; CHECK-LABEL: @test_invert_demorgan_or(
866866
; CHECK-NEXT: entry:
867-
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[B1:%.*]], 0
868867
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 0
869-
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP3]], [[CMP2]]
870-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[COND:%.*]], true
871-
; CHECK-NEXT: [[MERGE:%.*]] = or i1 [[OR]], [[NOT]]
868+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[B1:%.*]], 0
869+
; CHECK-NEXT: [[OR_NOT1:%.*]] = and i1 [[CMP2]], [[CMP3]]
870+
; CHECK-NEXT: [[MERGE:%.*]] = and i1 [[OR_NOT1]], [[COND:%.*]]
872871
; CHECK-NEXT: br i1 [[MERGE]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
873872
; CHECK: if.then:
874873
; CHECK-NEXT: call void @f1()
@@ -894,12 +893,11 @@ if.else:
894893

895894
define i1 @test_invert_demorgan_or2(i64 %a, i64 %b, i64 %c) {
896895
; CHECK-LABEL: @test_invert_demorgan_or2(
897-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[A:%.*]], 23
898-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i64 [[B:%.*]], 59
899-
; CHECK-NEXT: [[OR1:%.*]] = or i1 [[CMP1]], [[CMP2]]
900-
; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i64 [[C:%.*]], 59
901-
; CHECK-NEXT: [[OR2:%.*]] = or i1 [[OR1]], [[CMP3]]
902-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[OR2]], true
896+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[A:%.*]], 24
897+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[B:%.*]], 60
898+
; CHECK-NEXT: [[OR1_NOT1:%.*]] = and i1 [[CMP1]], [[CMP2]]
899+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i64 [[C:%.*]], 60
900+
; CHECK-NEXT: [[NOT:%.*]] = and i1 [[OR1_NOT1]], [[CMP3]]
903901
; CHECK-NEXT: ret i1 [[NOT]]
904902
;
905903
%cmp1 = icmp ugt i64 %a, 23
@@ -913,17 +911,16 @@ define i1 @test_invert_demorgan_or2(i64 %a, i64 %b, i64 %c) {
913911

914912
define i1 @test_invert_demorgan_or3(i32 %a, i32 %b) {
915913
; CHECK-LABEL: @test_invert_demorgan_or3(
916-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 178206
917-
; CHECK-NEXT: [[V1:%.*]] = add i32 [[B:%.*]], -195102
918-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[V1]], 1506
919-
; CHECK-NEXT: [[V2:%.*]] = add i32 [[B]], -201547
920-
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[V2]], 716213
921-
; CHECK-NEXT: [[V3:%.*]] = add i32 [[B]], -918000
922-
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[V3]], 196112
923-
; CHECK-NEXT: [[OR1:%.*]] = or i1 [[CMP1]], [[CMP2]]
924-
; CHECK-NEXT: [[OR2:%.*]] = or i1 [[OR1]], [[CMP3]]
925-
; CHECK-NEXT: [[OR3:%.*]] = or i1 [[OR2]], [[CMP4]]
926-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[OR3]], true
914+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 178206
915+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B:%.*]], -196608
916+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[TMP1]], -1506
917+
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[B]], -917760
918+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[TMP2]], -716213
919+
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[B]], -1114112
920+
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[TMP3]], -196112
921+
; CHECK-NEXT: [[OR1_NOT2:%.*]] = and i1 [[CMP1]], [[CMP2]]
922+
; CHECK-NEXT: [[OR2_NOT1:%.*]] = and i1 [[OR1_NOT2]], [[CMP3]]
923+
; CHECK-NEXT: [[NOT:%.*]] = and i1 [[OR2_NOT1]], [[CMP4]]
927924
; CHECK-NEXT: ret i1 [[NOT]]
928925
;
929926
%cmp1 = icmp eq i32 %a, 178206
@@ -942,12 +939,11 @@ define i1 @test_invert_demorgan_or3(i32 %a, i32 %b) {
942939

943940
define i1 @test_invert_demorgan_logical_or(i64 %x, i64 %y) {
944941
; CHECK-LABEL: @test_invert_demorgan_logical_or(
945-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[X:%.*]], 27
946-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[Y:%.*]], 0
947-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
948-
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i64 [[X]], 0
949-
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP3]], [[SEL]]
950-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[OR]], true
942+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[X:%.*]], 27
943+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i64 [[Y:%.*]], 0
944+
; CHECK-NEXT: [[SEL_NOT1:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
945+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i64 [[X]], 0
946+
; CHECK-NEXT: [[NOT:%.*]] = and i1 [[CMP3]], [[SEL_NOT1]]
951947
; CHECK-NEXT: ret i1 [[NOT]]
952948
;
953949
%cmp1 = icmp eq i64 %x, 27
@@ -962,11 +958,10 @@ define i1 @test_invert_demorgan_logical_or(i64 %x, i64 %y) {
962958
define i1 @test_invert_demorgan_and(i32 %a, i32 %b, i1 %cond) {
963959
; CHECK-LABEL: @test_invert_demorgan_and(
964960
; CHECK-NEXT: entry:
965-
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[B1:%.*]], 0
966961
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 0
967-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP3]], [[CMP2]]
968-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[COND:%.*]], true
969-
; CHECK-NEXT: [[MERGE:%.*]] = and i1 [[AND]], [[NOT]]
962+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[B1:%.*]], 0
963+
; CHECK-NEXT: [[AND_NOT1:%.*]] = or i1 [[CMP2]], [[CMP3]]
964+
; CHECK-NEXT: [[MERGE:%.*]] = or i1 [[AND_NOT1]], [[COND:%.*]]
970965
; CHECK-NEXT: br i1 [[MERGE]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
971966
; CHECK: if.then:
972967
; CHECK-NEXT: call void @f1()
@@ -992,9 +987,8 @@ if.else:
992987

993988
define i64 @test_invert_demorgan_and2(i64 %x) {
994989
; CHECK-LABEL: @test_invert_demorgan_and2(
995-
; CHECK-NEXT: [[ADD:%.*]] = add i64 [[X:%.*]], 9223372036854775807
996-
; CHECK-NEXT: [[AND:%.*]] = and i64 [[ADD]], 9223372036854775807
997-
; CHECK-NEXT: [[SUB:%.*]] = xor i64 [[AND]], -1
990+
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 0, [[X:%.*]]
991+
; CHECK-NEXT: [[SUB:%.*]] = or i64 [[TMP1]], -9223372036854775808
998992
; CHECK-NEXT: ret i64 [[SUB]]
999993
;
1000994
%add = add i64 %x, 9223372036854775807
@@ -1005,10 +999,9 @@ define i64 @test_invert_demorgan_and2(i64 %x) {
1005999

10061000
define i1 @test_invert_demorgan_and3(i32 %a, i32 %b) {
10071001
; CHECK-LABEL: @test_invert_demorgan_and3(
1008-
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A:%.*]], -1
1009-
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NOT]], [[B:%.*]]
1002+
; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[A:%.*]], [[B:%.*]]
10101003
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 4095
1011-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
1004+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 4095
10121005
; CHECK-NEXT: ret i1 [[CMP]]
10131006
;
10141007
%not = xor i32 %a, -1
@@ -1020,12 +1013,11 @@ define i1 @test_invert_demorgan_and3(i32 %a, i32 %b) {
10201013

10211014
define i1 @test_invert_demorgan_logical_and(i64 %x, i64 %y) {
10221015
; CHECK-LABEL: @test_invert_demorgan_logical_and(
1023-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[X:%.*]], 27
1024-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[Y:%.*]], 0
1025-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
1026-
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i64 [[X]], 0
1027-
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP3]], [[SEL]]
1028-
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[OR]], true
1016+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[X:%.*]], 27
1017+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i64 [[Y:%.*]], 0
1018+
; CHECK-NEXT: [[SEL_NOT1:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
1019+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i64 [[X]], 0
1020+
; CHECK-NEXT: [[NOT:%.*]] = and i1 [[CMP3]], [[SEL_NOT1]]
10291021
; CHECK-NEXT: ret i1 [[NOT]]
10301022
;
10311023
%cmp1 = icmp eq i64 %x, 27

llvm/test/Transforms/InstCombine/pr63791.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ define void @y() {
1515
; CHECK-NEXT: store i1 true, ptr poison, align 1
1616
; CHECK-NEXT: br i1 poison, label [[FOR_COND_I]], label [[FOR_COND5_PREHEADER_I]]
1717
; CHECK: for.cond5.preheader.i:
18-
; CHECK-NEXT: br i1 false, label [[FOR_INC19_I:%.*]], label [[FOR_COND1_LOOPEXIT_I:%.*]]
18+
; CHECK-NEXT: br i1 true, label [[FOR_COND1_LOOPEXIT_I:%.*]], label [[FOR_INC19_I:%.*]]
1919
; CHECK: for.inc19.i:
2020
; CHECK-NEXT: br i1 poison, label [[FOR_INC19_I]], label [[FOR_COND1_LOOPEXIT_I]]
2121
;

0 commit comments

Comments
 (0)