[llvm] [BOLT] Keep X86 HLT instruction as a terminator in user mode (PR #154402)

Maksim Panchenko via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 19 11:59:41 PDT 2025


https://github.com/maksfb updated https://github.com/llvm/llvm-project/pull/154402

>From 8e56f4bb9bd83b2cb047e8e1b49fd0ae5f917196 Mon Sep 17 00:00:00 2001
From: Maksim Panchenko <maks at fb.com>
Date: Tue, 19 Aug 2025 11:19:29 -0700
Subject: [PATCH] [BOLT] Keep X86 HLT instruction as a terminator in user mode

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 ++++-
 bolt/test/X86/cfg_build_hlt.s        | 17 -----------------
 bolt/test/X86/hlt-terminator.s       | 24 ++++++++++++++++++++++++
 4 files changed, 40 insertions(+), 22 deletions(-)
 delete mode 100644 bolt/test/X86/cfg_build_hlt.s
 create mode 100644 bolt/test/X86/hlt-terminator.s

diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp
index d8a2ac6f6837a..7f962e14ea115 100644
--- a/bolt/lib/Core/MCPlusBuilder.cpp
+++ b/bolt/lib/Core/MCPlusBuilder.cpp
@@ -30,6 +30,11 @@ using namespace bolt;
 using namespace MCPlus;
 
 namespace opts {
+cl::opt<bool>
+    TerminalHLT("terminal-x86-hlt",
+                cl::desc("Assume that execution stops at x86 HLT instruction"),
+                cl::init(true), cl::Hidden, cl::cat(BoltCategory));
+
 cl::opt<bool>
     TerminalTrap("terminal-trap",
                  cl::desc("Assume that execution stops at trap instruction"),
@@ -132,10 +137,13 @@ bool MCPlusBuilder::equals(const MCSpecifierExpr &A, const MCSpecifierExpr &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 fe4a23cc01382..b2056ba2380fb 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -84,6 +84,7 @@ extern cl::opt<bool> KeepNops;
 extern cl::opt<bool> Lite;
 extern cl::list<std::string> ReorderData;
 extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
+extern cl::opt<bool> TerminalHLT;
 extern cl::opt<bool> TerminalTrap;
 extern cl::opt<bool> TimeBuild;
 extern cl::opt<bool> TimeRewrite;
@@ -2177,7 +2178,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/cfg_build_hlt.s
deleted file mode 100644
index a78134df34014..0000000000000
--- a/bolt/test/X86/cfg_build_hlt.s
+++ /dev/null
@@ -1,17 +0,0 @@
-## 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: <main>:
-# CHECK-BIN-NEXT: f4                            hlt
-# CHECK-BIN-NEXT: c3                            retq
-
-.global main
-  .type main, %function
-main:
-        hlt
-        retq
-.size main, .-main
diff --git a/bolt/test/X86/hlt-terminator.s b/bolt/test/X86/hlt-terminator.s
new file mode 100644
index 0000000000000..3f67182fdf432
--- /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: <main>:
+# CHECK-BIN-NEXT: f4                            hlt
+# CHECK-BIN-NEXT: c3                            retq
+
+.global main
+  .type main, %function
+main:
+        hlt
+        retq
+.size main, .-main



More information about the llvm-commits mailing list