Eliminate nop instruction in input and derive alignment.

Summary:
Nop instructions are primarily used for alignment purposes on the input.
We remove all nops when we build CFG and derive alignment of basic blocks
based on existing alignment and a presence of nops before it. This
will not always work as some basic blocks will be naturally aligned
without necessity for nops. However, it's better than random alignment.
We would also add heuristics for BB alignment based on execution profile.

(cherry picked from FBD2561740)
This commit is contained in:
Maksim Panchenko 2015-10-20 10:51:17 -07:00
parent cd6250d1e3
commit 85b99eb7b7
4 changed files with 41 additions and 16 deletions

View File

@ -93,6 +93,7 @@ public:
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
bool empty() const { return Instructions.empty(); }
MCInst &front() { return Instructions.front(); }
MCInst &back() { return Instructions.back(); }
const MCInst &front() const { return Instructions.front(); }
@ -182,6 +183,11 @@ public:
Instructions.emplace_back(Inst);
}
/// Set minimum alignment for the basic block.
void setAlignment(uint64_t Align) {
Alignment = Align;
}
/// Return required alignment for the block.
uint64_t getAlignment() const {
return Alignment;

View File

@ -91,7 +91,8 @@ void BinaryFunction::print(raw_ostream &OS, bool PrintInstructions) const {
for (auto BB : BasicBlocksLayout) {
OS << BB->getName() << " ("
<< BB->Instructions.size() << " instructions)\n";
<< BB->Instructions.size() << " instructions, align : "
<< BB->getAlignment() << ")\n";
uint64_t BBExecCount = BB->getExecutionCount();
if (BBExecCount != BinaryBasicBlock::COUNT_NO_PROFILE) {
@ -342,12 +343,14 @@ bool BinaryFunction::buildCFG() {
// sorted by offsets.
BinaryBasicBlock *InsertBB{nullptr};
BinaryBasicBlock *PrevBB{nullptr};
bool IsLastInstrNop = false;
for (auto &InstrInfo : Instructions) {
auto LI = Labels.find(InstrInfo.first);
if (LI != Labels.end()) {
// Always create new BB at branch destination.
PrevBB = InsertBB;
InsertBB = addBasicBlock(LI->first, LI->second);
InsertBB = addBasicBlock(LI->first, LI->second,
/* DeriveAlignment = */ IsLastInstrNop);
}
if (!InsertBB) {
// It must be a fallthrough. Create a new block unless we see an
@ -358,10 +361,20 @@ bool BinaryFunction::buildCFG() {
InsertBB = PrevBB;
} else {
InsertBB = addBasicBlock(InstrInfo.first,
BC.Ctx->createTempSymbol("FT", true));
BC.Ctx->createTempSymbol("FT", true),
/* DeriveAlignment = */ IsLastInstrNop);
}
}
// Ignore nops. We use nops to derive alignment of the next basic block.
// It will not always work, as some blocks are naturally aligned, but
// it's just part of heuristic for block alignment.
if (MIA->isNoop(InstrInfo.second)) {
IsLastInstrNop = true;
continue;
}
IsLastInstrNop = false;
InsertBB->addInstruction(InstrInfo.second);
// How well do we detect tail calls here?
@ -416,7 +429,9 @@ bool BinaryFunction::buildCFG() {
}
MCInst &LastInst = BB.back();
if (BB.succ_size() == 0) {
if (BB.empty()) {
IsPrevFT = true;
} else if (BB.succ_size() == 0) {
IsPrevFT = MIA->isTerminator(LastInst) ? false : true;
} else if (BB.succ_size() == 1) {
IsPrevFT = MIA->isConditionalBranch(LastInst) ? true : false;

View File

@ -260,21 +260,23 @@ public:
/// Create a basic block at a given \p Offset in the
/// function and append it to the end of list of blocks.
/// If \p DeriveAlignment is true, set the alignment of the block based
/// on the alignment of the existing offset.
///
/// Returns NULL if basic block already exists at the \p Offset.
BinaryBasicBlock *addBasicBlock(uint64_t Offset, MCSymbol *Label = nullptr) {
BinaryBasicBlock *addBasicBlock(uint64_t Offset, MCSymbol *Label,
bool DeriveAlignment = false) {
assert(!getBasicBlockAtOffset(Offset) && "basic block already exists");
if (!Label)
Label = BC.Ctx->createTempSymbol("BB", true);
BasicBlocks.emplace_back(BinaryBasicBlock(Label, Offset));
return &BasicBlocks.back();
}
auto BB = &BasicBlocks.back();
BinaryBasicBlock *getOrCreateBasicBlockAt(uint64_t Offset,
MCSymbol *Label = nullptr) {
BinaryBasicBlock *BB = getBasicBlockAtOffset(Offset);
if (!BB)
BB = addBasicBlock(Offset, Label);
if (DeriveAlignment) {
uint64_t DerivedAlignment = Offset & (1 + ~Offset);
BB->setAlignment(std::min(DerivedAlignment, uint64_t(16)));
}
return BB;
}

View File

@ -95,8 +95,8 @@ EliminateUnreachable("eliminate-unreachable",
static cl::opt<bool>
ReorderBlocks("reorder-blocks",
cl::desc("redo basic block layout based on profiling data"),
cl::Optional);
cl::desc("redo basic block layout based on profiling data"),
cl::Optional);
static cl::opt<bool>
DumpData("dump-data", cl::desc("dump parsed flo data (debugging)"),
@ -104,11 +104,11 @@ DumpData("dump-data", cl::desc("dump parsed flo data (debugging)"),
static cl::opt<bool>
DumpFunctions("dump-functions", cl::desc("dump parsed functions (debugging)"),
cl::Hidden);
cl::Hidden);
static cl::opt<bool>
DumpLayout("dump-layout", cl::desc("dump parsed flo data (debugging)"),
cl::Hidden);
cl::Hidden);
} // namespace opts
static StringRef ToolName;
@ -588,6 +588,8 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
// Emit code.
for (auto BB : Function.layout()) {
if (BB->getAlignment() > 1)
Streamer->EmitCodeAlignment(BB->getAlignment());
Streamer->EmitLabel(BB->getLabel());
for (const auto &Instr : *BB) {
Streamer->EmitInstruction(Instr, *BC->STI);