[llvm] [SPIR-V] Do not use OpenCL metadata for ptr element type resolution (PR #82678)
Michal Paszkowski via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 3 21:19:14 PST 2024
https://github.com/michalpaszkowski updated https://github.com/llvm/llvm-project/pull/82678
>From c7cf89f3e0976bd3aa15ebab6eab4790ef386d7b Mon Sep 17 00:00:00 2001
From: Michal Paszkowski <michal at paszkowski.org>
Date: Thu, 22 Feb 2024 10:59:39 -0800
Subject: [PATCH 1/2] [SPIR-V] Do not rely on type metadata for ptr element
type resolution
---
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 76 ++++++--
llvm/lib/Target/SPIRV/SPIRVBuiltins.h | 16 +-
llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp | 54 ++++--
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 181 +++++++++++-------
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 44 +----
llvm/lib/Target/SPIRV/SPIRVMetadata.cpp | 7 -
llvm/lib/Target/SPIRV/SPIRVMetadata.h | 1 -
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 6 +-
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 42 ++--
llvm/lib/Target/SPIRV/SPIRVUtils.h | 7 +-
.../SPIRV/function/alloca-load-store.ll | 11 +-
llvm/test/CodeGen/SPIRV/half_no_extension.ll | 3 -
.../undef-nested-composite-store.ll | 10 +-
.../undef-simple-composite-store.ll | 10 +-
llvm/test/CodeGen/SPIRV/opaque_pointers.ll | 13 +-
.../SPIRV/opencl/basic/get_global_offset.ll | 24 +--
.../kernel_arg_type_function_metadata.ll | 12 --
.../kernel_arg_type_module_metadata.ll | 16 --
llvm/test/CodeGen/SPIRV/opencl/vload2.ll | 20 +-
llvm/test/CodeGen/SPIRV/opencl/vstore2.ll | 23 +++
...cs-TargetExtType-arg-no-spv_assign_type.ll | 12 ++
...insics-no-divergent-spv_assign_ptr_type.ll | 12 ++
...Intrinsics-no-duplicate-spv_assign_type.ll | 14 ++
.../pointers/getelementptr-kernel-arg-char.ll | 20 +-
...argument-builtin-vload-type-discrapency.ll | 35 ++++
...rgument-pointer-type-deduction-mismatch.ll | 12 ++
...ment-pointer-type-deduction-no-metadata.ll | 13 ++
.../pointers/store-operand-ptr-to-struct.ll | 19 ++
...users.ll => two-bitcast-or-param-users.ll} | 10 +-
.../SPIRV/pointers/two-subsequent-bitcasts.ll | 7 +-
llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll | 5 +-
.../transcoding/OpenCL/atomic_cmpxchg.ll | 5 +-
.../SPIRV/transcoding/OpenCL/atomic_legacy.ll | 5 +-
.../spirv-private-array-initialization.ll | 1 -
llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll | 5 +-
35 files changed, 465 insertions(+), 286 deletions(-)
delete mode 100644 llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_function_metadata.ll
delete mode 100644 llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_module_metadata.ll
create mode 100644 llvm/test/CodeGen/SPIRV/opencl/vstore2.ll
create mode 100644 llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-TargetExtType-arg-no-spv_assign_type.ll
create mode 100644 llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-divergent-spv_assign_ptr_type.ll
create mode 100644 llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-duplicate-spv_assign_type.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/kernel-argument-builtin-vload-type-discrapency.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-mismatch.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-no-metadata.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/store-operand-ptr-to-struct.ll
rename llvm/test/CodeGen/SPIRV/pointers/{two-bitcast-users.ll => two-bitcast-or-param-users.ll} (50%)
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index c1bb27322443ff6..abf97a727130b78 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1775,7 +1775,7 @@ static const Type *getMachineInstrType(MachineInstr *MI) {
return nullptr;
Type *Ty = getMDOperandAsType(NextMI->getOperand(2).getMetadata(), 0);
assert(Ty && "Type is expected");
- return getTypedPtrEltType(Ty);
+ return Ty;
}
static const Type *getBlockStructType(Register ParamReg,
@@ -1787,7 +1787,7 @@ static const Type *getBlockStructType(Register ParamReg,
// section 6.12.5 should guarantee that we can do this.
MachineInstr *MI = getBlockStructInstr(ParamReg, MRI);
if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
- return getTypedPtrEltType(MI->getOperand(1).getGlobal()->getType());
+ return MI->getOperand(1).getGlobal()->getType();
assert(isSpvIntrinsic(*MI, Intrinsic::spv_alloca) &&
"Blocks in OpenCL C must be traceable to allocation site");
return getMachineInstrType(MI);
@@ -2043,7 +2043,8 @@ static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call,
.addImm(Builtin->Number);
for (auto Argument : Call->Arguments)
MIB.addUse(Argument);
- MIB.addImm(Builtin->ElementCount);
+ if (Builtin->Name.contains("load") && Builtin->ElementCount > 1)
+ MIB.addImm(Builtin->ElementCount);
// Rounding mode should be passed as a last argument in the MI for builtins
// like "vstorea_halfn_r".
@@ -2179,6 +2180,61 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
return false;
}
+Type *parseBuiltinCallArgumentBaseType(const StringRef DemangledCall,
+ unsigned ArgIdx, LLVMContext &Ctx) {
+ SmallVector<StringRef, 10> BuiltinArgsTypeStrs;
+ StringRef BuiltinArgs =
+ DemangledCall.slice(DemangledCall.find('(') + 1, DemangledCall.find(')'));
+ BuiltinArgs.split(BuiltinArgsTypeStrs, ',', -1, false);
+ if (ArgIdx >= BuiltinArgsTypeStrs.size())
+ return nullptr;
+ StringRef TypeStr = BuiltinArgsTypeStrs[ArgIdx].trim();
+
+ // Parse strings representing OpenCL builtin types.
+ if (hasBuiltinTypePrefix(TypeStr)) {
+ // OpenCL builtin types in demangled call strings have the following format:
+ // e.g. ocl_image2d_ro
+ bool IsOCLBuiltinType = TypeStr.consume_front("ocl_");
+ assert(IsOCLBuiltinType && "Invalid OpenCL builtin prefix");
+
+ // Check if this is pointer to a builtin type and not just pointer
+ // representing a builtin type. In case it is a pointer to builtin type,
+ // this will require additional handling in the method calling
+ // parseBuiltinCallArgumentBaseType(...) as this function only retrieves the
+ // base types.
+ if (TypeStr.ends_with("*"))
+ TypeStr = TypeStr.slice(0, TypeStr.find_first_of(" "));
+
+ return parseBuiltinTypeNameToTargetExtType("opencl." + TypeStr.str() + "_t",
+ Ctx);
+ }
+
+ // Parse type name in either "typeN" or "type vector[N]" format, where
+ // N is the number of elements of the vector.
+ Type *BaseType;
+ unsigned VecElts = 0;
+
+ BaseType = parseBasicTypeName(TypeStr, Ctx);
+ if (!BaseType)
+ // Unable to recognize SPIRV type name.
+ return nullptr;
+
+ if (BaseType->isVoidTy())
+ BaseType = Type::getInt8Ty(Ctx);
+
+ // Handle "typeN*" or "type vector[N]*".
+ TypeStr.consume_back("*");
+
+ if (TypeStr.consume_front(" vector["))
+ TypeStr = TypeStr.substr(0, TypeStr.find(']'));
+
+ TypeStr.getAsInteger(10, VecElts);
+ if (VecElts > 0)
+ BaseType = VectorType::get(BaseType, VecElts, false);
+
+ return BaseType;
+}
+
struct BuiltinType {
StringRef Name;
uint32_t Opcode;
@@ -2277,9 +2333,8 @@ static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,
}
namespace SPIRV {
-const TargetExtType *
-parseBuiltinTypeNameToTargetExtType(std::string TypeName,
- MachineIRBuilder &MIRBuilder) {
+TargetExtType *parseBuiltinTypeNameToTargetExtType(std::string TypeName,
+ LLVMContext &Context) {
StringRef NameWithParameters = TypeName;
// Pointers-to-opaque-structs representing OpenCL types are first translated
@@ -2303,7 +2358,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
// Parameterized SPIR-V builtins names follow this format:
// e.g. %spirv.Image._void_1_0_0_0_0_0_0, %spirv.Pipe._0
if (!NameWithParameters.contains('_'))
- return TargetExtType::get(MIRBuilder.getContext(), NameWithParameters);
+ return TargetExtType::get(Context, NameWithParameters);
SmallVector<StringRef> Parameters;
unsigned BaseNameLength = NameWithParameters.find('_') - 1;
@@ -2312,8 +2367,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
SmallVector<Type *, 1> TypeParameters;
bool HasTypeParameter = !isDigit(Parameters[0][0]);
if (HasTypeParameter)
- TypeParameters.push_back(parseTypeString(
- Parameters[0], MIRBuilder.getMF().getFunction().getContext()));
+ TypeParameters.push_back(parseTypeString(Parameters[0], Context));
SmallVector<unsigned> IntParameters;
for (unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) {
unsigned IntParameter = 0;
@@ -2323,7 +2377,7 @@ parseBuiltinTypeNameToTargetExtType(std::string TypeName,
"Invalid format of SPIR-V builtin parameter literal!");
IntParameters.push_back(IntParameter);
}
- return TargetExtType::get(MIRBuilder.getContext(),
+ return TargetExtType::get(Context,
NameWithParameters.substr(0, BaseNameLength),
TypeParameters, IntParameters);
}
@@ -2343,7 +2397,7 @@ SPIRVType *lowerBuiltinType(const Type *OpaqueType,
const TargetExtType *BuiltinType = dyn_cast<TargetExtType>(OpaqueType);
if (!BuiltinType)
BuiltinType = parseBuiltinTypeNameToTargetExtType(
- OpaqueType->getStructName().str(), MIRBuilder);
+ OpaqueType->getStructName().str(), MIRBuilder.getContext());
unsigned NumStartingVRegs = MIRBuilder.getMRI()->getNumVirtRegs();
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
index 6f957295464812e..649f5bfd1d7c262 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
@@ -38,6 +38,17 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
const SmallVectorImpl<Register> &Args,
SPIRVGlobalRegistry *GR);
+/// Parses the provided \p ArgIdx argument base type in the \p DemangledCall
+/// skeleton. A base type is either a basic type (e.g. i32 for int), pointer
+/// element type (e.g. i8 for char*), or builtin type (TargetExtType).
+///
+/// \return LLVM Type or nullptr if unrecognized
+///
+/// \p DemangledCall is the skeleton of the lowered builtin function call.
+/// \p ArgIdx is the index of the argument to parse.
+Type *parseBuiltinCallArgumentBaseType(const StringRef DemangledCall,
+ unsigned ArgIdx, LLVMContext &Ctx);
+
/// Translates a string representing a SPIR-V or OpenCL builtin type to a
/// TargetExtType that can be further lowered with lowerBuiltinType().
///
@@ -45,9 +56,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
///
/// \p TypeName is the full string representation of the SPIR-V or OpenCL
/// builtin type.
-const TargetExtType *
-parseBuiltinTypeNameToTargetExtType(std::string TypeName,
- MachineIRBuilder &MIRBuilder);
+TargetExtType *parseBuiltinTypeNameToTargetExtType(std::string TypeName,
+ LLVMContext &Context);
/// Handles the translation of the provided special opaque/builtin type \p Type
/// to SPIR-V type. Generates the corresponding machine instructions for the
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 10569ef0468bda9..f8983cc7d5da3d4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -22,6 +22,8 @@
#include "SPIRVSubtarget.h"
#include "SPIRVUtils.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/Support/ModRef.h"
using namespace llvm;
@@ -158,28 +160,42 @@ static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx,
Type *OriginalArgType = getOriginalFunctionType(F)->getParamType(ArgIdx);
- // In case of non-kernel SPIR-V function or already TargetExtType, use the
- // original IR type.
- if (F.getCallingConv() != CallingConv::SPIR_KERNEL ||
- isSpecialOpaqueType(OriginalArgType))
+ // If OriginalArgType is non-pointer, use the OriginalArgType (the type cannot
+ // be legally reassigned later).
+ if (!OriginalArgType->isPointerTy())
return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
- 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(),
- ST));
- else if (MDTypeStr.ends_with("_t"))
- ResArgType = GR->getOrCreateSPIRVTypeByName(
- "opencl." + MDTypeStr.str(), MIRBuilder,
- SPIRV::StorageClass::Function, ArgAccessQual);
+ // In case OriginalArgType is of pointer type, there are two possibilities:
+ // 1) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type
+ // intrinsic assigning a TargetExtType.
+ // 2) This is a pointer, try to retrieve pointer element type from a
+ // spv_assign_ptr_type intrinsic or otherwise use default pointer element
+ // type.
+ for (auto User : F.getArg(ArgIdx)->users()) {
+ auto *II = dyn_cast<IntrinsicInst>(User);
+ // Check if this is spv_assign_type assigning OpenCL/SPIR-V builtin type.
+ if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) {
+ MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
+ Type *BuiltinType =
+ cast<ConstantAsMetadata>(VMD->getMetadata())->getType();
+ assert(BuiltinType->isTargetExtTy() && "Expected TargetExtType");
+ return GR->getOrCreateSPIRVType(BuiltinType, MIRBuilder, ArgAccessQual);
+ }
+
+ // Check if this is spv_assign_ptr_type assigning pointer element type.
+ if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
+ continue;
+
+ MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
+ SPIRVType *ElementType = GR->getOrCreateSPIRVType(
+ cast<ConstantAsMetadata>(VMD->getMetadata())->getType(), MIRBuilder);
+ return GR->getOrCreateSPIRVPointerType(
+ ElementType, MIRBuilder,
+ addressSpaceToStorageClass(
+ cast<ConstantInt>(II->getOperand(2))->getZExtValue(), ST));
}
- return ResArgType ? ResArgType
- : GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder,
- ArgAccessQual);
+
+ return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
}
static SPIRV::ExecutionModel::ExecutionModel
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index afb24bfb3223918..6a700014ea93cea 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "SPIRV.h"
+#include "SPIRVBuiltins.h"
#include "SPIRVMetadata.h"
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
@@ -75,7 +76,12 @@ class SPIRVEmitIntrinsics
void processInstrAfterVisit(Instruction *I);
void insertAssignPtrTypeIntrs(Instruction *I);
void insertAssignTypeIntrs(Instruction *I);
- void insertPtrCastInstr(Instruction *I);
+ void insertAssignTypeInstrForTargetExtTypes(TargetExtType *AssignedType,
+ Value *V);
+ void replacePointerOperandWithPtrCast(Instruction *I, Value *Pointer,
+ Type *ExpectedElementType,
+ unsigned OperandToReplace);
+ void insertPtrCastOrAssignTypeInstr(Instruction *I);
void processGlobalValue(GlobalVariable &GV);
public:
@@ -130,13 +136,6 @@ static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
B.SetInsertPoint(I);
}
-static bool requireAssignPtrType(Instruction *I) {
- if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I))
- return true;
-
- return false;
-}
-
static bool requireAssignType(Instruction *I) {
IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
if (Intr) {
@@ -269,7 +268,7 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
// SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
// varying element types. In case of IR coming from older versions of LLVM
// such bitcasts do not provide sufficient information, should be just skipped
- // here, and handled in insertPtrCastInstr.
+ // here, and handled in insertPtrCastOrAssignTypeInstr.
if (I.getType()->isPointerTy()) {
I.replaceAllUsesWith(Source);
I.eraseFromParent();
@@ -286,34 +285,38 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
return NewI;
}
-void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) {
- Value *Pointer;
- Type *ExpectedElementType;
- unsigned OperandToReplace;
+void SPIRVEmitIntrinsics::insertAssignTypeInstrForTargetExtTypes(
+ TargetExtType *AssignedType, Value *V) {
+ // Do not emit spv_assign_type if the V is of the AssignedType already.
+ if (V->getType() == AssignedType)
+ return;
- StoreInst *SI = dyn_cast<StoreInst>(I);
- if (SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
- SI->getValueOperand()->getType()->isPointerTy() &&
- isa<Argument>(SI->getValueOperand())) {
- Pointer = SI->getValueOperand();
- ExpectedElementType = IntegerType::getInt8Ty(F->getContext());
- OperandToReplace = 0;
- } else if (SI) {
- Pointer = SI->getPointerOperand();
- ExpectedElementType = SI->getValueOperand()->getType();
- OperandToReplace = 1;
- } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
- Pointer = LI->getPointerOperand();
- ExpectedElementType = LI->getType();
- OperandToReplace = 0;
- } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
- Pointer = GEPI->getPointerOperand();
- ExpectedElementType = GEPI->getSourceElementType();
- OperandToReplace = 0;
- } else {
+ // Do not emit spv_assign_type if there is one already targetting V. If the
+ // found spv_assign_type assigns a type different than AssignedType, report an
+ // error. Builtin types cannot be redeclared or casted.
+ for (auto User : V->users()) {
+ auto *II = dyn_cast<IntrinsicInst>(User);
+ if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_type)
+ continue;
+
+ MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1));
+ Type *BuiltinType =
+ dyn_cast<ConstantAsMetadata>(VMD->getMetadata())->getType();
+ if (BuiltinType != AssignedType)
+ report_fatal_error("Type mismatch " + BuiltinType->getTargetExtName() +
+ "/" + AssignedType->getTargetExtName() +
+ " for value " + V->getName(),
+ false);
return;
}
+ Constant *Const = UndefValue::get(AssignedType);
+ buildIntrWithMD(Intrinsic::spv_assign_type, {V->getType()}, Const, V, {});
+}
+
+void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
+ Instruction *I, Value *Pointer, Type *ExpectedElementType,
+ unsigned OperandToReplace) {
// If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
// pointer instead. The BitCastInst should be later removed when visited.
while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
@@ -378,38 +381,76 @@ void SPIRVEmitIntrinsics::insertPtrCastInstr(Instruction *I) {
return;
}
- // Do not emit spv_ptrcast if it would cast to the default pointer element
- // type (i8) of the same address space. In case of OpenCL kernels, make sure
- // i8 is the pointer element type defined for the given kernel argument.
- if (ExpectedElementType->isIntegerTy(8) &&
- F->getCallingConv() != CallingConv::SPIR_KERNEL)
- return;
+ // // Do not emit spv_ptrcast if it would cast to the default pointer element
+ // // type (i8) of the same address space.
+ // if (ExpectedElementType->isIntegerTy(8))
+ // return;
- Argument *Arg = dyn_cast<Argument>(Pointer);
- if (ExpectedElementType->isIntegerTy(8) &&
- F->getCallingConv() == CallingConv::SPIR_KERNEL && Arg) {
- MDString *ArgType = getOCLKernelArgType(*Arg->getParent(), Arg->getArgNo());
- if (ArgType && ArgType->getString().starts_with("uchar*"))
- return;
- }
-
- // If this would be the first spv_ptrcast, the pointer's defining instruction
- // requires spv_assign_ptr_type and does not already have one, do not emit
- // spv_ptrcast and emit spv_assign_ptr_type instead.
- Instruction *PointerDefInst = dyn_cast<Instruction>(Pointer);
- if (FirstPtrCastOrAssignPtrType && PointerDefInst &&
- requireAssignPtrType(PointerDefInst)) {
+ // If this would be the first spv_ptrcast, do not emit spv_ptrcast and emit
+ // spv_assign_ptr_type instead.
+ if (FirstPtrCastOrAssignPtrType &&
+ (isa<Instruction>(Pointer) || isa<Argument>(Pointer))) {
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {Pointer->getType()},
ExpectedElementTypeConst, Pointer,
{IRB->getInt32(AddressSpace)});
return;
- } else {
- SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
- SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)};
- auto *PtrCastI =
- IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
- I->setOperand(OperandToReplace, PtrCastI);
+ }
+
+ // Emit spv_ptrcast
+ SmallVector<Type *, 2> Types = {Pointer->getType(), Pointer->getType()};
+ SmallVector<Value *, 2> Args = {Pointer, VMD, IRB->getInt32(AddressSpace)};
+ auto *PtrCastI = IRB->CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
+ I->setOperand(OperandToReplace, PtrCastI);
+}
+
+void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I) {
+ // Handle basic instructions:
+ StoreInst *SI = dyn_cast<StoreInst>(I);
+ if (SI && F->getCallingConv() == CallingConv::SPIR_KERNEL &&
+ SI->getValueOperand()->getType()->isPointerTy() &&
+ isa<Argument>(SI->getValueOperand())) {
+ return replacePointerOperandWithPtrCast(
+ I, SI->getValueOperand(), IntegerType::getInt8Ty(F->getContext()), 0);
+ } else if (SI) {
+ return replacePointerOperandWithPtrCast(
+ I, SI->getPointerOperand(), SI->getValueOperand()->getType(), 1);
+ } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ return replacePointerOperandWithPtrCast(I, LI->getPointerOperand(),
+ LI->getType(), 0);
+ } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
+ return replacePointerOperandWithPtrCast(I, GEPI->getPointerOperand(),
+ GEPI->getSourceElementType(), 0);
+ }
+
+ // Handle calls to builtins (non-intrinsics):
+ CallInst *CI = dyn_cast<CallInst>(I);
+ if (!CI || CI->isIndirectCall() || CI->getCalledFunction()->isIntrinsic())
+ return;
+
+ std::string DemangledName =
+ getOclOrSpirvBuiltinDemangledName(CI->getCalledFunction()->getName());
+ if (DemangledName.empty())
return;
+
+ for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) {
+ Value *ArgOperand = CI->getArgOperand(OpIdx);
+ if (!isa<PointerType>(ArgOperand->getType()))
+ continue;
+
+ // Constants (nulls/undefs) are handled in insertAssignPtrTypeIntrs()
+ if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand))
+ continue;
+
+ Type *ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType(
+ DemangledName, OpIdx, I->getContext());
+ if (!ExpectedType)
+ continue;
+
+ if (ExpectedType->isTargetExtTy())
+ insertAssignTypeInstrForTargetExtTypes(cast<TargetExtType>(ExpectedType),
+ ArgOperand);
+ else
+ replacePointerOperandWithPtrCast(CI, ArgOperand, ExpectedType, OpIdx);
}
}
@@ -567,22 +608,20 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV) {
void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) {
reportFatalOnTokenType(I);
- if (I->getType()->isVoidTy() || !requireAssignPtrType(I))
+ if (!I->getType()->isPointerTy() || !requireAssignType(I) ||
+ isa<BitCastInst>(I))
return;
setInsertPointSkippingPhis(*IRB, I->getNextNode());
Constant *EltTyConst;
- unsigned AddressSpace = 0;
- if (auto *AI = dyn_cast<AllocaInst>(I)) {
+ unsigned AddressSpace = I->getType()->getPointerAddressSpace();
+ if (auto *AI = dyn_cast<AllocaInst>(I))
EltTyConst = UndefValue::get(AI->getAllocatedType());
- AddressSpace = AI->getAddressSpace();
- } else if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
+ else if (auto *GEP = dyn_cast<GetElementPtrInst>(I))
EltTyConst = UndefValue::get(GEP->getResultElementType());
- AddressSpace = GEP->getPointerAddressSpace();
- } else {
- llvm_unreachable("Unexpected instruction!");
- }
+ else if (I->getType()->isPointerTy())
+ EltTyConst = UndefValue::get(IntegerType::getInt8Ty(I->getContext()));
buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {I->getType()}, EltTyConst, I,
{IRB->getInt32(AddressSpace)});
@@ -591,7 +630,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I) {
void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
reportFatalOnTokenType(I);
Type *Ty = I->getType();
- if (!Ty->isVoidTy() && requireAssignType(I) && !requireAssignPtrType(I)) {
+ if (!Ty->isVoidTy() && !Ty->isPointerTy() && requireAssignType(I)) {
setInsertPointSkippingPhis(*IRB, I->getNextNode());
Type *TypeToAssign = Ty;
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
@@ -613,7 +652,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I) {
if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->getInt32Ty()}, Op,
UndefValue::get(IRB->getInt32Ty()), {});
- else
+ else if (!isa<Instruction>(Op)) // TODO: This case could be removed
buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op,
{});
}
@@ -689,7 +728,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
for (auto &I : Worklist) {
insertAssignPtrTypeIntrs(I);
insertAssignTypeIntrs(I);
- insertPtrCastInstr(I);
+ insertPtrCastOrAssignTypeInstr(I);
}
for (auto *I : Worklist) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index a1cb630f1aa4779..0a797eca1e32eae 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -947,7 +947,6 @@ SPIRVGlobalRegistry::checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD,
}
// Returns nullptr if unable to recognize SPIRV type name
-// TODO: maybe use tablegen to implement this.
SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
StringRef TypeStr, MachineIRBuilder &MIRBuilder,
SPIRV::StorageClass::StorageClass SC,
@@ -957,51 +956,18 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVTypeByName(
// Parse strings representing either a SPIR-V or OpenCL builtin type.
if (hasBuiltinTypePrefix(TypeStr))
- return getOrCreateSPIRVType(
- SPIRV::parseBuiltinTypeNameToTargetExtType(TypeStr.str(), MIRBuilder),
- MIRBuilder, AQ);
+ return getOrCreateSPIRVType(SPIRV::parseBuiltinTypeNameToTargetExtType(
+ TypeStr.str(), MIRBuilder.getContext()),
+ MIRBuilder, AQ);
// Parse type name in either "typeN" or "type vector[N]" format, where
// N is the number of elements of the vector.
Type *Ty;
- TypeStr.consume_front("atomic_");
-
- if (TypeStr.starts_with("void")) {
- Ty = Type::getVoidTy(Ctx);
- TypeStr = TypeStr.substr(strlen("void"));
- } else if (TypeStr.starts_with("bool")) {
- Ty = Type::getIntNTy(Ctx, 1);
- TypeStr = TypeStr.substr(strlen("bool"));
- } else if (TypeStr.starts_with("char") || TypeStr.starts_with("uchar")) {
- Ty = Type::getInt8Ty(Ctx);
- TypeStr = TypeStr.starts_with("char") ? TypeStr.substr(strlen("char"))
- : TypeStr.substr(strlen("uchar"));
- } else if (TypeStr.starts_with("short") || TypeStr.starts_with("ushort")) {
- Ty = Type::getInt16Ty(Ctx);
- TypeStr = TypeStr.starts_with("short") ? TypeStr.substr(strlen("short"))
- : TypeStr.substr(strlen("ushort"));
- } else if (TypeStr.starts_with("int") || TypeStr.starts_with("uint")) {
- Ty = Type::getInt32Ty(Ctx);
- TypeStr = TypeStr.starts_with("int") ? TypeStr.substr(strlen("int"))
- : TypeStr.substr(strlen("uint"));
- } else if (TypeStr.starts_with("long") || TypeStr.starts_with("ulong")) {
- Ty = Type::getInt64Ty(Ctx);
- TypeStr = TypeStr.starts_with("long") ? TypeStr.substr(strlen("long"))
- : TypeStr.substr(strlen("ulong"));
- } else if (TypeStr.starts_with("half")) {
- Ty = Type::getHalfTy(Ctx);
- TypeStr = TypeStr.substr(strlen("half"));
- } else if (TypeStr.starts_with("float")) {
- Ty = Type::getFloatTy(Ctx);
- TypeStr = TypeStr.substr(strlen("float"));
- } else if (TypeStr.starts_with("double")) {
- Ty = Type::getDoubleTy(Ctx);
- TypeStr = TypeStr.substr(strlen("double"));
- } else {
+ Ty = parseBasicTypeName(TypeStr, Ctx);
+ if (!Ty)
// Unable to recognize SPIRV type name
return nullptr;
- }
auto SpirvTy = getOrCreateSPIRVType(Ty, MIRBuilder, AQ);
diff --git a/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp b/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp
index e8c707742f24437..3800aac70df3272 100644
--- a/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp
@@ -82,11 +82,4 @@ MDString *getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx) {
return getOCLKernelArgAttribute(F, ArgIdx, "kernel_arg_type_qual");
}
-MDString *getOCLKernelArgType(const Function &F, unsigned ArgIdx) {
- assert(
- F.getCallingConv() == CallingConv::SPIR_KERNEL &&
- "Kernel attributes are attached/belong only to OpenCL kernel functions");
- return getOCLKernelArgAttribute(F, ArgIdx, "kernel_arg_type");
-}
-
} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVMetadata.h b/llvm/lib/Target/SPIRV/SPIRVMetadata.h
index 50aee7234395927..fb4269457d6dd36 100644
--- a/llvm/lib/Target/SPIRV/SPIRVMetadata.h
+++ b/llvm/lib/Target/SPIRV/SPIRVMetadata.h
@@ -25,7 +25,6 @@ namespace llvm {
MDString *getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx);
MDString *getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx);
-MDString *getOCLKernelArgType(const Function &F, unsigned ArgIdx);
} // namespace llvm
#endif // LLVM_LIB_TARGET_SPIRV_METADATA_H
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 144216896eb68ce..49b0a9c8f75f130 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -279,8 +279,10 @@ static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
MachineInstr *Def = MRI.getVRegDef(Reg);
assert(Def && "Expecting an instruction that defines the register");
- insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
- MF.getRegInfo());
+ // G_GLOBAL_VALUE already has type info.
+ if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
+ insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
+ MF.getRegInfo());
ToErase.push_back(&MI);
} else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
Register Reg = MI.getOperand(1).getReg();
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 169d7cc93897eda..fc7502479fdcdd5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -341,25 +341,15 @@ std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
return Name.substr(Start, Len).str();
}
-const Type *getTypedPtrEltType(const Type *Ty) {
- // TODO: This function requires updating following the opaque pointer
- // migration.
- return Ty;
-}
-
bool hasBuiltinTypePrefix(StringRef Name) {
- if (Name.starts_with("opencl.") || Name.starts_with("spirv."))
+ if (Name.starts_with("opencl.") || Name.starts_with("ocl_") ||
+ Name.starts_with("spirv."))
return true;
return false;
}
bool isSpecialOpaqueType(const Type *Ty) {
- const StructType *SType = dyn_cast<StructType>(getTypedPtrEltType(Ty));
- if (SType && SType->hasName())
- return hasBuiltinTypePrefix(SType->getName());
-
- if (const TargetExtType *EType =
- dyn_cast<TargetExtType>(getTypedPtrEltType(Ty)))
+ if (const TargetExtType *EType = dyn_cast<TargetExtType>(Ty))
return hasBuiltinTypePrefix(EType->getName());
return false;
@@ -378,4 +368,30 @@ bool isEntryPoint(const Function &F) {
return false;
}
+
+Type *parseBasicTypeName(StringRef TypeName, LLVMContext &Ctx) {
+ TypeName.consume_front("atomic_");
+ if (TypeName.consume_front("void"))
+ return Type::getVoidTy(Ctx);
+ else if (TypeName.consume_front("bool"))
+ return Type::getIntNTy(Ctx, 1);
+ else if (TypeName.consume_front("char") || TypeName.consume_front("uchar"))
+ return Type::getInt8Ty(Ctx);
+ else if (TypeName.consume_front("short") || TypeName.consume_front("ushort"))
+ return Type::getInt16Ty(Ctx);
+ else if (TypeName.consume_front("int") || TypeName.consume_front("uint"))
+ return Type::getInt32Ty(Ctx);
+ else if (TypeName.consume_front("long") || TypeName.consume_front("ulong"))
+ return Type::getInt64Ty(Ctx);
+ else if (TypeName.consume_front("half"))
+ return Type::getHalfTy(Ctx);
+ else if (TypeName.consume_front("float"))
+ return Type::getFloatTy(Ctx);
+ else if (TypeName.consume_front("double"))
+ return Type::getDoubleTy(Ctx);
+
+ // Unable to recognize SPIRV type name
+ return nullptr;
+}
+
} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 1af53dcd0c4cd15..e5f35aaca9a8bae 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -89,10 +89,6 @@ Type *getMDOperandAsType(const MDNode *N, unsigned I);
// name, otherwise return an empty string.
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
-// If Type is a pointer type and it is not opaque pointer, return its
-// element type, otherwise return Type.
-const Type *getTypedPtrEltType(const Type *Type);
-
// Check if a string contains a builtin prefix.
bool hasBuiltinTypePrefix(StringRef Name);
@@ -101,5 +97,8 @@ bool isSpecialOpaqueType(const Type *Ty);
// Check if the function is an SPIR-V entry point
bool isEntryPoint(const Function &F);
+
+// Parse basic scalar type name, substring TypeName, and return LLVM type.
+Type *parseBasicTypeName(StringRef TypeName, LLVMContext &Ctx);
} // namespace llvm
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
diff --git a/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll b/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
index c64a708b28ebe4e..5c06d65b6b4e61a 100644
--- a/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
+++ b/llvm/test/CodeGen/SPIRV/function/alloca-load-store.ll
@@ -4,13 +4,11 @@
; CHECK-DAG: OpName %[[#FOO:]] "foo"
; CHECK-DAG: OpName %[[#GOO:]] "goo"
-; CHECK-DAG: %[[#CHAR:]] = OpTypeInt 8
; CHECK-DAG: %[[#INT:]] = OpTypeInt 32
; CHECK-DAG: %[[#STACK_PTR_INT:]] = OpTypePointer Function %[[#INT]]
; CHECK-DAG: %[[#GLOBAL_PTR_INT:]] = OpTypePointer CrossWorkgroup %[[#INT]]
-; CHECK-DAG: %[[#GLOBAL_PTR_CHAR:]] = OpTypePointer CrossWorkgroup %[[#CHAR]]
; CHECK-DAG: %[[#FN1:]] = OpTypeFunction %[[#INT]] %[[#INT]]
-; CHECK-DAG: %[[#FN2:]] = OpTypeFunction %[[#INT]] %[[#INT]] %[[#GLOBAL_PTR_CHAR]]
+; CHECK-DAG: %[[#FN2:]] = OpTypeFunction %[[#INT]] %[[#INT]] %[[#GLOBAL_PTR_INT]]
define i32 @bar(i32 %a) {
%p = alloca i32
@@ -55,10 +53,9 @@ define i32 @goo(i32 %a, ptr addrspace(1) %p) {
; CHECK: %[[#GOO]] = OpFunction %[[#INT]] None %[[#FN2]]
; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
-; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR_CHAR]]
+; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR_INT]]
; CHECK: OpLabel
-; CHECK: %[[#C:]] = OpBitcast %[[#GLOBAL_PTR_INT]] %[[#P]]
-; CHECK: OpStore %[[#C]] %[[#A]]
-; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#C]]
+; CHECK: OpStore %[[#P]] %[[#A]]
+; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#P]]
; CHECK: OpReturnValue %[[#B]]
; CHECK: OpFunctionEnd
diff --git a/llvm/test/CodeGen/SPIRV/half_no_extension.ll b/llvm/test/CodeGen/SPIRV/half_no_extension.ll
index 6414b62874bc71d..a5b0ec9c92d236a 100644
--- a/llvm/test/CodeGen/SPIRV/half_no_extension.ll
+++ b/llvm/test/CodeGen/SPIRV/half_no_extension.ll
@@ -7,9 +7,6 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; TODO(#60133): Requires updates following opaque pointer migration.
-; XFAIL: *
-
; CHECK-SPIRV: OpCapability Float16Buffer
; CHECK-SPIRV-NOT: OpCapability Float16
diff --git a/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
index 5fa4a7a93ee0b95..7425b303f8a87cc 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-nested-composite-store.ll
@@ -7,12 +7,10 @@
; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#NESTED_STRUCT]]
; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
-; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
-; CHECK-NEXT: %[[#]] = OpLabel
-; CHECK-NEXT: %[[#BC:]] = OpBitcast %[[#]] %[[#PTR]]
-; CHECK-NEXT: OpStore %[[#BC]] %[[#UNDEF]] Aligned 4
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
+; CHECK: %[[#]] = OpLabel
+; CHECK: OpStore %[[#]] %[[#UNDEF]] Aligned 4
+; CHECK: OpReturn
+; CHECK: OpFunctionEnd
%struct = type {
i32,
diff --git a/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
index 24dad10382ada90..cb2c89be28f1f1f 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/undef-simple-composite-store.ll
@@ -6,12 +6,10 @@
; CHECK-DAG: %[[#UNDEF:]] = OpUndef %[[#STRUCT]]
; CHECK: %[[#]] = OpFunction %[[#]] None %[[#]]
-; CHECK-NEXT: %[[#PTR:]] = OpFunctionParameter %[[#]]
-; CHECK-NEXT: %[[#]] = OpLabel
-; CHECK-NEXT: %[[#BC:]] = OpBitcast %[[#]] %[[#PTR]]
-; CHECK-NEXT: OpStore %[[#BC]] %[[#UNDEF]] Aligned 4
-; CHECK-NEXT: OpReturn
-; CHECK-NEXT: OpFunctionEnd
+; CHECK: %[[#]] = OpLabel
+; CHECK: OpStore %[[#]] %[[#UNDEF]] Aligned 4
+; CHECK: OpReturn
+; CHECK: OpFunctionEnd
define void @foo(ptr %ptr) {
store { i32, i16 } undef, ptr %ptr
diff --git a/llvm/test/CodeGen/SPIRV/opaque_pointers.ll b/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
index 30c9d8dc774e24b..db4d1b130b85232 100644
--- a/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
+++ b/llvm/test/CodeGen/SPIRV/opaque_pointers.ll
@@ -1,19 +1,16 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK
-; CHECK-DAG: %[[#Int8Ty:]] = OpTypeInt 8 0
-; CHECK-DAG: %[[#PtrInt8Ty:]] = OpTypePointer Function %[[#Int8Ty]]
; CHECK-DAG: %[[#Int32Ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#PtrInt32Ty:]] = OpTypePointer Function %[[#Int32Ty]]
; CHECK-DAG: %[[#Int64Ty:]] = OpTypeInt 64 0
; CHECK-DAG: %[[#PtrInt64Ty:]] = OpTypePointer Function %[[#Int64Ty]]
-; CHECK-DAG: %[[#FTy:]] = OpTypeFunction %[[#Int64Ty]] %[[#PtrInt8Ty]]
+; CHECK-DAG: %[[#FTy:]] = OpTypeFunction %[[#Int64Ty]] %[[#PtrInt32Ty]]
; CHECK-DAG: %[[#Const:]] = OpConstant %[[#Int32Ty]] 0
; CHECK: OpFunction %[[#Int64Ty]] None %[[#FTy]]
-; CHECK: %[[#Parm:]] = OpFunctionParameter %[[#PtrInt8Ty]]
-; CHECK-DAG: %[[#Bitcast1:]] = OpBitcast %[[#PtrInt32Ty]] %[[#Parm]]
-; CHECK: OpStore %[[#Bitcast1]] %[[#Const]] Aligned 4
-; CHECK-DAG: %[[#Bitcast2:]] = OpBitcast %[[#PtrInt64Ty]] %[[#Parm]]
-; CHECK: %[[#Res:]] = OpLoad %[[#Int64Ty]] %[[#Bitcast2]] Aligned 4
+; CHECK: %[[#Param:]] = OpFunctionParameter %[[#PtrInt32Ty]]
+; CHECK: OpStore %[[#Param]] %[[#Const]] Aligned 4
+; CHECK-DAG: %[[#Bitcast:]] = OpBitcast %[[#PtrInt64Ty]] %[[#Param]]
+; CHECK: %[[#Res:]] = OpLoad %[[#Int64Ty]] %[[#Bitcast]] Aligned 4
; CHECK: OpReturnValue %[[#Res]]
define i64 @test(ptr %p) {
diff --git a/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll b/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
index 43d6238360f6fcf..46a7cf424942616 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/basic/get_global_offset.ll
@@ -1,22 +1,18 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; CHECK: OpEntryPoint Kernel %[[#test_func:]] "test"
-; CHECK: OpDecorate %[[#f2_decl:]] LinkageAttributes "BuiltInGlobalOffset" Import
-; CHECK: %[[#int_ty:]] = OpTypeInt 8 0
-; CHECK: %[[#void_ty:]] = OpTypeVoid
-; CHECK: %[[#iptr_ty:]] = OpTypePointer CrossWorkgroup %[[#int_ty]]
-; CHECK: %[[#func_ty:]] = OpTypeFunction %[[#void_ty]] %[[#iptr_ty]]
-; CHECK: %[[#int64_ty:]] = OpTypeInt 64 0
-; CHECK: %[[#vec_ty:]] = OpTypeVector %[[#int64_ty]] 3
-; CHECK: %[[#func2_ty:]] = OpTypeFunction %[[#vec_ty]]
-; CHECK: %[[#int32_ty:]] = OpTypeInt 32 0
-; CHECK: %[[#i32ptr_ty:]] = OpTypePointer CrossWorkgroup %[[#int32_ty]]
+; CHECK-DAG: OpEntryPoint Kernel %[[#test_func:]] "test"
+; CHECK-DAG: OpDecorate %[[#f2_decl:]] LinkageAttributes "BuiltInGlobalOffset" Import
+; CHECK-DAG: %[[#int32_ty:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#i32ptr_ty:]] = OpTypePointer CrossWorkgroup %[[#int32_ty]]
+; CHECK-DAG: %[[#void_ty:]] = OpTypeVoid
+; CHECK-DAG: %[[#func_ty:]] = OpTypeFunction %[[#void_ty]] %[[#i32ptr_ty]]
+; CHECK-DAG: %[[#int64_ty:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#vec_ty:]] = OpTypeVector %[[#int64_ty]] 3
+; CHECK-DAG: %[[#func2_ty:]] = OpTypeFunction %[[#vec_ty]]
;; TODO: add 64-bit constant defs
-; CHECK: %[[#f2_decl]] = OpFunction %[[#vec_ty]] Pure %[[#func2_ty]]
+; CHECK-DAG: %[[#f2_decl]] = OpFunction %[[#vec_ty]] Pure %[[#func2_ty]]
; CHECK: OpFunctionEnd
;; Check that the function register name does not match other registers
-; CHECK-NOT: %[[#int_ty]] = OpFunction
-; CHECK-NOT: %[[#iptr_ty]] = OpFunction
; CHECK-NOT: %[[#void_ty]] = OpFunction
; CHECK-NOT: %[[#func_ty]] = OpFunction
; CHECK-NOT: %[[#int64_ty]] = OpFunction
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_function_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_function_metadata.ll
deleted file mode 100644
index ce5910efc6ccd40..000000000000000
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_function_metadata.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-
-; CHECK: %[[#TypeSampler:]] = OpTypeSampler
-define spir_kernel void @foo(i64 %sampler) !kernel_arg_addr_space !7 !kernel_arg_access_qual !8 !kernel_arg_type !9 !kernel_arg_type_qual !10 !kernel_arg_base_type !9 {
-entry:
- ret void
-}
-
-!7 = !{i32 0}
-!8 = !{!"none"}
-!9 = !{!"sampler_t"}
-!10 = !{!""}
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_module_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_module_metadata.ll
deleted file mode 100644
index b5bb8433321daf2..000000000000000
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/kernel_arg_type_module_metadata.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-
-; CHECK: %[[#TypeSampler:]] = OpTypeSampler
-define spir_kernel void @foo(i64 %sampler) {
-entry:
- ret void
-}
-!opencl.kernels = !{!0}
-
-!0 = !{void (i64)* @foo, !1, !2, !3, !4, !5, !6}
-!1 = !{!"kernel_arg_addr_space", i32 0}
-!2 = !{!"kernel_arg_access_qual", !"none"}
-!3 = !{!"kernel_arg_type", !"sampler_t"}
-!4 = !{!"kernel_arg_type_qual", !""}
-!5 = !{!"kernel_arg_base_type", !"sampler_t"}
-!6 = !{!"kernel_arg_name", !"sampler"}
diff --git a/llvm/test/CodeGen/SPIRV/opencl/vload2.ll b/llvm/test/CodeGen/SPIRV/opencl/vload2.ll
index b219aebc29befef..592de33d4d39386 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/vload2.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/vload2.ll
@@ -15,20 +15,28 @@
; CHECK-DAG: %[[#VINT64:]] = OpTypeVector %[[#INT64]] 2
; CHECK-DAG: %[[#VFLOAT:]] = OpTypeVector %[[#FLOAT]] 2
; CHECK-DAG: %[[#PTRINT8:]] = OpTypePointer CrossWorkgroup %[[#INT8]]
+; CHECK-DAG: %[[#PTRINT16:]] = OpTypePointer CrossWorkgroup %[[#INT16]]
+; CHECK-DAG: %[[#PTRINT32:]] = OpTypePointer CrossWorkgroup %[[#INT32]]
+; CHECK-DAG: %[[#PTRINT64:]] = OpTypePointer CrossWorkgroup %[[#INT64]]
+; CHECK-DAG: %[[#PTRFLOAT:]] = OpTypePointer CrossWorkgroup %[[#FLOAT]]
; CHECK: %[[#OFFSET:]] = OpFunctionParameter %[[#INT64]]
-; CHECK: %[[#ADDRESS:]] = OpFunctionParameter %[[#PTRINT8]]
define spir_kernel void @test_fn(i64 %offset, ptr addrspace(1) %address) {
-; CHECK: %[[#]] = OpExtInst %[[#VINT8]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#ADDRESS]] 2
+; CHECK: %[[#CASTorPARAMofPTRI8:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRINT8]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#VINT8]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#CASTorPARAMofPTRI8]] 2
%call1 = call spir_func <2 x i8> @_Z6vload2mPU3AS1Kc(i64 %offset, ptr addrspace(1) %address)
-; CHECK: %[[#]] = OpExtInst %[[#VINT16]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#ADDRESS]] 2
+; CHECK: %[[#CASTorPARAMofPTRI16:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRINT16]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#VINT16]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#CASTorPARAMofPTRI16]] 2
%call2 = call spir_func <2 x i16> @_Z6vload2mPU3AS1Ks(i64 %offset, ptr addrspace(1) %address)
-; CHECK: %[[#]] = OpExtInst %[[#VINT32]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#ADDRESS]] 2
+; CHECK: %[[#CASTorPARAMofPTRI32:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRINT32]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#VINT32]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#CASTorPARAMofPTRI32]] 2
%call3 = call spir_func <2 x i32> @_Z6vload2mPU3AS1Ki(i64 %offset, ptr addrspace(1) %address)
-; CHECK: %[[#]] = OpExtInst %[[#VINT64]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#ADDRESS]] 2
+; CHECK: %[[#CASTorPARAMofPTRI64:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRINT64]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#VINT64]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#CASTorPARAMofPTRI64]] 2
%call4 = call spir_func <2 x i64> @_Z6vload2mPU3AS1Kl(i64 %offset, ptr addrspace(1) %address)
-; CHECK: %[[#]] = OpExtInst %[[#VFLOAT]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#ADDRESS]] 2
+; CHECK: %[[#CASTorPARAMofPTRFLOAT:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRFLOAT]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#VFLOAT]] %[[#IMPORT]] vloadn %[[#OFFSET]] %[[#CASTorPARAMofPTRFLOAT]] 2
%call5 = call spir_func <2 x float> @_Z6vload2mPU3AS1Kf(i64 %offset, ptr addrspace(1) %address)
ret void
}
diff --git a/llvm/test/CodeGen/SPIRV/opencl/vstore2.ll b/llvm/test/CodeGen/SPIRV/opencl/vstore2.ll
new file mode 100644
index 000000000000000..0ea14c7f25e8778
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/opencl/vstore2.ll
@@ -0,0 +1,23 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; This test only intends to check the vstoren builtin name resolution.
+; The calls to the OpenCL builtins are not valid and will not pass SPIR-V validation.
+
+; CHECK-DAG: %[[#IMPORT:]] = OpExtInstImport "OpenCL.std"
+
+; CHECK-DAG: %[[#VOID:]] = OpTypeVoid
+; CHECK-DAG: %[[#INT8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#INT64:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#VINT8:]] = OpTypeVector %[[#INT8]] 2
+; CHECK-DAG: %[[#PTRINT8:]] = OpTypePointer CrossWorkgroup %[[#INT8]]
+
+; CHECK: %[[#DATA:]] = OpFunctionParameter %[[#VINT8]]
+; CHECK: %[[#OFFSET:]] = OpFunctionParameter %[[#INT64]]
+; CHECK: %[[#ADDRESS:]] = OpFunctionParameter %[[#PTRINT8]]
+
+define spir_kernel void @test_fn(<2 x i8> %data, i64 %offset, ptr addrspace(1) %address) {
+; CHECK: %[[#]] = OpExtInst %[[#VOID]] %[[#IMPORT]] vstoren %[[#DATA]] %[[#OFFSET]] %[[#ADDRESS]]
+ call spir_func void @_Z7vstore2Dv2_cmPU3AS1c(<2 x i8> %data, i64 %offset, ptr addrspace(1) %address)
+ ret void
+}
+
+declare spir_func void @_Z7vstore2Dv2_cmPU3AS1c(<2 x i8>, i64, ptr addrspace(1))
diff --git a/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-TargetExtType-arg-no-spv_assign_type.ll b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-TargetExtType-arg-no-spv_assign_type.ll
new file mode 100644
index 000000000000000..d6cdcd7e20e8f28
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-TargetExtType-arg-no-spv_assign_type.ll
@@ -0,0 +1,12 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -print-after-all -o - 2>&1 | FileCheck %s
+
+; CHECK: *** IR Dump After SPIRV emit intrinsics (emit-intrinsics) ***
+
+define spir_kernel void @test(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) %srcimg) {
+; CHECK-NOT: call void @llvm.spv.assign.type.p1(ptr addrspace(1) %srcimg, metadata target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) undef)
+ %call = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) %srcimg)
+ ret void
+; CHECK: }
+}
+
+declare spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0))
diff --git a/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-divergent-spv_assign_ptr_type.ll b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-divergent-spv_assign_ptr_type.ll
new file mode 100644
index 000000000000000..f728eda079860d4
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-divergent-spv_assign_ptr_type.ll
@@ -0,0 +1,12 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -print-after-all -o - 2>&1 | FileCheck %s
+
+; CHECK: *** IR Dump After SPIRV emit intrinsics (emit-intrinsics) ***
+
+define spir_kernel void @test_pointer_cast(ptr addrspace(1) %src) {
+; CHECK-NOT: call void @llvm.spv.assign.ptr.type.p1(ptr addrspace(1) %src, metadata i8 undef, i32 1)
+; CHECK: call void @llvm.spv.assign.ptr.type.p1(ptr addrspace(1) %src, metadata i32 0, i32 1)
+ %b = bitcast ptr addrspace(1) %src to ptr addrspace(1)
+ %g = getelementptr inbounds i32, ptr addrspace(1) %b, i64 52
+ ret void
+; CHECK: }
+}
diff --git a/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-duplicate-spv_assign_type.ll b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-duplicate-spv_assign_type.ll
new file mode 100644
index 000000000000000..7056b9cb1230dcb
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/passes/SPIRVEmitIntrinsics-no-duplicate-spv_assign_type.ll
@@ -0,0 +1,14 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -print-after-all -o - 2>&1 | FileCheck %s
+
+; CHECK: *** IR Dump After SPIRV emit intrinsics (emit-intrinsics) ***
+
+define spir_kernel void @test(ptr addrspace(1) %srcimg) {
+; CHECK: call void @llvm.spv.assign.type.p1(ptr addrspace(1) %srcimg, metadata target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) undef)
+ %call1 = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1) %srcimg)
+; CHECK-NOT: call void @llvm.spv.assign.type.p1(ptr addrspace(1) %srcimg, metadata target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) undef)
+ %call2 = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1) %srcimg)
+ ret void
+; CHECK: }
+}
+
+declare spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1))
diff --git a/llvm/test/CodeGen/SPIRV/pointers/getelementptr-kernel-arg-char.ll b/llvm/test/CodeGen/SPIRV/pointers/getelementptr-kernel-arg-char.ll
index cca71d409d258d7..d2a65917bfd6590 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/getelementptr-kernel-arg-char.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/getelementptr-kernel-arg-char.ll
@@ -4,28 +4,20 @@
; CHECK-DAG: %[[#INT8:]] = OpTypeInt 8 0
; CHECK-DAG: %[[#INT64:]] = OpTypeInt 64 0
-; CHECK-DAG: %[[#VINT8:]] = OpTypeVector %[[#INT8]] 2
; CHECK-DAG: %[[#PTRINT8:]] = OpTypePointer Workgroup %[[#INT8]]
-; CHECK-DAG: %[[#PTRVINT8:]] = OpTypePointer Workgroup %[[#VINT8]]
; CHECK-DAG: %[[#CONST:]] = OpConstant %[[#INT64]] 1
-; CHECK: %[[#PARAM1:]] = OpFunctionParameter %[[#PTRVINT8]]
-define spir_kernel void @test1(ptr addrspace(3) %address) !kernel_arg_type !1 {
-; CHECK: %[[#BITCAST1:]] = OpBitcast %[[#PTRINT8]] %[[#PARAM1]]
-; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTRINT8]] %[[#BITCAST1]] %[[#CONST]]
+; CHECK: %[[#PARAM1:]] = OpFunctionParameter %[[#PTRINT8]]
+define spir_kernel void @test1(ptr addrspace(3) %address) {
+; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTRINT8]] %[[#PARAM1]] %[[#CONST]]
%cast = bitcast ptr addrspace(3) %address to ptr addrspace(3)
%gep = getelementptr inbounds i8, ptr addrspace(3) %cast, i64 1
ret void
}
-; CHECK: %[[#PARAM2:]] = OpFunctionParameter %[[#PTRVINT8]]
-define spir_kernel void @test2(ptr addrspace(3) %address) !kernel_arg_type !1 {
-; CHECK: %[[#BITCAST2:]] = OpBitcast %[[#PTRINT8]] %[[#PARAM2]]
-; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTRINT8]] %[[#BITCAST2]] %[[#CONST]]
+; CHECK: %[[#PARAM2:]] = OpFunctionParameter %[[#PTRINT8]]
+define spir_kernel void @test2(ptr addrspace(3) %address) {
+; CHECK: %[[#]] = OpInBoundsPtrAccessChain %[[#PTRINT8]] %[[#PARAM2]] %[[#CONST]]
%gep = getelementptr inbounds i8, ptr addrspace(3) %address, i64 1
ret void
}
-
-declare spir_func <2 x i8> @_Z6vload2mPU3AS3Kc(i64, ptr addrspace(3))
-
-!1 = !{!"char2*"}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-builtin-vload-type-discrapency.ll b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-builtin-vload-type-discrapency.ll
new file mode 100644
index 000000000000000..b4948b66aed86df
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-builtin-vload-type-discrapency.ll
@@ -0,0 +1,35 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#INT8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#PTRINT8:]] = OpTypePointer CrossWorkgroup %[[#INT8]]
+
+define spir_kernel void @test_fn(ptr addrspace(1) %src) !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_type_qual !4 !kernel_arg_base_type !3 {
+entry:
+ %g1 = call spir_func i64 @_Z13get_global_idj(i32 0)
+ %i1 = insertelement <3 x i64> undef, i64 %g1, i32 0
+ %g2 = call spir_func i64 @_Z13get_global_idj(i32 1)
+ %i2 = insertelement <3 x i64> %i1, i64 %g2, i32 1
+ %g3 = call spir_func i64 @_Z13get_global_idj(i32 2)
+ %i3 = insertelement <3 x i64> %i2, i64 %g3, i32 2
+ %e = extractelement <3 x i64> %i3, i32 0
+ %c1 = trunc i64 %e to i32
+ %c2 = sext i32 %c1 to i64
+ %b = bitcast ptr addrspace(1) %src to ptr addrspace(1)
+
+; Make sure that builtin call directly uses either a OpBitcast or OpFunctionParameter of i8* type
+; CHECK: %[[#BITCASTorPARAMETER:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#PTRINT8]]{{.*}}
+; CHECK: %[[#]] = OpExtInst %[[#]] %[[#]] vloadn %[[#]] %[[#BITCASTorPARAMETER]] 3
+ %call = call spir_func <3 x i8> @_Z6vload3mPU3AS1Kc(i64 %c2, ptr addrspace(1) %b)
+
+ ret void
+}
+
+declare spir_func i64 @_Z13get_global_idj(i32)
+
+declare spir_func <3 x i8> @_Z6vload3mPU3AS1Kc(i64, ptr addrspace(1))
+
+!1 = !{i32 1}
+!2 = !{!"none"}
+!3 = !{!"char3*"}
+!4 = !{!""}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-mismatch.ll b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-mismatch.ll
new file mode 100644
index 000000000000000..46e315b2dc62a25
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-mismatch.ll
@@ -0,0 +1,12 @@
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o - 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: Type mismatch {{.*}}
+
+define spir_kernel void @test(ptr addrspace(1) %srcimg) {
+ %call1 = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1) %srcimg)
+ %call2 = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_rw(ptr addrspace(1) %srcimg)
+ ret void
+}
+
+declare spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1))
+declare spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_rw(ptr addrspace(1))
diff --git a/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-no-metadata.ll b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-no-metadata.ll
new file mode 100644
index 000000000000000..a513d1039706637
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/kernel-argument-pointer-type-deduction-no-metadata.ll
@@ -0,0 +1,13 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+define spir_kernel void @test(ptr addrspace(1) %srcimg) {
+; CHECK: %[[#VOID:]] = OpTypeVoid
+; CHECK: %[[#IMAGE:]] = OpTypeImage %[[#VOID]] 2D 0 0 0 0 Unknown ReadOnly
+; CHECK: %[[#PARAM:]] = OpFunctionParameter %[[#IMAGE]]
+; CHECK: %[[#]] = OpImageQuerySizeLod %[[#]] %[[#PARAM]] %[[#]]
+ %call = call spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1) %srcimg)
+ ret void
+}
+
+declare spir_func <2 x i32> @_Z13get_image_dim14ocl_image2d_ro(ptr addrspace(1))
diff --git a/llvm/test/CodeGen/SPIRV/pointers/store-operand-ptr-to-struct.ll b/llvm/test/CodeGen/SPIRV/pointers/store-operand-ptr-to-struct.ll
new file mode 100644
index 000000000000000..00b03c08e7bbcd3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/store-operand-ptr-to-struct.ll
@@ -0,0 +1,19 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+
+; TODO: OpFunctionParameter should be a pointer of struct base type.
+; XFAIL: *
+
+%struct = type {
+ i32,
+ i16
+}
+
+%nested_struct = type {
+ %struct,
+ i16
+}
+
+define void @foo(ptr %ptr) {
+ store %nested_struct undef, ptr %ptr
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll b/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-or-param-users.ll
similarity index 50%
rename from llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll
rename to llvm/test/CodeGen/SPIRV/pointers/two-bitcast-or-param-users.ll
index f4ea710fa04317e..52180d53740883b 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-users.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/two-bitcast-or-param-users.ll
@@ -1,9 +1,7 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
-; CHECK-DAG: %[[#CHAR:]] = OpTypeInt 8
; CHECK-DAG: %[[#INT:]] = OpTypeInt 32
; CHECK-DAG: %[[#GLOBAL_PTR_INT:]] = OpTypePointer CrossWorkgroup %[[#INT]]
-; CHECK-DAG: %[[#GLOBAL_PTR_CHAR:]] = OpTypePointer CrossWorkgroup %[[#CHAR]]
define i32 @foo(i32 %a, ptr addrspace(1) %p) {
store i32 %a, i32 addrspace(1)* %p
@@ -12,8 +10,6 @@ define i32 @foo(i32 %a, ptr addrspace(1) %p) {
}
; CHECK: %[[#A:]] = OpFunctionParameter %[[#INT]]
-; CHECK: %[[#P:]] = OpFunctionParameter %[[#GLOBAL_PTR_CHAR]]
-; CHECK: %[[#C:]] = OpBitcast %[[#GLOBAL_PTR_INT]] %[[#P]]
-; CHECK: OpStore %[[#C]] %[[#A]]
-; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#C]]
-; CHECK-NOT: %[[#B:]] = OpLoad %[[#INT]] %[[#P]]
+; CHECK: %[[#CorP:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#GLOBAL_PTR_INT]]{{.*}}
+; CHECK: OpStore %[[#CorP]] %[[#A]]
+; CHECK: %[[#B:]] = OpLoad %[[#INT]] %[[#CorP]]
diff --git a/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll b/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll
index 8998329ea64fe20..473c2a8b7311152 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/two-subsequent-bitcasts.ll
@@ -2,14 +2,13 @@
; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
; CHECK-DAG: %[[#pointer:]] = OpTypePointer CrossWorkgroup %[[#float]]
-; CHECK: %[[#A:]] = OpFunctionParameter %[[#]]
define void @foo(float addrspace(1)* %A, i32 %B) {
%cmp = icmp sgt i32 %B, 0
%conv = uitofp i1 %cmp to float
-; CHECK: %[[#utof_res:]] = OpConvertUToF %[[#float]] %[[#]]
-; CHECK: %[[#bitcast:]] = OpBitcast %[[#pointer]] %[[#A]]
-; CHECK: OpStore %[[#bitcast]] %[[#utof_res]]
+; CHECK-DAG: %[[#utof_res:]] = OpConvertUToF %[[#float]] %[[#]]
+; CHECK-DAG: %[[#bitcastORparam:]] = {{OpBitcast|OpFunctionParameter}}{{.*}}%[[#pointer]]{{.*}}
+; CHECK: OpStore %[[#bitcastORparam]] %[[#utof_res]]
%BC1 = bitcast float addrspace(1)* %A to i32 addrspace(1)*
%BC2 = bitcast i32 addrspace(1)* %BC1 to float addrspace(1)*
store float %conv, float addrspace(1)* %BC2, align 4;
diff --git a/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll b/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
index 06f27e2cb1f9065..d9145e8d9f0a948 100644
--- a/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
+++ b/llvm/test/CodeGen/SPIRV/sitofp-with-bool.ll
@@ -8,13 +8,12 @@
; CHECK-DAG: %[[#ptr:]] = OpTypePointer CrossWorkgroup %[[#float]]
; CHECK: OpFunction
-; CHECK: %[[#A:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#ptr]]
; CHECK: %[[#B:]] = OpFunctionParameter %[[#]]
; CHECK: %[[#cmp_res:]] = OpSGreaterThan %[[#bool]] %[[#B]] %[[#zero]]
; CHECK: %[[#select_res:]] = OpSelect %[[#int_32]] %[[#cmp_res]] %[[#one]] %[[#zero]]
; CHECK: %[[#stof_res:]] = OpConvertSToF %[[#]] %[[#select_res]]
-; CHECK: %[[#bitcast:]] = OpBitcast %[[#ptr]] %[[#A]]
-; CHECK: OpStore %[[#bitcast]] %[[#stof_res]]
+; CHECK: OpStore %[[#A]] %[[#stof_res]]
define dso_local spir_kernel void @K(ptr addrspace(1) nocapture %A, i32 %B) local_unnamed_addr {
entry:
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_cmpxchg.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_cmpxchg.ll
index f4e6c83a8cd519e..331960cdb341e7b 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_cmpxchg.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_cmpxchg.ll
@@ -14,9 +14,8 @@
;; }
; CHECK-SPIRV: OpName %[[#TEST:]] "test_atomic_cmpxchg"
-; CHECK-SPIRV-DAG: %[[#UCHAR:]] = OpTypeInt 8 0
; CHECK-SPIRV-DAG: %[[#UINT:]] = OpTypeInt 32 0
-; CHECK-SPIRV-DAG: %[[#UCHAR_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR]]
+; CHECK-SPIRV-DAG: %[[#UINT_PTR:]] = OpTypePointer CrossWorkgroup %[[#UINT]]
;; In SPIR-V, atomic_cmpxchg is represented as OpAtomicCompareExchange [2],
;; which also includes memory scope and two memory semantic arguments. The
@@ -31,7 +30,7 @@
; CHECK-SPIRV-DAG: %[[#RELAXED:]] = OpConstant %[[#UINT]] 0
; CHECK-SPIRV: %[[#TEST]] = OpFunction %[[#]]
-; CHECK-SPIRV: %[[#PTR:]] = OpFunctionParameter %[[#UCHAR_PTR]]
+; CHECK-SPIRV: %[[#PTR:]] = OpFunctionParameter %[[#UINT_PTR]]
; CHECK-SPIRV: %[[#CMP:]] = OpFunctionParameter %[[#UINT]]
; CHECK-SPIRV: %[[#VAL:]] = OpFunctionParameter %[[#UINT]]
; CHECK-SPIRV: %[[#]] = OpAtomicCompareExchange %[[#UINT]] %[[#PTR]] %[[#WORKGROUP_SCOPE]] %[[#RELAXED]] %[[#RELAXED]] %[[#VAL]] %[[#CMP]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_legacy.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_legacy.ll
index 3e805e6eea97d0a..95eb6ade11a25cb 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_legacy.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpenCL/atomic_legacy.ll
@@ -11,8 +11,7 @@
; CHECK-SPIRV: OpName %[[#TEST:]] "test_legacy_atomics"
; CHECK-SPIRV-DAG: %[[#UINT:]] = OpTypeInt 32 0
-; CHECK-SPIRV-DAG: %[[#UCHAR:]] = OpTypeInt 8 0
-; CHECK-SPIRV-DAG: %[[#UCHAR_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR]]
+; CHECK-SPIRV-DAG: %[[#UINT_PTR:]] = OpTypePointer CrossWorkgroup %[[#UINT]]
;; In SPIR-V, atomic_add is represented as OpAtomicIAdd [2], which also includes
;; memory scope and memory semantic arguments. The backend applies a default
@@ -26,7 +25,7 @@
; CHECK-SPIRV-DAG: %[[#RELAXED:]] = OpConstant %[[#UINT]] 0
; CHECK-SPIRV: %[[#TEST]] = OpFunction %[[#]]
-; CHECK-SPIRV: %[[#PTR:]] = OpFunctionParameter %[[#UCHAR_PTR]]
+; CHECK-SPIRV: %[[#PTR:]] = OpFunctionParameter %[[#UINT_PTR]]
; CHECK-SPIRV: %[[#VAL:]] = OpFunctionParameter %[[#UINT]]
; CHECK-SPIRV: %[[#]] = OpAtomicIAdd %[[#UINT]] %[[#PTR]] %[[#WORKGROUP_SCOPE]] %[[#RELAXED]] %[[#VAL]]
; CHECK-SPIRV: %[[#]] = OpAtomicIAdd %[[#UINT]] %[[#PTR]] %[[#WORKGROUP_SCOPE]] %[[#RELAXED]] %[[#VAL]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll b/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
index a07af76c2232403..3551030843d062f 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/spirv-private-array-initialization.ll
@@ -13,7 +13,6 @@
; CHECK-SPIRV: %[[#test_arr2:]] = OpVariable %[[#const_i32x3_ptr]] UniformConstant %[[#test_arr_init]]
; CHECK-SPIRV: %[[#test_arr:]] = OpVariable %[[#const_i32x3_ptr]] UniformConstant %[[#test_arr_init]]
-; CHECK-SPIRV-DAG: %[[#i8_ptr:]] = OpTypePointer Function %[[#i8]]
; CHECK-SPIRV-DAG: %[[#const_i8_ptr:]] = OpTypePointer UniformConstant %[[#i8]]
; CHECK-SPIRV-DAG: %[[#i32x3_ptr:]] = OpTypePointer Function %[[#i32x3]]
diff --git a/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll b/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
index 8a3c2853d99149d..6f793fc5d030e6f 100644
--- a/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
+++ b/llvm/test/CodeGen/SPIRV/uitofp-with-bool.ll
@@ -69,7 +69,7 @@
; SPV-DAG: %[[#pointer:]] = OpTypePointer CrossWorkgroup %[[#float]]
; SPV-DAG: OpFunction
-; SPV-DAG: %[[#A:]] = OpFunctionParameter %[[#]]
+; SPV-DAG: %[[#A:]] = OpFunctionParameter %[[#pointer]]
; SPV-DAG: %[[#B:]] = OpFunctionParameter %[[#]]
; SPV-DAG: %[[#i1s:]] = OpFunctionParameter %[[#]]
; SPV-DAG: %[[#i1v:]] = OpFunctionParameter %[[#]]
@@ -82,8 +82,7 @@ entry:
; SPV-DAG: %[[#select_res:]] = OpSelect %[[#int_32]] %[[#cmp_res]] %[[#one_32]] %[[#zero_32]]
; SPV-DAG: %[[#utof_res:]] = OpConvertUToF %[[#float]] %[[#select_res]]
%conv = uitofp i1 %cmp to float
-; SPV-DAG: %[[#bitcast:]] = OpBitcast %[[#pointer]] %[[#A]]
-; SPV-DAG: OpStore %[[#bitcast]] %[[#utof_res]]
+; SPV-DAG: OpStore %[[#A]] %[[#utof_res]]
store float %conv, float addrspace(1)* %A, align 4;
; SPV-DAG: %[[#s1]] = OpSelect %[[#int_8]] %[[#i1s]] %[[#mone_8]] %[[#zero_8]]
>From bf3df62cc8c308052191e447ba59448b24811746 Mon Sep 17 00:00:00 2001
From: Michal Paszkowski <michal at paszkowski.org>
Date: Sun, 3 Mar 2024 21:17:42 -0800
Subject: [PATCH 2/2] [SPIR-V] Add basic support for byval/byref ptr arguments
---
llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp | 20 ++++++++++++----
.../SPIRV/pointers/ptr-argument-byref.ll | 24 +++++++++++++++++++
.../SPIRV/pointers/ptr-argument-byval.ll | 22 +++++++++++++++++
3 files changed, 62 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byref.ll
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byval.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index f8983cc7d5da3d4..2d7a00bab38e915 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -165,13 +165,25 @@ static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx,
if (!OriginalArgType->isPointerTy())
return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual);
- // In case OriginalArgType is of pointer type, there are two possibilities:
- // 1) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type
+ // In case OriginalArgType is of pointer type, there are three possibilities:
+ // 1) This is a pointer of an LLVM IR element type, passed byval/byref.
+ // 2) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type
// intrinsic assigning a TargetExtType.
- // 2) This is a pointer, try to retrieve pointer element type from a
+ // 3) This is a pointer, try to retrieve pointer element type from a
// spv_assign_ptr_type intrinsic or otherwise use default pointer element
// type.
- for (auto User : F.getArg(ArgIdx)->users()) {
+ Argument *Arg = F.getArg(ArgIdx);
+ if (Arg->hasByValAttr() || Arg->hasByRefAttr()) {
+ Type *ByValRefType = Arg->hasByValAttr() ? Arg->getParamByValType()
+ : Arg->getParamByRefType();
+ SPIRVType *ElementType = GR->getOrCreateSPIRVType(ByValRefType, MIRBuilder);
+ return GR->getOrCreateSPIRVPointerType(
+ ElementType, MIRBuilder,
+ addressSpaceToStorageClass(Arg->getType()->getPointerAddressSpace(),
+ ST));
+ }
+
+ for (auto User : Arg->users()) {
auto *II = dyn_cast<IntrinsicInst>(User);
// Check if this is spv_assign_type assigning OpenCL/SPIR-V builtin type.
if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) {
diff --git a/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byref.ll b/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byref.ll
new file mode 100644
index 000000000000000..639906af3a952fe
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byref.ll
@@ -0,0 +1,24 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+target triple = "spirv64-unknown-unknown"
+
+; CHECK-DAG: %[[#VOID:]] = OpTypeVoid
+; CHECK-DAG: %[[#INT32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#STRUCT1:]] = OpTypeStruct %[[#INT32]]
+; CHECK-DAG: %[[#CONST:]] = OpConstant %[[#INT32]] 7
+; CHECK-DAG: %[[#ARRAY:]] = OpTypeArray %[[#STRUCT1]] %[[#CONST]]
+; CHECK-DAG: %[[#STRUCT2:]] = OpTypeStruct %[[#ARRAY]]
+; CHECK-DAG: %[[#PTR:]] = OpTypePointer Function %[[#STRUCT2]]
+
+; CHECK: %[[#FUNC:]] = OpTypeFunction %[[#VOID]] %[[#PTR]]
+; CHECK: %[[#]] = OpFunction %[[#VOID]] None %[[#FUNC]]
+; CHECK: %[[#]] = OpFunctionParameter %[[#PTR]]
+
+%struct.S = type { i32 }
+%struct.__wrapper_class = type { [7 x %struct.S] }
+
+define spir_kernel void @foo(ptr noundef byref(%struct.__wrapper_class) align 4 %_arg_Arr) {
+entry:
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byval.ll b/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byval.ll
new file mode 100644
index 000000000000000..6b684bf41bbb09a
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/ptr-argument-byval.ll
@@ -0,0 +1,22 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#VOID:]] = OpTypeVoid
+; CHECK-DAG: %[[#INT32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#STRUCT1:]] = OpTypeStruct %[[#INT32]]
+; CHECK-DAG: %[[#CONST:]] = OpConstant %[[#INT32]] 7
+; CHECK-DAG: %[[#ARRAY:]] = OpTypeArray %[[#STRUCT1]] %[[#CONST]]
+; CHECK-DAG: %[[#STRUCT2:]] = OpTypeStruct %[[#ARRAY]]
+; CHECK-DAG: %[[#PTR:]] = OpTypePointer Function %[[#STRUCT2]]
+
+; CHECK: %[[#FUNC:]] = OpTypeFunction %[[#VOID]] %[[#PTR]]
+; CHECK: %[[#]] = OpFunction %[[#VOID]] None %[[#FUNC]]
+; CHECK: %[[#]] = OpFunctionParameter %[[#PTR]]
+
+%struct.S = type { i32 }
+%struct.__wrapper_class = type { [7 x %struct.S] }
+
+define spir_kernel void @foo(ptr noundef byval(%struct.__wrapper_class) align 4 %_arg_Arr) {
+entry:
+ ret void
+}
More information about the llvm-commits
mailing list