OLD | NEW |
(Empty) | |
| 1 ; RUN: opt -expand-byval %s -S | FileCheck %s |
| 2 |
| 3 target datalayout = "p:32:32:32" |
| 4 |
| 5 %MyStruct = type { i32, i8, i32 } |
| 6 %AlignedStruct = type { double, double } |
| 7 |
| 8 |
| 9 ; Removal of "byval" attribute for passing structs arguments by value |
| 10 |
| 11 declare void @ext_func(%MyStruct*) |
| 12 |
| 13 define void @byval_receiver(%MyStruct* byval align 32 %ptr) { |
| 14 call void @ext_func(%MyStruct* %ptr) |
| 15 ret void |
| 16 } |
| 17 ; Strip the "byval" and "align" attributes. |
| 18 ; CHECK: define void @byval_receiver(%MyStruct* %ptr) { |
| 19 ; CHECK-NEXT: call void @ext_func(%MyStruct* %ptr) |
| 20 |
| 21 |
| 22 declare void @ext_byval_func(%MyStruct* byval) |
| 23 ; CHECK: declare void @ext_byval_func(%MyStruct*) |
| 24 |
| 25 define void @byval_caller(%MyStruct* %ptr) { |
| 26 call void @ext_byval_func(%MyStruct* byval %ptr) |
| 27 ret void |
| 28 } |
| 29 ; CHECK: define void @byval_caller(%MyStruct* %ptr) { |
| 30 ; CHECK-NEXT: %ptr.byval_copy = alloca %MyStruct, align 4 |
| 31 ; CHECK: call void @llvm.lifetime.start(i64 12, i8* %{{.*}}) |
| 32 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 12,
i32 0, i1 false) |
| 33 ; CHECK-NEXT: call void @ext_byval_func(%MyStruct* %ptr.byval_copy) |
| 34 |
| 35 |
| 36 define void @byval_tail_caller(%MyStruct* %ptr) { |
| 37 tail call void @ext_byval_func(%MyStruct* byval %ptr) |
| 38 ret void |
| 39 } |
| 40 ; CHECK: define void @byval_tail_caller(%MyStruct* %ptr) { |
| 41 ; CHECK: {{^}} call void @ext_byval_func(%MyStruct* %ptr.byval_copy) |
| 42 |
| 43 |
| 44 define void @byval_invoke(%MyStruct* %ptr) { |
| 45 invoke void @ext_byval_func(%MyStruct* byval align 32 %ptr) |
| 46 to label %cont unwind label %lpad |
| 47 cont: |
| 48 ret void |
| 49 lpad: |
| 50 %lp = landingpad { i8*, i32 } personality i8* null cleanup |
| 51 ret void |
| 52 } |
| 53 ; CHECK: define void @byval_invoke(%MyStruct* %ptr) { |
| 54 ; CHECK: %ptr.byval_copy = alloca %MyStruct, align 32 |
| 55 ; CHECK: call void @llvm.lifetime.start(i64 12, i8* %{{.*}}) |
| 56 ; CHECK: invoke void @ext_byval_func(%MyStruct* %ptr.byval_copy) |
| 57 ; CHECK: cont: |
| 58 ; CHECK: call void @llvm.lifetime.end(i64 12, i8* %{{.*}}) |
| 59 ; CHECK: lpad: |
| 60 ; CHECK: call void @llvm.lifetime.end(i64 12, i8* %{{.*}}) |
| 61 |
| 62 |
| 63 ; Check handling of alignment |
| 64 |
| 65 ; Check that "align" is stripped for declarations too. |
| 66 declare void @ext_byval_func_align(%MyStruct* byval align 32) |
| 67 ; CHECK: declare void @ext_byval_func_align(%MyStruct*) |
| 68 |
| 69 define void @byval_caller_align_via_attr(%MyStruct* %ptr) { |
| 70 call void @ext_byval_func(%MyStruct* byval align 32 %ptr) |
| 71 ret void |
| 72 } |
| 73 ; CHECK: define void @byval_caller_align_via_attr(%MyStruct* %ptr) { |
| 74 ; CHECK-NEXT: %ptr.byval_copy = alloca %MyStruct, align 32 |
| 75 ; The memcpy may assume that %ptr is 32-byte-aligned. |
| 76 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 12, i32 32, i1
false) |
| 77 |
| 78 declare void @ext_byval_func_align_via_type(%AlignedStruct* byval) |
| 79 |
| 80 ; %AlignedStruct contains a double so requires an alignment of 8 bytes. |
| 81 ; Looking at the alignment of %AlignedStruct is a workaround for a bug |
| 82 ; in pnacl-clang: |
| 83 ; https://code.google.com/p/nativeclient/issues/detail?id=3403 |
| 84 define void @byval_caller_align_via_type(%AlignedStruct* %ptr) { |
| 85 call void @ext_byval_func_align_via_type(%AlignedStruct* byval %ptr) |
| 86 ret void |
| 87 } |
| 88 ; CHECK: define void @byval_caller_align_via_type(%AlignedStruct* %ptr) { |
| 89 ; CHECK-NEXT: %ptr.byval_copy = alloca %AlignedStruct, align 8 |
| 90 ; Don't assume that %ptr is 8-byte-aligned when doing the memcpy. |
| 91 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 16,
i32 0, i1 false) |
| 92 |
| 93 |
| 94 ; Removal of "sret" attribute for returning structs by value |
| 95 |
| 96 declare void @ext_sret_func(%MyStruct* sret align 32) |
| 97 ; CHECK: declare void @ext_sret_func(%MyStruct*) |
| 98 |
| 99 define void @sret_func(%MyStruct* sret align 32 %buf) { |
| 100 ret void |
| 101 } |
| 102 ; CHECK: define void @sret_func(%MyStruct* %buf) { |
| 103 |
| 104 define void @sret_caller(%MyStruct* %buf) { |
| 105 call void @ext_sret_func(%MyStruct* sret align 32 %buf) |
| 106 ret void |
| 107 } |
| 108 ; CHECK: define void @sret_caller(%MyStruct* %buf) { |
| 109 ; CHECK-NEXT: call void @ext_sret_func(%MyStruct* %buf) |
| 110 |
| 111 |
| 112 ; Check that other attributes are preserved |
| 113 |
| 114 define void @inreg_attr(%MyStruct* inreg %ptr) { |
| 115 ret void |
| 116 } |
| 117 ; CHECK: define void @inreg_attr(%MyStruct* inreg %ptr) { |
| 118 |
| 119 declare void @func_attrs() #0 |
| 120 ; CHECK: declare void @func_attrs() #0 |
| 121 |
| 122 attributes #0 = { noreturn nounwind } |
| 123 ; CHECK: attributes #0 = { noreturn nounwind } |
OLD | NEW |