OLD | NEW |
(Empty) | |
| 1 ; RUN: opt %s -simplify-struct-reg-signatures -S | FileCheck %s |
| 2 |
| 3 declare i32 @__gxx_personality_v0(...) |
| 4 |
| 5 %struct = type { i32, i32 } |
| 6 |
| 7 %rec_struct = type {%rec_struct*} |
| 8 %rec_problem_struct = type{void (%rec_problem_struct)*} |
| 9 %rec_pair_1 = type {%rec_pair_2*} |
| 10 %rec_pair_2 = type {%rec_pair_1*} |
| 11 %rec_returning = type { %rec_returning (%rec_returning)* } |
| 12 %direct_def = type { void(%struct)*, %struct } |
| 13 |
| 14 ; new type declarations: |
| 15 ; CHECK: %struct = type { i32, i32 } |
| 16 ; CHECK-NEXT: %rec_struct = type { %rec_struct* } |
| 17 ; CHECK-NEXT: %rec_problem_struct.simplified = type { void (%rec_problem_struct.
simplified*)* } |
| 18 ; CHECK-NEXT: %rec_pair_1 = type { %rec_pair_2* } |
| 19 ; CHECK-NEXT: %rec_pair_2 = type { %rec_pair_1* } |
| 20 ; CHECK-NEXT: %rec_returning.simplified = type { void (%rec_returning.simplified
*, %rec_returning.simplified*)* } |
| 21 ; CHECK-NEXT: %direct_def.simplified = type { void (%struct*)*, %struct } |
| 22 |
| 23 ; externs |
| 24 declare void @extern_func(%struct) |
| 25 declare %struct @struct_returning_extern(i32, %struct) |
| 26 |
| 27 ; verify that parameters are mapped correctly: single param, two, and combo |
| 28 ; with non-struct regs |
| 29 ; CHECK-NOT: declare void @extern_func(%struct) |
| 30 ; CHECK-NOT: declare %struct @struct_returning_extern(i32, %struct) |
| 31 ; CHECK-LABEL: declare void @extern_func(%struct* byval) |
| 32 ; CHECK-LABEL: declare void @struct_returning_extern(%struct* sret, i32, %struct
* byval) |
| 33 |
| 34 define void @main(%struct* byval %ptr) { |
| 35 %val = load %struct* %ptr |
| 36 call void @extern_func(%struct %val) |
| 37 ret void |
| 38 } |
| 39 |
| 40 define void @two_param_func(%struct %val1, %struct %val2) { |
| 41 call void @extern_func(%struct %val1) |
| 42 call void @extern_func(%struct %val2) |
| 43 ret void |
| 44 } |
| 45 |
| 46 ; CHECK-LABEL: define void @two_param_func(%struct* byval %val1.ptr, %struct* by
val %val2.ptr) |
| 47 ; CHECK-NOT: define void @two_param_func(%struct %val1, %struct %val2) |
| 48 |
| 49 define i32 @another_func(i32 %a, %struct %str, i64 %b) { |
| 50 call void @two_param_func(%struct %str, %struct %str) |
| 51 call void @extern_func(%struct %str) |
| 52 ret i32 0 |
| 53 } |
| 54 |
| 55 ; CHECK-LABEL: define i32 @another_func(i32 %a, %struct* byval %str.ptr, i64 %b) |
| 56 ; CHECK: call void @two_param_func(%struct* byval %str.sreg.ptr, %struct* byval
%str.sreg.ptr1) |
| 57 |
| 58 define %struct @returns_struct(i32 %an_int, %struct %val) { |
| 59 %tmp = call %struct @struct_returning_extern(i32 %an_int, %struct %val) |
| 60 %tmp2 = invoke %struct @struct_returning_extern(i32 1, %struct %tmp) |
| 61 to label %Cont unwind label %Cleanup |
| 62 |
| 63 Cont: |
| 64 ret %struct %tmp2 |
| 65 Cleanup: |
| 66 %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0 |
| 67 cleanup |
| 68 resume {i8*, i32} %exn |
| 69 } |
| 70 |
| 71 ; verify return value and codegen |
| 72 ; CHECK-LABEL: define void @returns_struct(%struct* sret %retVal, i32 %an_int, %
struct* byval %val.ptr) |
| 73 ; CHECK-NEXT: %tmp2 = alloca %struct |
| 74 ; CHECK-NEXT: %tmp.sreg.ptr = alloca %struct |
| 75 ; CHECK-NEXT: %tmp = alloca %struct |
| 76 ; CHECK-NEXT: %val.sreg.ptr = alloca %struct |
| 77 ; CHECK-NEXT: %val.sreg = load %struct* %val.ptr |
| 78 ; CHECK-NEXT: store %struct %val.sreg, %struct* %val.sreg.ptr |
| 79 ; CHECK-NEXT: call void @struct_returning_extern(%struct* sret %tmp, i32 %an_in
t, %struct* byval %val.sreg.ptr) |
| 80 ; CHECK-NEXT: %tmp.sreg = load %struct* %tmp |
| 81 ; CHECK-NEXT: store %struct %tmp.sreg, %struct* %tmp.sreg.ptr |
| 82 ; CHECK-NEXT: invoke void @struct_returning_extern(%struct* sret %tmp2, i32 1,
%struct* byval %tmp.sreg.ptr) |
| 83 ; CHECK-NEXT: to label %Cont unwind label %Cleanup |
| 84 ; CHECK-DAG: Cont: |
| 85 ; CHECK-NEXT: %tmp2.sreg = load %struct* %tmp2 |
| 86 ; CHECK-NEXT: store %struct %tmp2.sreg, %struct* %retVal |
| 87 ; CHECK-NEXT: ret void |
| 88 ; CHECK-DAG: Cleanup: |
| 89 ; CHECK-NEXT: %exn = landingpad { i8*, i32 } personality i32 (...)* @__gxx_pe
rsonality_v0 |
| 90 ; CHECK-NEXT: cleanup |
| 91 ; CHECK-NEXT: resume { i8*, i32 } %exn |
| 92 |
| 93 define i32 @lots_of_call_attrs() { |
| 94 %tmp.0 = insertvalue %struct undef, i32 1, 0 |
| 95 %tmp.1 = insertvalue %struct %tmp.0, i32 2, 1 |
| 96 %ret = tail call zeroext i32 @another_func(i32 1, %struct %tmp.1, i64 2) reado
nly |
| 97 ret i32 %ret |
| 98 } |
| 99 |
| 100 ; verify attributes are copied |
| 101 ; CHECK_LABEL: @lots_of_call_attrs |
| 102 ; CHECK: %ret = tail call zeroext i32 @another_func(i32 1, %struct* byval %tmp.1
.ptr, i64 2) #0 |
| 103 ; CHECK-NEXT: ret i32 %ret |
| 104 |
| 105 declare void @rec_struct_ok(%rec_struct*) |
| 106 declare void @rec_struct_mod(%rec_struct) |
| 107 |
| 108 ; compliant recursive structs are kept as-is |
| 109 ; CHECK-LABEL: declare void @rec_struct_ok(%rec_struct*) |
| 110 ; CHECK-LABEL: declare void @rec_struct_mod(%rec_struct* byval) |
| 111 |
| 112 define void @rec_call_sreg(%rec_problem_struct %r) { |
| 113 %tmp = extractvalue %rec_problem_struct %r, 0 |
| 114 call void %tmp(%rec_problem_struct %r) |
| 115 ret void |
| 116 } |
| 117 |
| 118 ; non-compliant structs are correctly mapped and calls are changed |
| 119 ; CHECK-LABEL: define void @rec_call_sreg(%rec_problem_struct.simplified* byval
%r.ptr) |
| 120 ; CHECK: call void %tmp(%rec_problem_struct.simplified* byval %r.sreg.ptr) |
| 121 |
| 122 declare void @pairs(%rec_pair_1) |
| 123 |
| 124 define %rec_returning @rec_returning_fun(%rec_returning %str) { |
| 125 %tmp = extractvalue %rec_returning %str, 0 |
| 126 %ret = call %rec_returning %tmp(%rec_returning %str) |
| 127 ret %rec_returning %ret |
| 128 } |
| 129 |
| 130 ; pair structs |
| 131 ; CHECK-LABEL: declare void @pairs(%rec_pair_1* byval) |
| 132 ; CHECK-LABEL: define void @rec_returning_fun(%rec_returning.simplified* sret %r
etVal, %rec_returning.simplified* byval %str.ptr) |
| 133 ; CHECK-NEXT: %ret = alloca %rec_returning.simplified |
| 134 ; CHECK-NEXT: %str.sreg.ptr = alloca %rec_returning.simplified |
| 135 ; CHECK-NEXT: %str.sreg = load %rec_returning.simplified* %str.ptr |
| 136 ; CHECK-NEXT: %tmp = extractvalue %rec_returning.simplified %str.sreg, 0 |
| 137 ; CHECK-NEXT: store %rec_returning.simplified %str.sreg, %rec_returning.simpli
fied* %str.sreg.ptr |
| 138 ; CHECK-NEXT: call void %tmp(%rec_returning.simplified* sret %ret, %rec_return
ing.simplified* byval %str.sreg.ptr) |
| 139 ; CHECK-NEXT: %ret.sreg = load %rec_returning.simplified* %ret |
| 140 ; CHECK-NEXT: store %rec_returning.simplified %ret.sreg, %rec_returning.simpli
fied* %retVal |
| 141 ; CHECK-NEXT: ret void |
| 142 |
| 143 define void @direct_caller(%direct_def %def) { |
| 144 %func = extractvalue %direct_def %def, 0 |
| 145 %param = extractvalue %direct_def %def, 1 |
| 146 call void %func(%struct %param) |
| 147 ret void |
| 148 } |
| 149 |
| 150 ; CHECK-LABEL: define void @direct_caller(%direct_def.simplified* byval %def.ptr
) |
| 151 ; CHECK-NEXT: %param.ptr = alloca %struct |
| 152 ; CHECK-NEXT: %def.sreg = load %direct_def.simplified* %def.ptr |
| 153 ; CHECK-NEXT: %func = extractvalue %direct_def.simplified %def.sreg, 0 |
| 154 ; CHECK-NEXT: %param = extractvalue %direct_def.simplified %def.sreg, 1 |
| 155 ; CHECK-NEXT: store %struct %param, %struct* %param.ptr |
| 156 ; CHECK-NEXT: call void %func(%struct* byval %param.ptr) |
| 157 ; CHECK-NEXT: ret void |
| 158 |
| 159 ; vararg functions are converted correctly |
| 160 declare void @vararg_ok(i32, ...) |
| 161 ; CHECK-LABEL: declare void @vararg_ok(i32, ...) |
| 162 |
| 163 define void @vararg_problem(%rec_problem_struct %arg1, ...) { |
| 164 ; CHECK-LABEL: define void @vararg_problem(%rec_problem_struct.simplified* byv
al %arg1.ptr, ...) |
| 165 ret void |
| 166 } |
| 167 |
| 168 %vararg_fp_struct = type { i32, void (i32, ...)* } |
| 169 declare void @vararg_fp_fct(%vararg_fp_struct %arg) |
| 170 ;CHECK-LABEL: declare void @vararg_fp_fct(%vararg_fp_struct* byval) |
| 171 |
| 172 define void @call_vararg(%vararg_fp_struct %param1, ...) { |
| 173 %fptr = extractvalue %vararg_fp_struct %param1, 1 |
| 174 call void (i32, ...)* %fptr(i32 0, i32 1) |
| 175 ret void |
| 176 } |
| 177 |
| 178 ; CHECK-LABEL: define void @call_vararg(%vararg_fp_struct* byval %param1.ptr, ..
.) |
| 179 ; CHECK-NEXT: %param1.sreg = load %vararg_fp_struct* %param1.ptr |
| 180 ; CHECK-NEXT: %fptr = extractvalue %vararg_fp_struct %param1.sreg, 1 |
| 181 ; CHECK-NEXT: call void (i32, ...)* %fptr(i32 0, i32 1) |
| 182 ; CHECK-NEXT: ret void |
| 183 |
| 184 %vararg_fp_problem_struct = type { void(%vararg_fp_problem_struct)* } |
| 185 define void @vararg_fp_problem_call(%vararg_fp_problem_struct* byval %param) { |
| 186 %fct_ptr = getelementptr %vararg_fp_problem_struct* %param, i32 0, i32 0 |
| 187 %fct = load void(%vararg_fp_problem_struct)** %fct_ptr |
| 188 %param_for_call = load %vararg_fp_problem_struct* %param |
| 189 call void %fct(%vararg_fp_problem_struct %param_for_call) |
| 190 ret void |
| 191 } |
| 192 |
| 193 ; CHECK-LABEL: define void @vararg_fp_problem_call(%vararg_fp_problem_struct.sim
plified* byval %param) |
| 194 ; CHECK-NEXT: %param_for_call.ptr = alloca %vararg_fp_problem_struct.simplified |
| 195 ; CHECK-NEXT: %fct_ptr = getelementptr %vararg_fp_problem_struct.simplified* %p
aram, i32 0, i32 0 |
| 196 ; CHECK-NEXT: %fct = load void (%vararg_fp_problem_struct.simplified*)** %fct_p
tr |
| 197 ; CHECK-NEXT: %param_for_call = load %vararg_fp_problem_struct.simplified* %par
am |
| 198 ; CHECK-NEXT: store %vararg_fp_problem_struct.simplified %param_for_call, %vara
rg_fp_problem_struct.simplified* %param_for_call.ptr |
| 199 ; CHECK-NEXT: call void %fct(%vararg_fp_problem_struct.simplified* byval %param
_for_call.ptr) |
| 200 ; CHECK-NEXT: ret void |
| 201 |
| 202 define void @call_with_array([4 x void(%struct)*] %fptrs, %struct %str) { |
| 203 %fptr = extractvalue [4 x void(%struct)*] %fptrs, 2 |
| 204 call void %fptr(%struct %str) |
| 205 ret void |
| 206 } |
| 207 |
| 208 ; CHECK-LABEL: define void @call_with_array([4 x void (%struct*)*]* byval %fptrs
.ptr, %struct* byval %str.ptr) |
| 209 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct |
| 210 ; CHECK-NEXT: %fptrs.sreg = load [4 x void (%struct*)*]* %fptrs.ptr |
| 211 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr |
| 212 ; CHECK-NEXT: %fptr = extractvalue [4 x void (%struct*)*] %fptrs.sreg, 2 |
| 213 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr |
| 214 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) |
| 215 ; CHECK-NEXT: ret void |
| 216 |
| 217 define void @call_with_array_ptr([4 x void(%struct)*]* %fptrs, %struct %str) { |
| 218 %fptr_ptr = getelementptr [4 x void(%struct)*]* %fptrs, i32 0, i32 2 |
| 219 %fptr = load void(%struct)** %fptr_ptr |
| 220 call void %fptr(%struct %str) |
| 221 ret void |
| 222 } |
| 223 |
| 224 ; CHECK-LABEL: define void @call_with_array_ptr([4 x void (%struct*)*]* %fptrs,
%struct* byval %str.ptr) |
| 225 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct |
| 226 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr |
| 227 ; CHECK-NEXT: %fptr_ptr = getelementptr [4 x void (%struct*)*]* %fptrs, i32 0,
i32 2 |
| 228 ; CHECK-NEXT: %fptr = load void (%struct*)** %fptr_ptr |
| 229 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr |
| 230 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) |
| 231 ; CHECK-NEXT: ret void |
| 232 |
| 233 define void @call_with_vector(<4 x void (%struct)*> %fptrs, %struct %str) { |
| 234 %fptr = extractelement <4 x void (%struct)*> %fptrs, i32 2 |
| 235 call void %fptr(%struct %str) |
| 236 ret void |
| 237 } |
| 238 |
| 239 ; CHECK-LABEL: define void @call_with_vector(<4 x void (%struct*)*> %fptrs, %str
uct* byval %str.ptr) |
| 240 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct |
| 241 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr |
| 242 ; CHECK-NEXT: %fptr = extractelement <4 x void (%struct*)*> %fptrs, i32 2 |
| 243 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr |
| 244 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) |
| 245 ; CHECK-NEXT: ret void |
| 246 |
| 247 define void @call_with_array_vect([4 x <2 x void(%struct)*>] %fptrs, %struct %st
r) { |
| 248 %vect = extractvalue [4 x <2 x void(%struct)*>] %fptrs, 2 |
| 249 %fptr = extractelement <2 x void (%struct)*> %vect, i32 1 |
| 250 call void %fptr(%struct %str) |
| 251 ret void |
| 252 } |
| 253 |
| 254 ; CHECK-LABEL: define void @call_with_array_vect([4 x <2 x void (%struct*)*>]* b
yval %fptrs.ptr, %struct* byval %str.ptr) |
| 255 ; CHECK-NEXT: %str.sreg.ptr = alloca %struct |
| 256 ; CHECK-NEXT: %fptrs.sreg = load [4 x <2 x void (%struct*)*>]* %fptrs.ptr |
| 257 ; CHECK-NEXT: %str.sreg = load %struct* %str.ptr |
| 258 ; CHECK-NEXT: %vect = extractvalue [4 x <2 x void (%struct*)*>] %fptrs.sreg, 2 |
| 259 ; CHECK-NEXT: %fptr = extractelement <2 x void (%struct*)*> %vect, i32 1 |
| 260 ; CHECK-NEXT: store %struct %str.sreg, %struct* %str.sreg.ptr |
| 261 ; CHECK-NEXT: call void %fptr(%struct* byval %str.sreg.ptr) |
| 262 ; CHECK-NEXT: ret void |
| 263 |
| 264 ; this is at the end, corresponds to the call marked as readonly |
| 265 ; CHECK: attributes #0 = { readonly } |
OLD | NEW |