Skip to content

Commit cc995ad

Browse files
authored
[InstSimpify] Simplifying (xor (sub C_Mask, X), C_Mask) -> X (#122552)
- **[InstSimpify] Add tests for simplifying `(xor (sub C_Mask, X), C_Mask)`; NFC** - **[InstSimpify] Simplifying `(xor (sub C_Mask, X), C_Mask)` -> `X`** Helps address regressions with folding `clz(Pow2)`. Proof: https://alive2.llvm.org/ce/z/zGwUBp
1 parent bfe93ae commit cc995ad

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,14 @@ static Value *simplifySubInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
871871
if (Value *V = simplifyByDomEq(Instruction::Sub, Op0, Op1, Q, MaxRecurse))
872872
return V;
873873

874+
// (sub nuw C_Mask, (xor X, C_Mask)) -> X
875+
if (IsNUW) {
876+
Value *X;
877+
if (match(Op1, m_Xor(m_Value(X), m_Specific(Op0))) &&
878+
match(Op0, m_LowBitMask()))
879+
return X;
880+
}
881+
874882
return nullptr;
875883
}
876884

@@ -2540,6 +2548,14 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
25402548
if (Value *V = simplifyByDomEq(Instruction::Xor, Op0, Op1, Q, MaxRecurse))
25412549
return V;
25422550

2551+
// (xor (sub nuw C_Mask, X), C_Mask) -> X
2552+
{
2553+
Value *X;
2554+
if (match(Op0, m_NUWSub(m_Specific(Op1), m_Value(X))) &&
2555+
match(Op1, m_LowBitMask()))
2556+
return X;
2557+
}
2558+
25432559
return nullptr;
25442560
}
25452561

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
3+
4+
define i8 @xor_w_sub_fail_missing_nuw(i8 range(i8 0, 16) %x) {
5+
; CHECK-LABEL: define i8 @xor_w_sub_fail_missing_nuw(
6+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
7+
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 15
8+
; CHECK-NEXT: [[R:%.*]] = sub nsw i8 15, [[XOR]]
9+
; CHECK-NEXT: ret i8 [[R]]
10+
;
11+
%xor = xor i8 %x, 15
12+
%r = sub nsw i8 15, %xor
13+
ret i8 %r
14+
}
15+
16+
define i8 @xor_w_sub_fail_diff_values(i8 range(i8 0, 16) %x) {
17+
; CHECK-LABEL: define i8 @xor_w_sub_fail_diff_values(
18+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
19+
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 15
20+
; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 31, [[XOR]]
21+
; CHECK-NEXT: ret i8 [[R]]
22+
;
23+
%xor = xor i8 %x, 15
24+
%r = sub nsw nuw i8 31, %xor
25+
ret i8 %r
26+
}
27+
28+
define i8 @xor_w_sub_fail_diff_values2(i8 range(i8 0, 16) %x) {
29+
; CHECK-LABEL: define i8 @xor_w_sub_fail_diff_values2(
30+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
31+
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 31
32+
; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 15, [[XOR]]
33+
; CHECK-NEXT: ret i8 [[R]]
34+
;
35+
%xor = xor i8 %x, 31
36+
%r = sub nsw nuw i8 15, %xor
37+
ret i8 %r
38+
}
39+
40+
define i8 @xor_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
41+
; CHECK-LABEL: define i8 @xor_w_sub_fail_not_mask(
42+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
43+
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 30
44+
; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 30, [[XOR]]
45+
; CHECK-NEXT: ret i8 [[R]]
46+
;
47+
%xor = xor i8 %x, 30
48+
%r = sub nsw nuw i8 30, %xor
49+
ret i8 %r
50+
}
51+
52+
define i8 @xor_w_sub_okay(i8 range(i8 0, 16) %x) {
53+
; CHECK-LABEL: define i8 @xor_w_sub_okay(
54+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
55+
; CHECK-NEXT: ret i8 [[X]]
56+
;
57+
%xor = xor i8 %x, 31
58+
%r = sub nsw nuw i8 31, %xor
59+
ret i8 %r
60+
}
61+
62+
define i8 @sub_w_xor_fail_missing_nuw(i8 range(i8 0, 16) %x) {
63+
; CHECK-LABEL: define i8 @sub_w_xor_fail_missing_nuw(
64+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
65+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 15, [[X]]
66+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 15
67+
; CHECK-NEXT: ret i8 [[R]]
68+
;
69+
%sub = sub nsw i8 15, %x
70+
%r = xor i8 %sub, 15
71+
ret i8 %r
72+
}
73+
74+
define i8 @sub_w_xor_fail_diff_values(i8 range(i8 0, 16) %x) {
75+
; CHECK-LABEL: define i8 @sub_w_xor_fail_diff_values(
76+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
77+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 15, [[X]]
78+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 31
79+
; CHECK-NEXT: ret i8 [[R]]
80+
;
81+
%sub = sub nsw nuw i8 15, %x
82+
%r = xor i8 %sub, 31
83+
ret i8 %r
84+
}
85+
86+
define i8 @sub_w_sub_fail_diff_values2(i8 range(i8 0, 16) %x) {
87+
; CHECK-LABEL: define i8 @sub_w_sub_fail_diff_values2(
88+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
89+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 31, [[X]]
90+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 15
91+
; CHECK-NEXT: ret i8 [[R]]
92+
;
93+
%sub = sub nsw nuw i8 31, %x
94+
%r = xor i8 %sub, 15
95+
ret i8 %r
96+
}
97+
98+
define i8 @sub_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
99+
; CHECK-LABEL: define i8 @sub_w_sub_fail_not_mask(
100+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
101+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 30, [[X]]
102+
; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 30
103+
; CHECK-NEXT: ret i8 [[R]]
104+
;
105+
%sub = sub nsw nuw i8 30, %x
106+
%r = xor i8 %sub, 30
107+
ret i8 %r
108+
}
109+
110+
define i8 @sub_w_sub_okay(i8 range(i8 0, 16) %x) {
111+
; CHECK-LABEL: define i8 @sub_w_sub_okay(
112+
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
113+
; CHECK-NEXT: ret i8 [[X]]
114+
;
115+
%sub = sub nsw nuw i8 31, %x
116+
%r = xor i8 %sub, 31
117+
ret i8 %r
118+
}

0 commit comments

Comments
 (0)