Skip to content

Commit fe1f3cf

Browse files
committed
[SCCP] convert signed div/rem to unsigned for non-negative operands
This extends the transform added with D81756 to handle div/rem opcodes. For example: https://alive2.llvm.org/ce/z/cX6za6 This replicates part of what CVP already does, but the motivating example from issue #57472 demonstrates a phase ordering problem - we convert branches to select before CVP runs and miss the transform. Differential Revision: https://reviews.llvm.org/D133198
1 parent 5948258 commit fe1f3cf

File tree

4 files changed

+44
-11
lines changed

4 files changed

+44
-11
lines changed

llvm/lib/Transforms/Scalar/SCCP.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ static bool replaceSignedInst(SCCPSolver &Solver,
175175
NewInst = new ZExtInst(Op0, Inst.getType(), "", &Inst);
176176
break;
177177
}
178+
case Instruction::SDiv:
179+
case Instruction::SRem: {
180+
// If both operands are not negative, this is the same as udiv/urem.
181+
Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1);
182+
if (InsertedValues.count(Op0) || InsertedValues.count(Op1) ||
183+
!isNonNegative(Op0) || !isNonNegative(Op1))
184+
return false;
185+
auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv
186+
: Instruction::URem;
187+
NewInst = BinaryOperator::Create(NewOpcode, Op0, Op1, "", &Inst);
188+
break;
189+
}
178190
default:
179191
return false;
180192
}

llvm/test/Transforms/PhaseOrdering/srem.ll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
; RUN: opt -O2 -S < %s | FileCheck %s
44
; RUN: opt -O3 -S < %s | FileCheck %s
55

6+
; srem should be folded based on branch conditions
7+
; This can be done by IPSCCP or CVP.
8+
69
define i32 @PR57472(i32 noundef %x) {
710
; CHECK-LABEL: @PR57472(
811
; CHECK-NEXT: entry:
912
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], -1
10-
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[X]], 16
11-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[REM]], i32 42
12-
; CHECK-NEXT: ret i32 [[COND]]
13+
; CHECK-NEXT: [[REM:%.*]] = and i32 [[X]], 15
14+
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[CMP]], i32 [[REM]], i32 42
15+
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
1316
;
1417
entry:
1518
%x.addr = alloca i32, align 4

llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ define void @srem_cmp_constants() {
130130
; CHECK-NEXT: call void @use(i1 false)
131131
; CHECK-NEXT: call void @use(i1 true)
132132
; CHECK-NEXT: call void @use(i1 false)
133-
; CHECK-NEXT: [[SREM_3:%.*]] = srem i16 12704, 0
133+
; CHECK-NEXT: [[SREM_3:%.*]] = urem i16 12704, 0
134134
; CHECK-NEXT: [[C_5:%.*]] = icmp eq i16 [[SREM_3]], 1
135135
; CHECK-NEXT: call void @use(i1 [[C_5]])
136136
; CHECK-NEXT: ret void

llvm/test/Transforms/SCCP/divrem.ll

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ define i8 @sdiv_nonneg0_nonneg1(i8 %x, i8 %y) {
55
; CHECK-LABEL: @sdiv_nonneg0_nonneg1(
66
; CHECK-NEXT: [[PX:%.*]] = and i8 [[X:%.*]], 127
77
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
8-
; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[PX]], [[PY]]
8+
; CHECK-NEXT: [[R:%.*]] = udiv i8 [[PX]], [[PY]]
99
; CHECK-NEXT: ret i8 [[R]]
1010
;
1111
%px = and i8 %x, 127
@@ -17,14 +17,16 @@ define i8 @sdiv_nonneg0_nonneg1(i8 %x, i8 %y) {
1717
define i8 @sdiv_nonnegconst0_nonneg1(i7 %y) {
1818
; CHECK-LABEL: @sdiv_nonnegconst0_nonneg1(
1919
; CHECK-NEXT: [[PY:%.*]] = zext i7 [[Y:%.*]] to i8
20-
; CHECK-NEXT: [[R:%.*]] = sdiv i8 42, [[PY]]
20+
; CHECK-NEXT: [[R:%.*]] = udiv i8 42, [[PY]]
2121
; CHECK-NEXT: ret i8 [[R]]
2222
;
2323
%py = zext i7 %y to i8
2424
%r = sdiv i8 42, %py
2525
ret i8 %r
2626
}
2727

28+
; TODO: This can be converted to udiv.
29+
2830
define i8 @sdiv_nonneg0_nonnegconst1(i8 %x) {
2931
; CHECK-LABEL: @sdiv_nonneg0_nonnegconst1(
3032
; CHECK-NEXT: [[PX:%.*]] = mul nsw i8 [[X:%.*]], [[X]]
@@ -36,6 +38,8 @@ define i8 @sdiv_nonneg0_nonnegconst1(i8 %x) {
3638
ret i8 %r
3739
}
3840

41+
; negative test
42+
3943
define i8 @sdiv_unknown0_nonneg1(i8 %x, i8 %y) {
4044
; CHECK-LABEL: @sdiv_unknown0_nonneg1(
4145
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
@@ -47,6 +51,8 @@ define i8 @sdiv_unknown0_nonneg1(i8 %x, i8 %y) {
4751
ret i8 %r
4852
}
4953

54+
; negative test
55+
5056
define i8 @sdiv_nonnegconst0_unknown1(i7 %y) {
5157
; CHECK-LABEL: @sdiv_nonnegconst0_unknown1(
5258
; CHECK-NEXT: [[SY:%.*]] = sext i7 [[Y:%.*]] to i8
@@ -58,6 +64,8 @@ define i8 @sdiv_nonnegconst0_unknown1(i7 %y) {
5864
ret i8 %r
5965
}
6066

67+
; negative test - mul must be 'nsw' to be known non-negative
68+
6169
define i8 @sdiv_unknown0_nonnegconst1(i8 %x) {
6270
; CHECK-LABEL: @sdiv_unknown0_nonnegconst1(
6371
; CHECK-NEXT: [[SX:%.*]] = mul i8 [[X:%.*]], [[X]]
@@ -73,7 +81,7 @@ define i8 @srem_nonneg0_nonneg1(i8 %x, i8 %y) {
7381
; CHECK-LABEL: @srem_nonneg0_nonneg1(
7482
; CHECK-NEXT: [[PX:%.*]] = and i8 [[X:%.*]], 127
7583
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
76-
; CHECK-NEXT: [[R:%.*]] = srem i8 [[PX]], [[PY]]
84+
; CHECK-NEXT: [[R:%.*]] = urem i8 [[PX]], [[PY]]
7785
; CHECK-NEXT: ret i8 [[R]]
7886
;
7987
%px = and i8 %x, 127
@@ -85,7 +93,7 @@ define i8 @srem_nonneg0_nonneg1(i8 %x, i8 %y) {
8593
define i8 @srem_nonnegconst0_nonneg1(i8 %y) {
8694
; CHECK-LABEL: @srem_nonnegconst0_nonneg1(
8795
; CHECK-NEXT: [[PY:%.*]] = and i8 [[Y:%.*]], 127
88-
; CHECK-NEXT: [[R:%.*]] = srem i8 42, [[PY]]
96+
; CHECK-NEXT: [[R:%.*]] = urem i8 42, [[PY]]
8997
; CHECK-NEXT: ret i8 [[R]]
9098
;
9199
%py = and i8 %y, 127
@@ -96,14 +104,16 @@ define i8 @srem_nonnegconst0_nonneg1(i8 %y) {
96104
define i8 @srem_nonneg0_nonnegconst1(i7 %x) {
97105
; CHECK-LABEL: @srem_nonneg0_nonnegconst1(
98106
; CHECK-NEXT: [[PX:%.*]] = zext i7 [[X:%.*]] to i8
99-
; CHECK-NEXT: [[R:%.*]] = srem i8 [[PX]], 42
107+
; CHECK-NEXT: [[R:%.*]] = urem i8 [[PX]], 42
100108
; CHECK-NEXT: ret i8 [[R]]
101109
;
102110
%px = zext i7 %x to i8
103111
%r = srem i8 %px, 42
104112
ret i8 %r
105113
}
106114

115+
; negative test
116+
107117
define i8 @srem_unknown0_nonneg1(i8 %x, i8 %y) {
108118
; CHECK-LABEL: @srem_unknown0_nonneg1(
109119
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
@@ -115,6 +125,8 @@ define i8 @srem_unknown0_nonneg1(i8 %x, i8 %y) {
115125
ret i8 %r
116126
}
117127

128+
; negative test
129+
118130
define i8 @srem_nonnegconst0_unknown1(i7 %y) {
119131
; CHECK-LABEL: @srem_nonnegconst0_unknown1(
120132
; CHECK-NEXT: [[SY:%.*]] = sext i7 [[Y:%.*]] to i8
@@ -126,6 +138,8 @@ define i8 @srem_nonnegconst0_unknown1(i7 %y) {
126138
ret i8 %r
127139
}
128140

141+
; negative test - mul must be 'nsw' to be known non-negative
142+
129143
define i8 @srem_unknown0_nonnegconst1(i8 %x) {
130144
; CHECK-LABEL: @srem_unknown0_nonnegconst1(
131145
; CHECK-NEXT: [[SX:%.*]] = mul i8 [[X:%.*]], [[X]]
@@ -137,13 +151,15 @@ define i8 @srem_unknown0_nonnegconst1(i8 %x) {
137151
ret i8 %r
138152
}
139153

154+
; x is known non-negative in t block
155+
140156
define i32 @PR57472(i32 %x) {
141157
; CHECK-LABEL: @PR57472(
142158
; CHECK-NEXT: entry:
143159
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
144160
; CHECK-NEXT: br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
145161
; CHECK: t:
146-
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[X]], 16
162+
; CHECK-NEXT: [[REM:%.*]] = urem i32 [[X]], 16
147163
; CHECK-NEXT: br label [[EXIT:%.*]]
148164
; CHECK: f:
149165
; CHECK-NEXT: br label [[EXIT]]
@@ -167,6 +183,8 @@ exit:
167183
ret i32 %cond
168184
}
169185

186+
; x is known non-negative in f block
187+
170188
define i32 @PR57472_alt(i32 %x) {
171189
; CHECK-LABEL: @PR57472_alt(
172190
; CHECK-NEXT: entry:
@@ -175,7 +193,7 @@ define i32 @PR57472_alt(i32 %x) {
175193
; CHECK: t:
176194
; CHECK-NEXT: br label [[EXIT:%.*]]
177195
; CHECK: f:
178-
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 16, [[X]]
196+
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 16, [[X]]
179197
; CHECK-NEXT: br label [[EXIT]]
180198
; CHECK: exit:
181199
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ -42, [[T]] ], [ [[DIV]], [[F]] ]

0 commit comments

Comments
 (0)