summaryrefslogtreecommitdiff
path: root/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
commitd8e91e46262bc44006913e6796843909f1ac7bcd (patch)
tree7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
parentb7eb8e35e481a74962664b63dfb09483b200209a (diff)
Notes
Diffstat (limited to 'lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp')
-rw-r--r--lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp116
1 files changed, 62 insertions, 54 deletions
diff --git a/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
index 8619cbdcb5ee..27aabe6ba0bd 100644
--- a/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
+++ b/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
@@ -11,7 +11,7 @@
/// This file converts any remaining registers into WebAssembly locals.
///
/// After register stackification and register coloring, convert non-stackified
-/// registers into locals, inserting explicit get_local and set_local
+/// registers into locals, inserting explicit local.get and local.set
/// instructions.
///
//===----------------------------------------------------------------------===//
@@ -31,12 +31,14 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-explicit-locals"
-// A command-line option to disable this pass. Note that this produces output
-// which is not valid WebAssembly, though it may be more convenient for writing
-// LLVM unit tests with.
-static cl::opt<bool> DisableWebAssemblyExplicitLocals(
- "disable-wasm-explicit-locals", cl::ReallyHidden,
- cl::desc("WebAssembly: Disable emission of get_local/set_local."),
+// A command-line option to disable this pass, and keep implicit locals
+// for the purpose of testing with lit/llc ONLY.
+// This produces output which is not valid WebAssembly, and is not supported
+// by assemblers/disassemblers and other MC based tools.
+static cl::opt<bool> WasmDisableExplicitLocals(
+ "wasm-disable-explicit-locals", cl::Hidden,
+ cl::desc("WebAssembly: output implicit locals in"
+ " instruction output for test purposes only."),
cl::init(false));
namespace {
@@ -94,54 +96,54 @@ static unsigned getDropOpcode(const TargetRegisterClass *RC) {
llvm_unreachable("Unexpected register class");
}
-/// Get the appropriate get_local opcode for the given register class.
+/// Get the appropriate local.get opcode for the given register class.
static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
if (RC == &WebAssembly::I32RegClass)
- return WebAssembly::GET_LOCAL_I32;
+ return WebAssembly::LOCAL_GET_I32;
if (RC == &WebAssembly::I64RegClass)
- return WebAssembly::GET_LOCAL_I64;
+ return WebAssembly::LOCAL_GET_I64;
if (RC == &WebAssembly::F32RegClass)
- return WebAssembly::GET_LOCAL_F32;
+ return WebAssembly::LOCAL_GET_F32;
if (RC == &WebAssembly::F64RegClass)
- return WebAssembly::GET_LOCAL_F64;
+ return WebAssembly::LOCAL_GET_F64;
if (RC == &WebAssembly::V128RegClass)
- return WebAssembly::GET_LOCAL_V128;
+ return WebAssembly::LOCAL_GET_V128;
if (RC == &WebAssembly::EXCEPT_REFRegClass)
- return WebAssembly::GET_LOCAL_EXCEPT_REF;
+ return WebAssembly::LOCAL_GET_EXCEPT_REF;
llvm_unreachable("Unexpected register class");
}
-/// Get the appropriate set_local opcode for the given register class.
+/// Get the appropriate local.set opcode for the given register class.
static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
if (RC == &WebAssembly::I32RegClass)
- return WebAssembly::SET_LOCAL_I32;
+ return WebAssembly::LOCAL_SET_I32;
if (RC == &WebAssembly::I64RegClass)
- return WebAssembly::SET_LOCAL_I64;
+ return WebAssembly::LOCAL_SET_I64;
if (RC == &WebAssembly::F32RegClass)
- return WebAssembly::SET_LOCAL_F32;
+ return WebAssembly::LOCAL_SET_F32;
if (RC == &WebAssembly::F64RegClass)
- return WebAssembly::SET_LOCAL_F64;
+ return WebAssembly::LOCAL_SET_F64;
if (RC == &WebAssembly::V128RegClass)
- return WebAssembly::SET_LOCAL_V128;
+ return WebAssembly::LOCAL_SET_V128;
if (RC == &WebAssembly::EXCEPT_REFRegClass)
- return WebAssembly::SET_LOCAL_EXCEPT_REF;
+ return WebAssembly::LOCAL_SET_EXCEPT_REF;
llvm_unreachable("Unexpected register class");
}
-/// Get the appropriate tee_local opcode for the given register class.
+/// Get the appropriate local.tee opcode for the given register class.
static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
if (RC == &WebAssembly::I32RegClass)
- return WebAssembly::TEE_LOCAL_I32;
+ return WebAssembly::LOCAL_TEE_I32;
if (RC == &WebAssembly::I64RegClass)
- return WebAssembly::TEE_LOCAL_I64;
+ return WebAssembly::LOCAL_TEE_I64;
if (RC == &WebAssembly::F32RegClass)
- return WebAssembly::TEE_LOCAL_F32;
+ return WebAssembly::LOCAL_TEE_F32;
if (RC == &WebAssembly::F64RegClass)
- return WebAssembly::TEE_LOCAL_F64;
+ return WebAssembly::LOCAL_TEE_F64;
if (RC == &WebAssembly::V128RegClass)
- return WebAssembly::TEE_LOCAL_V128;
+ return WebAssembly::LOCAL_TEE_V128;
if (RC == &WebAssembly::EXCEPT_REFRegClass)
- return WebAssembly::TEE_LOCAL_EXCEPT_REF;
+ return WebAssembly::LOCAL_TEE_EXCEPT_REF;
llvm_unreachable("Unexpected register class");
}
@@ -155,6 +157,8 @@ static MVT typeForRegClass(const TargetRegisterClass *RC) {
return MVT::f32;
if (RC == &WebAssembly::F64RegClass)
return MVT::f64;
+ if (RC == &WebAssembly::V128RegClass)
+ return MVT::v16i8;
if (RC == &WebAssembly::EXCEPT_REFRegClass)
return MVT::ExceptRef;
llvm_unreachable("unrecognized register class");
@@ -162,7 +166,7 @@ static MVT typeForRegClass(const TargetRegisterClass *RC) {
/// Given a MachineOperand of a stackified vreg, return the instruction at the
/// start of the expression tree.
-static MachineInstr *FindStartOfTree(MachineOperand &MO,
+static MachineInstr *findStartOfTree(MachineOperand &MO,
MachineRegisterInfo &MRI,
WebAssemblyFunctionInfo &MFI) {
unsigned Reg = MO.getReg();
@@ -173,7 +177,7 @@ static MachineInstr *FindStartOfTree(MachineOperand &MO,
for (MachineOperand &DefMO : Def->explicit_uses()) {
if (!DefMO.isReg())
continue;
- return FindStartOfTree(DefMO, MRI, MFI);
+ return findStartOfTree(DefMO, MRI, MFI);
}
// If there were no stackified uses, we've reached the start.
@@ -186,7 +190,7 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
<< MF.getName() << '\n');
// Disable this pass if directed to do so.
- if (DisableWebAssemblyExplicitLocals)
+ if (WasmDisableExplicitLocals)
return false;
bool Changed = false;
@@ -206,19 +210,19 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
break;
unsigned Reg = MI.getOperand(0).getReg();
assert(!MFI.isVRegStackified(Reg));
- Reg2Local[Reg] = MI.getOperand(1).getImm();
+ Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
MI.eraseFromParent();
Changed = true;
}
// Start assigning local numbers after the last parameter.
- unsigned CurLocal = MFI.getParams().size();
+ unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
// Precompute the set of registers that are unused, so that we can insert
// drops to their defs.
BitVector UseEmpty(MRI.getNumVirtRegs());
- for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
- UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
+ for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
+ UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
// Visit each instruction in the function.
for (MachineBasicBlock &MBB : MF) {
@@ -229,8 +233,8 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
if (MI.isDebugInstr() || MI.isLabel())
continue;
- // Replace tee instructions with tee_local. The difference is that tee
- // instructins have two defs, while tee_local instructions have one def
+ // Replace tee instructions with local.tee. The difference is that tee
+ // instructions have two defs, while local.tee instructions have one def
// and an index of a local to write to.
if (WebAssembly::isTee(MI)) {
assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
@@ -249,7 +253,7 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
MFI.stackifyVReg(NewReg);
}
- // Replace the TEE with a TEE_LOCAL.
+ // Replace the TEE with a LOCAL_TEE.
unsigned LocalId =
getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
unsigned Opc = getTeeLocalOpcode(RC);
@@ -263,7 +267,7 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
continue;
}
- // Insert set_locals for any defs that aren't stackified yet. Currently
+ // Insert local.sets for any defs that aren't stackified yet. Currently
// we handle at most one def.
assert(MI.getDesc().getNumDefs() <= 1);
if (MI.getDesc().getNumDefs() == 1) {
@@ -292,15 +296,16 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
.addReg(NewReg);
}
MI.getOperand(0).setReg(NewReg);
- // This register operand is now being used by the inserted drop
- // instruction, so make it undead.
+ // This register operand of the original instruction is now being used
+ // by the inserted drop or local.set instruction, so make it not dead
+ // yet.
MI.getOperand(0).setIsDead(false);
MFI.stackifyVReg(NewReg);
Changed = true;
}
}
- // Insert get_locals for any uses that aren't stackified yet.
+ // Insert local.gets for any uses that aren't stackified yet.
MachineInstr *InsertPt = &MI;
for (MachineOperand &MO : reverse(MI.explicit_uses())) {
if (!MO.isReg())
@@ -314,15 +319,17 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
if (MO.isDef()) {
assert(MI.getOpcode() == TargetOpcode::INLINEASM);
unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
- MRI.removeRegOperandFromUseList(&MO);
- MO = MachineOperand::CreateImm(LocalId);
+ // If this register operand is tied to another operand, we can't
+ // change it to an immediate. Untie it first.
+ MI.untieRegOperand(MI.getOperandNo(&MO));
+ MO.ChangeToImmediate(LocalId);
continue;
}
// If we see a stackified register, prepare to insert subsequent
- // get_locals before the start of its tree.
+ // local.gets before the start of its tree.
if (MFI.isVRegStackified(OldReg)) {
- InsertPt = FindStartOfTree(MO, MRI, MFI);
+ InsertPt = findStartOfTree(MO, MRI, MFI);
continue;
}
@@ -330,12 +337,13 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
// indices as immediates.
if (MI.getOpcode() == TargetOpcode::INLINEASM) {
unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
- MRI.removeRegOperandFromUseList(&MO);
- MO = MachineOperand::CreateImm(LocalId);
+ // Untie it first if this reg operand is tied to another operand.
+ MI.untieRegOperand(MI.getOperandNo(&MO));
+ MO.ChangeToImmediate(LocalId);
continue;
}
- // Insert a get_local.
+ // Insert a local.get.
unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
unsigned NewReg = MRI.createVirtualRegister(RC);
@@ -361,13 +369,13 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
// Define the locals.
// TODO: Sort the locals for better compression.
MFI.setNumLocals(CurLocal - MFI.getParams().size());
- for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
- unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
- auto I = Reg2Local.find(Reg);
- if (I == Reg2Local.end() || I->second < MFI.getParams().size())
+ for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
+ unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
+ auto RL = Reg2Local.find(Reg);
+ if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
continue;
- MFI.setLocal(I->second - MFI.getParams().size(),
+ MFI.setLocal(RL->second - MFI.getParams().size(),
typeForRegClass(MRI.getRegClass(Reg)));
Changed = true;
}