mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[mips] Merge MipsLongBranch and MipsHazardSchedule passes
MipsLongBranchPass and MipsHazardSchedule passes are joined to one pass because of mutual conflict. When MipsHazardSchedule inserts 'nop's, it potentially breaks some jumps, so they have to be expanded to long branches. When some branch is expanded to long branch, it potentially creates a hazard situation, which should be fixed by adding nops. New pass is called MipsBranchExpansion, it combines these two passes, and runs them alternately until one of them reports no changes were made. Differential Revision: https://reviews.llvm.org/D46641 llvm-svn: 332834
This commit is contained in:
parent
8df0d84f3d
commit
56d716f1af
@ -31,14 +31,13 @@ add_llvm_target(MipsCodeGen
|
||||
MipsConstantIslandPass.cpp
|
||||
MipsDelaySlotFiller.cpp
|
||||
MipsFastISel.cpp
|
||||
MipsHazardSchedule.cpp
|
||||
MipsInstrInfo.cpp
|
||||
MipsInstructionSelector.cpp
|
||||
MipsISelDAGToDAG.cpp
|
||||
MipsISelLowering.cpp
|
||||
MipsFrameLowering.cpp
|
||||
MipsLegalizerInfo.cpp
|
||||
MipsLongBranch.cpp
|
||||
MipsBranchExpansion.cpp
|
||||
MipsMCInstLower.cpp
|
||||
MipsMachineFunction.cpp
|
||||
MipsModuleISelDAGToDAG.cpp
|
||||
|
@ -33,8 +33,7 @@ namespace llvm {
|
||||
FunctionPass *createMipsModuleISelDagPass();
|
||||
FunctionPass *createMipsOptimizePICCallPass();
|
||||
FunctionPass *createMipsDelaySlotFillerPass();
|
||||
FunctionPass *createMipsHazardSchedule();
|
||||
FunctionPass *createMipsLongBranchPass();
|
||||
FunctionPass *createMipsBranchExpansion();
|
||||
FunctionPass *createMipsConstantIslandPass();
|
||||
FunctionPass *createMicroMipsSizeReductionPass();
|
||||
|
||||
@ -43,7 +42,7 @@ namespace llvm {
|
||||
MipsRegisterBankInfo &);
|
||||
|
||||
void initializeMipsDelaySlotFillerPass(PassRegistry &);
|
||||
void initializeMipsLongBranchPass(PassRegistry &);
|
||||
void initializeMipsBranchExpansionPass(PassRegistry &);
|
||||
} // end namespace llvm;
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- MipsLongBranch.cpp - Emit long branches ----------------------------===//
|
||||
//===----------------------- MipsBranchExpansion.cpp ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -6,11 +6,70 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass expands a branch or jump instruction into a long branch if its
|
||||
// offset is too large to fit into its immediate field.
|
||||
//
|
||||
// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries.
|
||||
/// \file
|
||||
///
|
||||
/// This pass do two things:
|
||||
/// - it expands a branch or jump instruction into a long branch if its offset
|
||||
/// is too large to fit into its immediate field,
|
||||
/// - it inserts nops to prevent forbidden slot hazards.
|
||||
///
|
||||
/// The reason why this pass combines these two tasks is that one of these two
|
||||
/// tasks can break the result of the previous one.
|
||||
///
|
||||
/// Example of that is a situation where at first, no branch should be expanded,
|
||||
/// but after adding at least one nop somewhere in the code to prevent a
|
||||
/// forbidden slot hazard, offset of some branches may go out of range. In that
|
||||
/// case it is necessary to check again if there is some branch that needs
|
||||
/// expansion. On the other hand, expanding some branch may cause a control
|
||||
/// transfer instruction to appear in the forbidden slot, which is a hazard that
|
||||
/// should be fixed. This pass alternates between this two tasks untill no
|
||||
/// changes are made. Only then we can be sure that all branches are expanded
|
||||
/// properly, and no hazard situations exist.
|
||||
///
|
||||
/// Regarding branch expanding:
|
||||
///
|
||||
/// When branch instruction like beqzc or bnezc has offset that is too large
|
||||
/// to fit into its immediate field, it has to be expanded to another
|
||||
/// instruction or series of instructions.
|
||||
///
|
||||
/// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries.
|
||||
/// TODO: Handle out of range bc, b (pseudo) instructions.
|
||||
///
|
||||
/// Regarding compact branch hazard prevention:
|
||||
///
|
||||
/// 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 insufficient, as
|
||||
/// backwards delay slot fillling can also produce hazards in previously
|
||||
/// processed instuctions.
|
||||
///
|
||||
/// In future this pass can be extended (or new pass can be created) to handle
|
||||
/// 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 such as compact branch hazard, hence the existing hazard
|
||||
/// recognizer is not suitable.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/MipsABIInfo.h"
|
||||
@ -30,6 +89,7 @@
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
@ -37,80 +97,125 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "mips-long-branch"
|
||||
#define DEBUG_TYPE "mips-branch-expansion"
|
||||
|
||||
STATISTIC(NumInsertedNops, "Number of nops inserted");
|
||||
STATISTIC(LongBranches, "Number of long branches.");
|
||||
|
||||
static cl::opt<bool> SkipLongBranch(
|
||||
"skip-mips-long-branch",
|
||||
cl::init(false),
|
||||
cl::desc("MIPS: Skip long branch pass."),
|
||||
cl::Hidden);
|
||||
static cl::opt<bool>
|
||||
SkipLongBranch("skip-mips-long-branch", cl::init(false),
|
||||
cl::desc("MIPS: Skip branch expansion pass."), cl::Hidden);
|
||||
|
||||
static cl::opt<bool> ForceLongBranch(
|
||||
"force-mips-long-branch",
|
||||
cl::init(false),
|
||||
cl::desc("MIPS: Expand all branches to long format."),
|
||||
cl::Hidden);
|
||||
static cl::opt<bool>
|
||||
ForceLongBranch("force-mips-long-branch", cl::init(false),
|
||||
cl::desc("MIPS: Expand all branches to long format."),
|
||||
cl::Hidden);
|
||||
|
||||
namespace {
|
||||
|
||||
using Iter = MachineBasicBlock::iterator;
|
||||
using ReverseIter = MachineBasicBlock::reverse_iterator;
|
||||
using Iter = MachineBasicBlock::iterator;
|
||||
using ReverseIter = MachineBasicBlock::reverse_iterator;
|
||||
|
||||
struct MBBInfo {
|
||||
uint64_t Size = 0;
|
||||
uint64_t Address;
|
||||
bool HasLongBranch = false;
|
||||
MachineInstr *Br = nullptr;
|
||||
struct MBBInfo {
|
||||
uint64_t Size = 0;
|
||||
bool HasLongBranch = false;
|
||||
MachineInstr *Br = nullptr;
|
||||
MBBInfo() = default;
|
||||
};
|
||||
|
||||
MBBInfo() = default;
|
||||
};
|
||||
class MipsBranchExpansion : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
class MipsLongBranch : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
MipsBranchExpansion() : MachineFunctionPass(ID), ABI(MipsABIInfo::Unknown()) {
|
||||
initializeMipsBranchExpansionPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
MipsLongBranch() : MachineFunctionPass(ID), ABI(MipsABIInfo::Unknown()) {
|
||||
initializeMipsLongBranchPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
StringRef getPassName() const override {
|
||||
return "Mips Branch Expansion Pass";
|
||||
}
|
||||
|
||||
StringRef getPassName() const override { return "Mips Long Branch"; }
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
private:
|
||||
void splitMBB(MachineBasicBlock *MBB);
|
||||
void initMBBInfo();
|
||||
int64_t computeOffset(const MachineInstr *Br);
|
||||
void replaceBranch(MachineBasicBlock &MBB, Iter Br, const DebugLoc &DL,
|
||||
MachineBasicBlock *MBBOpnd);
|
||||
void expandToLongBranch(MBBInfo &Info);
|
||||
bool handleForbiddenSlot();
|
||||
bool handlePossibleLongBranch();
|
||||
|
||||
private:
|
||||
void splitMBB(MachineBasicBlock *MBB);
|
||||
void initMBBInfo();
|
||||
int64_t computeOffset(const MachineInstr *Br);
|
||||
void replaceBranch(MachineBasicBlock &MBB, Iter Br, const DebugLoc &DL,
|
||||
MachineBasicBlock *MBBOpnd);
|
||||
void expandToLongBranch(MBBInfo &Info);
|
||||
const MipsSubtarget *STI;
|
||||
const MipsInstrInfo *TII;
|
||||
|
||||
MachineFunction *MF;
|
||||
SmallVector<MBBInfo, 16> MBBInfos;
|
||||
bool IsPIC;
|
||||
MipsABIInfo ABI;
|
||||
unsigned LongBranchSeqSize;
|
||||
};
|
||||
MachineFunction *MFp;
|
||||
SmallVector<MBBInfo, 16> MBBInfos;
|
||||
bool IsPIC;
|
||||
MipsABIInfo ABI;
|
||||
unsigned LongBranchSeqSize;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
} // end of anonymous namespace
|
||||
|
||||
char MipsLongBranch::ID = 0;
|
||||
char MipsBranchExpansion::ID = 0;
|
||||
|
||||
INITIALIZE_PASS(MipsLongBranch, DEBUG_TYPE,
|
||||
"Expand out of range branch instructions", false, false)
|
||||
INITIALIZE_PASS(MipsBranchExpansion, DEBUG_TYPE,
|
||||
"Expand out of range branch instructions and prevent forbidden"
|
||||
" slot hazards",
|
||||
false, false)
|
||||
|
||||
/// Returns a pass that clears pipeline hazards.
|
||||
FunctionPass *llvm::createMipsBranchExpansion() {
|
||||
return new MipsBranchExpansion();
|
||||
}
|
||||
|
||||
// Find the next real instruction from the current position in current basic
|
||||
// block.
|
||||
static Iter getNextMachineInstrInBB(Iter Position) {
|
||||
Iter I = Position, E = Position->getParent()->end();
|
||||
I = std::find_if_not(I, E,
|
||||
[](const Iter &Insn) { return Insn->isTransient(); });
|
||||
|
||||
return I;
|
||||
}
|
||||
|
||||
// Find the next real instruction from the current position, looking through
|
||||
// basic block boundaries.
|
||||
static std::pair<Iter, bool> getNextMachineInstr(Iter Position,
|
||||
MachineBasicBlock *Parent) {
|
||||
if (Position == Parent->end()) {
|
||||
do {
|
||||
MachineBasicBlock *Succ = Parent->getNextNode();
|
||||
if (Succ != nullptr && Parent->isSuccessor(Succ)) {
|
||||
Position = Succ->begin();
|
||||
Parent = Succ;
|
||||
} else {
|
||||
return std::make_pair(Position, true);
|
||||
}
|
||||
} while (Parent->empty());
|
||||
}
|
||||
|
||||
Iter Instr = getNextMachineInstrInBB(Position);
|
||||
if (Instr == Parent->end()) {
|
||||
return getNextMachineInstr(Instr, Parent);
|
||||
}
|
||||
return std::make_pair(Instr, false);
|
||||
}
|
||||
|
||||
/// Iterate over list of Br's operands and search for a MachineBasicBlock
|
||||
/// operand.
|
||||
@ -136,7 +241,7 @@ static ReverseIter getNonDebugInstr(ReverseIter B, const ReverseIter &E) {
|
||||
}
|
||||
|
||||
// Split MBB if it has two direct jumps/branches.
|
||||
void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) {
|
||||
void MipsBranchExpansion::splitMBB(MachineBasicBlock *MBB) {
|
||||
ReverseIter End = MBB->rend();
|
||||
ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End);
|
||||
|
||||
@ -157,7 +262,7 @@ void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) {
|
||||
|
||||
// Create a new MBB. Move instructions in MBB to the newly created MBB.
|
||||
MachineBasicBlock *NewMBB =
|
||||
MF->CreateMachineBasicBlock(MBB->getBasicBlock());
|
||||
MFp->CreateMachineBasicBlock(MBB->getBasicBlock());
|
||||
|
||||
// Insert NewMBB and fix control flow.
|
||||
MachineBasicBlock *Tgt = getTargetMBB(*FirstBr);
|
||||
@ -165,26 +270,24 @@ void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) {
|
||||
NewMBB->removeSuccessor(Tgt, true);
|
||||
MBB->addSuccessor(NewMBB);
|
||||
MBB->addSuccessor(Tgt);
|
||||
MF->insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
|
||||
MFp->insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
|
||||
|
||||
NewMBB->splice(NewMBB->end(), MBB, LastBr.getReverse(), MBB->end());
|
||||
}
|
||||
|
||||
// Fill MBBInfos.
|
||||
void MipsLongBranch::initMBBInfo() {
|
||||
void MipsBranchExpansion::initMBBInfo() {
|
||||
// Split the MBBs if they have two branches. Each basic block should have at
|
||||
// most one branch after this loop is executed.
|
||||
for (auto &MBB : *MF)
|
||||
for (auto &MBB : *MFp)
|
||||
splitMBB(&MBB);
|
||||
|
||||
MF->RenumberBlocks();
|
||||
MFp->RenumberBlocks();
|
||||
MBBInfos.clear();
|
||||
MBBInfos.resize(MF->size());
|
||||
MBBInfos.resize(MFp->size());
|
||||
|
||||
const MipsInstrInfo *TII =
|
||||
static_cast<const MipsInstrInfo *>(MF->getSubtarget().getInstrInfo());
|
||||
for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {
|
||||
MachineBasicBlock *MBB = MF->getBlockNumbered(I);
|
||||
MachineBasicBlock *MBB = MFp->getBlockNumbered(I);
|
||||
|
||||
// Compute size of MBB.
|
||||
for (MachineBasicBlock::instr_iterator MI = MBB->instr_begin();
|
||||
@ -202,7 +305,7 @@ void MipsLongBranch::initMBBInfo() {
|
||||
}
|
||||
|
||||
// Compute offset of branch in number of bytes.
|
||||
int64_t MipsLongBranch::computeOffset(const MachineInstr *Br) {
|
||||
int64_t MipsBranchExpansion::computeOffset(const MachineInstr *Br) {
|
||||
int64_t Offset = 0;
|
||||
int ThisMBB = Br->getParent()->getNumber();
|
||||
int TargetMBB = getTargetMBB(*Br)->getNumber();
|
||||
@ -224,11 +327,9 @@ int64_t MipsLongBranch::computeOffset(const MachineInstr *Br) {
|
||||
|
||||
// Replace Br with a branch which has the opposite condition code and a
|
||||
// MachineBasicBlock operand MBBOpnd.
|
||||
void MipsLongBranch::replaceBranch(MachineBasicBlock &MBB, Iter Br,
|
||||
const DebugLoc &DL,
|
||||
MachineBasicBlock *MBBOpnd) {
|
||||
const MipsInstrInfo *TII = static_cast<const MipsInstrInfo *>(
|
||||
MBB.getParent()->getSubtarget().getInstrInfo());
|
||||
void MipsBranchExpansion::replaceBranch(MachineBasicBlock &MBB, Iter Br,
|
||||
const DebugLoc &DL,
|
||||
MachineBasicBlock *MBBOpnd) {
|
||||
unsigned NewOpc = TII->getOppositeBranchOpc(Br->getOpcode());
|
||||
const MCInstrDesc &NewDesc = TII->get(NewOpc);
|
||||
|
||||
@ -262,24 +363,20 @@ void MipsLongBranch::replaceBranch(MachineBasicBlock &MBB, Iter Br,
|
||||
// currently assumes that all branches have 16-bit offsets, and will produce
|
||||
// wrong code if branches whose allowed offsets are [-128, -126, ..., 126]
|
||||
// are present.
|
||||
void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
void MipsBranchExpansion::expandToLongBranch(MBBInfo &I) {
|
||||
MachineBasicBlock::iterator Pos;
|
||||
MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br);
|
||||
DebugLoc DL = I.Br->getDebugLoc();
|
||||
const BasicBlock *BB = MBB->getBasicBlock();
|
||||
MachineFunction::iterator FallThroughMBB = ++MachineFunction::iterator(MBB);
|
||||
MachineBasicBlock *LongBrMBB = MF->CreateMachineBasicBlock(BB);
|
||||
const MipsSubtarget &Subtarget =
|
||||
static_cast<const MipsSubtarget &>(MF->getSubtarget());
|
||||
const MipsInstrInfo *TII =
|
||||
static_cast<const MipsInstrInfo *>(Subtarget.getInstrInfo());
|
||||
MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);
|
||||
|
||||
MF->insert(FallThroughMBB, LongBrMBB);
|
||||
MFp->insert(FallThroughMBB, LongBrMBB);
|
||||
MBB->replaceSuccessor(TgtMBB, LongBrMBB);
|
||||
|
||||
if (IsPIC) {
|
||||
MachineBasicBlock *BalTgtMBB = MF->CreateMachineBasicBlock(BB);
|
||||
MF->insert(FallThroughMBB, BalTgtMBB);
|
||||
MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);
|
||||
MFp->insert(FallThroughMBB, BalTgtMBB);
|
||||
LongBrMBB->addSuccessor(BalTgtMBB);
|
||||
BalTgtMBB->addSuccessor(TgtMBB);
|
||||
|
||||
@ -287,9 +384,9 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
// instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an
|
||||
// pseudo-instruction wrapping BGEZAL).
|
||||
const unsigned BalOp =
|
||||
Subtarget.hasMips32r6()
|
||||
? Subtarget.inMicroMipsMode() ? Mips::BALC_MMR6 : Mips::BALC
|
||||
: Subtarget.inMicroMipsMode() ? Mips::BAL_BR_MM : Mips::BAL_BR;
|
||||
STI->hasMips32r6()
|
||||
? STI->inMicroMipsMode() ? Mips::BALC_MMR6 : Mips::BALC
|
||||
: STI->inMicroMipsMode() ? Mips::BAL_BR_MM : Mips::BAL_BR;
|
||||
|
||||
if (!ABI.IsN64()) {
|
||||
// Pre R6:
|
||||
@ -324,9 +421,12 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
Pos = LongBrMBB->begin();
|
||||
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)
|
||||
.addReg(Mips::SP).addImm(-8);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA)
|
||||
.addReg(Mips::SP).addImm(0);
|
||||
.addReg(Mips::SP)
|
||||
.addImm(-8);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW))
|
||||
.addReg(Mips::RA)
|
||||
.addReg(Mips::SP)
|
||||
.addImm(0);
|
||||
|
||||
// LUi and ADDiu instructions create 32-bit offset of the target basic
|
||||
// block from the target of BAL(C) instruction. We cannot use immediate
|
||||
@ -345,16 +445,17 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
// operands to lowered instructions.
|
||||
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)
|
||||
.addMBB(TgtMBB).addMBB(BalTgtMBB);
|
||||
.addMBB(TgtMBB)
|
||||
.addMBB(BalTgtMBB);
|
||||
|
||||
MachineInstrBuilder BalInstr =
|
||||
BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
|
||||
BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
|
||||
MachineInstrBuilder ADDiuInstr =
|
||||
BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
|
||||
BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
|
||||
.addReg(Mips::AT)
|
||||
.addMBB(TgtMBB)
|
||||
.addMBB(BalTgtMBB);
|
||||
if (Subtarget.hasMips32r6()) {
|
||||
if (STI->hasMips32r6()) {
|
||||
LongBrMBB->insert(Pos, ADDiuInstr);
|
||||
LongBrMBB->insert(Pos, BalInstr);
|
||||
} else {
|
||||
@ -366,35 +467,38 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
Pos = BalTgtMBB->begin();
|
||||
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT)
|
||||
.addReg(Mips::RA).addReg(Mips::AT);
|
||||
.addReg(Mips::RA)
|
||||
.addReg(Mips::AT);
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA)
|
||||
.addReg(Mips::SP).addImm(0);
|
||||
if (Subtarget.isTargetNaCl())
|
||||
.addReg(Mips::SP)
|
||||
.addImm(0);
|
||||
if (STI->isTargetNaCl())
|
||||
// Bundle-align the target of indirect branch JR.
|
||||
TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
|
||||
|
||||
// In NaCl, modifying the sp is not allowed in branch delay slot.
|
||||
// For MIPS32R6, we can skip using a delay slot branch.
|
||||
if (Subtarget.isTargetNaCl() ||
|
||||
(Subtarget.hasMips32r6() && !Subtarget.useIndirectJumpsHazard()))
|
||||
if (STI->isTargetNaCl() ||
|
||||
(STI->hasMips32r6() && !STI->useIndirectJumpsHazard()))
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)
|
||||
.addReg(Mips::SP).addImm(8);
|
||||
.addReg(Mips::SP)
|
||||
.addImm(8);
|
||||
|
||||
if (Subtarget.hasMips32r6() && !Subtarget.useIndirectJumpsHazard()) {
|
||||
if (STI->hasMips32r6() && !STI->useIndirectJumpsHazard()) {
|
||||
const unsigned JICOp =
|
||||
Subtarget.inMicroMipsMode() ? Mips::JIC_MMR6 : Mips::JIC;
|
||||
STI->inMicroMipsMode() ? Mips::JIC_MMR6 : Mips::JIC;
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(JICOp))
|
||||
.addReg(Mips::AT)
|
||||
.addImm(0);
|
||||
|
||||
} else {
|
||||
unsigned JROp =
|
||||
Subtarget.useIndirectJumpsHazard()
|
||||
? (Subtarget.hasMips32r6() ? Mips::JR_HB_R6 : Mips::JR_HB)
|
||||
STI->useIndirectJumpsHazard()
|
||||
? (STI->hasMips32r6() ? Mips::JR_HB_R6 : Mips::JR_HB)
|
||||
: Mips::JR;
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(JROp)).addReg(Mips::AT);
|
||||
|
||||
if (Subtarget.isTargetNaCl()) {
|
||||
if (STI->isTargetNaCl()) {
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::NOP));
|
||||
} else
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)
|
||||
@ -452,23 +556,29 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
Pos = LongBrMBB->begin();
|
||||
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)
|
||||
.addReg(Mips::SP_64).addImm(-16);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD)).addReg(Mips::RA_64)
|
||||
.addReg(Mips::SP_64).addImm(0);
|
||||
.addReg(Mips::SP_64)
|
||||
.addImm(-16);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD))
|
||||
.addReg(Mips::RA_64)
|
||||
.addReg(Mips::SP_64)
|
||||
.addImm(0);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu),
|
||||
Mips::AT_64).addReg(Mips::ZERO_64)
|
||||
.addMBB(TgtMBB, MipsII::MO_ABS_HI).addMBB(BalTgtMBB);
|
||||
Mips::AT_64)
|
||||
.addReg(Mips::ZERO_64)
|
||||
.addMBB(TgtMBB, MipsII::MO_ABS_HI)
|
||||
.addMBB(BalTgtMBB);
|
||||
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
|
||||
.addReg(Mips::AT_64).addImm(16);
|
||||
.addReg(Mips::AT_64)
|
||||
.addImm(16);
|
||||
|
||||
MachineInstrBuilder BalInstr =
|
||||
BuildMI(*MF, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
|
||||
BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
|
||||
MachineInstrBuilder DADDiuInstr =
|
||||
BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)
|
||||
BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)
|
||||
.addReg(Mips::AT_64)
|
||||
.addMBB(TgtMBB, MipsII::MO_ABS_LO)
|
||||
.addMBB(BalTgtMBB);
|
||||
if (Subtarget.hasMips32r6()) {
|
||||
if (STI->hasMips32r6()) {
|
||||
LongBrMBB->insert(Pos, DADDiuInstr);
|
||||
LongBrMBB->insert(Pos, BalInstr);
|
||||
} else {
|
||||
@ -480,11 +590,13 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
Pos = BalTgtMBB->begin();
|
||||
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64)
|
||||
.addReg(Mips::RA_64).addReg(Mips::AT_64);
|
||||
.addReg(Mips::RA_64)
|
||||
.addReg(Mips::AT_64);
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64)
|
||||
.addReg(Mips::SP_64).addImm(0);
|
||||
.addReg(Mips::SP_64)
|
||||
.addImm(0);
|
||||
|
||||
if (Subtarget.hasMips64r6() && !Subtarget.useIndirectJumpsHazard()) {
|
||||
if (STI->hasMips64r6() && !STI->useIndirectJumpsHazard()) {
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)
|
||||
.addReg(Mips::SP_64)
|
||||
.addImm(16);
|
||||
@ -493,8 +605,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
.addImm(0);
|
||||
} else {
|
||||
unsigned JROp =
|
||||
Subtarget.useIndirectJumpsHazard()
|
||||
? (Subtarget.hasMips32r6() ? Mips::JR_HB64_R6 : Mips::JR_HB64)
|
||||
STI->useIndirectJumpsHazard()
|
||||
? (STI->hasMips32r6() ? Mips::JR_HB64_R6 : Mips::JR_HB64)
|
||||
: Mips::JR64;
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(JROp)).addReg(Mips::AT_64);
|
||||
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)
|
||||
@ -514,14 +626,14 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
|
||||
//
|
||||
Pos = LongBrMBB->begin();
|
||||
LongBrMBB->addSuccessor(TgtMBB);
|
||||
if (Subtarget.hasMips32r6())
|
||||
if (STI->hasMips32r6())
|
||||
BuildMI(*LongBrMBB, Pos, DL,
|
||||
TII->get(Subtarget.inMicroMipsMode() ? Mips::BC_MMR6 : Mips::BC))
|
||||
TII->get(STI->inMicroMipsMode() ? Mips::BC_MMR6 : Mips::BC))
|
||||
.addMBB(TgtMBB);
|
||||
else
|
||||
MIBundleBuilder(*LongBrMBB, Pos)
|
||||
.append(BuildMI(*MF, DL, TII->get(Mips::J)).addMBB(TgtMBB))
|
||||
.append(BuildMI(*MF, DL, TII->get(Mips::NOP)));
|
||||
.append(BuildMI(*MFp, DL, TII->get(Mips::J)).addMBB(TgtMBB))
|
||||
.append(BuildMI(*MFp, DL, TII->get(Mips::NOP)));
|
||||
|
||||
assert(LongBrMBB->size() == LongBranchSeqSize);
|
||||
}
|
||||
@ -541,35 +653,66 @@ static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {
|
||||
MachineBasicBlock::iterator I = MBB.begin();
|
||||
DebugLoc DL = MBB.findDebugLoc(MBB.begin());
|
||||
BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0)
|
||||
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
|
||||
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
|
||||
BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0)
|
||||
.addReg(Mips::V0).addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
|
||||
.addReg(Mips::V0)
|
||||
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
|
||||
MBB.removeLiveIn(Mips::V0);
|
||||
}
|
||||
|
||||
bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) {
|
||||
const MipsSubtarget &STI =
|
||||
static_cast<const MipsSubtarget &>(F.getSubtarget());
|
||||
const MipsInstrInfo *TII =
|
||||
static_cast<const MipsInstrInfo *>(STI.getInstrInfo());
|
||||
|
||||
const TargetMachine& TM = F.getTarget();
|
||||
IsPIC = TM.isPositionIndependent();
|
||||
ABI = static_cast<const MipsTargetMachine &>(TM).getABI();
|
||||
|
||||
LongBranchSeqSize = IsPIC ? ((ABI.IsN64() || STI.isTargetNaCl()) ? 10 : 9)
|
||||
: (STI.hasMips32r6() ? 1 : 2);
|
||||
|
||||
if (STI.inMips16Mode() || !STI.enableLongBranchPass())
|
||||
bool MipsBranchExpansion::handleForbiddenSlot() {
|
||||
// Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
|
||||
if (!STI->hasMips32r6() || STI->inMicroMipsMode())
|
||||
return false;
|
||||
|
||||
const MipsInstrInfo *TII = STI->getInstrInfo();
|
||||
|
||||
bool Changed = false;
|
||||
|
||||
for (MachineFunction::iterator FI = MFp->begin(); FI != MFp->end(); ++FI) {
|
||||
for (Iter I = FI->begin(); I != FI->end(); ++I) {
|
||||
|
||||
// Forbidden slot hazard handling. Use lookahead over state.
|
||||
if (!TII->HasForbiddenSlot(*I))
|
||||
continue;
|
||||
|
||||
Iter Inst;
|
||||
bool LastInstInFunction =
|
||||
std::next(I) == FI->end() && std::next(FI) == MFp->end();
|
||||
if (!LastInstInFunction) {
|
||||
std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI);
|
||||
LastInstInFunction |= Res.second;
|
||||
Inst = Res.first;
|
||||
}
|
||||
|
||||
if (LastInstInFunction || !TII->SafeInForbiddenSlot(*Inst)) {
|
||||
|
||||
MachineBasicBlock::instr_iterator Iit = I->getIterator();
|
||||
if (std::next(Iit) == FI->end() ||
|
||||
std::next(Iit)->getOpcode() != Mips::NOP) {
|
||||
Changed = true;
|
||||
MIBundleBuilder(&*I).append(
|
||||
BuildMI(*MFp, I->getDebugLoc(), TII->get(Mips::NOP)));
|
||||
NumInsertedNops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
bool MipsBranchExpansion::handlePossibleLongBranch() {
|
||||
|
||||
LongBranchSeqSize = IsPIC ? ((ABI.IsN64() || STI->isTargetNaCl()) ? 10 : 9)
|
||||
: (STI->hasMips32r6() ? 1 : 2);
|
||||
|
||||
if (STI->inMips16Mode() || !STI->enableLongBranchPass())
|
||||
return false;
|
||||
if (IsPIC && static_cast<const MipsTargetMachine &>(TM).getABI().IsO32() &&
|
||||
F.getInfo<MipsFunctionInfo>()->globalBaseRegSet())
|
||||
emitGPDisp(F, TII);
|
||||
|
||||
if (SkipLongBranch)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
MF = &F;
|
||||
initMBBInfo();
|
||||
|
||||
SmallVectorImpl<MBBInfo>::iterator I, E = MBBInfos.end();
|
||||
@ -586,7 +729,7 @@ bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) {
|
||||
|
||||
int64_t Offset = computeOffset(I->Br);
|
||||
|
||||
if (STI.isTargetNaCl()) {
|
||||
if (STI->isTargetNaCl()) {
|
||||
// The offset calculation does not include sandboxing instructions
|
||||
// that will be added later in the MC layer. Since at this point we
|
||||
// don't know the exact amount of code that "sandboxing" will add, we
|
||||
@ -607,26 +750,45 @@ bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) {
|
||||
}
|
||||
|
||||
if (!EverMadeChange)
|
||||
return true;
|
||||
|
||||
// Compute basic block addresses.
|
||||
if (IsPIC) {
|
||||
uint64_t Address = 0;
|
||||
|
||||
for (I = MBBInfos.begin(); I != E; Address += I->Size, ++I)
|
||||
I->Address = Address;
|
||||
}
|
||||
return false;
|
||||
|
||||
// Do the expansion.
|
||||
for (I = MBBInfos.begin(); I != E; ++I)
|
||||
if (I->HasLongBranch)
|
||||
if (I->HasLongBranch) {
|
||||
expandToLongBranch(*I);
|
||||
}
|
||||
|
||||
MF->RenumberBlocks();
|
||||
MFp->RenumberBlocks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// createMipsLongBranchPass - Returns a pass that converts branches to long
|
||||
/// branches.
|
||||
FunctionPass *llvm::createMipsLongBranchPass() { return new MipsLongBranch(); }
|
||||
bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
|
||||
const TargetMachine &TM = MF.getTarget();
|
||||
IsPIC = TM.isPositionIndependent();
|
||||
ABI = static_cast<const MipsTargetMachine &>(TM).getABI();
|
||||
STI = &static_cast<const MipsSubtarget &>(MF.getSubtarget());
|
||||
TII = static_cast<const MipsInstrInfo *>(STI->getInstrInfo());
|
||||
|
||||
if (IsPIC && ABI.IsO32() &&
|
||||
MF.getInfo<MipsFunctionInfo>()->globalBaseRegSet())
|
||||
emitGPDisp(MF, TII);
|
||||
|
||||
MFp = &MF;
|
||||
|
||||
// Run these two at least once
|
||||
bool longBranchChanged = handlePossibleLongBranch();
|
||||
bool forbiddenSlotChanged = handleForbiddenSlot();
|
||||
|
||||
bool Changed = longBranchChanged || forbiddenSlotChanged;
|
||||
|
||||
// Then run them alternatively while there are changes
|
||||
while (forbiddenSlotChanged) {
|
||||
longBranchChanged = handlePossibleLongBranch();
|
||||
if (!longBranchChanged)
|
||||
break;
|
||||
forbiddenSlotChanged = handleForbiddenSlot();
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
//===- 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 insufficient, as
|
||||
/// backwards delay slot fillling can also produce hazards in previously
|
||||
/// processed instuctions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Mips.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsSubtarget.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "mips-hazard-schedule"
|
||||
|
||||
STATISTIC(NumInsertedNops, "Number of nops inserted");
|
||||
|
||||
namespace {
|
||||
|
||||
using Iter = MachineBasicBlock::iterator;
|
||||
using ReverseIter = MachineBasicBlock::reverse_iterator;
|
||||
|
||||
class MipsHazardSchedule : public MachineFunctionPass {
|
||||
public:
|
||||
MipsHazardSchedule() : MachineFunctionPass(ID) {}
|
||||
|
||||
StringRef getPassName() const override { return "Mips Hazard Schedule"; }
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
private:
|
||||
static char ID;
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
char MipsHazardSchedule::ID = 0;
|
||||
|
||||
/// Returns a pass that clears pipeline hazards.
|
||||
FunctionPass *llvm::createMipsHazardSchedule() {
|
||||
return new MipsHazardSchedule();
|
||||
}
|
||||
|
||||
// Find the next real instruction from the current position in current basic
|
||||
// block.
|
||||
static Iter getNextMachineInstrInBB(Iter Position) {
|
||||
Iter I = Position, E = Position->getParent()->end();
|
||||
I = std::find_if_not(I, E,
|
||||
[](const Iter &Insn) { return Insn->isTransient(); });
|
||||
|
||||
return I;
|
||||
}
|
||||
|
||||
// Find the next real instruction from the current position, looking through
|
||||
// basic block boundaries.
|
||||
static std::pair<Iter, bool> getNextMachineInstr(Iter Position, MachineBasicBlock * Parent) {
|
||||
if (Position == Parent->end()) {
|
||||
do {
|
||||
MachineBasicBlock *Succ = Parent->getNextNode();
|
||||
if (Succ != nullptr && Parent->isSuccessor(Succ)) {
|
||||
Position = Succ->begin();
|
||||
Parent = Succ;
|
||||
} else {
|
||||
return std::make_pair(Position, true);
|
||||
}
|
||||
} while (Parent->empty());
|
||||
}
|
||||
|
||||
Iter Instr = getNextMachineInstrInBB(Position);
|
||||
if (Instr == Parent->end()) {
|
||||
return getNextMachineInstr(Instr, Parent);
|
||||
}
|
||||
return std::make_pair(Instr, false);
|
||||
}
|
||||
|
||||
bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
const MipsSubtarget *STI =
|
||||
&static_cast<const MipsSubtarget &>(MF.getSubtarget());
|
||||
|
||||
// Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
|
||||
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;
|
||||
|
||||
Iter Inst;
|
||||
bool LastInstInFunction =
|
||||
std::next(I) == FI->end() && std::next(FI) == MF.end();
|
||||
if (!LastInstInFunction) {
|
||||
std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI);
|
||||
LastInstInFunction |= Res.second;
|
||||
Inst = Res.first;
|
||||
}
|
||||
|
||||
if (LastInstInFunction || !TII->SafeInForbiddenSlot(*Inst)) {
|
||||
Changed = true;
|
||||
MIBundleBuilder(&*I)
|
||||
.append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
|
||||
NumInsertedNops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
}
|
@ -54,7 +54,7 @@ extern "C" void LLVMInitializeMipsTarget() {
|
||||
PassRegistry *PR = PassRegistry::getPassRegistry();
|
||||
initializeGlobalISel(*PR);
|
||||
initializeMipsDelaySlotFillerPass(*PR);
|
||||
initializeMipsLongBranchPass(*PR);
|
||||
initializeMipsBranchExpansionPass(*PR);
|
||||
}
|
||||
|
||||
static std::string computeDataLayout(const Triple &TT, StringRef CPU,
|
||||
@ -290,12 +290,20 @@ MipsTargetMachine::getTargetTransformInfo(const Function &F) {
|
||||
void MipsPassConfig::addPreEmitPass() {
|
||||
addPass(createMicroMipsSizeReductionPass());
|
||||
|
||||
// The delay slot filler and the long branch passes can potientially create
|
||||
// forbidden slot/ hazards for MIPSR6 which the hazard schedule pass will
|
||||
// fix. Any new pass must come before the hazard schedule pass.
|
||||
// The delay slot filler pass can potientially create forbidden slot hazards
|
||||
// for MIPSR6 and therefore it should go before MipsBranchExpansion pass.
|
||||
addPass(createMipsDelaySlotFillerPass());
|
||||
addPass(createMipsLongBranchPass());
|
||||
addPass(createMipsHazardSchedule());
|
||||
|
||||
// This pass expands branches and takes care about the forbidden slot hazards.
|
||||
// Expanding branches may potentially create forbidden slot hazards for
|
||||
// MIPSR6, and fixing such hazard may potentially break a branch by extending
|
||||
// its offset out of range. That's why this pass combine these two tasks, and
|
||||
// runs them alternately until one of them finishes without any changes. Only
|
||||
// then we can be sure that all branches are expanded properly and no hazards
|
||||
// exists.
|
||||
// Any new pass should go before this pass.
|
||||
addPass(createMipsBranchExpansion());
|
||||
|
||||
addPass(createMipsConstantIslandPass());
|
||||
}
|
||||
|
||||
|
64
test/CodeGen/Mips/branch-relaxation-with-hazard.ll
Normal file
64
test/CodeGen/Mips/branch-relaxation-with-hazard.ll
Normal file
@ -0,0 +1,64 @@
|
||||
; RUN: llc -O0 -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -relocation-model=pic < %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-PIC
|
||||
; RUN: llc -O0 -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -relocation-model=static < %s -o - | FileCheck %s --check-prefixes=CHECK-STATIC
|
||||
|
||||
declare i32 @boo(...)
|
||||
declare i32 @foo(...)
|
||||
|
||||
define i32 @main(i32 signext %argc, i8** %argv) {
|
||||
; CHECK: main:
|
||||
; CHECK: # %bb.1:
|
||||
; CHECK-PIC: addiu
|
||||
; CHECK-PIC: sw
|
||||
; CHECK-PIC: lui
|
||||
; CHECK-PIC: addiu
|
||||
; CHECK-PIC: balc
|
||||
; CHECK-PIC: addu
|
||||
; CHECK-PIC: lw
|
||||
; CHECK-PIC: addiu
|
||||
; CHECK-PIC: jrc
|
||||
; CHECK-PIC: bc
|
||||
; CHECK-PIC: bnezc
|
||||
; CHECK-PIC: nop
|
||||
; CHECK-PIC: bc
|
||||
|
||||
; CHECK-STATIC: bc
|
||||
; CHECK-STATIC: j
|
||||
; CHECK-STATIC: bnezc
|
||||
; CHECK-STATIC: nop
|
||||
; CHECK-STATIC: j
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%argc.addr = alloca i32, align 4
|
||||
%argv.addr = alloca i8**, align 4
|
||||
store i32 0, i32* %retval, align 4
|
||||
store i32 %argc, i32* %argc.addr, align 4
|
||||
store i8** %argv, i8*** %argv.addr, align 4
|
||||
%0 = load i32, i32* %argc.addr, align 4
|
||||
%cmp = icmp sgt i32 %0, 1
|
||||
br i1 %cmp, label %if.then, label %if.end4
|
||||
|
||||
if.then:
|
||||
%1 = load i32, i32* %argc.addr, align 4
|
||||
%cmp1 = icmp sgt i32 %1, 3
|
||||
br i1 %cmp1, label %if.then2, label %if.end
|
||||
|
||||
if.then2:
|
||||
%call = call i32 bitcast (i32 (...)* @boo to i32 ()*)()
|
||||
store i32 %call, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
if.end:
|
||||
call void asm sideeffect ".space 4194228", "~{$1}"()
|
||||
%call3 = call i32 bitcast (i32 (...)* @foo to i32 ()*)()
|
||||
store i32 %call3, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
if.end4:
|
||||
store i32 0, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%2 = load i32, i32* %retval, align 4
|
||||
ret i32 %2
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MIPS
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MIPS
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
--- |
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=R6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=R6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MM
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MMR6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MMR6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -mattr=+micromips -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MIPS64
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MIPS64
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MIPS64
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MIPS64
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=R6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=R6
|
||||
# RUN: llc -mtriple=mips-img-linux-gnu -mcpu=mips32r6 -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MIPS
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -o - %s -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MIPS
|
||||
# RUN: llc -mtriple=mips-mti-linux-gnu -o - %s -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu -mcpu=mips64r5 -mattr=+fp64,+msa %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch | FileCheck %s --check-prefix=MSA
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu -mcpu=mips64r5 -mattr=+fp64,+msa %s -o - -start-before mips-delay-slot-filler -stop-after mips-long-branch -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu -mcpu=mips64r5 -mattr=+fp64,+msa %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion | FileCheck %s --check-prefix=MSA
|
||||
# RUN: llc -mtriple=mips64-mti-linux-gnu -mcpu=mips64r5 -mattr=+fp64,+msa %s -o - -start-before mips-delay-slot-filler -stop-after mips-branch-expansion -relocation-model=pic | FileCheck %s --check-prefix=PIC
|
||||
|
||||
# Test the long branch expansion of various branches
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user