diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 5a8a4f6e391c9dcac77e53d033f4184f1e4f0258..2e167ffb29091cec2eace1c3302ef041d7ec49fc 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -579,6 +579,10 @@ public: return false; } + /// Return true if the hlt instruction under the x86, otherwise, default to + /// false. + virtual bool isX86HLT(const MCInst &Inst) const { return false; } + /// Return the width, in bytes, of the memory access performed by \p Inst, if /// this is a pop instruction. Return zero otherwise. virtual int getPopSize(const MCInst &Inst) const { diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp index 5d25a514862af4e182c5adb83612241a213ca748..778528d251b6b83980654929c0c456f4c848be46 100644 --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -31,6 +31,11 @@ using namespace bolt; using namespace MCPlus; namespace opts { +cl::opt + TerminalHLT("terminal-x86-hlt", + cl::desc("Assume that execution stops at x86 HLT instruction"), + cl::init(true), cl::Hidden, cl::cat(BoltCategory)); + cl::opt TerminalTrap("terminal-trap", cl::desc("Assume that execution stops at trap instruction"), @@ -131,8 +136,13 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B, } bool MCPlusBuilder::isTerminator(const MCInst &Inst) const { - return Analysis->isTerminator(Inst) || - (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()); + if (isX86HLT(Inst)) + return opts::TerminalHLT; + + if (Info->get(Inst.getOpcode()).isTrap()) + return opts::TerminalTrap; + + return Analysis->isTerminator(Inst); } void MCPlusBuilder::setTailCall(MCInst &Inst) const { diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 43d5c0cbcdf7e28efd20170631712284fbe7013f..0c24ec652ecd3b01031fbe24e67f5791eac005bf 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -83,6 +83,7 @@ extern cl::opt KeepNops; extern cl::opt Lite; extern cl::list ReorderData; extern cl::opt ReorderFunctions; +extern cl::opt TerminalHLT; extern cl::opt TerminalTrap; extern cl::opt TimeBuild; extern cl::opt TimeRewrite; @@ -2141,7 +2142,9 @@ void RewriteInstance::adjustCommandLineOptions() { if (!opts::KeepNops.getNumOccurrences()) opts::KeepNops = true; - // Linux kernel may resume execution after a trap instruction in some cases. + // Linux kernel may resume execution after a trap or x86 HLT instruction. + if (!opts::TerminalHLT.getNumOccurrences()) + opts::TerminalHLT = false; if (!opts::TerminalTrap.getNumOccurrences()) opts::TerminalTrap = false; } diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 9b51ab0763e3500a3e52c50d013554efaa63f1ad..cd6172f2b0e9db7ed937a30b7df0eee7fd1bde40 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -224,6 +224,10 @@ public: return Inst.getOpcode() == X86::ENDBR32 || Inst.getOpcode() == X86::ENDBR64; } + bool isX86HLT(const MCInst &Inst) const override { + return Inst.getOpcode() == X86::HLT; + } + int getPopSize(const MCInst &Inst) const override { switch (Inst.getOpcode()) { case X86::POP16r: diff --git a/bolt/test/X86/hlt-terminator.s b/bolt/test/X86/hlt-terminator.s new file mode 100644 index 0000000000000000000000000000000000000000..3f67182fdf4320694d32258d2f24786d17d81528 --- /dev/null +++ b/bolt/test/X86/hlt-terminator.s @@ -0,0 +1,24 @@ +## Check that HLT instruction is handled differently depending on the flags. +## It's a terminator in the user-level code, but the execution can resume in +## ring 0. + +# RUN: %clang %cflags %s -static -o %t.exe -nostdlib +# RUN: llvm-bolt %t.exe --print-cfg --print-only=main --terminal-x86-hlt=0 \ +# RUN: -o %t.ring0 2>&1 | FileCheck %s --check-prefix=CHECK-RING0 +# RUN: llvm-bolt %t.exe --print-cfg --print-only=main \ +# RUN: -o %t.ring3 2>&1 | FileCheck %s --check-prefix=CHECK-RING3 +# RUN: llvm-objdump -d %t.ring0 --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN + +# CHECK-RING0: BB Count : 1 +# CHECK-RING3: BB Count : 2 + +# CHECK-BIN:
: +# CHECK-BIN-NEXT: f4 hlt +# CHECK-BIN-NEXT: c3 retq + +.global main + .type main, %function +main: + hlt + retq +.size main, .-main