mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-11 13:46:13 +00:00
Added (preliminary) branch shortening capability to constantpool island pass.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33497 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6318ffd736
commit
af5cbcb809
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#define DEBUG_TYPE "arm-cp-islands"
|
#define DEBUG_TYPE "arm-cp-islands"
|
||||||
#include "ARM.h"
|
#include "ARM.h"
|
||||||
|
#include "ARMMachineFunctionInfo.h"
|
||||||
#include "ARMInstrInfo.h"
|
#include "ARMInstrInfo.h"
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||||
@ -72,13 +73,30 @@ namespace {
|
|||||||
/// constant pools and their max displacement.
|
/// constant pools and their max displacement.
|
||||||
std::vector<CPUser> CPUsers;
|
std::vector<CPUser> CPUsers;
|
||||||
|
|
||||||
|
/// ImmBranch - One per immediate branch, keeping the machine instruction
|
||||||
|
/// pointer, conditional or unconditional, the max displacement,
|
||||||
|
/// and (if isCond is true) the corresponding unconditional branch
|
||||||
|
/// opcode.
|
||||||
|
struct ImmBranch {
|
||||||
|
MachineInstr *MI;
|
||||||
|
bool isCond;
|
||||||
|
int UncondBr;
|
||||||
|
unsigned MaxDisp;
|
||||||
|
ImmBranch(MachineInstr *mi, bool cond, int ubr, unsigned maxdisp)
|
||||||
|
: MI(mi), isCond(cond), UncondBr(ubr), MaxDisp(maxdisp) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Branches - Keep track of all the immediate branche instructions.
|
||||||
|
///
|
||||||
|
std::vector<ImmBranch> ImmBranches;
|
||||||
|
|
||||||
const TargetInstrInfo *TII;
|
const TargetInstrInfo *TII;
|
||||||
const TargetAsmInfo *TAI;
|
const TargetAsmInfo *TAI;
|
||||||
public:
|
public:
|
||||||
virtual bool runOnMachineFunction(MachineFunction &Fn);
|
virtual bool runOnMachineFunction(MachineFunction &Fn);
|
||||||
|
|
||||||
virtual const char *getPassName() const {
|
virtual const char *getPassName() const {
|
||||||
return "ARM constant island placement pass";
|
return "ARM constant island placement and branch shortening pass";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -87,16 +105,18 @@ namespace {
|
|||||||
void InitialFunctionScan(MachineFunction &Fn,
|
void InitialFunctionScan(MachineFunction &Fn,
|
||||||
const std::vector<MachineInstr*> &CPEMIs);
|
const std::vector<MachineInstr*> &CPEMIs);
|
||||||
void SplitBlockBeforeInstr(MachineInstr *MI);
|
void SplitBlockBeforeInstr(MachineInstr *MI);
|
||||||
bool HandleConstantPoolUser(MachineFunction &Fn, CPUser &U);
|
|
||||||
void UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB);
|
void UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB);
|
||||||
|
bool HandleConstantPoolUser(MachineFunction &Fn, CPUser &U);
|
||||||
|
bool ShortenImmediateBranch(MachineFunction &Fn, ImmBranch &Br);
|
||||||
|
|
||||||
unsigned GetInstSize(MachineInstr *MI) const;
|
unsigned GetInstSize(MachineInstr *MI) const;
|
||||||
unsigned GetOffsetOf(MachineInstr *MI) const;
|
unsigned GetOffsetOf(MachineInstr *MI) const;
|
||||||
|
unsigned GetOffsetOf(MachineBasicBlock *MBB) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// createARMLoadStoreOptimizationPass - returns an instance of the load / store
|
/// createARMConstantIslandPass - returns an instance of the constpool
|
||||||
/// optimization pass.
|
/// island pass.
|
||||||
FunctionPass *llvm::createARMConstantIslandPass() {
|
FunctionPass *llvm::createARMConstantIslandPass() {
|
||||||
return new ARMConstantIslands();
|
return new ARMConstantIslands();
|
||||||
}
|
}
|
||||||
@ -133,11 +153,14 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &Fn) {
|
|||||||
MadeChange = false;
|
MadeChange = false;
|
||||||
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i)
|
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i)
|
||||||
MadeChange |= HandleConstantPoolUser(Fn, CPUsers[i]);
|
MadeChange |= HandleConstantPoolUser(Fn, CPUsers[i]);
|
||||||
|
for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i)
|
||||||
|
MadeChange |= ShortenImmediateBranch(Fn, ImmBranches[i]);
|
||||||
} while (MadeChange);
|
} while (MadeChange);
|
||||||
|
|
||||||
BBSizes.clear();
|
BBSizes.clear();
|
||||||
WaterList.clear();
|
WaterList.clear();
|
||||||
CPUsers.clear();
|
CPUsers.clear();
|
||||||
|
ImmBranches.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -208,6 +231,37 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn,
|
|||||||
// Add instruction size to MBBSize.
|
// Add instruction size to MBBSize.
|
||||||
MBBSize += GetInstSize(I);
|
MBBSize += GetInstSize(I);
|
||||||
|
|
||||||
|
int Opc = I->getOpcode();
|
||||||
|
if (TII->isBranch(Opc)) {
|
||||||
|
bool isCond = false;
|
||||||
|
unsigned Bits = 0;
|
||||||
|
unsigned Scale = 1;
|
||||||
|
int UOpc = Opc;
|
||||||
|
switch (Opc) {
|
||||||
|
default: break; // Ignore JT branches
|
||||||
|
case ARM::Bcc:
|
||||||
|
isCond = true;
|
||||||
|
UOpc = ARM::B;
|
||||||
|
// Fallthrough
|
||||||
|
case ARM::B:
|
||||||
|
Bits = 24;
|
||||||
|
Scale = 4;
|
||||||
|
break;
|
||||||
|
case ARM::tBcc:
|
||||||
|
isCond = true;
|
||||||
|
UOpc = ARM::tB;
|
||||||
|
Bits = 8;
|
||||||
|
Scale = 2;
|
||||||
|
break;
|
||||||
|
case ARM::tB:
|
||||||
|
Bits = 11;
|
||||||
|
Scale = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsigned MaxDisp = (1 << (Bits-1)) * Scale;
|
||||||
|
ImmBranches.push_back(ImmBranch(I, isCond, UOpc, MaxDisp));
|
||||||
|
}
|
||||||
|
|
||||||
// Scan the instructions for constant pool operands.
|
// Scan the instructions for constant pool operands.
|
||||||
for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op)
|
for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op)
|
||||||
if (I->getOperand(op).isConstantPoolIndex()) {
|
if (I->getOperand(op).isConstantPoolIndex()) {
|
||||||
@ -336,6 +390,18 @@ unsigned ARMConstantIslands::GetOffsetOf(MachineInstr *MI) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GetOffsetOf - Return the current offset of the specified machine BB
|
||||||
|
/// from the start of the function. This offset changes as stuff is moved
|
||||||
|
/// around inside the function.
|
||||||
|
unsigned ARMConstantIslands::GetOffsetOf(MachineBasicBlock *MBB) const {
|
||||||
|
// Sum block sizes before MBB.
|
||||||
|
unsigned Offset = 0;
|
||||||
|
for (unsigned BB = 0, e = MBB->getNumber(); BB != e; ++BB)
|
||||||
|
Offset += BBSizes[BB];
|
||||||
|
|
||||||
|
return Offset;
|
||||||
|
}
|
||||||
|
|
||||||
/// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB
|
/// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB
|
||||||
/// ID.
|
/// ID.
|
||||||
static bool CompareMBBNumbers(const MachineBasicBlock *LHS,
|
static bool CompareMBBNumbers(const MachineBasicBlock *LHS,
|
||||||
@ -368,6 +434,8 @@ void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) {
|
|||||||
/// account for this change.
|
/// account for this change.
|
||||||
void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
|
void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
|
||||||
MachineBasicBlock *OrigBB = MI->getParent();
|
MachineBasicBlock *OrigBB = MI->getParent();
|
||||||
|
const ARMFunctionInfo *AFI = OrigBB->getParent()->getInfo<ARMFunctionInfo>();
|
||||||
|
bool isThumb = AFI->isThumbFunction();
|
||||||
|
|
||||||
// Create a new MBB for the code after the OrigBB.
|
// Create a new MBB for the code after the OrigBB.
|
||||||
MachineBasicBlock *NewBB = new MachineBasicBlock(OrigBB->getBasicBlock());
|
MachineBasicBlock *NewBB = new MachineBasicBlock(OrigBB->getBasicBlock());
|
||||||
@ -378,7 +446,7 @@ void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
|
|||||||
NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end());
|
NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end());
|
||||||
|
|
||||||
// Add an unconditional branch from OrigBB to NewBB.
|
// Add an unconditional branch from OrigBB to NewBB.
|
||||||
BuildMI(OrigBB, TII->get(ARM::B)).addMBB(NewBB);
|
BuildMI(OrigBB, TII->get(isThumb ? ARM::tB : ARM::B)).addMBB(NewBB);
|
||||||
NumSplit++;
|
NumSplit++;
|
||||||
|
|
||||||
// Update the CFG. All succs of OrigBB are now succs of NewBB.
|
// Update the CFG. All succs of OrigBB are now succs of NewBB.
|
||||||
@ -409,8 +477,8 @@ void ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
|
|||||||
BBSizes[NewBB->getNumber()] = NewBBSize;
|
BBSizes[NewBB->getNumber()] = NewBBSize;
|
||||||
|
|
||||||
// We removed instructions from UserMBB, subtract that off from its size.
|
// We removed instructions from UserMBB, subtract that off from its size.
|
||||||
// Add 4 to the block to count the unconditional branch we added to it.
|
// Add 2 or 4 to the block to count the unconditional branch we added to it.
|
||||||
BBSizes[OrigBB->getNumber()] -= NewBBSize-4;
|
BBSizes[OrigBB->getNumber()] -= NewBBSize - (isThumb ? 2 : 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HandleConstantPoolUser - Analyze the specified user, checking to see if it
|
/// HandleConstantPoolUser - Analyze the specified user, checking to see if it
|
||||||
@ -491,3 +559,58 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &Fn, CPUser &U){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ARMConstantIslands::ShortenImmediateBranch(MachineFunction &Fn, ImmBranch &Br) {
|
||||||
|
MachineInstr *MI = Br.MI;
|
||||||
|
MachineBasicBlock *DestBB = MI->getOperand(0).getMachineBasicBlock();
|
||||||
|
|
||||||
|
unsigned BrOffset = GetOffsetOf(MI);
|
||||||
|
unsigned DestOffset = GetOffsetOf(DestBB);
|
||||||
|
|
||||||
|
// Check to see if the destination BB is in range.
|
||||||
|
if (BrOffset < DestOffset) {
|
||||||
|
if (DestOffset - BrOffset < Br.MaxDisp)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (BrOffset - DestOffset <= Br.MaxDisp)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Br.isCond) {
|
||||||
|
// Unconditional branch. We have to insert a branch somewhere to perform
|
||||||
|
// a two level branch (branch to branch). FIXME: not yet implemented.
|
||||||
|
assert(false && "Can't handle unconditional branch yet!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, add a unconditional branch to the destination and
|
||||||
|
// invert the branch condition to jump over it:
|
||||||
|
// blt L1
|
||||||
|
// =>
|
||||||
|
// bge L2
|
||||||
|
// b L1
|
||||||
|
// L2:
|
||||||
|
ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(1).getImmedValue();
|
||||||
|
CC = ARMCC::getOppositeCondition(CC);
|
||||||
|
|
||||||
|
// If the branch is at the end of its MBB and that has a fall-through block,
|
||||||
|
// direct the updated conditional branch to the fall-through block. Otherwise,
|
||||||
|
// split the MBB before the next instruction.
|
||||||
|
MachineBasicBlock *MBB = MI->getParent();
|
||||||
|
if (&MBB->back() != MI || !BBHasFallthrough(MBB))
|
||||||
|
SplitBlockBeforeInstr(MI);
|
||||||
|
MachineBasicBlock *NextBB = next(MachineFunction::iterator(MBB));
|
||||||
|
|
||||||
|
// Insert a unconditional branch and replace the conditional branch.
|
||||||
|
// Also update the ImmBranch as well as adding a new entry for the new branch.
|
||||||
|
BuildMI(MBB, TII->get(MI->getOpcode())).addMBB(NextBB).addImm((unsigned)CC);
|
||||||
|
Br.MI = &MBB->back();
|
||||||
|
BuildMI(MBB, TII->get(Br.UncondBr)).addMBB(DestBB);
|
||||||
|
unsigned MaxDisp = (Br.UncondBr == ARM::tB) ? (1<<10)*2 : (1<<23)*4;
|
||||||
|
ImmBranches.push_back(ImmBranch(&MBB->back(), false, Br.UncondBr, MaxDisp));
|
||||||
|
MI->eraseFromParent();
|
||||||
|
|
||||||
|
// Increase the size of MBB to account for the new unconditional branch.
|
||||||
|
BBSizes[MBB->getNumber()] += GetInstSize(&MBB->back());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user