• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -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(i32* 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]], i32* [[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, i32* %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 sgt 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 sgt 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