Skip to content

Commit 60f76f9

Browse files
committed
[InstCombine] Optimised expressions in issue #97044
1 parent 0db68ca commit 60f76f9

File tree

2 files changed

+66
-23
lines changed

2 files changed

+66
-23
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3780,6 +3780,43 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
37803780
return replaceInstUsesWith(I, V);
37813781

37823782
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
3783+
3784+
// ((X & Y & ~Z) | (X & ~Y & Z) | (~X & ~Y &~Z) | (X & Y &Z)) -> ~((Y | Z) ^
3785+
// X)
3786+
{
3787+
Value *X, *Y, *Z;
3788+
Value *Term1, *Term2, *XAndYAndZ;
3789+
if (match(&I,
3790+
m_Or(m_Or(m_Value(Term1), m_Value(Term2)), m_Value(XAndYAndZ))) &&
3791+
match(XAndYAndZ, m_And(m_And(m_Value(X), m_Value(Y)), m_Value(Z)))) {
3792+
Value *YOrZ = Builder.CreateOr(Y, Z);
3793+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
3794+
return BinaryOperator::CreateNot(YOrZXorX);
3795+
}
3796+
}
3797+
3798+
// (Z & X) | ~((Y ^ X) | Z) -> ~((Y | Z) ^ X)
3799+
{
3800+
Value *X, *Y, *Z;
3801+
Value *ZAndX, *NotPattern;
3802+
3803+
if (match(&I, m_c_Or(m_Value(ZAndX), m_Value(NotPattern))) &&
3804+
match(ZAndX, m_c_And(m_Value(Z), m_Value(X)))) {
3805+
3806+
Value *YXorXOrZ;
3807+
if (match(NotPattern, m_Not(m_Value(YXorXOrZ)))) {
3808+
Value *YXorX;
3809+
if (match(YXorXOrZ, m_c_Or(m_Value(YXorX), m_Specific(Z))) &&
3810+
match(YXorX, m_c_Xor(m_Value(Y), m_Specific(X)))) {
3811+
3812+
Value *YOrZ = Builder.CreateOr(Y, Z);
3813+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
3814+
return BinaryOperator::CreateNot(YOrZXorX);
3815+
}
3816+
}
3817+
}
3818+
}
3819+
37833820
Type *Ty = I.getType();
37843821
if (Ty->isIntOrIntVectorTy(1)) {
37853822
if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
@@ -5191,6 +5228,25 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
51915228
}
51925229
}
51935230

5231+
// ((X & Y) | (~X & ~Y)) ^ (Z & (((X & Y) | (~X & ~Y)) ^ ((X & Y) | (X &
5232+
// ~Y)))) -> ~((Y | Z) ^ X)
5233+
if (match(Op1, m_AllOnes())) {
5234+
Value *X, *Y, *Z;
5235+
Value *XorWithY;
5236+
if (match(Op0, m_Xor(m_Value(XorWithY), m_Value(Y)))) {
5237+
Value *ZAndNotY;
5238+
if (match(XorWithY, m_Xor(m_Value(X), m_Value(ZAndNotY)))) {
5239+
Value *NotY;
5240+
if (match(ZAndNotY, m_And(m_Value(Z), m_Value(NotY))) &&
5241+
match(NotY, m_Not(m_Specific(Y)))) {
5242+
Value *YOrZ = Builder.CreateOr(Y, Z);
5243+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
5244+
return BinaryOperator::CreateNot(YOrZXorX);
5245+
}
5246+
}
5247+
}
5248+
}
5249+
51945250
if (auto *LHS = dyn_cast<ICmpInst>(I.getOperand(0)))
51955251
if (auto *RHS = dyn_cast<ICmpInst>(I.getOperand(1)))
51965252
if (Value *V = foldXorOfICmps(LHS, RHS, I))

llvm/test/Transforms/InstCombine/pr97044.ll

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,9 @@
33
; Tests for GitHub issue #97044 - Boolean expression canonicalization
44
define i32 @test0_4way_or(i32 %x, i32 %y, i32 %z) {
55
; CHECK-LABEL: @test0_4way_or(
6-
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[Z:%.*]], -1
7-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[NOT]]
8-
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[AND]], [[X:%.*]]
9-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[Y]], -1
10-
; CHECK-NEXT: [[AND3:%.*]] = and i32 [[X]], [[NOT2]]
11-
; CHECK-NEXT: [[AND4:%.*]] = and i32 [[AND3]], [[Z]]
12-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND1]], [[AND4]]
13-
; CHECK-NEXT: [[AND7_DEMORGAN:%.*]] = or i32 [[X]], [[Y]]
14-
; CHECK-NEXT: [[AND9_DEMORGAN:%.*]] = or i32 [[AND7_DEMORGAN]], [[Z]]
15-
; CHECK-NEXT: [[AND9:%.*]] = xor i32 [[AND9_DEMORGAN]], -1
16-
; CHECK-NEXT: [[OR10:%.*]] = or i32 [[OR]], [[AND9]]
17-
; CHECK-NEXT: [[AND11:%.*]] = and i32 [[X]], [[Y]]
18-
; CHECK-NEXT: [[AND12:%.*]] = and i32 [[AND11]], [[Z]]
19-
; CHECK-NEXT: [[OR13:%.*]] = or i32 [[OR10]], [[AND12]]
6+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], [[Z:%.*]]
7+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
8+
; CHECK-NEXT: [[OR13:%.*]] = xor i32 [[TMP2]], -1
209
; CHECK-NEXT: ret i32 [[OR13]]
2110
;
2211
%not = xor i32 %z, -1
@@ -39,11 +28,9 @@ define i32 @test0_4way_or(i32 %x, i32 %y, i32 %z) {
3928
}
4029
define i32 @test1_xor_pattern(i32 %x, i32 %y, i32 %z) {
4130
; CHECK-LABEL: @test1_xor_pattern(
42-
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
43-
; CHECK-NEXT: [[AND4_DEMORGAN:%.*]] = or i32 [[TMP1]], [[Z:%.*]]
44-
; CHECK-NEXT: [[AND8:%.*]] = and i32 [[Z]], [[X]]
45-
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[AND4_DEMORGAN]], -1
46-
; CHECK-NEXT: [[XOR:%.*]] = or i32 [[AND8]], [[TMP2]]
31+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], [[Z:%.*]]
32+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
33+
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[TMP2]], -1
4734
; CHECK-NEXT: ret i32 [[XOR]]
4835
;
4936
%not = xor i32 %z, -1
@@ -62,10 +49,10 @@ define i32 @test1_xor_pattern(i32 %x, i32 %y, i32 %z) {
6249
}
6350
define i32 @test2_nested_xor(i32 %x, i32 %y, i32 %z) {
6451
; CHECK-LABEL: @test2_nested_xor(
65-
; CHECK-NEXT: [[NOT7:%.*]] = xor i32 [[Y:%.*]], -1
66-
; CHECK-NEXT: [[AND8:%.*]] = and i32 [[Z:%.*]], [[NOT7]]
67-
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[AND8]]
68-
; CHECK-NEXT: ret i32 [[TMP1]]
52+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], [[Z:%.*]]
53+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
54+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], [[Y]]
55+
; CHECK-NEXT: ret i32 [[TMP3]]
6956
;
7057
%and = and i32 %x, %y
7158
%not = xor i32 %x, -1

0 commit comments

Comments
 (0)