1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=EMSCRIPTEN 2; RUN: llc < %s -mtriple wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=UNKNOWN 3 4; Test varargs constructs. 5 6target triple = "wasm32-unknown-emscripten" 7 8; Test va_start. 9 10; TODO: Test va_start. 11; CHECK-LABEL: start: 12; CHECK-NEXT: .functype start (i32, i32) -> () 13; CHECK-NOT: __stack_pointer 14define void @start(ptr %ap, ...) { 15entry: 16; Store the second argument (the hidden vararg buffer pointer) into ap 17; CHECK: i32.store 0($0), $1 18 call void @llvm.va_start(ptr %ap) 19 ret void 20} 21 22; Test va_end. 23 24; CHECK-LABEL: end: 25; CHECK-NEXT: .functype end (i32) -> (){{$}} 26; CHECK-NEXT: return{{$}} 27define void @end(ptr %ap) { 28entry: 29 call void @llvm.va_end(ptr %ap) 30 ret void 31} 32 33; Test va_copy. 34 35; CHECK-LABEL: copy: 36; CHECK-NEXT: .functype copy (i32, i32) -> (){{$}} 37; CHECK-NEXT: i32.load $push0=, 0($1){{$}} 38; CHECK-NEXT: i32.store 0($0), $pop0{{$}} 39; CHECK-NEXT: return{{$}} 40define void @copy(ptr %ap, ptr %bp) { 41entry: 42 call void @llvm.va_copy(ptr %ap, ptr %bp) 43 ret void 44} 45 46; Test va_arg with an i8 argument. 47 48; CHECK-LABEL: arg_i8: 49; CHECK-NEXT: .functype arg_i8 (i32) -> (i32){{$}} 50; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 51; CHECK-NEXT: local.tee $push[[NUM1:[0-9]+]]=, $1=, $pop[[NUM0]]{{$}} 52; CHECK-NEXT: i32.const $push[[NUM2:[0-9]+]]=, 4{{$}} 53; CHECK-NEXT: i32.add $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}} 54; CHECK-NEXT: i32.store 0($0), $pop[[NUM3]]{{$}} 55; CHECK-NEXT: i32.load $push[[NUM4:[0-9]+]]=, 0($1){{$}} 56; CHECK-NEXT: return $pop[[NUM4]]{{$}} 57define i8 @arg_i8(ptr %ap) { 58entry: 59 %t = va_arg ptr %ap, i8 60 ret i8 %t 61} 62 63; Test va_arg with an i32 argument. 64 65; CHECK-LABEL: arg_i32: 66; CHECK-NEXT: .functype arg_i32 (i32) -> (i32){{$}} 67; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($0){{$}} 68; CHECK-NEXT: i32.const $push[[NUM1:[0-9]+]]=, 3{{$}} 69; CHECK-NEXT: i32.add $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}} 70; CHECK-NEXT: i32.const $push[[NUM3:[0-9]+]]=, -4{{$}} 71; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM2]], $pop[[NUM3]]{{$}} 72; CHECK-NEXT: local.tee $push[[NUM5:[0-9]+]]=, $1=, $pop[[NUM4]]{{$}} 73; CHECK-NEXT: i32.const $push[[NUM6:[0-9]+]]=, 4{{$}} 74; CHECK-NEXT: i32.add $push[[NUM7:[0-9]+]]=, $pop[[NUM5]], $pop[[NUM6]]{{$}} 75; CHECK-NEXT: i32.store 0($0), $pop[[NUM7]]{{$}} 76; CHECK-NEXT: i32.load $push[[NUM8:[0-9]+]]=, 0($1){{$}} 77; CHECK-NEXT: return $pop[[NUM8]]{{$}} 78define i32 @arg_i32(ptr %ap) { 79entry: 80 %t = va_arg ptr %ap, i32 81 ret i32 %t 82} 83 84; Test va_arg with an i128 argument. 85 86; CHECK-LABEL: arg_i128: 87; CHECK-NEXT: .functype arg_i128 (i32, i32) -> (){{$}} 88; CHECK: i32.and 89; CHECK: i64.load 90; CHECK: i64.load 91; CHECK: return{{$}} 92define i128 @arg_i128(ptr %ap) { 93entry: 94 %t = va_arg ptr %ap, i128 95 ret i128 %t 96} 97 98; Test a varargs call with no actual arguments. 99 100declare void @callee(...) 101 102; CHECK-LABEL: caller_none: 103; CHECK: i32.const $push0=, 0 104; CHECK-NEXT: call callee, $pop0 105; CHECK-NEXT: return{{$}} 106define void @caller_none() { 107 call void (...) @callee() 108 ret void 109} 110 111; Test a varargs call with some actual arguments. 112; Note that the store of 2.0 is converted to an i64 store; this optimization 113; is not needed on WebAssembly, but there isn't currently a convenient hook for 114; disabling it. 115 116; CHECK-LABEL: caller_some 117; CHECK-DAG: i32.store 118; CHECK-DAG: i64.store 119define void @caller_some() { 120 call void (...) @callee(i32 0, double 2.0) 121 ret void 122} 123 124; Test a va_start call in a non-entry block 125; CHECK-LABEL: startbb: 126; CHECK: .functype startbb (i32, i32, i32) -> () 127define void @startbb(i1 %cond, ptr %ap, ...) { 128entry: 129 br i1 %cond, label %bb0, label %bb1 130bb0: 131 ret void 132bb1: 133; Store the second argument (the hidden vararg buffer pointer) into ap 134; CHECK: i32.store 0($1), $2 135 call void @llvm.va_start(ptr %ap) 136 ret void 137} 138 139; Test a call to a varargs function with a non-legal fixed argument. 140 141declare void @callee_with_nonlegal_fixed(fp128, ...) nounwind 142 143; CHECK-LABEL: call_nonlegal_fixed: 144; CHECK: i64.const $push[[L0:[0-9]+]]=, 0 145; CHECK: i64.const $push[[L1:[0-9]+]]=, 0 146; CHECK: i32.const $push[[L2:[0-9]+]]=, 0 147; CHECK: call callee_with_nonlegal_fixed, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}} 148define void @call_nonlegal_fixed() nounwind { 149 call void (fp128, ...) @callee_with_nonlegal_fixed(fp128 0xL00000000000000000000000000000000) 150 ret void 151} 152 153; Test a definition a varargs function with a non-legal fixed argument. 154 155; CHECK-LABEL: nonlegal_fixed: 156; CHECK-NEXT: .functype nonlegal_fixed (i64, i64, i32) -> (){{$}} 157define void @nonlegal_fixed(fp128 %x, ...) nounwind { 158 ret void 159} 160 161; Test that an fp128 argument is properly aligned and allocated 162; within a vararg buffer. 163 164; EMSCRIPTEN-LABEL: call_fp128_alignment: 165; EMSCRIPTEN: global.get $push5=, __stack_pointer 166; EMSCRIPTEN-NEXT: i32.const $push6=, 32 167; EMSCRIPTEN-NEXT: i32.sub $push10=, $pop5, $pop6 168; EMSCRIPTEN-NEXT: local.tee $push9=, $1=, $pop10 169; EMSCRIPTEN-NEXT: global.set __stack_pointer, $pop9 170; EMSCRIPTEN-NEXT: i32.const $push0=, 16 171; EMSCRIPTEN-NEXT: i32.add $push1=, $1, $pop0 172; EMSCRIPTEN-NEXT: i64.const $push2=, -9223372036854775808 173; EMSCRIPTEN-NEXT: i64.store 0($pop1), $pop2 174; EMSCRIPTEN-NEXT: i64.const $push3=, 1 175; EMSCRIPTEN-NEXT: i64.store 8($1), $pop3 176; EMSCRIPTEN-NEXT: i32.const $push4=, 7 177; EMSCRIPTEN-NEXT: i32.store 0($1), $pop4 178; EMSCRIPTEN-NEXT: call callee, $1 179 180; Alignment of fp128 is a current disagreement between emscripten and others. 181; UNKNOWN-LABEL: call_fp128_alignment: 182; UNKNOWN: global.get $push7=, __stack_pointer 183; UNKNOWN-NEXT: i32.const $push8=, 32 184; UNKNOWN-NEXT: i32.sub $push12=, $pop7, $pop8 185; UNKNOWN-NEXT: local.tee $push11=, $1=, $pop12 186; UNKNOWN-NEXT: global.set __stack_pointer, $pop11 187; UNKNOWN-NEXT: i32.const $push0=, 24 188; UNKNOWN-NEXT: i32.add $push1=, $1, $pop0 189; UNKNOWN-NEXT: i64.const $push2=, -9223372036854775808 190; UNKNOWN-NEXT: i64.store 0($pop1), $pop2 191; UNKNOWN-NEXT: i32.const $push3=, 16 192; UNKNOWN-NEXT: i32.add $push4=, $1, $pop3 193; UNKNOWN-NEXT: i64.const $push5=, 1 194; UNKNOWN-NEXT: i64.store 0($pop4), $pop5 195; UNKNOWN-NEXT: i32.const $push6=, 7 196; UNKNOWN-NEXT: i32.store 0($1), $pop6 197; UNKNOWN-NEXT: call callee, $1 198define void @call_fp128_alignment(ptr %p) { 199entry: 200 call void (...) @callee(i8 7, fp128 0xL00000000000000018000000000000000) 201 ret void 202} 203 204declare void @llvm.va_start(ptr) 205declare void @llvm.va_end(ptr) 206declare void @llvm.va_copy(ptr, ptr) 207