From 6ad42d1fab45d488e0661bd63ed0410cb5280934 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 26 Feb 2019 05:20:19 +0000 Subject: [PATCH] [WebAssembly] Properly align fp128 arguments in outgoing varargs arguments For outgoing varargs arguments, it's necessary to check the OrigAlign field of the corresponding OutputArg entry to determine argument alignment, rather than just computing an alignment from the argument value type. This is because types like fp128 are split into multiple argument values, with narrower types that don't reflect the ABI alignment of the full fp128. This fixes the printf("printfL: %4.*Lf\n", 2, lval); testcase. Differential Revision: https://reviews.llvm.org/D58656 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354846 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../WebAssembly/WebAssemblyISelLowering.cpp | 9 ++++--- test/CodeGen/WebAssembly/varargs.ll | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index a4246eb8eb9..50bd5a94f4b 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -674,13 +674,16 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, if (IsVarArg) { // Outgoing non-fixed arguments are placed in a buffer. First // compute their offsets and the total amount of buffer space needed. - for (SDValue Arg : - make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) { + for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) { + const ISD::OutputArg &Out = Outs[I]; + SDValue &Arg = OutVals[I]; EVT VT = Arg.getValueType(); assert(VT != MVT::iPTR && "Legalized args should be concrete"); Type *Ty = VT.getTypeForEVT(*DAG.getContext()); + unsigned Align = std::max(Out.Flags.getOrigAlign(), + Layout.getABITypeAlignment(Ty)); unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), - Layout.getABITypeAlignment(Ty)); + Align); CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(), Offset, VT.getSimpleVT(), CCValAssign::Full)); diff --git a/test/CodeGen/WebAssembly/varargs.ll b/test/CodeGen/WebAssembly/varargs.ll index cf634beb89a..c36912854c0 100644 --- a/test/CodeGen/WebAssembly/varargs.ll +++ b/test/CodeGen/WebAssembly/varargs.ll @@ -163,6 +163,32 @@ define void @nonlegal_fixed(fp128 %x, ...) nounwind { ret void } +; Test that an fp128 argument is properly aligned and allocated +; within a vararg buffer. + +; CHECK-LABEL: call_fp128_alignment: +; CHECK: global.get $push7=, __stack_pointer +; CHECK-NEXT: i32.const $push8=, 32 +; CHECK-NEXT: i32.sub $push12=, $pop7, $pop8 +; CHECK-NEXT: local.tee $push11=, $1=, $pop12 +; CHECK-NEXT: global.set __stack_pointer, $pop11 +; CHECK-NEXT: i32.const $push0=, 24 +; CHECK-NEXT: i32.add $push1=, $1, $pop0 +; CHECK-NEXT: i64.const $push2=, -9223372036854775808 +; CHECK-NEXT: i64.store 0($pop1), $pop2 +; CHECK-NEXT: i32.const $push3=, 16 +; CHECK-NEXT: i32.add $push4=, $1, $pop3 +; CHECK-NEXT: i64.const $push5=, 1 +; CHECK-NEXT: i64.store 0($pop4), $pop5 +; CHECK-NEXT: i32.const $push6=, 7 +; CHECK-NEXT: i32.store 0($1), $pop6 +; CHECK-NEXT: call callee, $1 +define void @call_fp128_alignment(i8* %p) { +entry: + call void (...) @callee(i8 7, fp128 0xL00000000000000018000000000000000) + ret void +} + declare void @llvm.va_start(i8*) declare void @llvm.va_end(i8*) declare void @llvm.va_copy(i8*, i8*) -- 2.40.0