Skip to content

Commit 0c2fe3e

Browse files
sarnexsys-ce-bb
authored andcommitted
Add option to control builtin format for reverse translation (#1986)
Currently, we always convert SPIR-V bultins to globals for forward translation and to functions for reverse translation. I have a use case where I want to keep them as globals for reverse translation, so I added this mode. Implementations for both cases already existed, I just consolidated them and added the option. Signed-off-by: Sarnie, Nick <[email protected]> Original commit: KhronosGroup/SPIRV-LLVM-Translator@730eaf0
1 parent fcdebe6 commit 0c2fe3e

File tree

10 files changed

+182
-78
lines changed

10 files changed

+182
-78
lines changed

llvm-spirv/include/LLVMSPIRVOpts.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ enum class DebugInfoEIS : uint32_t {
8787
NonSemantic_Shader_DebugInfo_200
8888
};
8989

90+
enum class BuiltinFormat : uint32_t { Function, Global };
91+
9092
/// \brief Helper class to manage SPIR-V translation
9193
class TranslatorOpts {
9294
public:
@@ -199,6 +201,11 @@ class TranslatorOpts {
199201
PreserveOCLKernelArgTypeMetadataThroughString = Value;
200202
}
201203

204+
void setBuiltinFormat(BuiltinFormat Value) noexcept {
205+
SPIRVBuiltinFormat = Value;
206+
}
207+
BuiltinFormat getBuiltinFormat() const noexcept { return SPIRVBuiltinFormat; }
208+
202209
private:
203210
// Common translation options
204211
VersionNumber MaxVersion = VersionNumber::MaximumVersion;
@@ -241,6 +248,8 @@ class TranslatorOpts {
241248
bool PreserveOCLKernelArgTypeMetadataThroughString = false;
242249

243250
bool PreserveAuxData = false;
251+
252+
BuiltinFormat SPIRVBuiltinFormat = BuiltinFormat::Function;
244253
};
245254

246255
} // namespace SPIRV

llvm-spirv/lib/SPIRV/SPIRVInternal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,13 @@ bool lowerBuiltinVariableToCall(GlobalVariable *GV,
991991
// Transform all builtin variables into calls
992992
bool lowerBuiltinVariablesToCalls(Module *M);
993993

994+
// Transform all builtin calls into variables
995+
bool lowerBuiltinCallsToVariables(Module *M);
996+
997+
// Transform all builtins into variables or calls
998+
// depending on user specification
999+
bool lowerBuiltins(SPIRVModule *BM, Module *M);
1000+
9941001
/// \brief Post-process OpenCL or SPIRV builtin function returning struct type.
9951002
///
9961003
/// Some builtin functions are translated to SPIR-V instructions with

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,14 +3341,7 @@ bool SPIRVToLLVM::translate() {
33413341
if (!transSourceExtension())
33423342
return false;
33433343
transGeneratorMD();
3344-
// TODO: add an option to control the builtin format in SPV-IR.
3345-
// The primary format should be function calls:
3346-
// e.g. call spir_func i32 @_Z29__spirv_BuiltInGlobalLinearIdv()
3347-
// The secondary format should be global variables:
3348-
// e.g. load i32, i32* @__spirv_BuiltInGlobalLinearId, align 4
3349-
// If the desired format is global variables, we don't have to lower them
3350-
// as calls.
3351-
if (!lowerBuiltinVariablesToCalls(M))
3344+
if (!lowerBuiltins(BM, M))
33523345
return false;
33533346
if (BM->getDesiredBIsRepresentation() == BIsRepresentation::SPIRVFriendlyIR) {
33543347
SPIRVWord SrcLangVer = 0;

llvm-spirv/lib/SPIRV/SPIRVUtil.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,82 @@ bool lowerBuiltinVariablesToCalls(Module *M) {
20972097
return true;
20982098
}
20992099

2100+
/// Transforms SPV-IR work-item builtin calls to SPIRV builtin variables.
2101+
/// e.g.
2102+
/// SPV-IR: @_Z33__spirv_BuiltInGlobalInvocationIdi(i)
2103+
/// is transformed as:
2104+
/// x = load GlobalInvocationId; extract x, i
2105+
/// e.g.
2106+
/// SPV-IR: @_Z22__spirv_BuiltInWorkDim()
2107+
/// is transformed as:
2108+
/// load WorkDim
2109+
bool lowerBuiltinCallsToVariables(Module *M) {
2110+
LLVM_DEBUG(dbgs() << "Enter lowerBuiltinCallsToVariables\n");
2111+
// Store instructions and functions that need to be removed.
2112+
SmallVector<Value *, 16> ToRemove;
2113+
for (auto &F : *M) {
2114+
// Builtins should be declaration only.
2115+
if (!F.isDeclaration())
2116+
continue;
2117+
StringRef DemangledName;
2118+
if (!oclIsBuiltin(F.getName(), DemangledName))
2119+
continue;
2120+
LLVM_DEBUG(dbgs() << "Function demangled name: " << DemangledName << '\n');
2121+
SmallVector<StringRef, 2> Postfix;
2122+
// Deprefix "__spirv_"
2123+
StringRef Name = dePrefixSPIRVName(DemangledName, Postfix);
2124+
// Lookup SPIRV Builtin map.
2125+
if (!SPIRVBuiltInNameMap::rfind(Name.str(), nullptr))
2126+
continue;
2127+
std::string BuiltinVarName = DemangledName.str();
2128+
LLVM_DEBUG(dbgs() << "builtin variable name: " << BuiltinVarName << '\n');
2129+
bool IsVec = F.getFunctionType()->getNumParams() > 0;
2130+
Type *GVType =
2131+
IsVec ? FixedVectorType::get(F.getReturnType(), 3) : F.getReturnType();
2132+
auto *BV = new GlobalVariable(
2133+
*M, GVType, /*isConstant=*/true, GlobalValue::ExternalLinkage, nullptr,
2134+
BuiltinVarName, 0, GlobalVariable::NotThreadLocal, SPIRAS_Input);
2135+
for (auto *U : F.users()) {
2136+
auto *CI = dyn_cast<CallInst>(U);
2137+
assert(CI && "invalid instruction");
2138+
const DebugLoc &DLoc = CI->getDebugLoc();
2139+
Instruction *NewValue = new LoadInst(GVType, BV, "", CI);
2140+
if (DLoc)
2141+
NewValue->setDebugLoc(DLoc);
2142+
LLVM_DEBUG(dbgs() << "Transform: " << *CI << " => " << *NewValue << '\n');
2143+
if (IsVec) {
2144+
NewValue =
2145+
ExtractElementInst::Create(NewValue, CI->getArgOperand(0), "", CI);
2146+
if (DLoc)
2147+
NewValue->setDebugLoc(DLoc);
2148+
LLVM_DEBUG(dbgs() << *NewValue << '\n');
2149+
}
2150+
NewValue->takeName(CI);
2151+
CI->replaceAllUsesWith(NewValue);
2152+
ToRemove.push_back(CI);
2153+
}
2154+
ToRemove.push_back(&F);
2155+
}
2156+
for (auto *V : ToRemove) {
2157+
if (auto *I = dyn_cast<Instruction>(V))
2158+
I->eraseFromParent();
2159+
else if (auto *F = dyn_cast<Function>(V))
2160+
F->eraseFromParent();
2161+
else
2162+
llvm_unreachable("Unexpected value to remove!");
2163+
}
2164+
return true;
2165+
}
2166+
2167+
bool lowerBuiltins(SPIRVModule *BM, Module *M) {
2168+
auto Format = BM->getBuiltinFormat();
2169+
if (Format == BuiltinFormat::Function && !lowerBuiltinVariablesToCalls(M))
2170+
return false;
2171+
if (Format == BuiltinFormat::Global && !lowerBuiltinCallsToVariables(M))
2172+
return false;
2173+
return true;
2174+
}
2175+
21002176
bool postProcessBuiltinReturningStruct(Function *F) {
21012177
Module *M = F->getParent();
21022178
LLVMContext *Context = &M->getContext();

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,73 +2901,6 @@ bool LLVMToSPIRVBase::transBuiltinSet() {
29012901
return true;
29022902
}
29032903

2904-
/// Transforms SPV-IR work-item builtin calls to SPIRV builtin variables.
2905-
/// e.g.
2906-
/// SPV-IR: @_Z33__spirv_BuiltInGlobalInvocationIdi(i)
2907-
/// is transformed as:
2908-
/// x = load GlobalInvocationId; extract x, i
2909-
/// e.g.
2910-
/// SPV-IR: @_Z22__spirv_BuiltInWorkDim()
2911-
/// is transformed as:
2912-
/// load WorkDim
2913-
bool LLVMToSPIRVBase::transWorkItemBuiltinCallsToVariables() {
2914-
LLVM_DEBUG(dbgs() << "Enter transWorkItemBuiltinCallsToVariables\n");
2915-
// Store instructions and functions that need to be removed.
2916-
SmallVector<Value *, 16> ToRemove;
2917-
for (auto &F : *M) {
2918-
// Builtins should be declaration only.
2919-
if (!F.isDeclaration())
2920-
continue;
2921-
StringRef DemangledName;
2922-
if (!oclIsBuiltin(F.getName(), DemangledName))
2923-
continue;
2924-
LLVM_DEBUG(dbgs() << "Function demangled name: " << DemangledName << '\n');
2925-
SmallVector<StringRef, 2> Postfix;
2926-
// Deprefix "__spirv_"
2927-
StringRef Name = dePrefixSPIRVName(DemangledName, Postfix);
2928-
// Lookup SPIRV Builtin map.
2929-
if (!SPIRVBuiltInNameMap::rfind(Name.str(), nullptr))
2930-
continue;
2931-
std::string BuiltinVarName = DemangledName.str();
2932-
LLVM_DEBUG(dbgs() << "builtin variable name: " << BuiltinVarName << '\n');
2933-
bool IsVec = F.getFunctionType()->getNumParams() > 0;
2934-
Type *GVType =
2935-
IsVec ? FixedVectorType::get(F.getReturnType(), 3) : F.getReturnType();
2936-
auto *BV = new GlobalVariable(
2937-
*M, GVType, /*isConstant=*/true, GlobalValue::ExternalLinkage, nullptr,
2938-
BuiltinVarName, 0, GlobalVariable::NotThreadLocal, SPIRAS_Input);
2939-
for (auto *U : F.users()) {
2940-
auto *CI = dyn_cast<CallInst>(U);
2941-
assert(CI && "invalid instruction");
2942-
const DebugLoc &DLoc = CI->getDebugLoc();
2943-
Instruction *NewValue = new LoadInst(GVType, BV, "", CI);
2944-
if (DLoc)
2945-
NewValue->setDebugLoc(DLoc);
2946-
LLVM_DEBUG(dbgs() << "Transform: " << *CI << " => " << *NewValue << '\n');
2947-
if (IsVec) {
2948-
NewValue =
2949-
ExtractElementInst::Create(NewValue, CI->getArgOperand(0), "", CI);
2950-
if (DLoc)
2951-
NewValue->setDebugLoc(DLoc);
2952-
LLVM_DEBUG(dbgs() << *NewValue << '\n');
2953-
}
2954-
NewValue->takeName(CI);
2955-
CI->replaceAllUsesWith(NewValue);
2956-
ToRemove.push_back(CI);
2957-
}
2958-
ToRemove.push_back(&F);
2959-
}
2960-
for (auto *V : ToRemove) {
2961-
if (auto *I = dyn_cast<Instruction>(V))
2962-
I->eraseFromParent();
2963-
else if (auto *F = dyn_cast<Function>(V))
2964-
F->eraseFromParent();
2965-
else
2966-
llvm_unreachable("Unexpected value to remove!");
2967-
}
2968-
return true;
2969-
}
2970-
29712904
/// Translate sampler* spcv.cast(i32 arg) or
29722905
/// sampler* __translate_sampler_initializer(i32 arg)
29732906
/// Three cases are possible:
@@ -5186,8 +5119,7 @@ bool LLVMToSPIRVBase::translate() {
51865119
if (isEmptyLLVMModule(M))
51875120
BM->addCapability(CapabilityLinkage);
51885121

5189-
// Transform SPV-IR builtin calls to builtin variables.
5190-
if (!transWorkItemBuiltinCallsToVariables())
5122+
if (!lowerBuiltinCallsToVariables(M))
51915123
return false;
51925124

51935125
// Use the type scavenger to recover pointer element types.

llvm-spirv/lib/SPIRV/SPIRVWriter.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ class LLVMToSPIRVBase : protected BuiltinCallHelper {
106106
bool transSourceLanguage();
107107
bool transExtension();
108108
bool transBuiltinSet();
109-
bool transWorkItemBuiltinCallsToVariables();
110109
bool isKnownIntrinsic(Intrinsic::ID Id);
111110
SPIRVValue *transIntrinsicInst(IntrinsicInst *Intrinsic, SPIRVBasicBlock *BB);
112111
SPIRVValue *transFenceInst(FenceInst *FI, SPIRVBasicBlock *BB);

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,10 @@ class SPIRVModule {
531531
return TranslationOpts.preserveAuxData();
532532
}
533533

534+
BuiltinFormat getBuiltinFormat() const noexcept {
535+
return TranslationOpts.getBuiltinFormat();
536+
}
537+
534538
SPIRVExtInstSetKind getDebugInfoEIS() const {
535539
switch (TranslationOpts.getDebugInfoEIS()) {
536540
case DebugInfoEIS::SPIRV_Debug:

llvm-spirv/test/builtin-functions.ll

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -spirv-text -o %t
3+
; RUN: llvm-spirv -r %t -spirv-text --spirv-target-env=SPV-IR --spirv-builtin-format=function -o %t2_rev.bc
4+
; RUN: llvm-spirv -r %t -spirv-text --spirv-target-env=SPV-IR --spirv-builtin-format=global -o %t3_rev.bc
5+
; RUN: llvm-spirv -r %t -spirv-text --spirv-builtin-format=function -o %t2_rev_ocl.bc
6+
; RUN: llvm-dis < %t2_rev.bc | FileCheck --check-prefix=CHECK-FUNCTION-FORMAT-REV %s
7+
; RUN: llvm-dis < %t3_rev.bc | FileCheck --check-prefix=CHECK-GLOBAL-FORMAT-REV %s
8+
; RUN: llvm-dis < %t2_rev_ocl.bc | FileCheck --check-prefix=CHECK-FUNCTION-FORMAT-OCL-REV %s
9+
; RUN: llvm-spirv %t.bc -o %t.spv
10+
; RUN: spirv-val %t.spv
11+
; RUN: llvm-spirv %t.bc --spirv-builtin-format=function -o %t2.spv
12+
; RUN: spirv-val %t2.spv
13+
; RUN: llvm-spirv %t.bc --spirv-builtin-format=global -o %t3.spv
14+
; RUN: spirv-val %t3.spv
15+
16+
; CHECK-FUNCTION-FORMAT-REV: declare spir_func i64 @_Z26__spirv_BuiltInWorkgroupIdi(i32)
17+
; CHECK-FUNCTION-FORMAT-OCL-REV: declare spir_func i64 @_Z12get_group_idj(i32)
18+
19+
; CHECK-GLOBAL-FORMAT-REV: @__spirv_BuiltInWorkgroupId = external addrspace(7) constant <3 x i64>
20+
21+
; ModuleID = 'test.bc'
22+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
23+
target triple = "spir64-unknown-unknown"
24+
25+
; Function Attrs: nounwind
26+
declare spir_func i64 @_Z26__spirv_BuiltInWorkgroupIdi(i32) #0
27+
28+
; Function Attrs: convergent norecurse nounwind
29+
define weak_odr dso_local spir_kernel void @foo() {
30+
entry:
31+
%0 = call spir_func i64 @_Z26__spirv_BuiltInWorkgroupIdi(i32 0) #0
32+
ret void
33+
}

llvm-spirv/test/builtin-globals.ll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -spirv-text -o %t
3+
; RUN: llvm-spirv -r %t -spirv-text --spirv-target-env=SPV-IR --spirv-builtin-format=function -o %t2_rev.bc
4+
; RUN: llvm-spirv -r %t -spirv-text --spirv-target-env=SPV-IR --spirv-builtin-format=global -o %t3_rev.bc
5+
; RUN: llvm-spirv -r %t -spirv-text --spirv-builtin-format=function -o %t2_rev_ocl.bc
6+
; RUN: llvm-dis < %t2_rev.bc | FileCheck --check-prefix=CHECK-FUNCTION-FORMAT-REV %s
7+
; RUN: llvm-dis < %t3_rev.bc | FileCheck --check-prefix=CHECK-GLOBAL-FORMAT-REV %s
8+
; RUN: llvm-dis < %t2_rev_ocl.bc | FileCheck --check-prefix=CHECK-FUNCTION-FORMAT-OCL-REV %s
9+
; RUN: llvm-spirv %t.bc -o %t.spv
10+
; RUN: spirv-val %t.spv
11+
; RUN: llvm-spirv %t.bc --spirv-builtin-format=function -o %t2.spv
12+
; RUN: spirv-val %t2.spv
13+
; RUN: llvm-spirv %t.bc --spirv-builtin-format=global -o %t3.spv
14+
; RUN: spirv-val %t3.spv
15+
16+
; CHECK-FUNCTION-FORMAT-REV: declare spir_func i64 @_Z26__spirv_BuiltInWorkgroupIdi(i32)
17+
; CHECK-FUNCTION-FORMAT-OCL-REV: declare spir_func i64 @_Z12get_group_idj(i32)
18+
19+
; CHECK-GLOBAL-FORMAT-REV: @__spirv_BuiltInWorkgroupId = external addrspace(1) constant <3 x i64>, align 32
20+
21+
; ModuleID = 'test.bc'
22+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
23+
target triple = "spir64-unknown-unknown"
24+
25+
@__spirv_BuiltInWorkgroupId = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32
26+
27+
; Function Attrs: convergent norecurse nounwind
28+
define weak_odr dso_local spir_kernel void @foo() {
29+
entry:
30+
%0 = load i64, i64 addrspace(1)* getelementptr inbounds (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInWorkgroupId, i64 0, i64 0), align 32
31+
ret void
32+
}

llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,16 @@ static cl::opt<bool> SPIRVReplaceLLVMFmulAddWithOpenCLMad(
261261
"instruction from OpenCL extended instruction set"),
262262
cl::init(true));
263263

264+
static cl::opt<SPIRV::BuiltinFormat> SPIRVBuiltinFormat(
265+
"spirv-builtin-format",
266+
cl::desc("Set LLVM-IR representation of SPIR-V builtin variables:"),
267+
cl::init(SPIRV::BuiltinFormat::Function),
268+
cl::values(
269+
clEnumValN(SPIRV::BuiltinFormat::Function, "function",
270+
"Use functions to represent SPIR-V builtin variables"),
271+
clEnumValN(SPIRV::BuiltinFormat::Global, "global",
272+
"Use globals to represent SPIR-V builtin variables")));
273+
264274
static std::string removeExt(const std::string &FileName) {
265275
size_t Pos = FileName.find_last_of(".");
266276
if (Pos != std::string::npos)
@@ -715,6 +725,15 @@ int main(int Ac, char **Av) {
715725

716726
Opts.setFPContractMode(FPCMode);
717727

728+
if (SPIRVBuiltinFormat.getNumOccurrences() != 0) {
729+
if (!IsReverse) {
730+
errs() << "Note: --spirv-builtin-format option ignored as it only "
731+
"affects translation from SPIR-V to LLVM IR";
732+
} else {
733+
Opts.setBuiltinFormat(SPIRVBuiltinFormat);
734+
}
735+
}
736+
718737
if (SPIRVMemToReg)
719738
Opts.setMemToRegEnabled(SPIRVMemToReg);
720739
if (SPIRVGenKernelArgNameMD)

0 commit comments

Comments
 (0)