1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC 3; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC 4 5declare void @use(ptr) 6declare i32 @get.i32() 7declare i64 @get.i64() 8declare ptr @get.ptr() 9 10define void @only_one_inbounds(ptr %ptr, i1 %c, i32 %arg) { 11; CHECK-LABEL: define void @only_one_inbounds 12; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) { 13; CHECK-NEXT: entry: 14; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i64 15; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG_EXT]] 16; CHECK-NEXT: br label [[LOOP:%.*]] 17; CHECK: loop: 18; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() 19; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 20; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] 21; CHECK-NEXT: call void @use(ptr [[GEP]]) 22; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 23; CHECK: exit: 24; CHECK-NEXT: ret void 25; 26entry: 27 %arg.ext = zext i32 %arg to i64 28 br label %loop 29 30loop: 31 %val = call i32 @get.i32() 32 %val.ext = zext i32 %val to i64 33 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext 34 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext 35 call void @use(ptr %ptr3) 36 br i1 %c, label %loop, label %exit 37 38exit: 39 ret void 40} 41 42define void @both_inbounds_one_neg(ptr %ptr, i1 %c) { 43; CHECK-LABEL: define void @both_inbounds_one_neg 44; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { 45; CHECK-NEXT: entry: 46; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 -1 47; CHECK-NEXT: br label [[LOOP:%.*]] 48; CHECK: loop: 49; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() 50; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 51; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] 52; CHECK-NEXT: call void @use(ptr [[GEP]]) 53; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 54; CHECK: exit: 55; CHECK-NEXT: ret void 56; 57entry: 58 br label %loop 59 60loop: 61 %val = call i32 @get.i32() 62 %val.ext = zext i32 %val to i64 63 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext 64 %ptr3 = getelementptr i8, ptr %ptr2, i64 -1 65 call void @use(ptr %ptr3) 66 br i1 %c, label %loop, label %exit 67 68exit: 69 ret void 70} 71 72define void @both_inbounds_pos(ptr %ptr, i1 %c) { 73; CHECK-LABEL: define void @both_inbounds_pos 74; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { 75; CHECK-NEXT: entry: 76; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 1 77; CHECK-NEXT: br label [[LOOP:%.*]] 78; CHECK: loop: 79; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() 80; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 81; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] 82; CHECK-NEXT: call void @use(ptr [[GEP]]) 83; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 84; CHECK: exit: 85; CHECK-NEXT: ret void 86; 87entry: 88 br label %loop 89 90loop: 91 %val = call i32 @get.i32() 92 %val.ext = zext i32 %val to i64 93 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext 94 %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1 95 call void @use(ptr %ptr3) 96 br i1 %c, label %loop, label %exit 97 98exit: 99 ret void 100} 101 102define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) { 103; CHECK-LABEL: define void @different_elem_types 104; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) { 105; CHECK-NEXT: entry: 106; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]] 107; CHECK-NEXT: br label [[LOOP:%.*]] 108; CHECK: loop: 109; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() 110; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]] 111; CHECK-NEXT: call void @use(ptr [[GEP]]) 112; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 113; CHECK: exit: 114; CHECK-NEXT: ret void 115; 116entry: 117 br label %loop 118 119loop: 120 %val = call i64 @get.i64() 121 %ptr2 = getelementptr i32, ptr %ptr, i64 %val 122 %ptr3 = getelementptr i64, ptr %ptr2, i64 %arg 123 call void @use(ptr %ptr3) 124 br i1 %c, label %loop, label %exit 125 126exit: 127 ret void 128} 129 130define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) { 131; CHECK-LABEL: define void @different_index_types 132; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) { 133; CHECK-NEXT: entry: 134; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]] 135; CHECK-NEXT: br label [[LOOP:%.*]] 136; CHECK: loop: 137; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() 138; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]] 139; CHECK-NEXT: call void @use(ptr [[GEP]]) 140; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 141; CHECK: exit: 142; CHECK-NEXT: ret void 143; 144entry: 145 br label %loop 146 147loop: 148 %val = call i64 @get.i64() 149 %ptr2 = getelementptr i8, ptr %ptr, i64 %val 150 %ptr3 = getelementptr i8, ptr %ptr2, i32 %arg 151 call void @use(ptr %ptr3) 152 br i1 %c, label %loop, label %exit 153 154exit: 155 ret void 156} 157 158define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { 159; CHECK-LABEL: define void @different_index_count 160; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { 161; CHECK-NEXT: entry: 162; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] 163; CHECK-NEXT: br label [[LOOP:%.*]] 164; CHECK: loop: 165; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() 166; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]] 167; CHECK-NEXT: call void @use(ptr [[GEP]]) 168; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 169; CHECK: exit: 170; CHECK-NEXT: ret void 171; 172entry: 173 br label %loop 174 175loop: 176 %val = call i64 @get.i64() 177 %ptr2 = getelementptr i8, ptr %ptr, i64 %val 178 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 179 call void @use(ptr %ptr3) 180 br i1 %c, label %loop, label %exit 181 182exit: 183 ret void 184} 185 186define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) { 187; CHECK-LABEL: define void @src_has_extra_use 188; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) { 189; CHECK-NEXT: entry: 190; CHECK-NEXT: br label [[LOOP:%.*]] 191; CHECK: loop: 192; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() 193; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]] 194; CHECK-NEXT: call void @use(ptr [[PTR2]]) 195; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]] 196; CHECK-NEXT: call void @use(ptr [[PTR3]]) 197; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 198; CHECK: exit: 199; CHECK-NEXT: ret void 200; 201entry: 202 br label %loop 203 204loop: 205 %val = call i64 @get.i64() 206 %ptr2 = getelementptr i8, ptr %ptr, i64 %val 207 call void @use(ptr %ptr2) 208 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg 209 call void @use(ptr %ptr3) 210 br i1 %c, label %loop, label %exit 211 212exit: 213 ret void 214} 215 216define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { 217; CHECK-LABEL: define void @src_already_invariant 218; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { 219; CHECK-NEXT: entry: 220; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] 221; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] 222; CHECK-NEXT: br label [[LOOP:%.*]] 223; CHECK: loop: 224; CHECK-NEXT: call void @use(ptr [[PTR3]]) 225; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 226; CHECK: exit: 227; CHECK-NEXT: ret void 228; 229entry: 230 br label %loop 231 232loop: 233 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1 234 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2 235 call void @use(ptr %ptr3) 236 br i1 %c, label %loop, label %exit 237 238exit: 239 ret void 240} 241 242define void @gep_idx_not_invariant(ptr %ptr, i1 %c) { 243; CHECK-LABEL: define void @gep_idx_not_invariant 244; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { 245; CHECK-NEXT: entry: 246; CHECK-NEXT: br label [[LOOP:%.*]] 247; CHECK: loop: 248; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() 249; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() 250; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]] 251; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]] 252; CHECK-NEXT: call void @use(ptr [[PTR3]]) 253; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 254; CHECK: exit: 255; CHECK-NEXT: ret void 256; 257entry: 258 br label %loop 259 260loop: 261 %val1 = call i64 @get.i64() 262 %val2 = call i64 @get.i64() 263 %ptr2 = getelementptr i8, ptr %ptr, i64 %val1 264 %ptr3 = getelementptr i8, ptr %ptr2, i64 %val2 265 call void @use(ptr %ptr3) 266 br i1 %c, label %loop, label %exit 267 268exit: 269 ret void 270} 271 272define void @src_ptr_not_invariant(i1 %c, i64 %arg) { 273; CHECK-LABEL: define void @src_ptr_not_invariant 274; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) { 275; CHECK-NEXT: entry: 276; CHECK-NEXT: br label [[LOOP:%.*]] 277; CHECK: loop: 278; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() 279; CHECK-NEXT: [[PTR:%.*]] = call ptr @get.ptr() 280; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]] 281; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]] 282; CHECK-NEXT: call void @use(ptr [[PTR3]]) 283; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 284; CHECK: exit: 285; CHECK-NEXT: ret void 286; 287entry: 288 br label %loop 289 290loop: 291 %val = call i64 @get.i64() 292 %ptr = call ptr @get.ptr() 293 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg 294 %ptr3 = getelementptr i8, ptr %ptr2, i64 %val 295 call void @use(ptr %ptr3) 296 br i1 %c, label %loop, label %exit 297 298exit: 299 ret void 300} 301 302define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { 303; CHECK-LABEL: define void @multiple_indices 304; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { 305; CHECK-NEXT: entry: 306; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] 307; CHECK-NEXT: br label [[LOOP:%.*]] 308; CHECK: loop: 309; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() 310; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() 311; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]] 312; CHECK-NEXT: call void @use(ptr [[GEP]]) 313; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 314; CHECK: exit: 315; CHECK-NEXT: ret void 316; 317entry: 318 br label %loop 319 320loop: 321 %val1 = call i64 @get.i64() 322 %val2 = call i64 @get.i64() 323 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2 324 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 325 call void @use(ptr %ptr3) 326 br i1 %c, label %loop, label %exit 327 328exit: 329 ret void 330} 331 332define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) { 333; CHECK-LABEL: define void @multiple_indices_not_invariant 334; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) { 335; CHECK-NEXT: entry: 336; CHECK-NEXT: br label [[LOOP:%.*]] 337; CHECK: loop: 338; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() 339; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() 340; CHECK-NEXT: [[VAL3:%.*]] = call i64 @get.i64() 341; CHECK-NEXT: [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]] 342; CHECK-NEXT: [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]] 343; CHECK-NEXT: call void @use(ptr [[PTR3]]) 344; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 345; CHECK: exit: 346; CHECK-NEXT: ret void 347; 348entry: 349 br label %loop 350 351loop: 352 %val1 = call i64 @get.i64() 353 %val2 = call i64 @get.i64() 354 %val3 = call i64 @get.i64() 355 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2 356 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3 357 call void @use(ptr %ptr3) 358 br i1 %c, label %loop, label %exit 359 360exit: 361 ret void 362} 363 364define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) { 365; CHECK-LABEL: define void @multiple_indices_very_invariant 366; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) { 367; CHECK-NEXT: entry: 368; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] 369; CHECK-NEXT: br label [[LOOP:%.*]] 370; CHECK: loop: 371; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() 372; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]] 373; CHECK-NEXT: call void @use(ptr [[GEP]]) 374; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 375; CHECK: exit: 376; CHECK-NEXT: ret void 377; 378entry: 379 br label %loop 380 381loop: 382 %val1 = call i64 @get.i64() 383 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1 384 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 385 call void @use(ptr %ptr3) 386 br i1 %c, label %loop, label %exit 387 388exit: 389 ret void 390} 391 392define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) { 393; SPEC-LABEL: define void @src_already_invariant_speculation 394; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { 395; SPEC-NEXT: entry: 396; SPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] 397; SPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] 398; SPEC-NEXT: br label [[LOOP:%.*]] 399; SPEC: loop: 400; SPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]] 401; SPEC: if: 402; SPEC-NEXT: call void @use(ptr [[PTR3]]) 403; SPEC-NEXT: br label [[LATCH]] 404; SPEC: latch: 405; SPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 406; SPEC: exit: 407; SPEC-NEXT: ret void 408; 409; NOSPEC-LABEL: define void @src_already_invariant_speculation 410; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { 411; NOSPEC-NEXT: entry: 412; NOSPEC-NEXT: br label [[LOOP:%.*]] 413; NOSPEC: loop: 414; NOSPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]] 415; NOSPEC: if: 416; NOSPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] 417; NOSPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] 418; NOSPEC-NEXT: call void @use(ptr [[PTR3]]) 419; NOSPEC-NEXT: br label [[LATCH]] 420; NOSPEC: latch: 421; NOSPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 422; NOSPEC: exit: 423; NOSPEC-NEXT: ret void 424; 425entry: 426 br label %loop 427 428loop: 429 br i1 %c2, label %if, label %latch 430 431if: 432 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1 433 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2 434 call void @use(ptr %ptr3) 435 br label %latch 436 437latch: 438 br i1 %c, label %loop, label %exit 439 440exit: 441 ret void 442} 443