Skip to content

Commit fbbe276

Browse files
authored
[Comgr] Add new Action to compile SPIR-V to Relocatable (llvm#1252) (llvm#1355)
In this patch, we add a new action: AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE That accepts a set of .spv files, translates them to .bc files, extracts any embedded @llvm.cmdline flags, and then compiles to a set of relocatable .o files.
2 parents cf0a05f + 0342825 commit fbbe276

File tree

9 files changed

+362
-9
lines changed

9 files changed

+362
-9
lines changed

amd/comgr/include/amd_comgr.h.in

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,23 @@ typedef enum amd_comgr_action_kind_s {
17761776
*/
17771777
AMD_COMGR_ACTION_UNBUNDLE = 0xF,
17781778

1779+
/**
1780+
* Compile each source SPIR-V object in @p input into a relocatable.
1781+
* For each successful compilation, add a relocatable object to @p result
1782+
*
1783+
* We accomplish this by first translating the .spv files to .bc via the
1784+
* SPIR-V translator. We then extract any relevant -cc1 flags from the embedded
1785+
* @llvm.cmdline variable. Finally, we compile the bitcode to a reloctable,
1786+
* appending any extracted flags.
1787+
*
1788+
* Return @p AMD_COMGR_STATUS_ERROR if any translation, flag extraction, or
1789+
* compilation fails.
1790+
*
1791+
* Return @p AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT
1792+
* if any input is not SPIR-V.
1793+
*/
1794+
AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE = 0x10,
1795+
17791796
/**
17801797
* Translate each source SPIR-V object in @p input into LLVM IR Bitcode.
17811798
* For each successful translation, add a bc object to @p result *

amd/comgr/src/comgr-compiler.cpp

Lines changed: 162 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "clang/FrontendTool/Utils.h"
6060
#include "llvm/ADT/StringExtras.h"
6161
#include "llvm/Bitcode/BitcodeWriter.h"
62+
#include "llvm/IR/Constants.h"
6263
#include "llvm/IR/LLVMContext.h"
6364
#include "llvm/IR/Module.h"
6465
#include "llvm/IR/Verifier.h"
@@ -875,7 +876,8 @@ amd_comgr_status_t AMDGPUCompiler::removeTmpDirs() {
875876
#endif
876877
}
877878

878-
amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
879+
amd_comgr_status_t AMDGPUCompiler::processFile(DataObject *Input,
880+
const char *InputFilePath,
879881
const char *OutputFilePath) {
880882
SmallVector<const char *, 128> Argv = Args;
881883

@@ -896,6 +898,12 @@ amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
896898
Argv.push_back("-save-temps=obj");
897899
}
898900

901+
// Add SPIR-V flags
902+
for (auto Flag : Input->SpirvFlags) {
903+
Argv.push_back("-Xclang");
904+
Argv.push_back(Flag);
905+
}
906+
899907
Argv.push_back(InputFilePath);
900908

901909
Argv.push_back("-o");
@@ -907,6 +915,12 @@ amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
907915
amd_comgr_status_t
908916
AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
909917
const char *OutputSuffix) {
918+
return processFiles(OutputKind, OutputSuffix, InSet);
919+
}
920+
921+
amd_comgr_status_t
922+
AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
923+
const char *OutputSuffix, DataSet *InSet) {
910924
for (auto *Input : InSet->DataObjects) {
911925
if (Input->DataKind != AMD_COMGR_DATA_KIND_INCLUDE) {
912926
continue;
@@ -944,7 +958,7 @@ AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
944958
auto OutputFilePath = getFilePath(Output, OutputDir);
945959

946960
if (auto Status =
947-
processFile(InputFilePath.c_str(), OutputFilePath.c_str())) {
961+
processFile(Input, InputFilePath.c_str(), OutputFilePath.c_str())) {
948962
return Status;
949963
}
950964

@@ -1868,19 +1882,115 @@ amd_comgr_status_t AMDGPUCompiler::linkToExecutable() {
18681882
return amd_comgr_data_set_add(OutSetT, OutputT);
18691883
}
18701884

1885+
// TODO: Generalize this list to include all -cc1 flags and arguments that are
1886+
// still valid in a bitcode compilation context
1887+
static inline const std::unordered_set<std::string_view> ValidSpirvFlags{
1888+
"-fapprox-func",
1889+
"-fcolor-diagnostics",
1890+
"-fconvergent-functions",
1891+
"-fexceptions",
1892+
"-ffast-math",
1893+
"-ffinite-math-only",
1894+
"-ffp-contract=fast",
1895+
"-ffp-contract=fast-honor-pragmas",
1896+
"-ffp-contract=on",
1897+
"-fgpu-rdc",
1898+
"-finline-functions",
1899+
"-fno-autolink",
1900+
"-fno-experimental-relative-c++-abi-vtables",
1901+
"-fno-rounding-math",
1902+
"-fno-signed-zeros",
1903+
"-fno-threadsafe-statics",
1904+
"-freciprocal-math",
1905+
"-funsafe-math-optimizations",
1906+
"-fvisibility=hidden",
1907+
"-O0",
1908+
"-O1",
1909+
"-O2",
1910+
"-O3",
1911+
"--save-temps"};
1912+
1913+
amd_comgr_status_t AMDGPUCompiler::extractSpirvFlags(DataSet *BcSet) {
1914+
1915+
for (auto *Bc : BcSet->DataObjects) {
1916+
// Create SPIR-V IR Module from Bitcode Buffer
1917+
SMDiagnostic SMDiag;
1918+
LLVMContext Context;
1919+
Context.setDiagnosticHandler(
1920+
std::make_unique<AMDGPUCompilerDiagnosticHandler>(this->LogS), true);
1921+
1922+
auto Mod = getLazyIRModule(
1923+
MemoryBuffer::getMemBuffer(StringRef(Bc->Data, Bc->Size), "", false),
1924+
SMDiag, Context, true);
1925+
1926+
if (!Mod) {
1927+
SMDiag.print("SPIR-V Bitcode", LogS, /* ShowColors */ false);
1928+
return AMD_COMGR_STATUS_ERROR;
1929+
}
1930+
1931+
if (verifyModule(*Mod, &LogS))
1932+
return AMD_COMGR_STATUS_ERROR;
1933+
1934+
// Fetch @llvm.cmdline
1935+
GlobalVariable *CmdLine = Mod->getNamedGlobal("llvm.cmdline");
1936+
1937+
// Return if no @llvm.cmdline
1938+
if (!CmdLine)
1939+
return AMD_COMGR_STATUS_SUCCESS;
1940+
1941+
if (ConstantDataSequential *CDS =
1942+
dyn_cast<ConstantDataSequential>(CmdLine->getInitializer())) {
1943+
1944+
// Add each valid null-terminated '\0' string to Flags
1945+
std::string Tmp;
1946+
StringRef CmdLineRaw = CDS->getRawDataValues();
1947+
std::stringstream ss(CmdLineRaw.str());
1948+
while (getline(ss, Tmp, '\0')) {
1949+
if (Tmp == "--hipstdpar" || Tmp == "-amdgpu-enable-hipstdpar") {
1950+
Bc->SpirvFlags.push_back("-mllvm");
1951+
Bc->SpirvFlags.push_back("-amdgpu-enable-hipstdpar");
1952+
} else if (Tmp == "-amdgpu-spill-cfi-saved-regs") {
1953+
Bc->SpirvFlags.push_back("-mllvm");
1954+
Bc->SpirvFlags.push_back("-amdgpu-spill-cfi-saved-regs");
1955+
} else if (ValidSpirvFlags.count(Tmp)) {
1956+
Bc->SpirvFlags.push_back(Saver.save(Tmp.c_str()).data());
1957+
}
1958+
}
1959+
}
1960+
1961+
// COV5 required for SPIR-V
1962+
Bc->SpirvFlags.push_back("-mcode-object-version=5");
1963+
1964+
if (env::shouldEmitVerboseLogs()) {
1965+
LogS << " SPIR-V Flags: " << Bc->Name << "\n";
1966+
for (auto Flag : Bc->SpirvFlags)
1967+
LogS << " " << Flag << "\n";
1968+
}
1969+
}
1970+
1971+
return AMD_COMGR_STATUS_SUCCESS;
1972+
}
1973+
18711974
amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
1975+
return translateSpirvToBitcodeImpl(InSet, DataSet::convert(OutSetT));
1976+
}
1977+
1978+
amd_comgr_status_t
1979+
AMDGPUCompiler::translateSpirvToBitcodeImpl(DataSet *SpirvInSet,
1980+
DataSet *BcOutSet) {
18721981
#ifdef COMGR_DISABLE_SPIRV
1873-
LogS << "Calling AMDGPUCompiler::translateSpirvToBitcode() not supported "
1874-
<< "Comgr is built with -DCOMGR_DISABLE_SPIRV. Re-build LLVM and Comgr "
1875-
<< "with LLVM-SPIRV-Translator support to continue.\n";
1982+
LogS << "Calling AMDGPUCompiler::translateSpirvToBitcodeImpl() not "
1983+
<< "supported. Comgr is built with -DCOMGR_DISABLE_SPIRV. Re-build LLVM "
1984+
<< "and Comgr with LLVM-SPIRV-Translator support to continue.\n";
18761985
return AMD_COMGR_STATUS_ERROR;
18771986
#else
18781987
if (auto Status = createTmpDirs()) {
18791988
return Status;
18801989
}
18811990

18821991
auto Cache = CommandCache::get(LogS);
1883-
for (auto *Input : InSet->DataObjects) {
1992+
1993+
for (auto *Input : SpirvInSet->DataObjects) {
18841994

18851995
if (env::shouldSaveTemps()) {
18861996
if (auto Status = outputToFile(Input, getFilePath(Input, InputDir))) {
@@ -1918,7 +2028,8 @@ amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
19182028
Output->setName(std::string(Input->Name) + std::string(".bc"));
19192029
Output->setData(OutBuf);
19202030

1921-
if (auto Status = amd_comgr_data_set_add(OutSetT, OutputT)) {
2031+
if (auto Status =
2032+
amd_comgr_data_set_add(DataSet::convert(BcOutSet), OutputT)) {
19222033
return Status;
19232034
}
19242035

@@ -1937,6 +2048,50 @@ amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
19372048
#endif
19382049
}
19392050

2051+
amd_comgr_status_t AMDGPUCompiler::compileSpirvToRelocatable() {
2052+
if (auto Status = createTmpDirs()) {
2053+
return Status;
2054+
}
2055+
2056+
for (auto *Input : InSet->DataObjects) {
2057+
if (Input->DataKind != AMD_COMGR_DATA_KIND_SPIRV)
2058+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
2059+
}
2060+
2061+
// Translate .spv to .bc
2062+
amd_comgr_data_set_t TranslatedSpirvT;
2063+
if (auto Status = amd_comgr_create_data_set(&TranslatedSpirvT))
2064+
return Status;
2065+
DataSet *TranslatedSpirv = DataSet::convert(TranslatedSpirvT);
2066+
2067+
if (auto Status = translateSpirvToBitcodeImpl(InSet, TranslatedSpirv))
2068+
return Status;
2069+
2070+
// Extract relevant -cc1 flags from @llvm.cmdline
2071+
if (auto Status = extractSpirvFlags(TranslatedSpirv))
2072+
return Status;
2073+
2074+
// Compile bitcode to relocatable
2075+
if (ActionInfo->IsaName) {
2076+
if (auto Status = addTargetIdentifierFlags(ActionInfo->IsaName)) {
2077+
return Status;
2078+
}
2079+
}
2080+
2081+
if (ActionInfo->ShouldLinkDeviceLibs) {
2082+
if (auto Status = addDeviceLibraries()) {
2083+
return Status;
2084+
}
2085+
}
2086+
2087+
Args.push_back("-c");
2088+
2089+
Args.push_back("-mllvm");
2090+
Args.push_back("-amdgpu-internalize-symbols");
2091+
2092+
return processFiles(AMD_COMGR_DATA_KIND_RELOCATABLE, ".o", TranslatedSpirv);
2093+
}
2094+
19402095
AMDGPUCompiler::AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet,
19412096
DataSet *OutSet, raw_ostream &LogS)
19422097
: ActionInfo(ActionInfo), InSet(InSet), OutSetT(DataSet::convert(OutSet)),

amd/comgr/src/comgr-compiler.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,25 @@ class AMDGPUCompiler {
7575

7676
amd_comgr_status_t createTmpDirs();
7777
amd_comgr_status_t removeTmpDirs();
78-
amd_comgr_status_t processFile(const char *InputFilePath,
78+
amd_comgr_status_t processFile(DataObject *Input, const char *InputFilePath,
7979
const char *OutputFilePath);
8080
/// Process each file in @c InSet individually, placing output in @c OutSet.
8181
amd_comgr_status_t processFiles(amd_comgr_data_kind_t OutputKind,
8282
const char *OutputSuffix);
83+
amd_comgr_status_t processFiles(amd_comgr_data_kind_t OutputKind,
84+
const char *OutputSuffix, DataSet *InSet);
8385
amd_comgr_status_t addIncludeFlags();
8486
amd_comgr_status_t addTargetIdentifierFlags(llvm::StringRef IdentStr,
8587
bool CompilingSrc);
8688
amd_comgr_status_t addCompilationFlags();
8789
amd_comgr_status_t addDeviceLibraries();
90+
amd_comgr_status_t extractSpirvFlags(DataSet *BcSet);
8891

8992
amd_comgr_status_t executeInProcessDriver(llvm::ArrayRef<const char *> Args);
9093

94+
amd_comgr_status_t translateSpirvToBitcodeImpl(DataSet *SpirvInSet,
95+
DataSet *BcOutSet);
96+
9197
public:
9298
AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet, DataSet *OutSet,
9399
llvm::raw_ostream &LogS);
@@ -104,6 +110,7 @@ class AMDGPUCompiler {
104110
amd_comgr_status_t linkToRelocatable();
105111
amd_comgr_status_t linkToExecutable();
106112
amd_comgr_status_t compileToExecutable();
113+
amd_comgr_status_t compileSpirvToRelocatable();
107114
amd_comgr_status_t translateSpirvToBitcode();
108115

109116
amd_comgr_language_t getLanguage() const { return ActionInfo->Language; }

amd/comgr/src/comgr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ amd_comgr_status_t dispatchCompilerAction(amd_comgr_action_kind_t ActionKind,
187187
return Compiler.compileToBitcode(true);
188188
case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE:
189189
return Compiler.compileToExecutable();
190+
case AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE:
191+
return Compiler.compileSpirvToRelocatable();
190192
case AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC:
191193
return Compiler.translateSpirvToBitcode();
192194

@@ -291,6 +293,8 @@ StringRef getActionKindName(amd_comgr_action_kind_t ActionKind) {
291293
return "AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE";
292294
case AMD_COMGR_ACTION_UNBUNDLE:
293295
return "AMD_COMGR_ACTION_UNBUNDLE";
296+
case AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE:
297+
return "AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE";
294298
case AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC:
295299
return "AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC";
296300
}
@@ -1376,6 +1380,7 @@ amd_comgr_status_t AMD_COMGR_API
13761380
case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_RELOCATABLE:
13771381
case AMD_COMGR_ACTION_COMPILE_SOURCE_WITH_DEVICE_LIBS_TO_BC:
13781382
case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE:
1383+
case AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE:
13791384
case AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC:
13801385
ActionStatus = dispatchCompilerAction(ActionKind, ActionInfoP, InputSetP,
13811386
ResultSetP, *LogP);

amd/comgr/src/comgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ struct DataObject {
131131
DataSymbol *DataSym;
132132
std::vector<std::string> MangledNames;
133133
std::map<std::string, std::string> NameExpressionMap;
134+
llvm::SmallVector<const char *, 128> SpirvFlags;
134135

135136
private:
136137
std::unique_ptr<llvm::MemoryBuffer> Buffer;

amd/comgr/test-lit/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ endmacro()
3636

3737
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
3838

39-
add_comgr_lit_binary(compile-minimal-test)
4039
add_comgr_lit_binary(source-to-bc-with-dev-libs)
4140
add_comgr_lit_binary(spirv-translator)
41+
add_comgr_lit_binary(compile-minimal-test)
42+
add_comgr_lit_binary(spirv-to-reloc)
4243

4344
add_dependencies(check-comgr test-lit)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "amd_comgr.h"
2+
#include "common.h"
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
int main(int argc, char *argv[]) {
8+
char *BufSpv;
9+
size_t SizeSpv;
10+
amd_comgr_data_t DataSpv;
11+
amd_comgr_data_set_t DataSetSpv, DataSetReloc;
12+
amd_comgr_action_info_t DataAction;
13+
size_t Count;
14+
15+
if (argc != 3) {
16+
fprintf(stderr, "Usage: spirv-to-reloc file.spv file.o\n");
17+
exit(1);
18+
}
19+
20+
SizeSpv = setBuf(argv[1], &BufSpv);
21+
22+
amd_comgr_(create_data(AMD_COMGR_DATA_KIND_SPIRV, &DataSpv));
23+
amd_comgr_(set_data(DataSpv, SizeSpv, BufSpv));
24+
amd_comgr_(set_data_name(DataSpv, "file.spv"));
25+
26+
amd_comgr_(create_data_set(&DataSetSpv));
27+
amd_comgr_(data_set_add(DataSetSpv, DataSpv));
28+
29+
amd_comgr_(create_action_info(&DataAction));
30+
amd_comgr_(action_info_set_language(DataAction, AMD_COMGR_LANGUAGE_HIP));
31+
amd_comgr_(action_info_set_isa_name(DataAction, "amdgcn-amd-amdhsa--gfx900"));
32+
33+
amd_comgr_(create_data_set(&DataSetReloc));
34+
amd_comgr_(do_action(AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE,
35+
DataAction, DataSetSpv, DataSetReloc));
36+
37+
amd_comgr_(
38+
action_data_count(DataSetReloc, AMD_COMGR_DATA_KIND_RELOCATABLE, &Count));
39+
40+
if (Count != 1) {
41+
printf("AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE Failed: "
42+
"produced %zu RELOCATABLE objects (expected 1)\n",
43+
Count);
44+
exit(1);
45+
}
46+
47+
amd_comgr_data_t DataReloc;
48+
amd_comgr_(action_data_get_data(DataSetReloc, AMD_COMGR_DATA_KIND_RELOCATABLE,
49+
0, &DataReloc));
50+
dumpData(DataReloc, argv[2]);
51+
52+
amd_comgr_(release_data(DataSpv));
53+
amd_comgr_(destroy_data_set(DataSetSpv));
54+
amd_comgr_(destroy_data_set(DataSetReloc));
55+
amd_comgr_(destroy_action_info(DataAction));
56+
free(BufSpv);
57+
}

0 commit comments

Comments
 (0)