| Index: test/Transforms/NaCl/expand-byval.ll
 | 
| diff --git a/test/Transforms/NaCl/expand-byval.ll b/test/Transforms/NaCl/expand-byval.ll
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..12977a7d7d3bee4288e9dad2a5cc46b73e1573d7
 | 
| --- /dev/null
 | 
| +++ b/test/Transforms/NaCl/expand-byval.ll
 | 
| @@ -0,0 +1,123 @@
 | 
| +; RUN: opt -expand-byval %s -S | FileCheck %s
 | 
| +
 | 
| +target datalayout = "p:32:32:32"
 | 
| +
 | 
| +%MyStruct = type { i32, i8, i32 }
 | 
| +%AlignedStruct = type { double, double }
 | 
| +
 | 
| +
 | 
| +; Removal of "byval" attribute for passing structs arguments by value
 | 
| +
 | 
| +declare void @ext_func(%MyStruct*)
 | 
| +
 | 
| +define void @byval_receiver(%MyStruct* byval align 32 %ptr) {
 | 
| +  call void @ext_func(%MyStruct* %ptr)
 | 
| +  ret void
 | 
| +}
 | 
| +; Strip the "byval" and "align" attributes.
 | 
| +; CHECK: define void @byval_receiver(%MyStruct* %ptr) {
 | 
| +; CHECK-NEXT: call void @ext_func(%MyStruct* %ptr)
 | 
| +
 | 
| +
 | 
| +declare void @ext_byval_func(%MyStruct* byval)
 | 
| +; CHECK: declare void @ext_byval_func(%MyStruct*)
 | 
| +
 | 
| +define void @byval_caller(%MyStruct* %ptr) {
 | 
| +  call void @ext_byval_func(%MyStruct* byval %ptr)
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @byval_caller(%MyStruct* %ptr) {
 | 
| +; CHECK-NEXT: %ptr.byval_copy = alloca %MyStruct, align 4
 | 
| +; CHECK: call void @llvm.lifetime.start(i64 12, i8* %{{.*}})
 | 
| +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 12, i32 0, i1 false)
 | 
| +; CHECK-NEXT: call void @ext_byval_func(%MyStruct* %ptr.byval_copy)
 | 
| +
 | 
| +
 | 
| +define void @byval_tail_caller(%MyStruct* %ptr) {
 | 
| +  tail call void @ext_byval_func(%MyStruct* byval %ptr)
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @byval_tail_caller(%MyStruct* %ptr) {
 | 
| +; CHECK: {{^}} call void @ext_byval_func(%MyStruct* %ptr.byval_copy)
 | 
| +
 | 
| +
 | 
| +define void @byval_invoke(%MyStruct* %ptr) {
 | 
| +  invoke void @ext_byval_func(%MyStruct* byval align 32 %ptr)
 | 
| +      to label %cont unwind label %lpad
 | 
| +cont:
 | 
| +  ret void
 | 
| +lpad:
 | 
| +  %lp = landingpad { i8*, i32 } personality i8* null cleanup
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @byval_invoke(%MyStruct* %ptr) {
 | 
| +; CHECK: %ptr.byval_copy = alloca %MyStruct, align 32
 | 
| +; CHECK: call void @llvm.lifetime.start(i64 12, i8* %{{.*}})
 | 
| +; CHECK: invoke void @ext_byval_func(%MyStruct* %ptr.byval_copy)
 | 
| +; CHECK: cont:
 | 
| +; CHECK: call void @llvm.lifetime.end(i64 12, i8* %{{.*}})
 | 
| +; CHECK: lpad:
 | 
| +; CHECK: call void @llvm.lifetime.end(i64 12, i8* %{{.*}})
 | 
| +
 | 
| +
 | 
| +; Check handling of alignment
 | 
| +
 | 
| +; Check that "align" is stripped for declarations too.
 | 
| +declare void @ext_byval_func_align(%MyStruct* byval align 32)
 | 
| +; CHECK: declare void @ext_byval_func_align(%MyStruct*)
 | 
| +
 | 
| +define void @byval_caller_align_via_attr(%MyStruct* %ptr) {
 | 
| +  call void @ext_byval_func(%MyStruct* byval align 32 %ptr)
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @byval_caller_align_via_attr(%MyStruct* %ptr) {
 | 
| +; CHECK-NEXT: %ptr.byval_copy = alloca %MyStruct, align 32
 | 
| +; The memcpy may assume that %ptr is 32-byte-aligned.
 | 
| +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 12, i32 32, i1 false)
 | 
| +
 | 
| +declare void @ext_byval_func_align_via_type(%AlignedStruct* byval)
 | 
| +
 | 
| +; %AlignedStruct contains a double so requires an alignment of 8 bytes.
 | 
| +; Looking at the alignment of %AlignedStruct is a workaround for a bug
 | 
| +; in pnacl-clang:
 | 
| +; https://code.google.com/p/nativeclient/issues/detail?id=3403
 | 
| +define void @byval_caller_align_via_type(%AlignedStruct* %ptr) {
 | 
| +  call void @ext_byval_func_align_via_type(%AlignedStruct* byval %ptr)
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @byval_caller_align_via_type(%AlignedStruct* %ptr) {
 | 
| +; CHECK-NEXT: %ptr.byval_copy = alloca %AlignedStruct, align 8
 | 
| +; Don't assume that %ptr is 8-byte-aligned when doing the memcpy.
 | 
| +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 16, i32 0, i1 false)
 | 
| +
 | 
| +
 | 
| +; Removal of "sret" attribute for returning structs by value
 | 
| +
 | 
| +declare void @ext_sret_func(%MyStruct* sret align 32)
 | 
| +; CHECK: declare void @ext_sret_func(%MyStruct*)
 | 
| +
 | 
| +define void @sret_func(%MyStruct* sret align 32 %buf) {
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @sret_func(%MyStruct* %buf) {
 | 
| +
 | 
| +define void @sret_caller(%MyStruct* %buf) {
 | 
| +  call void @ext_sret_func(%MyStruct* sret align 32 %buf)
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @sret_caller(%MyStruct* %buf) {
 | 
| +; CHECK-NEXT: call void @ext_sret_func(%MyStruct* %buf)
 | 
| +
 | 
| +
 | 
| +; Check that other attributes are preserved
 | 
| +
 | 
| +define void @inreg_attr(%MyStruct* inreg %ptr) {
 | 
| +  ret void
 | 
| +}
 | 
| +; CHECK: define void @inreg_attr(%MyStruct* inreg %ptr) {
 | 
| +
 | 
| +declare void @func_attrs() #0
 | 
| +; CHECK: declare void @func_attrs() #0
 | 
| +
 | 
| +attributes #0 = { noreturn nounwind }
 | 
| +; CHECK: attributes #0 = { noreturn nounwind }
 | 
| 
 |