Skip to content

Commit 3a55b19

Browse files
committed
[InstCombine] Optimised expressions in issue #97044
1 parent cf2f9db commit 3a55b19

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
@@ -3776,6 +3776,43 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
37763776
return replaceInstUsesWith(I, V);
37773777

37783778
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
3779+
3780+
// ((X & Y & ~Z) | (X & ~Y & Z) | (~X & ~Y &~Z) | (X & Y &Z)) -> ~((Y | Z) ^
3781+
// X)
3782+
{
3783+
Value *X, *Y, *Z;
3784+
Value *Term1, *Term2, *XAndYAndZ;
3785+
if (match(&I,
3786+
m_Or(m_Or(m_Value(Term1), m_Value(Term2)), m_Value(XAndYAndZ))) &&
3787+
match(XAndYAndZ, m_And(m_And(m_Value(X), m_Value(Y)), m_Value(Z)))) {
3788+
Value *YOrZ = Builder.CreateOr(Y, Z);
3789+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
3790+
return BinaryOperator::CreateNot(YOrZXorX);
3791+
}
3792+
}
3793+
3794+
// (Z & X) | ~((Y ^ X) | Z) -> ~((Y | Z) ^ X)
3795+
{
3796+
Value *X, *Y, *Z;
3797+
Value *ZAndX, *NotPattern;
3798+
3799+
if (match(&I, m_c_Or(m_Value(ZAndX), m_Value(NotPattern))) &&
3800+
match(ZAndX, m_c_And(m_Value(Z), m_Value(X)))) {
3801+
3802+
Value *YXorXOrZ;
3803+
if (match(NotPattern, m_Not(m_Value(YXorXOrZ)))) {
3804+
Value *YXorX;
3805+
if (match(YXorXOrZ, m_c_Or(m_Value(YXorX), m_Specific(Z))) &&
3806+
match(YXorX, m_c_Xor(m_Value(Y), m_Specific(X)))) {
3807+
3808+
Value *YOrZ = Builder.CreateOr(Y, Z);
3809+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
3810+
return BinaryOperator::CreateNot(YOrZXorX);
3811+
}
3812+
}
3813+
}
3814+
}
3815+
37793816
Type *Ty = I.getType();
37803817
if (Ty->isIntOrIntVectorTy(1)) {
37813818
if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
@@ -5182,6 +5219,25 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
51825219
}
51835220
}
51845221

5222+
// ((X & Y) | (~X & ~Y)) ^ (Z & (((X & Y) | (~X & ~Y)) ^ ((X & Y) | (X &
5223+
// ~Y)))) -> ~((Y | Z) ^ X)
5224+
if (match(Op1, m_AllOnes())) {
5225+
Value *X, *Y, *Z;
5226+
Value *XorWithY;
5227+
if (match(Op0, m_Xor(m_Value(XorWithY), m_Value(Y)))) {
5228+
Value *ZAndNotY;
5229+
if (match(XorWithY, m_Xor(m_Value(X), m_Value(ZAndNotY)))) {
5230+
Value *NotY;
5231+
if (match(ZAndNotY, m_And(m_Value(Z), m_Value(NotY))) &&
5232+
match(NotY, m_Not(m_Specific(Y)))) {
5233+
Value *YOrZ = Builder.CreateOr(Y, Z);
5234+
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
5235+
return BinaryOperator::CreateNot(YOrZXorX);
5236+
}
5237+
}
5238+
}
5239+
}
5240+
51855241
if (auto *LHS = dyn_cast<ICmpInst>(I.getOperand(0)))
51865242
if (auto *RHS = dyn_cast<ICmpInst>(I.getOperand(1)))
51875243
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)