1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s 2 3; Test varargs constructs. 4 5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6target 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 14define void @start(i8** %ap, ...) { 15entry: 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{{$}} 28define void @end(i8** %ap) { 29entry: 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{{$}} 42define void @copy(i8** %ap, i8** %bp) { 43entry: 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]]{{$}} 63define i8 @arg_i8(i8** %ap) { 64entry: 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]]{{$}} 86define i32 @arg_i32(i8** %ap) { 87entry: 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{{$}} 101define i128 @arg_i128(i8** %ap) { 102entry: 103 %t = va_arg i8** %ap, i128 104 ret i128 %t 105} 106 107; Test a varargs call with no actual arguments. 108 109declare 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{{$}} 115define 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 128define 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 136define void @startbb(i1 %cond, i8** %ap, ...) { 137entry: 138 br i1 %cond, label %bb0, label %bb1 139bb0: 140 ret void 141bb1: 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 150declare void @llvm.va_start(i8*) 151declare void @llvm.va_end(i8*) 152declare void @llvm.va_copy(i8*, i8*) 153