summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--llvm/test/CodeGen/Mips/analyzebranch.ll5
-rw-r--r--llvm/test/CodeGen/Mips/atomic.ll28
-rw-r--r--llvm/test/CodeGen/Mips/compactbranches/compact-branches.ll155
-rw-r--r--llvm/test/CodeGen/Mips/fcmp.ll8
-rw-r--r--llvm/test/CodeGen/Mips/fpbr.ll18
18 files changed, 555 insertions, 73 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));
}
diff --git a/llvm/test/CodeGen/Mips/analyzebranch.ll b/llvm/test/CodeGen/Mips/analyzebranch.ll
index d5ecaaeddc3..75ed2def4d9 100644
--- a/llvm/test/CodeGen/Mips/analyzebranch.ll
+++ b/llvm/test/CodeGen/Mips/analyzebranch.ll
@@ -19,7 +19,7 @@ entry:
; GPR: cmp.lt.d $[[FGRCC:f[0-9]+]], $[[Z]], $f12
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: bnez $[[GPRCC]], $BB
+; GPR: bnezc $[[GPRCC]], $BB
%cmp = fcmp ogt double %a, 0.000000e+00
br i1 %cmp, label %if.end6, label %if.else
@@ -50,7 +50,8 @@ entry:
; GPR: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $[[Z]]
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: beqz $[[GPRCC]], $BB
+; 64-GPR beqzc $[[GPRCC]], $BB
+; 32-GPR beqz $[[GPRCC]], $BB
%cmp = fcmp une float %f, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end
diff --git a/llvm/test/CodeGen/Mips/atomic.ll b/llvm/test/CodeGen/Mips/atomic.ll
index 031cce0b607..a0cbe0ecb13 100644
--- a/llvm/test/CodeGen/Mips/atomic.ll
+++ b/llvm/test/CodeGen/Mips/atomic.ll
@@ -1,10 +1,10 @@
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
-; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
+; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MIPSR6
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips4 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
-; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
+; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MIPSR6
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r2 -mattr=micromips < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MICROMIPS
; Keep one big-endian check so that we don't reduce testing, but don't add more
@@ -29,6 +29,7 @@ entry:
; ALL: sc $[[R2]], 0($[[R0]])
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
+; MIPSR6: beqzc $[[R2]], $[[BB0]]
}
define i32 @AtomicLoadNand32(i32 signext %incr) nounwind {
@@ -48,6 +49,7 @@ entry:
; ALL: sc $[[R2]], 0($[[R0]])
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
+; MIPSR6: beqzc $[[R2]], $[[BB0]]
}
define i32 @AtomicSwap32(i32 signext %newval) nounwind {
@@ -68,6 +70,7 @@ entry:
; ALL: sc $[[R2:[0-9]+]], 0($[[R0]])
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
+; MIPSR6: beqzc $[[R2]], $[[BB0]]
}
define i32 @AtomicCmpSwap32(i32 signext %oldval, i32 signext %newval) nounwind {
@@ -86,10 +89,13 @@ entry:
; ALL: $[[BB0:[A-Z_0-9]+]]:
; ALL: ll $2, 0($[[R0]])
-; ALL: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
+; NOT-MICROMIPS: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
+; MICROMIPS: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
+; MIPSR6: bnec $2, $4, $[[BB1:[A-Z_0-9]+]]
; ALL: sc $[[R2:[0-9]+]], 0($[[R0]])
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
+; MIPSR6: beqzc $[[R2]], $[[BB0]]
; ALL: $[[BB1]]:
}
@@ -127,6 +133,7 @@ entry:
; ALL: sc $[[R14]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
+; MIPSR6: beqzc $[[R14]], $[[BB0]]
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
@@ -167,6 +174,7 @@ entry:
; ALL: sc $[[R14]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
+; MIPSR6: beqzc $[[R14]], $[[BB0]]
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
@@ -208,6 +216,7 @@ entry:
; ALL: sc $[[R14]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
+; MIPSR6: beqzc $[[R14]], $[[BB0]]
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
@@ -247,6 +256,7 @@ entry:
; ALL: sc $[[R14]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
+; MIPSR6: beqzc $[[R14]], $[[BB0]]
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
@@ -286,13 +296,16 @@ entry:
; ALL: $[[BB0:[A-Z_0-9]+]]:
; ALL: ll $[[R13:[0-9]+]], 0($[[R2]])
; ALL: and $[[R14:[0-9]+]], $[[R13]], $[[R7]]
-; ALL: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; NOT-MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; MIPSR6: bnec $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
; ALL: and $[[R15:[0-9]+]], $[[R13]], $[[R8]]
; ALL: or $[[R16:[0-9]+]], $[[R15]], $[[R12]]
; ALL: sc $[[R16]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R16]], $[[BB0]]
; MICROMIPS: beqzc $[[R16]], $[[BB0]]
+; MIPSR6: beqzc $[[R16]], $[[BB0]]
; ALL: $[[BB1]]:
; ALL: srlv $[[R17:[0-9]+]], $[[R14]], $[[R5]]
@@ -327,13 +340,16 @@ entry:
; ALL: $[[BB0:[A-Z_0-9]+]]:
; ALL: ll $[[R13:[0-9]+]], 0($[[R2]])
; ALL: and $[[R14:[0-9]+]], $[[R13]], $[[R7]]
-; ALL: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; NOT-MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
+; MIPSR6: bnec $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
; ALL: and $[[R15:[0-9]+]], $[[R13]], $[[R8]]
; ALL: or $[[R16:[0-9]+]], $[[R15]], $[[R12]]
; ALL: sc $[[R16]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R16]], $[[BB0]]
; MICROMIPS: beqzc $[[R16]], $[[BB0]]
+; MIPSR6: beqzc $[[R16]], $[[BB0]]
; ALL: $[[BB1]]:
; ALL: srlv $[[R17:[0-9]+]], $[[R14]], $[[R5]]
@@ -380,6 +396,7 @@ entry:
; ALL: sc $[[R14]], 0($[[R2]])
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
+; MIPSR6: beqzc $[[R14]], $[[BB0]]
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
@@ -444,4 +461,5 @@ entry:
; ALL: sc $[[R2]], 0($[[PTR]])
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
+; MIPSR6: beqzc $[[R2]], $[[BB0]]
}
diff --git a/llvm/test/CodeGen/Mips/compactbranches/compact-branches.ll b/llvm/test/CodeGen/Mips/compactbranches/compact-branches.ll
new file mode 100644
index 00000000000..e863c740943
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/compactbranches/compact-branches.ll
@@ -0,0 +1,155 @@
+; RUN: llc -march=mipsel -mcpu=mips32r6 -relocation-model=static < %s | FileCheck %s
+
+; Function Attrs: nounwind
+define void @l() {
+entry:
+ %call = tail call i32 @k()
+ %call1 = tail call i32 @j()
+ %cmp = icmp eq i32 %call, %call1
+; CHECK: bnec
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext -2)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+declare i32 @k()
+
+declare i32 @j()
+
+declare void @f(i32 signext)
+
+; Function Attrs: define void @l2() {
+define void @l2() {
+entry:
+ %call = tail call i32 @k()
+ %call1 = tail call i32 @i()
+ %cmp = icmp eq i32 %call, %call1
+; CHECK beqc
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext -1)
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ ret void
+}
+
+declare i32 @i()
+
+; Function Attrs: nounwind
+define void @l3() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp slt i32 %call, 0
+; CHECK : bgez
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 0)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @l4() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp slt i32 %call, 1
+; CHECK: bgtzc
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 1)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @l5() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp sgt i32 %call, 0
+; CHECK: blezc
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 2)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @l6() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp sgt i32 %call, -1
+; CHECK: bltzc
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 3)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @l7() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp eq i32 %call, 0
+; CHECK: bnezc
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 4)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @l8() {
+entry:
+ %call = tail call i32 @k()
+ %cmp = icmp eq i32 %call, 0
+; CHECK: beqzc
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then: ; preds = %entry:
+; CHECK: nop
+; CHECK: jal
+ tail call void @f(i32 signext 5)
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ ret void
+}
diff --git a/llvm/test/CodeGen/Mips/fcmp.ll b/llvm/test/CodeGen/Mips/fcmp.ll
index aa1f09bf7ab..0e44c5bded2 100644
--- a/llvm/test/CodeGen/Mips/fcmp.ll
+++ b/llvm/test/CodeGen/Mips/fcmp.ll
@@ -750,7 +750,7 @@ entry:
; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
; FIXME: This instruction is redundant.
; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 32-CMP-DAG: bnez $[[T4]],
+; 32-CMP-DAG: bnezc $[[T4]],
; 64-C-DAG: add.s $[[T0:f[0-9]+]], $f13, $f12
; 64-C-DAG: lwc1 $[[T1:f[0-9]+]], %got_ofst($CPI32_0)(
@@ -763,7 +763,7 @@ entry:
; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
; FIXME: This instruction is redundant.
; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 64-CMP-DAG: bnez $[[T4]],
+; 64-CMP-DAG: bnezc $[[T4]],
%add = fadd fast float %at, %angle
%cmp = fcmp ogt float %add, 1.000000e+00
@@ -794,7 +794,7 @@ entry:
; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
; FIXME: This instruction is redundant.
; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 32-CMP-DAG: bnez $[[T4]],
+; 32-CMP-DAG: bnezc $[[T4]],
; 64-C-DAG: add.d $[[T0:f[0-9]+]], $f13, $f12
; 64-C-DAG: ldc1 $[[T1:f[0-9]+]], %got_ofst($CPI33_0)(
@@ -807,7 +807,7 @@ entry:
; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
; FIXME: This instruction is redundant.
; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
-; 64-CMP-DAG: bnez $[[T4]],
+; 64-CMP-DAG: bnezc $[[T4]],
%add = fadd fast double %at, %angle
%cmp = fcmp ogt double %add, 1.000000e+00
diff --git a/llvm/test/CodeGen/Mips/fpbr.ll b/llvm/test/CodeGen/Mips/fpbr.ll
index 27d7094376e..9f1df9821cd 100644
--- a/llvm/test/CodeGen/Mips/fpbr.ll
+++ b/llvm/test/CodeGen/Mips/fpbr.ll
@@ -18,7 +18,8 @@ entry:
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; FIXME: We ought to be able to transform not+bnez -> beqz
; GPR: not $[[GPRCC]], $[[GPRCC]]
-; GPR: bnez $[[GPRCC]], $BB0_2
+; 32-GPR: bnez $[[GPRCC]], $BB0_2
+; 64-GPR: bnezc $[[GPRCC]], $BB0_2
%cmp = fcmp oeq float %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -51,7 +52,8 @@ entry:
; 64-GPR: cmp.ule.s $[[FGRCC:f[0-9]+]], $f13, $f12
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: bnez $[[GPRCC]], $BB1_2
+; 32-GPR: bnez $[[GPRCC]], $BB1_2
+; 64-GPR: bnezc $[[GPRCC]], $BB1_2
%cmp = fcmp olt float %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -80,7 +82,8 @@ entry:
; 64-GPR: cmp.ult.s $[[FGRCC:f[0-9]+]], $f13, $f12
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: beqz $[[GPRCC]], $BB2_2
+; 32-GPR: beqz $[[GPRCC]], $BB2_2
+; 64-GPR: beqzc $[[GPRCC]], $BB2_2
%cmp = fcmp ugt float %f2, %f3
br i1 %cmp, label %if.else, label %if.then
@@ -110,7 +113,8 @@ entry:
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; FIXME: We ought to be able to transform not+bnez -> beqz
; GPR: not $[[GPRCC]], $[[GPRCC]]
-; GPR: bnez $[[GPRCC]], $BB3_2
+; 32-GPR: bnez $[[GPRCC]], $BB3_2
+; 64-GPR: bnezc $[[GPRCC]], $BB3_2
%cmp = fcmp oeq double %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -139,7 +143,8 @@ entry:
; 64-GPR: cmp.ule.d $[[FGRCC:f[0-9]+]], $f13, $f12
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: bnez $[[GPRCC]], $BB4_2
+; 32-GPR: bnez $[[GPRCC]], $BB4_2
+; 64-GPR: bnezc $[[GPRCC]], $BB4_2
%cmp = fcmp olt double %f2, %f3
br i1 %cmp, label %if.then, label %if.else
@@ -168,7 +173,8 @@ entry:
; 64-GPR: cmp.ult.d $[[FGRCC:f[0-9]+]], $f13, $f12
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
-; GPR: beqz $[[GPRCC]], $BB5_2
+; 32-GPR: beqz $[[GPRCC]], $BB5_2
+; 64-GPR: beqzc $[[GPRCC]], $BB5_2
%cmp = fcmp ugt double %f2, %f3
br i1 %cmp, label %if.else, label %if.then
OpenPOWER on IntegriCloud