xref: /llvm-project/llvm/test/Transforms/SROA/invariant-group.ll (revision 2d69827c5c754f0eca98e497ecf0e52ed54b4fd3)
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