[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