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 @@ -292,6 +292,8 @@ W->OS << Str; } + void writeStringWithAlignment(const StringRef Str, unsigned Alignment); + void writeI32(int32_t val) { char Buffer[4]; support::endian::write32le(Buffer, val); @@ -362,6 +364,28 @@ Section.Index = SectionCount++; } +// Write a string with extra paddings for trailing alignment +// TODO: support alignment at asm and llvm level? +void WasmObjectWriter::writeStringWithAlignment(const StringRef Str, + unsigned Alignment) { + + // Calculate the encoded size of str length and add pads based on it and + // alignment. + raw_null_ostream NullOS; + uint64_t StrSizeLength = encodeULEB128(Str.size(), NullOS); + uint64_t Offset = W->OS.tell() + StrSizeLength + Str.size(); + uint64_t Paddings = offsetToAlignment(Offset, Align(Alignment)); + Offset += Paddings; + + // LEB128 greater than 5 bytes is invalid + assert((StrSizeLength + Paddings) <= 5 && "too long string to align"); + + encodeSLEB128(Str.size(), W->OS, StrSizeLength + Paddings); + W->OS << Str; + + assert(W->OS.tell() == Offset && "invalid padding"); +} + void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section, StringRef Name) { LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n"); @@ -371,7 +395,12 @@ Section.PayloadOffset = W->OS.tell(); // Custom sections in wasm also have a string identifier. - writeString(Name); + if (Name != "__clangast") { + writeString(Name); + } else { + // The on-disk hashtable in clangast needs to be aligned by 4 bytes. + writeStringWithAlignment(Name, 4); + } // The position where the custom section starts. Section.ContentsOffset = W->OS.tell(); 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