Skip to content

Commit 56d502c

Browse files
authored
[Comgr] Add new Action to compile SPIR-V to Relocatable (llvm#1252)
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 6d74d3f + 328352b commit 56d502c

File tree

9 files changed

+360
-8
lines changed

9 files changed

+360
-8
lines changed

amd/comgr/include/amd_comgr.h.in

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,23 @@ typedef enum amd_comgr_action_kind_s {
17941794
*/
17951795
AMD_COMGR_ACTION_UNBUNDLE = 0xF,
17961796

1797+
/**
1798+
* Compile each source SPIR-V object in @p input into a relocatable.
1799+
* For each successful compilation, add a relocatable object to @p result
1800+
*
1801+
* We accomplish this by first translating the .spv files to .bc via the
1802+
* SPIR-V translator. We then extract any relevant -cc1 flags from the embedded
1803+
* @llvm.cmdline variable. Finally, we compile the bitcode to a reloctable,
1804+
* appending any extracted flags.
1805+
*
1806+
* Return @p AMD_COMGR_STATUS_ERROR if any translation, flag extraction, or
1807+
* compilation fails.
1808+
*
1809+
* Return @p AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT
1810+
* if any input is not SPIR-V.
1811+
*/
1812+
AMD_COMGR_ACTION_COMPILE_SPIRV_TO_RELOCATABLE = 0x10,
1813+
17971814
/**
17981815
* Translate each source SPIR-V object in @p input into LLVM IR Bitcode.
17991816
* For each successful translation, add a bc object to @p result *

amd/comgr/src/comgr-compiler.cpp

Lines changed: 161 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "clang/FrontendTool/Utils.h"
5959
#include "llvm/ADT/StringExtras.h"
6060
#include "llvm/Bitcode/BitcodeWriter.h"
61+
#include "llvm/IR/Constants.h"
6162
#include "llvm/IR/LLVMContext.h"
6263
#include "llvm/IR/Module.h"
6364
#include "llvm/IR/Verifier.h"
@@ -877,7 +878,8 @@ amd_comgr_status_t AMDGPUCompiler::removeTmpDirs() {
877878
#endif
878879
}
879880

880-
amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
881+
amd_comgr_status_t AMDGPUCompiler::processFile(DataObject *Input,
882+
const char *InputFilePath,
881883
const char *OutputFilePath) {
882884
SmallVector<const char *, 128> Argv = Args;
883885

@@ -899,6 +901,12 @@ amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
899901
Argv.push_back("-save-temps=obj");
900902
}
901903

904+
// Add SPIR-V flags
905+
for (auto Flag : Input->SpirvFlags) {
906+
Argv.push_back("-Xclang");
907+
Argv.push_back(Flag);
908+
}
909+
902910
Argv.push_back(InputFilePath);
903911

904912
Argv.push_back("-o");
@@ -910,6 +918,12 @@ amd_comgr_status_t AMDGPUCompiler::processFile(const char *InputFilePath,
910918
amd_comgr_status_t
911919
AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
912920
const char *OutputSuffix) {
921+
return processFiles(OutputKind, OutputSuffix, InSet);
922+
}
923+
924+
amd_comgr_status_t
925+
AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
926+
const char *OutputSuffix, DataSet *InSet) {
913927
for (auto *Input : InSet->DataObjects) {
914928
if (Input->DataKind != AMD_COMGR_DATA_KIND_INCLUDE) {
915929
continue;
@@ -947,7 +961,7 @@ AMDGPUCompiler::processFiles(amd_comgr_data_kind_t OutputKind,
947961
auto OutputFilePath = getFilePath(Output, OutputDir);
948962

949963
if (auto Status =
950-
processFile(InputFilePath.c_str(), OutputFilePath.c_str())) {
964+
processFile(Input, InputFilePath.c_str(), OutputFilePath.c_str())) {
951965
return Status;
952966
}
953967

@@ -1888,11 +1902,106 @@ amd_comgr_status_t AMDGPUCompiler::linkToExecutable() {
18881902
return amd_comgr_data_set_add(OutSetT, OutputT);
18891903
}
18901904

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

19022011
auto Cache = CommandCache::get(LogS);
19032012

1904-
for (auto *Input : InSet->DataObjects) {
2013+
for (auto *Input : SpirvInSet->DataObjects) {
19052014

19062015
if (env::shouldSaveTemps()) {
19072016
if (auto Status = outputToFile(Input, getFilePath(Input, InputDir))) {
@@ -1939,7 +2048,8 @@ amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
19392048
Output->setName(std::string(Input->Name) + std::string(".bc"));
19402049
Output->setData(OutBuf);
19412050

1942-
if (auto Status = amd_comgr_data_set_add(OutSetT, OutputT)) {
2051+
if (auto Status =
2052+
amd_comgr_data_set_add(DataSet::convert(BcOutSet), OutputT)) {
19432053
return Status;
19442054
}
19452055

@@ -1960,6 +2070,50 @@ amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
19602070
#endif
19612071
}
19622072

2073+
amd_comgr_status_t AMDGPUCompiler::compileSpirvToRelocatable() {
2074+
if (auto Status = createTmpDirs()) {
2075+
return Status;
2076+
}
2077+
2078+
for (auto *Input : InSet->DataObjects) {
2079+
if (Input->DataKind != AMD_COMGR_DATA_KIND_SPIRV)
2080+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
2081+
}
2082+
2083+
// Translate .spv to .bc
2084+
amd_comgr_data_set_t TranslatedSpirvT;
2085+
if (auto Status = amd_comgr_create_data_set(&TranslatedSpirvT))
2086+
return Status;
2087+
DataSet *TranslatedSpirv = DataSet::convert(TranslatedSpirvT);
2088+
2089+
if (auto Status = translateSpirvToBitcodeImpl(InSet, TranslatedSpirv))
2090+
return Status;
2091+
2092+
// Extract relevant -cc1 flags from @llvm.cmdline
2093+
if (auto Status = extractSpirvFlags(TranslatedSpirv))
2094+
return Status;
2095+
2096+
// Compile bitcode to relocatable
2097+
if (ActionInfo->IsaName) {
2098+
if (auto Status = addTargetIdentifierFlags(ActionInfo->IsaName)) {
2099+
return Status;
2100+
}
2101+
}
2102+
2103+
if (ActionInfo->ShouldLinkDeviceLibs) {
2104+
if (auto Status = addDeviceLibraries()) {
2105+
return Status;
2106+
}
2107+
}
2108+
2109+
Args.push_back("-c");
2110+
2111+
Args.push_back("-mllvm");
2112+
Args.push_back("-amdgpu-internalize-symbols");
2113+
2114+
return processFiles(AMD_COMGR_DATA_KIND_RELOCATABLE, ".o", TranslatedSpirv);
2115+
}
2116+
19632117
AMDGPUCompiler::AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet,
19642118
DataSet *OutSet, raw_ostream &LogS)
19652119
: 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
@@ -69,19 +69,25 @@ class AMDGPUCompiler {
6969

7070
amd_comgr_status_t createTmpDirs();
7171
amd_comgr_status_t removeTmpDirs();
72-
amd_comgr_status_t processFile(const char *InputFilePath,
72+
amd_comgr_status_t processFile(DataObject *Input, const char *InputFilePath,
7373
const char *OutputFilePath);
7474
/// Process each file in @c InSet individually, placing output in @c OutSet.
7575
amd_comgr_status_t processFiles(amd_comgr_data_kind_t OutputKind,
7676
const char *OutputSuffix);
77+
amd_comgr_status_t processFiles(amd_comgr_data_kind_t OutputKind,
78+
const char *OutputSuffix, DataSet *InSet);
7779
amd_comgr_status_t addIncludeFlags();
7880
amd_comgr_status_t addTargetIdentifierFlags(llvm::StringRef IdentStr,
7981
bool CompilingSrc);
8082
amd_comgr_status_t addCompilationFlags();
8183
amd_comgr_status_t addDeviceLibraries();
84+
amd_comgr_status_t extractSpirvFlags(DataSet *BcSet);
8285

8386
amd_comgr_status_t executeInProcessDriver(llvm::ArrayRef<const char *> Args);
8487

88+
amd_comgr_status_t translateSpirvToBitcodeImpl(DataSet *SpirvInSet,
89+
DataSet *BcOutSet);
90+
8591
public:
8692
AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet, DataSet *OutSet,
8793
llvm::raw_ostream &LogS);
@@ -98,6 +104,7 @@ class AMDGPUCompiler {
98104
amd_comgr_status_t linkToRelocatable();
99105
amd_comgr_status_t linkToExecutable();
100106
amd_comgr_status_t compileToExecutable();
107+
amd_comgr_status_t compileSpirvToRelocatable();
101108
amd_comgr_status_t translateSpirvToBitcode();
102109

103110
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
4141
add_comgr_lit_binary(source-to-bc-with-dev-libs c)
4242
add_comgr_lit_binary(spirv-translator c)
4343
add_comgr_lit_binary(compile-minimal-test c)
44+
add_comgr_lit_binary(spirv-to-reloc c)
4445

4546
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)