[PATCH] D16353: [mips] MIPSR6 compact branch support
Vasileios Kalintiris via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 25 05:17:15 PST 2016
vkalintiris added inline comments.
================
Comment at: lib/Target/Mips/MipsDelaySlotFiller.cpp:506-510
@@ -522,5 +505,7 @@
+ unsigned NewOpcode = TII->getEquivalentCompactForm(Branch);
+ TII->genInstrWithNewOpc(NewOpcode, Branch);
Iter tmpIter = Branch;
Branch = std::prev(Branch);
MBB.erase(tmpIter);
----------------
If you update `Branch` with the return value of `genInstrWithNewOpc()` then deleting the previous branch is as simple as: `std::next(Branch)->eraseFromParent();`
================
Comment at: lib/Target/Mips/MipsDelaySlotFiller.cpp:533-575
@@ -547,2 +532,45 @@
+// Predicate for distingushing between control transfer instructions and all
+// other instructions for handling forbidden slots. Consider inline assembly
+// as unsafe as well.
+static bool safeInForbiddenSlot(const MachineInstr *MI) {
+ if (MI->isCall() || MI->isBranch() || MI->isReturn() || MI->isInlineAsm())
+ return false;
+
+ switch (MI->getOpcode()) {
+ case Mips::ERET:
+ case Mips::ERETNC:
+ case Mips::DERET:
+ case Mips::PAUSE:
+ case Mips::WAIT:
+ return false;
+ default:
+ return true;
+ }
+}
+
+// Predicate for distingushing instructions that have forbidden slots.
+static bool hasForbiddenSlot(const MachineInstr *MI) {
+ if (!MI->isBranch())
+ return false;
+
+ switch ((unsigned)MI->getOpcode()) {
+ case Mips::BEQC:
+ case Mips::BNEC:
+ case Mips::BLTC:
+ case Mips::BGEC:
+ case Mips::BLTUC:
+ case Mips::BGEUC:
+ case Mips::BEQZC:
+ case Mips::BNEZC:
+ case Mips::BGEZC:
+ case Mips::BGTZC:
+ case Mips::BLEZC:
+ case Mips::BLTZC:
+ return true;
+ default:
+ return false;
+ }
+}
+
// For given opcode returns opcode of corresponding instruction with short
----------------
I think that it would be useful to have these functions at `MipsInstrInfo` as we could call them from other passes too.
================
Comment at: lib/Target/Mips/MipsDelaySlotFiller.cpp:557
@@ +556,3 @@
+
+ switch ((unsigned)MI->getOpcode()) {
+ case Mips::BEQC:
----------------
The cast is redundant.
================
Comment at: lib/Target/Mips/MipsDelaySlotFiller.cpp:595-659
@@ -566,2 +594,67 @@
+// The forbidden slot is the instruction immediately following a compact
+// branch. A forbidden slot hazard occurs when a compact branch instruction
+// is executed and the adjacent instruction in memory is a control transfer
+// instruction such as a branch or jump, ERET, ERETNC, DERET, WAIT and
+// PAUSE.
+//
+// In such cases, the processor is required to signal a Reserved Instruction
+// exception. Forbidden slot hazards are defined for MIPSR6, no microMIPS.
+//
+// There are three sources of forbidden slot hazards:
+//
+// A) Transforming a delay slot branch into compact branch.
+// B) A previous pass has created a compact branch directly.
+// C) Filling a delay slot using a backwards search when the instruction
+// moved was in a forbidden slot. This case will create hazards in already
+// processed code.
+//
+bool Filler::clearFSHazards(MachineFunction &F) {
+ bool Changed = false;
+ const MipsSubtarget &STI = F.getSubtarget<MipsSubtarget>();
+ const MipsSEInstrInfo *TII =
+ static_cast<const MipsSEInstrInfo *>(STI.getInstrInfo());
+
+ for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ for (Iter I = (*FI).begin(); I != (*FI).end(); ++I) {
+ if (hasForbiddenSlot(I)) {
+ if (std::next(I) != (*FI).end() &&
+ !safeInForbiddenSlot(&*std::next(I))) {
+ BuildMI((*FI), std::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
+ Changed = true;
+ } else {
+ for (auto *Succ : (*FI).successors()) {
+ if ((*FI).isLayoutSuccessor(Succ) &&
+ (Succ->getFirstNonDebugInstr()) != Succ->end() &&
+ !safeInForbiddenSlot((Succ->getFirstNonDebugInstr()))) {
+ BuildMI(&(*FI), I->getDebugLoc(), TII->get(Mips::NOP));
+ Changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return Changed;
+}
+
+bool Filler::runOnMachineFunction(MachineFunction &F) {
+ bool Changed = false;
+ for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
+ Changed |= runOnMachineBasicBlock(*FI);
+
+ // Make a second pass over the instructions to clear hazards.
+ const MipsSubtarget &STI = F.getSubtarget<MipsSubtarget>();
+ if (STI.hasMips32r6() && !STI.inMicroMipsMode())
+ Changed |= clearFSHazards(F);
+
+ // This pass invalidates liveness information when it reorders
+ // instructions to fill delay slot. Without this, -verify-machineinstrs
+ // will fail.
+ if (Changed)
+ F.getRegInfo().invalidateLiveness();
+
+ return Changed;
+}
+
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
----------------
There's no need to iterate over every instruction twice. We can check whether we have to add a NOP inside `replaceWithCompactBranch()` and bundle it together with the compact branch.
================
Comment at: lib/Target/Mips/MipsInstrInfo.cpp:286
@@ +285,3 @@
+ // branch distance in non-microMIPS mode.
+ if (I->isBranch() && I->getNumExplicitOperands() == 3 &&
+ (unsigned)I->getOperand(1).getReg() == Mips::ZERO) {
----------------
We don't have to check for the number of explicit operands.
================
Comment at: lib/Target/Mips/MipsInstrInfo.cpp:287
@@ +286,3 @@
+ if (I->isBranch() && I->getNumExplicitOperands() == 3 &&
+ (unsigned)I->getOperand(1).getReg() == Mips::ZERO) {
+ ZeroOperandBranch = true;
----------------
You can use MipsABIInfo::GetZeroReg() to test with the right zero register. Also, the cast is unnecessary.
================
Comment at: lib/Target/Mips/MipsInstrInfo.cpp:302-303
@@ +301,4 @@
+ break;
+ default:
+ break;
+ }
----------------
Shouldn't we set `ZeroOperandBranch` to false in the default case?
================
Comment at: lib/Target/Mips/MipsSEInstrInfo.cpp:438
@@ +437,3 @@
+MipsSEInstrInfo::getEquivalentCompactForm(MachineBasicBlock::iterator I) const {
+
+ const MipsSubtarget &STI =
----------------
Redundant newline.
================
Comment at: lib/Target/Mips/MipsSEInstrInfo.cpp:473-482
@@ +472,12 @@
+
+ if (STI.inMicroMipsMode()) {
+ switch (Opcode) {
+ case Mips::BEQ:
+ case Mips::BNE:
+ if ((unsigned)I->getOperand(1).getReg() == Mips::ZERO)
+ return Opcode == Mips::BEQ ? Mips::BEQZC_MM : Mips::BNEZC_MM;
+ default:
+ return 0;
+ }
+ }
+ return 0;
----------------
We will never reach this if `STI.hasMips32r6()` is true. We should merge the logic of opcode selection into the first switch statement.
http://reviews.llvm.org/D16353
More information about the llvm-commits
mailing list