#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
#define LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
namespace llvm {
// Forward declarations.
-class RegisterBankInfo;
+class MachineRegisterInfo;
/// This pass implements the reg bank selector pass used in the GlobalISel
/// pipeline. At the end of this pass, all register operands have been assigned
/// to register banks.
const RegisterBankInfo *RBI;
+ /// MRI contains all the register class/bank information that this
+ /// pass uses and updates.
+ MachineRegisterInfo *MRI;
+
+ /// Helper class used for every code morphing.
+ MachineIRBuilder MIRBuilder;
+
+ /// Assign the register bank of each operand of \p MI.
+ void assignInstr(MachineInstr &MI);
+
+ /// Initialize the field members using \p MF.
+ void init(MachineFunction &MF);
+
+ /// Check if \p Reg is already assigned what is described by \p ValMapping.
+ bool assignmentMatch(unsigned Reg,
+ const RegisterBankInfo::ValueMapping &ValMapping) const;
+
+ /// Insert repairing code to map \p Reg as specified by \p ValMapping.
+ /// The repairing code is inserted where the MIRBuilder points.
+ /// \return The register of the properly mapped value.
+ unsigned repairReg(unsigned Reg,
+ const RegisterBankInfo::ValueMapping &ValMapping);
+
public:
// Ctor, nothing fancy.
RegBankSelect();
return "RegBankSelect";
}
- // Simplified algo:
- // RBI = MF.subtarget.getRegBankInfo()
- // MIRBuilder.reset(MF)
- // for each bb in MF
- // for each inst in bb
- // MappingCosts = RBI.getMapping(inst);
- // Idx = findIdxOfMinCost(MappingCosts)
- // CurRegBank = MappingCosts[Idx].RegBank
- // MRI.setRegBank(inst.getOperand(0).getReg(), CurRegBank)
- // for each argument in inst
- // if (CurRegBank != argument.RegBank)
- // ArgReg = argument.getReg()
- // Tmp = MRI.createNewVirtual(MRI.getSize(ArgReg), CurRegBank)
- // MIRBuilder.buildInstr(COPY, Tmp, ArgReg)
- // inst.getOperand(argument.getOperandNo()).setReg(Tmp)
+ /// Walk through \p MF and assign a register bank to every virtual register
+ /// that are still mapped to nothing.
+ /// The target needs to provide a RegisterBankInfo and in particular
+ /// override RegisterBankInfo::getInstrMapping.
+ ///
+ /// Simplified algo:
+ /// \code
+ /// RBI = MF.subtarget.getRegBankInfo()
+ /// MIRBuilder.setMF(MF)
+ /// for each bb in MF
+ /// for each inst in bb
+ /// MIRBuilder.setInstr(inst)
+ /// MappingCosts = RBI.getMapping(inst);
+ /// Idx = findIdxOfMinCost(MappingCosts)
+ /// CurRegBank = MappingCosts[Idx].RegBank
+ /// MRI.setRegBank(inst.getOperand(0).getReg(), CurRegBank)
+ /// for each argument in inst
+ /// if (CurRegBank != argument.RegBank)
+ /// ArgReg = argument.getReg()
+ /// Tmp = MRI.createNewVirtual(MRI.getSize(ArgReg), CurRegBank)
+ /// MIRBuilder.buildInstr(COPY, Tmp, ArgReg)
+ /// inst.getOperand(argument.getOperandNo()).setReg(Tmp)
+ /// \endcode
bool runOnMachineFunction(MachineFunction &MF) override;
};
} // End namespace llvm.
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
+#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#define DEBUG_TYPE "regbankselect"
"Assign register bank of generic virtual registers",
false, false);
-RegBankSelect::RegBankSelect() : MachineFunctionPass(ID), RBI(nullptr) {
+RegBankSelect::RegBankSelect()
+ : MachineFunctionPass(ID), RBI(nullptr), MRI(nullptr) {
initializeRegBankSelectPass(*PassRegistry::getPassRegistry());
}
+void RegBankSelect::init(MachineFunction &MF) {
+ RBI = MF.getSubtarget().getRegBankInfo();
+ assert(RBI && "Cannot work without RegisterBankInfo");
+ MRI = &MF.getRegInfo();
+ MIRBuilder.setMF(MF);
+}
+
+bool RegBankSelect::assignmentMatch(
+ unsigned Reg, const RegisterBankInfo::ValueMapping &ValMapping) const {
+ // Each part of a break down needs to end up in a different register.
+ // In other word, Reg assignement does not match.
+ if (ValMapping.BreakDown.size() > 1)
+ return false;
+
+ const RegClassOrRegBank &CurAssignment = MRI->getRegClassOrRegBank(Reg);
+ // Nothing assigned, the assignment does not match.
+ if (!CurAssignment)
+ return false;
+ // Get the register bank form the current assignment.
+ const RegisterBank *CurRegBank = nullptr;
+ if (CurAssignment.is<const TargetRegisterClass *>())
+ CurRegBank = &RBI->getRegBankFromRegClass(
+ *CurAssignment.get<const TargetRegisterClass *>());
+ else
+ CurRegBank = CurAssignment.get<const RegisterBank *>();
+ return CurRegBank == ValMapping.BreakDown[0].RegBank;
+}
+
+unsigned
+RegBankSelect::repairReg(unsigned Reg,
+ const RegisterBankInfo::ValueMapping &ValMapping) {
+ assert(ValMapping.BreakDown.size() == 1 &&
+ "Support for complex break down not supported yet");
+ const RegisterBankInfo::PartialMapping &PartialMap = ValMapping.BreakDown[0];
+ assert(PartialMap.Mask.getBitWidth() == MRI->getSize(Reg) &&
+ "Repairing other than copy not implemented yet");
+ unsigned NewReg =
+ MRI->createGenericVirtualRegister(PartialMap.Mask.getBitWidth());
+ (void)MIRBuilder.buildInstr(TargetOpcode::COPY, NewReg, Reg);
+ return NewReg;
+}
+
+void RegBankSelect::assignInstr(MachineInstr &MI) {
+ const RegisterBankInfo::InstructionMapping DefaultMapping =
+ RBI->getInstrMapping(MI);
+ // Make sure the mapping is valid for MI.
+ DefaultMapping.verify(MI);
+ // Set the insertion point before MI.
+ // This is where we are going to insert the repairing code if any.
+ MIRBuilder.setInstr(MI, /*Before*/ true);
+
+ // For now, do not look for alternative mappings.
+ // Alternative mapping may require to rewrite MI and we do not support
+ // that yet.
+ // Walk the operands and assign then to the chosen mapping, possibly with
+ // the insertion of repair code for uses.
+ for (unsigned OpIdx = 0, EndIdx = MI.getNumOperands(); OpIdx != EndIdx;
+ ++OpIdx) {
+ MachineOperand &MO = MI.getOperand(OpIdx);
+ // Nothing to be done for non-register operands.
+ if (!MO.isReg())
+ continue;
+ unsigned Reg = MO.getReg();
+ if (!Reg)
+ continue;
+
+ const RegisterBankInfo::ValueMapping &ValMapping =
+ DefaultMapping.getOperandMapping(OpIdx);
+ // If Reg is already properly mapped, move on.
+ if (assignmentMatch(Reg, ValMapping))
+ continue;
+
+ // For uses, we may need to create a new temporary.
+ // Indeed, if Reg is already assigned a register bank, at this
+ // point, we know it is different from the one defined by the
+ // chosen mapping, we need to adjust for that.
+ assert(ValMapping.BreakDown.size() == 1 &&
+ "Support for complex break down not supported yet");
+ if (!MO.isDef() && MRI->getRegClassOrRegBank(Reg)) {
+ // For phis, we need to change the insertion point to the end of
+ // the related predecessor block.
+ assert(!MI.isPHI() && "PHI support not implemented yet");
+ Reg = repairReg(Reg, ValMapping);
+ }
+ // If we end up here, MO should be free of encoding constraints,
+ // i.e., we do not have to constrained the RegBank of Reg to
+ // the requirement of the operands.
+ // If that is not the case, this means the code was broken before
+ // hands because we should have found that the assignment match.
+ // This will not hold when we will consider alternative mappings.
+ MRI->setRegBank(Reg, *ValMapping.BreakDown[0].RegBank);
+ MO.setReg(Reg);
+ }
+}
+
bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) {
- // Avoid unused field member warning.
- (void)RBI;
+ init(MF);
+ // Walk the function and assign register banks to all operands.
+ for (MachineBasicBlock &MBB : MF)
+ for (MachineInstr &MI : MBB)
+ assignInstr(MI);
return false;
}