[clang] [llvm] [Clang][PCH] Use metadata for embedding AST (PR #214135)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 4 22:36:26 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Steffen Larsen (steffenlarsen)
<details>
<summary>Changes</summary>
To avoid the size restriction that may be imposed by the address spaces of the target, this patch changes the embedding of the Clang AST from placing it inside a global variable to placing it inside a metadata node. This is done by introducing a new metadata node, namely `llvm.raw.sections`, which refers to nodes comprised of a section name, an alignment and the section data. The AsmPrinter lowers this to the corresponding sections.
Assisted-by: Claude Opus 4.6
---
Full diff: https://github.com/llvm/llvm-project/pull/214135.diff
11 Files Affected:
- (modified) clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp (+18-16)
- (modified) clang/test/Modules/lsv-debuginfo.cpp (+6-3)
- (added) clang/test/PCH/pch-clangast-raw-section.c (+6)
- (modified) llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h (+8)
- (modified) llvm/include/llvm/Target/TargetLoweringObjectFile.h (+7)
- (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+21)
- (modified) llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (+23)
- (added) llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll (+7)
- (added) llvm/test/CodeGen/X86/raw-sections-coff.ll (+12)
- (added) llvm/test/CodeGen/X86/raw-sections-elf.ll (+7)
- (added) llvm/test/CodeGen/X86/raw-sections-macho.ll (+9)
``````````diff
diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp
index 074f2a520704d..3a507782bb66e 100644
--- a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp
+++ b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp
@@ -297,25 +297,27 @@ class PCHContainerGenerator : public ASTConsumer {
auto *NameAndContent = llvm::MDTuple::get(*VMContext, Ops);
MD->addOperand(NameAndContent);
} else {
- auto Int8Ty = llvm::Type::getInt8Ty(*VMContext);
- auto *Ty = llvm::ArrayType::get(Int8Ty, Size);
- auto *Data = llvm::ConstantDataArray::getString(
- *VMContext, StringRef(SerializedAST.data(), Size),
- /*AddNull=*/false);
- auto *ASTSym = new llvm::GlobalVariable(
- *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage,
- Data, "__clang_ast");
- // The on-disk hashtable needs to be aligned.
- ASTSym->setAlignment(llvm::Align(8));
-
- // Mach-O also needs a segment name.
+ // Emit the serialized AST into a named section via llvm.raw.sections
+ // metadata, which the AsmPrinter emits directly at the MC layer.
+ // This avoids IR-level size constraints from the target's address space.
+ llvm::NamedMDNode *RawSections =
+ M->getOrInsertNamedMetadata("llvm.raw.sections");
+
+ StringRef SectionName;
if (Triple.isOSBinFormatMachO())
- ASTSym->setSection("__CLANG,__clangast");
- // COFF has an eight character length limit.
+ SectionName = "__CLANG,__clangast";
else if (Triple.isOSBinFormatCOFF())
- ASTSym->setSection("clangast");
+ SectionName = "clangast";
else
- ASTSym->setSection("__clangast");
+ SectionName = "__clangast";
+
+ llvm::Metadata *Ops[] = {
+ llvm::MDString::get(*VMContext, SectionName),
+ llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(*VMContext), 8)),
+ llvm::MDString::get(*VMContext,
+ StringRef(SerializedAST.data(), Size))};
+ RawSections->addOperand(llvm::MDTuple::get(*VMContext, Ops));
}
LLVM_DEBUG({
diff --git a/clang/test/Modules/lsv-debuginfo.cpp b/clang/test/Modules/lsv-debuginfo.cpp
index 40455727ecdda..61d2ff9514ed3 100644
--- a/clang/test/Modules/lsv-debuginfo.cpp
+++ b/clang/test/Modules/lsv-debuginfo.cpp
@@ -21,17 +21,20 @@
// RUN: cat %t-mod.ll | FileCheck %s
// ADT
-// CHECK: @__clang_ast =
+// CHECK: !llvm.raw.sections = !{[[ADT_SEC:![0-9]+]]}
+// CHECK: [[ADT_SEC]] = !{!"__clangast",
// B
-// CHECK: @__clang_ast =
+// CHECK: !llvm.raw.sections = !{[[B_SEC:![0-9]+]]}
+// CHECK: [[B_SEC]] = !{!"__clangast",
// This type isn't anchored anywhere, expect a full definition.
// CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>",
// CHECK-SAME: elements:
// C
-// CHECK: @__clang_ast =
+// CHECK: !llvm.raw.sections = !{[[C_SEC:![0-9]+]]}
+// CHECK: [[C_SEC]] = !{!"__clangast",
// Here, too.
// CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>",
diff --git a/clang/test/PCH/pch-clangast-raw-section.c b/clang/test/PCH/pch-clangast-raw-section.c
new file mode 100644
index 0000000000000..2ef54cf640e1c
--- /dev/null
+++ b/clang/test/PCH/pch-clangast-raw-section.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -fmodule-format=obj %S/pchpch1.h -o - | llvm-readelf --sections - | FileCheck %s
+
+// Ensure the serialized AST is emitted via llvm.raw.sections metadata into
+// a __clangast section with 8-byte alignment.
+
+// CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8
diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 78954a8bb2121..a56e8ed6e0879 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -49,6 +49,8 @@ class LLVM_ABI TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
/// Emit Obj-C garbage collection and linker options.
void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
+ MCSection *getNamedReadOnlySection(StringRef Name) const override;
+
void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL,
const MCSymbol *Sym,
const MachineModuleInfo *MMI) const override;
@@ -144,6 +146,8 @@ class LLVM_ABI TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
/// Emit the module flags that specify the garbage collection information.
void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
+ MCSection *getNamedReadOnlySection(StringRef Name) const override;
+
void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override;
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
@@ -207,6 +211,8 @@ class LLVM_ABI TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile {
/// Emit Obj-C garbage collection and linker options.
void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
+ MCSection *getNamedReadOnlySection(StringRef Name) const override;
+
void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override;
MCSection *getStaticCtorSection(unsigned Priority,
@@ -245,6 +251,8 @@ class LLVM_ABI TargetLoweringObjectFileWasm : public TargetLoweringObjectFile {
bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference,
const Function &F) const override;
+ MCSection *getNamedReadOnlySection(StringRef Name) const override;
+
void InitializeWasm();
MCSection *getStaticCtorSection(unsigned Priority,
const MCSymbol *KeySym) const override;
diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
index 3cce5974e6705..df8dd3466451e 100644
--- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h
+++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
@@ -90,6 +90,13 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
/// Emit the module-level metadata that the platform cares about.
virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {}
+ /// Get a read-only data section with the given name, using format-appropriate
+ /// defaults.
+ /// Returns nullptr if not supported by this object file format.
+ virtual MCSection *getNamedReadOnlySection(StringRef Name) const {
+ return nullptr;
+ }
+
/// Emit Call Graph Profile metadata.
void emitCGProfileMetadata(MCStreamer &Streamer, Module &M) const;
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 0580fc0f3a034..af48b444b7991 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2980,6 +2980,27 @@ bool AsmPrinter::doFinalization(Module &M) {
TLOF.emitModuleMetadata(*OutStreamer, M);
+ // Emit raw section data from llvm.raw.sections metadata.
+ if (const NamedMDNode *RawSections =
+ M.getNamedMetadata("llvm.raw.sections")) {
+ for (const MDNode *Op : RawSections->operands()) {
+ assert(Op->getNumOperands() == 3 &&
+ "llvm.raw.sections metadata entry must have three operands");
+ auto *SectionName = cast<MDString>(Op->getOperand(0));
+ auto *AlignCI = mdconst::extract<ConstantInt>(Op->getOperand(1));
+ auto *Data = cast<MDString>(Op->getOperand(2));
+
+ if (MCSection *Section =
+ TLOF.getNamedReadOnlySection(SectionName->getString())) {
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(Section);
+ OutStreamer->emitValueToAlignment(Align(AlignCI->getZExtValue()));
+ OutStreamer->emitBytes(Data->getString());
+ OutStreamer->popSection();
+ }
+ }
+ }
+
if (Target.isOSBinFormatELF()) {
MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 84b72321b1f55..bcdb2c3d63715 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -377,6 +377,11 @@ void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer,
emitCGProfileMetadata(Streamer, M);
}
+MCSection *
+TargetLoweringObjectFileELF::getNamedReadOnlySection(StringRef Name) const {
+ return getContext().getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+}
+
void TargetLoweringObjectFileELF::emitLinkerDirectives(MCStreamer &Streamer,
Module &M) const {
auto &C = getContext();
@@ -1350,6 +1355,13 @@ void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer,
Streamer.addBlankLine();
}
+MCSection *
+TargetLoweringObjectFileMachO::getNamedReadOnlySection(StringRef Name) const {
+ auto [Segment, SecName] = Name.split(',');
+ return getContext().getMachOSection(Segment, SecName, 0,
+ SectionKind::getReadOnly());
+}
+
void TargetLoweringObjectFileMachO::emitLinkerDirectives(MCStreamer &Streamer,
Module &M) const {
if (auto *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) {
@@ -1944,6 +1956,12 @@ void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer,
});
}
+MCSection *
+TargetLoweringObjectFileCOFF::getNamedReadOnlySection(StringRef Name) const {
+ return getContext().getCOFFSection(
+ Name, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ);
+}
+
void TargetLoweringObjectFileCOFF::emitLinkerDirectives(
MCStreamer &Streamer, Module &M) const {
if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) {
@@ -2258,6 +2276,11 @@ void TargetLoweringObjectFileWasm::getModuleMetadata(Module &M) {
Used.insert(GO);
}
+MCSection *
+TargetLoweringObjectFileWasm::getNamedReadOnlySection(StringRef Name) const {
+ return getContext().getWasmSection(Name, SectionKind::getReadOnly());
+}
+
MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
// We don't support explict section names for functions in the wasm object
diff --git a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll
new file mode 100644
index 0000000000000..a326a5e912508
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll
@@ -0,0 +1,7 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown %s -o %t.o
+; RUN: llvm-readobj --sections %t.o | FileCheck %s
+
+; CHECK: Name: __clangast
+
+!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"}
+!llvm.raw.sections = !{!0}
diff --git a/llvm/test/CodeGen/X86/raw-sections-coff.ll b/llvm/test/CodeGen/X86/raw-sections-coff.ll
new file mode 100644
index 0000000000000..fc9d2e7515f94
--- /dev/null
+++ b/llvm/test/CodeGen/X86/raw-sections-coff.ll
@@ -0,0 +1,12 @@
+; RUN: llc -filetype=obj -mtriple=x86_64-windows-msvc %s -o %t.o
+; RUN: llvm-readobj --sections %t.o | FileCheck %s
+
+; CHECK: Name: clangast
+; CHECK: RawDataSize:
+; CHECK: Characteristics [
+; CHECK-DAG: IMAGE_SCN_CNT_INITIALIZED_DATA
+; CHECK-DAG: IMAGE_SCN_MEM_READ
+; CHECK: ]
+
+!0 = !{!"clangast", i32 8, !"\de\ad\be\ef"}
+!llvm.raw.sections = !{!0}
diff --git a/llvm/test/CodeGen/X86/raw-sections-elf.ll b/llvm/test/CodeGen/X86/raw-sections-elf.ll
new file mode 100644
index 0000000000000..c1afbb043066b
--- /dev/null
+++ b/llvm/test/CodeGen/X86/raw-sections-elf.ll
@@ -0,0 +1,7 @@
+; RUN: llc -filetype=obj -mtriple=x86_64-linux-gnu %s -o %t.o
+; RUN: llvm-readelf --sections %t.o | FileCheck %s
+
+; CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8
+
+!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"}
+!llvm.raw.sections = !{!0}
diff --git a/llvm/test/CodeGen/X86/raw-sections-macho.ll b/llvm/test/CodeGen/X86/raw-sections-macho.ll
new file mode 100644
index 0000000000000..54d16b45529c4
--- /dev/null
+++ b/llvm/test/CodeGen/X86/raw-sections-macho.ll
@@ -0,0 +1,9 @@
+; RUN: llc -filetype=obj -mtriple=x86_64-apple-darwin %s -o %t.o
+; RUN: llvm-readobj --sections %t.o | FileCheck %s
+
+; CHECK: Name: __clangast
+; CHECK-NEXT: Segment: __CLANG
+; CHECK: Size:
+
+!0 = !{!"__CLANG,__clangast", i32 8, !"\de\ad\be\ef"}
+!llvm.raw.sections = !{!0}
``````````
</details>
https://github.com/llvm/llvm-project/pull/214135
More information about the llvm-commits
mailing list