[llvm] 5a07774 - [SPIR-V] Improve how lowering of formal arguments in SPIR-V Backend interprets a value of 'kernel_arg_type' (#78730)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 31 02:58:53 PST 2024
Author: Vyacheslav Levytskyy
Date: 2024-01-31T02:58:50-08:00
New Revision: 5a07774fe11b560652b15776ff6477ba17b6cae0
URL: https://github.com/llvm/llvm-project/commit/5a07774fe11b560652b15776ff6477ba17b6cae0
DIFF: https://github.com/llvm/llvm-project/commit/5a07774fe11b560652b15776ff6477ba17b6cae0.diff
LOG: [SPIR-V] Improve how lowering of formal arguments in SPIR-V Backend interprets a value of 'kernel_arg_type' (#78730)
The goal of this PR is to tolerate differences between description of
formal arguments by function metadata (represented by "kernel_arg_type")
and LLVM actual parameter types. A compiler may use "kernel_arg_type" of
function metadata fields to encode detailed type information, whereas
LLVM IR may utilize for an actual parameter a more general type, in
particular, opaque pointer type. This PR proposes to resolve this by a
fallback to LLVM actual parameter types during the lowering of formal
function arguments in cases when the type can't be created by string
content of "kernel_arg_type", i.e., when "kernel_arg_type" contains a
type unknown for the SPIR-V Backend.
An example of the issue manifestation is
https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/test/transcoding/KernelArgTypeInOpString.ll,
where a compiler generates for the following kernel function detailed
`kernel_arg_type` info in a form of `!{!"image_kernel_data*", !"myInt",
!"struct struct_name*"}`, and in LLVM IR same arguments are referred to
as `@foo(ptr addrspace(1) %in, i32 %out, ptr addrspace(1) %outData)`.
Both definitions are correct, and the resulting LLVM IR is correct, but
lowering stage of SPIR-V Backend fails to generate SPIR-V type.
```
typedef int myInt;
typedef struct {
int width;
int height;
} image_kernel_data;
struct struct_name {
int i;
int y;
};
void kernel foo(__global image_kernel_data* in,
__global struct struct_name *outData,
myInt out) {}
```
```
define spir_kernel void @foo(ptr addrspace(1) %in, i32 %out, ptr addrspace(1) %outData) ... !kernel_arg_type !7 ... {
entry:
ret void
}
...
!7 = !{!"image_kernel_data*", !"myInt", !"struct struct_name*"}
```
The PR changes a contract of `SPIRVType *getArgSPIRVType(...)` in a way
that it may return `nullptr` to signal that the metadata string content
is not recognized, so corresponding comments are added and a couple of
checks for `nullptr` are inserted where appropriate.
Added:
llvm/test/CodeGen/SPIRV/pointers/custom-kernel-arg-type.ll
Modified:
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index c85bd27d256b2..e4593e7db90e8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1386,6 +1386,11 @@ static bool generateSampleImageInst(const StringRef DemangledCall,
ReturnType = ReturnType.substr(0, ReturnType.find('('));
}
SPIRVType *Type = GR->getOrCreateSPIRVTypeByName(ReturnType, MIRBuilder);
+ if (!Type) {
+ std::string DiagMsg =
+ "Unable to recognize SPIRV type name: " + ReturnType;
+ report_fatal_error(DiagMsg.c_str());
+ }
MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
MRI->setRegClass(Call->Arguments[3], &SPIRV::IDRegClass);
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 62c08bab46eee..97b25147ffb34 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -157,22 +157,22 @@ static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx,
isSpecialOpaqueType(OriginalArgType))
return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
- MDString *MDKernelArgType = getOCLKernelArgType(F, ArgIdx);
- if (!MDKernelArgType || (!MDKernelArgType->getString().ends_with("*") &&
- !MDKernelArgType->getString().ends_with("_t")))
- return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
-
- if (MDKernelArgType->getString().ends_with("*"))
- return GR->getOrCreateSPIRVTypeByName(
- MDKernelArgType->getString(), MIRBuilder,
- addressSpaceToStorageClass(OriginalArgType->getPointerAddressSpace()));
-
- if (MDKernelArgType->getString().ends_with("_t"))
- return GR->getOrCreateSPIRVTypeByName(
- "opencl." + MDKernelArgType->getString().str(), MIRBuilder,
- SPIRV::StorageClass::Function, ArgAccessQual);
-
- llvm_unreachable("Unable to recognize argument type name.");
+ SPIRVType *ResArgType = nullptr;
+ if (MDString *MDKernelArgType = getOCLKernelArgType(F, ArgIdx)) {
+ StringRef MDTypeStr = MDKernelArgType->getString();
+ if (MDTypeStr.ends_with("*"))
+ ResArgType = GR->getOrCreateSPIRVTypeByName(
+ MDTypeStr, MIRBuilder,
+ addressSpaceToStorageClass(
+ OriginalArgType->getPointerAddressSpace()));
+ else if (MDTypeStr.ends_with("_t"))
+ ResArgType = GR->getOrCreateSPIRVTypeByName(
+ "opencl." + MDTypeStr.str(), MIRBuilder,
+ SPIRV::StorageClass::Function, ArgAccessQual);
+ }
+ return ResArgType ? ResArgType
+ : GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder,
+ ArgAccessQual);
}
static bool isEntryPoint(const Function &F) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index f9581390c28b9..47fec745c3f18 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -443,8 +443,9 @@ Register SPIRVGlobalRegistry::buildConstantSampler(
SPIRVType *SampTy;
if (SpvType)
SampTy = getOrCreateSPIRVType(getTypeForSPIRVType(SpvType), MIRBuilder);
- else
- SampTy = getOrCreateSPIRVTypeByName("opencl.sampler_t", MIRBuilder);
+ else if ((SampTy = getOrCreateSPIRVTypeByName("opencl.sampler_t",
+ MIRBuilder)) == nullptr)
+ report_fatal_error("Unable to recognize SPIRV type name: opencl.sampler_t");
auto Sampler =
ResReg.isValid()
@@ -942,6 +943,7 @@ SPIRVGlobalRegistry::checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD,
return nullptr;
}
+// Returns nullptr if unable to recognize SPIRV type name
// TODO: maybe use tablegen to implement this.
SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
StringRef TypeStr, MachineIRBuilder &MIRBuilder,
@@ -993,8 +995,10 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
} else if (TypeStr.starts_with("double")) {
Ty = Type::getDoubleTy(Ctx);
TypeStr = TypeStr.substr(strlen("double"));
- } else
- llvm_unreachable("Unable to recognize SPIRV type name.");
+ } else {
+ // Unable to recognize SPIRV type name
+ return nullptr;
+ }
auto SpirvTy = getOrCreateSPIRVType(Ty, MIRBuilder, AQ);
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index 60967bfb68a87..f3280928c25df 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -138,6 +138,7 @@ class SPIRVGlobalRegistry {
// Either generate a new OpTypeXXX instruction or return an existing one
// corresponding to the given string containing the name of the builtin type.
+ // Return nullptr if unable to recognize SPIRV type name from `TypeStr`.
SPIRVType *getOrCreateSPIRVTypeByName(
StringRef TypeStr, MachineIRBuilder &MIRBuilder,
SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function,
diff --git a/llvm/test/CodeGen/SPIRV/pointers/custom-kernel-arg-type.ll b/llvm/test/CodeGen/SPIRV/pointers/custom-kernel-arg-type.ll
new file mode 100644
index 0000000000000..4593fad783c60
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/custom-kernel-arg-type.ll
@@ -0,0 +1,34 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: %[[TyInt:.*]] = OpTypeInt 8 0
+; CHECK: %[[TyPtr:.*]] = OpTypePointer {{[a-zA-Z]+}} %[[TyInt]]
+; CHECK: OpFunctionParameter %[[TyPtr]]
+; CHECK: OpFunctionParameter %[[TyPtr]]
+
+%struct.my_kernel_data = type { i32, i32, i32, i32, i32 }
+%struct.my_struct = type { i32, i32 }
+
+define spir_kernel void @test(ptr addrspace(1) %in, ptr addrspace(1) %outData) !kernel_arg_type !5 {
+entry:
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!opencl.enable.FP_CONTRACT = !{}
+!opencl.ocl.version = !{!1}
+!opencl.spir.version = !{!2}
+!opencl.used.extensions = !{!3}
+!opencl.used.optional.core.features = !{!3}
+!opencl.compiler.options = !{!3}
+!llvm.ident = !{!4}
+!opencl.kernels = !{!6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, i32 0}
+!2 = !{i32 1, i32 2}
+!3 = !{}
+!4 = !{!"clang version 6.0.0"}
+!5 = !{!"my_kernel_data*", !"struct my_struct*"}
+!6 = !{ptr @test}
+
More information about the llvm-commits
mailing list