[BOLT] Limited "support" for AVX-512

Summary:
In relocation mode trap on entry to any function that has AVX-512
instructions. This is controlled by "-trap-avx512" option which is on
by default. If the option is disabled and AVX-512 instruction is seen
in relocation mode, then we abort while re-writing the binary.

(cherry picked from FBD6893165)
This commit is contained in:
Maksim Panchenko
2018-02-02 16:07:11 -08:00
parent 8a5a30156e
commit 1298d99a41
5 changed files with 69 additions and 5 deletions

View File

@@ -154,6 +154,9 @@ public:
/// True if the binary requires immediate relocation processing.
bool RequiresZNow{false};
/// List of functions that always trap.
std::vector<const BinaryFunction *> TrappedFunctions;
BinaryContext(std::unique_ptr<MCContext> Ctx,
std::unique_ptr<DWARFContext> DwCtx,
std::unique_ptr<Triple> TheTriple,

View File

@@ -136,6 +136,15 @@ TimeBuild("time-build",
cl::Hidden,
cl::cat(BoltCategory));
cl::opt<bool>
TrapOnAVX512("trap-avx512",
cl::desc("in relocation mode trap upon entry to any function that uses "
"AVX-512 instructions (on by default)"),
cl::init(true),
cl::ZeroOrMore,
cl::Hidden,
cl::cat(BoltCategory));
bool shouldPrint(const BinaryFunction &Function) {
if (PrintOnly.empty() && PrintOnlyRegex.empty())
return true;
@@ -1005,7 +1014,14 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
<< Twine::utohexstr(Offset) << " (address 0x"
<< Twine::utohexstr(AbsoluteInstrAddr) << ") in function "
<< *this << '\n';
IsSimple = false;
// Some AVX-512 instructions could not be disassembled at all.
if (BC.HasRelocations && opts::TrapOnAVX512 &&
BC.TheTriple->getArch() == llvm::Triple::x86_64) {
setTrapOnEntry();
BC.TrappedFunctions.push_back(this);
} else {
IsSimple = false;
}
}
break;
}
@@ -1018,7 +1034,13 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
<< Twine::utohexstr(Offset) << ". Disassembly could be wrong."
" Skipping further processing.\n";
}
IsSimple = false;
if (BC.HasRelocations && opts::TrapOnAVX512) {
setTrapOnEntry();
BC.TrappedFunctions.push_back(this);
} else {
IsSimple = false;
}
break;
}
@@ -2168,6 +2190,20 @@ void BinaryFunction::emitBodyRaw(MCStreamer *Streamer) {
}
}
void BinaryFunction::setTrapOnEntry() {
clearList(Instructions);
clearList(IgnoredBranches);
clearList(TakenBranches);
for (const auto EntryOffset : EntryOffsets) {
MCInst TrapInstr;
BC.MIA->createTrap(TrapInstr);
addInstruction(EntryOffset, std::move(TrapInstr));
}
TrapsOnEntry = true;
}
void BinaryFunction::addConstantIslandDependency(BinaryFunction *OtherBF,
MCSymbol *HotSymbol,
MCSymbol *ColdSymbol) {

View File

@@ -305,6 +305,9 @@ private:
/// for ICF optimization without relocations.
bool IsFolded{false};
/// Execution halts whenever this function is entered.
bool TrapsOnEntry{false};
/// The address for the code for this function in codegen memory.
uint64_t ImageAddress{0};
@@ -814,8 +817,9 @@ private:
friend class BinaryContext;
/// Creation should be handled by RewriteInstance::createBinaryFunction().
BinaryFunction(const std::string &Name, BinarySection &Section, uint64_t Address,
uint64_t Size, BinaryContext &BC, bool IsSimple) :
BinaryFunction(const std::string &Name, BinarySection &Section,
uint64_t Address, uint64_t Size, BinaryContext &BC,
bool IsSimple) :
Names({Name}), Section(Section), Address(Address),
Size(Size), BC(BC), IsSimple(IsSimple),
CodeSectionName(".local.text." + Name),
@@ -1292,6 +1296,15 @@ public:
return StringRef(ColdCodeSectionName);
}
/// Return true iif the function will halt execution on entry.
bool trapsOnEntry() const {
return TrapsOnEntry;
}
/// Make the function always trap on entry. Other than the trap instruction,
/// the function body will be empty.
void setTrapOnEntry();
/// Return true if the function could be correctly processed.
bool isSimple() const {
return IsSimple;

View File

@@ -1512,6 +1512,18 @@ PrintProgramStats::runOnFunctions(BinaryContext &BC,
outs() << "\n";
}
}
if (!BC.TrappedFunctions.empty()) {
errs() << "BOLT-WARNING: " << BC.TrappedFunctions.size()
<< " functions will trap on entry";
if (opts::Verbosity >= 1) {
errs() << ".\n";
for (const auto *Function : BC.TrappedFunctions)
errs() << " " << *Function << '\n';
} else {
errs() << " (use -v=1 to see the list).\n";
}
}
}
void InstructionLowering::runOnFunctions(

View File

@@ -2162,7 +2162,7 @@ void RewriteInstance::disassembleFunctions() {
BC->InterproceduralReferences.clear();
// Fill in CFI information for this function
if (Function.isSimple()) {
if (Function.isSimple() && !Function.trapsOnEntry()) {
if (!CFIRdWrt->fillCFIInfoFor(Function)) {
errs() << "BOLT-ERROR: unable to fill CFI for function "
<< Function << ".\n";