Skip to content

Commit eb53480

Browse files
committed
[InstCombine][Tests] Check Tests added
1 parent b1589c7 commit eb53480

File tree

2 files changed

+110
-22
lines changed

2 files changed

+110
-22
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,45 +2139,37 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
21392139
X);
21402140
}
21412141

2142-
// Issue #97044: Boolean instruction optimisations
2143-
// test1: ((~Z) & ((X&Y) | (~X&~Y))) ^ (Z & ((X&Y) | (X&~Y))) -> ~((Y | Z) ^ X)
2142+
// ((~Z) & ((X & Y) | (~X & ~Y))) ^ (Z & ((X & Y) | (X & ~Y))) -> ~((Y | Z) ^
2143+
// X)
21442144
{
21452145
{
21462146
Value *X, *Y, *Z;
21472147
Value *SomethingOrZ, *ZAndX;
2148-
2148+
21492149
if (match(&I, m_c_Xor(m_Value(SomethingOrZ), m_Value(ZAndX))) &&
21502150
match(ZAndX, m_And(m_Value(Z), m_Value(X))) &&
21512151
match(SomethingOrZ, m_Or(m_Value(), m_Specific(Z)))) {
2152-
2153-
// Extract Y from the "something" part
21542152
Value *Something;
21552153
if (match(SomethingOrZ, m_Or(m_Value(Something), m_Specific(Z))) &&
21562154
match(Something, m_Xor(m_Specific(X), m_Value(Y)))) {
2157-
2158-
llvm::errs() << "DEBUG: Found test1 actual pattern! X=" << *X << ", Y=" << *Y << ", Z=" << *Z << "\n";
2159-
21602155
Value *YOrZ = Builder.CreateOr(Y, Z);
21612156
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
21622157
return BinaryOperator::CreateNot(YOrZXorX);
21632158
}
21642159
}
21652160
}
2166-
2167-
// test2: ((X&Y) | (~X&~Y)) ^ (Z & (((X&Y) | (~X&~Y)) ^ ((X&Y) | (X&~Y)))) -> ~((Y | Z) ^ X)
2168-
if (match(Op1, m_AllOnes())) {
2169-
// here we match: ~((x ^ (z & ~y)) ^ y)
2161+
2162+
// ((X & Y) | (~X & ~Y)) ^ (Z & (((X & Y) | (~X & ~Y)) ^ ((X & Y) | (X &
2163+
// ~Y)))) -> ~((Y | Z) ^ X)
2164+
if (match(Op1, m_AllOnes())) {
21702165
Value *X, *Y, *Z;
21712166
Value *XorWithY;
2172-
if (match(Op0, m_Xor(m_Value(XorWithY), m_Value(Y)))) {
2173-
// see if XorWithY is: x ^ (z & ~y)
2167+
if (match(Op0, m_Xor(m_Value(XorWithY), m_Value(Y)))) {
21742168
Value *ZAndNotY;
2175-
if (match(XorWithY, m_Xor(m_Value(X), m_Value(ZAndNotY)))) {
2176-
// see if ZAndNotY is: z & ~y
2169+
if (match(XorWithY, m_Xor(m_Value(X), m_Value(ZAndNotY)))) {
21772170
Value *NotY;
21782171
if (match(ZAndNotY, m_And(m_Value(Z), m_Value(NotY))) &&
2179-
match(NotY, m_Not(m_Specific(Y)))) {
2180-
// apply final optimisation: ~((y | z) ^ x)
2172+
match(NotY, m_Not(m_Specific(Y)))) {
21812173
Value *YOrZ = Builder.CreateOr(Y, Z);
21822174
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
21832175
return BinaryOperator::CreateNot(YOrZXorX);
@@ -3828,12 +3820,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
38283820
return replaceInstUsesWith(I, V);
38293821

38303822
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
3831-
3832-
// Issue #97044: test0 optimisation
3823+
3824+
// ((X & Y & ~Z) | (X & ~Y & Z) | (~X & ~Y &~Z) | (X & Y &Z)) -> ~((Y | Z) ^
3825+
// X)
38333826
{
38343827
Value *X, *Y, *Z;
38353828
Value *Term1, *Term2, *XAndYAndZ;
3836-
if (match(&I, m_Or(m_Or(m_Value(Term1), m_Value(Term2)), m_Value(XAndYAndZ))) &&
3829+
if (match(&I,
3830+
m_Or(m_Or(m_Value(Term1), m_Value(Term2)), m_Value(XAndYAndZ))) &&
38373831
match(XAndYAndZ, m_And(m_And(m_Value(X), m_Value(Y)), m_Value(Z)))) {
38383832
Value *YOrZ = Builder.CreateOr(Y, Z);
38393833
Value *YOrZXorX = Builder.CreateXor(YOrZ, X);
@@ -5289,6 +5283,6 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
52895283

52905284
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
52915285
return Res;
5292-
5286+
52935287
return nullptr;
52945288
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
; Tests for GitHub issue #97044 - Boolean instruction canonicalization
5+
; All expressions should optimise to the same canonical form: ~((y | z) ^ x)
6+
7+
define i32 @test0_4way_or(i32 %x, i32 %y, i32 %z) {
8+
; CHECK-LABEL: @test0_4way_or(
9+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], [[Z:%.*]]
10+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
11+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], -1
12+
; CHECK-NEXT: ret i32 [[TMP3]]
13+
;
14+
%not = xor i32 %z, -1
15+
%and = and i32 %y, %not
16+
%and1 = and i32 %and, %x
17+
%not2 = xor i32 %y, -1
18+
%and3 = and i32 %x, %not2
19+
%and4 = and i32 %and3, %z
20+
%or = or i32 %and1, %and4
21+
%not5 = xor i32 %x, -1
22+
%not6 = xor i32 %y, -1
23+
%and7 = and i32 %not5, %not6
24+
%not8 = xor i32 %z, -1
25+
%and9 = and i32 %and7, %not8
26+
%or10 = or i32 %or, %and9
27+
%and11 = and i32 %x, %y
28+
%and12 = and i32 %and11, %z
29+
%or13 = or i32 %or10, %and12
30+
ret i32 %or13
31+
}
32+
33+
define i32 @test1_xor_pattern(i32 %x, i32 %y, i32 %z) {
34+
; CHECK-LABEL: @test1_xor_pattern(
35+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1:%.*]], [[X:%.*]]
36+
; CHECK-NEXT: [[AND4_DEMORGAN:%.*]] = or i32 [[TMP2]], [[Z:%.*]]
37+
; CHECK-NEXT: [[AND8:%.*]] = and i32 [[Z]], [[TMP1]]
38+
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[AND4_DEMORGAN]], -1
39+
; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[AND8]], [[TMP4]]
40+
; CHECK-NEXT: ret i32 [[TMP3]]
41+
;
42+
%not = xor i32 %z, -1
43+
%and = and i32 %x, %y
44+
%not1 = xor i32 %x, -1
45+
%not2 = xor i32 %y, -1
46+
%and3 = and i32 %not1, %not2
47+
%or = or i32 %and, %and3
48+
%and4 = and i32 %not, %or
49+
%and5 = and i32 %x, %y
50+
%and6 = and i32 %x, %not2
51+
%or7 = or i32 %and5, %and6
52+
%and8 = and i32 %z, %or7
53+
%xor = xor i32 %and4, %and8
54+
ret i32 %xor
55+
}
56+
57+
define i32 @test2_nested_xor(i32 %x, i32 %y, i32 %z) {
58+
; CHECK-LABEL: @test2_nested_xor(
59+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2:%.*]], -1
60+
; CHECK-NEXT: [[AND8:%.*]] = and i32 [[Z:%.*]], [[TMP3]]
61+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[AND8]]
62+
; CHECK-NEXT: ret i32 [[TMP1]]
63+
;
64+
%and = and i32 %x, %y
65+
%not = xor i32 %x, -1
66+
%not1 = xor i32 %y, -1
67+
%and2 = and i32 %not, %not1
68+
%or = or i32 %and, %and2
69+
%and3 = and i32 %x, %y
70+
%not4 = xor i32 %y, -1
71+
%and5 = and i32 %x, %not4
72+
%or6 = or i32 %and3, %and5
73+
%xor = xor i32 %or, %or6
74+
%not7 = xor i32 %y, -1
75+
%and8 = and i32 %z, %not7
76+
%and9 = and i32 %xor, %and8
77+
%xor10 = xor i32 %or, %and9
78+
%xor11 = xor i32 %xor10, %y
79+
%xor12 = xor i32 %xor11, -1
80+
ret i32 %xor12
81+
}
82+
83+
define i32 @test3_already_optimal(i32 %x, i32 %y, i32 %z) {
84+
; CHECK-LABEL: @test3_already_optimal(
85+
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[Z:%.*]]
86+
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR]], [[X:%.*]]
87+
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[XOR]], -1
88+
; CHECK-NEXT: ret i32 [[NOT]]
89+
;
90+
%or = or i32 %y, %z
91+
%xor = xor i32 %or, %x
92+
%not = xor i32 %xor, -1
93+
ret i32 %not
94+
}

0 commit comments

Comments
 (0)