Skip to content

Commit b5a9361

Browse files
committed
[InstCombine] canonicalize zext-and-of-bool compare to narrow and
https://alive2.llvm.org/ce/z/3jYbEH We should choose one of these forms, and the option that uses the narrow type allows the motivating example from issue #56294 to reduce. In the best case (no 'not' needed and 'trunc' remains), this does remove an instruction. Note that there is what looks like a regression because there is an existing canonicalization that turns trunc into and+icmp. That is a long-standing transform, and I'm not sure what effect reversing it would have.
1 parent 26821f7 commit b5a9361

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,19 @@ Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp,
19041904
return new ICmpInst(NewPred, X, SubOne(cast<Constant>(Cmp.getOperand(1))));
19051905
}
19061906

1907+
// ((zext i1 X) & Y) == 0 --> !((trunc Y) & X)
1908+
// ((zext i1 X) & Y) != 0 --> ((trunc Y) & X)
1909+
if (match(And, m_OneUse(m_c_And(m_OneUse(m_ZExt(m_Value(X))), m_Value(Y)))) &&
1910+
C.isZero() && X->getType()->isIntOrIntVectorTy(1)) {
1911+
Value *TruncY = Builder.CreateTrunc(Y, X->getType());
1912+
if (Pred == CmpInst::ICMP_EQ) {
1913+
Value *And = Builder.CreateAnd(TruncY, X);
1914+
return BinaryOperator::CreateNot(And);
1915+
}
1916+
assert(Pred == CmpInst::ICMP_NE && "Unexpected predicate");
1917+
return BinaryOperator::CreateAnd(TruncY, X);
1918+
}
1919+
19071920
return nullptr;
19081921
}
19091922

llvm/test/Transforms/InstCombine/and-xor-or.ll

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4345,11 +4345,7 @@ define i32 @or_sext_sext_use1(i8 %x, i4 %y) {
43454345
define i1 @PR56294(i8 %x) {
43464346
; CHECK-LABEL: define {{[^@]+}}@PR56294
43474347
; CHECK-SAME: (i8 [[X:%.*]]) {
4348-
; CHECK-NEXT: [[T2:%.*]] = icmp eq i8 [[X]], 2
4349-
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[T2]] to i8
4350-
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], [[X]]
4351-
; CHECK-NEXT: [[T7:%.*]] = icmp ne i8 [[TMP2]], 0
4352-
; CHECK-NEXT: ret i1 [[T7]]
4348+
; CHECK-NEXT: ret i1 false
43534349
;
43544350
%t2 = icmp eq i8 %x, 2
43554351
%t3 = and i8 %x, 1

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4113,9 +4113,10 @@ define i1 @signbit_true_logic_uses_commute(i64 %x) {
41134113

41144114
define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
41154115
; CHECK-LABEL: @zext_bool_and_eq0(
4116-
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i8
4117-
; CHECK-NEXT: [[A:%.*]] = and i8 [[ZX]], [[Y:%.*]]
4118-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[A]], 0
4116+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
4117+
; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
4118+
; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[X:%.*]]
4119+
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP3]], true
41194120
; CHECK-NEXT: ret i1 [[R]]
41204121
;
41214122
%zx = zext i1 %x to i8
@@ -4126,9 +4127,9 @@ define i1 @zext_bool_and_eq0(i1 %x, i8 %y) {
41264127

41274128
define <2 x i1> @zext_bool_and_eq0_commute(<2 x i1> %x, <2 x i8> %p) {
41284129
; CHECK-LABEL: @zext_bool_and_eq0_commute(
4129-
; CHECK-NEXT: [[ZX:%.*]] = zext <2 x i1> [[X:%.*]] to <2 x i8>
4130-
; CHECK-NEXT: [[A:%.*]] = and <2 x i8> [[ZX]], [[P:%.*]]
4131-
; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[A]], zeroinitializer
4130+
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i8> [[P:%.*]] to <2 x i1>
4131+
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i1> [[TMP1]], [[X:%.*]]
4132+
; CHECK-NEXT: [[R:%.*]] = xor <2 x i1> [[TMP2]], <i1 true, i1 true>
41324133
; CHECK-NEXT: ret <2 x i1> [[R]]
41334134
;
41344135
%y = mul <2 x i8> %p, %p ; thwart complexity-based canonicalization
@@ -4140,9 +4141,9 @@ define <2 x i1> @zext_bool_and_eq0_commute(<2 x i1> %x, <2 x i8> %p) {
41404141

41414142
define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
41424143
; CHECK-LABEL: @zext_bool_and_ne0(
4143-
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i8
4144-
; CHECK-NEXT: [[A:%.*]] = and i8 [[ZX]], [[Y:%.*]]
4145-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[A]], 0
4144+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[Y:%.*]], 1
4145+
; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
4146+
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[X:%.*]]
41464147
; CHECK-NEXT: ret i1 [[R]]
41474148
;
41484149
%zx = zext i1 %x to i8
@@ -4151,6 +4152,8 @@ define i1 @zext_bool_and_ne0(i1 %x, i8 %y) {
41514152
ret i1 %r
41524153
}
41534154

4155+
; TODO: This should transform similarly to eq/ne 0.
4156+
41544157
define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
41554158
; CHECK-LABEL: @zext_bool_and_ne1(
41564159
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i8
@@ -4164,6 +4167,8 @@ define i1 @zext_bool_and_ne1(i1 %x, i8 %y) {
41644167
ret i1 %r
41654168
}
41664169

4170+
; negative test - wrong logic op
4171+
41674172
define i1 @zext_bool_or_eq0(i1 %x, i8 %y) {
41684173
; CHECK-LABEL: @zext_bool_or_eq0(
41694174
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i8
@@ -4177,6 +4182,8 @@ define i1 @zext_bool_or_eq0(i1 %x, i8 %y) {
41774182
ret i1 %r
41784183
}
41794184

4185+
; negative test - extra use
4186+
41804187
define i1 @zext_bool_and_eq0_use(i1 %x, i64 %y) {
41814188
; CHECK-LABEL: @zext_bool_and_eq0_use(
41824189
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i64
@@ -4192,6 +4199,8 @@ define i1 @zext_bool_and_eq0_use(i1 %x, i64 %y) {
41924199
ret i1 %r
41934200
}
41944201

4202+
; negative test - extra use
4203+
41954204
define i1 @zext_bool_and_ne0_use(i1 %x, i64 %y) {
41964205
; CHECK-LABEL: @zext_bool_and_ne0_use(
41974206
; CHECK-NEXT: [[ZX:%.*]] = zext i1 [[X:%.*]] to i64
@@ -4207,6 +4216,8 @@ define i1 @zext_bool_and_ne0_use(i1 %x, i64 %y) {
42074216
ret i1 %r
42084217
}
42094218

4219+
; negative test - must zext from i1
4220+
42104221
define i1 @zext_notbool_and_ne0(i2 %x, i8 %y) {
42114222
; CHECK-LABEL: @zext_notbool_and_ne0(
42124223
; CHECK-NEXT: [[ZX:%.*]] = zext i2 [[X:%.*]] to i8

0 commit comments

Comments
 (0)