diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
10 files changed, 66 insertions, 38 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 405a2a977a0..5a3e02133f5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -377,6 +377,10 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments( if (IsVarArg) fail(DL, DAG, "WebAssembly doesn't support varargs yet"); + // Set up the incoming ARGUMENTS value, which serves to represent the liveness + // of the incoming values before they're represented by virtual registers. + MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); + for (const ISD::InputArg &In : Ins) { if (In.Flags.isByVal()) fail(DL, DAG, "WebAssembly hasn't implemented byval arguments"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td index 530411b147d..4028460bd23 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -12,6 +12,8 @@ /// //===----------------------------------------------------------------------===// +let Defs = [ARGUMENTS] in { + // The call sequence start/end LLVM-isms isn't useful to WebAssembly since it's // a virtual ISA. let isCodeGenOnly = 1 in { @@ -42,3 +44,5 @@ let Uses = [SP32, SP64], isCall = 1 in { [(WebAssemblycall0 I32:$callee)], "call_indirect\t$callee">; } // Uses = [SP32,SP64], isCall = 1 + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index 7fa4c5613e9..840f7d66931 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -12,6 +12,8 @@ /// //===----------------------------------------------------------------------===// +let Defs = [ARGUMENTS] in { + let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { def BR_IF : I<(outs), (ins I32:$a, bb_op:$dst), [(brcond I32:$a, bb:$dst)], @@ -59,3 +61,5 @@ let isReturn = 1 in { } // isReturn = 1 def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable">; } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td index a4ae5fe7c6d..a34916eb5a2 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td @@ -13,6 +13,8 @@ /// //===----------------------------------------------------------------------===// +let Defs = [ARGUMENTS] in { + def I32_WRAP_I64 : I<(outs I32:$dst), (ins I64:$src), [(set I32:$dst, (trunc I64:$src))], "i32.wrap/i64\t$dst, $src">; @@ -93,3 +95,5 @@ def I64_REINTERPRET_F64 : I<(outs I64:$dst), (ins F64:$src), def F64_REINTERPRET_I64 : I<(outs F64:$dst), (ins I64:$src), [(set F64:$dst, (bitconvert I64:$src))], "f64.reinterpret/i64\t$dst, $src">; + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td index 33efbb350cb..a24c8bfdef3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td @@ -12,6 +12,8 @@ /// //===----------------------------------------------------------------------===// +let Defs = [ARGUMENTS] in { + defm ADD : BinaryFP<fadd, "add ">; defm SUB : BinaryFP<fsub, "sub ">; defm MUL : BinaryFP<fmul, "mul ">; @@ -30,10 +32,14 @@ defm FLOOR : UnaryFP<ffloor, "floor">; defm TRUNC : UnaryFP<ftrunc, "trunc">; defm NEAREST : UnaryFP<fnearbyint, "nearest">; +} // Defs = [ARGUMENTS] + // WebAssembly doesn't expose inexact exceptions, so map frint to fnearbyint. def : Pat<(frint f32:$src), (NEAREST_F32 f32:$src)>; def : Pat<(frint f64:$src), (NEAREST_F64 f64:$src)>; +let Defs = [ARGUMENTS] in { + defm EQ : ComparisonFP<SETOEQ, "eq ">; defm NE : ComparisonFP<SETUNE, "ne ">; defm LT : ComparisonFP<SETOLT, "lt ">; @@ -41,6 +47,8 @@ defm LE : ComparisonFP<SETOLE, "le ">; defm GT : ComparisonFP<SETOGT, "gt ">; defm GE : ComparisonFP<SETOGE, "ge ">; +} // Defs = [ARGUMENTS] + // Don't care floating-point comparisons, supported via other comparisons. def : Pat<(seteq f32:$lhs, f32:$rhs), (EQ_F32 f32:$lhs, f32:$rhs)>; def : Pat<(setne f32:$lhs, f32:$rhs), (NE_F32 f32:$lhs, f32:$rhs)>; @@ -55,9 +63,13 @@ def : Pat<(setle f64:$lhs, f64:$rhs), (LE_F64 f64:$lhs, f64:$rhs)>; def : Pat<(setgt f64:$lhs, f64:$rhs), (GT_F64 f64:$lhs, f64:$rhs)>; def : Pat<(setge f64:$lhs, f64:$rhs), (GE_F64 f64:$lhs, f64:$rhs)>; +let Defs = [ARGUMENTS] in { + def SELECT_F32 : I<(outs F32:$dst), (ins I32:$cond, F32:$lhs, F32:$rhs), [(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))], "f32.select\t$dst, $cond, $lhs, $rhs">; def SELECT_F64 : I<(outs F64:$dst), (ins I32:$cond, F64:$lhs, F64:$rhs), [(set F64:$dst, (select I32:$cond, F64:$lhs, F64:$rhs))], "f64.select\t$dst, $cond, $lhs, $rhs">; + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index e9a16cec33a..52e0bd6e97f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -81,6 +81,7 @@ include "WebAssemblyInstrFormats.td" //===----------------------------------------------------------------------===// multiclass ARGUMENT<WebAssemblyRegClass vt> { + let hasSideEffects = 1, Uses = [ARGUMENTS] in def ARGUMENT_#vt : I<(outs vt:$res), (ins i32imm:$argno), [(set vt:$res, (WebAssemblyargument timm:$argno))]>; } @@ -89,6 +90,8 @@ defm : ARGUMENT<I64>; defm : ARGUMENT<F32>; defm : ARGUMENT<F64>; +let Defs = [ARGUMENTS] in { + // get_local and set_local are not generated by instruction selection; they // are implied by virtual register uses and defs in most contexts. However, // they are explicitly emitted for special purposes. @@ -125,11 +128,15 @@ def CONST_F64 : I<(outs F64:$res), (ins f64imm:$imm), [(set F64:$res, fpimm:$imm)], "f64.const\t$res, $imm">; +} // Defs = [ARGUMENTS] + def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$dst)), (CONST_I32 tglobaladdr:$dst)>; def : Pat<(i32 (WebAssemblywrapper texternalsym:$dst)), (CONST_I32 texternalsym:$dst)>; +let Defs = [ARGUMENTS] in { + def JUMP_TABLE : I<(outs I32:$dst), (ins tjumptable_op:$addr), [(set I32:$dst, (WebAssemblywrapper tjumptable:$addr))], "jump_table\t$dst, $addr">; @@ -139,6 +146,8 @@ def PARAM : I<(outs), (ins variable_ops), [], ".param \t">; def RESULT : I<(outs), (ins variable_ops), [], ".result \t">; def LOCAL : I<(outs), (ins variable_ops), [], ".local \t">; +} // Defs = [ARGUMENTS] + //===----------------------------------------------------------------------===// // Additional sets of instructions. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td index 1d634dfae08..bc00cd6b4f7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td @@ -12,6 +12,8 @@ /// //===----------------------------------------------------------------------===// +let Defs = [ARGUMENTS] in { + // The spaces after the names are for aesthetic purposes only, to make // operands line up vertically after tab expansion. defm ADD : BinaryInt<add, "add ">; @@ -43,15 +45,21 @@ defm CLZ : UnaryInt<ctlz, "clz ">; defm CTZ : UnaryInt<cttz, "ctz ">; defm POPCNT : UnaryInt<ctpop, "popcnt">; +} // Defs = [ARGUMENTS] + // Expand the "don't care" operations to supported operations. def : Pat<(ctlz_zero_undef I32:$src), (CLZ_I32 I32:$src)>; def : Pat<(ctlz_zero_undef I64:$src), (CLZ_I64 I64:$src)>; def : Pat<(cttz_zero_undef I32:$src), (CTZ_I32 I32:$src)>; def : Pat<(cttz_zero_undef I64:$src), (CTZ_I64 I64:$src)>; +let Defs = [ARGUMENTS] in { + def SELECT_I32 : I<(outs I32:$dst), (ins I32:$cond, I32:$lhs, I32:$rhs), [(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))], "i32.select\t$dst, $cond, $lhs, $rhs">; def SELECT_I64 : I<(outs I64:$dst), (ins I32:$cond, I64:$lhs, I64:$rhs), [(set I64:$dst, (select I32:$cond, I64:$lhs, I64:$rhs))], "i64.select\t$dst, $cond, $lhs, $rhs">; + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td index f0cc02ada65..700a196fa29 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -22,6 +22,8 @@ // local types. These memory-only types instead zero- or sign-extend into local // types when loading, and truncate when storing. +let Defs = [ARGUMENTS] in { + // Basic load. def LOAD_I32 : I<(outs I32:$dst), (ins I32:$addr), [(set I32:$dst, (load I32:$addr))], @@ -68,6 +70,8 @@ def LOAD32_U_I64 : I<(outs I64:$dst), (ins I32:$addr), [(set I64:$dst, (zextloadi32 I32:$addr))], "i64.load32_u\t$dst, $addr">; +} // Defs = [ARGUMENTS] + // "Don't care" extending load become zero-extending load. def : Pat<(i32 (extloadi8 I32:$addr)), (LOAD8_U_I32 $addr)>; def : Pat<(i32 (extloadi16 I32:$addr)), (LOAD16_U_I32 $addr)>; @@ -75,6 +79,8 @@ def : Pat<(i64 (extloadi8 I32:$addr)), (LOAD8_U_I64 $addr)>; def : Pat<(i64 (extloadi16 I32:$addr)), (LOAD16_U_I64 $addr)>; def : Pat<(i64 (extloadi32 I32:$addr)), (LOAD32_U_I64 $addr)>; +let Defs = [ARGUMENTS] in { + // Basic store. // Note that we split the patterns out of the instruction definitions because // WebAssembly's stores return their operand value, and tablegen doesn't like @@ -90,11 +96,15 @@ def STORE_F32 : I<(outs F32:$dst), (ins I32:$addr, F32:$val), [], def STORE_F64 : I<(outs F64:$dst), (ins I32:$addr, F64:$val), [], "f64.store\t$dst, $addr, $val">; +} // Defs = [ARGUMENTS] + def : Pat<(store I32:$val, I32:$addr), (STORE_I32 I32:$addr, I32:$val)>; def : Pat<(store I64:$val, I32:$addr), (STORE_I64 I32:$addr, I64:$val)>; def : Pat<(store F32:$val, I32:$addr), (STORE_F32 I32:$addr, F32:$val)>; def : Pat<(store F64:$val, I32:$addr), (STORE_F64 I32:$addr, F64:$val)>; +let Defs = [ARGUMENTS] in { + // Truncating store. def STORE8_I32 : I<(outs I32:$dst), (ins I32:$addr, I32:$val), [], "i32.store8\t$dst, $addr, $val">; @@ -107,6 +117,8 @@ def STORE16_I64 : I<(outs I64:$dst), (ins I32:$addr, I64:$val), [], def STORE32_I64 : I<(outs I64:$dst), (ins I32:$addr, I64:$val), [], "i64.store32\t$dst, $addr, $val">; +} // Defs = [ARGUMENTS] + def : Pat<(truncstorei8 I32:$val, I32:$addr), (STORE8_I32 I32:$addr, I32:$val)>; def : Pat<(truncstorei16 I32:$val, I32:$addr), @@ -118,6 +130,8 @@ def : Pat<(truncstorei16 I64:$val, I32:$addr), def : Pat<(truncstorei32 I64:$val, I32:$addr), (STORE32_I64 I32:$addr, I64:$val)>; +let Defs = [ARGUMENTS] in { + // Memory size. def MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins), [(set I32:$dst, (int_wasm_memory_size))], @@ -137,3 +151,5 @@ def GROW_MEMORY_I64 : I<(outs), (ins I64:$delta), [(int_wasm_grow_memory I64:$delta)], "grow_memory\t$delta">, Requires<[HasAddr64]>; + +} // Defs = [ARGUMENTS] diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp index b497612b54e..9ec66595d8d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp @@ -19,7 +19,6 @@ #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -46,7 +45,6 @@ public: AU.addRequired<MachineBlockFrequencyInfo>(); AU.addPreserved<MachineBlockFrequencyInfo>(); AU.addPreservedID(MachineDominatorsID); - AU.addRequired<SlotIndexes>(); // for ARGUMENT fixups MachineFunctionPass::getAnalysisUsage(AU); } @@ -96,42 +94,6 @@ bool WebAssemblyRegColoring::runOnMachineFunction(MachineFunction &MF) { SmallVector<LiveInterval *, 0> SortedIntervals; SortedIntervals.reserve(NumVRegs); - // FIXME: If scheduling has moved an ARGUMENT virtual register, move it back, - // and recompute liveness. This is a temporary hack. - bool MovedArg = false; - MachineBasicBlock &EntryMBB = MF.front(); - MachineBasicBlock::iterator InsertPt = EntryMBB.end(); - // Look for the first NonArg instruction. - for (auto MII = EntryMBB.begin(), MIE = EntryMBB.end(); MII != MIE; ++MII) { - MachineInstr *MI = MII; - if (MI->getOpcode() != WebAssembly::ARGUMENT_I32 && - MI->getOpcode() != WebAssembly::ARGUMENT_I64 && - MI->getOpcode() != WebAssembly::ARGUMENT_F32 && - MI->getOpcode() != WebAssembly::ARGUMENT_F64) { - InsertPt = MII; - break; - } - } - // Now move any argument instructions later in the block - // to before our first NonArg instruction. - for (auto I = InsertPt, E = EntryMBB.end(); I != E; ++I) { - MachineInstr *MI = I; - if (MI->getOpcode() == WebAssembly::ARGUMENT_I32 || - MI->getOpcode() == WebAssembly::ARGUMENT_I64 || - MI->getOpcode() == WebAssembly::ARGUMENT_F32 || - MI->getOpcode() == WebAssembly::ARGUMENT_F64) { - EntryMBB.insert(InsertPt, MI->removeFromParent()); - MovedArg = true; - } - } - if (MovedArg) { - SlotIndexes &Slots = getAnalysis<SlotIndexes>(); - Liveness->releaseMemory(); - Slots.releaseMemory(); - Slots.runOnMachineFunction(MF); - Liveness->runOnMachineFunction(MF); - } - DEBUG(dbgs() << "Interesting register intervals:\n"); for (unsigned i = 0; i < NumVRegs; ++i) { unsigned VReg = TargetRegisterInfo::index2VirtReg(i); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td index 2cf1e38b25b..4057ff7a9b4 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td @@ -43,6 +43,11 @@ def F64_0 : WebAssemblyReg<"%f64.0">; // order uses and defs that must remain in FIFO order. def EXPR_STACK : WebAssemblyReg<"STACK">; +// The incoming arguments "register". This is an opaque entity which serves to +// order the ARGUMENT instructions that are emulating live-in registers and +// must not be scheduled below other instructions. +def ARGUMENTS : WebAssemblyReg<"ARGUMENTS">; + //===----------------------------------------------------------------------===// // Register classes //===----------------------------------------------------------------------===// |