diff options
Diffstat (limited to 'llvm/lib')
8 files changed, 126 insertions, 71 deletions
diff --git a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp index d3c4861e1d6..aed722cf739 100644 --- a/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -38,8 +38,8 @@ WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI, void WebAssemblyInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { assert(RegNo != WebAssemblyFunctionInfo::UnusedReg); - // FIXME: Revisit whether we actually print the get_local explicitly. - OS << "(get_local " << RegNo << ")"; + // Note that there's an implicit get_local/set_local here! + OS << "$" << RegNo; } void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, @@ -56,20 +56,6 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, } printAnnotation(OS, Annot); - - unsigned NumDefs = MII.get(MI->getOpcode()).getNumDefs(); - assert(NumDefs <= 1 && - "Instructions with multiple result values not implemented"); - - // FIXME: Revisit whether we actually print the set_local explicitly. - if (NumDefs != 0) { - unsigned WAReg = MI->getOperand(0).getReg(); - // Only print the set_local if the register is used. - // TODO: Revisit this once the spec explains what should happen here. - if (WAReg != WebAssemblyFunctionInfo::UnusedReg) - OS << "\n" - "\t" "set_local " << WAReg << ", $pop"; - } } static std::string toString(const APFloat &FP) { @@ -93,14 +79,15 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isReg()) { - if (OpNo >= MII.get(MI->getOpcode()).getNumDefs()) - printRegName(O, Op.getReg()); - else { - if (Op.getReg() != WebAssemblyFunctionInfo::UnusedReg) - O << "$push"; - else - O << "$discard"; - } + unsigned WAReg = Op.getReg(); + if (int(WAReg) >= 0) + printRegName(O, WAReg); + else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs()) + O << "$pop" << (WAReg & INT32_MAX); + else if (WAReg != WebAssemblyFunctionInfo::UnusedReg) + O << "$push" << (WAReg & INT32_MAX); + else + O << "$discard"; } else if (Op.isImm()) O << Op.getImm(); else if (Op.isFPImm()) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 0516e7a3bd8..400e85748eb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -110,9 +110,10 @@ std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { if (TargetRegisterInfo::isPhysicalRegister(RegNo)) return WebAssemblyInstPrinter::getRegisterName(RegNo); + assert(!MFI->isVRegStackified(RegNo)); unsigned WAReg = MFI->getWAReg(RegNo); assert(WAReg != WebAssemblyFunctionInfo::UnusedReg); - return utostr(WAReg); + return '$' + utostr(WAReg); } const char *WebAssemblyAsmPrinter::toString(MVT VT) const { @@ -179,19 +180,27 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { if (ResultVTs.size() == 1) OS << "\t" ".result " << toString(ResultVTs.front()) << '\n'; - bool FirstVReg = true; + bool FirstWAReg = true; for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) { unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx); - if (!MRI->use_empty(VReg)) { - if (FirstVReg) - OS << "\t" ".local "; - else - OS << ", "; - OS << getRegTypeName(VReg); - FirstVReg = false; - } + unsigned WAReg = MFI->getWAReg(VReg); + // Don't declare unused registers. + if (WAReg == WebAssemblyFunctionInfo::UnusedReg) + continue; + // Don't redeclare parameters. + if (WAReg < MFI->getParams().size()) + continue; + // Don't declare stackified registers. + if (int(WAReg) < 0) + continue; + if (FirstWAReg) + OS << "\t" ".local "; + else + OS << ", "; + OS << getRegTypeName(VReg); + FirstWAReg = false; } - if (!FirstVReg) + if (!FirstWAReg) OS << '\n'; // EmitRawText appends a newline, so strip off the last newline. @@ -204,19 +213,7 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); - assert(MI->getDesc().getNumDefs() <= 1 && - "Instructions with multiple result values not implemented"); - switch (MI->getOpcode()) { - case TargetOpcode::COPY: { - // TODO: Figure out a way to lower COPY instructions to MCInst form. - SmallString<128> Str; - raw_svector_ostream OS(Str); - OS << "\t" "set_local " << regToString(MI->getOperand(0)) << ", " - "(get_local " << regToString(MI->getOperand(1)) << ")"; - OutStreamer->EmitRawText(OS.str()); - break; - } case WebAssembly::ARGUMENT_I32: case WebAssembly::ARGUMENT_I64: case WebAssembly::ARGUMENT_F32: @@ -234,8 +231,6 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { } } - - void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { const DataLayout &DL = M.getDataLayout(); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index ed30b535480..97e848709c3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -34,7 +34,22 @@ void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, DebugLoc DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { - BuildMI(MBB, I, DL, get(WebAssembly::COPY), DestReg) + const TargetRegisterClass *RC = + MBB.getParent()->getRegInfo().getRegClass(SrcReg); + + unsigned SetLocalOpcode; + if (RC == &WebAssembly::I32RegClass) + SetLocalOpcode = WebAssembly::SET_LOCAL_I32; + else if (RC == &WebAssembly::I64RegClass) + SetLocalOpcode = WebAssembly::SET_LOCAL_I64; + else if (RC == &WebAssembly::F32RegClass) + SetLocalOpcode = WebAssembly::SET_LOCAL_F32; + else if (RC == &WebAssembly::F64RegClass) + SetLocalOpcode = WebAssembly::SET_LOCAL_F64; + else + llvm_unreachable("Unexpected register class"); + + BuildMI(MBB, I, DL, get(SetLocalOpcode), DestReg) .addReg(SrcReg, KillSrc ? RegState::Kill : 0); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 9d595198220..382f928be74 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -66,13 +66,6 @@ def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper", // WebAssembly-specific Operands. //===----------------------------------------------------------------------===// -/* - * TODO(jfb): Add the following. - * - * get_local: read the current value of a local variable - * set_local: set the current value of a local variable -*/ - def bb_op : Operand<OtherVT>; def tjumptable_op : Operand<iPTR>; def global : Operand<iPTR>; @@ -83,6 +76,10 @@ def global : Operand<iPTR>; include "WebAssemblyInstrFormats.td" +//===----------------------------------------------------------------------===// +// Additional instructions. +//===----------------------------------------------------------------------===// + multiclass ARGUMENT<WebAssemblyRegClass vt> { def ARGUMENT_#vt : I<(outs vt:$res), (ins i32imm:$argno), [(set vt:$res, (WebAssemblyargument timm:$argno))]>; @@ -92,6 +89,20 @@ defm : ARGUMENT<I64>; defm : ARGUMENT<F32>; defm : ARGUMENT<F64>; +// 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. +multiclass LOCAL<WebAssemblyRegClass vt> { + def GET_LOCAL_#vt : I<(outs vt:$res), (ins i32imm:$regno), [], + "get_local\t$res, $regno">; + // TODO: set_local returns its operand value + def SET_LOCAL_#vt : I<(outs), (ins i32imm:$regno, vt:$src), [], + "set_local\t$regno, $src">; +} +defm : LOCAL<I32>; +defm : LOCAL<I64>; +defm : LOCAL<F32>; +defm : LOCAL<F64>; def CONST_I32 : I<(outs I32:$res), (ins i32imm:$imm), [(set I32:$res, imm:$imm)], @@ -106,7 +117,6 @@ def CONST_F64 : I<(outs F64:$res), (ins f64imm:$imm), [(set F64:$res, fpimm:$imm)], "f64.const\t$res, $imm">; - def : Pat<(i32 (WebAssemblywrapper tglobaladdr :$dst)), (CONST_I32 tglobaladdr :$dst)>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp index 1cf9956a3e9..7f27e7cede6 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp @@ -19,6 +19,7 @@ #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" @@ -45,6 +46,7 @@ public: AU.addRequired<MachineBlockFrequencyInfo>(); AU.addPreserved<MachineBlockFrequencyInfo>(); AU.addPreservedID(MachineDominatorsID); + AU.addRequired<SlotIndexes>(); // for ARGUMENT fixups MachineFunctionPass::getAnalysisUsage(AU); } @@ -94,6 +96,32 @@ 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 SawNonArg = false; + bool MovedArg = false; + MachineBasicBlock &EntryMBB = MF.front(); + for (auto MII = EntryMBB.begin(); MII != EntryMBB.end(); ) { + MachineInstr *MI = &*MII++; + if (MI->getOpcode() == WebAssembly::ARGUMENT_I32 || + MI->getOpcode() == WebAssembly::ARGUMENT_I64 || + MI->getOpcode() == WebAssembly::ARGUMENT_F32 || + MI->getOpcode() == WebAssembly::ARGUMENT_F64) { + EntryMBB.insert(EntryMBB.begin(), MI->removeFromParent()); + if (SawNonArg) + MovedArg = true; + } else { + SawNonArg = 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/WebAssemblyRegNumbering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp index 3fcf28ebdd2..52d93e5fd89 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp @@ -65,18 +65,17 @@ bool WebAssemblyRegNumbering::runOnMachineFunction(MachineFunction &MF) { // WebAssembly argument registers are in the same index space as local // variables. Assign the numbers for them first. - for (MachineBasicBlock &MBB : MF) { - for (MachineInstr &MI : MBB) { - switch (MI.getOpcode()) { - case WebAssembly::ARGUMENT_I32: - case WebAssembly::ARGUMENT_I64: - case WebAssembly::ARGUMENT_F32: - case WebAssembly::ARGUMENT_F64: - MFI.setWAReg(MI.getOperand(0).getReg(), MI.getOperand(1).getImm()); - break; - default: - break; - } + MachineBasicBlock &EntryMBB = MF.front(); + for (MachineInstr &MI : EntryMBB) { + switch (MI.getOpcode()) { + case WebAssembly::ARGUMENT_I32: + case WebAssembly::ARGUMENT_I64: + case WebAssembly::ARGUMENT_F32: + case WebAssembly::ARGUMENT_F64: + MFI.setWAReg(MI.getOperand(0).getReg(), MI.getOperand(1).getImm()); + break; + default: + break; } } @@ -84,9 +83,15 @@ bool WebAssemblyRegNumbering::runOnMachineFunction(MachineFunction &MF) { // virtual registers. unsigned NumArgRegs = MFI.getParams().size(); unsigned NumVRegs = MF.getRegInfo().getNumVirtRegs(); + unsigned NumStackRegs = 0; unsigned CurReg = 0; for (unsigned VRegIdx = 0; VRegIdx < NumVRegs; ++VRegIdx) { unsigned VReg = TargetRegisterInfo::index2VirtReg(VRegIdx); + // Handle stackified registers. + if (MFI.isVRegStackified(VReg)) { + MFI.setWAReg(VReg, INT32_MIN | NumStackRegs++); + continue; + } // Skip unused registers. if (MRI.use_empty(VReg)) continue; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index a159b4011e2..8104aafc726 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -22,6 +22,7 @@ #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" @@ -98,6 +99,14 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) continue; + // Argument instructions represent live-in registers and not real + // instructions. + if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || + Def->getOpcode() == WebAssembly::ARGUMENT_I64 || + Def->getOpcode() == WebAssembly::ARGUMENT_F32 || + Def->getOpcode() == WebAssembly::ARGUMENT_F64) + continue; + // Single-use expression trees require defs that have one use, or that // they be trivially clonable. // TODO: Eventually we'll relax this, to take advantage of set_local diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 5aae7108474..4c576ec647d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -155,7 +155,10 @@ bool WebAssemblyPassConfig::addInstSelector() { bool WebAssemblyPassConfig::addILPOpts() { return true; } -void WebAssemblyPassConfig::addPreRegAlloc() {} +void WebAssemblyPassConfig::addPreRegAlloc() { + // Mark registers as representing wasm's expression stack. + addPass(createWebAssemblyRegStackify()); +} void WebAssemblyPassConfig::addPostRegAlloc() { // FIXME: the following passes dislike virtual registers. Disable them for now @@ -169,6 +172,9 @@ void WebAssemblyPassConfig::addPostRegAlloc() { // TODO: Until we get ReverseBranchCondition support, MachineBlockPlacement // can create ugly-looking control flow. disablePass(&MachineBlockPlacementID); + + // Run the register coloring pass to reduce the total number of registers. + addPass(createWebAssemblyRegColoring()); } void WebAssemblyPassConfig::addPreSched2() {} |

