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..d8738990c74de9fd40ed8ce97068bc2a7877fa1d |
--- /dev/null |
+++ b/test/Transforms/NaCl/simplify-struct-reg-signatures.ll |
@@ -0,0 +1,138 @@ |
+; 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*} |
+%rec_returning = type { %rec_returning (%rec_returning)* } |
+%direct_def = type { void(%struct)*, %struct } |
+ |
+; new type declarations: |
+; CHECK: %struct = type { i32, i32 } |
+; CHECK-NEXT: %rec_struct = type { %rec_struct* } |
+; CHECK-NEXT: %rec_problem_struct.simplified = type { void (%rec_problem_struct.simplified*)* } |
+; CHECK-NEXT: %rec_pair_1 = type { %rec_pair_2* } |
+; CHECK-NEXT: %rec_pair_2 = type { %rec_pair_1* } |
+; CHECK-NEXT: %rec_returning.simplified = type { void (%rec_returning.simplified*, %rec_returning.simplified*)* } |
+; CHECK-NEXT: %direct_def.simplified = type { void (%struct*)*, %struct } |
+ |
+; externs |
+declare void @extern_func(%struct) |
+declare %struct @struct_returning_extern(i32, %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) |
+ |
+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 |
+} |
+ |
+; 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) |
+ |
+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 |
+} |
+ |
+; 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) |
+ |
+define %struct @returns_struct(i32 %an_int, %struct %val) { |
+ %tmp = call %struct @struct_returning_extern(i32 %an_int, %struct %val) |
+ ret %struct %tmp |
+} |
+ |
+; verify return value and codegen |
+; CHECK: define void @returns_struct(%struct* sret %retVal, i32 %an_int, %struct* byval %val.ptr) |
JF
2015/03/16 21:53:47
This should be:
; CHECK-LABEL: @lots_of_call_attrs
|
+; CHECK-NEXT: %val.sreg = load %struct* %val.ptr |
+; CHECK-NEXT: %tmp = 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 %tmp, i32 %an_int, %struct* byval %val.sreg.ptr) |
+; CHECK-NEXT: %tmp.sreg = load %struct* %tmp |
+; CHECK-NEXT: store %struct %tmp.sreg, %struct* %retVal |
+; CHECK-NEXT: ret void |
+ |
+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 |
+} |
+ |
+; verify attributes are copied |
+; CHECK: %ret = tail call zeroext i32 @another_func(i32 1, %struct* byval %tmp.1.ptr, i64 2) #0 |
+; CHECK-NEXT: ret i32 %ret |
+ |
+declare void @rec_struct_ok(%rec_struct*) |
+declare void @rec_struct_mod(%rec_struct) |
+ |
+; compliant recursive structs are kept as-is |
+; CHECK: declare void @rec_struct_ok(%rec_struct*) |
+; CHECK: declare void @rec_struct_mod(%rec_struct* byval) |
+ |
+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 |
+} |
+ |
+; non-compliant structs are correctly mapped and calls are changed |
+; CHECK: define void @rec_call_sreg(%rec_problem_struct.simplified* byval %r.ptr) |
+; CHECK: call void %tmp(%rec_problem_struct.simplified* byval %r.sreg.ptr) |
+ |
+declare void @pairs(%rec_pair_1) |
+ |
+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 |
+} |
+ |
+; pair structs |
+; CHECK: declare void @pairs(%rec_pair_1* byval) |
+; CHECK: define void @rec_returning_fun(%rec_returning.simplified* sret %retVal, %rec_returning.simplified* byval %str.ptr) |
+; CHECK-NEXT: %str.sreg = load %rec_returning.simplified* %str.ptr |
+; CHECK-NEXT: %tmp = extractvalue %rec_returning.simplified %str.sreg, 0 |
+; CHECK-NEXT: %ret = alloca %rec_returning.simplified |
+; CHECK-NEXT: %str.sreg.ptr = alloca %rec_returning.simplified |
+; CHECK-NEXT: store %rec_returning.simplified %str.sreg, %rec_returning.simplified* %str.sreg.ptr |
+; CHECK-NEXT: call void %tmp(%rec_returning.simplified* sret %ret, %rec_returning.simplified* byval %str.sreg.ptr) |
+; CHECK-NEXT: %ret.sreg = load %rec_returning.simplified* %ret |
+; CHECK-NEXT: store %rec_returning.simplified %ret.sreg, %rec_returning.simplified* %retVal |
+; CHECK-NEXT: ret void |
+ |
+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 |
+} |
+ |
+; CHECK: define void @direct_caller(%direct_def.simplified* byval %def.ptr) |
+; CHECK-NEXT: %def.sreg = load %direct_def.simplified* %def.ptr |
+; CHECK-NEXT: %func = extractvalue %direct_def.simplified %def.sreg, 0 |
+; CHECK-NEXT: %param = extractvalue %direct_def.simplified %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 } |