1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -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 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 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: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 56; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $1=, $pop[[NUM0]]{{$}} 57; CHECK-NEXT: i32.const $push[[NUM2:[0-9]+]]=, 4{{$}} 58; CHECK-NEXT: i32.add $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}} 59; CHECK-NEXT: i32.store 0($0), $pop[[NUM3]]{{$}} 60; CHECK-NEXT: i32.load $push[[NUM4:[0-9]+]]=, 0($1){{$}} 61; CHECK-NEXT: return $pop[[NUM4]]{{$}} 62define i8 @arg_i8(i8** %ap) { 63entry: 64 %t = va_arg i8** %ap, i8 65 ret i8 %t 66} 67 68; Test va_arg with an i32 argument. 69 70; CHECK-LABEL: arg_i32: 71; CHECK-NEXT: .param i32{{$}} 72; CHECK-NEXT: .result i32{{$}} 73; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 74; CHECK-NEXT: i32.const $push[[NUM1:[0-9]+]]=, 3{{$}} 75; CHECK-NEXT: i32.add $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}} 76; CHECK-NEXT: i32.const $push[[NUM3:[0-9]+]]=, -4{{$}} 77; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM2]], $pop[[NUM3]]{{$}} 78; CHECK-NEXT: tee_local $push[[NUM5:[0-9]+]]=, $1=, $pop[[NUM4]]{{$}} 79; CHECK-NEXT: i32.const $push[[NUM6:[0-9]+]]=, 4{{$}} 80; CHECK-NEXT: i32.add $push[[NUM7:[0-9]+]]=, $pop[[NUM5]], $pop[[NUM6]]{{$}} 81; CHECK-NEXT: i32.store 0($0), $pop[[NUM7]]{{$}} 82; CHECK-NEXT: i32.load $push[[NUM8:[0-9]+]]=, 0($1){{$}} 83; CHECK-NEXT: return $pop[[NUM8]]{{$}} 84define i32 @arg_i32(i8** %ap) { 85entry: 86 %t = va_arg i8** %ap, i32 87 ret i32 %t 88} 89 90; Test va_arg with an i128 argument. 91 92; CHECK-LABEL: arg_i128: 93; CHECK-NEXT: .param i32, i32{{$}} 94; CHECK: i32.and 95; CHECK: i64.load 96; CHECK: i64.load 97; CHECK: return{{$}} 98define i128 @arg_i128(i8** %ap) { 99entry: 100 %t = va_arg i8** %ap, i128 101 ret i128 %t 102} 103 104; Test a varargs call with no actual arguments. 105 106declare void @callee(...) 107 108; CHECK-LABEL: caller_none: 109; CHECK-NEXT: i32.const $push0=, 0 110; CHECK-NEXT: call callee@FUNCTION, $pop0 111; CHECK-NEXT: return{{$}} 112define void @caller_none() { 113 call void (...) @callee() 114 ret void 115} 116 117; Test a varargs call with some actual arguments. 118; Note that the store of 2.0 is converted to an i64 store; this optimization 119; is not needed on WebAssembly, but there isn't currently a convenient hook for 120; disabling it. 121 122; CHECK-LABEL: caller_some 123; CHECK-DAG: i32.store 124; CHECK-DAG: i64.store 125define void @caller_some() { 126 call void (...) @callee(i32 0, double 2.0) 127 ret void 128} 129 130; Test a va_start call in a non-entry block 131; CHECK-LABEL: startbb: 132; CHECK: .param i32, i32, i32 133define void @startbb(i1 %cond, i8** %ap, ...) { 134entry: 135 br i1 %cond, label %bb0, label %bb1 136bb0: 137 ret void 138bb1: 139 %0 = bitcast i8** %ap to i8* 140; Store the second argument (the hidden vararg buffer pointer) into ap 141; CHECK: i32.store 0($1), $2 142 call void @llvm.va_start(i8* %0) 143 ret void 144} 145 146; Test a call to a varargs function with a non-legal fixed argument. 147 148declare void @callee_with_nonlegal_fixed(fp128, ...) nounwind 149 150; CHECK-LABEL: call_nonlegal_fixed: 151; CHECK: i64.const $push[[L0:[0-9]+]]=, 0 152; CHECK: i64.const $push[[L1:[0-9]+]]=, 0 153; CHECK: i32.const $push[[L2:[0-9]+]]=, 0 154; CHECK: call callee_with_nonlegal_fixed@FUNCTION, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}} 155define void @call_nonlegal_fixed() nounwind { 156 call void (fp128, ...) @callee_with_nonlegal_fixed(fp128 0xL00000000000000000000000000000000) 157 ret void 158} 159 160; Test a definition a varargs function with a non-legal fixed argument. 161 162; CHECK-LABEL: nonlegal_fixed: 163; CHECK-NEXT: .param i64, i64, i32{{$}} 164define void @nonlegal_fixed(fp128 %x, ...) nounwind { 165 ret void 166} 167 168declare void @llvm.va_start(i8*) 169declare void @llvm.va_end(i8*) 170declare void @llvm.va_copy(i8*, i8*) 171