diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -358,6 +358,7 @@ CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead /// virtual function elimination /// optimization. +CODEGENOPT(EmbedLTOObjects, 1, 0) /// Whether to use public LTO visibility for entities in std and stdext /// namespaces. This is enabled by clang-cl's /MT and /MTd flags. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2174,6 +2174,11 @@ Flags<[CoreOption, CC1Option]>, Group, HelpText<"Write minimized bitcode to for the ThinLTO thin link only">, MarshallingInfoString>; + +def fembedded_lto : Flag<["-"], "fembedded-lto">, Flags<[CC1Option]>, + HelpText<"Embed the bitcode into the module and generate object code from an -flto compile.">, + MarshallingInfoFlag>; + def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group, Flags<[NoXarchOption, CoreOption]>; defm merge_all_constants : BoolFOption<"merge-all-constants", diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -25,6 +25,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/Bitcode/EmbedBitcodePass.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -970,6 +971,17 @@ break; } + // Run pass to embed the bitcode into the module to preserve for + // LTO usage. + if (CodeGenOpts.EmbedLTOObjects) { + if (!TheModule->getModuleFlag("ThinLTO")) + TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + uint32_t(1)); + MPM.addPass(EmbedBitcodePass()); + } + // Now that we have all of the passes ready, run them. { PrettyStackTraceString CrashInfo("Optimizer"); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4633,6 +4633,9 @@ if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; + if (Args.hasArg(options::OPT_fembedded_lto)) + Output = types::TY_PP_Asm; + return C.MakeAction(Input, Output); } if (isUsingLTO(/* IsOffload */ true) && diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7140,6 +7140,10 @@ } } + if (IsUsingLTO && LTOMode == LTOK_Full && + Args.getLastArg(options::OPT_fembedded_lto)) + CmdArgs.push_back("-fembedded-lto"); + 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 diff --git a/clang/test/CodeGen/PowerPC/aix-embedded-bitcode.c b/clang/test/CodeGen/PowerPC/aix-embedded-bitcode.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/aix-embedded-bitcode.c @@ -0,0 +1,13 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -flto -fembedded-lto -S -triple powerpc-unknown-aix < %s | \ +// RUN: FileCheck %s +// +// RUN: %clang_cc1 -flto -fembedded-lto -S -triple powerpc64-unknown-aix < %s | \ +// RUN: FileCheck %s +extern int puts(const char*); + +int external_func(const char* msg) { + return puts(msg); +} + +// CHECK: .info , 0xffffffff # Magic diff --git a/clang/test/CodeGen/embed-lto-metadata.c b/clang/test/CodeGen/embed-lto-metadata.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/embed-lto-metadata.c @@ -0,0 +1,9 @@ +// RUN: %clang -cc1 -triple powerpc64-unknown-aix-xcoff -S -flto=full -fembedded-lto -emit-llvm < %s | FileCheck %s +// RUN: %clang -cc1 -triple powerpc-unknown-aix-xcoff -S -flto=full -fembedded-lto -emit-llvm < %s | FileCheck %s + +// CHECK: !{{[0-9]+}} = !{i32 1, !"ThinLTO", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"EnableSplitLTOUnit", i32 1} + +int test(void) { + return 0xabcd; +} diff --git a/clang/test/Driver/embedded-lto.c b/clang/test/Driver/embedded-lto.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/embedded-lto.c @@ -0,0 +1,8 @@ +// RUN: %clang -target powerpc-unknown-aix-xcoff -flto -fembedded-lto -### %s -c -o /dev/null 2>&1 | FileCheck --check-prefix=WLTO %s +// RUN %clang -target powerpc64-unknown-aix-xcoff -flto -fembedded-lto -### %s -c -o /dev/null 2>&1 | FileCheck --check-prefix=WLTO %s + +// RUN %clang -target powerpc-unknown-aix-xcoff -fmebedded-lto -### %s -c -o /dev/null 2>&1 | FileCheck --check-prefix=WOLTO %s +// RUN %clang -target powerpc64-unknown-aix-xcoff -fembedded-lto -### %s -c -o /dev/null 2>&1 | FileCheck --check-prefix=WOLTO %s + +// WLTO: "-fembedded-lto" +// WOLTO-NOT: "-fembedded-lto" diff --git a/llvm/include/llvm/Bitcode/EmbedBitcodePass.h b/llvm/include/llvm/Bitcode/EmbedBitcodePass.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Bitcode/EmbedBitcodePass.h @@ -0,0 +1,36 @@ +//===-- EmbedBitcodePass.h - Embeds bitcode into global ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides apass which embeds the bitcode into a global variable. +/// +//===----------------------------------------------------------------------===// +// +#ifndef LLVM_BITCODE_EMBEDBITCODEPASS_H +#define LLVM_BITCODE_EMBEDBITCODEPASS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +class Module; +class ModulePass; +class Pass; + +/// Pass embeds the current module into a global variable. +class EmbedBitcodePass : public PassInfoMixin { +public: + EmbedBitcodePass(){}; + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + + static bool isRequired() { return true; } +}; + +} // end namespace llvm. + +#endif diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -634,6 +634,9 @@ /// \param Sym - The symbol on the .ref directive. virtual void emitXCOFFRefDirective(StringRef Sym); + virtual void emitXCOFFInfoDirective(StringRef Name, + const SmallVector &Metadata); + /// Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -41,6 +41,12 @@ report_fatal_error("emitXCOFFRenameDirective is not implemented yet on " "object generation path"); } + + void emitXCOFFInfoDirective(const StringRef Name, + const SmallVector &Metadata) override { + report_fatal_error("emitXCOFFInfoDirective is not implemented yet on " + "object generation path"); + } }; } // end namespace llvm diff --git a/llvm/lib/Bitcode/Writer/CMakeLists.txt b/llvm/lib/Bitcode/Writer/CMakeLists.txt --- a/llvm/lib/Bitcode/Writer/CMakeLists.txt +++ b/llvm/lib/Bitcode/Writer/CMakeLists.txt @@ -2,6 +2,7 @@ BitWriter.cpp BitcodeWriter.cpp BitcodeWriterPass.cpp + EmbedBitcodePass.cpp ValueEnumerator.cpp DEPENDS diff --git a/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp b/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp @@ -0,0 +1,52 @@ +//===- EmbedBitcodePass.cpp - Pass that embeds the bitcode into a global---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// EmbedBitcodePass implementation. +// +//===----------------------------------------------------------------------===// +// +#include "llvm/Bitcode/EmbedBitcodePass.h" + +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/PassManager.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) { + if (M.getGlobalVariable("llvm.embedded.module", true)) + report_fatal_error("Can only embed the module once."); + + Triple T(M.getTargetTriple()); + if (T.getObjectFormat() != Triple::XCOFF) + report_fatal_error( + "Embed bitcode pass currently only supports XCOFF object format."); + + std::string Data; + raw_string_ostream OS(Data); + WriteBitcodeToFile(M, OS, /* ShouldPreserveUseListOrder */ true); + ArrayRef ModuleData((const uint8_t *)OS.str().data(), + OS.str().size()); + Constant *ModuleConstant = ConstantDataArray::get(M.getContext(), ModuleData); + + llvm::GlobalVariable *EM = new llvm::GlobalVariable( + M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage, + ModuleConstant); + + EM->setSection("LLVMLTO"); + EM->setAlignment(Align(1)); + EM->setName("llvm.embedded.module"); + appendToCompilerUsed(M, {EM}); + + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" @@ -196,6 +197,8 @@ StringRef Rename) override; void emitXCOFFRefDirective(StringRef Name) override; + void emitXCOFFInfoDirective(StringRef Name, + const SmallVector &Metadata) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -941,6 +944,111 @@ EmitEOL(); } +void MCAsmStreamer::emitXCOFFInfoDirective( + StringRef Name, const SmallVector &Metadata) { + const char *InfoDirective = "\t.info , "; + // Start with the .info pseudo-op, and the magic number indicating embedded + // metadata format. + OS << InfoDirective << format_hex(0Xffffffff, 10); + if (IsVerboseAsm) + OS << " # Magic"; + EmitEOL(); + + // NameSize does not include the null terminator of the string. Since we are + // padding out to a word boundary anyway, we can calcualte the padding in the + // range [1,4] instead of [0,3] to account for the terminator. + size_t NameSize = Name.size(); + uint32_t NamePaddingSize = 4 - NameSize % 4; + + // Metadata needs to be padded out to an even word size. + size_t MetadataSize = Metadata.size(); + uint32_t MetadataPaddingSize = MetadataSize % 4 ? 4 - (MetadataSize % 4) : 0; + + // Total length of all the metadata. We have: + // * 4 byte magic + // * 8 byte length + // * The (null terminated) name string + padding + // * The word sized difference between the first length and the length + // of the payload. + // * The payload padded to a word boundary. + uint64_t Length = 4 + sizeof(Length) + NameSize + NamePaddingSize + + sizeof(uint32_t) + MetadataSize + MetadataPaddingSize; + uint32_t Difference = Length - MetadataSize; + + // Emit the 8-byte length as 2 seperate words. + OS << InfoDirective; + OS << format_hex(uint32_t(Length << 32), 10) << ", "; + OS << format_hex(uint32_t(Length), 10); + if (IsVerboseAsm) + OS << " # Length"; + EmitEOL(); + + // Write out the full word portion of the identifying string. + OS << InfoDirective; + const char *NameData = Name.data(); + while (NameData + 4 <= Name.data() + NameSize) { + uint32_t NextWord = llvm::support::endian::read32be(NameData); + OS << format_hex(NextWord, 10) << ", "; + NameData += 4; + } + + // Write out the remainder of the identifier and the null-terminating + // padding. + uint32_t NextWord = 0; + if (NamePaddingSize == 3) + NextWord = NameData[0] << 24; + else if (NamePaddingSize == 2) + NextWord = NameData[0] << 24 | NameData[1] << 16; + else if (NamePaddingSize == 1) + NextWord = NameData[0] << 24 | NameData[1] << 16 | NameData[2] << 8; + + OS << format_hex(NextWord, 10); + if (IsVerboseAsm) + OS << " # Identifier string"; + EmitEOL(); + + // Emit the size difference used to calculate the payload size and + // end the first line. + OS << InfoDirective; + OS << format_hex(Difference, 10); + if (IsVerboseAsm) + OS << " # Size difference"; + EmitEOL(); + + // The assembler has a limit on the number of oprands in an expression. + // For the .info pseudo op we excced that limit even with relatively small + // payloads. Break this up to multiple .info directives to accomadate this + // limitation. The number of bytes written here is chosen just to kkep the + // assembly readable. + uint64_t Index = 0; + while (Index + 4 <= MetadataSize) { + OS << "\t.info "; + uint64_t End = std::min(Index + 40, MetadataSize); + while (Index + 4 <= End) { + OS << ", "; + uint32_t NextWord = + llvm::support::endian::read32be(Metadata.data() + Index); + OS << format_hex(NextWord, 10); + Index += 4; + } + EmitEOL(); + } + + if (MetadataPaddingSize) { + // If there is padding, then we have at least one byte of payload left to + // emit. + uint32_t LastWord = Metadata[Index] << 24; + if (MetadataPaddingSize == 2) + LastWord |= Metadata[Index + 1] << 16; + else if (MetadataPaddingSize == 1) + LastWord |= ((Metadata[Index + 1] << 16) | (Metadata[Index + 2] << 8)); + + OS << InfoDirective; + OS << format_hex(LastWord, 10); + EmitEOL(); + } +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1190,6 +1190,12 @@ llvm_unreachable("emitXCOFFRefDirective is only supported on XCOFF targets"); } +void MCStreamer::emitXCOFFInfoDirective(StringRef Name, + const SmallVector &Metadaga) { + llvm_unreachable("emitXCOFFInfoDirective is only supported on" + "XCOFF targets"); +} + void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name, bool KeepOriginalSym) {} diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -72,6 +72,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/TypeBasedAliasAnalysis.h" +#include "llvm/Bitcode/EmbedBitcodePass.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/PassManager.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -56,6 +56,7 @@ MODULE_PASS("debugify", NewPMDebugifyPass()) MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass()) MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass()) +MODULE_PASS("embed-bitcode", EmbedBitcodePass()) MODULE_PASS("extract-blocks", BlockExtractorPass()) MODULE_PASS("forceattrs", ForceFunctionAttrsPass()) MODULE_PASS("function-import", FunctionImportPass()) diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -2392,6 +2392,39 @@ } void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) { + if (GV->getName().equals("llvm.embedded.module")) { + // Bitcode is stored in the intitalizer. + assert(GV->hasInitializer() && "embedded module must have intializer."); + + // The globals CSECT name is emitted as part of the info directive to + // allow consumers to determine what the embedded bitcode is for. + SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); + MCSectionXCOFF *Csect = cast( + getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); + + // The embeded module must be an array of bytes. + const ConstantDataArray *EmbeddedModule = + dyn_cast(GV->getInitializer()); + assert(EmbeddedModule && "EmbededModule must be a constant data array."); + const ArrayType *ArrayTy = EmbeddedModule->getType(); + assert(ArrayTy->getElementType()->isIntegerTy(8) && + "Expected an array of bytes."); + + SmallVector Metadata; + uint64_t ElementCount = ArrayTy->getNumElements(); + Metadata.reserve(ElementCount); + + for (uint64_t I = 0; I != ElementCount; ++I) { + uint64_t Element = EmbeddedModule->getElementAsInteger(I); + assert(Element <= UINT8_MAX && "Element must represent a byte value."); + Metadata.push_back((uint8_t)Element); + } + + OutStreamer->emitXCOFFInfoDirective(Csect->getSymbolTableName(), Metadata); + return; + } + + // Any other special LLVM globals are unexpected. assert(!GV->getName().startswith("llvm.") && "Unhandled intrinsic global variable."); diff --git a/llvm/test/Bitcode/embed-multiple.ll b/llvm/test/Bitcode/embed-multiple.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/embed-multiple.ll @@ -0,0 +1,6 @@ +; RUN: not --crash opt --mtriple powerpc64-unknown-aix < %s -passes=embed-bitcode -S 2>&1 | FileCheck %s + +@a = global i32 1 +@llvm.embedded.module = private constant [4 x i8] c"BC\C0\DE" + +; CHECK: LLVM ERROR: Can only embed the module once. diff --git a/llvm/test/Bitcode/embed-unsupported-object-format.ll b/llvm/test/Bitcode/embed-unsupported-object-format.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/embed-unsupported-object-format.ll @@ -0,0 +1,5 @@ +; RUN: not --crash opt --mtriple powerpc64le-unknown-linux < %s -passes=embed-bitcode -S 2>&1 | FileCheck %s + +@a = global i32 1 + +; CHECK: LLVM ERROR: Embed bitcode pass currently only supports XCOFF object format. diff --git a/llvm/test/Bitcode/embed.ll b/llvm/test/Bitcode/embed.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/embed.ll @@ -0,0 +1,9 @@ +; RUN: opt --mtriple powerpc64-unknown-aix < %s -passes=embed-bitcode -S | FileCheck %s + + target triple = "powerpc-ibm-aix7.2.0.0" + + @a = global i32 1 + + ; CHECK: @a = global i32 1 + ; CHECK: @llvm.embedded.module = private constant [1288 x i8] c"{{.*}}", section "LLVMLTO", align 1 + ; CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @llvm.embedded.module], section "llvm.metadata" diff --git a/llvm/test/CodeGen/PowerPC/aix-embeded-bitcode.ll b/llvm/test/CodeGen/PowerPC/aix-embeded-bitcode.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-embeded-bitcode.ll @@ -0,0 +1,27 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \ +; RUN: FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \ +; RUN: FileCheck %s + +; CHECK-NOT: .info , 0x434d444c, 0x494e4500 +; CHECK: .info , 0xffffffff # Magic +; CHECK: .info , 0x00000000, 0x00000c24 # Length +; CHECK: .info , 0x4c4c564d, 0x4c544f00 # Identifier string +; CHECK: .info , 0x00000018 # Size difference +; CHECK: .info , 0x4243c0de, +; CHECK-NOT: .info , 0x434d444c, 0x494e4500 + +@.str = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 +@a = external local_unnamed_addr global i32, align 4 +@llvm.embedded.module = private constant [3084 x i8] c"BC\C0\DE5\14\00\00\05\00\00\00b\0C0$MY\BEf\9D\FB\B4O\1B\C8$D\012\05\00!\0C\00\00\B0\02\00\00\0B\02!\00\02\00\00\00\16\00\00\00\07\81#\91A\C8\04I\06\1029\92\01\84\0C%\05\08\19\1E\04\8Bb\80\10E\02B\92\0BB\84\102\148\08\18K\0A2B\88Hp\C4!#D\12\87\8C\10A\92\02d\C8\08\B1\14 CF\88 \C9\012B\84\18*(*\901|\B0\\\91 \C4\C8\00\00\00\89 \00\00\0F\00\00\002\22\08\09 bF\00!+$\98\10!%$\98\10\19'\0C\85\A4\90`Bd\\ $d\82\A0\99#@\B4\01(\E6\08\C0\80\C6\04CE`\849\C2\81\809\02P\18\01\00\00Q\18\00\00\FB\00\00\00\1Bx%\F8\FF\FF\FF\FF\01\90\08s\90\87ph\87rh\03xx\87tp\07z(\07y\00\DC\E1\1D\DC\A1\1C\00\A2\1D\D2\C1\1D\DA\80\1D\CA\E1\1C\C2\81\1D\DA\C0\1E\CAa\1C\E8\E1\1D\E4\A1\0D\EE!\1D\C8\81\1E\D0\01\80\03\80p\87wh\03z\90\87p\80\07xH\07w8\876h\87p\A0\07t\00\E8A\1E\EA\A1\1C\00b\1E\E8!\1C\C6a\1D\DA\00\1E\E4\E1\1D\E8\A1\1C\C6\81\1E\DEA\1E\DA@\1C\EA\C1\1C\CC\A1\1C\E4\A1\0D\E6!\1D\F4\A1\1C\00<\00\08z\08\07y8\87r\A0\876\18\07x\A8\07\00\1E\EEA\1E\EE\00 \E8!\1C\E4\E1\1C\CA\81\1E\DA\C0\1C\CA!\1C\E8\A1\1E\E4\A1\1C\E6\01X\83p`\07zH\07{(\87q`\835\10\07x(\07yh\07r`\835(\07|\A0\07rH\07{`\835H\87y\08\876\B0\079\80\03;h\83tp\87y\A0\07y\A8\87q\A0\87tx\07w\98\076X\03{\98\07|`\836\18\07y\10\87t\A0\87y`\836\18\07y\C8\07x\A0\87w`\836 \87t\90\87r\18\07zh\83vx\07{(\076h\03t\A0\87v`\836H\87y\08\876\B0\079\80\83;h\83tp\87y\A0\07y\A8\87q\A0\87tx\07w\98\076h\83t\98\87ph\03{\98\038h\83tp\87y\A0\07y\A8\87q\A0\87tx\07w\98\076h\03xx\87{(\07y\C0\836\B0\87r\18\07zx\07y`\836\80\87w\B8\87r\90\87\C0\03=\BC\03\1B\B4\019\A4\83<\94\C38\D0C\1B\B4\C3;\D8C9\B0A\1B\A0\03=\B4\03\1B\B4A:\CCC8\B4\81=\C8\01\1C\DCA\1B\A4\83;\CC\03=\C8C=\8C\03=\A4\C3;\B8\C3<\B0A\1B\A4\C3<\84C\1B\D8\C3\1C\C0A\1B\A4\83;\CC\03=\C8C=\8C\03=\A4\C3;\B8\C3<\B0A\1B\C0\C3;\DCC9\C8\03\1E\B4\81=\94\C38\D0\C3;\C8\03\1B\B4\01<\BC\C3=\94\83<\E4A\1B\D8C9\8C\03=\BC\83<\B0A\1B\C0\83<\A4\83=\A4\03;\94\C39\94\039\B0A\1B\C4C=\84\039\DC\C3;\C8\039\B4A8\D0\C3;\B4C:\8C\C3<\B0A\1B\C8\C3;\C0C\1B\C0\83<\BC\03=\94\C38\D0\03\1B\B4\C1<\C0C9\00\1B\88!\00Ha\03A\FC\FF\FF\FF\FF\00H\00\00I\18\00\00\03\00\00\00\13\82`\82 \0C\13\04b\00\00\00\13,xx\87{(\07y\80\87qh\83t\10\87vh\83pH\07|\B8\037\90\037\80\037\80\83\0DX)\B4A;\E8A8\B4\01<\E8\C1\1C\C8\81\1E\CC\81\1C\B4A:\D8\01\1D\E8\81\1D\D0A\1B\B8\C3\1C\C8\81\D2\03B\84D\90!#ED\00\8D\10\865\18\00i|a\C7\04\10\C1\A0$\01\00\00\01\00\00@@\00\C0\8E\89\08\06\01\00\06\00\00\04\00\00\00\80\00\80!UA\14\00\00\04\00\00\00\02\00\00\00\00\00\040\A4J\1A\04\08\00\01\00\00@\00\00\00\00\00\80\00$6\08\14\A6\15\00\00\C8\02\01\00\0A\00\00\002\1E\98\10\19\11L\90\8C\09&G\C6\04C\9A\12(\82r\18\01\A0\1D\01\A0P\06Yf\B3\DF\A0\EB[\CE&\87\00\00\B1\18\00\00\9B\00\00\003\08\80\1C\C4\E1\1Cf\14\01=\88C8\84\C3\8CB\80\07yx\07s\98q\0C\E6\00\0F\ED\10\0E\F4\80\0E3\0CB\1E\C2\C1\1D\CE\A1\1Cf0\05=\88C8\84\83\1B\CC\03=\C8C=\8C\03=\CCx\8Ctp\07{\08\07yH\87pp\07zp\03vx\87p \87\19\CC\11\0E\EC\90\0E\E10\0Fn0\0F\E3\F0\0E\F0P\0E3\10\C4\1D\DE!\1C\D8!\1D\C2a\1Ef0\89;\BC\83;\D0C9\B4\03<\BC\83<\84\03;\CC\F0\14v`\07{h\077h\87rh\077\80\87p\90\87p`\07v(\07v\F8\05vx\87w\80\87_\08\87q\18\87r\98\87y\98\81,\EE\F0\0E\EE\E0\0E\F5\C0\0E\EC0\03b\C8\A1\1C\E4\A1\1C\CC\A1\1C\E4\A1\1C\DCa\1C\CA!\1C\C4\81\1D\CAa\06\D6\90C9\C8C9\98C9\C8C9\B8\C38\94C8\88\03;\94\C3/\BC\83<\FC\82;\D4\03;\B0\C3\0C\C7i\87pX\87rp\83th\07x`\87t\18\87t\A0\87\19\CES\0F\EE\00\0F\F2P\0E\E4\90\0E\E3@\0F\E1 \0E\ECP\0E3 (\1D\DC\C1\1E\C2A\1E\D2!\1C\DC\81\1E\DC\E0\1C\E4\E1\1D\EA\01\1Ef\18Q8\B0C:\9C\83;\CCP$v`\07{h\077`\87wx\07x\98QL\F4\90\0F\F0P\0E3\1Ej\1E\CAa\1C\E8!\1D\DE\C1\1D~\01\1E\E4\A1\1C\CC!\1D\F0a\06T\85\838\CC\C3;\B0C=\D0C9\FC\C2<\E4C;\88\C3;\B0\C3\8C\C5\0A\87y\98\87w\18\87t\08\07z(\07r\98\81\\\E3\10\0E\EC\C0\0E\E5P\0E\F30#\C1\D2A\1E\E4\E1\17\D8\E1\1D\DE\01\1EfH\19;\B0\83=\B4\83\1B\84\C38\8CC9\CC\C3<\B8\C19\C8\C3;\D4\03<\CCH\B4q\08\07v`\07q\08\87qX\87\19\DB\C6\0E\EC`\0F\ED\E0\06\F0 \0F\E50\0F\E5 \0F\F6P\0En\10\0E\E30\0E\E50\0F\F3\E0\06\E9\E0\0E\E4P\0E\F80#\E2\ECa\1C\C2\81\1D\D8\E1\17\EC!\1D\E6!\1D\C4!\1D\D8!\1D\E8!\1Ff \9D;\BCC=\B8\039\94\839\CCX\BCpp\07wx\07z\08\07zH\87wp\87\19\CB\E7\0E\EF0\0F\E1\E0\0E\E9@\0F\E9\A0\0F\E5\00y \00\00<\00\00\00r\1EH C\88\0C\19\09r2H #\81\8C\91\91\D1D\A0\10(d<12B\8E\90!\A3X \FD\00JrH\A9\00\00\00\00wchar_sizePIC LevelThinLTOEnableSplitLTOUnitXL C/C++ for AIX, (IBM Internal Development Branch), clang version 15.0.0\00\00\00#\08\031\820\14#\08\831\820\1C3\0CFp\CC0 \C21\C3`\0C\C9\0C\83A\183\04\85\8C\04&(#66\BB6\97\B67\B2:\B62\173\B6\B0\B3\B9Q\88DY\98T\D8\D8\EC\DA\\\D2\C8\CA\DC\E8F\09\1A\00\A9\18\00\00%\00\00\00\0B\0Ar(\87w\80\07zXp\98C=\B8\C38\B0C9\D0\C3\82\E6\1C\C6\A1\0D\E8A\1E\C2\C1\1D\E6!\1D\E8!\1D\DE\C1\1D\164\E3`\0E\E7P\0F\E1 \0F\E4@\0F\E1 \0F\E7P\0E\F4\B0\80\81\07y(\87p`\07vx\87q\08\07z(\07rXp\9C\C38\B4\01;\A4\83=\94\C3\02k\1C\D8!\1C\DC\E1\1C\DC \1C\E4a\1C\DC \1C\E8\81\1E\C2a\1C\D0\A1\1C\C8a\1C\C2\81\1D\D8a\C1\01\0F\F4 \0F\E1P\0F\F4\80\0E\00\00\00\00\D1\10\00\00\06\00\00\00\07\CC<\A4\83;\9C\03;\94\03=\A0\83<\94C8\90\C3\01\00\00\00a \00\00'\00\00\00\13\04A,\10\00\00\00\03\00\00\00tC\1D\81\00\0C\C7p\00\00\00\00\F10\00\00\12\00\00\00\22G\C8\90Q\0E\C4\19\00\00\00\00\C3\13\01\00intomnipotent charSimple C/C++ TBAA\00\13\84\05\D9\10D\1B\06h\926\0C\0F%m\18\AAJ\02\00#\06\C5\10\82`\80 \01-36\08\07\02\00\03\00\00\00\07P\10\CD\14a\B6@\08\C0\B2\00\011\00\00\02\00\00\00[\86 \A8\00\00\00\00\00\00\00\00\C1 \00\00\13\00\00\00\A3\04\C9P\01\22\AA\00!2\84\88\10!B\C4\08\89\1A@\88\0C!\22D\88\101BR\0E\10\22c\84\C4\BC D\86\88\11\12\F2\80\10\19BRZ\10\22d\84J\00\1A@\0C\01\18\00\02\06\0C\00\17\82\82\C1\82\00\00\00\00\00q \00\00\03\00\00\002\0E\10\22\84\02\F6\04\00\00\00\00\00\00\00\00e\0C\00\001\00\00\00\12\03\94x\01\00\00\00\03\00\00\00\16\00\00\00\09\00\00\00L\00\00\00\01\00\00\00X\00\00\00\00\00\00\00X\00\00\00\04\00\00\00\B8\00\00\00\00\00\00\00\1F\00\00\00\16\00\00\005\00\00\00\06\00\00\00\04\00\00\00\00\00\00\00\B8\00\00\00\00\00\00\00\00\00\00\00\04\00\00\00\00\00\00\00\05\00\00\00\04\00\00\00\05\00\00\00\04\00\00\00\FF\FF\FF\FF\00$\00\00\09\00\00\00\0D\00\00\00\09\00\00\00\0D\00\00\00\FF\FF\FF\FF\08$\00\00;\00\00\00\07\00\00\00\00\00\00\00\04\00\00\00\FF\FF\FF\FF\00\18\00\00\04\00\00\00\01\00\00\00\04\00\00\00\01\00\00\00\FF\FF\FF\FF\08\04\00\00\00\00\00\00]\0C\00\00\14\00\00\00\12\03\94\A2\00\00\00\00.stramainexternal_func15.0.0gitpowerpc-ibm-aix7.2.0.0main.cL...str\00\00\00\00\00\00", section "LLVMLTO", align 1 +@llvm.compiler.used = appending global [1 x i8*] [i8* getelementptr inbounds ([3084 x i8], [3084 x i8]* @llvm.embedded.module, i32 0, i32 0)], section "llvm.metadata" + +; Function Attrs: nounwind +define i32 @main() local_unnamed_addr { +entry: + %call = tail call i32 @external_func(i8* noundef getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0)) + %0 = load i32, i32* @a, align 4 + ret i32 %0 +} + +declare i32 @external_func(i8* noundef) local_unnamed_addr diff --git a/llvm/test/CodeGen/PowerPC/aix-embeded-module-padding.ll b/llvm/test/CodeGen/PowerPC/aix-embeded-module-padding.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-embeded-module-padding.ll @@ -0,0 +1,20 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \ +; RUN: FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \ +; RUN: FileCheck %s + +target datalayout = "E-m:a-p:32:32-i64:64-n32" +target triple = "powerpc-ibm-aix7.2.0.0" + +@c = local_unnamed_addr global i8 -85, align 1 +@llvm.embedded.module = private constant [1647 x i8] c"BC\C0\DE5\14\00\00\05\00\00\00b\0C0$MY\BEf\9D\FB\B4O\1B\C8$D\012\05\00!\0C\00\00_\01\00\00\0B\02!\00\02\00\00\00\16\00\00\00\07\81#\91A\C8\04I\06\1029\92\01\84\0C%\05\08\19\1E\04\8Bb\80\0CE\02B\92\0BBd\102\148\08\18K\0A22\88Hp\C4!#D\12\87\8C\10A\92\02d\C8\08\B1\14 CF\88 \C9\0122\84\18*(*\901|\B0\\\91 \C3\C8\00\00\00\89 \00\00\0B\00\00\002\22\C8\08 bF\00!+$\98\0C!%$\98\0C\19'\0C\85\A4\90`2d\\ $c\82\80\98#@\08\03\01s\04`\00\00\13,xx\87{(\07y\80\87qh\83t\10\87vh\83pH\07|\B8\037\90\037\80\037\80\83\0DX)\B4A;\E8A8\B4\01<\E8\C1\1C\C8\81\1E\CC\81\1C\B4A:\D8\01\1D\E8\81\1D\D0A\1B\B8\C3\1C\C8\81\D2\03B\84\04\90!#EB\00\8D\10\86}$\A41\16\E27\16'\00\16_\D8!\01\01 \08@\00\00\80\00\00\00\00\04\80\C4\06\81\C2d\01\00\00Y \00\00\00\07\00\00\002\1E\98\0C\19\11L\90\8C\09&G\C6\04CB\AD\06\D0J\A0\08\CAa\04\00\00\00\B1\18\00\00\9B\00\00\003\08\80\1C\C4\E1\1Cf\14\01=\88C8\84\C3\8CB\80\07yx\07s\98q\0C\E6\00\0F\ED\10\0E\F4\80\0E3\0CB\1E\C2\C1\1D\CE\A1\1Cf0\05=\88C8\84\83\1B\CC\03=\C8C=\8C\03=\CCx\8Ctp\07{\08\07yH\87pp\07zp\03vx\87p \87\19\CC\11\0E\EC\90\0E\E10\0Fn0\0F\E3\F0\0E\F0P\0E3\10\C4\1D\DE!\1C\D8!\1D\C2a\1Ef0\89;\BC\83;\D0C9\B4\03<\BC\83<\84\03;\CC\F0\14v`\07{h\077h\87rh\077\80\87p\90\87p`\07v(\07v\F8\05vx\87w\80\87_\08\87q\18\87r\98\87y\98\81,\EE\F0\0E\EE\E0\0E\F5\C0\0E\EC0\03b\C8\A1\1C\E4\A1\1C\CC\A1\1C\E4\A1\1C\DCa\1C\CA!\1C\C4\81\1D\CAa\06\D6\90C9\C8C9\98C9\C8C9\B8\C38\94C8\88\03;\94\C3/\BC\83<\FC\82;\D4\03;\B0\C3\0C\C7i\87pX\87rp\83th\07x`\87t\18\87t\A0\87\19\CES\0F\EE\00\0F\F2P\0E\E4\90\0E\E3@\0F\E1 \0E\ECP\0E3 (\1D\DC\C1\1E\C2A\1E\D2!\1C\DC\81\1E\DC\E0\1C\E4\E1\1D\EA\01\1Ef\18Q8\B0C:\9C\83;\CCP$v`\07{h\077`\87wx\07x\98QL\F4\90\0F\F0P\0E3\1Ej\1E\CAa\1C\E8!\1D\DE\C1\1D~\01\1E\E4\A1\1C\CC!\1D\F0a\06T\85\838\CC\C3;\B0C=\D0C9\FC\C2<\E4C;\88\C3;\B0\C3\8C\C5\0A\87y\98\87w\18\87t\08\07z(\07r\98\81\\\E3\10\0E\EC\C0\0E\E5P\0E\F30#\C1\D2A\1E\E4\E1\17\D8\E1\1D\DE\01\1EfH\19;\B0\83=\B4\83\1B\84\C38\8CC9\CC\C3<\B8\C19\C8\C3;\D4\03<\CCH\B4q\08\07v`\07q\08\87qX\87\19\DB\C6\0E\EC`\0F\ED\E0\06\F0 \0F\E50\0F\E5 \0F\F6P\0En\10\0E\E30\0E\E50\0F\F3\E0\06\E9\E0\0E\E4P\0E\F80#\E2\ECa\1C\C2\81\1D\D8\E1\17\EC!\1D\E6!\1D\C4!\1D\D8!\1D\E8!\1Ff \9D;\BCC=\B8\039\94\839\CCX\BCpp\07wx\07z\08\07zH\87wp\87\19\CB\E7\0E\EF0\0F\E1\E0\0E\E9@\0F\E9\A0\0F\E5\00y \00\00>\00\00\00r\1EH C\88\0C\19\09r2H #\81\8C\91\91\D1D\A0\10(d<12B\8E\90!\A3X &\01JrH\B2\00\00\00\00wchar_sizePIC LevelThinLTOEnableSplitLTOUnitIBM Open XL C/C++ for AIX, (IBM Internal Development Branch), clang version 15.0.0\00\00#\08\830\820\0C#\08\031\820\143\0CFp\CC0 \C21\C3`\0C\C9\0C\83A\183\04\85\8C\04&(#66\BB6\97\B67\B2:\B62\173\B6\B0\B3\B9Q\88DY\98T\D8\D8\EC\DA\\\D2\C8\CA\DC\E8F\09\1A\00\A9\18\00\00%\00\00\00\0B\0Ar(\87w\80\07zXp\98C=\B8\C38\B0C9\D0\C3\82\E6\1C\C6\A1\0D\E8A\1E\C2\C1\1D\E6!\1D\E8!\1D\DE\C1\1D\164\E3`\0E\E7P\0F\E1 \0F\E4@\0F\E1 \0F\E7P\0E\F4\B0\80\81\07y(\87p`\07vx\87q\08\07z(\07rXp\9C\C38\B4\01;\A4\83=\94\C3\02k\1C\D8!\1C\DC\E1\1C\DC \1C\E4a\1C\DC \1C\E8\81\1E\C2a\1C\D0\A1\1C\C8a\1C\C2\81\1D\D8a\C1\01\0F\F4 \0F\E1P\0F\F4\80\0E\00\00\00\00\D1\10\00\00\06\00\00\00\07\CC<\A4\83;\9C\03;\94\03=\A0\83<\94C8\90\C3\01\00\00\00q \00\00\02\00\00\002\0E\10\22\04\00\00\00\00\00\00\00e\0C\00\00\1F\00\00\00\12\03\94\F0\00\00\00\00\03\00\00\00\01\00\00\00\09\00\00\00L\00\00\00\01\00\00\00X\00\00\00\00\00\00\00X\00\00\00\01\00\00\00p\00\00\00\00\00\00\00\0A\00\00\00\16\00\00\00 \00\00\00\0F\00\00\00\01\00\00\00\00\00\00\00p\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\01\00\00\00\FF\FF\FF\FF\00\04\00\00\00\00\00\00]\0C\00\00\0F\00\00\00\12\03\94o\00\00\00\00c15.0.0gitpowerpc-ibm-aix7.2.0.0single_global.c\00\00\00\00\00\0A\0B\0C", section ".NeedsPadding", align 1 +@llvm.compiler.used = appending global [1 x i8*] [i8* getelementptr inbounds ([1647 x i8], [1647 x i8]* @llvm.embedded.module, i32 0, i32 0)], section "llvm.metadata" + +; CHECK: .info , 0xffffffff # Magic +; CHECK: .info , 0x00000000, 0x00000690 # Length +; CHECK: .info , 0x2e4e6565, 0x64735061, 0x6464696e, 0x67000000 # Identifier string +; CHECK: .info , 0x00000021 # Size difference +;; Start of embeded module +; CHECK: .info , 0x4243c0de, +;; Trailing padding +; CHECK: .info , 0x0a0b0c00 diff --git a/llvm/test/Transforms/Util/embeded-lto-TLI-mappings.ll b/llvm/test/Transforms/Util/embeded-lto-TLI-mappings.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Util/embeded-lto-TLI-mappings.ll @@ -0,0 +1,20 @@ +; RUN: opt -vector-library=MASSV -passes='function(inject-tli-mappings),embed-bitcode' -S < %s | FileCheck %s + +target triple = "powerpc-unknown-aix" + +; CHECK: @llvm.compiler.used = appending global [3 x ptr] [ptr @__sind2, ptr @__log10f4, ptr @llvm.embedded.module], section "llvm.metadata" + +define double @sin_f64(double %in) { + %call = tail call double @sin(double %in) + ret double %call +} + +declare double @sin(double) #0 + +define float @call_llvm.log10.f32(float %in) { + %call = tail call float @llvm.log10.f32(float %in) + ret float %call +} + +declare float @llvm.log10.f32(float) #0 +attributes #0 = { nounwind readnone }