summaryrefslogtreecommitdiff
path: root/lib/Target/Mips/MipsInstrInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Mips/MipsInstrInfo.cpp')
-rw-r--r--lib/Target/Mips/MipsInstrInfo.cpp236
1 files changed, 208 insertions, 28 deletions
diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp
index b1d69506c16f2..800d834e0ab8e 100644
--- a/lib/Target/Mips/MipsInstrInfo.cpp
+++ b/lib/Target/Mips/MipsInstrInfo.cpp
@@ -13,7 +13,6 @@
#include "MipsInstrInfo.h"
#include "InstPrinter/MipsInstPrinter.h"
-#include "MipsAnalyzeImmediate.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
#include "llvm/ADT/STLExtras.h"
@@ -47,6 +46,7 @@ bool MipsInstrInfo::isZeroImm(const MachineOperand &op) const {
/// insertNoop - If data hazard condition is found insert the target nop
/// instruction.
+// FIXME: This appears to be dead code.
void MipsInstrInfo::
insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
{
@@ -54,14 +54,15 @@ insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
BuildMI(MBB, MI, DL, get(Mips::NOP));
}
-MachineMemOperand *MipsInstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI,
- unsigned Flag) const {
+MachineMemOperand *
+MipsInstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI,
+ MachineMemOperand::Flags Flags) const {
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo &MFI = *MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI),
- Flag, MFI.getObjectSize(FI), Align);
+ Flags, MFI.getObjectSize(FI), Align);
}
//===----------------------------------------------------------------------===//
@@ -83,20 +84,20 @@ void MipsInstrInfo::AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc,
Cond.push_back(Inst->getOperand(i));
}
-bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
+bool MipsInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const {
SmallVector<MachineInstr*, 2> BranchInstrs;
- BranchType BT = AnalyzeBranch(MBB, TBB, FBB, Cond, AllowModify, BranchInstrs);
+ BranchType BT = analyzeBranch(MBB, TBB, FBB, Cond, AllowModify, BranchInstrs);
return (BT == BT_None) || (BT == BT_Indirect);
}
-void
-MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
- DebugLoc DL, ArrayRef<MachineOperand> Cond) const {
+void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ const DebugLoc &DL,
+ ArrayRef<MachineOperand> Cond) const {
unsigned Opc = Cond[0].getImm();
const MCInstrDesc &MCID = get(Opc);
MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID);
@@ -107,14 +108,16 @@ MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
else if (Cond[i].isImm())
MIB.addImm(Cond[i].getImm());
else
- assert(true && "Cannot copy operand");
+ assert(false && "Cannot copy operand");
}
MIB.addMBB(TBB);
}
-unsigned MipsInstrInfo::InsertBranch(
- MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
- ArrayRef<MachineOperand> Cond, DebugLoc DL) const {
+unsigned MipsInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ ArrayRef<MachineOperand> Cond,
+ const DebugLoc &DL) const {
// Shouldn't be a fall through.
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
@@ -174,7 +177,7 @@ bool MipsInstrInfo::ReverseBranchCondition(
return false;
}
-MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
+MipsInstrInfo::BranchType MipsInstrInfo::analyzeBranch(
MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond, bool AllowModify,
SmallVectorImpl<MachineInstr *> &BranchInstrs) const {
@@ -185,7 +188,7 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
while (I != REnd && I->isDebugValue())
++I;
- if (I == REnd || !isUnpredicatedTerminator(&*I)) {
+ if (I == REnd || !isUnpredicatedTerminator(*I)) {
// This block ends with no branches (it just falls through to its succ).
// Leave TBB/FBB null.
TBB = FBB = nullptr;
@@ -209,14 +212,14 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
SecondLastOpc = getAnalyzableBrOpc(SecondLastInst->getOpcode());
// Not an analyzable branch (must be an indirect jump).
- if (isUnpredicatedTerminator(SecondLastInst) && !SecondLastOpc)
+ if (isUnpredicatedTerminator(*SecondLastInst) && !SecondLastOpc)
return BT_None;
}
// If there is only one terminator instruction, process it.
if (!SecondLastOpc) {
// Unconditional branch.
- if (LastOpc == UncondBrOpc) {
+ if (LastInst->isUnconditionalBranch()) {
TBB = LastInst->getOperand(0).getMBB();
return BT_Uncond;
}
@@ -228,14 +231,14 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
// If we reached here, there are two branches.
// If there are three terminators, we don't know what sort of block this is.
- if (++I != REnd && isUnpredicatedTerminator(&*I))
+ if (++I != REnd && isUnpredicatedTerminator(*I))
return BT_None;
BranchInstrs.insert(BranchInstrs.begin(), SecondLastInst);
// If second to last instruction is an unconditional branch,
// analyze it and remove the last instruction.
- if (SecondLastOpc == UncondBrOpc) {
+ if (SecondLastInst->isUnconditionalBranch()) {
// Return if the last instruction cannot be removed.
if (!AllowModify)
return BT_None;
@@ -248,7 +251,7 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
// Conditional branch followed by an unconditional branch.
// The last one must be unconditional.
- if (LastOpc != UncondBrOpc)
+ if (!LastInst->isUnconditionalBranch())
return BT_None;
AnalyzeCondBr(SecondLastInst, SecondLastOpc, TBB, Cond);
@@ -257,20 +260,137 @@ 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 canUseShortMicroMipsCTI = false;
+
+ if (Subtarget.inMicroMipsMode()) {
+ switch (Opcode) {
+ case Mips::BNE:
+ case Mips::BEQ:
+ // microMIPS has NE,EQ branches that do not have delay slots provided one
+ // of the operands is zero.
+ if (I->getOperand(1).getReg() == Subtarget.getABI().GetZeroReg())
+ canUseShortMicroMipsCTI = true;
+ break;
+ // For microMIPS the PseudoReturn and PseudoIndirectBranch are always
+ // expanded to JR_MM, so they can be replaced with JRC16_MM.
+ case Mips::JR:
+ case Mips::PseudoReturn:
+ case Mips::PseudoIndirectBranch:
+ canUseShortMicroMipsCTI = true;
+ break;
+ }
+ }
+
+ // MIPSR6 forbids both operands being the zero register.
+ if (Subtarget.hasMips32r6() && (I->getNumOperands() > 1) &&
+ (I->getOperand(0).isReg() &&
+ (I->getOperand(0).getReg() == Mips::ZERO ||
+ I->getOperand(0).getReg() == Mips::ZERO_64)) &&
+ (I->getOperand(1).isReg() &&
+ (I->getOperand(1).getReg() == Mips::ZERO ||
+ I->getOperand(1).getReg() == Mips::ZERO_64)))
+ return 0;
+
+ if (Subtarget.hasMips32r6() || canUseShortMicroMipsCTI) {
+ switch (Opcode) {
+ case Mips::B:
+ return Mips::BC;
+ case Mips::BAL:
+ return Mips::BALC;
+ case Mips::BEQ:
+ if (canUseShortMicroMipsCTI)
+ return Mips::BEQZC_MM;
+ else if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BEQC;
+ case Mips::BNE:
+ if (canUseShortMicroMipsCTI)
+ return Mips::BNEZC_MM;
+ else if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BNEC;
+ case Mips::BGE:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BGEC;
+ case Mips::BGEU:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BGEUC;
+ case Mips::BGEZ:
+ return Mips::BGEZC;
+ case Mips::BGTZ:
+ return Mips::BGTZC;
+ case Mips::BLEZ:
+ return Mips::BLEZC;
+ case Mips::BLT:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BLTC;
+ case Mips::BLTU:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BLTUC;
+ case Mips::BLTZ:
+ return Mips::BLTZC;
+ // For MIPSR6, the instruction 'jic' can be used for these cases. Some
+ // tools will accept 'jrc reg' as an alias for 'jic 0, $reg'.
+ case Mips::JR:
+ case Mips::PseudoReturn:
+ case Mips::PseudoIndirectBranch:
+ if (canUseShortMicroMipsCTI)
+ return Mips::JRC16_MM;
+ return Mips::JIC;
+ case Mips::JALRPseudo:
+ return Mips::JIALC;
+ case Mips::JR64:
+ case Mips::PseudoReturn64:
+ case Mips::PseudoIndirectBranch64:
+ return Mips::JIC64;
+ case Mips::JALR64Pseudo:
+ return Mips::JIALC64;
+ 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()) {
+unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
default:
- return MI->getDesc().getSize();
+ return MI.getDesc().getSize();
case TargetOpcode::INLINEASM: { // Inline Asm: Variable size.
- const MachineFunction *MF = MI->getParent()->getParent();
- const char *AsmStr = MI->getOperand(0).getSymbolName();
+ const MachineFunction *MF = MI.getParent()->getParent();
+ const char *AsmStr = MI.getOperand(0).getSymbolName();
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
}
case Mips::CONSTPOOL_ENTRY:
// If this machine instr is a constant pool entry, its size is recorded as
// operand #2.
- return MI->getOperand(2).getImm();
+ return MI.getOperand(2).getImm();
}
}
@@ -278,10 +398,70 @@ MachineInstrBuilder
MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
MachineBasicBlock::iterator I) const {
MachineInstrBuilder MIB;
+
+ // 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.
+ // 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.
+ bool BranchWithZeroOperand =
+ (I->isBranch() && !I->isPseudo() && I->getOperand(1).isReg() &&
+ (I->getOperand(1).getReg() == Mips::ZERO ||
+ I->getOperand(1).getReg() == Mips::ZERO_64));
+
+ if (BranchWithZeroOperand) {
+ 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;
+ }
+ }
+
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));
+ // For MIPSR6 JI*C requires an immediate 0 as an operand, JIALC(64) an
+ // immediate 0 as an operand and requires the removal of it's %RA<imp-def>
+ // implicit operand as copying the implicit operations of the instructio we're
+ // looking at will give us the correct flags.
+ if (NewOpc == Mips::JIC || NewOpc == Mips::JIALC || NewOpc == Mips::JIC64 ||
+ NewOpc == Mips::JIALC64) {
+
+ if (NewOpc == Mips::JIALC || NewOpc == Mips::JIALC64)
+ MIB->RemoveOperand(0);
+
+ for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) {
+ MIB.addOperand(I->getOperand(J));
+ }
+
+ MIB.addImm(0);
+
+ } else if (BranchWithZeroOperand) {
+ // For MIPSR6 and microMIPS branches with an explicit zero operand, copy
+ // everything after the zero.
+ MIB.addOperand(I->getOperand(0));
+
+ for (unsigned J = 2, E = I->getDesc().getNumOperands(); J < E; ++J) {
+ MIB.addOperand(I->getOperand(J));
+ }
+ } else {
+ // All other cases copy all other operands.
+ for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) {
+ MIB.addOperand(I->getOperand(J));
+ }
+ }
+
+ MIB.copyImplicitOps(*I);
MIB.setMemRefs(I->memoperands_begin(), I->memoperands_end());
return MIB;