xref: /llvm-project/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll (revision b7db403e701029c801fd990dceeb219de9fb800c)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
3
4target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
5target triple = "thumbv7m-arm-none-eabi"
6
7define void @h(ptr nocapture %p, i32 %x) local_unnamed_addr #0 {
8; CHECK-LABEL: @h(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], 0
11; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
12; CHECK:       if.then:
13; CHECK-NEXT:    [[REM21:%.*]] = urem i32 [[X]], 10
14; CHECK-NEXT:    store i32 [[REM21]], ptr [[P:%.*]], align 4
15; CHECK-NEXT:    br label [[IF_END]]
16; CHECK:       if.end:
17; CHECK-NEXT:    ret void
18;
19entry:
20
21  %cmp = icmp sgt i32 %x, 0
22  br i1 %cmp, label %if.then, label %if.end
23
24if.then:
25  %rem2 = srem i32 %x, 10
26  store i32 %rem2, ptr %p, align 4
27  br label %if.end
28
29if.end:
30  ret void
31}
32
33; looping case where loop has exactly one block
34; at the point of srem, we know that %a is always greater than 0,
35; because of the assume before it, so we can transform it to urem.
36declare void @llvm.assume(i1)
37define void @test4(i32 %n) {
38; CHECK-LABEL: @test4(
39; CHECK-NEXT:  entry:
40; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 0
41; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP:%.*]], label [[EXIT:%.*]]
42; CHECK:       loop:
43; CHECK-NEXT:    [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[REM1:%.*]], [[LOOP]] ]
44; CHECK-NEXT:    [[COND:%.*]] = icmp samesign ugt i32 [[A]], 4
45; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
46; CHECK-NEXT:    [[REM1]] = urem i32 [[A]], 17
47; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ugt i32 [[REM1]], 8
48; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOP]], label [[EXIT]]
49; CHECK:       exit:
50; CHECK-NEXT:    ret void
51;
52entry:
53  %cmp = icmp sgt i32 %n, 0
54  br i1 %cmp, label %loop, label %exit
55
56loop:
57  %a = phi i32 [ %n, %entry ], [ %rem, %loop ]
58  %cond = icmp sgt i32 %a, 4
59  call void @llvm.assume(i1 %cond)
60  %rem = srem i32 %a, 17
61  %loopcond = icmp sgt i32 %rem, 8
62  br i1 %loopcond, label %loop, label %exit
63
64exit:
65  ret void
66}
67
68; Now, let's try various domain combinations for operands.
69
70define i8 @test5_pos_pos(i8 %x, i8 %y) {
71; CHECK-LABEL: @test5_pos_pos(
72; CHECK-NEXT:    [[C0:%.*]] = icmp sge i8 [[X:%.*]], 0
73; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
74; CHECK-NEXT:    [[C1:%.*]] = icmp sge i8 [[Y:%.*]], 0
75; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
76; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X]], [[Y]]
77; CHECK-NEXT:    ret i8 [[REM1]]
78;
79  %c0 = icmp sge i8 %x, 0
80  call void @llvm.assume(i1 %c0)
81  %c1 = icmp sge i8 %y, 0
82  call void @llvm.assume(i1 %c1)
83
84  %rem = srem i8 %x, %y
85  ret i8 %rem
86}
87define i8 @test6_pos_neg(i8 %x, i8 %y) {
88; CHECK-LABEL: @test6_pos_neg(
89; CHECK-NEXT:    [[C0:%.*]] = icmp sge i8 [[X:%.*]], 0
90; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
91; CHECK-NEXT:    [[C1:%.*]] = icmp sle i8 [[Y:%.*]], 0
92; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
93; CHECK-NEXT:    [[Y_NONNEG:%.*]] = sub i8 0, [[Y]]
94; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X]], [[Y_NONNEG]]
95; CHECK-NEXT:    ret i8 [[REM1]]
96;
97  %c0 = icmp sge i8 %x, 0
98  call void @llvm.assume(i1 %c0)
99  %c1 = icmp sle i8 %y, 0
100  call void @llvm.assume(i1 %c1)
101
102  %rem = srem i8 %x, %y
103  ret i8 %rem
104}
105define i8 @test7_neg_pos(i8 %x, i8 %y) {
106; CHECK-LABEL: @test7_neg_pos(
107; CHECK-NEXT:    [[C0:%.*]] = icmp sle i8 [[X:%.*]], 0
108; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
109; CHECK-NEXT:    [[C1:%.*]] = icmp sge i8 [[Y:%.*]], 0
110; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
111; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i8 0, [[X]]
112; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X_NONNEG]], [[Y]]
113; CHECK-NEXT:    [[REM1_NEG:%.*]] = sub i8 0, [[REM1]]
114; CHECK-NEXT:    ret i8 [[REM1_NEG]]
115;
116  %c0 = icmp sle i8 %x, 0
117  call void @llvm.assume(i1 %c0)
118  %c1 = icmp sge i8 %y, 0
119  call void @llvm.assume(i1 %c1)
120
121  %rem = srem i8 %x, %y
122  ret i8 %rem
123}
124define i8 @test8_neg_neg(i8 %x, i8 %y) {
125; CHECK-LABEL: @test8_neg_neg(
126; CHECK-NEXT:    [[C0:%.*]] = icmp sle i8 [[X:%.*]], 0
127; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
128; CHECK-NEXT:    [[C1:%.*]] = icmp sle i8 [[Y:%.*]], 0
129; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
130; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i8 0, [[X]]
131; CHECK-NEXT:    [[Y_NONNEG:%.*]] = sub i8 0, [[Y]]
132; CHECK-NEXT:    [[REM1:%.*]] = urem i8 [[X_NONNEG]], [[Y_NONNEG]]
133; CHECK-NEXT:    [[REM1_NEG:%.*]] = sub i8 0, [[REM1]]
134; CHECK-NEXT:    ret i8 [[REM1_NEG]]
135;
136  %c0 = icmp sle i8 %x, 0
137  call void @llvm.assume(i1 %c0)
138  %c1 = icmp sle i8 %y, 0
139  call void @llvm.assume(i1 %c1)
140
141  %rem = srem i8 %x, %y
142  ret i8 %rem
143}
144
145; After making remainder unsigned, can we narrow it?
146define i16 @test9_narrow(i16 %x, i16 %y) {
147; CHECK-LABEL: @test9_narrow(
148; CHECK-NEXT:    [[C0:%.*]] = icmp ult i16 [[X:%.*]], 128
149; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
150; CHECK-NEXT:    [[C1:%.*]] = icmp ult i16 [[Y:%.*]], 128
151; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
152; CHECK-NEXT:    [[REM1_LHS_TRUNC:%.*]] = trunc i16 [[X]] to i8
153; CHECK-NEXT:    [[REM1_RHS_TRUNC:%.*]] = trunc i16 [[Y]] to i8
154; CHECK-NEXT:    [[REM12:%.*]] = urem i8 [[REM1_LHS_TRUNC]], [[REM1_RHS_TRUNC]]
155; CHECK-NEXT:    [[REM1_ZEXT:%.*]] = zext i8 [[REM12]] to i16
156; CHECK-NEXT:    ret i16 [[REM1_ZEXT]]
157;
158  %c0 = icmp ult i16 %x, 128
159  call void @llvm.assume(i1 %c0)
160  %c1 = icmp ult i16 %y, 128
161  call void @llvm.assume(i1 %c1)
162
163  %rem = srem i16 %x, %y
164  ret i16 %rem
165}
166
167; Ok, but what about narrowing srem in general?
168
169; If both operands are i15, it's uncontroversial - we can truncate to i16
170define i64 @test11_i15_i15(i64 %x, i64 %y) {
171; CHECK-LABEL: @test11_i15_i15(
172; CHECK-NEXT:  entry:
173; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 16383
174; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
175; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -16384
176; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
177; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 16383
178; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
179; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -16384
180; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
181; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i16
182; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i16
183; CHECK-NEXT:    [[DIV1:%.*]] = srem i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
184; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i16 [[DIV1]] to i64
185; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
186;
187entry:
188  %c0 = icmp sle i64 %x, 16383
189  call void @llvm.assume(i1 %c0)
190  %c1 = icmp sge i64 %x, -16384
191  call void @llvm.assume(i1 %c1)
192
193  %c2 = icmp sle i64 %y, 16383
194  call void @llvm.assume(i1 %c2)
195  %c3 = icmp sge i64 %y, -16384
196  call void @llvm.assume(i1 %c3)
197
198  %div = srem i64 %x, %y
199  ret i64 %div
200}
201
202; But if operands are i16, we can only truncate to i32, because we can't
203; rule out UB of  i16 INT_MIN s/ i16 -1
204define i64 @test12_i16_i16(i64 %x, i64 %y) {
205; CHECK-LABEL: @test12_i16_i16(
206; CHECK-NEXT:  entry:
207; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 32767
208; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
209; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -32768
210; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
211; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 32767
212; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
213; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -32768
214; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
215; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i32
216; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i32
217; CHECK-NEXT:    [[DIV1:%.*]] = srem i32 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
218; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i32 [[DIV1]] to i64
219; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
220;
221entry:
222  %c0 = icmp sle i64 %x, 32767
223  call void @llvm.assume(i1 %c0)
224  %c1 = icmp sge i64 %x, -32768
225  call void @llvm.assume(i1 %c1)
226
227  %c2 = icmp sle i64 %y, 32767
228  call void @llvm.assume(i1 %c2)
229  %c3 = icmp sge i64 %y, -32768
230  call void @llvm.assume(i1 %c3)
231
232  %div = srem i64 %x, %y
233  ret i64 %div
234}
235
236; But if divident is i16, and divisor is u15, then we know that i16 is UB-safe.
237define i64 @test13_i16_u15(i64 %x, i64 %y) {
238; CHECK-LABEL: @test13_i16_u15(
239; CHECK-NEXT:  entry:
240; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 32767
241; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
242; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -32768
243; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
244; CHECK-NEXT:    [[C2:%.*]] = icmp ule i64 [[Y:%.*]], 32767
245; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
246; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i16
247; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i16
248; CHECK-NEXT:    [[DIV1:%.*]] = srem i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
249; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i16 [[DIV1]] to i64
250; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
251;
252entry:
253  %c0 = icmp sle i64 %x, 32767
254  call void @llvm.assume(i1 %c0)
255  %c1 = icmp sge i64 %x, -32768
256  call void @llvm.assume(i1 %c1)
257
258  %c2 = icmp ule i64 %y, 32767
259  call void @llvm.assume(i1 %c2)
260
261  %div = srem i64 %x, %y
262  ret i64 %div
263}
264
265; And likewise, if we know that if the divident is never i16 INT_MIN,
266; we can truncate to i16.
267define i64 @test14_i16safe_i16(i64 %x, i64 %y) {
268; CHECK-LABEL: @test14_i16safe_i16(
269; CHECK-NEXT:  entry:
270; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 32767
271; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
272; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i64 [[X]], -32768
273; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
274; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 32767
275; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
276; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -32768
277; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
278; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i16
279; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i16
280; CHECK-NEXT:    [[DIV1:%.*]] = srem i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
281; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i16 [[DIV1]] to i64
282; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
283;
284entry:
285  %c0 = icmp sle i64 %x, 32767
286  call void @llvm.assume(i1 %c0)
287  %c1 = icmp sgt i64 %x, -32768
288  call void @llvm.assume(i1 %c1)
289
290  %c2 = icmp sle i64 %y, 32767
291  call void @llvm.assume(i1 %c2)
292  %c3 = icmp sge i64 %y, -32768
293  call void @llvm.assume(i1 %c3)
294
295  %div = srem i64 %x, %y
296  ret i64 %div
297}
298
299; Of course, both of the conditions can happen at once.
300define i64 @test15_i16safe_u15(i64 %x, i64 %y) {
301; CHECK-LABEL: @test15_i16safe_u15(
302; CHECK-NEXT:  entry:
303; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 32767
304; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
305; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i64 [[X]], -32768
306; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
307; CHECK-NEXT:    [[C2:%.*]] = icmp ule i64 [[Y:%.*]], 32767
308; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
309; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i16
310; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i16
311; CHECK-NEXT:    [[DIV1:%.*]] = srem i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
312; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i16 [[DIV1]] to i64
313; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
314;
315entry:
316  %c0 = icmp sle i64 %x, 32767
317  call void @llvm.assume(i1 %c0)
318  %c1 = icmp sgt i64 %x, -32768
319  call void @llvm.assume(i1 %c1)
320
321  %c2 = icmp ule i64 %y, 32767
322  call void @llvm.assume(i1 %c2)
323
324  %div = srem i64 %x, %y
325  ret i64 %div
326}
327
328; We at most truncate to i8
329define i64 @test16_i4_i4(i64 %x, i64 %y) {
330; CHECK-LABEL: @test16_i4_i4(
331; CHECK-NEXT:  entry:
332; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 3
333; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
334; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -4
335; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
336; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 3
337; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
338; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -4
339; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
340; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i8
341; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i8
342; CHECK-NEXT:    [[DIV1:%.*]] = srem i8 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
343; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i8 [[DIV1]] to i64
344; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
345;
346entry:
347  %c0 = icmp sle i64 %x, 3
348  call void @llvm.assume(i1 %c0)
349  %c1 = icmp sge i64 %x, -4
350  call void @llvm.assume(i1 %c1)
351
352  %c2 = icmp sle i64 %y, 3
353  call void @llvm.assume(i1 %c2)
354  %c3 = icmp sge i64 %y, -4
355  call void @llvm.assume(i1 %c3)
356
357  %div = srem i64 %x, %y
358  ret i64 %div
359}
360
361; And we round up to the powers of two
362define i64 @test17_i9_i9(i64 %x, i64 %y) {
363; CHECK-LABEL: @test17_i9_i9(
364; CHECK-NEXT:  entry:
365; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 255
366; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
367; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -256
368; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
369; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 255
370; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
371; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -256
372; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
373; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i16
374; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i16
375; CHECK-NEXT:    [[DIV1:%.*]] = srem i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
376; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i16 [[DIV1]] to i64
377; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
378;
379entry:
380  %c0 = icmp sle i64 %x, 255
381  call void @llvm.assume(i1 %c0)
382  %c1 = icmp sge i64 %x, -256
383  call void @llvm.assume(i1 %c1)
384
385  %c2 = icmp sle i64 %y, 255
386  call void @llvm.assume(i1 %c2)
387  %c3 = icmp sge i64 %y, -256
388  call void @llvm.assume(i1 %c3)
389
390  %div = srem i64 %x, %y
391  ret i64 %div
392}
393
394; Don't widen the operation to the next power of two if it wasn't a power of two.
395define i9 @test18_i9_i9(i9 %x, i9 %y) {
396; CHECK-LABEL: @test18_i9_i9(
397; CHECK-NEXT:  entry:
398; CHECK-NEXT:    [[C0:%.*]] = icmp sle i9 [[X:%.*]], 255
399; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
400; CHECK-NEXT:    [[C1:%.*]] = icmp sge i9 [[X]], -256
401; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
402; CHECK-NEXT:    [[C2:%.*]] = icmp sle i9 [[Y:%.*]], 255
403; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
404; CHECK-NEXT:    [[C3:%.*]] = icmp sge i9 [[Y]], -256
405; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
406; CHECK-NEXT:    [[DIV:%.*]] = srem i9 [[X]], [[Y]]
407; CHECK-NEXT:    ret i9 [[DIV]]
408;
409entry:
410  %c0 = icmp sle i9 %x, 255
411  call void @llvm.assume(i1 %c0)
412  %c1 = icmp sge i9 %x, -256
413  call void @llvm.assume(i1 %c1)
414
415  %c2 = icmp sle i9 %y, 255
416  call void @llvm.assume(i1 %c2)
417  %c3 = icmp sge i9 %y, -256
418  call void @llvm.assume(i1 %c3)
419
420  %div = srem i9 %x, %y
421  ret i9 %div
422}
423define i10 @test19_i10_i10(i10 %x, i10 %y) {
424; CHECK-LABEL: @test19_i10_i10(
425; CHECK-NEXT:  entry:
426; CHECK-NEXT:    [[C0:%.*]] = icmp sle i10 [[X:%.*]], 255
427; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
428; CHECK-NEXT:    [[C1:%.*]] = icmp sge i10 [[X]], -256
429; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
430; CHECK-NEXT:    [[C2:%.*]] = icmp sle i10 [[Y:%.*]], 255
431; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
432; CHECK-NEXT:    [[C3:%.*]] = icmp sge i10 [[Y]], -256
433; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
434; CHECK-NEXT:    [[DIV:%.*]] = srem i10 [[X]], [[Y]]
435; CHECK-NEXT:    ret i10 [[DIV]]
436;
437entry:
438  %c0 = icmp sle i10 %x, 255
439  call void @llvm.assume(i1 %c0)
440  %c1 = icmp sge i10 %x, -256
441  call void @llvm.assume(i1 %c1)
442
443  %c2 = icmp sle i10 %y, 255
444  call void @llvm.assume(i1 %c2)
445  %c3 = icmp sge i10 %y, -256
446  call void @llvm.assume(i1 %c3)
447
448  %div = srem i10 %x, %y
449  ret i10 %div
450}
451
452; Note that we need to take the maximal bitwidth, in which both of the operands are representable!
453define i64 @test20_i16_i18(i64 %x, i64 %y) {
454; CHECK-LABEL: @test20_i16_i18(
455; CHECK-NEXT:  entry:
456; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 16383
457; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
458; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -16384
459; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
460; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 65535
461; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
462; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -65536
463; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
464; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i32
465; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i32
466; CHECK-NEXT:    [[DIV1:%.*]] = srem i32 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
467; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i32 [[DIV1]] to i64
468; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
469;
470entry:
471  %c0 = icmp sle i64 %x, 16383
472  call void @llvm.assume(i1 %c0)
473  %c1 = icmp sge i64 %x, -16384
474  call void @llvm.assume(i1 %c1)
475
476  %c2 = icmp sle i64 %y, 65535
477  call void @llvm.assume(i1 %c2)
478  %c3 = icmp sge i64 %y, -65536
479  call void @llvm.assume(i1 %c3)
480
481  %div = srem i64 %x, %y
482  ret i64 %div
483}
484define i64 @test21_i18_i16(i64 %x, i64 %y) {
485; CHECK-LABEL: @test21_i18_i16(
486; CHECK-NEXT:  entry:
487; CHECK-NEXT:    [[C0:%.*]] = icmp sle i64 [[X:%.*]], 65535
488; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
489; CHECK-NEXT:    [[C1:%.*]] = icmp sge i64 [[X]], -65536
490; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
491; CHECK-NEXT:    [[C2:%.*]] = icmp sle i64 [[Y:%.*]], 16383
492; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
493; CHECK-NEXT:    [[C3:%.*]] = icmp sge i64 [[Y]], -16384
494; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
495; CHECK-NEXT:    [[DIV_LHS_TRUNC:%.*]] = trunc i64 [[X]] to i32
496; CHECK-NEXT:    [[DIV_RHS_TRUNC:%.*]] = trunc i64 [[Y]] to i32
497; CHECK-NEXT:    [[DIV1:%.*]] = srem i32 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
498; CHECK-NEXT:    [[DIV_SEXT:%.*]] = sext i32 [[DIV1]] to i64
499; CHECK-NEXT:    ret i64 [[DIV_SEXT]]
500;
501entry:
502  %c0 = icmp sle i64 %x, 65535
503  call void @llvm.assume(i1 %c0)
504  %c1 = icmp sge i64 %x, -65536
505  call void @llvm.assume(i1 %c1)
506
507  %c2 = icmp sle i64 %y, 16383
508  call void @llvm.assume(i1 %c2)
509  %c3 = icmp sge i64 %y, -16384
510  call void @llvm.assume(i1 %c3)
511
512  %div = srem i64 %x, %y
513  ret i64 %div
514}
515
516define dso_local i8 @abs_x_lt_abs_y_positive(i8 %x, i8 %y) {
517; CHECK-LABEL: @abs_x_lt_abs_y_positive(
518; CHECK-NEXT:  entry:
519; CHECK-NEXT:    [[X_CMP:%.*]] = icmp slt i8 [[X:%.*]], 10
520; CHECK-NEXT:    [[X_CMP2:%.*]] = icmp sgt i8 [[X]], -10
521; CHECK-NEXT:    [[AND_X:%.*]] = and i1 [[X_CMP]], [[X_CMP2]]
522; CHECK-NEXT:    [[Y_CMP:%.*]] = icmp sge i8 [[Y:%.*]], 10
523; CHECK-NEXT:    [[AND_COND:%.*]] = and i1 [[AND_X]], [[Y_CMP]]
524; CHECK-NEXT:    br i1 [[AND_COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
525; CHECK:       if.else:
526; CHECK-NEXT:    ret i8 [[X]]
527; CHECK:       if.then:
528; CHECK-NEXT:    ret i8 0
529;
530entry:
531  %x.cmp = icmp slt i8 %x, 10
532  %x.cmp2 = icmp sgt i8 %x, -10
533  %and.x = and i1 %x.cmp, %x.cmp2
534  %y.cmp = icmp sge i8 %y, 10
535  %and.cond = and i1 %and.x, %y.cmp
536  br i1 %and.cond, label %if.else, label %if.then
537
538if.else:                                          ; preds = %entry
539  %rem = srem i8 %x, %y
540  ret i8 %rem
541
542if.then:                                          ; preds = %entry, %if.then6, %if.end4
543  ret i8 0
544}
545
546define dso_local i8 @abs_x_lt_abs_y_positive_unsigned_cmp(i8 %x, i8 %y) {
547; CHECK-LABEL: @abs_x_lt_abs_y_positive_unsigned_cmp(
548; CHECK-NEXT:  entry:
549; CHECK-NEXT:    [[X_CMP:%.*]] = icmp slt i8 [[X:%.*]], 10
550; CHECK-NEXT:    [[X_CMP2:%.*]] = icmp sgt i8 [[X]], -10
551; CHECK-NEXT:    [[AND_X:%.*]] = and i1 [[X_CMP]], [[X_CMP2]]
552; CHECK-NEXT:    [[Y_CMP:%.*]] = icmp uge i8 [[Y:%.*]], 10
553; CHECK-NEXT:    [[Y_CMP2:%.*]] = icmp ule i8 [[Y]], 20
554; CHECK-NEXT:    [[AND_Y:%.*]] = and i1 [[Y_CMP]], [[Y_CMP2]]
555; CHECK-NEXT:    [[AND_COND:%.*]] = and i1 [[AND_X]], [[AND_Y]]
556; CHECK-NEXT:    br i1 [[AND_COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
557; CHECK:       if.else:
558; CHECK-NEXT:    ret i8 [[X]]
559; CHECK:       if.then:
560; CHECK-NEXT:    ret i8 0
561;
562entry:
563  %x.cmp = icmp slt i8 %x, 10
564  %x.cmp2 = icmp sgt i8 %x, -10
565  %and.x = and i1 %x.cmp, %x.cmp2
566  %y.cmp = icmp uge i8 %y, 10
567  %y.cmp2 = icmp ule i8 %y, 20
568  %and.y = and i1 %y.cmp, %y.cmp2
569  %and.cond = and i1 %and.x, %and.y
570  br i1 %and.cond, label %if.else, label %if.then
571
572if.else:                                          ; preds = %entry
573  %rem = srem i8 %x, %y
574  ret i8 %rem
575
576if.then:                                          ; preds = %entry, %if.then6, %if.end4
577  ret i8 0
578}
579
580define dso_local i8 @abs_x_lt_abs_y_negative(i8 %x, i8 %y) {
581; CHECK-LABEL: @abs_x_lt_abs_y_negative(
582; CHECK-NEXT:  entry:
583; CHECK-NEXT:    [[X_CMP:%.*]] = icmp slt i8 [[X:%.*]], 10
584; CHECK-NEXT:    [[X_CMP2:%.*]] = icmp sgt i8 [[X]], -10
585; CHECK-NEXT:    [[AND_X:%.*]] = and i1 [[X_CMP]], [[X_CMP2]]
586; CHECK-NEXT:    [[Y_CMP:%.*]] = icmp sge i8 [[Y:%.*]], -20
587; CHECK-NEXT:    [[Y_CMP2:%.*]] = icmp sle i8 [[Y]], -11
588; CHECK-NEXT:    [[AND_Y:%.*]] = and i1 [[Y_CMP]], [[Y_CMP2]]
589; CHECK-NEXT:    [[AND_COND:%.*]] = and i1 [[AND_X]], [[AND_Y]]
590; CHECK-NEXT:    br i1 [[AND_COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
591; CHECK:       if.else:
592; CHECK-NEXT:    ret i8 [[X]]
593; CHECK:       if.then:
594; CHECK-NEXT:    ret i8 0
595;
596entry:
597  %x.cmp = icmp slt i8 %x, 10
598  %x.cmp2 = icmp sgt i8 %x, -10
599  %and.x = and i1 %x.cmp, %x.cmp2
600  %y.cmp = icmp sge i8 %y, -20
601  %y.cmp2 = icmp sle i8 %y, -11
602  %and.y = and i1 %y.cmp, %y.cmp2
603  %and.cond = and i1 %and.x, %and.y
604  br i1 %and.cond, label %if.else, label %if.then
605
606if.else:                                          ; preds = %entry
607  %rem = srem i8 %x, %y
608  ret i8 %rem
609
610if.then:                                          ; preds = %entry, %if.then6, %if.end4
611  ret i8 0
612}
613
614; Negative test: abs(x) less than or equal abs(y)
615
616define dso_local i8 @abs_x_lte_abs_y(i8 %x, i8 %y) {
617; CHECK-LABEL: @abs_x_lte_abs_y(
618; CHECK-NEXT:  entry:
619; CHECK-NEXT:    [[X_CMP:%.*]] = icmp slt i8 [[X:%.*]], 10
620; CHECK-NEXT:    [[X_CMP2:%.*]] = icmp sgt i8 [[X]], -10
621; CHECK-NEXT:    [[AND_X:%.*]] = and i1 [[X_CMP]], [[X_CMP2]]
622; CHECK-NEXT:    [[Y_CMP:%.*]] = icmp sge i8 [[Y:%.*]], -20
623; CHECK-NEXT:    [[Y_CMP2:%.*]] = icmp sle i8 [[Y]], -9
624; CHECK-NEXT:    [[AND_Y:%.*]] = and i1 [[Y_CMP]], [[Y_CMP2]]
625; CHECK-NEXT:    [[AND_COND:%.*]] = and i1 [[AND_X]], [[AND_Y]]
626; CHECK-NEXT:    br i1 [[AND_COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
627; CHECK:       if.else:
628; CHECK-NEXT:    [[REM:%.*]] = srem i8 [[X]], [[Y]]
629; CHECK-NEXT:    ret i8 [[REM]]
630; CHECK:       if.then:
631; CHECK-NEXT:    ret i8 0
632;
633entry:
634  %x.cmp = icmp slt i8 %x, 10
635  %x.cmp2 = icmp sgt i8 %x, -10
636  %and.x = and i1 %x.cmp, %x.cmp2
637  %y.cmp = icmp sge i8 %y, -20
638  %y.cmp2 = icmp sle i8 %y, -9
639  %and.y = and i1 %y.cmp, %y.cmp2
640  %and.cond = and i1 %and.x, %and.y
641  br i1 %and.cond, label %if.else, label %if.then
642
643if.else:                                          ; preds = %entry
644  %rem = srem i8 %x, %y
645  ret i8 %rem
646
647if.then:                                          ; preds = %entry, %if.then6, %if.end4
648  ret i8 0
649}
650
651; Negative test: abs(x) has unknown predication with abs(y)
652
653define dso_local i8 @abs_x_unknown_abs_y(i8 %x, i8 %y) {
654; CHECK-LABEL: @abs_x_unknown_abs_y(
655; CHECK-NEXT:  entry:
656; CHECK-NEXT:    [[X_CMP:%.*]] = icmp slt i8 [[X:%.*]], 10
657; CHECK-NEXT:    [[X_CMP2:%.*]] = icmp sgt i8 [[X]], -10
658; CHECK-NEXT:    [[AND_X:%.*]] = and i1 [[X_CMP]], [[X_CMP2]]
659; CHECK-NEXT:    [[Y_CMP:%.*]] = icmp sge i8 [[Y:%.*]], -20
660; CHECK-NEXT:    [[Y_CMP2:%.*]] = icmp sle i8 [[Y]], -9
661; CHECK-NEXT:    [[AND_Y:%.*]] = and i1 [[Y_CMP]], [[Y_CMP2]]
662; CHECK-NEXT:    [[AND_COND:%.*]] = and i1 [[AND_X]], [[AND_Y]]
663; CHECK-NEXT:    br i1 [[AND_COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
664; CHECK:       if.else:
665; CHECK-NEXT:    [[REM:%.*]] = srem i8 [[X]], [[Y]]
666; CHECK-NEXT:    ret i8 [[REM]]
667; CHECK:       if.then:
668; CHECK-NEXT:    ret i8 0
669;
670entry:
671  %x.cmp = icmp slt i8 %x, 10
672  %x.cmp2 = icmp sgt i8 %x, -10
673  %and.x = and i1 %x.cmp, %x.cmp2
674  %y.cmp = icmp sge i8 %y, -20
675  %y.cmp2 = icmp sle i8 %y, -9
676  %and.y = and i1 %y.cmp, %y.cmp2
677  %and.cond = and i1 %and.x, %and.y
678  br i1 %and.cond, label %if.else, label %if.then
679
680if.else:                                          ; preds = %entry
681  %rem = srem i8 %x, %y
682  ret i8 %rem
683
684if.then:                                          ; preds = %entry, %if.then6, %if.end4
685  ret i8 0
686}
687