forked from OSchip/llvm-project
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:
parent
cd6250d1e3
commit
85b99eb7b7
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue