diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp --- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -270,25 +270,42 @@ assert(Buffer->IsComplete && "serialization did not complete"); auto &SerializedAST = Buffer->Data; auto Size = SerializedAST.size(); - 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. - if (Triple.isOSBinFormatMachO()) - ASTSym->setSection("__CLANG,__clangast"); - // COFF has an eight character length limit. - else if (Triple.isOSBinFormatCOFF()) - ASTSym->setSection("clangast"); - else - ASTSym->setSection("__clangast"); + + if (Triple.isOSBinFormatWasm()) { + // Emit __clangast in custom section instead of named data segment + // to find it while iterating sections. + // This could be avoided if all data segements (the wasm sense) were + // represented as their own sections (in the llvm sense). + // TODO: https://github.com/WebAssembly/tool-conventions/issues/138 + llvm::NamedMDNode *MD = + M->getOrInsertNamedMetadata("wasm.custom_sections"); + llvm::Metadata *Ops[2] = { + llvm::MDString::get(*VMContext, "__clangast"), + llvm::MDString::get(*VMContext, + StringRef(SerializedAST.data(), Size))}; + 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. + if (Triple.isOSBinFormatMachO()) + ASTSym->setSection("__CLANG,__clangast"); + // COFF has an eight character length limit. + else if (Triple.isOSBinFormatCOFF()) + ASTSym->setSection("clangast"); + else + ASTSym->setSection("__clangast"); + } LLVM_DEBUG({ // Print the IR for the PCH container to the debug output. diff --git a/clang/test/PCH/pch-wasm.c b/clang/test/PCH/pch-wasm.c new file mode 100644 --- /dev/null +++ b/clang/test/PCH/pch-wasm.c @@ -0,0 +1,7 @@ +// REQUIRES: webassembly-registered-target +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-pch -fmodule-format=obj %S/pchpch1.h -o - | llvm-objdump --section-headers - | FileCheck %s + +// Ensure that clangast section should be emitted in a section for wasm object file + +// CHECK: file format wasm +// CHECK: __clangast {{[0-9a-f]+}} {{[0-9a-f]+}} diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -370,11 +370,33 @@ // The position where the section header ends, for measuring its size. Section.PayloadOffset = W->OS.tell(); - // Custom sections in wasm also have a string identifier. - writeString(Name); + // Custom sections in wasm also have a string identifier with extra paddings + // for alignment for special sections. + // TODO: support section alignment at asm and llvm level? + unsigned Alignment = 1; + + // The on-disk hashtable in clangast needs to be aligned by 4 bytes. + if (Name == "__clangast") + Alignment = 4; + + // Calculate the encoded size of name length and add pads based on it and + // alignment. + raw_null_ostream NullOS; + uint64_t NameSizeLength = encodeULEB128(Name.size(), NullOS); + uint64_t ContentsOffset = + Section.PayloadOffset + NameSizeLength + Name.size(); + uint64_t Paddings = offsetToAlignment(ContentsOffset, Align(Alignment)); + ContentsOffset += Paddings; + + // LEB128 greater than 5 bytes is invalid + assert((NameSizeLength + Paddings) <= 5 && "too long section name to align"); + + encodeSLEB128(Name.size(), W->OS, NameSizeLength + Paddings); + W->OS << Name; // The position where the custom section starts. Section.ContentsOffset = W->OS.tell(); + assert(Section.ContentsOffset == ContentsOffset && "invalid padding"); } // Now that the section is complete and we know how big it is, patch up the diff --git a/llvm/test/MC/WebAssembly/custom-section-alignment.ll b/llvm/test/MC/WebAssembly/custom-section-alignment.ll new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/custom-section-alignment.ll @@ -0,0 +1,10 @@ +; RUN: llc -filetype=obj %s -o - | od -t x1 -v | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +!0 = !{ !"before", !"\de\ad\be\ef" } +!1 = !{ !"__clangast", !"\fe\ed\fa\ce" } +!wasm.custom_sections = !{ !0, !1 } + +; Ensure that __clangast content is aligned by 4 bytes +; CHECK: {{(([0-9a-f]{2} ){4})*}}fe ed fa ce