summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp35
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp45
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp17
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td26
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp28
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp29
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp9
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp8
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() {}
OpenPOWER on IntegriCloud