From cc95df7d964d6a4feea8af6a51128500014e3ee9 Mon Sep 17 00:00:00 2001 From: alessandra simmons Date: Thu, 20 Nov 2025 12:09:58 -0500 Subject: [PATCH 1/5] [comgr] Initial package support for comgr --- amd/comgr/src/comgr-compiler.cpp | 148 ++++++++++++++++++--- amd/comgr/src/comgr-compiler.h | 1 + amd/comgr/src/comgr-unpackage-command.cpp | 149 ++++++++++++++++++++++ amd/comgr/src/comgr-unpackage-command.h | 48 +++++++ 4 files changed, 326 insertions(+), 20 deletions(-) create mode 100644 amd/comgr/src/comgr-unpackage-command.cpp create mode 100644 amd/comgr/src/comgr-unpackage-command.h diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index 9e53c75e02342..b27df285b71fb 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -20,6 +20,7 @@ #include "comgr-env.h" #include "comgr-spirv-command.h" #include "comgr-unbundle-command.h" +#include "comgr-unpackage-command.h" #include "lld/Common/CommonLinkerContext.h" #include "lld/Common/Driver.h" #include "clang/CodeGen/CodeGenAction.h" @@ -33,6 +34,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/FrontendTool/Utils.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/Constants.h" @@ -57,9 +59,11 @@ #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/OffloadBinary.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" @@ -350,8 +354,8 @@ bool executeAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags, raw_ostream &LogS) { // Get the target specific parser. std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget( - llvm::Triple(Opts.Triple), Error); + const Target *TheTarget = + TargetRegistry::lookupTarget(llvm::Triple(Opts.Triple), Error); if (!TheTarget) { return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; } @@ -378,8 +382,8 @@ bool executeAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags, // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); - std::unique_ptr MRI(TheTarget->createMCRegInfo( - llvm::Triple(Opts.Triple))); + std::unique_ptr MRI( + TheTarget->createMCRegInfo(llvm::Triple(Opts.Triple))); assert(MRI && "Unable to create target register info!"); llvm::MCTargetOptions MCOptions; @@ -408,8 +412,8 @@ bool executeAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags, } std::unique_ptr MOFI(new MCObjectFileInfo()); - std::unique_ptr STI( - TheTarget->createMCSubtargetInfo(llvm::Triple(Opts.Triple), Opts.CPU, FS)); + std::unique_ptr STI(TheTarget->createMCSubtargetInfo( + llvm::Triple(Opts.Triple), Opts.CPU, FS)); MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr); Ctx.setObjectFileInfo(MOFI.get()); @@ -451,8 +455,9 @@ bool executeAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags, // FIXME: There is a bit of code duplication with addPassesToEmitFile. if (Opts.OutputType == AssemblerInvocation::FT_Asm) { std::unique_ptr InstructionPrinter( - TheTarget->createMCInstPrinter( - llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI)); + TheTarget->createMCInstPrinter(llvm::Triple(Opts.Triple), + Opts.OutputAsmVariant, *MAI, *MCII, + *MRI)); std::unique_ptr MCE; std::unique_ptr MAB; if (Opts.ShowEncoding) { @@ -461,7 +466,8 @@ bool executeAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags, MAB.reset(TheTarget->createMCAsmBackend(*STI, *MRI, Options)); } auto FOut = std::make_unique(*Out); - Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), std::move(InstructionPrinter), + Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), + std::move(InstructionPrinter), std::move(MCE), std::move(MAB))); } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { Str.reset(createNullStreamer(Ctx)); @@ -755,8 +761,8 @@ AMDGPUCompiler::executeInProcessDriver(ArrayRef Args) { TheDriver.setCheckInputsExist(false); // We do not want the driver to promote -include into -include-pch. - // Otherwise, the driver may pick PCH in the wrong format, without permissions, - // in the process's CWD. + // Otherwise, the driver may pick PCH in the wrong format, without + // permissions, in the process's CWD. TheDriver.setProbePrecompiled(false); // Log arguments used to build compilation @@ -1435,6 +1441,107 @@ amd_comgr_status_t AMDGPUCompiler::unbundle() { return AMD_COMGR_STATUS_SUCCESS; } +amd_comgr_status_t AMDGPUCompiler::unpackage() { + if (auto Status = createTmpDirs()) { + return Status; + } + + auto Cache = CommandCache::get(LogS); + for (auto *Input : InSet->DataObjects) { + llvm::SmallVector Files; + + llvm::MemoryBufferRef dataBufferRef(Input->Data, "package_data"); + llvm::object::extractOffloadBinaries(dataBufferRef, &Files); + + // Generate random name if none provided + if (!strcmp(Input->Name, "")) { + const size_t BufSize = sizeof(char) * 30; + char *Buf = (char *)malloc(BufSize); + snprintf(Buf, BufSize, "comgr-package-%d.%s", std::rand() % 10000, + FileExtension); + Input->Name = Buf; + } + + // Write input file system so that OffloadBundler API can process + // TODO: Switch write to VFS + SmallString<128> InputFilePath = getFilePath(Input, InputDir); + if (auto Status = outputToFile(Input, InputFilePath)) { + return Status; + } + + // Generate prefix for output files + StringRef OutputPrefix = Input->Name; + size_t Index = OutputPrefix.find_last_of("."); + OutputPrefix = OutputPrefix.substr(0, Index); + + // TODO: Log Command (see linkBitcodeToBitcode() unbundling) + if (env::shouldEmitVerboseLogs()) { + LogS << " Extracting Package:\n" + << " Input Filename: " << InputFilePath << "\n"; + } + + SmallVector OutputFileNames; + SmallVector TargetNames; + for (const OffloadFile &File : Files) { + const OffloadBinary &Binary = File.getBinary(); + StringRef Triple = Binary->getTriple(); + + const char *FileExtension; + switch (Binary->getImageKind()) { + case IMG_Object: + FileExtension = "o"; + break; + case IMG_Bitcode: + FileExtension = "bc"; + break; + case IMG_Cubin: + FileExtension = "cubin"; + break; + case IMG_Fatbinary: + FileExtension = "fatbin"; + break; + case IMG_PTX: + FileExtension = "ptx"; + break; + case IMG_SPIRV: + FileExtension = "spv"; + break; + default: + FileExtension = "unknown"; + break; + } + + SmallString<128> OutputFilePath = OutputDir; + sys::path::append(OutputFilePath, + OutputPrefix + "-" + Triple + "." + FileExtension); + + OutputFileNames.emplace_back(OutputFilePath); + TargetNames.emplace_back(Triple); + + if (env::shouldEmitVerboseLogs()) { + LogS << "\tPackage Entry Target: " << Triple << "\n" + << "\tOutput Filename: " << OutputFilePath << "\n"; + LogS.flush(); + } + } + + UnpackageCommand Unpackage(Files, OutputFileNames, TargetNames); + if (Cache) { + if (auto Status = Cache->execute(Unbundle, LogS)) { + return Status; + } + } else { + if (auto Status = Unpackage.execute(LogS)) { + return Status; + } + } + + // TODO: create OutSetT entries + } + + return AMD_COMGR_STATUS_SUCCESS; +} + amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { if (auto Status = createTmpDirs()) { return Status; @@ -1472,8 +1579,8 @@ amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { if (Input->DataKind == AMD_COMGR_DATA_KIND_BC) { if (env::shouldEmitVerboseLogs()) { - LogS << "\t Linking Bitcode: " << InputDir << path::get_separator() << Input->Name - << "\n"; + LogS << "\t Linking Bitcode: " << InputDir << path::get_separator() + << Input->Name << "\n"; } // The data in Input outlives Mod, and the linker destructs Mod after @@ -1494,8 +1601,8 @@ amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { return AMD_COMGR_STATUS_ERROR; } else if (Input->DataKind == AMD_COMGR_DATA_KIND_BC_BUNDLE) { if (env::shouldEmitVerboseLogs()) { - LogS << " Linking Bundle: " << InputDir << path::get_separator() << Input->Name - << "\n"; + LogS << " Linking Bundle: " << InputDir << path::get_separator() + << Input->Name << "\n"; } // Determine desired bundle entry ID @@ -1537,7 +1644,8 @@ amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { // on Windows. Replace with '_' std::replace(OutputFileName.begin(), OutputFileName.end(), ':', '_'); - std::string OutputFilePath = OutputDir.str().str() + path::get_separator().str() + OutputFileName; + std::string OutputFilePath = + OutputDir.str().str() + path::get_separator().str() + OutputFileName; BundlerConfig.OutputFileNames.push_back(OutputFilePath); OffloadBundler Bundler(BundlerConfig); @@ -1592,8 +1700,8 @@ amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { // Unbundle bitcode archive else if (Input->DataKind == AMD_COMGR_DATA_KIND_AR_BUNDLE) { if (env::shouldEmitVerboseLogs()) { - LogS << "\t Linking Archive: " << InputDir << path::get_separator() << Input->Name - << "\n"; + LogS << "\t Linking Archive: " << InputDir << path::get_separator() + << Input->Name << "\n"; } // Determine desired bundle entry ID @@ -1638,7 +1746,8 @@ amd_comgr_status_t AMDGPUCompiler::linkBitcodeToBitcode() { // on Windows. Replace with '_' std::replace(OutputFileName.begin(), OutputFileName.end(), ':', '_'); - std::string OutputFilePath = OutputDir.str().str() + path::get_separator().str() + OutputFileName; + std::string OutputFilePath = + OutputDir.str().str() + path::get_separator().str() + OutputFileName; BundlerConfig.OutputFileNames.push_back(OutputFilePath); OffloadBundler Bundler(BundlerConfig); @@ -2179,7 +2288,6 @@ amd_comgr_status_t AMDGPUCompiler::compileSourceToSpirv() { Args.push_back("--no-gpu-bundle-output"); Args.push_back("-c"); - #if _WIN32 Args.push_back("-fshort-wchar"); #endif diff --git a/amd/comgr/src/comgr-compiler.h b/amd/comgr/src/comgr-compiler.h index a950a130ecc41..2e9dcc1ad84ab 100644 --- a/amd/comgr/src/comgr-compiler.h +++ b/amd/comgr/src/comgr-compiler.h @@ -72,6 +72,7 @@ class AMDGPUCompiler { amd_comgr_status_t compileToBitcode(bool WithDeviceLibs = false); amd_comgr_status_t compileToRelocatable(); amd_comgr_status_t unbundle(); + amd_comgr_status_t unpackage(); amd_comgr_status_t linkBitcodeToBitcode(); amd_comgr_status_t codeGenBitcodeToRelocatable(); amd_comgr_status_t codeGenBitcodeToAssembly(); diff --git a/amd/comgr/src/comgr-unpackage-command.cpp b/amd/comgr/src/comgr-unpackage-command.cpp new file mode 100644 index 0000000000000..a3a5cb11e52f6 --- /dev/null +++ b/amd/comgr/src/comgr-unpackage-command.cpp @@ -0,0 +1,149 @@ +//===- comgr-unpackage-command.cpp - UnpackageCommand implementation +//--------===// +// +// Part of Comgr, under the Apache License v2.0 with LLVM Exceptions. See +// amd/comgr/LICENSE.TXT in this repository for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the CacheCommandAdaptor interface for +/// llvm::object::OffloadFile::extractOffloadBinaries() routines +/// that are stored in the cache. +/// +//===----------------------------------------------------------------------===// + +#include + +#include +#include +#include +#include +#include + +namespace COMGR { +using namespace llvm; +using namespace clang; + +using SizeFieldType = uint32_t; + +bool UnpackageCommand::canCache() const { + // TODO: when llvm-offload-binary gets compression support, investigate + // caching compressed packages + return false; +} + +Error UnpackageCommand::writeExecuteOutput(StringRef CachedBuffer) { + for (StringRef OutputFilename : OutputFileNames) { + SizeFieldType OutputFileSize; + if (CachedBuffer.size() < sizeof(OutputFileSize)) + return createStringError(std::errc::invalid_argument, + "Not enough bytes to read output file size"); + memcpy(&OutputFileSize, CachedBuffer.data(), sizeof(OutputFileSize)); + CachedBuffer = CachedBuffer.drop_front(sizeof(OutputFileSize)); + + if (CachedBuffer.size() < OutputFileSize) + return createStringError(std::errc::invalid_argument, + "Not enough bytes to read output file contents"); + + StringRef OutputFileContents = CachedBuffer.substr(0, OutputFileSize); + CachedBuffer = CachedBuffer.drop_front(OutputFileSize); + + if (Error Err = CachedCommandAdaptor::writeSingleOutputFile( + OutputFilename, OutputFileContents)) + return Err; + } + + if (!CachedBuffer.empty()) + return createStringError(std::errc::invalid_argument, + "Bytes in cache entry not used for the output"); + return Error::success(); +} + +Expected UnpackageCommand::readExecuteOutput() { + size_t OutputSize = 0; + for (StringRef OutputFilename : OutputFileNames) { + auto MaybeOneOutput = + CachedCommandAdaptor::readSingleOutputFile(OutputFilename); + if (!MaybeOneOutput) + return MaybeOneOutput.takeError(); + + const MemoryBuffer &OneOutputBuffer = **MaybeOneOutput; + SizeFieldType OneOutputFileSize = OneOutputBuffer.getBufferSize(); + + OutputBuffer.resize_for_overwrite(OutputSize + sizeof(OneOutputFileSize) + + OneOutputFileSize); + + memcpy(OutputBuffer.data() + OutputSize, &OneOutputFileSize, + sizeof(OneOutputFileSize)); + OutputSize += sizeof(OneOutputFileSize); + memcpy(OutputBuffer.data() + OutputSize, OneOutputBuffer.getBufferStart(), + OneOutputFileSize); + OutputSize += OneOutputFileSize; + } + return OutputBuffer; +} + +amd_comgr_status_t UnpackageCommand::execute(raw_ostream &LogS) { + StringMap Worklist; + auto Output = OutputFileNames.begin(); + for (auto &Triple : TargetNames) { + // TODO: check that triples are valid for a package + Worklist[Triple] = *Output; + ++Output; + } + + for (const OffloadFile &File : Files) { + const OffloadBinary &Binary = File.getBinary(); + StringRef Triple = Binary->getTriple(); + + // TODO: does this instead need to check that the triples are compatible? + // (rather than simply equivalent) + if (Worklist.contains(Triple)) { + StringRef Image = Binary->getImage(); + + // create an output file descriptor + auto OutputName = Worklist[Triple]; + std::error_code EC; + raw_fd_ostream OutputFile((*OutputName).second, EC, sys::fs::OF_None); + if (EC) + return AMD_COMGR_STATUS_ERROR; + + // write the packaged image into the output + OutputFile << Image; + OutputFile.flush(); + + // erase the entry from Worklist (so that we can track if all expected + // files have been unpackaged) + Worklist.erase(Triple); + } + } + + // if not all expected files were unpackaged, throw an error + // TODO: should this have an option associated with it? unbundler doesn't seem + // to + if (!Worklist.empty()) { + return AMD_COMGR_STATUS_ERROR; + } + + return AMD_COMGR_STATUS_SUCCESS; +} + +CachedCommandAdaptor::ActionClass UnpackageCommand::getClass() const { + // TODO: look into an upstream OffloadUnpackagerJobClass? + return clang::driver::Action::OffloadPackagerJobClass; +} + +void UnpackageCommand::addOptionsIdentifier(HashAlgorithm &H) const { + addUInt(H, TargetNames.size()); + for (StringRef Target : TargetNames) { + CachedCommandAdaptor::addString(H, Target); + } +} + +Error UnpackageCommand::addInputIdentifier(HashAlgorithm &H) const { + return Error::success(); +} + +} // namespace COMGR diff --git a/amd/comgr/src/comgr-unpackage-command.h b/amd/comgr/src/comgr-unpackage-command.h new file mode 100644 index 0000000000000..4ecb554bb1083 --- /dev/null +++ b/amd/comgr/src/comgr-unpackage-command.h @@ -0,0 +1,48 @@ +//===- comgr-package-command.h - UnpackageCommand implementation ----------===// +// +// Part of Comgr, under the Apache License v2.0 with LLVM Exceptions. See +// amd/comgr/LICENSE.TXT in this repository for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef COMGR_PACKAGER_COMMAND_H +#define COMGR_PACKAGER_COMMAND_H + +#include +#include +#include + +namespace COMGR { +class UnpackageCommand final : public CachedCommandAdaptor { +private: + const llvm::SmallVector &Files; + const llvm::SmallVector &TargetNames; + const llvm::SmallVector &OutputFileNames; + + // To avoid copies, store the output of execute, such that readExecuteOutput + // can return a reference. + llvm::SmallString<64> OutputBuffer; + +public: + UnpackageCommand(const llvm::SmallVector &Files, + const llvm::SmallVector &TargetNames, + const llvm::SmallVector &OutputFileNames) + : Files(Files), TargetNames(TargetNames), + OutputFileNames(OutputFileNames) {} + + bool canCache() const override; + llvm::Error writeExecuteOutput(llvm::StringRef CachedBuffer) override; + llvm::Expected readExecuteOutput() override; + amd_comgr_status_t execute(llvm::raw_ostream &LogS) override; + + ~UnpackageCommand() override = default; + +protected: + ActionClass getClass() const override; + void addOptionsIdentifier(HashAlgorithm &) const override; + llvm::Error addInputIdentifier(HashAlgorithm &) const override; +}; +} // namespace COMGR + +#endif From 84c14437941cc96265be4f58f7372b65cd3b95ba Mon Sep 17 00:00:00 2001 From: alessandra simmons Date: Thu, 20 Nov 2025 12:57:27 -0500 Subject: [PATCH 2/5] comgr-compiler build fixes --- amd/comgr/src/comgr-compiler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index b27df285b71fb..657db06b800ec 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -1448,10 +1448,10 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { auto Cache = CommandCache::get(LogS); for (auto *Input : InSet->DataObjects) { - llvm::SmallVector Files; + llvm::SmallVector Files; llvm::MemoryBufferRef dataBufferRef(Input->Data, "package_data"); - llvm::object::extractOffloadBinaries(dataBufferRef, &Files); + llvm::object::extractOffloadFiles(dataBufferRef, &Files); // Generate random name if none provided if (!strcmp(Input->Name, "")) { @@ -1482,8 +1482,8 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { SmallVector OutputFileNames; SmallVector TargetNames; - for (const OffloadFile &File : Files) { - const OffloadBinary &Binary = File.getBinary(); + for (const llvm::object::OffloadFile &File : Files) { + const llvm::object::OffloadBinary &Binary = File.getBinary(); StringRef Triple = Binary->getTriple(); const char *FileExtension; @@ -1527,7 +1527,7 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { UnpackageCommand Unpackage(Files, OutputFileNames, TargetNames); if (Cache) { - if (auto Status = Cache->execute(Unbundle, LogS)) { + if (auto Status = Cache->execute(Unpackage, LogS)) { return Status; } } else { From 5e286c5b36cfe3182887c3b0eef103389e3fd1b0 Mon Sep 17 00:00:00 2001 From: alessandra simmons Date: Thu, 20 Nov 2025 13:02:57 -0500 Subject: [PATCH 3/5] more comgr-compiler build fixes --- amd/comgr/src/comgr-compiler.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index 657db06b800ec..a291e8ff0763b 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -1451,7 +1451,7 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { llvm::SmallVector Files; llvm::MemoryBufferRef dataBufferRef(Input->Data, "package_data"); - llvm::object::extractOffloadFiles(dataBufferRef, &Files); + llvm::object::extractOffloadBinaries(dataBufferRef, &Files); // Generate random name if none provided if (!strcmp(Input->Name, "")) { @@ -1484,26 +1484,26 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { SmallVector TargetNames; for (const llvm::object::OffloadFile &File : Files) { const llvm::object::OffloadBinary &Binary = File.getBinary(); - StringRef Triple = Binary->getTriple(); + StringRef Triple = Binary.getTriple(); const char *FileExtension; - switch (Binary->getImageKind()) { - case IMG_Object: + switch (Binary.getImageKind()) { + case llvm::object::IMG_Object: FileExtension = "o"; break; - case IMG_Bitcode: + case llvm::object::IMG_Bitcode: FileExtension = "bc"; break; - case IMG_Cubin: + case llvm::object::IMG_Cubin: FileExtension = "cubin"; break; - case IMG_Fatbinary: + case llvm::object::IMG_Fatbinary: FileExtension = "fatbin"; break; - case IMG_PTX: + case llvm::object::IMG_PTX: FileExtension = "ptx"; break; - case IMG_SPIRV: + case llvm::object::IMG_SPIRV: FileExtension = "spv"; break; default: From c545ea6ed5af2ffb5486440a0017a70edfec1197 Mon Sep 17 00:00:00 2001 From: alessandra simmons Date: Thu, 20 Nov 2025 13:05:27 -0500 Subject: [PATCH 4/5] comgr-compiler build fixes 3 --- amd/comgr/src/comgr-compiler.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index a291e8ff0763b..6c02e3c1b6635 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -1457,8 +1457,7 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { if (!strcmp(Input->Name, "")) { const size_t BufSize = sizeof(char) * 30; char *Buf = (char *)malloc(BufSize); - snprintf(Buf, BufSize, "comgr-package-%d.%s", std::rand() % 10000, - FileExtension); + snprintf(Buf, BufSize, "comgr-package-%d", std::rand() % 10000); Input->Name = Buf; } @@ -1482,8 +1481,8 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { SmallVector OutputFileNames; SmallVector TargetNames; - for (const llvm::object::OffloadFile &File : Files) { - const llvm::object::OffloadBinary &Binary = File.getBinary(); + for (llvm::object::OffloadFile &File : Files) { + llvm::object::OffloadBinary &Binary = File.getBinary(); StringRef Triple = Binary.getTriple(); const char *FileExtension; From a090bbd1a0671104bfbe9cf073cb30bf7a973dcb Mon Sep 17 00:00:00 2001 From: "alessanda@adrs.pub" Date: Mon, 24 Nov 2025 10:02:01 -0600 Subject: [PATCH 5/5] create initial test infrastructure --- amd/comgr/CMakeLists.txt | 1 + amd/comgr/include/amd_comgr.h.in | 108 ++++++++++++++++++- amd/comgr/src/amdcomgr.def | 3 + amd/comgr/src/comgr-compiler.cpp | 49 +++++---- amd/comgr/src/comgr-unpackage-command.cpp | 38 ++++--- amd/comgr/src/comgr.cpp | 76 +++++++++++++ amd/comgr/src/comgr.h | 5 + amd/comgr/src/exportmap.in | 3 + amd/comgr/test-lit/CMakeLists.txt | 1 + amd/comgr/test-lit/comgr-sources/unpackage.c | 80 ++++++++++++++ 10 files changed, 329 insertions(+), 35 deletions(-) create mode 100644 amd/comgr/test-lit/comgr-sources/unpackage.c diff --git a/amd/comgr/CMakeLists.txt b/amd/comgr/CMakeLists.txt index 21a544402c48a..df220bb1cc188 100644 --- a/amd/comgr/CMakeLists.txt +++ b/amd/comgr/CMakeLists.txt @@ -82,6 +82,7 @@ set(SOURCES src/comgr-symbol.cpp src/comgr-symbolizer.cpp src/comgr-unbundle-command.cpp + src/comgr-unpackage-command.cpp src/time-stat/time-stat.cpp) if(COMGR_BUILD_SHARED_LIBS) diff --git a/amd/comgr/include/amd_comgr.h.in b/amd/comgr/include/amd_comgr.h.in index e4d66f3491403..de54595eb0127 100644 --- a/amd/comgr/include/amd_comgr.h.in +++ b/amd/comgr/include/amd_comgr.h.in @@ -399,10 +399,14 @@ typedef enum amd_comgr_data_kind_s { * The data is SPIR-V IR */ AMD_COMGR_DATA_KIND_SPIRV = 0x15, + /** + * The data is an llvm-offload-binary package. + */ + AMD_COMGR_DATA_KIND_PACKAGE = 0x16, /** * Marker for last valid data kind. */ - AMD_COMGR_DATA_KIND_LAST = AMD_COMGR_DATA_KIND_SPIRV + AMD_COMGR_DATA_KIND_LAST = AMD_COMGR_DATA_KIND_PACKAGE } amd_comgr_data_kind_t; /** @@ -1432,6 +1436,93 @@ amd_comgr_action_info_get_bundle_entry_id( size_t *size, char *bundle_entry_id) AMD_COMGR_VERSION_2_8; +/** + * @brief Set the package entry IDs of an action info object. + * + * When an action info object is created it has no package entry IDs. Some + * actions require that the action info object has package entry IDs + * defined. + * + * @param[in] action_info A handle to the action info object to be + * updated. + * + * @param[in] package_entry_ids An array of strings containing one or more + * package entry ID strings. If NULL then the package entry ID strings are + * cleared. These IDs are described at + * + * + * @retval ::AMD_COMGR_STATUS_SUCCESS The function has + * been executed successfully. + * + * @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p + * action_info is an invalid action info object. @p contains an invalid + * package ID not supported by this version of the code object manager + * library. + * + * @retval ::AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES + * Unable to update action info object as out of resources. + */ +amd_comgr_status_t AMD_COMGR_API +amd_comgr_action_info_set_package_entry_ids( + amd_comgr_action_info_t action_info, + const char *package_entry_ids[], + size_t count) AMD_COMGR_VERSION_3_1; + +/** + * @brief Get number of package entry IDs + * + * @param[in] action_info The action info object to query. + * + * @param[out] count The number of package entry IDs availible. This value + * can be used as an upper bound to the Index provided to the corresponding + * amd_comgr_get_package_entry_id() call. + * + * @retval ::AMD_COMGR_STATUS_SUCCESS The function has + * been executed successfully. + * + * @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p + * action_info is an invalid action info object. @p size is NULL. + * + * @retval ::AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES + * Unable to update the data object as out of resources. + */ +amd_comgr_status_t AMD_COMGR_API +amd_comgr_action_info_get_package_entry_id_count( + amd_comgr_action_info_t action_info, + size_t *count) AMD_COMGR_VERSION_3_1; + +/** + * @brief Fetch the Nth specific package entry ID or that ID's length. + * + * @param[in] action_info The action info object to query. + * + * @param[in] index The index of the package entry ID to be returned. + * + * @param[in, out] size For out, the size of @p package_entry_id. For in, + * if @package_entry_id is NULL, set to the size of the Nth ID string including + * the terminating null character. + * + * @param[out] package_entry_id If not NULL, then the first @p size characters of + * the Nth bundle entry ID string are copied into @p package_entry_id. If NULL, + * no package entry ID is copied, and only @p size is updated (useful in order + * to find the size of the buffer requried to copy the package_entry_id string). + * + * @retval ::AMD_COMGR_STATUS_SUCCESS The function has + * been executed successfully. + * + * @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p + * action_info is an invalid action info object. @p size is NULL. + * + * @retval ::AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES + * Unable to update the data object as out of resources. + */ +amd_comgr_status_t AMD_COMGR_API +amd_comgr_action_info_get_package_entry_id( + amd_comgr_action_info_t action_info, + size_t index, + size_t *size, + char *package_entry_id) AMD_COMGR_VERSION_3_1; + /** * @brief Set whether the specified action should use an * in-memory virtual file system (VFS). @@ -1838,10 +1929,23 @@ typedef enum amd_comgr_action_kind_s { */ AMD_COMGR_ACTION_COMPILE_SOURCE_TO_SPIRV = 0x14, + /** + * Unpackage each source data object in @p input. For each successful + * unbundling, add a bc object or archive object to @p result, depending on + * the corresponding input. + * + * Return @p AMD_COMGR_STATUS_ERROR if any unpackaging + * fails. + * + * Return @p AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT + * if @p is not a package. + */ + AMD_COMGR_ACTION_UNPACKAGE = 0x15, + /** * Marker for last valid action kind. */ - AMD_COMGR_ACTION_LAST = AMD_COMGR_ACTION_COMPILE_SOURCE_TO_SPIRV + AMD_COMGR_ACTION_LAST = AMD_COMGR_ACTION_UNPACKAGE } amd_comgr_action_kind_t; /** diff --git a/amd/comgr/src/amdcomgr.def b/amd/comgr/src/amdcomgr.def index 27b04dd8270f7..380c6eb7cda0c 100644 --- a/amd/comgr/src/amdcomgr.def +++ b/amd/comgr/src/amdcomgr.def @@ -47,5 +47,8 @@ amd_comgr_symbol_get_info amd_comgr_action_info_set_bundle_entry_ids amd_comgr_action_info_get_bundle_entry_id_count amd_comgr_action_info_get_bundle_entry_id +amd_comgr_action_info_set_package_entry_ids +amd_comgr_action_info_get_package_entry_id_count +amd_comgr_action_info_get_package_entry_id amd_comgr_action_info_set_device_lib_linking amd_comgr_action_info_set_vfs diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index 6c02e3c1b6635..fd14dfa43bfdc 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "comgr-compiler.h" +#include "amd_comgr.h" #include "comgr-cache.h" #include "comgr-clang-command.h" #include "comgr-device-libs.h" @@ -1448,10 +1449,17 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { auto Cache = CommandCache::get(LogS); for (auto *Input : InSet->DataObjects) { - llvm::SmallVector Files; + // if supplied file isn't a package, return an error + if (Input->DataKind != AMD_COMGR_DATA_KIND_PACKAGE) { + return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT; + } - llvm::MemoryBufferRef dataBufferRef(Input->Data, "package_data"); - llvm::object::extractOffloadBinaries(dataBufferRef, &Files); + llvm::SmallVector Files; + + llvm::MemoryBufferRef DataBufferRef(Input->Data, "package_data"); + if (llvm::object::extractOffloadBinaries(DataBufferRef, Files)) { + return AMD_COMGR_STATUS_ERROR; + } // Generate random name if none provided if (!strcmp(Input->Name, "")) { @@ -1481,12 +1489,12 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { SmallVector OutputFileNames; SmallVector TargetNames; - for (llvm::object::OffloadFile &File : Files) { - llvm::object::OffloadBinary &Binary = File.getBinary(); - StringRef Triple = Binary.getTriple(); + for (const llvm::object::OffloadFile &File : Files) { + const llvm::object::OffloadBinary *Binary = File.getBinary(); + StringRef Triple = Binary->getTriple(); const char *FileExtension; - switch (Binary.getImageKind()) { + switch (Binary->getImageKind()) { case llvm::object::IMG_Object: FileExtension = "o"; break; @@ -1510,17 +1518,22 @@ amd_comgr_status_t AMDGPUCompiler::unpackage() { break; } - SmallString<128> OutputFilePath = OutputDir; - sys::path::append(OutputFilePath, - OutputPrefix + "-" + Triple + "." + FileExtension); - - OutputFileNames.emplace_back(OutputFilePath); - TargetNames.emplace_back(Triple); - - if (env::shouldEmitVerboseLogs()) { - LogS << "\tPackage Entry Target: " << Triple << "\n" - << "\tOutput Filename: " << OutputFilePath << "\n"; - LogS.flush(); + for (StringRef Entry : ActionInfo->BundleEntryIDs) { + // TODO: this should probably check compatability, not strict equivalence + if (Entry == Triple) { + SmallString<128> OutputFilePath = OutputDir; + sys::path::append(OutputFilePath, + OutputPrefix + "-" + Triple + "." + FileExtension); + + OutputFileNames.emplace_back(OutputFilePath); + TargetNames.emplace_back(Triple); + + if (env::shouldEmitVerboseLogs()) { + LogS << "\tPackage Entry Target: " << Triple << "\n" + << "\tOutput Filename: " << OutputFilePath << "\n"; + LogS.flush(); + } + } } } diff --git a/amd/comgr/src/comgr-unpackage-command.cpp b/amd/comgr/src/comgr-unpackage-command.cpp index a3a5cb11e52f6..e10eb0d0f3db2 100644 --- a/amd/comgr/src/comgr-unpackage-command.cpp +++ b/amd/comgr/src/comgr-unpackage-command.cpp @@ -37,27 +37,31 @@ bool UnpackageCommand::canCache() const { Error UnpackageCommand::writeExecuteOutput(StringRef CachedBuffer) { for (StringRef OutputFilename : OutputFileNames) { SizeFieldType OutputFileSize; - if (CachedBuffer.size() < sizeof(OutputFileSize)) + if (CachedBuffer.size() < sizeof(OutputFileSize)) { return createStringError(std::errc::invalid_argument, "Not enough bytes to read output file size"); + } memcpy(&OutputFileSize, CachedBuffer.data(), sizeof(OutputFileSize)); CachedBuffer = CachedBuffer.drop_front(sizeof(OutputFileSize)); - if (CachedBuffer.size() < OutputFileSize) + if (CachedBuffer.size() < OutputFileSize) { return createStringError(std::errc::invalid_argument, "Not enough bytes to read output file contents"); + } StringRef OutputFileContents = CachedBuffer.substr(0, OutputFileSize); CachedBuffer = CachedBuffer.drop_front(OutputFileSize); if (Error Err = CachedCommandAdaptor::writeSingleOutputFile( - OutputFilename, OutputFileContents)) + OutputFilename, OutputFileContents)) { return Err; + } } - if (!CachedBuffer.empty()) + if (!CachedBuffer.empty()) { return createStringError(std::errc::invalid_argument, "Bytes in cache entry not used for the output"); + } return Error::success(); } @@ -66,8 +70,9 @@ Expected UnpackageCommand::readExecuteOutput() { for (StringRef OutputFilename : OutputFileNames) { auto MaybeOneOutput = CachedCommandAdaptor::readSingleOutputFile(OutputFilename); - if (!MaybeOneOutput) + if (!MaybeOneOutput) { return MaybeOneOutput.takeError(); + } const MemoryBuffer &OneOutputBuffer = **MaybeOneOutput; SizeFieldType OneOutputFileSize = OneOutputBuffer.getBufferSize(); @@ -87,15 +92,15 @@ Expected UnpackageCommand::readExecuteOutput() { amd_comgr_status_t UnpackageCommand::execute(raw_ostream &LogS) { StringMap Worklist; - auto Output = OutputFileNames.begin(); + const auto *Output = OutputFileNames.begin(); for (auto &Triple : TargetNames) { - // TODO: check that triples are valid for a package + // TODO: check that triples are valid for a package? Worklist[Triple] = *Output; ++Output; } - for (const OffloadFile &File : Files) { - const OffloadBinary &Binary = File.getBinary(); + for (const llvm::object::OffloadFile &File : Files) { + const llvm::object::OffloadBinary *Binary = File.getBinary(); StringRef Triple = Binary->getTriple(); // TODO: does this instead need to check that the triples are compatible? @@ -106,9 +111,10 @@ amd_comgr_status_t UnpackageCommand::execute(raw_ostream &LogS) { // create an output file descriptor auto OutputName = Worklist[Triple]; std::error_code EC; - raw_fd_ostream OutputFile((*OutputName).second, EC, sys::fs::OF_None); - if (EC) + raw_fd_ostream OutputFile(OutputName, EC, sys::fs::OF_None); + if (EC) { return AMD_COMGR_STATUS_ERROR; + } // write the packaged image into the output OutputFile << Image; @@ -120,11 +126,13 @@ amd_comgr_status_t UnpackageCommand::execute(raw_ostream &LogS) { } } - // if not all expected files were unpackaged, throw an error - // TODO: should this have an option associated with it? unbundler doesn't seem - // to + // if not all expected files were unpackaged, possibly throw an error + // TODO: should this have an option associated with it? unbundler doesn't if (!Worklist.empty()) { - return AMD_COMGR_STATUS_ERROR; + // the unbundler is invoked to ignore missing bundles, so, in matching that + // behavior, the following error shouldn't be thrown: + + // return AMD_COMGR_STATUS_ERROR; } return AMD_COMGR_STATUS_SUCCESS; diff --git a/amd/comgr/src/comgr.cpp b/amd/comgr/src/comgr.cpp index 53ea784db97ab..1ec89d0a4148c 100644 --- a/amd/comgr/src/comgr.cpp +++ b/amd/comgr/src/comgr.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "comgr.h" +#include "amd_comgr.h" #include "comgr-compiler.h" #include "comgr-device-libs.h" #include "comgr-disassembly.h" @@ -80,6 +81,8 @@ amd_comgr_status_t dispatchCompilerAction(amd_comgr_action_kind_t ActionKind, return Compiler.compileToBitcode(); case AMD_COMGR_ACTION_UNBUNDLE: return Compiler.unbundle(); + case AMD_COMGR_ACTION_UNPACKAGE: + return Compiler.unpackage(); case AMD_COMGR_ACTION_LINK_BC_TO_BC: return Compiler.linkBitcodeToBitcode(); case AMD_COMGR_ACTION_CODEGEN_BC_TO_RELOCATABLE: @@ -197,6 +200,8 @@ StringRef getActionKindName(amd_comgr_action_kind_t ActionKind) { return "AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC"; case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_SPIRV: return "AMD_COMGR_ACTION_COMPILE_SOURCE_TO_SPIRV"; + case AMD_COMGR_ACTION_UNPACKAGE: + return "AMD_COMGR_ACTION_UNPACKAGE"; } llvm_unreachable("invalid action"); @@ -414,6 +419,16 @@ DataAction::setBundleEntryIDs(ArrayRef EntryIDs) { ArrayRef DataAction::getBundleEntryIDs() { return BundleEntryIDs; } +amd_comgr_status_t DataAction::setPackageEntryIDs(llvm::ArrayRef EntryIDs) { + PackageEntryIDs.clear(); + for (auto &ID : EntryIDs) { + PackageEntryIDs.push_back(ID); + } + return AMD_COMGR_STATUS_SUCCESS; +} + +llvm::ArrayRef DataAction::getPackageEntryIDs() { return PackageEntryIDs; } + amd_comgr_metadata_kind_t DataMeta::getMetadataKind() { if (DocNode.isScalar()) { return AMD_COMGR_METADATA_KIND_STRING; @@ -1104,6 +1119,66 @@ amd_comgr_status_t AMD_COMGR_API return ActionP->setBundleEntryIDs(ArrayRef(EntryIDs, Count)); } +amd_comgr_status_t AMD_COMGR_API + // NOLINTNEXTLINE(readability-identifier-naming) + amd_comgr_action_info_get_package_entry_id_count + // + (amd_comgr_action_info_t ActionInfo, size_t *Count) { + DataAction *ActionP = DataAction::convert(ActionInfo); + + if (!ActionP) { + return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT; + } + + *Count = ActionP->getPackageEntryIDs().size(); + + return AMD_COMGR_STATUS_SUCCESS; +} + +amd_comgr_status_t AMD_COMGR_API + // NOLINTNEXTLINE(readability-identifier-naming) + amd_comgr_action_info_get_package_entry_id + // + (amd_comgr_action_info_t ActionInfo, size_t Index, size_t *Size, + char *PackageEntryID) { + DataAction *ActionP = DataAction::convert(ActionInfo); + + if (!ActionP || !Size) { + return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT; + } + + ArrayRef ActionPackageEntryIDs = ActionP->getPackageEntryIDs(); + + if (Index >= ActionPackageEntryIDs.size()) { + return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT; + } + + // First return the size of the PackageEntryID + if (PackageEntryID == NULL) + *Size = ActionPackageEntryIDs[Index].size() + 1; + + // Now that the calling API has had a chance to allocate memory, copy the + // bundle entry ID at Index to PackageEntryID + else + memcpy(PackageEntryID, ActionPackageEntryIDs[Index].c_str(), *Size); + + return AMD_COMGR_STATUS_SUCCESS; +} + +amd_comgr_status_t AMD_COMGR_API + // NOLINTNEXTLINE(readability-identifier-naming) + amd_comgr_action_info_set_package_entry_ids + // + (amd_comgr_action_info_t ActionInfo, const char *EntryIDs[], size_t Count) { + DataAction *ActionP = DataAction::convert(ActionInfo); + + if (!ActionP || (!EntryIDs && Count)) { + return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT; + } + + return ActionP->setPackageEntryIDs(ArrayRef(EntryIDs, Count)); +} + amd_comgr_status_t AMD_COMGR_API // NOLINTNEXTLINE(readability-identifier-naming) amd_comgr_action_info_set_vfs @@ -1295,6 +1370,7 @@ amd_comgr_status_t AMD_COMGR_API case AMD_COMGR_ACTION_SOURCE_TO_PREPROCESSOR: case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_BC: case AMD_COMGR_ACTION_UNBUNDLE: + case AMD_COMGR_ACTION_UNPACKAGE: case AMD_COMGR_ACTION_LINK_BC_TO_BC: case AMD_COMGR_ACTION_CODEGEN_BC_TO_RELOCATABLE: case AMD_COMGR_ACTION_CODEGEN_BC_TO_ASSEMBLY: diff --git a/amd/comgr/src/comgr.h b/amd/comgr/src/comgr.h index 59e05aade02cd..0fa493bcf47c4 100644 --- a/amd/comgr/src/comgr.h +++ b/amd/comgr/src/comgr.h @@ -11,6 +11,7 @@ #include "amd_comgr.h" #include "comgr-symbol.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -208,6 +209,9 @@ struct DataAction { amd_comgr_status_t setBundleEntryIDs(llvm::ArrayRef EntryIDs); llvm::ArrayRef getBundleEntryIDs(); + amd_comgr_status_t setPackageEntryIDs(llvm::ArrayRef EntryIDs); + llvm::ArrayRef getPackageEntryIDs(); + char *IsaName; char *Path; amd_comgr_language_t Language; @@ -216,6 +220,7 @@ struct DataAction { bool ShouldUseVFS = true; std::vector BundleEntryIDs; + std::vector PackageEntryIDs; private: std::vector ListOptions; diff --git a/amd/comgr/src/exportmap.in b/amd/comgr/src/exportmap.in index d79760dc96264..883b5cd1704cf 100644 --- a/amd/comgr/src/exportmap.in +++ b/amd/comgr/src/exportmap.in @@ -94,4 +94,7 @@ global: amd_comgr_action_info_set_device_lib_linking; @amd_comgr_NAME@3.1 { global: amd_comgr_action_info_set_vfs; + amd_comgr_action_info_set_package_entry_ids; + amd_comgr_action_info_get_package_entry_id_count; + amd_comgr_action_info_get_package_entry_id; } @amd_comgr_NAME@_2.9; diff --git a/amd/comgr/test-lit/CMakeLists.txt b/amd/comgr/test-lit/CMakeLists.txt index bfc765e4a743f..7f5b0c7cd3304 100644 --- a/amd/comgr/test-lit/CMakeLists.txt +++ b/amd/comgr/test-lit/CMakeLists.txt @@ -44,6 +44,7 @@ add_comgr_lit_binary(compile-opencl-minimal c) add_comgr_lit_binary(spirv-to-reloc c) add_comgr_lit_binary(source-to-spirv c) add_comgr_lit_binary(unbundle c) +add_comgr_lit_binary(unpackage c) add_comgr_lit_binary(get-version c) add_comgr_lit_binary(status-string c) add_comgr_lit_binary(data-action c) diff --git a/amd/comgr/test-lit/comgr-sources/unpackage.c b/amd/comgr/test-lit/comgr-sources/unpackage.c new file mode 100644 index 0000000000000..dbace9d7cf2b7 --- /dev/null +++ b/amd/comgr/test-lit/comgr-sources/unpackage.c @@ -0,0 +1,80 @@ +//===- unpackage.c --------------------------------------------------------===// +// +// Part of Comgr, under the Apache License v2.0 with LLVM Exceptions. See +// amd/comgr/LICENSE.TXT in this repository for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "amd_comgr.h" +#include "common.h" + +int main(int argc, char *argv[]) { + char *PackageData; + size_t PackageSize; + + if (argc < 4) { + printf("Usage: %s \n", argv[0]); + return -1; + } + + const char *PackagePath = argv[1]; + const char *Arch = argv[2]; + const char *BitcodePath = argv[3]; + + amd_comgr_data_t OnePackage; + amd_comgr_data_set_t InputPackages; + + PackageSize = setBuf(PackagePath, &PackageData); + + amd_comgr_(create_data_set(&InputPackages)); + amd_comgr_(create_data(AMD_COMGR_DATA_KIND_PACKAGE, &OnePackage)); + amd_comgr_(set_data(OnePackage, PackageSize, PackageData)); + amd_comgr_(set_data_name(OnePackage, "package.bc")); + amd_comgr_(data_set_add(InputPackages, OnePackage)); + + amd_comgr_data_set_t OutputBitcode; + amd_comgr_(create_data_set(&OutputBitcode)); + + amd_comgr_action_info_t DataAction; + amd_comgr_(create_action_info(&DataAction)); + + const char *AllArch[] = {Arch}; + amd_comgr_(action_info_set_package_entry_ids(DataAction, AllArch, 1)); + amd_comgr_(do_action(AMD_COMGR_ACTION_UNPACKAGE, DataAction, InputPackages, + OutputBitcode)); + + size_t Count; + amd_comgr_(action_data_count(OutputBitcode, AMD_COMGR_DATA_KIND_BC, &Count)); + + if (Count != 1) { + printf("AMD_COMGR_ACTION_COMPILE_SOURCE_TO_BC Failed: " + "produced %zu BC objects (expected 1)\n", + Count); + exit(1); + } + + amd_comgr_data_t OneBitcode; + amd_comgr_(action_data_get_data(OutputBitcode, AMD_COMGR_DATA_KIND_BC, 0, + &OneBitcode)); + + size_t BufferSize; + amd_comgr_(get_data(OneBitcode, &BufferSize, 0x0)); + char *Buffer = (char *)malloc(BufferSize); + amd_comgr_(get_data(OneBitcode, &BufferSize, Buffer)); + + FILE *BitcodeFile = fopen(BitcodePath, "wb"); + fwrite(Buffer, 1, BufferSize, BitcodeFile); + fclose(BitcodeFile); + + free(Buffer); + amd_comgr_(release_data(OneBitcode)); + amd_comgr_(release_data(OnePackage)); + amd_comgr_(destroy_action_info(DataAction)); + amd_comgr_(destroy_data_set(OutputBitcode)); + amd_comgr_(destroy_data_set(InputPackages)); + free(PackageData); + + return 0; + +}