[BOLT] Don't terminate on trap instruction for Linux kernel (#87021)
Under normal circumstances, we terminate basic blocks on a trap instruction. However, Linux kernel may resume execution after hitting a trap (ud2 on x86). Thus, we introduce "--terminal-trap" option that will specify if the trap instruction should terminate the control flow. The option is on by default except for the Linux kernel mode when it's off.
This commit is contained in:
parent
7467dc188a
commit
7de82ca369
@ -533,9 +533,7 @@ public:
|
||||
return Analysis->isReturn(Inst);
|
||||
}
|
||||
|
||||
virtual bool isTerminator(const MCInst &Inst) const {
|
||||
return Analysis->isTerminator(Inst);
|
||||
}
|
||||
virtual bool isTerminator(const MCInst &Inst) const;
|
||||
|
||||
virtual bool isNoop(const MCInst &Inst) const {
|
||||
llvm_unreachable("not implemented");
|
||||
|
@ -12,12 +12,14 @@
|
||||
|
||||
#include "bolt/Core/MCPlusBuilder.h"
|
||||
#include "bolt/Core/MCPlus.h"
|
||||
#include "bolt/Utils/CommandLineOpts.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstrAnalysis.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <cstdint>
|
||||
#include <queue>
|
||||
@ -28,6 +30,13 @@ using namespace llvm;
|
||||
using namespace bolt;
|
||||
using namespace MCPlus;
|
||||
|
||||
namespace opts {
|
||||
cl::opt<bool>
|
||||
TerminalTrap("terminal-trap",
|
||||
cl::desc("Assume that execution stops at trap instruction"),
|
||||
cl::init(true), cl::Hidden, cl::cat(BoltCategory));
|
||||
}
|
||||
|
||||
bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B,
|
||||
CompFuncTy Comp) const {
|
||||
if (A.getOpcode() != B.getOpcode())
|
||||
@ -121,6 +130,11 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B,
|
||||
llvm_unreachable("target-specific expressions are unsupported");
|
||||
}
|
||||
|
||||
bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
|
||||
return Analysis->isTerminator(Inst) ||
|
||||
(opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap());
|
||||
}
|
||||
|
||||
void MCPlusBuilder::setTailCall(MCInst &Inst) const {
|
||||
assert(!hasAnnotation(Inst, MCAnnotation::kTailCall));
|
||||
setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true);
|
||||
|
@ -84,6 +84,7 @@ extern cl::opt<JumpTableSupportLevel> JumpTables;
|
||||
extern cl::opt<bool> KeepNops;
|
||||
extern cl::list<std::string> ReorderData;
|
||||
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
|
||||
extern cl::opt<bool> TerminalTrap;
|
||||
extern cl::opt<bool> TimeBuild;
|
||||
|
||||
cl::opt<bool> AllowStripped("allow-stripped",
|
||||
@ -2033,8 +2034,14 @@ void RewriteInstance::adjustCommandLineOptions() {
|
||||
if (opts::Lite)
|
||||
BC->outs() << "BOLT-INFO: enabling lite mode\n";
|
||||
|
||||
if (BC->IsLinuxKernel && !opts::KeepNops.getNumOccurrences())
|
||||
opts::KeepNops = true;
|
||||
if (BC->IsLinuxKernel) {
|
||||
if (!opts::KeepNops.getNumOccurrences())
|
||||
opts::KeepNops = true;
|
||||
|
||||
// Linux kernel may resume execution after a trap instruction in some cases.
|
||||
if (!opts::TerminalTrap.getNumOccurrences())
|
||||
opts::TerminalTrap = false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -211,13 +211,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: For compatibility with old LLVM only!
|
||||
bool isTerminator(const MCInst &Inst) const override {
|
||||
unsigned Opcode = Inst.getOpcode();
|
||||
return Info->get(Opcode).isTerminator() || X86::isUD1(Opcode) ||
|
||||
X86::isUD2(Opcode);
|
||||
}
|
||||
|
||||
bool isIndirectCall(const MCInst &Inst) const override {
|
||||
return isCall(Inst) &&
|
||||
((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(0).isReg());
|
||||
|
@ -40,6 +40,10 @@ _start:
|
||||
# CHECK-REOPT-SAME: BugEntry: 2
|
||||
|
||||
ret
|
||||
## The return instruction is reachable only via preceding ud2. Test that it is
|
||||
## treated as a reachable instruction in the Linux kernel mode.
|
||||
|
||||
# CHECK-REOPT-NEXT: ret
|
||||
.size _start, .-_start
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user