#include "MSP430.h"
#include "MSP430InstrInfo.h"
#include "MSP430Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
#define DEBUG_TYPE "msp430-branch-select"
static cl::opt<bool>
BranchSelectEnabled("msp430-branch-select", cl::Hidden, cl::init(true),
cl::desc("Expand out of range branches"));
STATISTIC(NumSplit, "Number of machine basic blocks split");
STATISTIC(NumExpanded, "Number of branches expanded to long format");
namespace {
class MSP430BSel : public MachineFunctionPass {
typedef SmallVector<int, 16> OffsetVector;
MachineFunction *MF;
const MSP430InstrInfo *TII;
unsigned measureFunction(OffsetVector &BlockOffsets,
MachineBasicBlock *FromBB = nullptr);
bool expandBranches(OffsetVector &BlockOffsets);
public:
static char ID;
MSP430BSel() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
StringRef getPassName() const override { return "MSP430 Branch Selector"; }
};
char MSP430BSel::ID = 0;
}
static bool isInRage(int DistanceInBytes) {
const int WordSize = 2;
assert((DistanceInBytes % WordSize == 0) &&
"Branch offset should be word aligned!");
int Words = DistanceInBytes / WordSize;
return isInt<10>(Words);
}
unsigned MSP430BSel::measureFunction(OffsetVector &BlockOffsets,
MachineBasicBlock *FromBB) {
MF->RenumberBlocks(FromBB);
MachineFunction::iterator Begin;
if (FromBB == nullptr) {
Begin = MF->begin();
} else {
Begin = FromBB->getIterator();
}
BlockOffsets.resize(MF->getNumBlockIDs());
unsigned TotalSize = BlockOffsets[Begin->getNumber()];
for (auto &MBB : make_range(Begin, MF->end())) {
BlockOffsets[MBB.getNumber()] = TotalSize;
for (MachineInstr &MI : MBB) {
TotalSize += TII->getInstSizeInBytes(MI);
}
}
return TotalSize;
}
bool MSP430BSel::expandBranches(OffsetVector &BlockOffsets) {
bool MadeChange = false;
for (auto MBB = MF->begin(), E = MF->end(); MBB != E; ++MBB) {
unsigned MBBStartOffset = 0;
for (auto MI = MBB->begin(), EE = MBB->end(); MI != EE; ++MI) {
MBBStartOffset += TII->getInstSizeInBytes(*MI);
if (MI->getOpcode() != MSP430::JCC && MI->getOpcode() != MSP430::JMP) {
continue;
}
MachineBasicBlock *DestBB = MI->getOperand(0).getMBB();
int BlockDistance =
BlockOffsets[DestBB->getNumber()] - BlockOffsets[MBB->getNumber()];
int BranchDistance = BlockDistance - MBBStartOffset;
if (isInRage(BranchDistance)) {
continue;
}
LLVM_DEBUG(dbgs() << " Found a branch that needs expanding, "
<< printMBBReference(*DestBB) << ", Distance "
<< BranchDistance << "\n");
if (MI->getOpcode() == MSP430::JCC && std::next(MI) != EE) {
LLVM_DEBUG(dbgs() << " Found a basic block that needs to be split, "
<< printMBBReference(*MBB) << "\n");
MachineBasicBlock *NewBB =
MF->CreateMachineBasicBlock(MBB->getBasicBlock());
MF->insert(std::next(MBB), NewBB);
NewBB->splice(NewBB->end(), &*MBB, std::next(MI), MBB->end());
for (MachineBasicBlock *Succ : MBB->successors()) {
if (Succ == DestBB) {
continue;
}
MBB->replaceSuccessor(Succ, NewBB);
NewBB->addSuccessor(Succ);
}
measureFunction(BlockOffsets, &*MBB);
++NumSplit;
return true;
}
MachineInstr &OldBranch = *MI;
DebugLoc dl = OldBranch.getDebugLoc();
int InstrSizeDiff = -TII->getInstSizeInBytes(OldBranch);
if (MI->getOpcode() == MSP430::JCC) {
MachineBasicBlock *NextMBB = &*std::next(MBB);
assert(MBB->isSuccessor(NextMBB) &&
"This block must have a layout successor!");
SmallVector<MachineOperand, 1> Cond;
Cond.push_back(MI->getOperand(1));
TII->reverseBranchCondition(Cond);
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::JCC))
.addMBB(NextMBB)
.add(Cond[0]);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
++MI;
}
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::Bi)).addMBB(DestBB);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
OldBranch.eraseFromParent();
for (int i = MBB->getNumber() + 1, e = BlockOffsets.size(); i < e; ++i) {
BlockOffsets[i] += InstrSizeDiff;
}
MBBStartOffset += InstrSizeDiff;
++NumExpanded;
MadeChange = true;
}
}
return MadeChange;
}
bool MSP430BSel::runOnMachineFunction(MachineFunction &mf) {
MF = &mf;
TII = static_cast<const MSP430InstrInfo *>(MF->getSubtarget().getInstrInfo());
if (!BranchSelectEnabled)
return false;
LLVM_DEBUG(dbgs() << "\n********** " << getPassName() << " **********\n");
OffsetVector BlockOffsets;
unsigned FunctionSize = measureFunction(BlockOffsets);
if (isInRage(FunctionSize)) {
return false;
}
bool MadeChange = false;
while (expandBranches(BlockOffsets))
MadeChange = true;
return MadeChange;
}
FunctionPass *llvm::createMSP430BranchSelectionPass() {
return new MSP430BSel();
}