]> granicus.if.org Git - llvm/commitdiff
[WebAssembly] Properly align fp128 arguments in outgoing varargs arguments
authorDan Gohman <dan433584@gmail.com>
Tue, 26 Feb 2019 05:20:19 +0000 (05:20 +0000)
committerDan Gohman <dan433584@gmail.com>
Tue, 26 Feb 2019 05:20:19 +0000 (05:20 +0000)
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

lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
test/CodeGen/WebAssembly/varargs.ll

index a4246eb8eb91994538a09b114d15579a1734828e..50bd5a94f4b7ebdb567b5b333d2eee905d4f91da 100644 (file)
@@ -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));
index cf634beb89a7cb3b8271993f4b3df801879a4e5e..c36912854c0c19c22ce34877a1e4d32c23fde807 100644 (file)
@@ -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*)