llvm/lib/Target/MSP430/MSP430BranchSelector.cpp
Chandler Carruth 6b547686c5 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351636 91177308-0d34-0410-b5e6-96231b3b80d8
2019-01-19 08:50:56 +00:00

257 lines
8.6 KiB
C++

//===-- MSP430BranchSelector.cpp - Emit long conditional branches ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 10 bits of displacement to reach their
// target basic block. It does this in two passes; a calculation of basic block
// positions pass, and a branch pseudo op to machine branch opcode pass. This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//
#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/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) {
// According to CC430 Family User's Guide, Section 4.5.1.3, branch
// instructions have the signed 10-bit word offset field, so first we need to
// convert the distance from bytes to words, then check if it fits in 10-bit
// signed integer.
const int WordSize = 2;
assert((DistanceInBytes % WordSize == 0) &&
"Branch offset should be word aligned!");
int Words = DistanceInBytes / WordSize;
return isInt<10>(Words);
}
/// Measure each basic block, fill the BlockOffsets, and return the size of
/// the function, starting with BB
unsigned MSP430BSel::measureFunction(OffsetVector &BlockOffsets,
MachineBasicBlock *FromBB) {
// Give the blocks of the function a dense, in-order, numbering.
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;
}
/// Do expand branches and split the basic blocks if necessary.
/// Returns true if made any change.
bool MSP430BSel::expandBranches(OffsetVector &BlockOffsets) {
// For each conditional branch, if the offset to its destination is larger
// than the offset field allows, transform it into a long branch sequence
// like this:
// short branch:
// bCC MBB
// long branch:
// b!CC $PC+6
// b MBB
//
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 this instruction is not a short branch then skip it.
if (MI->getOpcode() != MSP430::JCC && MI->getOpcode() != MSP430::JMP) {
continue;
}
MachineBasicBlock *DestBB = MI->getOperand(0).getMBB();
// Determine the distance from the current branch to the destination
// block. MBBStartOffset already includes the size of the current branch
// instruction.
int BlockDistance =
BlockOffsets[DestBB->getNumber()] - BlockOffsets[MBB->getNumber()];
int BranchDistance = BlockDistance - MBBStartOffset;
// If this branch is in range, ignore it.
if (isInRage(BranchDistance)) {
continue;
}
LLVM_DEBUG(dbgs() << " Found a branch that needs expanding, "
<< printMBBReference(*DestBB) << ", Distance "
<< BranchDistance << "\n");
// If JCC is not the last instruction we need to split the MBB.
if (MI->getOpcode() == MSP430::JCC && std::next(MI) != EE) {
LLVM_DEBUG(dbgs() << " Found a basic block that needs to be split, "
<< printMBBReference(*MBB) << "\n");
// Create a new basic block.
MachineBasicBlock *NewBB =
MF->CreateMachineBasicBlock(MBB->getBasicBlock());
MF->insert(std::next(MBB), NewBB);
// Splice the instructions following MI over to the NewBB.
NewBB->splice(NewBB->end(), &*MBB, std::next(MI), MBB->end());
// Update the successor lists.
for (MachineBasicBlock *Succ : MBB->successors()) {
if (Succ == DestBB) {
continue;
}
MBB->replaceSuccessor(Succ, NewBB);
NewBB->addSuccessor(Succ);
}
// We introduced a new MBB so all following blocks should be numbered
// and measured again.
measureFunction(BlockOffsets, &*MBB);
++NumSplit;
// It may be not necessary to start all over at this point, but it's
// safer do this anyway.
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!");
// The BCC operands are:
// 0. Target MBB
// 1. MSP430 branch predicate
SmallVector<MachineOperand, 1> Cond;
Cond.push_back(MI->getOperand(1));
// Jump over the long branch on the opposite condition
TII->reverseBranchCondition(Cond);
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::JCC))
.addMBB(NextMBB)
.add(Cond[0]);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
++MI;
}
// Unconditional branch to the real destination.
MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::Bi)).addMBB(DestBB);
InstrSizeDiff += TII->getInstSizeInBytes(*MI);
// Remove the old branch from the function.
OldBranch.eraseFromParent();
// The size of a new instruction is different from the old one, so we need
// to correct all block offsets.
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 the pass is disabled, just bail early.
if (!BranchSelectEnabled)
return false;
LLVM_DEBUG(dbgs() << "\n********** " << getPassName() << " **********\n");
// BlockOffsets - Contains the distance from the beginning of the function to
// the beginning of each basic block.
OffsetVector BlockOffsets;
unsigned FunctionSize = measureFunction(BlockOffsets);
// If the entire function is smaller than the displacement of a branch field,
// we know we don't need to expand any branches in this
// function. This is a common case.
if (isInRage(FunctionSize)) {
return false;
}
// Iteratively expand branches until we reach a fixed point.
bool MadeChange = false;
while (expandBranches(BlockOffsets))
MadeChange = true;
return MadeChange;
}
/// Returns an instance of the Branch Selection Pass
FunctionPass *llvm::createMSP430BranchSelectionPass() {
return new MSP430BSel();
}