OLD | NEW |
(Empty) | |
| 1 ; RUN: opt < %s -expand-varargs -S | FileCheck %s |
| 2 |
| 3 %va_list = type i8* |
| 4 |
| 5 declare void @llvm.va_start(i8*) |
| 6 declare void @llvm.va_end(i8*) |
| 7 declare void @llvm.va_copy(i8*, i8*) |
| 8 |
| 9 declare i32 @outside_func(i32 %arg, %va_list* %args) |
| 10 |
| 11 define i32 @varargs_func(i32 %arg, ...) { |
| 12 %arglist_alloc = alloca %va_list |
| 13 %arglist = bitcast %va_list* %arglist_alloc to i8* |
| 14 |
| 15 call void @llvm.va_start(i8* %arglist) |
| 16 %result = call i32 @outside_func(i32 %arg, %va_list* %arglist_alloc) |
| 17 call void @llvm.va_end(i8* %arglist) |
| 18 ret i32 %result |
| 19 } |
| 20 ; CHECK: define i32 @varargs_func(i32 %arg, i8* noalias %varargs) { |
| 21 ; CHECK-NEXT: %arglist_alloc = alloca i8* |
| 22 ; CHECK-NEXT: %arglist = bitcast i8** %arglist_alloc to i8* |
| 23 ; CHECK-NEXT: %arglist1 = bitcast i8* %arglist to i8** |
| 24 ; CHECK-NEXT: store i8* %varargs, i8** %arglist1 |
| 25 ; CHECK-NEXT: %result = call i32 @outside_func(i32 %arg, i8** %arglist_alloc) |
| 26 ; CHECK-NEXT: ret i32 %result |
| 27 |
| 28 |
| 29 define i32 @varargs_call1() { |
| 30 %result = call i32 (i32, ...)* @varargs_func(i32 111, i64 222, i32 333) |
| 31 ret i32 %result |
| 32 } |
| 33 ; CHECK: define i32 @varargs_call1() { |
| 34 ; CHECK-NEXT: %vararg_buffer = alloca <{ i64, i32 }> |
| 35 ; CHECK-NEXT: %vararg_lifetime_bitcast = bitcast <{ i64, i32 }>* %vararg_buffer
to i8* |
| 36 ; CHECK-NEXT: call void @llvm.lifetime.start(i64 12, i8* %vararg_lifetime_bitcas
t) |
| 37 ; CHECK-NEXT: %vararg_ptr = getelementptr <{ i64, i32 }>* %vararg_buffer, i32 0,
i32 0 |
| 38 ; CHECK-NEXT: store i64 222, i64* %vararg_ptr |
| 39 ; CHECK-NEXT: %vararg_ptr1 = getelementptr <{ i64, i32 }>* %vararg_buffer, i32 0
, i32 1 |
| 40 ; CHECK-NEXT: store i32 333, i32* %vararg_ptr1 |
| 41 ; CHECK-NEXT: %vararg_func = bitcast i32 (i32, ...)* bitcast (i32 (i32, i8*)* @v
arargs_func to i32 (i32, ...)*) to i32 (i32, <{ i64, i32 }>*)* |
| 42 ; CHECK-NEXT: %result = call i32 %vararg_func(i32 111, <{ i64, i32 }>* %vararg_b
uffer) |
| 43 ; CHECK-NEXT: call void @llvm.lifetime.end(i64 12, i8* %vararg_lifetime_bitcast) |
| 44 ; CHECK-NEXT: ret i32 %result |
| 45 |
| 46 |
| 47 ; Check that the pass works when there are no variable arguments. |
| 48 define i32 @call_with_zero_varargs() { |
| 49 %result = call i32 (i32, ...)* @varargs_func(i32 111) |
| 50 ret i32 %result |
| 51 } |
| 52 ; CHECK: define i32 @call_with_zero_varargs() { |
| 53 ; We have a dummy i32 field to deal with buggy programs: |
| 54 ; CHECK-NEXT: %vararg_buffer = alloca <{ i32 }> |
| 55 ; CHECK: %vararg_func = bitcast i32 (i32, ...)* bitcast (i32 (i32, i8*)* @vararg
s_func to i32 (i32, ...)*) to i32 (i32, <{ i32 }>*)* |
| 56 ; CHECK-NEXT: %result = call i32 %vararg_func(i32 111, <{ i32 }>* %vararg_buffer
) |
| 57 |
| 58 |
| 59 ; Check that "invoke" instructions are expanded out too. |
| 60 define i32 @varargs_invoke() { |
| 61 %result = invoke i32 (i32, ...)* @varargs_func(i32 111, i64 222) |
| 62 to label %cont unwind label %lpad |
| 63 cont: |
| 64 ret i32 %result |
| 65 lpad: |
| 66 %lp = landingpad { i8*, i32 } personality i8* null cleanup |
| 67 ret i32 0 |
| 68 } |
| 69 ; CHECK: @varargs_invoke |
| 70 ; CHECK: %result = invoke i32 %vararg_func(i32 111, <{ i64 }>* %vararg_buffer) |
| 71 ; CHECK-NEXT: to label %cont unwind label %lpad |
| 72 ; CHECK: cont: |
| 73 ; CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* %vararg_lifetime_bitcast) |
| 74 ; CHECK: lpad: |
| 75 ; CHECK: call void @llvm.lifetime.end(i64 8, i8* %vararg_lifetime_bitcast) |
| 76 |
| 77 |
| 78 define void @varargs_multiple_calls() { |
| 79 %call1 = call i32 (i32, ...)* @varargs_func(i32 11, i64 22, i32 33) |
| 80 %call2 = call i32 (i32, ...)* @varargs_func(i32 44, i64 55, i32 66) |
| 81 ret void |
| 82 } |
| 83 ; CHECK: @varargs_multiple_calls() |
| 84 ; The added allocas should appear at the start of the function. |
| 85 ; CHECK: %vararg_buffer{{.*}} = alloca <{ i64, i32 }> |
| 86 ; CHECK: %vararg_buffer{{.*}} = alloca <{ i64, i32 }> |
| 87 ; CHECK: %call1 = call i32 %vararg_func{{.*}}(i32 11, <{ i64, i32 }>* %vararg_bu
ffer{{.*}}) |
| 88 ; CHECK: %call2 = call i32 %vararg_func{{.*}}(i32 44, <{ i64, i32 }>* %vararg_bu
ffer{{.*}}) |
| 89 |
| 90 |
| 91 define i32 @va_arg_i32(i8* %arglist) { |
| 92 %result = va_arg i8* %arglist, i32 |
| 93 ret i32 %result |
| 94 } |
| 95 ; CHECK: define i32 @va_arg_i32(i8* %arglist) { |
| 96 ; CHECK-NEXT: %arglist1 = bitcast i8* %arglist to i32** |
| 97 ; CHECK-NEXT: %arglist_current = load i32** %arglist1 |
| 98 ; CHECK-NEXT: %result = load i32* %arglist_current |
| 99 ; CHECK-NEXT: %arglist_next = getelementptr i32* %arglist_current, i32 1 |
| 100 ; CHECK-NEXT: store i32* %arglist_next, i32** %arglist1 |
| 101 ; CHECK-NEXT: ret i32 %result |
| 102 |
| 103 |
| 104 define i64 @va_arg_i64(i8* %arglist) { |
| 105 %result = va_arg i8* %arglist, i64 |
| 106 ret i64 %result |
| 107 } |
| 108 ; CHECK: define i64 @va_arg_i64(i8* %arglist) { |
| 109 ; CHECK-NEXT: %arglist1 = bitcast i8* %arglist to i64** |
| 110 ; CHECK-NEXT: %arglist_current = load i64** %arglist1 |
| 111 ; CHECK-NEXT: %result = load i64* %arglist_current |
| 112 ; CHECK-NEXT: %arglist_next = getelementptr i64* %arglist_current, i32 1 |
| 113 ; CHECK-NEXT: store i64* %arglist_next, i64** %arglist1 |
| 114 ; CHECK-NEXT: ret i64 %result |
| 115 |
| 116 |
| 117 define void @do_va_copy(i8* %dest, i8* %src) { |
| 118 call void @llvm.va_copy(i8* %dest, i8* %src) |
| 119 ret void |
| 120 } |
| 121 ; CHECK: define void @do_va_copy(i8* %dest, i8* %src) { |
| 122 ; CHECK-NEXT: %vacopy_src = bitcast i8* %src to i8** |
| 123 ; CHECK-NEXT: %vacopy_dest = bitcast i8* %dest to i8** |
| 124 ; CHECK-NEXT: %vacopy_currentptr = load i8** %vacopy_src |
| 125 ; CHECK-NEXT: store i8* %vacopy_currentptr, i8** %vacopy_dest |
| 126 ; CHECK-NEXT: ret void |
OLD | NEW |