diff options
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/lli/ForwardingMemoryManager.h | 7 | ||||
-rw-r--r-- | llvm/tools/llvm-offload-binary/CMakeLists.txt | 13 | ||||
-rw-r--r-- | llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp | 259 | ||||
-rw-r--r-- | llvm/tools/llvm-profdata/CMakeLists.txt | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/DeltaManager.cpp | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/DeltaPasses.def | 2 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.cpp | 103 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.h | 18 |
10 files changed, 403 insertions, 11 deletions
diff --git a/llvm/tools/lli/ForwardingMemoryManager.h b/llvm/tools/lli/ForwardingMemoryManager.h index e5c10d6..d193bef 100644 --- a/llvm/tools/lli/ForwardingMemoryManager.h +++ b/llvm/tools/lli/ForwardingMemoryManager.h @@ -109,8 +109,11 @@ public: if (Syms->size() != 1) return make_error<StringError>("Unexpected remote lookup result", inconvertibleErrorCode()); - return JITSymbol(Syms->front().getAddress().getValue(), - Syms->front().getFlags()); + if (!Syms->front()) + return make_error<StringError>("Expected valid address", + inconvertibleErrorCode()); + return JITSymbol(Syms->front()->getAddress().getValue(), + Syms->front()->getFlags()); } else return Syms.takeError(); } diff --git a/llvm/tools/llvm-offload-binary/CMakeLists.txt b/llvm/tools/llvm-offload-binary/CMakeLists.txt new file mode 100644 index 0000000..6f46f1b --- /dev/null +++ b/llvm/tools/llvm-offload-binary/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_LINK_COMPONENTS + BinaryFormat + Object + Support) + +add_llvm_tool(llvm-offload-binary + llvm-offload-binary.cpp + + DEPENDS + intrinsics_gen + ) +# Legacy binary name to be removed at a later release. +add_llvm_tool_symlink(clang-offload-packager llvm-offload-binary) diff --git a/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp b/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp new file mode 100644 index 0000000..b1bc335 --- /dev/null +++ b/llvm/tools/llvm-offload-binary/llvm-offload-binary.cpp @@ -0,0 +1,259 @@ +//===-- llvm-offload-binary.cpp - offload binary management utility -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This tool takes several device object files and bundles them into a single +// binary image using a custom binary format. This is intended to be used to +// embed many device files into an application to create a fat binary. It also +// supports extracting these files from a known location. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/OffloadBinary.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace llvm::object; + +static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); + +static cl::OptionCategory OffloadBinaryCategory("llvm-offload-binary options"); + +static cl::opt<std::string> OutputFile("o", cl::desc("Write output to <file>."), + cl::value_desc("file"), + cl::cat(OffloadBinaryCategory)); + +static cl::opt<std::string> InputFile(cl::Positional, + cl::desc("Extract from <file>."), + cl::value_desc("file"), + cl::cat(OffloadBinaryCategory)); + +static cl::list<std::string> + DeviceImages("image", + cl::desc("List of key and value arguments. Required keywords " + "are 'file' and 'triple'."), + cl::value_desc("<key>=<value>,..."), + cl::cat(OffloadBinaryCategory)); + +static cl::opt<bool> + CreateArchive("archive", + cl::desc("Write extracted files to a static archive"), + cl::cat(OffloadBinaryCategory)); + +/// Path of the current binary. +static const char *PackagerExecutable; + +// Get a map containing all the arguments for the image. Repeated arguments will +// be placed in a comma separated list. +static DenseMap<StringRef, StringRef> getImageArguments(StringRef Image, + StringSaver &Saver) { + DenseMap<StringRef, StringRef> Args; + for (StringRef Arg : llvm::split(Image, ",")) { + auto [Key, Value] = Arg.split("="); + auto [It, Inserted] = Args.try_emplace(Key, Value); + if (!Inserted) + It->second = Saver.save(It->second + "," + Value); + } + + return Args; +} + +static Error writeFile(StringRef Filename, StringRef Data) { + Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = + FileOutputBuffer::create(Filename, Data.size()); + if (!OutputOrErr) + return OutputOrErr.takeError(); + std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); + llvm::copy(Data, Output->getBufferStart()); + if (Error E = Output->commit()) + return E; + return Error::success(); +} + +static Error bundleImages() { + SmallVector<char, 1024> BinaryData; + raw_svector_ostream OS(BinaryData); + for (StringRef Image : DeviceImages) { + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + DenseMap<StringRef, StringRef> Args = getImageArguments(Image, Saver); + + if (!Args.count("triple") || !Args.count("file")) + return createStringError( + inconvertibleErrorCode(), + "'file' and 'triple' are required image arguments"); + + // Permit using multiple instances of `file` in a single string. + for (auto &File : llvm::split(Args["file"], ",")) { + OffloadBinary::OffloadingImage ImageBinary{}; + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr = + llvm::MemoryBuffer::getFileOrSTDIN(File); + if (std::error_code EC = ObjectOrErr.getError()) + return errorCodeToError(EC); + + // Clang uses the '.o' suffix for LTO bitcode. + if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode) + ImageBinary.TheImageKind = object::IMG_Bitcode; + else if (sys::path::has_extension(File)) + ImageBinary.TheImageKind = + getImageKind(sys::path::extension(File).drop_front()); + else + ImageBinary.TheImageKind = IMG_None; + ImageBinary.Image = std::move(*ObjectOrErr); + for (const auto &[Key, Value] : Args) { + if (Key == "kind") { + ImageBinary.TheOffloadKind = getOffloadKind(Value); + } else if (Key != "file") { + ImageBinary.StringData[Key] = Value; + } + } + llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); + if (Buffer.size() % OffloadBinary::getAlignment() != 0) + return createStringError(inconvertibleErrorCode(), + "Offload binary has invalid size alignment"); + OS << Buffer; + } + } + + if (Error E = writeFile(OutputFile, + StringRef(BinaryData.begin(), BinaryData.size()))) + return E; + return Error::success(); +} + +static Error unbundleImages() { + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = + MemoryBuffer::getFileOrSTDIN(InputFile); + if (std::error_code EC = BufferOrErr.getError()) + return createFileError(InputFile, EC); + std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrErr); + + // This data can be misaligned if extracted from an archive. + if (!isAddrAligned(Align(OffloadBinary::getAlignment()), + Buffer->getBufferStart())) + Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), + Buffer->getBufferIdentifier()); + + SmallVector<OffloadFile> Binaries; + if (Error Err = extractOffloadBinaries(*Buffer, Binaries)) + return Err; + + // Try to extract each device image specified by the user from the input file. + for (StringRef Image : DeviceImages) { + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + auto Args = getImageArguments(Image, Saver); + + SmallVector<const OffloadBinary *> Extracted; + for (const OffloadFile &File : Binaries) { + const auto *Binary = File.getBinary(); + // We handle the 'file' and 'kind' identifiers differently. + bool Match = llvm::all_of(Args, [&](auto &Arg) { + const auto [Key, Value] = Arg; + if (Key == "file") + return true; + if (Key == "kind") + return Binary->getOffloadKind() == getOffloadKind(Value); + return Binary->getString(Key) == Value; + }); + if (Match) + Extracted.push_back(Binary); + } + + if (Extracted.empty()) + continue; + + if (CreateArchive) { + if (!Args.count("file")) + return createStringError(inconvertibleErrorCode(), + "Image must have a 'file' argument."); + + SmallVector<NewArchiveMember> Members; + for (const OffloadBinary *Binary : Extracted) + Members.emplace_back(MemoryBufferRef( + Binary->getImage(), + Binary->getMemoryBufferRef().getBufferIdentifier())); + + if (Error E = writeArchive( + Args["file"], Members, SymtabWritingMode::NormalSymtab, + Archive::getDefaultKind(), true, false, nullptr)) + return E; + } else if (auto It = Args.find("file"); It != Args.end()) { + if (Extracted.size() > 1) + WithColor::warning(errs(), PackagerExecutable) + << "Multiple inputs match to a single file, '" << It->second + << "'\n"; + if (Error E = writeFile(It->second, Extracted.back()->getImage())) + return E; + } else { + uint64_t Idx = 0; + for (const OffloadBinary *Binary : Extracted) { + StringRef Filename = + Saver.save(sys::path::stem(InputFile) + "-" + Binary->getTriple() + + "-" + Binary->getArch() + "." + std::to_string(Idx++) + + "." + getImageKindName(Binary->getImageKind())); + if (Error E = writeFile(Filename, Binary->getImage())) + return E; + } + } + } + + return Error::success(); +} + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + cl::HideUnrelatedOptions(OffloadBinaryCategory); + cl::ParseCommandLineOptions( + argc, argv, + "A utility for bundling several object files into a single binary.\n" + "The output binary can then be embedded into the host section table\n" + "to create a fatbinary containing offloading code.\n"); + + if (sys::path::stem(argv[0]).ends_with("clang-offload-packager")) + WithColor::warning(errs(), PackagerExecutable) + << "'clang-offload-packager' is deprecated. Use 'llvm-offload-binary' " + "instead.\n"; + + if (Help || (OutputFile.empty() && InputFile.empty())) { + cl::PrintHelpMessage(); + return EXIT_SUCCESS; + } + + PackagerExecutable = argv[0]; + auto reportError = [argv](Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + return EXIT_FAILURE; + }; + + if (!InputFile.empty() && !OutputFile.empty()) + return reportError( + createStringError(inconvertibleErrorCode(), + "Packaging to an output file and extracting from an " + "input file are mutually exclusive.")); + + if (!OutputFile.empty()) { + if (Error Err = bundleImages()) + return reportError(std::move(Err)); + } else if (!InputFile.empty()) { + if (Error Err = unbundleImages()) + return reportError(std::move(Err)); + } + + return EXIT_SUCCESS; +} diff --git a/llvm/tools/llvm-profdata/CMakeLists.txt b/llvm/tools/llvm-profdata/CMakeLists.txt index 165be9a2..e5aa858 100644 --- a/llvm/tools/llvm-profdata/CMakeLists.txt +++ b/llvm/tools/llvm-profdata/CMakeLists.txt @@ -10,9 +10,6 @@ add_llvm_tool(llvm-profdata DEPENDS intrinsics_gen - GENERATE_DRIVER ) -if(NOT LLVM_TOOL_LLVM_DRIVER_BUILD) - target_link_libraries(llvm-profdata PRIVATE LLVMDebuginfod) -endif() +target_link_libraries(llvm-profdata PRIVATE LLVMDebuginfod) diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index d658ea9..15ddb05 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -3464,10 +3464,7 @@ static int order_main() { return 0; } -int llvm_profdata_main(int argc, char **argvNonConst, - const llvm::ToolContext &) { - const char **argv = const_cast<const char **>(argvNonConst); - +int main(int argc, const char *argv[]) { StringRef ProgName(sys::path::filename(argv[0])); if (argc < 2) { diff --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt index 7be90bc..c8673b4 100644 --- a/llvm/tools/llvm-reduce/CMakeLists.txt +++ b/llvm/tools/llvm-reduce/CMakeLists.txt @@ -39,6 +39,7 @@ add_llvm_tool(llvm-reduce deltas/ReduceGlobalValues.cpp deltas/ReduceGlobalVarInitializers.cpp deltas/ReduceGlobalVars.cpp + deltas/ReduceInlineCallSites.cpp deltas/ReduceInstructions.cpp deltas/ReduceInstructionFlags.cpp deltas/ReduceInvokes.cpp diff --git a/llvm/tools/llvm-reduce/DeltaManager.cpp b/llvm/tools/llvm-reduce/DeltaManager.cpp index f5c6276..9b13202 100644 --- a/llvm/tools/llvm-reduce/DeltaManager.cpp +++ b/llvm/tools/llvm-reduce/DeltaManager.cpp @@ -28,6 +28,7 @@ #include "deltas/ReduceGlobalVarInitializers.h" #include "deltas/ReduceGlobalVars.h" #include "deltas/ReduceIRReferences.h" +#include "deltas/ReduceInlineCallSites.h" #include "deltas/ReduceInstructionFlags.h" #include "deltas/ReduceInstructionFlagsMIR.h" #include "deltas/ReduceInstructions.h" diff --git a/llvm/tools/llvm-reduce/DeltaPasses.def b/llvm/tools/llvm-reduce/DeltaPasses.def index 3aed0cc..845b106 100644 --- a/llvm/tools/llvm-reduce/DeltaPasses.def +++ b/llvm/tools/llvm-reduce/DeltaPasses.def @@ -58,7 +58,7 @@ DELTA_PASS_IR("volatile", reduceVolatileInstructionsDeltaPass, "Reducing Volatil DELTA_PASS_IR("atomic-ordering", reduceAtomicOrderingDeltaPass, "Reducing Atomic Ordering") DELTA_PASS_IR("syncscopes", reduceAtomicSyncScopesDeltaPass, "Reducing Atomic Sync Scopes") DELTA_PASS_IR("instruction-flags", reduceInstructionFlagsDeltaPass, "Reducing Instruction Flags") - +DELTA_PASS_IR("inline-call-sites", reduceInlineCallSitesDeltaPass, "Inlining callsites") #ifndef DELTA_PASS_MIR #define DELTA_PASS_MIR(NAME, FUNC, DESC) diff --git a/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.cpp b/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.cpp new file mode 100644 index 0000000..cfef367 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.cpp @@ -0,0 +1,103 @@ +//===- ReduceInlineCallSites.cpp ------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "ReduceInlineCallSites.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils/Cloning.h" + +using namespace llvm; + +extern cl::OptionCategory LLVMReduceOptions; + +static cl::opt<int> CallsiteInlineThreshold( + "reduce-callsite-inline-threshold", + cl::desc("Number of instructions in a function to unconditionally inline " + "(-1 for inline all)"), + cl::init(5), cl::cat(LLVMReduceOptions)); + +static bool functionHasMoreThanNonTerminatorInsts(const Function &F, + uint64_t NumInsts) { + uint64_t InstCount = 0; + for (const BasicBlock &BB : F) { + for (const Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) { + (void)I; + if (InstCount++ > NumInsts) + return true; + } + } + + return false; +} + +static bool hasOnlyOneCallUse(const Function &F) { + unsigned UseCount = 0; + for (const Use &U : F.uses()) { + const CallBase *CB = dyn_cast<CallBase>(U.getUser()); + if (!CB || !CB->isCallee(&U)) + return false; + if (UseCount++ > 1) + return false; + } + + return UseCount == 1; +} + +// TODO: This could use more thought. +static bool inlineWillReduceComplexity(const Function &Caller, + const Function &Callee) { + // Backdoor to force all possible inlining. + if (CallsiteInlineThreshold < 0) + return true; + + if (!hasOnlyOneCallUse(Callee)) + return false; + + // Permit inlining small functions into big functions, or big functions into + // small functions. + if (!functionHasMoreThanNonTerminatorInsts(Callee, CallsiteInlineThreshold) && + !functionHasMoreThanNonTerminatorInsts(Caller, CallsiteInlineThreshold)) + return true; + + return false; +} + +static void reduceCallSites(Oracle &O, Function &F) { + std::vector<std::pair<CallBase *, InlineFunctionInfo>> CallSitesToInline; + + for (Use &U : F.uses()) { + if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) { + // Ignore callsites with wrong call type. + if (!CB->isCallee(&U)) + continue; + + // We do not consider isInlineViable here. It is overly conservative in + // cases that the inliner should handle correctly (e.g. disallowing inline + // of of functions with indirectbr). Some of the other cases are for other + // correctness issues which we do need to worry about here. + + // TODO: Should we delete the function body? + InlineFunctionInfo IFI; + if (CanInlineCallSite(*CB, IFI).isSuccess() && + inlineWillReduceComplexity(*CB->getFunction(), F) && !O.shouldKeep()) + CallSitesToInline.emplace_back(CB, std::move(IFI)); + } + } + + // TODO: InlineFunctionImpl will implicitly perform some simplifications / + // optimizations which we should be able to opt-out of. + for (auto [CB, IFI] : CallSitesToInline) + InlineFunctionImpl(*CB, IFI); +} + +void llvm::reduceInlineCallSitesDeltaPass(Oracle &O, ReducerWorkItem &Program) { + for (Function &F : Program.getModule()) { + if (!F.isDeclaration()) + reduceCallSites(O, F); + } +} diff --git a/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.h b/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.h new file mode 100644 index 0000000..1df31a1 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceInlineCallSites.h @@ -0,0 +1,18 @@ +//===- ReduceInlineCallSites.h ----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINLINECALLSITES_H +#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINLINECALLSITES_H + +#include "Delta.h" + +namespace llvm { +void reduceInlineCallSitesDeltaPass(Oracle &O, ReducerWorkItem &Program); +} // namespace llvm + +#endif |