480 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 22; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC3; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC4 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_inbounds12; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {13; CHECK-NEXT: entry:14; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i6415; 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 i6420; 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 void25;26entry:27 %arg.ext = zext i32 %arg to i6428 br label %loop29 30loop:31 %val = call i32 @get.i32()32 %val.ext = zext i32 %val to i6433 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext34 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext35 call void @use(ptr %ptr3)36 br i1 %c, label %loop, label %exit37 38exit:39 ret void40}41 42define void @both_inbounds_one_neg(ptr %ptr, i1 %c, i64 %neg) {43; CHECK-LABEL: define void @both_inbounds_one_neg44; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[NEG:%.*]]) {45; CHECK-NEXT: entry:46; CHECK-NEXT: [[IS_NEG:%.*]] = icmp slt i64 [[NEG]], 047; CHECK-NEXT: call void @llvm.assume(i1 [[IS_NEG]])48; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[NEG]]49; CHECK-NEXT: br label [[LOOP:%.*]]50; CHECK: loop:51; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32()52; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i6453; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]54; CHECK-NEXT: call void @use(ptr [[GEP]])55; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]56; CHECK: exit:57; CHECK-NEXT: ret void58;59entry:60 %is.neg = icmp slt i64 %neg, 061 call void @llvm.assume(i1 %is.neg)62 br label %loop63 64loop:65 %val = call i32 @get.i32()66 %val.ext = zext i32 %val to i6467 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext68 %ptr3 = getelementptr i8, ptr %ptr2, i64 %neg69 call void @use(ptr %ptr3)70 br i1 %c, label %loop, label %exit71 72exit:73 ret void74}75 76define void @both_inbounds_pos(ptr %ptr, i1 %c, i64 %nonneg) {77; CHECK-LABEL: define void @both_inbounds_pos78; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[NONNEG:%.*]]) {79; CHECK-NEXT: entry:80; CHECK-NEXT: [[IS_NONNEG:%.*]] = icmp sge i64 [[NONNEG]], 081; CHECK-NEXT: call void @llvm.assume(i1 [[IS_NONNEG]])82; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[NONNEG]]83; CHECK-NEXT: br label [[LOOP:%.*]]84; CHECK: loop:85; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32()86; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i6487; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]88; CHECK-NEXT: call void @use(ptr [[GEP]])89; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]90; CHECK: exit:91; CHECK-NEXT: ret void92;93entry:94 %is.nonneg = icmp sge i64 %nonneg, 095 call void @llvm.assume(i1 %is.nonneg)96 br label %loop97 98loop:99 %val = call i32 @get.i32()100 %val.ext = zext i32 %val to i64101 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext102 %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 %nonneg103 call void @use(ptr %ptr3)104 br i1 %c, label %loop, label %exit105 106exit:107 ret void108}109 110define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) {111; CHECK-LABEL: define void @different_elem_types112; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {113; CHECK-NEXT: entry:114; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]]115; CHECK-NEXT: br label [[LOOP:%.*]]116; CHECK: loop:117; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()118; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]]119; CHECK-NEXT: call void @use(ptr [[GEP]])120; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]121; CHECK: exit:122; CHECK-NEXT: ret void123;124entry:125 br label %loop126 127loop:128 %val = call i64 @get.i64()129 %ptr2 = getelementptr i32, ptr %ptr, i64 %val130 %ptr3 = getelementptr i64, ptr %ptr2, i64 %arg131 call void @use(ptr %ptr3)132 br i1 %c, label %loop, label %exit133 134exit:135 ret void136}137 138define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) {139; CHECK-LABEL: define void @different_index_types140; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {141; CHECK-NEXT: entry:142; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]]143; CHECK-NEXT: br label [[LOOP:%.*]]144; CHECK: loop:145; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()146; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]147; CHECK-NEXT: call void @use(ptr [[GEP]])148; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]149; CHECK: exit:150; CHECK-NEXT: ret void151;152entry:153 br label %loop154 155loop:156 %val = call i64 @get.i64()157 %ptr2 = getelementptr i8, ptr %ptr, i64 %val158 %ptr3 = getelementptr i8, ptr %ptr2, i32 %arg159 call void @use(ptr %ptr3)160 br i1 %c, label %loop, label %exit161 162exit:163 ret void164}165 166define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {167; CHECK-LABEL: define void @different_index_count168; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {169; CHECK-NEXT: entry:170; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]171; CHECK-NEXT: br label [[LOOP:%.*]]172; CHECK: loop:173; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()174; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]175; CHECK-NEXT: call void @use(ptr [[GEP]])176; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]177; CHECK: exit:178; CHECK-NEXT: ret void179;180entry:181 br label %loop182 183loop:184 %val = call i64 @get.i64()185 %ptr2 = getelementptr i8, ptr %ptr, i64 %val186 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2187 call void @use(ptr %ptr3)188 br i1 %c, label %loop, label %exit189 190exit:191 ret void192}193 194define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) {195; CHECK-LABEL: define void @src_has_extra_use196; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {197; CHECK-NEXT: entry:198; CHECK-NEXT: br label [[LOOP:%.*]]199; CHECK: loop:200; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()201; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]]202; CHECK-NEXT: call void @use(ptr [[PTR2]])203; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]]204; CHECK-NEXT: call void @use(ptr [[PTR3]])205; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]206; CHECK: exit:207; CHECK-NEXT: ret void208;209entry:210 br label %loop211 212loop:213 %val = call i64 @get.i64()214 %ptr2 = getelementptr i8, ptr %ptr, i64 %val215 call void @use(ptr %ptr2)216 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg217 call void @use(ptr %ptr3)218 br i1 %c, label %loop, label %exit219 220exit:221 ret void222}223 224define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {225; CHECK-LABEL: define void @src_already_invariant226; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {227; CHECK-NEXT: entry:228; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]229; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]230; CHECK-NEXT: br label [[LOOP:%.*]]231; CHECK: loop:232; CHECK-NEXT: call void @use(ptr [[PTR3]])233; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]234; CHECK: exit:235; CHECK-NEXT: ret void236;237entry:238 br label %loop239 240loop:241 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1242 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2243 call void @use(ptr %ptr3)244 br i1 %c, label %loop, label %exit245 246exit:247 ret void248}249 250define void @gep_idx_not_invariant(ptr %ptr, i1 %c) {251; CHECK-LABEL: define void @gep_idx_not_invariant252; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {253; CHECK-NEXT: entry:254; CHECK-NEXT: br label [[LOOP:%.*]]255; CHECK: loop:256; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()257; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()258; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]]259; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]]260; CHECK-NEXT: call void @use(ptr [[PTR3]])261; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]262; CHECK: exit:263; CHECK-NEXT: ret void264;265entry:266 br label %loop267 268loop:269 %val1 = call i64 @get.i64()270 %val2 = call i64 @get.i64()271 %ptr2 = getelementptr i8, ptr %ptr, i64 %val1272 %ptr3 = getelementptr i8, ptr %ptr2, i64 %val2273 call void @use(ptr %ptr3)274 br i1 %c, label %loop, label %exit275 276exit:277 ret void278}279 280define void @src_ptr_not_invariant(i1 %c, i64 %arg) {281; CHECK-LABEL: define void @src_ptr_not_invariant282; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) {283; CHECK-NEXT: entry:284; CHECK-NEXT: br label [[LOOP:%.*]]285; CHECK: loop:286; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()287; CHECK-NEXT: [[PTR:%.*]] = call ptr @get.ptr()288; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]]289; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]]290; CHECK-NEXT: call void @use(ptr [[PTR3]])291; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]292; CHECK: exit:293; CHECK-NEXT: ret void294;295entry:296 br label %loop297 298loop:299 %val = call i64 @get.i64()300 %ptr = call ptr @get.ptr()301 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg302 %ptr3 = getelementptr i8, ptr %ptr2, i64 %val303 call void @use(ptr %ptr3)304 br i1 %c, label %loop, label %exit305 306exit:307 ret void308}309 310define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {311; CHECK-LABEL: define void @multiple_indices312; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {313; CHECK-NEXT: entry:314; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]315; CHECK-NEXT: br label [[LOOP:%.*]]316; CHECK: loop:317; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()318; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()319; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]]320; CHECK-NEXT: call void @use(ptr [[GEP]])321; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]322; CHECK: exit:323; CHECK-NEXT: ret void324;325entry:326 br label %loop327 328loop:329 %val1 = call i64 @get.i64()330 %val2 = call i64 @get.i64()331 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2332 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2333 call void @use(ptr %ptr3)334 br i1 %c, label %loop, label %exit335 336exit:337 ret void338}339 340define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) {341; CHECK-LABEL: define void @multiple_indices_not_invariant342; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) {343; CHECK-NEXT: entry:344; CHECK-NEXT: br label [[LOOP:%.*]]345; CHECK: loop:346; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()347; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64()348; CHECK-NEXT: [[VAL3:%.*]] = call i64 @get.i64()349; CHECK-NEXT: [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]]350; CHECK-NEXT: [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]]351; CHECK-NEXT: call void @use(ptr [[PTR3]])352; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]353; CHECK: exit:354; CHECK-NEXT: ret void355;356entry:357 br label %loop358 359loop:360 %val1 = call i64 @get.i64()361 %val2 = call i64 @get.i64()362 %val3 = call i64 @get.i64()363 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2364 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3365 call void @use(ptr %ptr3)366 br i1 %c, label %loop, label %exit367 368exit:369 ret void370}371 372define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) {373; CHECK-LABEL: define void @multiple_indices_very_invariant374; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) {375; CHECK-NEXT: entry:376; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]377; CHECK-NEXT: br label [[LOOP:%.*]]378; CHECK: loop:379; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64()380; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]]381; CHECK-NEXT: call void @use(ptr [[GEP]])382; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]383; CHECK: exit:384; CHECK-NEXT: ret void385;386entry:387 br label %loop388 389loop:390 %val1 = call i64 @get.i64()391 %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1392 %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2393 call void @use(ptr %ptr3)394 br i1 %c, label %loop, label %exit395 396exit:397 ret void398}399 400define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) {401; SPEC-LABEL: define void @src_already_invariant_speculation402; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {403; SPEC-NEXT: entry:404; SPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]405; SPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]406; SPEC-NEXT: br label [[LOOP:%.*]]407; SPEC: loop:408; SPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]409; SPEC: if:410; SPEC-NEXT: call void @use(ptr [[PTR3]])411; SPEC-NEXT: br label [[LATCH]]412; SPEC: latch:413; SPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]414; SPEC: exit:415; SPEC-NEXT: ret void416;417; NOSPEC-LABEL: define void @src_already_invariant_speculation418; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {419; NOSPEC-NEXT: entry:420; NOSPEC-NEXT: br label [[LOOP:%.*]]421; NOSPEC: loop:422; NOSPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]423; NOSPEC: if:424; NOSPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]425; NOSPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]426; NOSPEC-NEXT: call void @use(ptr [[PTR3]])427; NOSPEC-NEXT: br label [[LATCH]]428; NOSPEC: latch:429; NOSPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]430; NOSPEC: exit:431; NOSPEC-NEXT: ret void432;433entry:434 br label %loop435 436loop:437 br i1 %c2, label %if, label %latch438 439if:440 %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1441 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2442 call void @use(ptr %ptr3)443 br label %latch444 445latch:446 br i1 %c, label %loop, label %exit447 448exit:449 ret void450}451 452; Do not reassociate constant offset GEP.453define void @constant_offset(ptr %ptr, i1 %c) {454; CHECK-LABEL: define void @constant_offset455; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {456; CHECK-NEXT: entry:457; CHECK-NEXT: br label [[LOOP:%.*]]458; CHECK: loop:459; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64()460; CHECK-NEXT: [[GEP_BASE:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]]461; CHECK-NEXT: [[GEP_OFF:%.*]] = getelementptr i8, ptr [[GEP_BASE]], i64 1462; CHECK-NEXT: call void @use(ptr [[GEP_OFF]])463; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]464; CHECK: exit:465; CHECK-NEXT: ret void466;467entry:468 br label %loop469 470loop:471 %val = call i64 @get.i64()472 %gep.base = getelementptr i8, ptr %ptr, i64 %val473 %gep.off = getelementptr i8, ptr %gep.base, i64 1474 call void @use(ptr %gep.off)475 br i1 %c, label %loop, label %exit476 477exit:478 ret void479}480