Skip to content

Commit 6d15522

Browse files
lamb-jsearlmc1
authored andcommitted
[Comgr] Add initial SPIR-V translation support
In this commit, we add a new SPIR-V data type: AMD_COMGR_DATA_KIND_SPIRV and translation action: AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC With this data type and action, users can provide a set of SPIR-V (.spv) files, and have Comgr translate them into a set of LLVM IR bitcode (.bc) objects. We also add a HIP and OpenCL test for the new translation action. The HIP test is currently disabled until compiler support is finalized. Change-Id: Ic05c880158b9c4fd49550a5b2e51bb26dfed0efc
1 parent acd3795 commit 6d15522

File tree

10 files changed

+225
-3
lines changed

10 files changed

+225
-3
lines changed

amd/comgr/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ else()
405405
Support
406406
Symbolize
407407
TargetParser
408+
SPIRVAMDLib
408409
)
409410
endif()
410411

amd/comgr/docs/ReleaseNotes.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ action, and Comgr will internally unbundle and link via the OffloadBundler and l
153153
- (Data Type) AMD\_COMGR\_DATA\_KIND\_OBJ\_BUNDLE
154154
- This data kind represents a clang-offload-bundle of object files, and can be
155155
passed when calling the AMD\_COMGR\_ACTION\_UNBUNDLE action
156-
156+
- (Data Type) AMD\_COMGR\_DATA\_KIND\_SPIRV
157+
- This data kind represents a SPIR-V binary file (.spv)
158+
- (Action) AMD\_COMGR\_ACTION\_TRANSLATE\_SPIRV\_TO\_BC
159+
- This accepts a set of SPIR-V (.spv) inputs, and returns a set of translated
160+
bitcode (.bc) outputs
157161

158162
Deprecated Comgr Actions and Data Types
159163
---------------------------------------

amd/comgr/include/amd_comgr.h.in

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,14 @@ typedef enum amd_comgr_data_kind_s {
392392
* The data is an object file bundle.
393393
*/
394394
AMD_COMGR_DATA_KIND_OBJ_BUNDLE = 0x14,
395+
/**
396+
* The data is SPIR-V IR
397+
*/
398+
AMD_COMGR_DATA_KIND_SPIRV = 0x15,
395399
/**
396400
* Marker for last valid data kind.
397401
*/
398-
AMD_COMGR_DATA_KIND_LAST = AMD_COMGR_DATA_KIND_OBJ_BUNDLE
402+
AMD_COMGR_DATA_KIND_LAST = AMD_COMGR_DATA_KIND_SPIRV
399403
} amd_comgr_data_kind_t;
400404

401405
/**
@@ -1772,10 +1776,21 @@ typedef enum amd_comgr_action_kind_s {
17721776
*/
17731777
AMD_COMGR_ACTION_UNBUNDLE = 0xF,
17741778

1779+
/**
1780+
* Translate each source SPIR-V object in @p input into LLVM IR Bitcode.
1781+
* For each successful translation, add a bc object to @p result *
1782+
*
1783+
* Return @p AMD_COMGR_STATUS_ERROR if any translation fails
1784+
*
1785+
* Return @p AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT
1786+
* if any input is not SPIR-V.
1787+
*/
1788+
AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC = 0x13,
1789+
17751790
/**
17761791
* Marker for last valid action kind.
17771792
*/
1778-
AMD_COMGR_ACTION_LAST = AMD_COMGR_ACTION_UNBUNDLE
1793+
AMD_COMGR_ACTION_LAST = AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC
17791794
} amd_comgr_action_kind_t;
17801795

