arda updated this revision to Diff 453345. arda added a comment. Herald added subscribers: cfe-commits, aheejin. Herald added a project: clang.
Add clang and llvm related changes Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D131618/new/ https://reviews.llvm.org/D131618 Files: clang/include/clang/Basic/CodeGenOptions.def clang/include/clang/CodeGen/BackendUtil.h clang/include/clang/Driver/Options.td clang/include/clang/Driver/ToolChain.h clang/lib/CodeGen/BackendUtil.cpp clang/lib/CodeGen/CodeGenAction.cpp clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChains/Clang.cpp lld/ELF/Config.h lld/ELF/Driver.cpp lld/ELF/InputFiles.cpp lld/ELF/Options.td lld/test/ELF/fatlto/Inputs/a-fatLTO.o lld/test/ELF/fatlto/Inputs/a-thinLTO.bc lld/test/ELF/fatlto/Inputs/a.c lld/test/ELF/fatlto/Inputs/a.h lld/test/ELF/fatlto/Inputs/a.o lld/test/ELF/fatlto/Inputs/main-fatLTO.o lld/test/ELF/fatlto/Inputs/main-thinLTO.bc lld/test/ELF/fatlto/Inputs/main.c lld/test/ELF/fatlto/Inputs/main.o lld/test/ELF/fatlto/fatlto.test llvm/include/llvm/Bitcode/BitcodeWriter.h llvm/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/lib/Object/ObjectFile.cpp
Index: llvm/lib/Object/ObjectFile.cpp =================================================================== --- llvm/lib/Object/ObjectFile.cpp +++ llvm/lib/Object/ObjectFile.cpp @@ -79,7 +79,7 @@ bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { Expected<StringRef> NameOrErr = getSectionName(Sec); if (NameOrErr) - return *NameOrErr == ".llvmbc"; + return *NameOrErr == ".llvmbc" || *NameOrErr == ".fatlto"; consumeError(NameOrErr.takeError()); return false; } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -4953,6 +4953,37 @@ llvm_unreachable("Unimplemented ObjectFormatType"); } +static const char *getSectionNameForBitcodeForFatLTO(const Triple &T) { + switch (T.getObjectFormat()) { + case Triple::MachO: + llvm::report_fatal_error("MachO is not yet implemented for FatLTO"); + break; + case Triple::COFF: + llvm::report_fatal_error("COFF is not yet implemented for FatLTO"); + break; + case Triple::ELF: + return ".fatlto"; + case Triple::Wasm: + llvm::report_fatal_error("Wasm is not yet implemented for FatLTO"); + break; + case Triple::UnknownObjectFormat: + return ".fatlto"; + case Triple::GOFF: + llvm::report_fatal_error("GOFF is not yet implemented for FatLTO"); + break; + case Triple::SPIRV: + llvm::report_fatal_error("SPIRV is not yet implemented for FatLTO"); + break; + case Triple::XCOFF: + llvm::report_fatal_error("XCOFF is not yet implemented for FatLTO"); + break; + case Triple::DXContainer: + llvm::report_fatal_error("DXContainer is not yet implemented for FatLTO"); + break; + } + llvm_unreachable("Unimplemented ObjectFormatType"); +} + void llvm::embedBitcodeInModule(llvm::Module &M, llvm::MemoryBufferRef Buf, bool EmbedBitcode, bool EmbedCmdline, const std::vector<uint8_t> &CmdArgs) { @@ -5045,3 +5076,68 @@ llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used"); NewUsed->setSection("llvm.metadata"); } + +void llvm::embedBitcodeInFatObject(llvm::Module &M, llvm::MemoryBufferRef Buf) { + // Save llvm.compiler.used and remove it. + SmallVector<Constant *, 2> UsedArray; + SmallVector<GlobalValue *, 4> UsedGlobals; + Type *UsedElementType = Type::getInt8Ty(M.getContext())->getPointerTo(0); + GlobalVariable *Used = collectUsedGlobalVariables(M, UsedGlobals, true); + for (auto *GV : UsedGlobals) { + if (GV->getName() != "llvm.embedded.module" && + GV->getName() != "llvm.cmdline") + UsedArray.push_back( + ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType)); + } + if (Used) + Used->eraseFromParent(); + + // Embed the bitcode for the llvm module. + std::string Data; + ArrayRef<uint8_t> ModuleData; + Triple T(M.getTargetTriple()); + + if (Buf.getBufferSize() == 0 || + !isBitcode((const unsigned char *)Buf.getBufferStart(), + (const unsigned char *)Buf.getBufferEnd())) { + // If the input is LLVM Assembly, bitcode is produced by serializing + // the module. Use-lists order need to be preserved in this case. + llvm::raw_string_ostream OS(Data); + llvm::WriteBitcodeToFile(M, OS, /* ShouldPreserveUseListOrder */ true); + ModuleData = + ArrayRef<uint8_t>((const uint8_t *)OS.str().data(), OS.str().size()); + } else + // If the input is LLVM bitcode, write the input byte stream directly. + ModuleData = ArrayRef<uint8_t>((const uint8_t *)Buf.getBufferStart(), + Buf.getBufferSize()); + llvm::Constant *ModuleConstant = + llvm::ConstantDataArray::get(M.getContext(), ModuleData); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage, + ModuleConstant); + GV->setSection(getSectionNameForBitcodeForFatLTO(T)); + // Set alignment to 1 to prevent padding between two contributions from input + // sections after linking. + GV->setAlignment(Align(1)); + UsedArray.push_back( + ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType)); + if (llvm::GlobalVariable *Old = + M.getGlobalVariable("llvm.embedded.module", true)) { + assert(Old->hasZeroLiveUses() && + "llvm.embedded.module can only be used once in llvm.compiler.used"); + GV->takeName(Old); + Old->eraseFromParent(); + } else { + GV->setName("llvm.embedded.module"); + } + + if (UsedArray.empty()) + return; + + // Recreate llvm.compiler.used. + ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size()); + auto *NewUsed = new GlobalVariable( + M, ATy, false, llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used"); + NewUsed->setSection("llvm.metadata"); +} Index: llvm/include/llvm/Bitcode/BitcodeWriter.h =================================================================== --- llvm/include/llvm/Bitcode/BitcodeWriter.h +++ llvm/include/llvm/Bitcode/BitcodeWriter.h @@ -165,6 +165,7 @@ bool EmbedCmdline, const std::vector<uint8_t> &CmdArgs); + void embedBitcodeInFatObject(Module &M, MemoryBufferRef Buf); } // end namespace llvm #endif // LLVM_BITCODE_BITCODEWRITER_H Index: lld/test/ELF/fatlto/fatlto.test =================================================================== --- /dev/null +++ lld/test/ELF/fatlto/fatlto.test @@ -0,0 +1,37 @@ +; REQUIRES: x86 + +; Following FatLTO and regular object files are produced as follows: +; clang -c -ffat-lto-objects -o a-fatLTO.o -x ir a-thinLTO.bc +; clang -c -ffat-lto-objects -o main-fatLTO.o -x ir main-thinLTO.bc +; clang -c -o a.c main.c + +; Basic FatLTO tests. +; Check that if input files contain .fatlto section +; RUN: llvm-readobj -S %p/Inputs/a-fatLTO.o | FileCheck --check-prefix=a %s +; a: Name: .fatlto +; RUN: llvm-readobj -S %p/Inputs/main-fatLTO.o | FileCheck --check-prefix=main %s +; main: Name: .fatlto + +; Final executable should not have .fatlto section no matter what the target is +; RUN: ld.lld -o %tfoo-fatLTO %p/Inputs/a-fatLTO.o %p/Inputs/main-fatLTO.o -fat-lto-objects +; RUN: llvm-readobj -S %tfoo-fatLTO | FileCheck --check-prefix=lto-target %s +; Check if .fatlto section gets aggregated in LTO target +; lto-target-NOT: Name: .fatlto + +; Final executable should not have .fatlto section no matter what the target is +; RUN: ld.lld -o %tfoo-fatNoLTO %p/Inputs/a-fatLTO.o %p/Inputs/main-fatLTO.o +; RUN: llvm-readobj -S %tfoo-fatNoLTO | FileCheck --check-prefix=non-lto-target %s +; Check if .fatlto section gets aggregated in non-LTO target +; non-lto-target-NOT: Name: .fatlto + +; Check if the LTO target executable produced from FatLTO object file is identical to the one produced from ThinLTO bitcode files +; RUN: ld.lld -o %tfoo-thinTO %p/Inputs/a-thinLTO.bc %p/Inputs/main-thinLTO.bc +; RUN: obj2yaml %tfoo-fatLTO > %tfoo-fatLTO.yaml +; RUN: obj2yaml %tfoo-thinLTO > %tfoo-thinLTO.yaml +; RUN: diff %tfoo-fatLTO.yaml %tfoo-thinLTO.yaml + +; Check if the no-LTO target executable produced from FatLTO object file is identical to the one produced from regular object files +; RUN: ld.lld -o %tfoo-noLTO %p/Inputs/a.o %p/Inputs/main.o +; RUN: obj2yaml %tfoo-fatNoLTO > %tfoo-fatNoLTO.yaml +; RUN: obj2yaml %tfoo-noLTO > %tfoo-noLTO.yaml +; RUN: diff %tfoo-fatNoLTO.yaml %tfoo-noLTO.yaml Index: lld/test/ELF/fatlto/Inputs/main.c =================================================================== --- /dev/null +++ lld/test/ELF/fatlto/Inputs/main.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include "a.h" + +void foo4(void) { + printf("Hi\n"); +} + +int main() { + return foo1(); +} Index: lld/test/ELF/fatlto/Inputs/a.h =================================================================== --- /dev/null +++ lld/test/ELF/fatlto/Inputs/a.h @@ -0,0 +1,3 @@ +extern int foo1(void); +extern void foo2(void); +extern void foo4(void); Index: lld/test/ELF/fatlto/Inputs/a.c =================================================================== --- /dev/null +++ lld/test/ELF/fatlto/Inputs/a.c @@ -0,0 +1,24 @@ +#include "a.h" + +static signed int i = 0; + +void foo2(void) { + i = -1; +} + +static int foo3() { + foo4(); + return 10; +} + +int foo1(void) { + int data = 0; + + if (i < 0) + data = foo3(); + + data = data + 42; + return data; +} + + Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -608,6 +608,10 @@ def thinlto_single_module_eq: JJ<"thinlto-single-module=">, HelpText<"Specific a single module to compile in ThinLTO mode, for debugging only">; +defm fatlto_objects: B<"fat-lto-objects", + "Use the embedded bitcode in the .fatlto section of the object file", + "Use the assembly in the object file (default)">; + def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for --lto-O">; def: F<"plugin-opt=debug-pass-manager">, Alias<lto_debug_pass_manager>, HelpText<"Alias for --lto-debug-pass-manager">; Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -1715,6 +1715,13 @@ if (isBitcode(mb)) return make<BitcodeFile>(mb, archiveName, offsetInArchive, /*lazy=*/false); + // If it is a fatLTO object file + if (config->fatLTOObjects) { + Expected<MemoryBufferRef> fatLTOData = IRObjectFile::findBitcodeInMemBuffer(mb); + if (!errorToBool(fatLTOData.takeError())) + return make<BitcodeFile>(*fatLTOData, archiveName, offsetInArchive, /*lazy=*/false); + } + switch (getELFKind(mb, archiveName)) { case ELF32LEKind: return make<ObjFile<ELF32LE>>(mb, archiveName); Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -1023,6 +1023,11 @@ args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || hasZOption(args, "muldefs"); + + config->fatLTOObjects = + args.hasFlag(OPT_fatlto_objects, + OPT_no_fatlto_objects, false); + config->androidMemtagHeap = args.hasFlag(OPT_android_memtag_heap, OPT_no_android_memtag_heap, false); config->androidMemtagStack = args.hasFlag(OPT_android_memtag_stack, @@ -2626,10 +2631,17 @@ // Now that we have a complete list of input files. // Beyond this point, no new files are added. // Aggregate all input sections into one place. - for (InputFile *f : ctx->objectFiles) - for (InputSectionBase *s : f->getSections()) - if (s && s != &InputSection::discarded) + for (InputFile *f : ctx->objectFiles) { + for (InputSectionBase *s : f->getSections()) { + if (!s) + continue; + // Do not aggregate the .fatlto section + if (s->name == ".fatlto") + continue; + if (s != &InputSection::discarded) inputSections.push_back(s); + } + } for (BinaryFile *f : ctx->binaryFiles) for (InputSectionBase *s : f->getSections()) inputSections.push_back(cast<InputSection>(s)); Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -155,6 +155,7 @@ uint64_t> callGraphProfile; bool allowMultipleDefinition; + bool fatLTOObjects; bool androidPackDynRelocs = false; bool armHasBlx = false; bool armHasMovtMovw = false; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -7117,6 +7117,9 @@ } } + if (Args.hasArg(options::OPT_ffat_lto_objects)) + CmdArgs.push_back("-ffat-lto-objects"); + if (Args.hasArg(options::OPT_forder_file_instrumentation)) { CmdArgs.push_back("-forder-file-instrumentation"); // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -1314,6 +1314,11 @@ BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); } + // Process -ffat-lto-objects flag. + if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects)) { + BitcodeEmbed = EmbedBitcode; + } + // Remove existing compilation database so that each job can append to it. if (Arg *A = Args.getLastArg(options::OPT_MJ)) llvm::sys::fs::remove(A->getValue()); Index: clang/lib/CodeGen/CodeGenAction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenAction.cpp +++ clang/lib/CodeGen/CodeGenAction.cpp @@ -375,6 +375,7 @@ } EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); + EmbedFatLTO(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts, C.getTargetInfo().getDataLayoutString(), @@ -1172,6 +1173,8 @@ EmbedObject(TheModule.get(), CodeGenOpts, Diagnostics); EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile); + EmbedFatLTO(TheModule.get(), CodeGenOpts, *MainFile); + LLVMContext &Ctx = TheModule->getContext(); Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -1197,6 +1197,8 @@ // __LLVM,__bitcode section. void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::MemoryBufferRef Buf) { + if (CGOpts.FatLTO) + return; if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off) return; llvm::embedBitcodeInModule( @@ -1205,6 +1207,15 @@ CGOpts.CmdArgs); } +// With -ffat-lto-objects, save a copy of the llvm IR as data in the +// .fatlto section. +void clang::EmbedFatLTO(llvm::Module *M, const CodeGenOptions &CGOpts, + llvm::MemoryBufferRef Buf) { + if (!CGOpts.FatLTO) + return; + llvm::embedBitcodeInFatObject(*M, Buf); +} + void clang::EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts, DiagnosticsEngine &Diags) { if (CGOpts.OffloadObjects.empty()) Index: clang/include/clang/Driver/ToolChain.h =================================================================== --- clang/include/clang/Driver/ToolChain.h +++ clang/include/clang/Driver/ToolChain.h @@ -569,6 +569,9 @@ /// SupportsEmbeddedBitcode - Does this tool chain support embedded bitcode. virtual bool SupportsEmbeddedBitcode() const { return false; } + /// SupportsFatLTO - Does this toolchain support fat LTO objects. + virtual bool SupportsFatLTO() const { return true; } + /// getThreadModel() - Which thread model does this target use? virtual std::string getThreadModel() const { return "posix"; } Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2124,6 +2124,11 @@ Alias<flto_EQ>, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>, Alias<flto_EQ>, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; +defm fat_lto_objects : BoolFOption<"fat-lto-objects", + CodeGenOpts<"FatLTO">, DefaultFalse, + PosFlag<SetTrue, [], "Enable fat LTO object support">, + NegFlag<SetFalse, [], "Disable fat LTO object support">, + BothFlags<[CC1Option], "">>; def fno_lto : Flag<["-"], "fno-lto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>, HelpText<"Disable LTO mode (default)">; def foffload_lto_EQ : Joined<["-"], "foffload-lto=">, Flags<[CoreOption]>, Group<f_Group>, @@ -4669,7 +4674,6 @@ defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>; defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>; -defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>; defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_gcc_optimization_f_Group>; defm friend_injection : BooleanFFlag<"friend-injection">, Group<clang_ignored_f_Group>; defm function_attribute_list : BooleanFFlag<"function-attribute-list">, Group<clang_ignored_f_Group>; Index: clang/include/clang/CodeGen/BackendUtil.h =================================================================== --- clang/include/clang/CodeGen/BackendUtil.h +++ clang/include/clang/CodeGen/BackendUtil.h @@ -45,6 +45,9 @@ void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::MemoryBufferRef Buf); + void EmbedFatLTO(llvm::Module *M, const CodeGenOptions &CGOpts, + llvm::MemoryBufferRef Buf); + void EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts, DiagnosticsEngine &Diags); } Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -161,6 +161,7 @@ ///< compile step. CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole ///< program vtable opt). +CODEGENOPT(FatLTO, 1, 0) ///< Set when -ffat-lto-objects is enabled. CODEGENOPT(EnableSplitLTOUnit, 1, 0) ///< Enable LTO unit splitting to support /// CFI and traditional whole program /// devirtualization that require whole
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits