587 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=sroa -S | FileCheck %s3 4declare void @callee(ptr nocapture readonly %p)5 6define i32 @simple() {7; CHECK-LABEL: @simple(8; CHECK-NEXT: [[A:%.*]] = alloca i32, align 49; CHECK-NEXT: store i32 0, ptr [[A]], align 410; CHECK-NEXT: call void @callee(ptr [[A]])11; CHECK-NEXT: ret i32 012;13 %a = alloca i3214 store i32 0, ptr %a15 call void @callee(ptr %a)16 %l1 = load i32, ptr %a17 ret i32 %l118}19 20define i32 @smallbig() {21; CHECK-LABEL: @smallbig(22; CHECK-NEXT: [[A:%.*]] = alloca i32, align 423; CHECK-NEXT: store i8 0, ptr [[A]], align 124; CHECK-NEXT: call void @callee(ptr [[A]])25; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 426; CHECK-NEXT: ret i32 [[L1]]27;28 %a = alloca i3229 store i8 0, ptr %a30 call void @callee(ptr %a)31 %l1 = load i32, ptr %a32 ret i32 %l133}34 35define i32 @twoalloc() {36; CHECK-LABEL: @twoalloc(37; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 838; CHECK-NEXT: store i32 0, ptr [[A]], align 439; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 140; CHECK-NEXT: store i32 1, ptr [[B]], align 441; CHECK-NEXT: call void @callee(ptr [[A]])42; CHECK-NEXT: [[R:%.*]] = add i32 0, 143; CHECK-NEXT: ret i32 [[R]]44;45 %a = alloca {i32, i32}46 store i32 0, ptr %a47 %b = getelementptr i32, ptr %a, i32 148 store i32 1, ptr %b49 call void @callee(ptr %a)50 %l1 = load i32, ptr %a51 %l2 = load i32, ptr %b52 %r = add i32 %l1, %l253 ret i32 %r54}55 56define i32 @twostore() {57; CHECK-LABEL: @twostore(58; CHECK-NEXT: [[A:%.*]] = alloca i32, align 459; CHECK-NEXT: store i32 1, ptr [[A]], align 460; CHECK-NEXT: call void @callee(ptr [[A]])61; CHECK-NEXT: store i32 2, ptr [[A]], align 462; CHECK-NEXT: ret i32 263;64 %a = alloca i3265 store i32 1, ptr %a66 call void @callee(ptr %a)67 store i32 2, ptr %a68 %l = load i32, ptr %a69 ret i32 %l70}71 72define float @differenttype() {73; CHECK-LABEL: @differenttype(74; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 875; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 176; CHECK-NEXT: store i32 1, ptr [[B]], align 477; CHECK-NEXT: call void @callee(ptr [[A]])78; CHECK-NEXT: [[L2:%.*]] = load float, ptr [[B]], align 479; CHECK-NEXT: ret float [[L2]]80;81 %a = alloca {i32, i32}82 %b = getelementptr i32, ptr %a, i32 183 store i32 1, ptr %b84 call void @callee(ptr %a)85 %l2 = load float, ptr %b86 ret float %l287}88 89define i32 @twoalloc_store64(i64 %x) {90; CHECK-LABEL: @twoalloc_store64(91; CHECK-NEXT: [[A:%.*]] = alloca i64, align 892; CHECK-NEXT: store i64 [[X:%.*]], ptr [[A]], align 493; CHECK-NEXT: call void @callee(ptr [[A]])94; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 495; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 196; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 497; CHECK-NEXT: ret i32 [[L2]]98;99 %a = alloca i64100 store i64 %x, ptr %a101 call void @callee(ptr %a)102 %l1 = load i32, ptr %a103 %b = getelementptr i32, ptr %a, i32 1104 %l2 = load i32, ptr %b105 ret i32 %l2106}107 108define i32 @twocalls() {109; CHECK-LABEL: @twocalls(110; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8111; CHECK-NEXT: store i32 0, ptr [[A]], align 4112; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1113; CHECK-NEXT: store i32 1, ptr [[B]], align 4114; CHECK-NEXT: call void @callee(ptr [[A]])115; CHECK-NEXT: call void @callee(ptr [[A]])116; CHECK-NEXT: [[R:%.*]] = add i32 0, 1117; CHECK-NEXT: ret i32 [[R]]118;119 %a = alloca {i32, i32}120 store i32 0, ptr %a121 %b = getelementptr i32, ptr %a, i32 1122 store i32 1, ptr %b123 call void @callee(ptr %a)124 %l1 = load i32, ptr %a125 call void @callee(ptr %a)126 %l2 = load i32, ptr %b127 %r = add i32 %l1, %l2128 ret i32 %r129}130 131define i32 @volatile() {132; CHECK-LABEL: @volatile(133; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8134; CHECK-NEXT: store i32 0, ptr [[A]], align 4135; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1136; CHECK-NEXT: store volatile i32 1, ptr [[B]], align 4137; CHECK-NEXT: call void @callee(ptr [[A]])138; CHECK-NEXT: [[L1:%.*]] = load volatile i32, ptr [[A]], align 4139; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4140; CHECK-NEXT: [[R:%.*]] = add i32 [[L1]], [[L2]]141; CHECK-NEXT: ret i32 [[R]]142;143 %a = alloca {i32, i32}144 store i32 0, ptr %a145 %b = getelementptr i32, ptr %a, i32 1146 store volatile i32 1, ptr %b147 call void @callee(ptr %a)148 %l1 = load volatile i32, ptr %a149 %l2 = load i32, ptr %b150 %r = add i32 %l1, %l2151 ret i32 %r152}153 154define i32 @atomic() {155; CHECK-LABEL: @atomic(156; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8157; CHECK-NEXT: store i32 0, ptr [[A]], align 4158; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1159; CHECK-NEXT: store i32 1, ptr [[B]], align 4160; CHECK-NEXT: call void @callee(ptr [[A]])161; CHECK-NEXT: [[L1:%.*]] = load atomic i32, ptr [[A]] seq_cst, align 4162; CHECK-NEXT: [[R:%.*]] = add i32 [[L1]], 1163; CHECK-NEXT: ret i32 [[R]]164;165 %a = alloca {i32, i32}166 store i32 0, ptr %a167 %b = getelementptr i32, ptr %a, i32 1168 store i32 1, ptr %b169 call void @callee(ptr %a)170 %l1 = load atomic i32, ptr %a seq_cst, align 4171 %l2 = load i32, ptr %b172 %r = add i32 %l1, %l2173 ret i32 %r174}175 176define i32 @notdominating() {177; CHECK-LABEL: @notdominating(178; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8179; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1180; CHECK-NEXT: store i32 0, ptr [[A]], align 4181; CHECK-NEXT: store i32 1, ptr [[B]], align 4182; CHECK-NEXT: call void @callee(ptr [[A]])183; CHECK-NEXT: [[R:%.*]] = add i32 undef, undef184; CHECK-NEXT: ret i32 [[R]]185;186 %a = alloca {i32, i32}187 %b = getelementptr i32, ptr %a, i32 1188 %l1 = load i32, ptr %a189 %l2 = load i32, ptr %b190 store i32 0, ptr %a191 store i32 1, ptr %b192 call void @callee(ptr %a)193 %r = add i32 %l1, %l2194 ret i32 %r195}196 197declare void @callee_notreadonly(ptr %p)198define i32 @notreadonly() {199; CHECK-LABEL: @notreadonly(200; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8201; CHECK-NEXT: store i32 0, ptr [[A]], align 4202; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1203; CHECK-NEXT: store i32 1, ptr [[B]], align 4204; CHECK-NEXT: call void @callee_notreadonly(ptr [[A]])205; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4206; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[B]], align 4207; CHECK-NEXT: [[R:%.*]] = add i32 [[L1]], [[L2]]208; CHECK-NEXT: ret i32 [[R]]209;210 %a = alloca {i32, i32}211 store i32 0, ptr %a212 %b = getelementptr i32, ptr %a, i32 1213 store i32 1, ptr %b214 call void @callee_notreadonly(ptr %a)215 %l1 = load i32, ptr %a216 %l2 = load i32, ptr %b217 %r = add i32 %l1, %l2218 ret i32 %r219}220 221declare void @callee_multiuse(ptr nocapture readonly %p, ptr nocapture readonly %q)222define i32 @multiuse() {223; CHECK-LABEL: @multiuse(224; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8225; CHECK-NEXT: store i32 0, ptr [[A]], align 4226; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1227; CHECK-NEXT: store i32 1, ptr [[B]], align 4228; CHECK-NEXT: call void @callee_multiuse(ptr [[A]], ptr [[A]])229; CHECK-NEXT: [[R:%.*]] = add i32 0, 1230; CHECK-NEXT: ret i32 [[R]]231;232 %a = alloca {i32, i32}233 store i32 0, ptr %a234 %b = getelementptr i32, ptr %a, i32 1235 store i32 1, ptr %b236 call void @callee_multiuse(ptr %a, ptr %a)237 %l1 = load i32, ptr %a238 %l2 = load i32, ptr %b239 %r = add i32 %l1, %l2240 ret i32 %r241}242 243define i32 @memcpyed(ptr %src) {244; CHECK-LABEL: @memcpyed(245; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4246; CHECK-NEXT: store i32 0, ptr [[A]], align 4247; CHECK-NEXT: call void @callee(ptr [[A]])248; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 4, i1 false)249; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4250; CHECK-NEXT: ret i32 [[L1]]251;252 %a = alloca i32253 store i32 0, ptr %a254 call void @callee(ptr %a)255 call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 4, i1 false)256 %l1 = load i32, ptr %a257 ret i32 %l1258}259 260define ptr @memcpyedsplit(ptr %src) {261; CHECK-LABEL: @memcpyedsplit(262; CHECK-NEXT: [[A:%.*]] = alloca { i64, i64 }, align 8263; CHECK-NEXT: store i8 1, ptr [[A]], align 1264; CHECK-NEXT: [[B:%.*]] = getelementptr i64, ptr [[A]], i32 1265; CHECK-NEXT: store ptr null, ptr [[B]], align 8266; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 16, i1 false)267; CHECK-NEXT: call void @callee(ptr [[A]])268; CHECK-NEXT: [[L1:%.*]] = load ptr, ptr [[B]], align 8269; CHECK-NEXT: ret ptr [[L1]]270;271 %a = alloca { i64, i64 }272 store i8 1, ptr %a273 %b = getelementptr i64, ptr %a, i32 1274 store ptr null, ptr %b275 call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 16, i1 false)276 call void @callee(ptr %a)277 %l1 = load ptr, ptr %b278 ret ptr %l1279}280 281; This struct contains padding bits. The load should not be replaced by poison.282%struct.LoadImmediateInfo = type { i32 }283define void @incompletestruct(i1 %b, i1 %c) {284; CHECK-LABEL: @incompletestruct(285; CHECK-NEXT: entry:286; CHECK-NEXT: [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4287; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[LII]])288; CHECK-NEXT: [[BF_CLEAR4:%.*]] = and i32 undef, -262144289; CHECK-NEXT: [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072290; CHECK-NEXT: [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]291; CHECK-NEXT: store i32 [[BF_SET12]], ptr [[LII]], align 4292; CHECK-NEXT: call void @callee(ptr [[LII]])293; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[LII]])294; CHECK-NEXT: ret void295;296entry:297 %LII = alloca %struct.LoadImmediateInfo, align 4298 call void @llvm.lifetime.start.p0(ptr nonnull %LII)299 %bf.load = load i32, ptr %LII, align 4300 %bf.clear4 = and i32 %bf.load, -262144301 %bf.set5 = select i1 %b, i32 196608, i32 131072302 %bf.set12 = or disjoint i32 %bf.set5, %bf.clear4303 store i32 %bf.set12, ptr %LII, align 4304 call void @callee(ptr %LII)305 call void @llvm.lifetime.end.p0(ptr nonnull %LII)306 ret void307}308 309define void @incompletestruct_bb(i1 %b, i1 %c) {310; CHECK-LABEL: @incompletestruct_bb(311; CHECK-NEXT: entry:312; CHECK-NEXT: [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4313; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]314; CHECK: if.then:315; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[LII]])316; CHECK-NEXT: [[BF_CLEAR4:%.*]] = and i32 undef, -262144317; CHECK-NEXT: [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072318; CHECK-NEXT: [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]319; CHECK-NEXT: store i32 [[BF_SET12]], ptr [[LII]], align 4320; CHECK-NEXT: call void @callee(ptr [[LII]])321; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[LII]])322; CHECK-NEXT: br label [[IF_END]]323; CHECK: if.end:324; CHECK-NEXT: ret void325;326entry:327 %LII = alloca %struct.LoadImmediateInfo, align 4328 br i1 %c, label %if.then, label %if.end329 330if.then: ; preds = %entry331 call void @llvm.lifetime.start.p0(ptr nonnull %LII)332 %bf.load = load i32, ptr %LII, align 4333 %bf.clear4 = and i32 %bf.load, -262144334 %bf.set5 = select i1 %b, i32 196608, i32 131072335 %bf.set12 = or disjoint i32 %bf.set5, %bf.clear4336 store i32 %bf.set12, ptr %LII, align 4337 call void @callee(ptr %LII)338 call void @llvm.lifetime.end.p0(ptr nonnull %LII)339 br label %if.end340 341if.end: ; preds = %if.then, %entry342 ret void343}344 345define i32 @sixteenload() {346; CHECK-LABEL: @sixteenload(347; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4348; CHECK-NEXT: store i32 0, ptr [[A]], align 4349; CHECK-NEXT: call void @callee(ptr [[A]])350; CHECK-NEXT: [[A1:%.*]] = add i32 0, 0351; CHECK-NEXT: [[A2:%.*]] = add i32 [[A1]], 0352; CHECK-NEXT: ret i32 [[A2]]353;354 %a = alloca i32355 store i32 0, ptr %a356 call void @callee(ptr %a)357 %l1 = load i32, ptr %a358 %l2 = load i32, ptr %a359 %l3 = load i32, ptr %a360 %l4 = load i32, ptr %a361 %l5 = load i32, ptr %a362 %l6 = load i32, ptr %a363 %l7 = load i32, ptr %a364 %l8 = load i32, ptr %a365 %l9 = load i32, ptr %a366 %l10 = load i32, ptr %a367 %l11 = load i32, ptr %a368 %l12 = load i32, ptr %a369 %l13 = load i32, ptr %a370 %l14 = load i32, ptr %a371 %l15 = load i32, ptr %a372 %l16 = load i32, ptr %a373 %a1 = add i32 %l1, %l2374 %a2 = add i32 %a1, %l3375 ret i32 %a2376}377 378define i32 @testcallalloca() {379; CHECK-LABEL: @testcallalloca(380; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4381; CHECK-NEXT: store i32 0, ptr [[A]], align 4382; CHECK-NEXT: call void [[A]]()383; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4384; CHECK-NEXT: ret i32 [[L1]]385;386 %a = alloca i32387 store i32 0, ptr %a388 call void %a()389 %l1 = load i32, ptr %a390 ret i32 %l1391}392 393declare void @callee_byval(ptr byval(i32) %p)394 395define i32 @simple_byval() {396; CHECK-LABEL: @simple_byval(397; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4398; CHECK-NEXT: store i32 0, ptr [[A]], align 4399; CHECK-NEXT: call void @callee_byval(ptr [[A]])400; CHECK-NEXT: ret i32 0401;402 %a = alloca i32403 store i32 0, ptr %a404 call void @callee_byval(ptr %a)405 %l1 = load i32, ptr %a406 ret i32 %l1407}408 409declare void @callee_address_only_capture(ptr readonly captures(address) %p)410 411define i32 @address_only_capture() {412; CHECK-LABEL: @address_only_capture(413; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4414; CHECK-NEXT: store i32 0, ptr [[A]], align 4415; CHECK-NEXT: call void @callee_address_only_capture(ptr [[A]])416; CHECK-NEXT: ret i32 0417;418 %a = alloca i32419 store i32 0, ptr %a420 call void @callee_address_only_capture(ptr %a)421 %l1 = load i32, ptr %a422 ret i32 %l1423}424 425declare void @callee_read_only_capture(ptr readonly captures(address, read_provenance) %p)426 427define i32 @read_only_capture() {428; CHECK-LABEL: @read_only_capture(429; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4430; CHECK-NEXT: store i32 0, ptr [[A]], align 4431; CHECK-NEXT: call void @callee_read_only_capture(ptr [[A]])432; CHECK-NEXT: ret i32 0433;434 %a = alloca i32435 store i32 0, ptr %a436 call void @callee_read_only_capture(ptr %a)437 %l1 = load i32, ptr %a438 ret i32 %l1439}440 441declare void @callee_provenance_only_capture(ptr readonly captures(provenance) %p)442 443; Should not be transformed, as write-provenance is captured.444define i32 @provenance_only_capture() {445; CHECK-LABEL: @provenance_only_capture(446; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4447; CHECK-NEXT: store i32 0, ptr [[A]], align 4448; CHECK-NEXT: call void @callee_provenance_only_capture(ptr [[A]])449; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[A]], align 4450; CHECK-NEXT: ret i32 [[L1]]451;452 %a = alloca i32453 store i32 0, ptr %a454 call void @callee_provenance_only_capture(ptr %a)455 %l1 = load i32, ptr %a456 ret i32 %l1457}458 459define i32 @simple_with_lifetimes() {460; CHECK-LABEL: @simple_with_lifetimes(461; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4462; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A]])463; CHECK-NEXT: store i32 0, ptr [[A]], align 4464; CHECK-NEXT: call void @callee(ptr [[A]])465; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A]])466; CHECK-NEXT: ret i32 0467;468 %a = alloca i32469 call void @llvm.lifetime.start(ptr %a)470 store i32 0, ptr %a471 call void @callee(ptr %a)472 %l1 = load i32, ptr %a473 call void @llvm.lifetime.end(ptr %a)474 ret i32 %l1475}476 477define i32 @twoalloc_with_lifetimes() {478; CHECK-LABEL: @twoalloc_with_lifetimes(479; CHECK-NEXT: [[A:%.*]] = alloca { i32, i32 }, align 8480; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A]])481; CHECK-NEXT: store i32 0, ptr [[A]], align 4482; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1483; CHECK-NEXT: store i32 1, ptr [[B]], align 4484; CHECK-NEXT: call void @callee(ptr [[A]])485; CHECK-NEXT: [[R:%.*]] = add i32 0, 1486; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A]])487; CHECK-NEXT: ret i32 [[R]]488;489 %a = alloca {i32, i32}490 call void @llvm.lifetime.start(ptr %a)491 store i32 0, ptr %a492 %b = getelementptr i32, ptr %a, i32 1493 store i32 1, ptr %b494 call void @callee(ptr %a)495 %l1 = load i32, ptr %a496 %l2 = load i32, ptr %b497 %r = add i32 %l1, %l2498 call void @llvm.lifetime.end(ptr %a)499 ret i32 %r500}501 502declare void @use.i32(i32)503 504; We can promote the %i load, even though there is an unknown offset load505; in the loop. It is sufficient that we know all stores.506define void @load_dyn_offset(ptr %ary) {507; CHECK-LABEL: @load_dyn_offset(508; CHECK-NEXT: [[A:%.*]] = alloca { i64, [4 x i32] }, align 8509; CHECK-NEXT: store i64 0, ptr [[A]], align 4510; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 8511; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[GEP]], ptr [[ARY:%.*]], i64 16, i1 false)512; CHECK-NEXT: br label [[LOOP:%.*]]513; CHECK: loop:514; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[TMP0:%.*]] ]515; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1516; CHECK-NEXT: store i64 [[I_NEXT]], ptr [[A]], align 4517; CHECK-NEXT: [[GEP_I:%.*]] = getelementptr i32, ptr [[GEP]], i64 [[I]]518; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[GEP_I]], align 4519; CHECK-NEXT: call void @use.i32(i32 [[VAL]])520; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[I_NEXT]], 6521; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]522; CHECK: exit:523; CHECK-NEXT: ret void524;525 %a = alloca {i64, [4 x i32]}526 store i64 0, ptr %a527 %gep = getelementptr i8, ptr %a, i64 8528 call void @llvm.memcpy(ptr %gep, ptr %ary, i64 16, i1 false)529 br label %loop530 531loop:532 %i = load i64, ptr %a533 %i.next = add i64 %i, 1534 store i64 %i.next, ptr %a535 %gep.i = getelementptr i32, ptr %gep, i64 %i536 %val = load i32, ptr %gep.i537 call void @use.i32(i32 %val)538 %cmp = icmp eq i64 %i.next, 6539 br i1 %cmp, label %exit, label %loop540 541exit:542 ret void543}544 545; Same as previous test, but with an unknown-offset store. We can't promote in546; that case.547define void @store_dyn_offset(ptr %ary) {548; CHECK-LABEL: @store_dyn_offset(549; CHECK-NEXT: [[A:%.*]] = alloca { i64, [4 x i32] }, align 8550; CHECK-NEXT: store i64 0, ptr [[A]], align 4551; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 8552; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[GEP]], ptr [[ARY:%.*]], i64 16, i1 false)553; CHECK-NEXT: br label [[LOOP:%.*]]554; CHECK: loop:555; CHECK-NEXT: [[I:%.*]] = load i64, ptr [[A]], align 4556; CHECK-NEXT: [[I_NEXT:%.*]] = add i64 [[I]], 1557; CHECK-NEXT: store i64 [[I_NEXT]], ptr [[A]], align 4558; CHECK-NEXT: [[GEP_I:%.*]] = getelementptr i32, ptr [[GEP]], i64 [[I]]559; CHECK-NEXT: [[I_TRUNC:%.*]] = trunc i64 [[I]] to i32560; CHECK-NEXT: store i32 [[I_TRUNC]], ptr [[GEP_I]], align 4561; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[I_NEXT]], 6562; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]563; CHECK: exit:564; CHECK-NEXT: ret void565;566 %a = alloca {i64, [4 x i32]}567 store i64 0, ptr %a568 %gep = getelementptr i8, ptr %a, i64 8569 call void @llvm.memcpy(ptr %gep, ptr %ary, i64 16, i1 false)570 br label %loop571 572loop:573 %i = load i64, ptr %a574 %i.next = add i64 %i, 1575 store i64 %i.next, ptr %a576 %gep.i = getelementptr i32, ptr %gep, i64 %i577 %i.trunc = trunc i64 %i to i32578 store i32 %i.trunc, ptr %gep.i579 %cmp = icmp eq i64 %i.next, 6580 br i1 %cmp, label %exit, label %loop581 582exit:583 ret void584}585 586declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)587