1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes='sroa<preserve-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG 3; RUN: opt -passes='sroa<modify-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG 4 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: [[SV1:%.*]] = call i32 @somevalue() 15; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue() 16; CHECK-NEXT: call void @h(i32 [[SV1]]) 17; CHECK-NEXT: call void @h(i32 [[SV2]]) 18; CHECK-NEXT: ret void 19; 20 %a = alloca %t 21 22 %a1_i8_inv = call ptr @llvm.launder.invariant.group.p0(ptr %a) 23 %a2 = getelementptr inbounds %t, ptr %a, i32 0, i32 1 24 25 %sv1 = call i32 @somevalue() 26 %sv2 = call i32 @somevalue() 27 28 store i32 %sv1, ptr %a1_i8_inv, !invariant.group !0 29 store i32 %sv2, ptr %a2 30 31 %v1 = load i32, ptr %a1_i8_inv, !invariant.group !0 32 %v2 = load i32, ptr %a2 33 34 call void @h(i32 %v1) 35 call void @h(i32 %v2) 36 37 ret void 38} 39 40define void @g() { 41; CHECK-LABEL: @g( 42; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 8 43; CHECK-NEXT: [[A1_I8_INV:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[A]]) 44; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i32 0, i32 1 45; CHECK-NEXT: [[SV1:%.*]] = call i32 @somevalue() 46; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue() 47; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0:![0-9]+]] 48; CHECK-NEXT: store i32 [[SV2]], ptr [[A2]], align 4 49; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]] 50; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[A2]], align 4 51; CHECK-NEXT: call void @h(i32 [[V1]]) 52; CHECK-NEXT: call void @h(i32 [[V2]]) 53; CHECK-NEXT: [[A1_STRIPPED:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[A]]) 54; CHECK-NEXT: [[A1_INT:%.*]] = ptrtoint ptr [[A1_STRIPPED]] to i32 55; CHECK-NEXT: call void @h(i32 [[A1_INT]]) 56; CHECK-NEXT: ret void 57; 58 %a = alloca %t 59 60 %a1_i8_inv = call ptr @llvm.launder.invariant.group.p0(ptr %a) 61 %a2 = getelementptr inbounds %t, ptr %a, i32 0, i32 1 62 63 %sv1 = call i32 @somevalue() 64 %sv2 = call i32 @somevalue() 65 66 store i32 %sv1, ptr %a1_i8_inv, !invariant.group !0 67 store i32 %sv2, ptr %a2 68 69 %v1 = load i32, ptr %a1_i8_inv, !invariant.group !0 70 %v2 = load i32, ptr %a2 71 72 call void @h(i32 %v1) 73 call void @h(i32 %v2) 74 75 %a1_stripped = call ptr @llvm.strip.invariant.group.p0(ptr %a) 76 %a1_int = ptrtoint ptr %a1_stripped to i32 77 call void @h(i32 %a1_int) 78 79 ret void 80} 81 82define void @store_and_launder() { 83; CHECK-LABEL: @store_and_launder( 84; CHECK-NEXT: ret void 85; 86 %valptr = alloca i32, align 4 87 store i32 0, ptr %valptr, align 4 88 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr) 89 ret void 90} 91 92define i32 @launder_and_load() { 93; CHECK-LABEL: @launder_and_load( 94; CHECK-NEXT: ret i32 undef 95; 96 %valptr = alloca i32, align 4 97 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr) 98 %v2 = load i32, ptr %valptr 99 ret i32 %v2 100} 101 102define void @launder_and_ptr_arith() { 103; CHECK-LABEL: @launder_and_ptr_arith( 104; CHECK-NEXT: ret void 105; 106 %valptr = alloca i32, align 4 107 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr) 108 %a2 = getelementptr inbounds i32, ptr %valptr, i32 0 109 ret void 110} 111 112define void @partial_use_of_alloca() { 113; CHECK-LABEL: @partial_use_of_alloca( 114; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4 115; CHECK-NEXT: store i32 0, ptr [[VALPTR]], align 4 116; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]]) 117; CHECK-NEXT: [[LOAD_VAL:%.*]] = load i32, ptr [[VALPTR]], align 4 118; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[LOAD_VAL]], 0 119; CHECK-NEXT: br i1 [[COND]], label [[USE_ALLOCA:%.*]], label [[END:%.*]] 120; CHECK: use_alloca: 121; CHECK-NEXT: call void @use(ptr nonnull [[VALPTR]]) 122; CHECK-NEXT: br label [[END]] 123; CHECK: end: 124; CHECK-NEXT: ret void 125; 126 %valptr = alloca i32, align 4 127 store i32 0, ptr %valptr, align 4 128 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr) 129 %load_val = load i32, ptr %valptr, align 4 130 %cond = icmp eq i32 %load_val, 0 131 br i1 %cond, label %use_alloca, label %end 132 133use_alloca: 134 call void @use(ptr nonnull %valptr) 135 br label %end 136 137end: 138 ret void 139} 140 141define void @partial_promotion_of_alloca() { 142; CHECK-LABEL: @partial_promotion_of_alloca( 143; CHECK-NEXT: [[STRUCT_PTR_SROA_2:%.*]] = alloca i32, align 4 144; CHECK-NEXT: store volatile i32 0, ptr [[STRUCT_PTR_SROA_2]], align 4 145; CHECK-NEXT: [[STRUCT_PTR_SROA_2_0_STRUCT_PTR_SROA_2_4_LOAD_VAL:%.*]] = load volatile i32, ptr [[STRUCT_PTR_SROA_2]], align 4 146; CHECK-NEXT: ret void 147; 148 %struct_ptr = alloca %t, align 4 149 %field_ptr = getelementptr inbounds %t, ptr %struct_ptr, i32 0, i32 0 150 store i32 0, ptr %field_ptr, align 4 151 %volatile_field_ptr = getelementptr inbounds %t, ptr %struct_ptr, i32 0, i32 1 152 store volatile i32 0, ptr %volatile_field_ptr, align 4, !invariant.group !0 153 %barr = call ptr @llvm.launder.invariant.group.p0(ptr %struct_ptr) 154 %load_val = load volatile i32, ptr %volatile_field_ptr, align 4, !invariant.group !0 155 ret void 156} 157 158declare void @use(ptr) 159 160!0 = !{} 161;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: 162; CHECK-MODIFY-CFG: {{.*}} 163; CHECK-PRESERVE-CFG: {{.*}} 164