From 51c62222f6cd8eca47f708592fc9e99f0a89471d Mon Sep 17 00:00:00 2001 From: Haibo Jiang <33863061+Jianghibo@users.noreply.github.com> Date: Sat, 16 Aug 2025 05:35:13 +0800 Subject: [PATCH 1/2] [BOLT] Do not use HLT as split point when build the CFG (#150963) For x86, the halt instruction is defined as a terminator instruction. When building the CFG, the instruction sequence following the hlt instruction is treated as an independent MBB. Since there is no jump information, the predecessor of this MBB cannot be identified, and it is considered an unreachable MBB that will be removed. Using this fix, the instruction sequences before and after hlt are refused to be placed in different blocks. --- bolt/include/bolt/Core/MCPlusBuilder.h | 4 ++++ bolt/lib/Core/MCPlusBuilder.cpp | 6 ++++-- bolt/lib/Target/X86/X86MCPlusBuilder.cpp | 4 ++++ bolt/test/X86/cfg_build_hlt.s | 17 +++++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 bolt/test/X86/cfg_build_hlt.s diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 5a8a4f6e391c..2e167ffb2909 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 5d25a514862a..cdfb9d7a94e5 100644 --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -131,8 +131,10 @@ 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()); + return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) || + Analysis->isTerminator(Inst) + ? !isX86HLT(Inst) + : false; } void MCPlusBuilder::setTailCall(MCInst &Inst) const { diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 9b51ab0763e3..cd6172f2b0e9 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/cfg_build_hlt.s b/bolt/test/X86/cfg_build_hlt.s new file mode 100644 index 000000000000..a78134df3401 --- /dev/null +++ b/bolt/test/X86/cfg_build_hlt.s @@ -0,0 +1,17 @@ +## Check CFG for halt instruction + +# RUN: %clang %cflags %s -static -o %t.exe -nostdlib +# RUN: llvm-bolt %t.exe --print-cfg --print-only=main -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-CFG +# RUN: llvm-objdump -d %t --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN + +# CHECK-CFG: BB Count : 1 +# CHECK-BIN:
: +# CHECK-BIN-NEXT: f4 hlt +# CHECK-BIN-NEXT: c3 retq + +.global main + .type main, %function +main: + hlt + retq +.size main, .-main -- Gitee From bd29ac09768952f251b56ae143588fa3a5262f0a Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Tue, 19 Aug 2025 14:41:13 -0700 Subject: [PATCH 2/2] [BOLT] Keep X86 HLT instruction as a terminator in user mode (#154402) This is a follow-up to #150963. X86 HLT instruction may appear in the user-level code, in which case we should treat it as a terminator. Handle it as a non-terminator in the Linux kernel mode. --- bolt/lib/Core/MCPlusBuilder.cpp | 16 ++++++++++++---- bolt/lib/Rewrite/RewriteInstance.cpp | 5 ++++- .../X86/{cfg_build_hlt.s => hlt-terminator.s} | 15 +++++++++++---- 3 files changed, 27 insertions(+), 9 deletions(-) rename bolt/test/X86/{cfg_build_hlt.s => hlt-terminator.s} (31%) diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp index cdfb9d7a94e5..778528d251b6 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,10 +136,13 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B, } bool MCPlusBuilder::isTerminator(const MCInst &Inst) const { - return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) || - Analysis->isTerminator(Inst) - ? !isX86HLT(Inst) - : false; + 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 43d5c0cbcdf7..0c24ec652ecd 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/test/X86/cfg_build_hlt.s b/bolt/test/X86/hlt-terminator.s similarity index 31% rename from bolt/test/X86/cfg_build_hlt.s rename to bolt/test/X86/hlt-terminator.s index a78134df3401..3f67182fdf43 100644 --- a/bolt/test/X86/cfg_build_hlt.s +++ b/bolt/test/X86/hlt-terminator.s @@ -1,10 +1,17 @@ -## Check CFG for halt instruction +## 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 -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-CFG -# RUN: llvm-objdump -d %t --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN +# 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-CFG: BB Count : 1 # CHECK-BIN:
: # CHECK-BIN-NEXT: f4 hlt # CHECK-BIN-NEXT: c3 retq -- Gitee