summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp')
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp139
1 files changed, 85 insertions, 54 deletions
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
index 0aa3b62..32ee09e 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
@@ -13,10 +13,10 @@
/// This pass reorders instructions to put register uses and defs in an order
/// such that they form single-use expression trees. Registers fitting this form
/// are then marked as "stackified", meaning references to them are replaced by
-/// "push" and "pop" from the stack.
+/// "push" and "pop" from the value stack.
///
/// This is primarily a code size optimization, since temporary values on the
-/// expression don't need to be named.
+/// value stack don't need to be named.
///
//===----------------------------------------------------------------------===//
@@ -24,6 +24,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
@@ -39,7 +40,7 @@ using namespace llvm;
namespace {
class WebAssemblyRegStackify final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Register Stackify";
}
@@ -73,19 +74,50 @@ FunctionPass *llvm::createWebAssemblyRegStackify() {
// expression stack ordering constraints for an instruction which is on
// the expression stack.
static void ImposeStackOrdering(MachineInstr *MI) {
- // Write the opaque EXPR_STACK register.
- if (!MI->definesRegister(WebAssembly::EXPR_STACK))
- MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
+ // Write the opaque VALUE_STACK register.
+ if (!MI->definesRegister(WebAssembly::VALUE_STACK))
+ MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
/*isDef=*/true,
/*isImp=*/true));
- // Also read the opaque EXPR_STACK register.
- if (!MI->readsRegister(WebAssembly::EXPR_STACK))
- MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
+ // Also read the opaque VALUE_STACK register.
+ if (!MI->readsRegister(WebAssembly::VALUE_STACK))
+ MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
/*isDef=*/false,
/*isImp=*/true));
}
+// Convert an IMPLICIT_DEF instruction into an instruction which defines
+// a constant zero value.
+static void ConvertImplicitDefToConstZero(MachineInstr *MI,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII,
+ MachineFunction &MF) {
+ assert(MI->getOpcode() == TargetOpcode::IMPLICIT_DEF);
+
+ const auto *RegClass =
+ MRI.getRegClass(MI->getOperand(0).getReg());
+ if (RegClass == &WebAssembly::I32RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_I32));
+ MI->addOperand(MachineOperand::CreateImm(0));
+ } else if (RegClass == &WebAssembly::I64RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_I64));
+ MI->addOperand(MachineOperand::CreateImm(0));
+ } else if (RegClass == &WebAssembly::F32RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_F32));
+ ConstantFP *Val = cast<ConstantFP>(Constant::getNullValue(
+ Type::getFloatTy(MF.getFunction()->getContext())));
+ MI->addOperand(MachineOperand::CreateFPImm(Val));
+ } else if (RegClass == &WebAssembly::F64RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_F64));
+ ConstantFP *Val = cast<ConstantFP>(Constant::getNullValue(
+ Type::getDoubleTy(MF.getFunction()->getContext())));
+ MI->addOperand(MachineOperand::CreateFPImm(Val));
+ } else {
+ llvm_unreachable("Unexpected reg class");
+ }
+}
+
// Determine whether a call to the callee referenced by
// MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side
// effects.
@@ -130,7 +162,7 @@ static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read,
return;
// Check for loads.
- if (MI.mayLoad() && !MI.isInvariantLoad(&AA))
+ if (MI.mayLoad() && !MI.isDereferenceableInvariantLoad(&AA))
Read = true;
// Check for stores.
@@ -255,7 +287,7 @@ static bool HasOneUse(unsigned Reg, MachineInstr *Def,
const VNInfo *DefVNI = LI.getVNInfoAt(
LIS.getInstructionIndex(*Def).getRegSlot());
assert(DefVNI);
- for (auto I : MRI.use_nodbg_operands(Reg)) {
+ for (auto &I : MRI.use_nodbg_operands(Reg)) {
const auto &Result = LI.Query(LIS.getInstructionIndex(*I.getParent()));
if (Result.valueIn() == DefVNI) {
if (!Result.isKill())
@@ -274,11 +306,11 @@ static bool HasOneUse(unsigned Reg, MachineInstr *Def,
// TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
// more precise.
static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
- AliasAnalysis &AA, const LiveIntervals &LIS,
- const MachineRegisterInfo &MRI) {
+ AliasAnalysis &AA, const MachineRegisterInfo &MRI) {
assert(Def->getParent() == Insert->getParent());
// Check for register dependencies.
+ SmallVector<unsigned, 4> MutableRegisters;
for (const MachineOperand &MO : Def->operands()) {
if (!MO.isReg() || MO.isUndef())
continue;
@@ -301,21 +333,11 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
return false;
}
- // Ask LiveIntervals whether moving this virtual register use or def to
- // Insert will change which value numbers are seen.
- //
- // If the operand is a use of a register that is also defined in the same
- // instruction, test that the newly defined value reaches the insert point,
- // since the operand will be moving along with the def.
- const LiveInterval &LI = LIS.getInterval(Reg);
- VNInfo *DefVNI =
- (MO.isDef() || Def->definesRegister(Reg)) ?
- LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot()) :
- LI.getVNInfoBefore(LIS.getInstructionIndex(*Def));
- assert(DefVNI && "Instruction input missing value number");
- VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*Insert));
- if (InsVNI && DefVNI != InsVNI)
- return false;
+ // If one of the operands isn't in SSA form, it has different values at
+ // different times, and we need to make sure we don't move our use across
+ // a different def.
+ if (!MO.isDef() && !MRI.hasOneDef(Reg))
+ MutableRegisters.push_back(Reg);
}
bool Read = false, Write = false, Effects = false, StackPointer = false;
@@ -323,7 +345,8 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
// If the instruction does not access memory and has no side effects, it has
// no additional dependencies.
- if (!Read && !Write && !Effects && !StackPointer)
+ bool HasMutableRegisters = !MutableRegisters.empty();
+ if (!Read && !Write && !Effects && !StackPointer && !HasMutableRegisters)
return true;
// Scan through the intervening instructions between Def and Insert.
@@ -343,6 +366,11 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
return false;
if (StackPointer && InterveningStackPointer)
return false;
+
+ for (unsigned Reg : MutableRegisters)
+ for (const MachineOperand &MO : I->operands())
+ if (MO.isReg() && MO.isDef() && MO.getReg() == Reg)
+ return false;
}
return true;
@@ -360,7 +388,7 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
const MachineInstr *OneUseInst = OneUse.getParent();
VNInfo *OneUseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*OneUseInst));
- for (const MachineOperand &Use : MRI.use_operands(Reg)) {
+ for (const MachineOperand &Use : MRI.use_nodbg_operands(Reg)) {
if (&Use == &OneUse)
continue;
@@ -384,7 +412,7 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
//
// This is needed as a consequence of using implicit get_locals for
// uses and implicit set_locals for defs.
- if (UseInst->getDesc().getNumDefs() == 0)
+ if (UseInst->getDesc().getNumDefs() == 0)
return false;
const MachineOperand &MO = UseInst->getOperand(0);
if (!MO.isReg())
@@ -408,16 +436,18 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
return true;
}
-/// Get the appropriate tee_local opcode for the given register class.
-static unsigned GetTeeLocalOpcode(const TargetRegisterClass *RC) {
+/// Get the appropriate tee opcode for the given register class.
+static unsigned GetTeeOpcode(const TargetRegisterClass *RC) {
if (RC == &WebAssembly::I32RegClass)
- return WebAssembly::TEE_LOCAL_I32;
+ return WebAssembly::TEE_I32;
if (RC == &WebAssembly::I64RegClass)
- return WebAssembly::TEE_LOCAL_I64;
+ return WebAssembly::TEE_I64;
if (RC == &WebAssembly::F32RegClass)
- return WebAssembly::TEE_LOCAL_F32;
+ return WebAssembly::TEE_F32;
if (RC == &WebAssembly::F64RegClass)
- return WebAssembly::TEE_LOCAL_F64;
+ return WebAssembly::TEE_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::TEE_V128;
llvm_unreachable("Unexpected register class");
}
@@ -515,8 +545,8 @@ static MachineInstr *RematerializeCheapDef(
/// A multiple-use def in the same block with no intervening memory or register
/// dependencies; move the def down, nest it with the current instruction, and
-/// insert a tee_local to satisfy the rest of the uses. As an illustration,
-/// rewrite this:
+/// insert a tee to satisfy the rest of the uses. As an illustration, rewrite
+/// this:
///
/// Reg = INST ... // Def
/// INST ..., Reg, ... // Insert
@@ -526,7 +556,7 @@ static MachineInstr *RematerializeCheapDef(
/// to this:
///
/// DefReg = INST ... // Def (to become the new Insert)
-/// TeeReg, Reg = TEE_LOCAL_... DefReg
+/// TeeReg, Reg = TEE_... DefReg
/// INST ..., TeeReg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
@@ -549,7 +579,7 @@ static MachineInstr *MoveAndTeeForMultiUse(
unsigned DefReg = MRI.createVirtualRegister(RegClass);
MachineOperand &DefMO = Def->getOperand(0);
MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
- TII->get(GetTeeLocalOpcode(RegClass)), TeeReg)
+ TII->get(GetTeeOpcode(RegClass)), TeeReg)
.addReg(Reg, RegState::Define)
.addReg(DefReg, getUndefRegState(DefMO.isDead()));
Op.setReg(TeeReg);
@@ -749,8 +779,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
if (TargetRegisterInfo::isPhysicalRegister(Reg))
continue;
- // Identify the definition for this register at this point. Most
- // registers are in SSA form here so we try a quick MRI query first.
+ // Identify the definition for this register at this point.
MachineInstr *Def = GetVRegDef(Reg, Insert, MRI, LIS);
if (!Def)
continue;
@@ -762,20 +791,17 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
// 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)
+ if (WebAssembly::isArgument(*Def))
continue;
// Decide which strategy to take. Prefer to move a single-use value
- // over cloning it, and prefer cloning over introducing a tee_local.
+ // over cloning it, and prefer cloning over introducing a tee.
// For moving, we require the def to be in the same block as the use;
// this makes things simpler (LiveIntervals' handleMove function only
// supports intra-block moves) and it's MachineSink's job to catch all
// the sinking opportunities anyway.
bool SameBlock = Def->getParent() == &MBB;
- bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, LIS, MRI) &&
+ bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, MRI) &&
!TreeWalker.IsOnStack(Reg);
if (CanMove && HasOneUse(Reg, Def, MRI, MDT, LIS)) {
Insert = MoveForSingleUse(Reg, Op, Def, MBB, Insert, LIS, MFI, MRI);
@@ -796,6 +822,12 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
continue;
}
+ // If the instruction we just stackified is an IMPLICIT_DEF, convert it
+ // to a constant 0 so that the def is explicit, and the push/pop
+ // correspondence is maintained.
+ if (Insert->getOpcode() == TargetOpcode::IMPLICIT_DEF)
+ ConvertImplicitDefToConstZero(Insert, MRI, TII, MF);
+
// We stackified an operand. Add the defining instruction's operands to
// the worklist stack now to continue to build an ever deeper tree.
Commuting.Reset();
@@ -806,19 +838,18 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
// the next instruction we can build a tree on.
if (Insert != &*MII) {
ImposeStackOrdering(&*MII);
- MII = std::prev(
- llvm::make_reverse_iterator(MachineBasicBlock::iterator(Insert)));
+ MII = MachineBasicBlock::iterator(Insert).getReverse();
Changed = true;
}
}
}
- // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere so
+ // If we used VALUE_STACK anywhere, add it to the live-in sets everywhere so
// that it never looks like a use-before-def.
if (Changed) {
- MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
+ MF.getRegInfo().addLiveIn(WebAssembly::VALUE_STACK);
for (MachineBasicBlock &MBB : MF)
- MBB.addLiveIn(WebAssembly::EXPR_STACK);
+ MBB.addLiveIn(WebAssembly::VALUE_STACK);
}
#ifndef NDEBUG
OpenPOWER on IntegriCloud