1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s 2 3 ; Test varargs constructs. 4 5 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6 target triple = "wasm32-unknown-unknown" 7 8 ; Test va_start. 9 10 ; TODO: Test va_start. 11 ; CHECK-LABEL: start: 12 ; CHECK-NEXT: .param i32, i32 13 ; CHECK-NOT: __stack_pointer 14 define void @start(i8** %ap, ...) { 15 entry: 16 %0 = bitcast i8** %ap to i8* 17 ; Store the second argument (the hidden vararg buffer pointer) into ap 18 ; CHECK: i32.store $drop=, 0($0), $1 19 call void @llvm.va_start(i8* %0) 20 ret void 21 } 22 23 ; Test va_end. 24 25 ; CHECK-LABEL: end: 26 ; CHECK-NEXT: .param i32{{$}} 27 ; CHECK-NEXT: return{{$}} 28 define void @end(i8** %ap) { 29 entry: 30 %0 = bitcast i8** %ap to i8* 31 call void @llvm.va_end(i8* %0) 32 ret void 33 } 34 35 ; Test va_copy. 36 37 ; CHECK-LABEL: copy: 38 ; CHECK-NEXT: .param i32, i32{{$}} 39 ; CHECK-NEXT: i32.load $push0=, 0($1){{$}} 40 ; CHECK-NEXT: i32.store $drop=, 0($0), $pop0{{$}} 41 ; CHECK-NEXT: return{{$}} 42 define void @copy(i8** %ap, i8** %bp) { 43 entry: 44 %0 = bitcast i8** %ap to i8* 45 %1 = bitcast i8** %bp to i8* 46 call void @llvm.va_copy(i8* %0, i8* %1) 47 ret void 48 } 49 50 ; Test va_arg with an i8 argument. 51 52 ; CHECK-LABEL: arg_i8: 53 ; CHECK-NEXT: .param i32{{$}} 54 ; CHECK-NEXT: .result i32{{$}} 55 ; CHECK-NEXT: .local i32{{$}} 56 ; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 57 ; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $1=, $pop[[NUM0]]{{$}} 58 ; CHECK-NEXT: i32.const $push[[NUM2:[0-9]+]]=, 4{{$}} 59 ; CHECK-NEXT: i32.add $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}} 60 ; CHECK-NEXT: i32.store $drop=, 0($0), $pop[[NUM3]]{{$}} 61 ; CHECK-NEXT: i32.load $push[[NUM4:[0-9]+]]=, 0($1){{$}} 62 ; CHECK-NEXT: return $pop[[NUM4]]{{$}} 63 define i8 @arg_i8(i8** %ap) { 64 entry: 65 %t = va_arg i8** %ap, i8 66 ret i8 %t 67 } 68 69 ; Test va_arg with an i32 argument. 70 71 ; CHECK-LABEL: arg_i32: 72 ; CHECK-NEXT: .param i32{{$}} 73 ; CHECK-NEXT: .result i32{{$}} 74 ; CHECK-NEXT: .local i32{{$}} 75 ; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 76 ; CHECK-NEXT: i32.const $push[[NUM1:[0-9]+]]=, 3{{$}} 77 ; CHECK-NEXT: i32.add $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}} 78 ; CHECK-NEXT: i32.const $push[[NUM3:[0-9]+]]=, -4{{$}} 79 ; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM2]], $pop[[NUM3]]{{$}} 80 ; CHECK-NEXT: tee_local $push[[NUM5:[0-9]+]]=, $1=, $pop[[NUM4]]{{$}} 81 ; CHECK-NEXT: i32.const $push[[NUM6:[0-9]+]]=, 4{{$}} 82 ; CHECK-NEXT: i32.add $push[[NUM7:[0-9]+]]=, $pop[[NUM5]], $pop[[NUM6]]{{$}} 83 ; CHECK-NEXT: i32.store $drop=, 0($0), $pop[[NUM7]]{{$}} 84 ; CHECK-NEXT: i32.load $push[[NUM8:[0-9]+]]=, 0($1){{$}} 85 ; CHECK-NEXT: return $pop[[NUM8]]{{$}} 86 define i32 @arg_i32(i8** %ap) { 87 entry: 88 %t = va_arg i8** %ap, i32 89 ret i32 %t 90 } 91 92 ; Test va_arg with an i128 argument. 93 94 ; CHECK-LABEL: arg_i128: 95 ; CHECK-NEXT: .param i32, i32{{$}} 96 ; CHECK-NEXT: .local 97 ; CHECK: i32.and 98 ; CHECK: i64.load 99 ; CHECK: i64.load 100 ; CHECK: return{{$}} 101 define i128 @arg_i128(i8** %ap) { 102 entry: 103 %t = va_arg i8** %ap, i128 104 ret i128 %t 105 } 106 107 ; Test a varargs call with no actual arguments. 108 109 declare void @callee(...) 110 111 ; CHECK-LABEL: caller_none: 112 ; CHECK-NEXT: i32.const $push0=, 0 113 ; CHECK-NEXT: call callee@FUNCTION, $pop0 114 ; CHECK-NEXT: return{{$}} 115 define void @caller_none() { 116 call void (...) @callee() 117 ret void 118 } 119 120 ; Test a varargs call with some actual arguments. 121 ; Note that the store of 2.0 is converted to an i64 store; this optimization 122 ; is not needed on WebAssembly, but there isn't currently a convenient hook for 123 ; disabling it. 124 125 ; CHECK-LABEL: caller_some 126 ; CHECK: i32.store 127 ; CHECK: i64.store 128 define void @caller_some() { 129 call void (...) @callee(i32 0, double 2.0) 130 ret void 131 } 132 133 ; Test a va_start call in a non-entry block 134 ; CHECK-LABEL: startbb: 135 ; CHECK: .param i32, i32, i32 136 define void @startbb(i1 %cond, i8** %ap, ...) { 137 entry: 138 br i1 %cond, label %bb0, label %bb1 139 bb0: 140 ret void 141 bb1: 142 %0 = bitcast i8** %ap to i8* 143 ; Store the second argument (the hidden vararg buffer pointer) into ap 144 ; CHECK: i32.store $drop=, 0($1), $2 145 call void @llvm.va_start(i8* %0) 146 ret void 147 } 148 149 150 declare void @llvm.va_start(i8*) 151 declare void @llvm.va_end(i8*) 152 declare void @llvm.va_copy(i8*, i8*) 153