[llvm] [BOLT] Not use hlt as split point when build the CFG (PR #150963)

Haibo Jiang via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 28 07:45:27 PDT 2025


https://github.com/Jianghibo created https://github.com/llvm/llvm-project/pull/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.

>From dce028b07ed55da14d0713e2a76c7864aed98743 Mon Sep 17 00:00:00 2001
From: jianghaibo <jianghaibo9 at huawei.com>
Date: Mon, 28 Jul 2025 22:43:43 +0800
Subject: [PATCH] [BOLT] Not use hlt as split point when build the CFG

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   | 3 +++
 bolt/lib/Core/BinaryFunction.cpp         | 5 +++--
 bolt/lib/Target/X86/X86MCPlusBuilder.cpp | 4 ++++
 bolt/test/X86/static-exe.test            | 3 +++
 4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index f902a8c43cd1d..b698ce54d6899 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -740,6 +740,9 @@ class MCPlusBuilder {
     return false;
   }
 
+  /// Return true if the hlt instruction is defind as terminator
+  virtual bool isTerminatorHLT(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/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index eec68ff5a5fce..0f904b679365f 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -2329,11 +2329,12 @@ Error BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
       assert(PrevBB && "no previous basic block for a fall through");
       MCInst *PrevInstr = PrevBB->getLastNonPseudoInstr();
       assert(PrevInstr && "no previous instruction for a fall through");
-      if (MIB->isUnconditionalBranch(Instr) &&
+      if ((MIB->isUnconditionalBranch(Instr) &&
           !MIB->isIndirectBranch(*PrevInstr) &&
           !MIB->isUnconditionalBranch(*PrevInstr) &&
           !MIB->getConditionalTailCall(*PrevInstr) &&
-          !MIB->isReturn(*PrevInstr)) {
+          !MIB->isReturn(*PrevInstr)) ||
+          MIB->isTerminatorHLT(*PrevInstr)) {
         // Temporarily restore inserter basic block.
         InsertBB = PrevBB;
       } else {
diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
index a60c1a6bf156e..090d933a1e66a 100644
--- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
+++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
@@ -223,6 +223,10 @@ class X86MCPlusBuilder : public MCPlusBuilder {
     return Inst.getOpcode() == X86::ENDBR32 || Inst.getOpcode() == X86::ENDBR64;
   }
 
+  bool isTerminatorHLT(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/static-exe.test b/bolt/test/X86/static-exe.test
index e288160da1521..5d9b389d6ccca 100644
--- a/bolt/test/X86/static-exe.test
+++ b/bolt/test/X86/static-exe.test
@@ -1,6 +1,9 @@
 ## Check that llvm-bolt can rewrite static executable
+## And check CFG for halt instruction
 
 RUN: %clang %cflags %S/Inputs/static_exe.s -static -o %t.exe -nostdlib
 RUN: llvm-bolt %t.exe -o %t 2>&1 | FileCheck %s
+RUN: llvm-bolt %t.exe --print-cfg -o %t 2>&1 | FileCheck --check-prefix=CHECK-CFG
 
 CHECK: 1 out of 1 functions were overwritten
+CHECK-CFG: BB Count    : 1



More information about the llvm-commits mailing list