summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorDaniel Sanders <daniel.sanders@imgtec.com>2016-03-14 16:24:05 +0000
committerDaniel Sanders <daniel.sanders@imgtec.com>2016-03-14 16:24:05 +0000
commite8efff373a5118edf298b63a4c24cdbcc3ebd1da (patch)
treef6b1d2a5e048d5e00395f880927d151257ec02e4 /llvm/lib/Target
parentaeb7b539f59cc9dd4e1a28c4cf841d19ba75e5a9 (diff)
downloadbcm5719-llvm-e8efff373a5118edf298b63a4c24cdbcc3ebd1da.tar.gz
bcm5719-llvm-e8efff373a5118edf298b63a4c24cdbcc3ebd1da.zip
[mips] MIPS32R6 compact branch support
Summary: MIPSR6 introduces a class of branches called compact branches. Unlike the traditional MIPS branches which have a delay slot, compact branches do not have a delay slot. The instruction following the compact branch is only executed if the branch is not taken and must not be a branch. It works by generating compact branches for MIPS32R6 when the delay slot filler cannot fill a delay slot. Then, inspecting the generated code for forbidden slot hazards (a compact branch with an adjacent branch or other CTI) and inserting nops to clear this hazard. Patch by Simon Dardis. Reviewers: vkalintiris, dsanders Subscribers: MatzeB, dsanders, llvm-commits Differential Revision: http://reviews.llvm.org/D16353 llvm-svn: 263444
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/Mips/CMakeLists.txt1
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h7
-rw-r--r--llvm/lib/Target/Mips/Mips.h1
-rw-r--r--llvm/lib/Target/Mips/Mips32r6InstrInfo.td15
-rw-r--r--llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp56
-rw-r--r--llvm/lib/Target/Mips/MipsHazardSchedule.cpp136
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.cpp2
-rw-r--r--llvm/lib/Target/Mips/MipsInstrFormats.td7
-rw-r--r--llvm/lib/Target/Mips/MipsInstrInfo.cpp103
-rw-r--r--llvm/lib/Target/Mips/MipsInstrInfo.h9
-rw-r--r--llvm/lib/Target/Mips/MipsInstrInfo.td55
-rw-r--r--llvm/lib/Target/Mips/MipsSEInstrInfo.cpp16
-rw-r--r--llvm/lib/Target/Mips/MipsTargetMachine.cpp6
13 files changed, 358 insertions, 56 deletions
diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt
index bde843afd3d..3650cc9fe07 100644
--- a/llvm/lib/Target/Mips/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/CMakeLists.txt
@@ -27,6 +27,7 @@ add_llvm_target(MipsCodeGen
MipsConstantIslandPass.cpp
MipsDelaySlotFiller.cpp
MipsFastISel.cpp
+ MipsHazardSchedule.cpp
MipsInstrInfo.cpp
MipsISelDAGToDAG.cpp
MipsISelLowering.cpp
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index ff7779ec1e7..0e54563b825 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -117,7 +117,12 @@ namespace MipsII {
/// FrmOther - This form is for instructions that have no specific format.
FrmOther = 6,
- FormMask = 15
+ FormMask = 15,
+ /// IsCTI - Instruction is a Control Transfer Instruction.
+ IsCTI = 1 << 4,
+ /// HasForbiddenSlot - Instruction has a forbidden slot.
+ HasForbiddenSlot = 1 << 5
+
};
}
}
diff --git a/llvm/lib/Target/Mips/Mips.h b/llvm/lib/Target/Mips/Mips.h
index 671d7a87cc3..917c8709f68 100644
--- a/llvm/lib/Target/Mips/Mips.h
+++ b/llvm/lib/Target/Mips/Mips.h
@@ -29,6 +29,7 @@ namespace llvm {
FunctionPass *createMipsModuleISelDagPass(MipsTargetMachine &TM);
FunctionPass *createMipsOptimizePICCallPass(MipsTargetMachine &TM);
FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM);
+ FunctionPass *createMipsHazardSchedule(MipsTargetMachine &tm);
FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM);
FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm);
} // end namespace llvm;
diff --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
index 52b340c2ee6..f3bd2bf275f 100644
--- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -182,6 +182,7 @@ class CMP_CONDN_DESC_BASE<string CondStr, string Typestr,
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft");
list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))];
+ bit isCTI = 1;
}
multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr,
@@ -300,6 +301,7 @@ class BRANCH_DESC_BASE {
bit isBranch = 1;
bit isTerminator = 1;
bit hasDelaySlot = 0;
+ bit isCTI = 1;
}
class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE,
@@ -309,6 +311,7 @@ class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE,
string AsmString = !strconcat(instr_asm, "\t$offset");
bit isBarrier = 1;
InstrItinClass Itinerary = II_BC;
+ bit isCTI = 1;
}
class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd,
@@ -318,6 +321,8 @@ class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd,
string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCC;
+ bit hasForbiddenSlot = 1;
+ bit isCTI = 1;
}
class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
@@ -327,6 +332,8 @@ class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
string AsmString = !strconcat(instr_asm, "\t$rs, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCZC;
+ bit hasForbiddenSlot = 1;
+ bit isCTI = 1;
}
class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
@@ -337,18 +344,22 @@ class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
string AsmString = !strconcat(instr_asm, "\t$rt, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCZC;
+ bit hasForbiddenSlot = 1;
+ bit isCTI = 1;
}
class BAL_DESC : BC_DESC_BASE<"bal", brtarget> {
bit isCall = 1;
bit hasDelaySlot = 1;
list<Register> Defs = [RA];
+ bit isCTI = 1;
}
class BALC_DESC : BC_DESC_BASE<"balc", brtarget26> {
bit isCall = 1;
list<Register> Defs = [RA];
InstrItinClass Itinerary = II_BALC;
+ bit isCTI = 1;
}
class BC_DESC : BC_DESC_BASE<"bc", brtarget26>;
@@ -385,6 +396,7 @@ class COP2_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE {
dag OutOperandList = (outs);
string AsmString = instr_asm;
bit hasDelaySlot = 1;
+ bit isCTI = 1;
}
class BC2EQZ_DESC : COP2_BCCZ_DESC_BASE<"bc2eqz $ct, $offset">;
@@ -403,6 +415,7 @@ class JMP_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd,
bit isTerminator = 1;
bit hasDelaySlot = 0;
InstrItinClass Itinerary = itin;
+ bit isCTI = 1;
}
class JIALC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16,
@@ -423,6 +436,7 @@ class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> {
bit hasDelaySlot = 1;
bit isTerminator=1;
bit isBarrier=1;
+ bit isCTI = 1;
}
class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
@@ -681,6 +695,7 @@ class SDBBP_R6_DESC {
dag InOperandList = (ins uimm20:$code_);
string AsmString = "sdbbp\t$code_";
list<dag> Pattern = [];
+ bit isCTI = 1;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index 8313d909df2..2c384b8addb 100644
--- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -507,23 +507,13 @@ getUnderlyingObjects(const MachineInstr &MI,
// Replace Branch with the compact branch instruction.
Iter Filler::replaceWithCompactBranch(MachineBasicBlock &MBB,
Iter Branch, DebugLoc DL) {
- const MipsInstrInfo *TII =
- MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo();
-
- unsigned NewOpcode =
- (((unsigned) Branch->getOpcode()) == Mips::BEQ) ? Mips::BEQZC_MM
- : Mips::BNEZC_MM;
-
- const MCInstrDesc &NewDesc = TII->get(NewOpcode);
- MachineInstrBuilder MIB = BuildMI(MBB, Branch, DL, NewDesc);
-
- MIB.addReg(Branch->getOperand(0).getReg());
- MIB.addMBB(Branch->getOperand(2).getMBB());
+ const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
+ const MipsInstrInfo *TII = STI.getInstrInfo();
- Iter tmpIter = Branch;
- Branch = std::prev(Branch);
- MBB.erase(tmpIter);
+ unsigned NewOpcode = TII->getEquivalentCompactForm(Branch);
+ Branch = TII->genInstrWithNewOpc(NewOpcode, Branch);
+ std::next(Branch)->eraseFromParent();
return Branch;
}
@@ -611,27 +601,27 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
// If instruction is BEQ or BNE with one ZERO register, then instead of
// adding NOP replace this instruction with the corresponding compact
// branch instruction, i.e. BEQZC or BNEZC.
- unsigned Opcode = I->getOpcode();
if (InMicroMipsMode) {
- switch (Opcode) {
- case Mips::BEQ:
- case Mips::BNE:
- if (((unsigned) I->getOperand(1).getReg()) == Mips::ZERO) {
- I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
- continue;
- }
- break;
- case Mips::JR:
- case Mips::PseudoReturn:
- case Mips::PseudoIndirectBranch:
- // For microMIPS the PseudoReturn and PseudoIndirectBranch are allways
- // expanded to JR_MM, so they can be replaced with JRC16_MM.
- I = replaceWithCompactJump(MBB, I, I->getDebugLoc());
- continue;
- default:
- break;
+ if (TII->getEquivalentCompactForm(I)) {
+ I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
+ continue;
+ }
+
+ if (I->isIndirectBranch() || I->isReturn()) {
+ // For microMIPS the PseudoReturn and PseudoIndirectBranch are always
+ // expanded to JR_MM, so they can be replaced with JRC16_MM.
+ I = replaceWithCompactJump(MBB, I, I->getDebugLoc());
+ continue;
}
}
+
+ // For MIPSR6 attempt to produce the corresponding compact (no delay slot)
+ // form of the branch. This should save putting in a NOP.
+ if ((STI.hasMips32r6()) && TII->getEquivalentCompactForm(I)) {
+ I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
+ continue;
+ }
+
// Bundle the NOP to the instruction with the delay slot.
BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
MIBundleBuilder(MBB, I, std::next(I, 2));
diff --git a/llvm/lib/Target/Mips/MipsHazardSchedule.cpp b/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
new file mode 100644
index 00000000000..b2b8eb04ce0
--- /dev/null
+++ b/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
@@ -0,0 +1,136 @@
+//===-- MipsHazardSchedule.cpp - Workaround pipeline hazards---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This pass is used to workaround certain pipeline hazards. For now, this covers
+/// compact branch hazards. In future this pass can be extended to other pipeline
+/// hazards, such as various MIPS1 hazards, processor errata that require
+/// instruction reorganization, etc.
+///
+/// This pass has to run after the delay slot filler as that pass can introduce
+/// pipeline hazards, hence the existing hazard recognizer is not suitable.
+///
+/// Hazards handled: forbidden slots for MIPSR6.
+///
+/// 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.
+///
+/// For example:
+///
+/// 0x8004 bnec a1,v0,<P+0x18>
+/// 0x8008 beqc a1,a2,<P+0x54>
+///
+/// In such cases, the processor is required to signal a Reserved Instruction
+/// exception.
+///
+/// Here, if the instruction at 0x8004 is executed, the processor will raise an
+/// exception as there is a control transfer instruction at 0x8008.
+///
+/// There are two sources of forbidden slot hazards:
+///
+/// A) A previous pass has created a compact branch directly.
+/// B) Transforming a delay slot branch into compact branch. This case can be
+/// difficult to process as lookahead for hazards is insufficent, as
+/// backwards delay slot fillling can also produce hazards in previously
+/// processed instuctions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Mips.h"
+#include "MipsInstrInfo.h"
+#include "MipsSEInstrInfo.h"
+#include "MipsTargetMachine.h"
+#include "llvm/IR/Function.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mips-hazard-schedule"
+
+STATISTIC(NumInsertedNops, "Number of nops inserted");
+
+namespace {
+
+typedef MachineBasicBlock::iterator Iter;
+typedef MachineBasicBlock::reverse_iterator ReverseIter;
+
+class MipsHazardSchedule : public MachineFunctionPass {
+
+public:
+ MipsHazardSchedule(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) {}
+
+ const char *getPassName() const override { return "Mips Hazard Schedule"; }
+
+ bool runOnMachineFunction(MachineFunction &F) override;
+
+private:
+ static char ID;
+ const TargetMachine &TM;
+};
+
+char MipsHazardSchedule::ID = 0;
+} // end of anonymous namespace
+
+/// Returns a pass that clears pipeline hazards.
+FunctionPass *llvm::createMipsHazardSchedule(MipsTargetMachine &tm) {
+ return new MipsHazardSchedule(tm);
+}
+
+bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
+
+ const MipsSubtarget *STI =
+ &static_cast<const MipsSubtarget &>(MF.getSubtarget());
+
+ // Forbidden slot hazards are only defined for MIPSR6.
+ if (!STI->hasMips32r6() || STI->inMicroMipsMode())
+ return false;
+
+ bool Changed = false;
+ const MipsInstrInfo *TII = STI->getInstrInfo();
+
+ for (MachineFunction::iterator FI = MF.begin(); FI != MF.end(); ++FI) {
+ for (Iter I = FI->begin(); I != FI->end(); ++I) {
+
+ // Forbidden slot hazard handling. Use lookahead over state.
+ if (!TII->HasForbiddenSlot(*I))
+ continue;
+
+ bool InsertNop = false;
+ // Next instruction in the basic block.
+ if (std::next(I) != FI->end() &&
+ !TII->SafeInForbiddenSlot(*std::next(I))) {
+ InsertNop = true;
+ } else {
+ // Next instruction in the physical successor basic block.
+ for (auto *Succ : FI->successors()) {
+ if (FI->isLayoutSuccessor(Succ) &&
+ Succ->getFirstNonDebugInstr() != Succ->end() &&
+ !TII->SafeInForbiddenSlot(*Succ->getFirstNonDebugInstr())) {
+ InsertNop = true;
+ break;
+ }
+ }
+ }
+
+ if (InsertNop) {
+ Changed = true;
+ MIBundleBuilder(I)
+ .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
+ NumInsertedNops++;
+ }
+ }
+ }
+ return Changed;
+}
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 694ff9b4943..2b3912ff02d 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -1064,6 +1064,8 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB,
DebugLoc DL = MI->getDebugLoc();
unsigned LL, SC, AND, NOR, ZERO, BEQ;
+ // FIXME: The below code should check for the ISA to emit the correct 64bit
+ // operations when the size is 4.
if (Size == 4) {
if (isMicroMips) {
LL = Mips::LL_MM;
diff --git a/llvm/lib/Target/Mips/MipsInstrFormats.td b/llvm/lib/Target/Mips/MipsInstrFormats.td
index 45baf27be51..0bbb49b6b08 100644
--- a/llvm/lib/Target/Mips/MipsInstrFormats.td
+++ b/llvm/lib/Target/Mips/MipsInstrFormats.td
@@ -94,10 +94,15 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern,
//
// Attributes specific to Mips instructions...
//
- bits<4> FormBits = Form.Value;
+ bits<4> FormBits = Form.Value;
+ bit isCTI = 0; // Any form of Control Transfer Instruction.
+ // Required for MIPSR6
+ bit hasForbiddenSlot = 0; // Instruction has a forbidden slot.
// TSFlags layout should be kept in sync with MipsInstrInfo.h.
let TSFlags{3-0} = FormBits;
+ let TSFlags{4} = isCTI;
+ let TSFlags{5} = hasForbiddenSlot;
let DecoderNamespace = "Mips";
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/llvm/lib/Target/Mips/MipsInstrInfo.cpp
index a3c69c67448..5e4f3a45aef 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.cpp
@@ -256,6 +256,71 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
return BT_CondUncond;
}
+/// Return the corresponding compact (no delay slot) form of a branch.
+unsigned MipsInstrInfo::getEquivalentCompactForm(
+ const MachineBasicBlock::iterator I) const {
+ unsigned Opcode = I->getOpcode();
+ bool canUseShortMMBranches =
+ Subtarget.inMicroMipsMode() &&
+ (Opcode == Mips::BNE || Opcode == Mips::BEQ) &&
+ I->getOperand(1).getReg() == Subtarget.getABI().GetZeroReg();
+
+ if (Subtarget.hasMips32r6() || canUseShortMMBranches) {
+ switch (Opcode) {
+ case Mips::B:
+ return Mips::BC;
+ case Mips::BAL:
+ return Mips::BALC;
+ case Mips::BEQ:
+ if (canUseShortMMBranches)
+ return Mips::BEQZC_MM;
+ else
+ return Mips::BEQC;
+ case Mips::BNE:
+ if (canUseShortMMBranches)
+ return Mips::BNEZC_MM;
+ else
+ return Mips::BNEC;
+ case Mips::BGE:
+ return Mips::BGEC;
+ case Mips::BGEU:
+ return Mips::BGEUC;
+ case Mips::BGEZ:
+ return Mips::BGEZC;
+ case Mips::BGTZ:
+ return Mips::BGTZC;
+ case Mips::BLEZ:
+ return Mips::BLEZC;
+ case Mips::BLT:
+ return Mips::BLTC;
+ case Mips::BLTU:
+ return Mips::BLTUC;
+ case Mips::BLTZ:
+ return Mips::BLTZC;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/// Predicate for distingushing between control transfer instructions and all
+/// other instructions for handling forbidden slots. Consider inline assembly
+/// as unsafe as well.
+bool MipsInstrInfo::SafeInForbiddenSlot(const MachineInstr &MI) const {
+ if (MI.isInlineAsm())
+ return false;
+
+ return (MI.getDesc().TSFlags & MipsII::IsCTI) == 0;
+
+}
+
+/// Predicate for distingushing instructions that have forbidden slots.
+bool MipsInstrInfo::HasForbiddenSlot(const MachineInstr &MI) const {
+ return (MI.getDesc().TSFlags & MipsII::HasForbiddenSlot) != 0;
+}
+
/// Return the number of bytes of code the specified instruction may be.
unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
switch (MI->getOpcode()) {
@@ -277,10 +342,46 @@ MachineInstrBuilder
MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
MachineBasicBlock::iterator I) const {
MachineInstrBuilder MIB;
+ bool BranchWithZeroOperand = false;
+
+ // Certain branches have two forms: e.g beq $1, $zero, dst vs beqz $1, dest
+ // Pick the zero form of the branch for readable assembly and for greater
+ // branch distance in non-microMIPS mode.
+ if (I->isBranch() && I->getOperand(1).isReg() &&
+ // FIXME: Certain atomic sequences on mips64 generate 32bit references to
+ // Mips::ZERO, which is incorrect. This test should be updated to use
+ // Subtarget.getABI().GetZeroReg() when those atomic sequences and others
+ // are fixed.
+ (I->getOperand(1).getReg() == Mips::ZERO ||
+ I->getOperand(1).getReg() == Mips::ZERO_64)) {
+ BranchWithZeroOperand = true;
+ switch (NewOpc) {
+ case Mips::BEQC:
+ NewOpc = Mips::BEQZC;
+ break;
+ case Mips::BNEC:
+ NewOpc = Mips::BNEZC;
+ break;
+ case Mips::BGEC:
+ NewOpc = Mips::BGEZC;
+ break;
+ case Mips::BLTC:
+ NewOpc = Mips::BLTZC;
+ break;
+ case Mips::BNEZC_MM:
+ case Mips::BEQZC_MM:
+ break;
+ default:
+ BranchWithZeroOperand = false;
+ break;
+ }
+ }
+
MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), get(NewOpc));
for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J)
- MIB.addOperand(I->getOperand(J));
+ if (!(BranchWithZeroOperand && (J == 1)))
+ MIB.addOperand(I->getOperand(J));
MIB.setMemRefs(I->memoperands_begin(), I->memoperands_end());
return MIB;
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.h b/llvm/lib/Target/Mips/MipsInstrInfo.h
index cb1134ecc35..b6361a2c506 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.h
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.h
@@ -70,6 +70,15 @@ public:
bool AllowModify,
SmallVectorImpl<MachineInstr*> &BranchInstrs) const;
+ /// Determine the opcode of a non-delay slot form for a branch if one exists.
+ unsigned getEquivalentCompactForm(const MachineBasicBlock::iterator I) const;
+
+ /// Predicate to determine if an instruction can go in a forbidden slot.
+ bool SafeInForbiddenSlot(const MachineInstr &MI) const;
+
+ /// Predicate to determine if an instruction has a forbidden slot.
+ bool HasForbiddenSlot(const MachineInstr &MI) const;
+
/// Insert nop instruction when hazard condition is found
void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const override;
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index e72d0b96bed..26be27f3e28 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -348,14 +348,17 @@ class IsCommutable {
class IsBranch {
bit isBranch = 1;
+ bit isCTI = 1;
}
class IsReturn {
bit isReturn = 1;
+ bit isCTI = 1;
}
class IsCall {
bit isCall = 1;
+ bit isCTI = 1;
}
class IsTailCall {
@@ -365,6 +368,7 @@ class IsTailCall {
bit isBarrier = 1;
bit hasExtraSrcRegAllocReq = 1;
bit isCodeGenOnly = 1;
+ bit isCTI = 1;
}
class IsAsCheapAsAMove {
@@ -1068,6 +1072,7 @@ class CBranch<string opstr, DAGOperand opnd, PatFrag cond_op,
let isTerminator = 1;
let hasDelaySlot = DelaySlot;
let Defs = [AT];
+ bit isCTI = 1;
}
class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op,
@@ -1080,6 +1085,7 @@ class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op,
let isTerminator = 1;
let hasDelaySlot = DelaySlot;
let Defs = [AT];
+ bit isCTI = 1;
}
// SetCC
@@ -1106,6 +1112,7 @@ class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator,
let hasDelaySlot = 1;
let DecoderMethod = "DecodeJumpTarget";
let Defs = [AT];
+ bit isCTI = 1;
}
// Unconditional branch
@@ -1118,10 +1125,11 @@ class UncondBranch<Instruction BEQInst> :
let hasDelaySlot = 1;
let AdditionalPredicates = [RelocPIC];
let Defs = [AT];
+ bit isCTI = 1;
}
// Base class for indirect branch and return instruction classes.
-let isTerminator=1, isBarrier=1, hasDelaySlot = 1 in
+let isTerminator=1, isBarrier=1, hasDelaySlot = 1, isCTI = 1 in
class JumpFR<string opstr, RegisterOperand RO,
SDPatternOperator operator = null_frag>:
InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], II_JR,
@@ -1134,7 +1142,7 @@ class IndirectBranch<string opstr, RegisterOperand RO> : JumpFR<opstr, RO> {
}
// Jump and Link (Call)
-let isCall=1, hasDelaySlot=1, Defs = [RA] in {
+let isCall=1, hasDelaySlot=1, isCTI=1, Defs = [RA] in {
class JumpLink<string opstr, DAGOperand opnd> :
InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"),
[(MipsJmpLink tglobaladdr:$target)], II_JAL, FrmJ, opstr> {
@@ -1160,7 +1168,7 @@ let isCall=1, hasDelaySlot=1, Defs = [RA] in {
}
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
- hasExtraSrcRegAllocReq = 1, Defs = [AT] in {
+ hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in {
class TailCall<Instruction JumpInst> :
PseudoSE<(outs), (ins calltarget:$target), [], II_J>,
PseudoInstExpansion<(JumpInst jmptarget:$target)>;
@@ -1179,8 +1187,10 @@ class BAL_BR_Pseudo<Instruction RealInst> :
let isBarrier = 1;
let hasDelaySlot = 1;
let Defs = [RA];
+ bit isCTI = 1;
}
+let isCTI = 1 in {
// Syscall
class SYS_FT<string opstr, Operand ImmOp> :
InstSE<(outs), (ins ImmOp:$code_),
@@ -1196,15 +1206,16 @@ class ER_FT<string opstr> :
InstSE<(outs), (ins),
opstr, [], NoItinerary, FrmOther, opstr>;
+// Wait
+class WAIT_FT<string opstr> :
+ InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>;
+}
+
// Interrupts
class DEI_FT<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$rt), (ins),
!strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther, opstr>;
-// Wait
-class WAIT_FT<string opstr> :
- InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>;
-
// Sync
let hasSideEffects = 1 in
class SYNC_FT<string opstr> :
@@ -1218,17 +1229,15 @@ class SYNCI_FT<string opstr> :
let DecoderMethod = "DecodeSyncI";
}
+let hasSideEffects = 1, isCTI = 1 in {
class TEQ_FT<string opstr, RegisterOperand RO, Operand ImmOp> :
InstSE<(outs), (ins RO:$rs, RO:$rt, ImmOp:$code_),
!strconcat(opstr, "\t$rs, $rt, $code_"), [], NoItinerary,
- FrmI, opstr> {
- let hasSideEffects = 1;
-}
+ FrmI, opstr>;
class TEQI_FT<string opstr, RegisterOperand RO> :
InstSE<(outs), (ins RO:$rs, simm16:$imm16),
- !strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr> {
- let hasSideEffects = 1;
+ !strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr>;
}
// Mul, Div
@@ -1392,6 +1401,7 @@ class TrapBase<Instruction RealInst>
let isBarrier = 1;
let isTerminator = 1;
let isCodeGenOnly = 1;
+ let isCTI = 1;
}
//===----------------------------------------------------------------------===//
@@ -1399,11 +1409,13 @@ class TrapBase<Instruction RealInst>
//===----------------------------------------------------------------------===//
// Return RA.
-let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in
-def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>;
+let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, isCTI=1 in {
+ let hasDelaySlot=1 in
+ def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>;
-let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, hasSideEffects=1 in
-def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>;
+ let hasSideEffects=1 in
+ def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>;
+}
let Defs = [SP], Uses = [SP], hasSideEffects = 1 in {
def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins i32imm:$amt),
@@ -1703,6 +1715,7 @@ class PseudoIndirectBranchBase<RegisterOperand RO> :
let hasDelaySlot = 1;
let isBranch = 1;
let isIndirectBranch = 1;
+ bit isCTI = 1;
}
def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>;
@@ -1720,6 +1733,7 @@ class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs),
let isCodeGenOnly = 1;
let hasCtrlDep = 1;
let hasExtraSrcRegAllocReq = 1;
+ bit isCTI = 1;
}
def PseudoReturn : PseudoReturnBase<GPR32Opnd>;
@@ -1737,7 +1751,7 @@ def SDT_MipsEHRET : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>;
def MIPSehret : SDNode<"MipsISD::EH_RETURN", SDT_MipsEHRET,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
-let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in {
+let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1, isCTI = 1 in {
def MIPSeh_return32 : MipsPseudo<(outs), (ins GPR32:$spoff, GPR32:$dst),
[(MIPSehret GPR32:$spoff, GPR32:$dst)]>;
def MIPSeh_return64 : MipsPseudo<(outs), (ins GPR64:$spoff,
@@ -1845,6 +1859,8 @@ class Barrier<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary,
FrmOther, asmstr>;
def SSNOP : MMRel, StdMMR6Rel, Barrier<"ssnop">, BARRIER_FM<1>;
def EHB : MMRel, Barrier<"ehb">, BARRIER_FM<3>;
+
+let isCTI = 1 in
def PAUSE : MMRel, StdMMR6Rel, Barrier<"pause">, BARRIER_FM<5>, ISA_MIPS32R2;
// JR_HB and JALR_HB are defined here using the new style naming
@@ -1873,12 +1889,14 @@ class JR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>,
let hasDelaySlot=1;
let isTerminator=1;
let isBarrier=1;
+ bit isCTI = 1;
}
class JALR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>,
JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> {
let isIndirectBranch=1;
let hasDelaySlot=1;
+ bit isCTI = 1;
}
class JR_HB_ENC : JR_HB_FM<8>;
@@ -2095,7 +2113,7 @@ def JalOneReg : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs),
def NORImm : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm),
"nor\t$rs, $rt, $imm"> ;
-let hasDelaySlot = 1 in {
+let hasDelaySlot = 1, isCTI = 1 in {
def BneImm : MipsAsmPseudoInst<(outs GPR32Opnd:$rt),
(ins imm64:$imm64, brtarget:$offset),
"bne\t$rt, $imm64, $offset">;
@@ -2126,6 +2144,7 @@ def BLEUL: CondBranchPseudo<"bleul">, ISA_MIPS2_NOT_32R6_64R6;
def BGEUL: CondBranchPseudo<"bgeul">, ISA_MIPS2_NOT_32R6_64R6;
def BGTUL: CondBranchPseudo<"bgtul">, ISA_MIPS2_NOT_32R6_64R6;
+let isCTI = 1 in
class CondBranchImmPseudo<string instr_asm> :
MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, imm64:$imm, brtarget:$offset),
!strconcat(instr_asm, "\t$rs, $imm, $offset")>;
diff --git a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
index a2535983e0d..81e93e98d9c 100644
--- a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
@@ -421,6 +421,14 @@ unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
case Mips::BC1F: return Mips::BC1T;
case Mips::BEQZC_MM: return Mips::BNEZC_MM;
case Mips::BNEZC_MM: return Mips::BEQZC_MM;
+ case Mips::BEQZC: return Mips::BNEZC;
+ case Mips::BNEZC: return Mips::BEQZC;
+ case Mips::BEQC: return Mips::BNEC;
+ case Mips::BNEC: return Mips::BEQC;
+ case Mips::BGTZC: return Mips::BLEZC;
+ case Mips::BGEZC: return Mips::BLTZC;
+ case Mips::BLTZC: return Mips::BGEZC;
+ case Mips::BLEZC: return Mips::BGTZC;
}
}
@@ -494,8 +502,12 @@ unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 ||
Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 ||
Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B ||
- Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM) ?
- Opc : 0;
+ Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM ||
+ Opc == Mips::BEQC || Opc == Mips::BNEC || Opc == Mips::BLTC ||
+ Opc == Mips::BGEC || Opc == Mips::BLTUC || Opc == Mips::BGEUC ||
+ Opc == Mips::BGTZC || Opc == Mips::BLEZC || Opc == Mips::BGEZC ||
+ Opc == Mips::BGTZC || Opc == Mips::BEQZC || Opc == Mips::BNEZC ||
+ Opc == Mips::BC) ? Opc : 0;
}
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 3e638720e83..607d124d007 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -250,7 +250,13 @@ TargetIRAnalysis MipsTargetMachine::getTargetIRAnalysis() {
// print out the code after the passes.
void MipsPassConfig::addPreEmitPass() {
MipsTargetMachine &TM = getMipsTargetMachine();
+
+ // The delay slot filler pass can potientially create forbidden slot (FS)
+ // hazards for MIPSR6 which the hazard schedule pass (HSP) will fix. Any
+ // (new) pass that creates compact branches after the HSP must handle FS
+ // hazards itself or be pipelined before the HSP.
addPass(createMipsDelaySlotFillerPass(TM));
+ addPass(createMipsHazardSchedule(TM));
addPass(createMipsLongBranchPass(TM));
addPass(createMipsConstantIslandPass(TM));
}
OpenPOWER on IntegriCloud