239 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes='sroa<preserve-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG3; RUN: opt -passes='sroa<modify-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG4 5%t = type { i32, i32 }6 7declare ptr @llvm.launder.invariant.group.p0(ptr %a)8declare ptr @llvm.strip.invariant.group.p0(ptr %a)9declare void @h(i32 %a)10declare i32 @somevalue()11 12define void @f() {13; CHECK-LABEL: @f(14; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 815; CHECK-NEXT: [[A1_I8_INV:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[A]])16; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i32 0, i32 117; CHECK-NEXT: [[SV1:%.*]] = call i32 @somevalue()18; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue()19; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0:![0-9]+]]20; CHECK-NEXT: store i32 [[SV2]], ptr [[A2]], align 421; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]22; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[A2]], align 423; CHECK-NEXT: call void @h(i32 [[V1]])24; CHECK-NEXT: call void @h(i32 [[V2]])25; CHECK-NEXT: ret void26;27 %a = alloca %t28 29 %a1_i8_inv = call ptr @llvm.launder.invariant.group.p0(ptr %a)30 %a2 = getelementptr inbounds %t, ptr %a, i32 0, i32 131 32 %sv1 = call i32 @somevalue()33 %sv2 = call i32 @somevalue()34 35 store i32 %sv1, ptr %a1_i8_inv, !invariant.group !036 store i32 %sv2, ptr %a237 38 %v1 = load i32, ptr %a1_i8_inv, !invariant.group !039 %v2 = load i32, ptr %a240 41 call void @h(i32 %v1)42 call void @h(i32 %v2)43 44 ret void45}46 47define void @g() {48; CHECK-LABEL: @g(49; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 850; CHECK-NEXT: [[A1_I8_INV:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[A]])51; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i32 0, i32 152; CHECK-NEXT: [[SV1:%.*]] = call i32 @somevalue()53; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue()54; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]55; CHECK-NEXT: store i32 [[SV2]], ptr [[A2]], align 456; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]57; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[A2]], align 458; CHECK-NEXT: call void @h(i32 [[V1]])59; CHECK-NEXT: call void @h(i32 [[V2]])60; CHECK-NEXT: [[A1_STRIPPED:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[A]])61; CHECK-NEXT: [[A1_INT:%.*]] = ptrtoint ptr [[A1_STRIPPED]] to i3262; CHECK-NEXT: call void @h(i32 [[A1_INT]])63; CHECK-NEXT: ret void64;65 %a = alloca %t66 67 %a1_i8_inv = call ptr @llvm.launder.invariant.group.p0(ptr %a)68 %a2 = getelementptr inbounds %t, ptr %a, i32 0, i32 169 70 %sv1 = call i32 @somevalue()71 %sv2 = call i32 @somevalue()72 73 store i32 %sv1, ptr %a1_i8_inv, !invariant.group !074 store i32 %sv2, ptr %a275 76 %v1 = load i32, ptr %a1_i8_inv, !invariant.group !077 %v2 = load i32, ptr %a278 79 call void @h(i32 %v1)80 call void @h(i32 %v2)81 82 %a1_stripped = call ptr @llvm.strip.invariant.group.p0(ptr %a)83 %a1_int = ptrtoint ptr %a1_stripped to i3284 call void @h(i32 %a1_int)85 86 ret void87}88 89define void @store_and_launder() {90; CHECK-LABEL: @store_and_launder(91; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 492; CHECK-NEXT: store i32 0, ptr [[VALPTR]], align 493; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])94; CHECK-NEXT: ret void95;96 %valptr = alloca i32, align 497 store i32 0, ptr %valptr, align 498 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr)99 ret void100}101 102define i32 @launder_and_load() {103; CHECK-LABEL: @launder_and_load(104; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4105; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])106; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[VALPTR]], align 4107; CHECK-NEXT: ret i32 [[V2]]108;109 %valptr = alloca i32, align 4110 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr)111 %v2 = load i32, ptr %valptr112 ret i32 %v2113}114 115define void @launder_and_ptr_arith() {116; CHECK-LABEL: @launder_and_ptr_arith(117; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4118; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])119; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i32, ptr [[VALPTR]], i32 0120; CHECK-NEXT: ret void121;122 %valptr = alloca i32, align 4123 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr)124 %a2 = getelementptr inbounds i32, ptr %valptr, i32 0125 ret void126}127 128define void @partial_use_of_alloca() {129; CHECK-LABEL: @partial_use_of_alloca(130; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4131; CHECK-NEXT: store i32 0, ptr [[VALPTR]], align 4132; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])133; CHECK-NEXT: [[LOAD_VAL:%.*]] = load i32, ptr [[VALPTR]], align 4134; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[LOAD_VAL]], 0135; CHECK-NEXT: br i1 [[COND]], label [[USE_ALLOCA:%.*]], label [[END:%.*]]136; CHECK: use_alloca:137; CHECK-NEXT: call void @use(ptr nonnull [[VALPTR]])138; CHECK-NEXT: br label [[END]]139; CHECK: end:140; CHECK-NEXT: ret void141;142 %valptr = alloca i32, align 4143 store i32 0, ptr %valptr, align 4144 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr)145 %load_val = load i32, ptr %valptr, align 4146 %cond = icmp eq i32 %load_val, 0147 br i1 %cond, label %use_alloca, label %end148 149use_alloca:150 call void @use(ptr nonnull %valptr)151 br label %end152 153end:154 ret void155}156 157define void @partial_promotion_of_alloca() {158; CHECK-LABEL: @partial_promotion_of_alloca(159; CHECK-NEXT: [[STRUCT_PTR:%.*]] = alloca [[T:%.*]], align 4160; CHECK-NEXT: [[FIELD_PTR:%.*]] = getelementptr inbounds [[T]], ptr [[STRUCT_PTR]], i32 0, i32 0161; CHECK-NEXT: store i32 0, ptr [[FIELD_PTR]], align 4162; CHECK-NEXT: [[VOLATILE_FIELD_PTR:%.*]] = getelementptr inbounds [[T]], ptr [[STRUCT_PTR]], i32 0, i32 1163; CHECK-NEXT: store volatile i32 0, ptr [[VOLATILE_FIELD_PTR]], align 4, !invariant.group [[META0]]164; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[STRUCT_PTR]])165; CHECK-NEXT: [[LOAD_VAL:%.*]] = load volatile i32, ptr [[VOLATILE_FIELD_PTR]], align 4, !invariant.group [[META0]]166; CHECK-NEXT: ret void167;168 %struct_ptr = alloca %t, align 4169 %field_ptr = getelementptr inbounds %t, ptr %struct_ptr, i32 0, i32 0170 store i32 0, ptr %field_ptr, align 4171 %volatile_field_ptr = getelementptr inbounds %t, ptr %struct_ptr, i32 0, i32 1172 store volatile i32 0, ptr %volatile_field_ptr, align 4, !invariant.group !0173 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %struct_ptr)174 %load_val = load volatile i32, ptr %volatile_field_ptr, align 4, !invariant.group !0175 ret void176}177 178define void @memcpy_after_laundering_alloca(ptr %ptr) {179; CHECK-LABEL: @memcpy_after_laundering_alloca(180; CHECK-NEXT: [[ALLOCA:%.*]] = alloca { i64, i64 }, align 8181; CHECK-NEXT: [[LAUNDER:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[ALLOCA]])182; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[LAUNDER]], ptr [[PTR:%.*]], i64 16, i1 false)183; CHECK-NEXT: ret void184;185 %alloca = alloca { i64, i64 }, align 8186 %launder = call ptr @llvm.launder.invariant.group.p0(ptr %alloca)187 call void @llvm.memcpy.p0.p0.i64(ptr %launder, ptr %ptr, i64 16, i1 false)188 ret void189}190 191define void @memcpy_after_laundering_alloca_slices(ptr %ptr) {192; CHECK-LABEL: @memcpy_after_laundering_alloca_slices(193; CHECK-NEXT: [[ALLOCA:%.*]] = alloca { [16 x i8], i64, [16 x i8] }, align 8194; CHECK-NEXT: [[LAUNDER:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[ALLOCA]])195; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[LAUNDER]], i64 16196; CHECK-NEXT: store i64 0, ptr [[GEP]], align 4197; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[LAUNDER]], ptr [[PTR:%.*]], i64 40, i1 false)198; CHECK-NEXT: ret void199;200 %alloca = alloca { [16 x i8], i64, [16 x i8] }, align 8201 %launder = call ptr @llvm.launder.invariant.group.p0(ptr %alloca)202 %gep = getelementptr i8, ptr %launder, i64 16203 store i64 0, ptr %gep204 call void @llvm.memcpy.p0.p0.i64(ptr %launder, ptr %ptr, i64 40, i1 false)205 ret void206}207 208define void @test_agg_store() {209; CHECK-LABEL: @test_agg_store(210; CHECK-NEXT: [[STRUCT_PTR:%.*]] = alloca [[T:%.*]], i64 1, align 4211; CHECK-NEXT: [[STRUCT_PTR_FRESH:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[STRUCT_PTR]])212; CHECK-NEXT: [[STRUCT:%.*]] = call [[T]] @[[MAKE_T:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]]()213; CHECK-NEXT: store [[T]] [[STRUCT]], ptr [[STRUCT_PTR_FRESH]], align 4, !invariant.group [[META0]]214; CHECK-NEXT: [[FIRST_PTR:%.*]] = getelementptr [[T]], ptr [[STRUCT_PTR_FRESH]], i32 0, i32 0215; CHECK-NEXT: [[FIRST:%.*]] = load i32, ptr [[FIRST_PTR]], align 4216; CHECK-NEXT: [[SECOND_PTR:%.*]] = getelementptr [[T]], ptr [[STRUCT_PTR_FRESH]], i32 0, i32 1217; CHECK-NEXT: [[SECOND:%.*]] = load i32, ptr [[SECOND_PTR]], align 4218; CHECK-NEXT: ret void219;220 %struct_ptr = alloca %t, i64 1, align 4221 %struct_ptr_fresh = call ptr @llvm.launder.invariant.group.p0(ptr %struct_ptr)222 %struct = call %t @make_t()223 store %t %struct, ptr %struct_ptr_fresh, align 4, !invariant.group !0224 %first_ptr = getelementptr %t, ptr %struct_ptr_fresh, i32 0, i32 0225 %first = load i32, ptr %first_ptr, align 4226 %second_ptr = getelementptr %t, ptr %struct_ptr_fresh, i32 0, i32 1227 %second = load i32, ptr %second_ptr, align 4228 ret void229}230 231declare %t @make_t()232 233declare void @use(ptr)234 235!0 = !{}236;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:237; CHECK-MODIFY-CFG: {{.*}}238; CHECK-PRESERVE-CFG: {{.*}}239