diff options
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp | 65 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/COFFDump.cpp | 2 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/DXContainerDump.cpp | 30 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/llvm-objdump.cpp | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/llvm-objdump.h | 3 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 2 | ||||
-rw-r--r-- | llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp | 3 | ||||
-rw-r--r-- | llvm/tools/llvm-split/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-split/llvm-split.cpp | 176 | ||||
-rw-r--r-- | llvm/tools/opt/optdriver.cpp | 3 |
11 files changed, 250 insertions, 41 deletions
diff --git a/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp b/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp index f6ed94b..8e17a4a 100644 --- a/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp +++ b/llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp @@ -9,22 +9,22 @@ /// \file /// This file implements the IR2Vec embedding generation tool. /// -/// This tool provides three main modes: +/// This tool provides three main subcommands: /// -/// 1. Triplet Generation Mode (--mode=triplets): +/// 1. Triplet Generation (triplets): /// Generates numeric triplets (head, tail, relation) for vocabulary /// training. Output format: MAX_RELATION=N header followed by /// head\ttail\trelation lines. Relations: 0=Type, 1=Next, 2+=Arg0,Arg1,... -/// Usage: llvm-ir2vec --mode=triplets input.bc -o train2id.txt +/// Usage: llvm-ir2vec triplets input.bc -o train2id.txt /// -/// 2. Entities Generation Mode (--mode=entities): +/// 2. Entity Mappings (entities): /// Generates entity mappings for vocabulary training. /// Output format: <total_entities> header followed by entity\tid lines. -/// Usage: llvm-ir2vec --mode=entities input.bc -o entity2id.txt +/// Usage: llvm-ir2vec entities input.bc -o entity2id.txt /// -/// 3. Embedding Generation Mode (--mode=embeddings): +/// 3. Embedding Generation (embeddings): /// Generates IR2Vec embeddings using a trained vocabulary. -/// Usage: llvm-ir2vec --mode=embeddings --ir2vec-vocab-path=vocab.json +/// Usage: llvm-ir2vec embeddings --ir2vec-vocab-path=vocab.json /// --level=func input.bc -o embeddings.txt Levels: --level=inst /// (instructions), --level=bb (basic blocks), --level=func (functions) /// (See IR2Vec.cpp for more embedding generation options) @@ -55,36 +55,33 @@ namespace ir2vec { static cl::OptionCategory IR2VecToolCategory("IR2Vec Tool Options"); +// Subcommands +static cl::SubCommand + TripletsSubCmd("triplets", "Generate triplets for vocabulary training"); +static cl::SubCommand + EntitiesSubCmd("entities", + "Generate entity mappings for vocabulary training"); +static cl::SubCommand + EmbeddingsSubCmd("embeddings", + "Generate embeddings using trained vocabulary"); + +// Common options static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input bitcode file or '-' for stdin>"), - cl::init("-"), cl::cat(IR2VecToolCategory)); + cl::init("-"), cl::sub(TripletsSubCmd), + cl::sub(EmbeddingsSubCmd), cl::cat(IR2VecToolCategory)); static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::init("-"), cl::cat(IR2VecToolCategory)); -enum ToolMode { - TripletMode, // Generate triplets for vocabulary training - EntityMode, // Generate entity mappings for vocabulary training - EmbeddingMode // Generate embeddings using trained vocabulary -}; - -static cl::opt<ToolMode> Mode( - "mode", cl::desc("Tool operation mode:"), - cl::values(clEnumValN(TripletMode, "triplets", - "Generate triplets for vocabulary training"), - clEnumValN(EntityMode, "entities", - "Generate entity mappings for vocabulary training"), - clEnumValN(EmbeddingMode, "embeddings", - "Generate embeddings using trained vocabulary")), - cl::init(EmbeddingMode), cl::cat(IR2VecToolCategory)); - +// Embedding-specific options static cl::opt<std::string> FunctionName("function", cl::desc("Process specific function only"), cl::value_desc("name"), cl::Optional, cl::init(""), - cl::cat(IR2VecToolCategory)); + cl::sub(EmbeddingsSubCmd), cl::cat(IR2VecToolCategory)); enum EmbeddingLevel { InstructionLevel, // Generate instruction-level embeddings @@ -93,14 +90,15 @@ enum EmbeddingLevel { }; static cl::opt<EmbeddingLevel> - Level("level", cl::desc("Embedding generation level (for embedding mode):"), + Level("level", cl::desc("Embedding generation level:"), cl::values(clEnumValN(InstructionLevel, "inst", "Generate instruction-level embeddings"), clEnumValN(BasicBlockLevel, "bb", "Generate basic block-level embeddings"), clEnumValN(FunctionLevel, "func", "Generate function-level embeddings")), - cl::init(FunctionLevel), cl::cat(IR2VecToolCategory)); + cl::init(FunctionLevel), cl::sub(EmbeddingsSubCmd), + cl::cat(IR2VecToolCategory)); namespace { @@ -291,7 +289,7 @@ public: Error processModule(Module &M, raw_ostream &OS) { IR2VecTool Tool(M); - if (Mode == EmbeddingMode) { + if (EmbeddingsSubCmd) { // Initialize vocabulary for embedding generation // Note: Requires --ir2vec-vocab-path option to be set auto VocabStatus = Tool.initializeVocabulary(); @@ -311,6 +309,7 @@ Error processModule(Module &M, raw_ostream &OS) { Tool.generateEmbeddings(OS); } } else { + // Both triplets and entities use triplet generation Tool.generateTriplets(OS); } return Error::success(); @@ -334,14 +333,6 @@ int main(int argc, char **argv) { "See https://llvm.org/docs/CommandGuide/llvm-ir2vec.html for more " "information.\n"); - // Validate command line options - if (Mode != EmbeddingMode) { - if (Level.getNumOccurrences() > 0) - errs() << "Warning: --level option is ignored\n"; - if (FunctionName.getNumOccurrences() > 0) - errs() << "Warning: --function option is ignored\n"; - } - std::error_code EC; raw_fd_ostream OS(OutputFilename, EC); if (EC) { @@ -349,7 +340,7 @@ int main(int argc, char **argv) { return 1; } - if (Mode == EntityMode) { + if (EntitiesSubCmd) { // Just dump entity mappings without processing any IR IR2VecTool::generateEntityMappings(OS); return 0; diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt index 7e3197f..41d301c 100644 --- a/llvm/tools/llvm-objdump/CMakeLists.txt +++ b/llvm/tools/llvm-objdump/CMakeLists.txt @@ -28,6 +28,7 @@ add_llvm_tool(llvm-objdump llvm-objdump.cpp SourcePrinter.cpp COFFDump.cpp + DXContainerDump.cpp ELFDump.cpp MachODump.cpp OffloadDump.cpp diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp index b22c9a4..de82561 100644 --- a/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/llvm/tools/llvm-objdump/COFFDump.cpp @@ -187,7 +187,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const { Size = Data->Size; } outs() << format("Entry %x ", I) << formatAddr(Addr) - << format(" %08x %s\n", uint32_t(Size), DirName[I]); + << format(" %08x %s\n", Size, DirName[I]); } } diff --git a/llvm/tools/llvm-objdump/DXContainerDump.cpp b/llvm/tools/llvm-objdump/DXContainerDump.cpp new file mode 100644 index 0000000..2fb0734 --- /dev/null +++ b/llvm/tools/llvm-objdump/DXContainerDump.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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 implements the DXContainer-specific dumper for llvm-objdump. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/DXContainer.h" + +using namespace llvm; + +namespace { +class DXContainerDumper : public objdump::Dumper { +public: + DXContainerDumper(const object::DXContainerObjectFile &Obj) + : objdump::Dumper(Obj) {} +}; +} // namespace + +std::unique_ptr<objdump::Dumper> llvm::objdump::createDXContainerDumper( + const object::DXContainerObjectFile &Obj) { + return std::make_unique<DXContainerDumper>(Obj); +} diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 0316c4b..c19c698 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -50,6 +50,7 @@ #include "llvm/Object/BuildID.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/DXContainer.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Object/FaultMapParser.h" @@ -386,6 +387,8 @@ static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) { return createWasmDumper(*O); if (const auto *O = dyn_cast<XCOFFObjectFile>(&Obj)) return createXCOFFDumper(*O); + if (const auto *O = dyn_cast<DXContainerObjectFile>(&Obj)) + return createDXContainerDumper(*O); return createStringError(errc::invalid_argument, "unsupported object file format"); @@ -2736,7 +2739,7 @@ void Dumper::printRelocations() { for (const SectionRef &Section : ToolSectionFilter(O, &Ndx)) { if (O.isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) continue; - if (Section.relocation_begin() == Section.relocation_end()) + if (Section.relocations().empty()) continue; Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); if (!SecOrErr) diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h index ce06429..3525be9 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -36,6 +36,7 @@ class ELFObjectFileBase; class MachOObjectFile; class WasmObjectFile; class XCOFFObjectFile; +class DXContainer; } // namespace object namespace objdump { @@ -105,6 +106,8 @@ std::unique_ptr<Dumper> createELFDumper(const object::ELFObjectFileBase &Obj); std::unique_ptr<Dumper> createMachODumper(const object::MachOObjectFile &Obj); std::unique_ptr<Dumper> createWasmDumper(const object::WasmObjectFile &Obj); std::unique_ptr<Dumper> createXCOFFDumper(const object::XCOFFObjectFile &Obj); +std::unique_ptr<Dumper> +createDXContainerDumper(const object::DXContainerObjectFile &Obj); // Various helper functions. diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 66153ad..26a84fa 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2215,7 +2215,7 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { const uint64_t FileSize = Obj.getBufSize(); const uint64_t DerivedSize = (uint64_t)HashTable->nchain * DynSymRegion->EntSize; - const uint64_t Offset = (const uint8_t *)DynSymRegion->Addr - Obj.base(); + const uint64_t Offset = DynSymRegion->Addr - Obj.base(); if (DerivedSize > FileSize - Offset) reportUniqueWarning( "the size (0x" + Twine::utohexstr(DerivedSize) + diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp index 8b64467..79272fe 100644 --- a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp @@ -73,6 +73,9 @@ static bool shouldReduceOperand(Use &Op) { if (&CB->getCalledOperandUse() == &Op) return false; } + // lifetime intrinsic argument must be an alloca. + if (isa<LifetimeIntrinsic>(Op.getUser())) + return false; return true; } diff --git a/llvm/tools/llvm-split/CMakeLists.txt b/llvm/tools/llvm-split/CMakeLists.txt index 1104e31..b755755 100644 --- a/llvm/tools/llvm-split/CMakeLists.txt +++ b/llvm/tools/llvm-split/CMakeLists.txt @@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS Support Target TargetParser + ipo ) add_llvm_tool(llvm-split diff --git a/llvm/tools/llvm-split/llvm-split.cpp b/llvm/tools/llvm-split/llvm-split.cpp index 9f6678a..97713c4 100644 --- a/llvm/tools/llvm-split/llvm-split.cpp +++ b/llvm/tools/llvm-split/llvm-split.cpp @@ -11,14 +11,19 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/PassInstrumentation.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" @@ -27,7 +32,9 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/TargetParser/Triple.h" +#include "llvm/Transforms/IPO/GlobalDCE.h" #include "llvm/Transforms/Utils/SplitModule.h" +#include "llvm/Transforms/Utils/SplitModuleByCategory.h" using namespace llvm; @@ -70,6 +77,164 @@ static cl::opt<std::string> MCPU("mcpu", cl::desc("Target CPU, ignored if --mtriple is not used"), cl::value_desc("cpu"), cl::cat(SplitCategory)); +enum class SplitByCategoryType { + SBCT_ByModuleId, + SBCT_ByKernel, + SBCT_None, +}; + +static cl::opt<SplitByCategoryType> SplitByCategory( + "split-by-category", + cl::desc("Split by category. If present, splitting by category is used " + "with the specified categorization type."), + cl::Optional, cl::init(SplitByCategoryType::SBCT_None), + cl::values(clEnumValN(SplitByCategoryType::SBCT_ByModuleId, "module-id", + "one output module per translation unit marked with " + "\"module-id\" attribute"), + clEnumValN(SplitByCategoryType::SBCT_ByKernel, "kernel", + "one output module per kernel")), + cl::cat(SplitCategory)); + +static cl::opt<bool> OutputAssembly{ + "S", cl::desc("Write output as LLVM assembly"), cl::cat(SplitCategory)}; + +void writeStringToFile(StringRef Content, StringRef Path) { + std::error_code EC; + raw_fd_ostream OS(Path, EC); + if (EC) { + errs() << formatv("error opening file: {0}, error: {1}\n", Path, + EC.message()); + exit(1); + } + + OS << Content << "\n"; +} + +void writeModuleToFile(const Module &M, StringRef Path, bool OutputAssembly) { + int FD = -1; + if (std::error_code EC = sys::fs::openFileForWrite(Path, FD)) { + errs() << formatv("error opening file: {0}, error: {1}", Path, EC.message()) + << '\n'; + exit(1); + } + + raw_fd_ostream OS(FD, /*ShouldClose*/ true); + if (OutputAssembly) + M.print(OS, /*AssemblyAnnotationWriter*/ nullptr); + else + WriteBitcodeToFile(M, OS); +} + +/// EntryPointCategorizer is used for splitting by category either by module-id +/// or by kernels. It doesn't provide categories for functions other than +/// kernels. Categorizer computes a string key for the given Function and +/// records the association between the string key and an integer category. If a +/// string key is already belongs to some category than the corresponding +/// integer category is returned. +class EntryPointCategorizer { +public: + EntryPointCategorizer(SplitByCategoryType Type) : Type(Type) {} + + EntryPointCategorizer() = delete; + EntryPointCategorizer(EntryPointCategorizer &) = delete; + EntryPointCategorizer &operator=(const EntryPointCategorizer &) = delete; + EntryPointCategorizer(EntryPointCategorizer &&) = default; + EntryPointCategorizer &operator=(EntryPointCategorizer &&) = default; + + /// Returns integer specifying the category for the given \p F. + /// If the given function isn't a kernel then returns std::nullopt. + std::optional<int> operator()(const Function &F) { + if (!isEntryPoint(F)) + return std::nullopt; // skip the function. + + auto StringKey = computeFunctionCategory(Type, F); + if (auto it = StrKeyToID.find(StringRef(StringKey)); it != StrKeyToID.end()) + return it->second; + + int ID = static_cast<int>(StrKeyToID.size()); + return StrKeyToID.try_emplace(std::move(StringKey), ID).first->second; + } + +private: + static bool isEntryPoint(const Function &F) { + if (F.isDeclaration()) + return false; + + return F.getCallingConv() == CallingConv::SPIR_KERNEL || + F.getCallingConv() == CallingConv::AMDGPU_KERNEL || + F.getCallingConv() == CallingConv::PTX_Kernel; + } + + static SmallString<0> computeFunctionCategory(SplitByCategoryType Type, + const Function &F) { + static constexpr char ATTR_MODULE_ID[] = "module-id"; + SmallString<0> Key; + switch (Type) { + case SplitByCategoryType::SBCT_ByKernel: + Key = F.getName().str(); + break; + case SplitByCategoryType::SBCT_ByModuleId: + Key = F.getFnAttribute(ATTR_MODULE_ID).getValueAsString().str(); + break; + default: + llvm_unreachable("unexpected mode."); + } + + return Key; + } + +private: + struct KeyInfo { + static SmallString<0> getEmptyKey() { return SmallString<0>(""); } + + static SmallString<0> getTombstoneKey() { return SmallString<0>("-"); } + + static bool isEqual(const SmallString<0> &LHS, const SmallString<0> &RHS) { + return LHS == RHS; + } + + static unsigned getHashValue(const SmallString<0> &S) { + return llvm::hash_value(StringRef(S)); + } + }; + + SplitByCategoryType Type; + DenseMap<SmallString<0>, int, KeyInfo> StrKeyToID; +}; + +void cleanupModule(Module &M) { + ModuleAnalysisManager MAM; + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + ModulePassManager MPM; + MPM.addPass(GlobalDCEPass()); // Delete unreachable globals. + MPM.run(M, MAM); +} + +Error runSplitModuleByCategory(std::unique_ptr<Module> M) { + size_t OutputID = 0; + auto PostSplitCallback = [&](std::unique_ptr<Module> MPart) { + if (verifyModule(*MPart)) { + errs() << "Broken Module!\n"; + exit(1); + } + + // TODO: DCE is a crucial pass since it removes unused declarations. + // At the moment, LIT checking can't be perfomed without DCE. + cleanupModule(*MPart); + size_t ID = OutputID; + ++OutputID; + StringRef ModuleSuffix = OutputAssembly ? ".ll" : ".bc"; + std::string ModulePath = + (Twine(OutputFilename) + "_" + Twine(ID) + ModuleSuffix).str(); + writeModuleToFile(*MPart, ModulePath, OutputAssembly); + }; + + auto Categorizer = EntryPointCategorizer(SplitByCategory); + splitModuleTransitiveFromEntryPoints(std::move(M), Categorizer, + PostSplitCallback); + return Error::success(); +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); @@ -123,6 +288,17 @@ int main(int argc, char **argv) { Out->keep(); }; + if (SplitByCategory != SplitByCategoryType::SBCT_None) { + auto E = runSplitModuleByCategory(std::move(M)); + if (E) { + errs() << E << "\n"; + Err.print(argv[0], errs()); + return 1; + } + + return 0; + } + if (TM) { if (PreserveLocals) { errs() << "warning: --preserve-locals has no effect when using " diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp index 4a3b058..a185ea4 100644 --- a/llvm/tools/opt/optdriver.cpp +++ b/llvm/tools/opt/optdriver.cpp @@ -224,7 +224,8 @@ static cl::opt<bool> EnableProfileVerification( #else cl::init(false), #endif - cl::desc("Start the pipeline with prof-inject and end it with prof-check")); + cl::desc( + "Start the pipeline with prof-inject and end it with prof-verify")); static cl::opt<std::string> ClDataLayout("data-layout", cl::desc("data layout string to use"), |