OLD | NEW |
1 ; RUN: opt %s -expand-struct-regs -S | FileCheck %s | 1 ; RUN: opt %s -expand-struct-regs -S | FileCheck %s |
2 ; RUN: opt %s -expand-struct-regs -S | FileCheck %s -check-prefix=CLEANUP | 2 ; RUN: opt %s -expand-struct-regs -S | FileCheck %s -check-prefix=CLEANUP |
3 | 3 |
4 ; These two instructions should not appear in the output: | 4 ; These two instructions should not appear in the output: |
5 ; CLEANUP-NOT: extractvalue | 5 ; CLEANUP-NOT: extractvalue |
6 ; CLEANUP-NOT: insertvalue | 6 ; CLEANUP-NOT: insertvalue |
7 | 7 |
| 8 target datalayout = "p:32:32:32" |
| 9 |
8 %struct = type { i8, i32 } | 10 %struct = type { i8, i32 } |
9 | 11 |
10 | 12 |
11 define void @struct_load(%struct* %p, i8* %out0, i32* %out1) { | 13 define void @struct_load(%struct* %p, i8* %out0, i32* %out1) { |
12 %val = load %struct* %p | 14 %val = load %struct* %p |
13 %field0 = extractvalue %struct %val, 0 | 15 %field0 = extractvalue %struct %val, 0 |
14 %field1 = extractvalue %struct %val, 1 | 16 %field1 = extractvalue %struct %val, 1 |
15 store i8 %field0, i8* %out0 | 17 store i8 %field0, i8* %out0 |
16 store i32 %field1, i32* %out1 | 18 store i32 %field1, i32* %out1 |
17 ret void | 19 ret void |
18 } | 20 } |
19 ; CHECK: define void @struct_load | 21 ; CHECK: define void @struct_load |
20 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %p, i32 0, i32 0 | 22 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %p, i32 0, i32 0 |
21 ; CHECK-NEXT: %val.field{{.*}} = load i8* %val.index{{.*}}, align 1 | 23 ; CHECK-NEXT: %val.field{{.*}} = load i8* %val.index{{.*}} |
22 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %p, i32 0, i32 1 | 24 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %p, i32 0, i32 1 |
23 ; CHECK-NEXT: %val.field{{.*}} = load i32* %val.index{{.*}}, align 1 | 25 ; CHECK-NEXT: %val.field{{.*}} = load i32* %val.index{{.*}} |
24 ; CHECK-NEXT: store i8 %val.field{{.*}}, i8* %out0 | 26 ; CHECK-NEXT: store i8 %val.field{{.*}}, i8* %out0 |
25 ; CHECK-NEXT: store i32 %val.field{{.*}}, i32* %out1 | 27 ; CHECK-NEXT: store i32 %val.field{{.*}}, i32* %out1 |
26 | 28 |
27 | 29 |
28 define void @struct_store(%struct* %in_ptr, %struct* %out_ptr) { | 30 define void @struct_store(%struct* %in_ptr, %struct* %out_ptr) { |
29 %val = load %struct* %in_ptr | 31 %val = load %struct* %in_ptr |
30 store %struct %val, %struct* %out_ptr | 32 store %struct %val, %struct* %out_ptr |
31 ret void | 33 ret void |
32 } | 34 } |
33 ; CHECK: define void @struct_store | 35 ; CHECK: define void @struct_store |
34 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %in_ptr, i32 0, i32 0 | 36 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %in_ptr, i32 0, i32 0 |
35 ; CHECK-NEXT: %val.field{{.*}} = load i8* %val.index{{.*}}, align 1 | 37 ; CHECK-NEXT: %val.field{{.*}} = load i8* %val.index{{.*}} |
36 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %in_ptr, i32 0, i32 1 | 38 ; CHECK-NEXT: %val.index{{.*}} = getelementptr %struct* %in_ptr, i32 0, i32 1 |
37 ; CHECK-NEXT: %val.field{{.*}} = load i32* %val.index{{.*}}, align 1 | 39 ; CHECK-NEXT: %val.field{{.*}} = load i32* %val.index{{.*}} |
38 ; CHECK-NEXT: %out_ptr.index{{.*}} = getelementptr %struct* %out_ptr, i32 0, i32
0 | 40 ; CHECK-NEXT: %out_ptr.index{{.*}} = getelementptr %struct* %out_ptr, i32 0, i32
0 |
39 ; CHECK-NEXT: store i8 %val.field{{.*}}, i8* %out_ptr.index{{.*}}, align 1 | 41 ; CHECK-NEXT: store i8 %val.field{{.*}}, i8* %out_ptr.index{{.*}} |
40 ; CHECK-NEXT: %out_ptr.index{{.*}} = getelementptr %struct* %out_ptr, i32 0, i32
1 | 42 ; CHECK-NEXT: %out_ptr.index{{.*}} = getelementptr %struct* %out_ptr, i32 0, i32
1 |
41 ; CHECK-NEXT: store i32 %val.field{{.*}}, i32* %out_ptr.index{{.*}}, align 1 | 43 ; CHECK-NEXT: store i32 %val.field{{.*}}, i32* %out_ptr.index{{.*}} |
42 | 44 |
43 | 45 |
44 ; Ensure that the pass works correctly across basic blocks. | 46 ; Ensure that the pass works correctly across basic blocks. |
45 define void @across_basic_block(%struct* %in_ptr, %struct* %out_ptr) { | 47 define void @across_basic_block(%struct* %in_ptr, %struct* %out_ptr) { |
46 %val = load %struct* %in_ptr | 48 %val = load %struct* %in_ptr |
47 br label %bb | 49 br label %bb |
48 bb: | 50 bb: |
49 store %struct %val, %struct* %out_ptr | 51 store %struct %val, %struct* %out_ptr |
50 ret void | 52 ret void |
51 } | 53 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 ; CHECK-NEXT: store i32 200, i32* %out1 | 119 ; CHECK-NEXT: store i32 200, i32* %out1 |
118 ; CHECK-NEXT: ret void | 120 ; CHECK-NEXT: ret void |
119 | 121 |
120 | 122 |
121 define i32 @extract_from_constant() { | 123 define i32 @extract_from_constant() { |
122 %ev = extractvalue %struct { i8 99, i32 888 }, 1 | 124 %ev = extractvalue %struct { i8 99, i32 888 }, 1 |
123 ret i32 %ev | 125 ret i32 %ev |
124 } | 126 } |
125 ; CHECK: define i32 @extract_from_constant() { | 127 ; CHECK: define i32 @extract_from_constant() { |
126 ; CHECK-NEXT: ret i32 888 | 128 ; CHECK-NEXT: ret i32 888 |
| 129 |
| 130 define void @nested_structs() { |
| 131 %a1 = alloca i64 |
| 132 %a2 = alloca i32 |
| 133 %a3 = alloca { { i32, i64 } } |
| 134 %a = insertvalue { i32, i64 } undef, i32 5, 0 |
| 135 %b = insertvalue { i32, i64 } %a, i64 6, 1 |
| 136 %c = insertvalue { { i32, i64 } } undef, { i32, i64 } %b, 0 |
| 137 %d = insertvalue { { { i32, i64 } }, i64 } undef, { { i32, i64 } } %c, 0 |
| 138 %e = insertvalue { { { i32, i64 } }, i64 } undef, { i32, i64 } %b, 0, 0 |
| 139 |
| 140 %f = extractvalue { { { i32, i64 } }, i64 } %d, 0, 0, 1 |
| 141 %g = extractvalue { { { i32, i64 } }, i64 } %e, 0, 0, 0 |
| 142 %h = extractvalue { { { i32, i64 } }, i64 } %e, 0 |
| 143 store i64 %f, i64* %a1 |
| 144 store i32 %g, i32* %a2 |
| 145 store { { i32, i64 } } %h, { { i32, i64 } }* %a3 |
| 146 ret void |
| 147 } |
| 148 ; CHECK-LABEL: define void @nested_structs() |
| 149 ; CHECK-NEXT: %a1 = alloca i64 |
| 150 ; CHECK-NEXT: %a2 = alloca i32 |
| 151 ; CHECK-NEXT: %a3 = alloca { { i32, i64 } } |
| 152 ; CHECK-NEXT: store i64 6, i64* %a1 |
| 153 ; CHECK-NEXT: store i32 5, i32* %a2 |
| 154 ; CHECK-NEXT: %a3.index = getelementptr { { i32, i64 } }* %a3, i32 0, i32 0 |
| 155 ; CHECK-NEXT: %a3.index.index = getelementptr { i32, i64 }* %a3.index, i32 0,
i32 0 |
| 156 ; CHECK-NEXT: store i32 5, i32* %a3.index.index |
| 157 ; CHECK-NEXT: %a3.index.index1 = getelementptr { i32, i64 }* %a3.index, i32 0
, i32 1 |
| 158 ; CHECK-NEXT: store i64 6, i64* %a3.index.index1 |
| 159 |
| 160 define void @load_another_pass() { |
| 161 %a = alloca { { i8, i64 } } |
| 162 %b = load { { i8, i64 } }* %a |
| 163 %c = load { { i8, i64 } }* %a, align 16 |
| 164 ret void |
| 165 } |
| 166 ; CHECK-LABEL: define void @load_another_pass() |
| 167 ; CHECK: %b.field.field = load i8* %b.field.index |
| 168 ; CHECK: %b.field.field{{.*}} = load i64* %b.field.index{{.*}} |
| 169 ; CHECK: %c.field.field = load i8* %c.field.index, align 16 |
| 170 ; CHECK: %c.field.field{{.*}} = load i64* %c.field.index{{.*}}, align 4 |
| 171 |
| 172 define void @store_another_pass() { |
| 173 %a = alloca { { i16, i64 } } |
| 174 store { { i16, i64 } } undef, { { i16, i64 } }* %a |
| 175 store { { i16, i64 } } undef, { { i16, i64 } }* %a, align 16 |
| 176 ret void |
| 177 } |
| 178 ; CHECK-LABEL: define void @store_another_pass() |
| 179 ; CHECK: store i16 undef, i16* %a.index.index |
| 180 ; CHECK: store i64 undef, i64* %a.index.index{{.*}} |
| 181 ; CHECK: store i16 undef, i16* %a.index1.index, align 16 |
| 182 ; CHECK: store i64 undef, i64* %a.index1.index{{.*}}, align 4 |
| 183 |
| 184 define void @select_another_pass() { |
| 185 %a = load { { i8, i64 } }* null |
| 186 %b = load { { i8, i64 } }* null |
| 187 %c = select i1 undef, { { i8, i64 } } %a, { { i8, i64 } } %b |
| 188 store { { i8, i64 } } %c, { { i8, i64 } }* null |
| 189 ret void |
| 190 } |
| 191 ; CHECK-LABEL: define void @select_another_pass() |
| 192 ; CHECK-NEXT: %a.index = getelementptr { { i8, i64 } }* null, i32 0, i32 0 |
| 193 ; CHECK-NEXT: %a.field.index = getelementptr { i8, i64 }* %a.index, i32 0, i3
2 0 |
| 194 ; CHECK-NEXT: %a.field.field = load i8* %a.field.index |
| 195 ; CHECK-NEXT: %a.field.index2 = getelementptr { i8, i64 }* %a.index, i32 0, i
32 1 |
| 196 ; CHECK-NEXT: %a.field.field3 = load i64* %a.field.index2 |
| 197 ; CHECK-NEXT: %b.index = getelementptr { { i8, i64 } }* null, i32 0, i32 0 |
| 198 ; CHECK-NEXT: %b.field.index = getelementptr { i8, i64 }* %b.index, i32 0, i3
2 0 |
| 199 ; CHECK-NEXT: %b.field.field = load i8* %b.field.index |
| 200 ; CHECK-NEXT: %b.field.index5 = getelementptr { i8, i64 }* %b.index, i32 0, i
32 1 |
| 201 ; CHECK-NEXT: %b.field.field6 = load i64* %b.field.index5 |
| 202 ; CHECK-NEXT: %c.index.index = select i1 undef, i8 %a.field.field, i8 %b.fiel
d.field |
| 203 ; CHECK-NEXT: %c.index.index11 = select i1 undef, i64 %a.field.field3, i64 %b
.field.field6 |
| 204 ; CHECK-NEXT: %.index = getelementptr { { i8, i64 } }* null, i32 0, i32 0 |
| 205 ; CHECK-NEXT: %.index.index = getelementptr { i8, i64 }* %.index, i32 0, i32
0 |
| 206 ; CHECK-NEXT: store i8 %c.index.index, i8* %.index.index |
| 207 ; CHECK-NEXT: %.index.index13 = getelementptr { i8, i64 }* %.index, i32 0, i3
2 1 |
| 208 ; CHECK-NEXT: store i64 %c.index.index11, i64* %.index.index13 |
| 209 ; CHECK-NEXT: ret void |
| 210 |
| 211 define void @phi_another_pass() { |
| 212 entry: |
| 213 br i1 false, label %next, label %not_next |
| 214 |
| 215 not_next: |
| 216 %a = alloca { { i64, i16 }, i8* } |
| 217 %b = load { { i64, i16 }, i8* }* %a |
| 218 br label %next |
| 219 |
| 220 next: |
| 221 %c = phi { { i64, i16 }, i8* } [ undef, %entry ], [ %b, %not_next ] |
| 222 store { { i64, i16 }, i8* } %c, { { i64, i16 }, i8* }* null |
| 223 ret void |
| 224 } |
| 225 ; CHECK-LABEL: define void @phi_another_pass() |
| 226 ; CHECK: %c.index.index = phi i64 [ undef, %entry ], [ %b.field.field, %
not_next ] |
| 227 ; CHECK: %c.index.index{{.*}} = phi i16 [ undef, %entry ], [ %b.field.fi
eld{{.*}}, %not_next ] |
| 228 ; CHECK: %c.index{{.*}} = phi i8* [ undef, %entry ], [ %b.field{{.*}}, %
not_next ] |
OLD | NEW |