[llvm] r258989 - [WebAssembly] Implement byval arguments

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 27 13:17:40 PST 2016


Author: dschuff
Date: Wed Jan 27 15:17:39 2016
New Revision: 258989

URL: http://llvm.org/viewvc/llvm-project?rev=258989&view=rev
Log:
[WebAssembly] Implement byval arguments

Summary:
Just does the simple allocation of a stack object and passes
a pointer to the callee.

Differential Revision: http://reviews.llvm.org/D16610

Added:
    llvm/trunk/test/CodeGen/WebAssembly/byval.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=258989&r1=258988&r2=258989&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Wed Jan 27 15:17:39 2016
@@ -296,16 +296,15 @@ WebAssemblyTargetLowering::LowerCall(Cal
     fail(DL, DAG, "WebAssembly doesn't support tail call yet");
   CLI.IsTailCall = false;
 
-  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
-
   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
   if (Ins.size() > 1)
     fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
 
   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
-  for (const ISD::OutputArg &Out : Outs) {
-    if (Out.Flags.isByVal())
-      fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
+  SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+  for (unsigned i = 0; i < Outs.size(); ++i) {
+    const ISD::OutputArg &Out = Outs[i];
+    SDValue &OutVal = OutVals[i];
     if (Out.Flags.isNest())
       fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
     if (Out.Flags.isInAlloca())
@@ -314,6 +313,21 @@ WebAssemblyTargetLowering::LowerCall(Cal
       fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
     if (Out.Flags.isInConsecutiveRegsLast())
       fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
+    if (Out.Flags.isByVal()) {
+      auto *MFI = MF.getFrameInfo();
+      assert(Out.Flags.getByValSize() && "Zero-size byval?");
+      int FI = MFI->CreateStackObject(Out.Flags.getByValSize(),
+                                      Out.Flags.getByValAlign(),
+                                      /*isSS=*/false);
+      SDValue SizeNode =
+          DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
+      SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
+      Chain = DAG.getMemcpy(
+          Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
+          /*isVolatile*/ false, /*AlwaysInline=*/true,
+          /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
+      OutVal = FINode;
+    }
   }
 
   bool IsVarArg = CLI.IsVarArg;
@@ -468,8 +482,6 @@ SDValue WebAssemblyTargetLowering::Lower
   MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
 
   for (const ISD::InputArg &In : Ins) {
-    if (In.Flags.isByVal())
-      fail(DL, DAG, "WebAssembly hasn't implemented byval arguments");
     if (In.Flags.isInAlloca())
       fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
     if (In.Flags.isNest())

Modified: llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt?rev=258989&r1=258988&r2=258989&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt (original)
+++ llvm/trunk/lib/Target/WebAssembly/known_gcc_test_failures.txt Wed Jan 27 15:17:39 2016
@@ -17,7 +17,6 @@ pr38151.c
 va-arg-22.c
 
 # TargetRegisterInfo.h:315: static unsigned int llvm::TargetRegisterInfo::virtReg2Index(unsigned int): Assertion `isVirtualRegister(Reg) && "Not a virtual register"' failed.
-struct-ret-1.c
 va-arg-11.c
 va-arg-21.c
 va-arg-24.c
@@ -29,20 +28,10 @@ va-arg-trap-1.c
 930628-1.c
 980707-1.c
 
-# WebAssemblyISelLowering.cpp:316: virtual llvm::SDValue llvm::WebAssemblyTargetLowering::LowerCall(llvm::TargetLowering::CallLoweringInfo&, llvm::SmallVectorImpl<llvm::SDValue>&) const: Assertion `!Out.Flags.isByVal() && "byval is not valid for return values"' failed.
-20030914-2.c
-20040703-1.c
-20081117-1.c
+# Unknown type!
+# UNREACHABLE executed at /s/llvm-upstream/llvm/lib/IR/ValueTypes.cpp:280!
 920625-1.c
-931004-11.c
-931004-13.c
-980223.c
-bitfld-5.c
-complex-7.c
-pr38969.c
-pr51323.c
-pr52129.c
-pr57130.c
+
 
 # These were previously "Cannot select FrameIndex." Now most of them fail
 # because they contain call frame pseudos (e.g. call a vararg func),
@@ -58,7 +47,6 @@ pr57130.c
 20021024-1.c
 
 20030828-1.c
-20030914-1.c
 
 20040302-1.c
 20040625-1.c
@@ -75,7 +63,6 @@ pr57130.c
 20080506-2.c
 20080519-1.c
 
-20081103-1.c
 20090113-1.c
 20090113-2.c
 20090113-3.c
@@ -103,9 +90,6 @@ pr57130.c
 
 991216-2.c
 
-#cbrt.c
-complex-5.c
-complex-6.c
 
 enum-3.c
 fprintf-chk-1.c
@@ -147,10 +131,6 @@ pr47925.c
 pr49390.c
 pr49419.c
 
-#pr51877.c
-
-#pr52979-1.c
-#pr52979-2.c
 pr53645-2.c
 pr53645.c
 
@@ -215,49 +195,6 @@ comp-goto-1.c
 980526-1.c
 990208-1.c
 
-# WebAssembly hasn't implemented byval arguments.
-20000412-3.c
-20000419-1.c
-20000706-1.c
-20000706-2.c
-20000707-1.c
-20000717-1.c
-20000717-5.c
-20000808-1.c
-20010605-2.c
-20011113-1.c
-20020215-1.c
-20020810-1.c
-20021118-1.c
-20040707-1.c
-20040709-1.c
-20040709-2.c
-20041201-1.c
-20050713-1.c
-20070614-1.c
-920908-2.c
-921112-1.c
-921117-1.c
-921123-2.c
-921204-1.c
-930126-1.c
-930208-1.c
-931004-5.c
-931004-9.c
-931031-1.c
-950607-2.c
-960416-1.c
-990525-1.c
-991118-1.c
-bf64-1.c
-complex-1.c
-complex-2.c
-pr15262-2.c
-pr20621-1.c
-pr23135.c
-pr30185.c
-pr42248.c
-
 # unimplemented operation lowering.
 20010122-1.c
 20030323-1.c

Added: llvm/trunk/test/CodeGen/WebAssembly/byval.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/byval.ll?rev=258989&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/byval.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/byval.ll Wed Jan 27 15:17:39 2016
@@ -0,0 +1,105 @@
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -fast-isel | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+%SmallStruct = type { i32 }
+%OddStruct = type { i32, i8, i32 }
+%AlignedStruct = type { double, double }
+%BigStruct = type { double, double, double, double, double, double, double, double, double, double, double, i8, i8, i8 }
+
+%BigArray = type { [33 x i8] }
+
+declare void @ext_func(%SmallStruct*)
+declare void @ext_byval_func(%SmallStruct* byval)
+declare void @ext_byval_func_align8(%SmallStruct* byval align 8)
+declare void @ext_byval_func_alignedstruct(%AlignedStruct* byval)
+declare void @ext_byval_func_bigarray(%BigArray* byval)
+
+; CHECK-LABEL: byval_arg
+define void @byval_arg(%SmallStruct* %ptr) {
+ ; CHECK: .param i32
+ ; Subtract 16 from SP (SP is 16-byte aligned)
+ ; CHECK: i32.const [[L1:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.load [[L1]]=, 0([[L1]])
+ ; CHECK-NEXT: i32.const [[L2:.+]]=, 16
+ ; CHECK-NEXT: i32.sub [[SP:.+]]=, [[L1]], [[L2]]
+ ; Ensure SP is stored back before the call
+ ; CHECK-NEXT: i32.const [[L3:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.store {{.*}}=, 0([[L3]]), [[SP]]
+ ; Copy the SmallStruct argument to the stack (SP+12, original SP-4)
+ ; CHECK-NEXT: i32.load $push[[L4:.+]]=, 0($0)
+ ; CHECK-NEXT: i32.store {{.*}}=, 12([[SP]]), $pop[[L4]]
+ ; Pass a pointer to the stack slot to the function
+ ; CHECK-NEXT: i32.const [[L5:.+]]=, 12
+ ; CHECK-NEXT: i32.add [[ARG:.+]]=, [[SP]], [[L5]]
+ ; CHECK-NEXT: call ext_byval_func at FUNCTION, [[L5]]
+ call void @ext_byval_func(%SmallStruct* byval %ptr)
+ ; Restore the stack
+ ; CHECK-NEXT: i32.const [[L6:.+]]=, 16
+ ; CHECK-NEXT: i32.add [[SP]]=, [[SP]], [[L6]]
+ ; CHECK-NEXT: i32.const [[L7:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.store {{.*}}=, 0([[L7]]), [[SP]]
+ ; CHECK-NEXT: return
+ ret void
+}
+
+; CHECK-LABEL: byval_arg_align8
+define void @byval_arg_align8(%SmallStruct* %ptr) {
+ ; CHECK: .param i32
+ ; Don't check the entire SP sequence, just enough to get the alignment.
+ ; CHECK: i32.const [[L2:.+]]=, 16
+ ; CHECK-NEXT: i32.sub [[SP:.+]]=, {{.+}}, [[L2]]
+ ; Copy the SmallStruct argument to the stack (SP+8, original SP-8)
+ ; CHECK: i32.load $push[[L4:.+]]=, 0($0):p2align=3
+ ; CHECK-NEXT: i32.store {{.*}}=, 8([[SP]]):p2align=3, $pop[[L4]]
+ ; Pass a pointer to the stack slot to the function
+ ; CHECK-NEXT: i32.const [[L5:.+]]=, 8
+ ; CHECK-NEXT: i32.add [[ARG:.+]]=, [[SP]], [[L5]]
+ ; CHECK-NEXT: call ext_byval_func_align8 at FUNCTION, [[L5]]
+ call void @ext_byval_func_align8(%SmallStruct* byval align 8 %ptr)
+ ret void
+}
+
+; CHECK-LABEL: byval_arg_double
+define void @byval_arg_double(%AlignedStruct* %ptr) {
+ ; CHECK: .param i32
+ ; Subtract 16 from SP (SP is 16-byte aligned)
+ ; CHECK: i32.const [[L2:.+]]=, 16
+ ; CHECK-NEXT: i32.sub [[SP:.+]]=, {{.+}}, [[L2]]
+ ; Copy the AlignedStruct argument to the stack (SP+0, original SP-16)
+ ; Just check the last load/store pair of the memcpy
+ ; CHECK: i64.load $push[[L4:.+]]=, 0($0)
+ ; CHECK-NEXT: i64.store {{.*}}=, 0([[SP]]), $pop[[L4]]
+ ; Pass a pointer to the stack slot to the function
+ ; CHECK-NEXT: call ext_byval_func_alignedstruct at FUNCTION, [[SP]]
+ tail call void @ext_byval_func_alignedstruct(%AlignedStruct* byval %ptr)
+ ret void
+}
+
+; CHECK-LABEL: byval_arg_big
+define void @byval_arg_big(%BigArray* %ptr) {
+ ; CHECK: .param i32
+ ; Subtract 48 from SP (SP is 16-byte aligned)
+ ; CHECK: i32.const [[L2:.+]]=, 48
+ ; CHECK-NEXT: i32.sub [[SP:.+]]=, {{.+}}, [[L2]]
+ ; Copy the AlignedStruct argument to the stack (SP+12, original SP-36)
+ ; CHECK: i64.load $push[[L4:.+]]=, 0($0):p2align=0
+ ; CHECK: i64.store {{.*}}=, 12([[SP]]):p2align=2, $pop[[L4]]
+ ; Pass a pointer to the stack slot to the function
+ ; CHECK-NEXT: i32.const [[L5:.+]]=, 12
+ ; CHECK-NEXT: i32.add [[ARG:.+]]=, [[SP]], [[L5]]
+ ; CHECK-NEXT: call ext_byval_func_bigarray at FUNCTION, [[ARG]]
+ call void @ext_byval_func_bigarray(%BigArray* byval %ptr)
+ ret void
+}
+
+; CHECK-LABEL: byval_param
+define void @byval_param(%SmallStruct* byval align 32 %ptr) {
+ ; CHECK: .param i32
+ ; %ptr is just a pointer to a struct, so pass it directly through
+ ; CHECK: call ext_func at FUNCTION, $0
+ call void @ext_func(%SmallStruct* %ptr)
+ ret void
+}




More information about the llvm-commits mailing list