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