| Index: test/Transforms/NaCl/simplify-struct-reg-signatures.ll
|
| diff --git a/test/Transforms/NaCl/simplify-struct-reg-signatures.ll b/test/Transforms/NaCl/simplify-struct-reg-signatures.ll
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..04ff60322f796dddd8f908f128cdf5e4d1c2cc20
|
| --- /dev/null
|
| +++ b/test/Transforms/NaCl/simplify-struct-reg-signatures.ll
|
| @@ -0,0 +1,140 @@
|
| +; RUN: opt %s -simplify-struct-reg-signatures -S | FileCheck %s
|
| +
|
| +%struct = type { i32, i32 }
|
| +%rec_struct = type {%rec_struct*}
|
| +%rec_problem_struct = type{void (%rec_problem_struct)*}
|
| +%rec_pair_1 = type {%rec_pair_2*}
|
| +%rec_pair_2 = type {%rec_pair_1*}
|
| +
|
| +; externs
|
| +declare void @extern_func(%struct)
|
| +declare %struct @struct_returning_extern(i32, %struct)
|
| +
|
| +define void @main(%struct* byval %ptr) {
|
| + %val = load %struct* %ptr
|
| + call void @extern_func(%struct %val)
|
| + ret void
|
| +}
|
| +
|
| +define void @two_param_func(%struct %val1, %struct %val2) {
|
| + call void @extern_func(%struct %val1)
|
| + call void @extern_func(%struct %val2)
|
| + ret void
|
| +}
|
| +
|
| +define i32 @another_func(i32 %a, %struct %str, i64 %b) {
|
| + call void @two_param_func(%struct %str, %struct %str)
|
| + call void @extern_func(%struct %str)
|
| + ret i32 0
|
| +}
|
| +
|
| +define %struct @returns_struct(i32 %an_int, %struct %val) {
|
| + %tmp = call %struct @struct_returning_extern(i32 %an_int, %struct %val)
|
| + ret %struct %tmp
|
| +}
|
| +
|
| +define i32 @lots_of_call_attrs() {
|
| + %tmp.0 = insertvalue %struct undef, i32 1, 0
|
| + %tmp.1 = insertvalue %struct %tmp.0, i32 2, 1
|
| + %ret = tail call zeroext i32 @another_func(i32 1, %struct %tmp.1, i64 2) readonly
|
| + ret i32 %ret
|
| +}
|
| +
|
| +declare void @rec_struct_ok(%rec_struct*)
|
| +declare void @rec_struct_mod(%rec_struct)
|
| +
|
| +define void @rec_call_sreg(%rec_problem_struct %r) {
|
| + %tmp = extractvalue %rec_problem_struct %r, 0
|
| + call void %tmp(%rec_problem_struct %r)
|
| + ret void
|
| +}
|
| +
|
| +declare void @pairs(%rec_pair_1)
|
| +
|
| +%rec_returning = type { %rec_returning (%rec_returning)* }
|
| +
|
| +define %rec_returning @rec_returning_fun(%rec_returning %str) {
|
| + %tmp = extractvalue %rec_returning %str, 0
|
| + %ret = call %rec_returning %tmp(%rec_returning %str)
|
| + ret %rec_returning %ret
|
| +}
|
| +
|
| +%direct_def = type { void(%struct)*, %struct }
|
| +
|
| +define void @direct_caller(%direct_def %def) {
|
| + %func = extractvalue %direct_def %def, 0
|
| + %param = extractvalue %direct_def %def, 1
|
| + call void %func(%struct %param)
|
| + ret void
|
| +}
|
| +
|
| +; new type declarations:
|
| +; CHECK: %struct = type { i32, i32 }
|
| +; CHECK-NEXT: %rec_struct = type { %rec_struct* }
|
| +; CHECK-NEXT: %rec_problem_struct.2 = type { void (%rec_problem_struct.2*)* }
|
| +; CHECK-NEXT: %rec_pair_1 = type { %rec_pair_2* }
|
| +; CHECK-NEXT: %rec_pair_2 = type { %rec_pair_1* }
|
| +; CHECK-NEXT: %rec_returning.6 = type { void (%rec_returning.6*, %rec_returning.6*)* }
|
| +; CHECK-NEXT: %direct_def.8 = type { void (%struct*)*, %struct }
|
| +
|
| +; verify that parameters are mapped correctly: single param, two, and combo
|
| +; with non-struct regs
|
| +; CHECK-NOT: declare void @extern_func(%struct)
|
| +; CHECK-NOT: declare %struct @struct_returning_extern(i32, %struct)
|
| +; CHECK: declare void @extern_func(%struct* byval)
|
| +; CHECK: declare void @struct_returning_extern(%struct* sret, i32, %struct* byval)
|
| +
|
| +; CHECK: define void @two_param_func(%struct* byval %val1.ptr, %struct* byval %val2.ptr)
|
| +; CHECK-NOT: define void @two_param_func(%struct %val1, %struct %val2)
|
| +
|
| +; CHECK: define i32 @another_func(i32 %a, %struct* byval %str.ptr, i64 %b)
|
| +; CHECK: call void @two_param_func(%struct* byval %str.sreg.ptr, %struct* byval %str.sreg.ptr1)
|
| +
|
| +; verify return value and codegen
|
| +; CHECK: define void @returns_struct(%struct* sret %retVal, i32 %an_int, %struct* byval %val.ptr)
|
| +; CHECK-NEXT: %val.sreg = load %struct* %val.ptr
|
| +; CHECK-NEXT: %1 = alloca %struct
|
| +; CHECK-NEXT: %val.sreg.ptr = alloca %struct
|
| +; CHECK-NEXT: store %struct %val.sreg, %struct* %val.sreg.ptr
|
| +; CHECK-NEXT: call void @struct_returning_extern(%struct* sret %1, i32 %an_int, %struct* byval %val.sreg.ptr)
|
| +; CHECK-NEXT: %tmp.sreg = load %struct* %1
|
| +; CHECK-NEXT: store %struct %tmp.sreg, %struct* %retVal
|
| +; CHECK-NEXT: ret void
|
| +
|
| +; verify attributes are copied
|
| +; CHECK: %1 = tail call zeroext i32 @another_func(i32 1, %struct* byval %tmp.1.ptr, i64 2) #0
|
| +; CHECK-NEXT: ret i32 %1
|
| +
|
| +; compliant recursive structs are kept as-is
|
| +; CHECK: declare void @rec_struct_ok(%rec_struct*)
|
| +; CHECK: declare void @rec_struct_mod(%rec_struct* byval)
|
| +
|
| +; non-compliant structs are correctly mapped and calls are changed
|
| +; CHECK: define void @rec_call_sreg(%rec_problem_struct.2* byval %r.ptr)
|
| +; CHECK: call void %tmp(%rec_problem_struct.2* byval %r.sreg.ptr)
|
| +
|
| +; pair structs
|
| +; CHECK: declare void @pairs(%rec_pair_1* byval)
|
| +; CHECK: define void @rec_returning_fun(%rec_returning.6* sret %retVal, %rec_returning.6* byval %str.ptr)
|
| +; CHECK-NEXT: %str.sreg = load %rec_returning.6* %str.ptr
|
| +; CHECK-NEXT: %tmp = extractvalue %rec_returning.6 %str.sreg, 0
|
| +; CHECK-NEXT: %1 = alloca %rec_returning.6
|
| +; CHECK-NEXT: %str.sreg.ptr = alloca %rec_returning.6
|
| +; CHECK-NEXT: store %rec_returning.6 %str.sreg, %rec_returning.6* %str.sreg.ptr
|
| +; CHECK-NEXT: call void %tmp(%rec_returning.6* sret %1, %rec_returning.6* byval %str.sreg.ptr)
|
| +; CHECK-NEXT: %ret.sreg = load %rec_returning.6* %1
|
| +; CHECK-NEXT: store %rec_returning.6 %ret.sreg, %rec_returning.6* %retVal
|
| +; CHECK-NEXT: ret void
|
| +
|
| +; CHECK: define void @direct_caller(%direct_def.8* byval %def.ptr)
|
| +; CHECK-NEXT: %def.sreg = load %direct_def.8* %def.ptr
|
| +; CHECK-NEXT: %func = extractvalue %direct_def.8 %def.sreg, 0
|
| +; CHECK-NEXT: %param = extractvalue %direct_def.8 %def.sreg, 1
|
| +; CHECK-NEXT: %param.ptr = alloca %struct
|
| +; CHECK-NEXT: store %struct %param, %struct* %param.ptr
|
| +; CHECK-NEXT: call void %func(%struct* byval %param.ptr)
|
| +; CHECK-NEXT: ret void
|
| +
|
| +
|
| +; this is at the end, corresponds to the call marked as readonly
|
| +; CHECK: attributes #0 = { readonly }
|
|
|