[clang] [llvm] [X86][COFF] Enable basic-block-address-map emission (PR #191347)
Haohai Wen via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 9 23:59:13 PDT 2026
https://github.com/HaohaiWen created https://github.com/llvm/llvm-project/pull/191347
Enable -fbasic-block-address-map fo X86 COFF.
Add COFF section creation for .llvm_bb_addr_map.
>From ad2ca2b69e5ba4ba7b6808d9b716fdb269e6f2eb Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Tue, 7 Apr 2026 15:44:11 +0800
Subject: [PATCH] [X86][COFF] Enable basic-block-address-map emission
Enable -fbasic-block-address-map fo X86 COFF.
Add COFF section creation for .llvm_bb_addr_map.
---
clang/lib/Driver/ToolChains/Clang.cpp | 3 +-
clang/test/Driver/basic-block-address-map.c | 1 +
llvm/include/llvm/Object/BBAddrMap.h | 3 ++
llvm/lib/MC/MCObjectFileInfo.cpp | 45 +++++++++++++------
...sic-block-address-map-function-sections.ll | 32 +++++++++----
.../CodeGen/X86/basic-block-address-map.ll | 13 ++++--
6 files changed, 70 insertions(+), 27 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 0d5722cd536f2..57f342273fef6 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6280,7 +6280,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_address_map,
options::OPT_fno_basic_block_address_map)) {
- if ((Triple.isX86() || Triple.isAArch64()) && Triple.isOSBinFormatELF()) {
+ if (((Triple.isX86() || Triple.isAArch64()) && Triple.isOSBinFormatELF()) ||
+ (Triple.isX86() && Triple.isOSBinFormatCOFF())) {
if (A->getOption().matches(options::OPT_fbasic_block_address_map))
A->render(Args, CmdArgs);
} else {
diff --git a/clang/test/Driver/basic-block-address-map.c b/clang/test/Driver/basic-block-address-map.c
index 12393e8ebfd54..b11dbb3c65548 100644
--- a/clang/test/Driver/basic-block-address-map.c
+++ b/clang/test/Driver/basic-block-address-map.c
@@ -1,5 +1,6 @@
// RUN: %clang -### --target=x86_64 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s
// RUN: %clang -### --target=aarch64 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s
+// RUN: %clang -### --target=x86_64-pc-windows-msvc -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s
// CHECK-PRESENT: -fbasic-block-address-map
// RUN: %clang -### --target=x86_64 -fno-basic-block-address-map %s -S 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT
diff --git a/llvm/include/llvm/Object/BBAddrMap.h b/llvm/include/llvm/Object/BBAddrMap.h
index 49c9b431822e0..4f710bc19951e 100644
--- a/llvm/include/llvm/Object/BBAddrMap.h
+++ b/llvm/include/llvm/Object/BBAddrMap.h
@@ -15,6 +15,7 @@
#define LLVM_OBJECT_BBADDRMAP_H
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/BlockFrequency.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/DataExtractor.h"
@@ -24,6 +25,8 @@
namespace llvm {
namespace object {
+inline constexpr StringLiteral BBAddrMapSectionName = ".llvm_bb_addr_map";
+
// Struct representing the BBAddrMap for one function.
struct BBAddrMap {
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 56a22241ae5d3..1e78e5fe2cc49 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -27,6 +27,7 @@
#include "llvm/MC/MCSectionXCOFF.h"
#include "llvm/MC/MCSymbolGOFF.h"
#include "llvm/MC/SectionKind.h"
+#include "llvm/Object/BBAddrMap.h"
#include "llvm/TargetParser/Triple.h"
using namespace llvm;
@@ -1266,23 +1267,39 @@ MCObjectFileInfo::getStackSizesSection(const MCSection &TextSec) const {
MCSection *
MCObjectFileInfo::getBBAddrMapSection(const MCSection &TextSec) const {
- if (Ctx->getObjectFileType() != MCContext::IsELF)
- return nullptr;
+ StringRef Name = object::BBAddrMapSectionName;
+ if (Ctx->getObjectFileType() == MCContext::IsELF) {
+ const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec);
+ unsigned Flags = ELF::SHF_LINK_ORDER;
+ StringRef GroupName;
+ if (const MCSymbol *Group = ElfSec.getGroup()) {
+ GroupName = Group->getName();
+ Flags |= ELF::SHF_GROUP;
+ }
- const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec);
- unsigned Flags = ELF::SHF_LINK_ORDER;
- StringRef GroupName;
- if (const MCSymbol *Group = ElfSec.getGroup()) {
- GroupName = Group->getName();
- Flags |= ELF::SHF_GROUP;
+ // Use the text section's begin symbol and unique ID to create a separate
+ // .llvm_bb_addr_map section associated with every unique text section.
+ return Ctx->getELFSection(
+ Name, ELF::SHT_LLVM_BB_ADDR_MAP, Flags, 0, GroupName, true,
+ ElfSec.getUniqueID(),
+ static_cast<const MCSymbolELF *>(TextSec.getBeginSymbol()));
+ } else if (Ctx->getObjectFileType() == MCContext::IsCOFF) {
+ StringRef COMDATSymName = "";
+ int Selection = 0;
+ unsigned Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_DISCARDABLE |
+ COFF::IMAGE_SCN_MEM_READ;
+ const auto &COFFSec = static_cast<const MCSectionCOFF &>(TextSec);
+ if (const MCSymbol *COMDATSym = COFFSec.getCOMDATSymbol()) {
+ COMDATSymName = COMDATSym->getName();
+ Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
+ Selection = COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
+ }
+ return Ctx->getCOFFSection(Name, Characteristics, COMDATSymName, Selection,
+ COFFSec.getUniqueID());
}
- // Use the text section's begin symbol and unique ID to create a separate
- // .llvm_bb_addr_map section associated with every unique text section.
- return Ctx->getELFSection(
- ".llvm_bb_addr_map", ELF::SHT_LLVM_BB_ADDR_MAP, Flags, 0, GroupName, true,
- ElfSec.getUniqueID(),
- static_cast<const MCSymbolELF *>(TextSec.getBeginSymbol()));
+ return nullptr;
}
MCSection *
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
index 892fa009935d2..2f4be8ab9fd06 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
@@ -1,15 +1,23 @@
-; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-address-map | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,ELF,ELF-FS
+; RUN: llc < %s -mtriple=x86_64 -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,ELF,ELF-NOFS
+; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc -function-sections -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,COFF-FS
+; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,COFF-NOFS
$_Z4fooTIiET_v = comdat any
define dso_local i32 @_Z3barv() {
ret i32 0
}
-;; Check we add SHF_LINK_ORDER for .llvm_bb_addr_map and link it with the corresponding .text sections.
-; CHECK: .section .text._Z3barv,"ax", at progbits
+;; For ELF, check we add SHF_LINK_ORDER for .llvm_bb_addr_map and link it with the corresponding .text sections.
+;; For COFF, it does not have SHF_LINK_ORDER like mechanism, we use function symbol to "link" them.
+; ELF-FS: .section .text._Z3barv,"ax", at progbits
+; COFF-FS: .section .text,"xr",one_only,_Z3barv
; CHECK-LABEL: _Z3barv:
; CHECK-NEXT: [[BAR_BEGIN:.Lfunc_begin[0-9]+]]:
-; CHECK: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3barv{{$}}
+; ELF-FS: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3barv{{$}}
+; ELF-NOFS: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text{{$}}
+; COFF-FS: .section .llvm_bb_addr_map,"drD",associative,_Z3barv,unique,0{{$}}
+; COFF-NOFS: .section .llvm_bb_addr_map,"drD"{{$}}
; CHECK-NEXT: .byte 5 # version
; CHECK-NEXT: .short 0 # feature
; CHECK-NEXT: .quad [[BAR_BEGIN]] # function address
@@ -19,10 +27,14 @@ define dso_local i32 @_Z3foov() {
%1 = call i32 @_Z4fooTIiET_v()
ret i32 %1
}
-; CHECK: .section .text._Z3foov,"ax", at progbits
+; ELF-FS: .section .text._Z3foov,"ax", at progbits
+; COFF-FS: .section .text,"xr",one_only,_Z3foov
; CHECK-LABEL: _Z3foov:
; CHECK-NEXT: [[FOO_BEGIN:.Lfunc_begin[0-9]+]]:
-; CHECK: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3foov{{$}}
+; ELF-FS: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3foov{{$}}
+; ELF-NOFS: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text{{$}}
+; COFF-FS: .section .llvm_bb_addr_map,"drD",associative,_Z3foov,unique,1{{$}}
+; COFF-NOFS: .section .llvm_bb_addr_map,"drD"{{$}}
; CHECK-NEXT: .byte 5 # version
; CHECK-NEXT: .short 32 # feature
; CHECK-NEXT: .quad [[FOO_BEGIN]] # function address
@@ -32,10 +44,14 @@ define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat {
ret i32 0
}
;; Check we add .llvm_bb_addr_map section to a COMDAT group with the corresponding .text section if such a COMDAT exists.
-; CHECK: .section .text._Z4fooTIiET_v,"axG", at progbits,_Z4fooTIiET_v,comdat
+; ELF: .section .text._Z4fooTIiET_v,"axG", at progbits,_Z4fooTIiET_v,comdat
+; COFF-FS: .section .text,"xr",discard,_Z4fooTIiET_v,unique,2{{$}}
+; COFF-NOFS: .section .text,"xr",discard,_Z4fooTIiET_v{{$}}
; CHECK-LABEL: _Z4fooTIiET_v:
; CHECK-NEXT: [[FOOCOMDAT_BEGIN:.Lfunc_begin[0-9]+]]:
-; CHECK: .section .llvm_bb_addr_map,"oG", at llvm_bb_addr_map,.text._Z4fooTIiET_v,_Z4fooTIiET_v,comdat{{$}}
+; ELF: .section .llvm_bb_addr_map,"oG", at llvm_bb_addr_map,.text._Z4fooTIiET_v,_Z4fooTIiET_v,comdat{{$}}
+; COFF-FS: .section .llvm_bb_addr_map,"drD",associative,_Z4fooTIiET_v,unique,2{{$}}
+; COFF-NOFS: .section .llvm_bb_addr_map,"drD",associative,_Z4fooTIiET_v{{$}}
; CHECK-NEXT: .byte 5 # version
; CHECK-NEXT: .short 0 # feature
; CHECK-NEXT: .quad [[FOOCOMDAT_BEGIN]] # function address
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map.ll b/llvm/test/CodeGen/X86/basic-block-address-map.ll
index 5567ccd4f9e75..c716e12a57646 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map.ll
@@ -1,7 +1,8 @@
; Check the basic block sections labels option
-; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,UNIQ
-; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,NOUNIQ
-; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -split-machine-functions | FileCheck %s --check-prefixes=CHECK,UNIQ
+; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,ELF,UNIQ
+; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,ELF,NOUNIQ
+; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -split-machine-functions | FileCheck %s --check-prefixes=CHECK,ELF,UNIQ
+; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc -function-sections -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,COFF
define void @_Z3bazb(i1 zeroext, i1 zeroext) personality ptr @__gxx_personality_v0 {
br i1 %0, label %3, label %8
@@ -52,6 +53,7 @@ declare i32 @__gxx_personality_v0(...)
; UNIQ: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3bazb{{$}}
;; Verify that with -unique-section-names=false, the unique id of the text section gets assigned to the llvm_bb_addr_map section.
; NOUNIQ: .section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text,unique,1
+; COFF: .section .llvm_bb_addr_map,"drD",associative,_Z3bazb,unique,0{{$}}
; CHECK-NEXT: .byte 5 # version
; CHECK-NEXT: .short 32 # feature
; CHECK-NEXT: .quad .Lfunc_begin0 # function address
@@ -87,4 +89,7 @@ declare i32 @__gxx_personality_v0(...)
; CHECK-NEXT: .uleb128 .LBB0_5-.LBB_END0_4
; CHECK-NEXT: .byte 0 # number of callsites
; CHECK-NEXT: .uleb128 .LBB_END0_5-.LBB0_5
-; CHECK-NEXT: .byte 5
+;; The landingpad block metadata differs: ELF uses eh_frame (HasReturn set),
+;; COFF uses SEH (HasReturn not set).
+; ELF-NEXT: .byte 5
+; COFF-NEXT: .byte 4
More information about the cfe-commits
mailing list