17811796
/**

amd/comgr/src/comgr-compiler.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@
8181
#include "llvm/Support/WithColor.h"
8282
#include "llvm/TargetParser/Host.h"
8383

84+
#include "LLVMSPIRVLib/LLVMSPIRVLib.h"
8485
#include "time-stat/ts-interface.h"
8586

8687
#include <csignal>
88+
#include <sstream>
8789

8890
LLD_HAS_DRIVER(elf)
8991

@@ -1849,6 +1851,63 @@ amd_comgr_status_t AMDGPUCompiler::linkToExecutable() {
18491851
return amd_comgr_data_set_add(OutSetT, OutputT);
18501852
}
18511853

1854+
amd_comgr_status_t AMDGPUCompiler::translateSpirvToBitcode() {
1855+
if (auto Status = createTmpDirs()) {
1856+
return Status;
1857+
}
1858+
1859+
LLVMContext Context;
1860+
Context.setDiagnosticHandler(
1861+
std::make_unique<AMDGPUCompilerDiagnosticHandler>(this), true);
1862+
1863+
for (auto *Input : InSet->DataObjects) {
1864+
1865+
if (Input->DataKind != AMD_COMGR_DATA_KIND_SPIRV) {
1866+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
1867+
}
1868+
1869+
// TODO: With C++23, we should investigate replacing with spanstream
1870+
// to avoid memory copies:
1871+
// https://en.cppreference.com/w/cpp/io/basic_ispanstream
1872+
std::istringstream ISS(std::string(Input->Data, Input->Size));
1873+
1874+
llvm::Module *M;
1875+
std::string Err;
1876+
1877+
if (!llvm::readSpirv(Context, ISS, M, Err)) {
1878+
LogS << "Failed to load SPIR-V as LLVM Module: " << Err << '\n';
1879+
return AMD_COMGR_STATUS_ERROR;
1880+
}
1881+
1882+
SmallString<0> OutBuf;
1883+
BitcodeWriter Writer(OutBuf);
1884+
Writer.writeModule(*M, false, nullptr, false, nullptr);
1885+
Writer.writeSymtab();
1886+
Writer.writeStrtab();
1887+
1888+
amd_comgr_data_t OutputT;
1889+
if (auto Status = amd_comgr_create_data(AMD_COMGR_DATA_KIND_BC, &OutputT)) {
1890+
return Status;
1891+
}
1892+
1893+
// OutputT can be released after addition to the data_set
1894+
ScopedDataObjectReleaser SDOR(OutputT);
1895+
1896+
DataObject *Output = DataObject::convert(OutputT);
1897+
Output->setName(std::string(Input->Name) + std::string(".bc"));
1898+
Output->setData(OutBuf);
1899+
1900+
if (auto Status = amd_comgr_data_set_add(OutSetT, OutputT)) {
1901+
return Status;
1902+
}
1903+
1904+
LogS << "SPIR-V Translation: amd-llvm-spirv -r " << Input->Name << " " <<
1905+
Output->Name << "\n";
1906+
}
1907+
1908+
return AMD_COMGR_STATUS_SUCCESS;
1909+
}
1910+
18521911
AMDGPUCompiler::AMDGPUCompiler(DataAction *ActionInfo, DataSet *InSet,
18531912
DataSet *OutSet, raw_ostream &LogS)
18541913
: ActionInfo(ActionInfo), InSet(InSet), OutSetT(DataSet::convert(OutSet)),

amd/comgr/src/comgr-compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class AMDGPUCompiler {
140140
amd_comgr_status_t linkToRelocatable();
141141
amd_comgr_status_t linkToExecutable();
142142
amd_comgr_status_t compileToExecutable();
143+
amd_comgr_status_t translateSpirvToBitcode();
143144

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

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_TRANSLATE_SPIRV_TO_BC:
191+
return Compiler.translateSpirvToBitcode();
190192

191193
default:
192194
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
@@ -289,6 +291,8 @@ StringRef getActionKindName(amd_comgr_action_kind_t ActionKind) {
289291
return "AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE";
290292
case AMD_COMGR_ACTION_UNBUNDLE:
291293
return "AMD_COMGR_ACTION_UNBUNDLE";
294+
case AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC:
295+
return "AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC";
292296
}
293297

294298
llvm_unreachable("invalid action");
@@ -1368,6 +1372,7 @@ amd_comgr_status_t AMD_COMGR_API
13681372
case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_RELOCATABLE:
13691373
case AMD_COMGR_ACTION_COMPILE_SOURCE_WITH_DEVICE_LIBS_TO_BC:
13701374
case AMD_COMGR_ACTION_COMPILE_SOURCE_TO_EXECUTABLE:
1375+
case AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC:
13711376
ActionStatus = dispatchCompilerAction(ActionKind, ActionInfoP, InputSetP,
13721377
ResultSetP, *LogP);
13731378
break;

amd/comgr/test-lit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ endmacro()
2424
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
2525

2626
add_comgr_lit_binary(source-to-bc-with-dev-libs)
27+
add_comgr_lit_binary(spirv-translator)
2728

2829
add_dependencies(check-comgr test-lit)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "amd_comgr.h"
2+
#include "common.h"
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
// Tests the AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC action
8+
// Accepts one or more .spv files, and returns one or more .bc files
9+
10+
int main(int argc, char *argv[]) {
11+
char *BufSpirv;
12+
size_t SizeSpirv;
13+
amd_comgr_data_t DataSpirv;
14+
amd_comgr_data_set_t DataSetSpirv, DataSetBc;
15+
amd_comgr_action_info_t DataAction;
16+
amd_comgr_status_t Status;
17+
size_t Count;
18+
19+
if (argc != 4) {
20+
fprintf(stderr, "Usage: spirv-translator file.spv -o file.spv.bc\n");
21+
exit(1);
22+
}
23+
24+
SizeSpirv = setBuf(argv[1], &BufSpirv);
25+
26+
amd_comgr_(create_data_set(&DataSetSpirv));
27+
amd_comgr_(create_data(AMD_COMGR_DATA_KIND_SPIRV, &DataSpirv));
28+
amd_comgr_(set_data(DataSpirv, SizeSpirv, BufSpirv));
29+
amd_comgr_(set_data_name(DataSpirv, "source.spv"));
30+
amd_comgr_(data_set_add(DataSetSpirv, DataSpirv));
31+
32+
amd_comgr_(create_action_info(&DataAction));
33+
amd_comgr_(create_data_set(&DataSetBc));
34+
35+
amd_comgr_(do_action(AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC,
36+
DataAction, DataSetSpirv, DataSetBc));
37+
38+
amd_comgr_(action_data_count(DataSetBc, AMD_COMGR_DATA_KIND_BC, &Count));
39+
40+
if (Count != 1) {
41+
printf("AMD_COMGR_ACTION_COMPILE_SOURCE_TO_BC Failed: "
42+
"produced %zu BC objects (expected 1)\n",
43+
Count);
44+
exit(1);
45+
}
46+
47+
// Write bitcode to file
48+
amd_comgr_data_t DataSpirvBc;
49+
50+
amd_comgr_(action_data_get_data(
51+
DataSetBc, AMD_COMGR_DATA_KIND_BC, 0, &DataSpirvBc));
52+
53+
dumpData(DataSpirvBc, argv[3]);
54+
55+
amd_comgr_(release_data(DataSpirv));
56+
amd_comgr_(destroy_data_set(DataSetSpirv));
57+
amd_comgr_(destroy_data_set(DataSetBc));
58+
amd_comgr_(destroy_action_info(DataAction));
59+
free(BufSpirv);
60+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// COM: Enable this test once changes from amdspirv docker land
2+
3+
// COM: Generate a spirv-targeted LLVM IR file from an OpenCL kernel
4+
// RUN: clang -c -emit-llvm --target=spirv64 %s -o %t.bc
5+
6+
// COM: Translate LLVM IR to SPIRV format
7+
// RUN: amd-llvm-spirv %t.bc -o %t.spv
8+
9+
// COM: Run Comgr Translator to covert SPIRV back to LLVM IR
10+
// RUN: spirv-translator %t.spv -o %t.translated.bc
11+
12+
// COM: Dissasemble LLVM IR bitcode to LLVM IR text
13+
// RUN: llvm-dis %t.translated.bc -o - | FileCheck %s
14+
15+
// COM: Verify LLVM IR text
16+
// CHECK: target triple = "spir64-unknown-unknown"
17+
// CHECK: define spir_kernel void @source
18+
19+
void kernel source(__global int *j) {
20+
*j += 2;
21+
}
22+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// XFAIL: *
2+
// COM: Generate a SPIRV file from a HIP kernel
3+
// RUN: clang -x hip --offload-arch=amdgcnspirv -nogpulib -nogpuinc \
4+
// RUN: --no-gpu-bundle-output --offload-device-only -O3 %s -o %t.spv
5+
6+
// COM: Run Comgr Translator to covert SPIRV back to LLVM IR
7+
// RUN: spirv-translator %t.spv -o %t.translated.bc
8+
9+
// COM: Dissasemble LLVM IR bitcode to LLVM IR text
10+
// RUN: llvm-dis %t.translated.bc -o - | FileCheck %s
11+
12+
// COM: Verify LLVM IR text
13+
// CHECK: target triple = "amdgcn-amd-amdhsa"
14+
// CHECK: define void @_Z11clean_valuePf
15+
// CHECK: define amdgpu_kernel void @_Z9add_valuePfS_S_
16+
17+
#include <cstdlib>
18+
19+
#define __constant__ __attribute__((constant))
20+
#define __device__ __attribute__((device))
21+
#define __global__ __attribute__((global))
22+
#define __host__ __attribute__((host))
23+
#define __shared__ __attribute__((shared))
24+
#define __managed__ __attribute__((managed))
25+
#define __launch_bounds__(...) __attribute__((launch_bounds(__VA_ARGS__)))
26+
27+
struct dim3 {
28+
unsigned x, y, z;
29+
__host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1) : x(x), y(y), z(z) {}
30+
};
31+
32+
#ifdef __HIP__
33+
typedef struct hipStream *hipStream_t;
34+
typedef enum hipError {} hipError_t;
35+
int hipConfigureCall(dim3 gridSize, dim3 blockSize, size_t sharedSize = 0,
36+
hipStream_t stream = 0);
37+
extern "C" hipError_t __hipPushCallConfiguration(dim3 gridSize, dim3 blockSize,
38+
size_t sharedSize = 0,
39+
hipStream_t stream = 0);
40+
extern "C" hipError_t hipLaunchKernel(const void *func, dim3 gridDim,
41+
dim3 blockDim, void **args,
42+
size_t sharedMem,
43+
hipStream_t stream);
44+
#endif
45+
46+
__attribute__((device))
47+
void clean_value(float* ptr) { *ptr = 0; }
48+
49+
__attribute__((global))
50+
void add_value(float* a, float* b, float* res) {
51+
*res = *a + *b;
52+
53+
clean_value(a);
54+
}

0 commit comments

Comments
 (0)