[llvm] 5752098 - [SPIR-V] Implement insertion of OpGenericCastToPtr using builtin functions (#95055)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 11 12:23:52 PDT 2024
Author: Vyacheslav Levytskyy
Date: 2024-06-11T21:23:48+02:00
New Revision: 57520985e09f3c098a5f5a6f72e3107a8a1d5446
URL: https://github.com/llvm/llvm-project/commit/57520985e09f3c098a5f5a6f72e3107a8a1d5446
DIFF: https://github.com/llvm/llvm-project/commit/57520985e09f3c098a5f5a6f72e3107a8a1d5446.diff
LOG: [SPIR-V] Implement insertion of OpGenericCastToPtr using builtin functions (#95055)
This PR implements insertion of OpGenericCastToPtr using builtin
functions (both opencl `to_global|local|private` and `__spirv_`
wrappers), and improves type inference.
Added:
llvm/test/CodeGen/SPIRV/transcoding/OpGenericCastToPtr.ll
Modified:
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
llvm/lib/Target/SPIRV/SPIRVBuiltins.td
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 49838e685a6d2..6bb3e215240a8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -300,6 +300,72 @@ lookupBuiltin(StringRef DemangledCall,
return nullptr;
}
+static MachineInstr *getBlockStructInstr(Register ParamReg,
+ MachineRegisterInfo *MRI) {
+ // We expect the following sequence of instructions:
+ // %0:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.alloca)
+ // or = G_GLOBAL_VALUE @block_literal_global
+ // %1:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.bitcast), %0
+ // %2:_(p4) = G_ADDRSPACE_CAST %1:_(pN)
+ MachineInstr *MI = MRI->getUniqueVRegDef(ParamReg);
+ assert(MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST &&
+ MI->getOperand(1).isReg());
+ Register BitcastReg = MI->getOperand(1).getReg();
+ MachineInstr *BitcastMI = MRI->getUniqueVRegDef(BitcastReg);
+ assert(isSpvIntrinsic(*BitcastMI, Intrinsic::spv_bitcast) &&
+ BitcastMI->getOperand(2).isReg());
+ Register ValueReg = BitcastMI->getOperand(2).getReg();
+ MachineInstr *ValueMI = MRI->getUniqueVRegDef(ValueReg);
+ return ValueMI;
+}
+
+// Return an integer constant corresponding to the given register and
+// defined in spv_track_constant.
+// TODO: maybe unify with prelegalizer pass.
+static unsigned getConstFromIntrinsic(Register Reg, MachineRegisterInfo *MRI) {
+ MachineInstr *DefMI = MRI->getUniqueVRegDef(Reg);
+ assert(isSpvIntrinsic(*DefMI, Intrinsic::spv_track_constant) &&
+ DefMI->getOperand(2).isReg());
+ MachineInstr *DefMI2 = MRI->getUniqueVRegDef(DefMI->getOperand(2).getReg());
+ assert(DefMI2->getOpcode() == TargetOpcode::G_CONSTANT &&
+ DefMI2->getOperand(1).isCImm());
+ return DefMI2->getOperand(1).getCImm()->getValue().getZExtValue();
+}
+
+// Return type of the instruction result from spv_assign_type intrinsic.
+// TODO: maybe unify with prelegalizer pass.
+static const Type *getMachineInstrType(MachineInstr *MI) {
+ MachineInstr *NextMI = MI->getNextNode();
+ if (!NextMI)
+ return nullptr;
+ if (isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_name))
+ if ((NextMI = NextMI->getNextNode()) == nullptr)
+ return nullptr;
+ Register ValueReg = MI->getOperand(0).getReg();
+ if ((!isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_type) &&
+ !isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_ptr_type)) ||
+ NextMI->getOperand(1).getReg() != ValueReg)
+ return nullptr;
+ Type *Ty = getMDOperandAsType(NextMI->getOperand(2).getMetadata(), 0);
+ assert(Ty && "Type is expected");
+ return Ty;
+}
+
+static const Type *getBlockStructType(Register ParamReg,
+ MachineRegisterInfo *MRI) {
+ // In principle, this information should be passed to us from Clang via
+ // an elementtype attribute. However, said attribute requires that
+ // the function call be an intrinsic, which is not. Instead, we rely on being
+ // able to trace this to the declaration of a variable: OpenCL C specification
+ // section 6.12.5 should guarantee that we can do this.
+ MachineInstr *MI = getBlockStructInstr(ParamReg, MRI);
+ if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
+ 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);
+}
+
//===----------------------------------------------------------------------===//
// Helper functions for building misc instructions
//===----------------------------------------------------------------------===//
@@ -1371,6 +1437,14 @@ static bool generateBarrierInst(const SPIRV::IncomingCall *Call,
return buildBarrierInst(Call, Opcode, MIRBuilder, GR);
}
+static bool generateCastToPtrInst(const SPIRV::IncomingCall *Call,
+ MachineIRBuilder &MIRBuilder) {
+ MIRBuilder.buildInstr(TargetOpcode::G_ADDRSPACE_CAST)
+ .addDef(Call->ReturnRegister)
+ .addUse(Call->Arguments[0]);
+ return true;
+}
+
static bool generateDotOrFMulInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
@@ -1847,68 +1921,6 @@ static bool buildNDRange(const SPIRV::IncomingCall *Call,
.addUse(TmpReg);
}
-static MachineInstr *getBlockStructInstr(Register ParamReg,
- MachineRegisterInfo *MRI) {
- // We expect the following sequence of instructions:
- // %0:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.alloca)
- // or = G_GLOBAL_VALUE @block_literal_global
- // %1:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.bitcast), %0
- // %2:_(p4) = G_ADDRSPACE_CAST %1:_(pN)
- MachineInstr *MI = MRI->getUniqueVRegDef(ParamReg);
- assert(MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST &&
- MI->getOperand(1).isReg());
- Register BitcastReg = MI->getOperand(1).getReg();
- MachineInstr *BitcastMI = MRI->getUniqueVRegDef(BitcastReg);
- assert(isSpvIntrinsic(*BitcastMI, Intrinsic::spv_bitcast) &&
- BitcastMI->getOperand(2).isReg());
- Register ValueReg = BitcastMI->getOperand(2).getReg();
- MachineInstr *ValueMI = MRI->getUniqueVRegDef(ValueReg);
- return ValueMI;
-}
-
-// Return an integer constant corresponding to the given register and
-// defined in spv_track_constant.
-// TODO: maybe unify with prelegalizer pass.
-static unsigned getConstFromIntrinsic(Register Reg, MachineRegisterInfo *MRI) {
- MachineInstr *DefMI = MRI->getUniqueVRegDef(Reg);
- assert(isSpvIntrinsic(*DefMI, Intrinsic::spv_track_constant) &&
- DefMI->getOperand(2).isReg());
- MachineInstr *DefMI2 = MRI->getUniqueVRegDef(DefMI->getOperand(2).getReg());
- assert(DefMI2->getOpcode() == TargetOpcode::G_CONSTANT &&
- DefMI2->getOperand(1).isCImm());
- return DefMI2->getOperand(1).getCImm()->getValue().getZExtValue();
-}
-
-// Return type of the instruction result from spv_assign_type intrinsic.
-// TODO: maybe unify with prelegalizer pass.
-static const Type *getMachineInstrType(MachineInstr *MI) {
- MachineInstr *NextMI = MI->getNextNode();
- if (isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_name))
- NextMI = NextMI->getNextNode();
- Register ValueReg = MI->getOperand(0).getReg();
- if (!isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_type) ||
- NextMI->getOperand(1).getReg() != ValueReg)
- return nullptr;
- Type *Ty = getMDOperandAsType(NextMI->getOperand(2).getMetadata(), 0);
- assert(Ty && "Type is expected");
- return Ty;
-}
-
-static const Type *getBlockStructType(Register ParamReg,
- MachineRegisterInfo *MRI) {
- // In principle, this information should be passed to us from Clang via
- // an elementtype attribute. However, said attribute requires that
- // the function call be an intrinsic, which is not. Instead, we rely on being
- // able to trace this to the declaration of a variable: OpenCL C specification
- // section 6.12.5 should guarantee that we can do this.
- MachineInstr *MI = getBlockStructInstr(ParamReg, MRI);
- if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
- 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);
-}
-
// TODO: maybe move to the global register.
static SPIRVType *
getOrCreateSPIRVDeviceEventPointer(MachineIRBuilder &MIRBuilder,
@@ -2322,6 +2334,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
return generateAtomicFloatingInst(Call.get(), MIRBuilder, GR);
case SPIRV::Barrier:
return generateBarrierInst(Call.get(), MIRBuilder, GR);
+ case SPIRV::CastToPtr:
+ return generateCastToPtrInst(Call.get(), MIRBuilder);
case SPIRV::Dot:
return generateDotOrFMulInst(Call.get(), MIRBuilder, GR);
case SPIRV::Wave:
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index edc9e1a33d9f5..2edd2992425bd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -59,6 +59,7 @@ def IntelSubgroups : BuiltinGroup;
def AtomicFloating : BuiltinGroup;
def GroupUniform : BuiltinGroup;
def KernelClock : BuiltinGroup;
+def CastToPtr : BuiltinGroup;
//===----------------------------------------------------------------------===//
// Class defining a demangled builtin record. The information in the record
@@ -595,6 +596,17 @@ defm : DemangledNativeBuiltin<"__spirv_GroupWaitEvents", OpenCL_std, AsyncCopy,
defm : DemangledNativeBuiltin<"__spirv_Load", OpenCL_std, LoadStore, 1, 3, OpLoad>;
defm : DemangledNativeBuiltin<"__spirv_Store", OpenCL_std, LoadStore, 2, 4, OpStore>;
+// Address Space Qualifier Functions/Pointers Conversion Instructions:
+defm : DemangledNativeBuiltin<"to_global", OpenCL_std, CastToPtr, 1, 1, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"to_local", OpenCL_std, CastToPtr, 1, 1, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"to_private", OpenCL_std, CastToPtr, 1, 1, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_GenericCastToPtr_ToGlobal", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_GenericCastToPtr_ToLocal", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_GenericCastToPtr_ToPrivate", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_OpGenericCastToPtrExplicit_ToGlobal", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_OpGenericCastToPtrExplicit_ToLocal", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+defm : DemangledNativeBuiltin<"__spirv_OpGenericCastToPtrExplicit_ToPrivate", OpenCL_std, CastToPtr, 2, 2, OpGenericCastToPtr>;
+
//===----------------------------------------------------------------------===//
// Class defining a work/sub group builtin that should be translated into a
// SPIR-V instruction using the defined properties.
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 7b8e3230bf553..5c10e04325d51 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -69,7 +69,7 @@ class SPIRVEmitIntrinsics
DenseSet<Instruction *> AggrStores;
// deduce element type of untyped pointers
- Type *deduceElementType(Value *I);
+ Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
Type *deduceElementTypeHelper(Value *I);
Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited);
Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
@@ -105,7 +105,8 @@ class SPIRVEmitIntrinsics
void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
- void insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B);
+ bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
+ bool UnknownElemTypeI8);
void insertAssignTypeIntrs(Instruction *I, IRBuilder<> &B);
void insertAssignPtrTypeTargetExt(TargetExtType *AssignedType, Value *V,
IRBuilder<> &B);
@@ -367,6 +368,23 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
if (Ty)
break;
}
+ } else if (auto *CI = dyn_cast<CallInst>(I)) {
+ static StringMap<unsigned> ResTypeByArg = {
+ {"to_global", 0},
+ {"to_local", 0},
+ {"to_private", 0},
+ {"__spirv_GenericCastToPtr_ToGlobal", 0},
+ {"__spirv_GenericCastToPtr_ToLocal", 0},
+ {"__spirv_GenericCastToPtr_ToPrivate", 0}};
+ // TODO: maybe improve performance by caching demangled names
+ if (Function *CalledF = CI->getCalledFunction()) {
+ std::string DemangledName =
+ getOclOrSpirvBuiltinDemangledName(CalledF->getName());
+ auto AsArgIt = ResTypeByArg.find(DemangledName);
+ if (AsArgIt != ResTypeByArg.end())
+ Ty = deduceElementTypeHelper(CI->getArgOperand(AsArgIt->second),
+ Visited);
+ }
}
// remember the found relationship
@@ -460,10 +478,10 @@ Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
return OrigTy;
}
-Type *SPIRVEmitIntrinsics::deduceElementType(Value *I) {
+Type *SPIRVEmitIntrinsics::deduceElementType(Value *I, bool UnknownElemTypeI8) {
if (Type *Ty = deduceElementTypeHelper(I))
return Ty;
- return IntegerType::getInt8Ty(I->getContext());
+ return UnknownElemTypeI8 ? IntegerType::getInt8Ty(I->getContext()) : nullptr;
}
// If the Instruction has Pointer operands with unresolved types, this function
@@ -1152,16 +1170,23 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
}
-void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
- IRBuilder<> &B) {
+// Return true, if we can't decide what is the pointee type now and will get
+// back to the question later. Return false is spv_assign_ptr_type is not needed
+// or can be inserted immediately.
+bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
+ IRBuilder<> &B,
+ bool UnknownElemTypeI8) {
reportFatalOnTokenType(I);
if (!isPointerTy(I->getType()) || !requireAssignType(I) ||
isa<BitCastInst>(I))
- return;
+ return false;
setInsertPointAfterDef(B, I);
- Type *ElemTy = deduceElementType(I);
- buildAssignPtr(B, ElemTy, I);
+ if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
+ buildAssignPtr(B, ElemTy, I);
+ return false;
+ }
+ return true;
}
void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
@@ -1199,7 +1224,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
buildAssignPtr(B, PType->getElementType(), Op);
} else if (isPointerTy(OpTy)) {
Type *ElemTy = GR->findDeducedElementType(Op);
- buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op), Op);
+ buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);
} else {
CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
{OpTy}, Op, Op, {}, B);
@@ -1395,10 +1420,15 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
if (isConvergenceIntrinsic(I))
continue;
- insertAssignPtrTypeIntrs(I, B);
+ bool Postpone = insertAssignPtrTypeIntrs(I, B, false);
+ // if Postpone is true, we can't decide on pointee type yet
insertAssignTypeIntrs(I, B);
insertPtrCastOrAssignTypeInstr(I, B);
insertSpirvDecorations(I, B);
+ // if instruction requires a pointee type set, let's check if we know it
+ // already, and force it to be i8 if not
+ if (Postpone && !GR->findAssignPtrTypeInstr(I))
+ insertAssignPtrTypeIntrs(I, B, true);
}
for (auto &I : instructions(Func))
diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
index 5ccbaf12ddee2..4383d1c5c0e25 100644
--- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
@@ -339,6 +339,7 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
GR.getSPIRVTypeForVReg(MI.getOperand(1).getReg()));
break;
case SPIRV::OpPtrCastToGeneric:
+ case SPIRV::OpGenericCastToPtr:
validateAccessChain(STI, MRI, GR, MI);
break;
case SPIRV::OpInBoundsPtrAccessChain:
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpGenericCastToPtr.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpGenericCastToPtr.ll
new file mode 100644
index 0000000000000..e3a82b3577701
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpGenericCastToPtr.ll
@@ -0,0 +1,138 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-SPIRV-DAG: %[[#Char:]] = OpTypeInt 8 0
+; CHECK-SPIRV-DAG: %[[#GlobalCharPtr:]] = OpTypePointer CrossWorkgroup %[[#Char]]
+; CHECK-SPIRV-DAG: %[[#LocalCharPtr:]] = OpTypePointer Workgroup %[[#Char]]
+; CHECK-SPIRV-DAG: %[[#PrivateCharPtr:]] = OpTypePointer Function %[[#Char]]
+; CHECK-SPIRV-DAG: %[[#GenericCharPtr:]] = OpTypePointer Generic %[[#Char]]
+
+; CHECK-SPIRV-DAG: %[[#Int:]] = OpTypeInt 32 0
+; CHECK-SPIRV-DAG: %[[#GlobalIntPtr:]] = OpTypePointer CrossWorkgroup %[[#Int]]
+; CHECK-SPIRV-DAG: %[[#PrivateIntPtr:]] = OpTypePointer Function %[[#Int]]
+; CHECK-SPIRV-DAG: %[[#GenericIntPtr:]] = OpTypePointer Generic %[[#Int]]
+
+%id = type { %arr }
+%arr = type { [1 x i64] }
+
+ at __spirv_BuiltInGlobalInvocationId = external local_unnamed_addr addrspace(1) constant <3 x i64>
+
+; Mangling
+
+; CHECK-SPIRV: OpFunction
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericCharPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#GlobalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#LocalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#PrivateCharPtr]]
+; CHECK-SPIRV: OpFunctionEnd
+
+; CHECK-SPIRV: OpFunction
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericCharPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#GlobalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#LocalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#PrivateCharPtr]]
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_kernel void @test1(ptr addrspace(1) %_arg_GlobalA, ptr byval(%id) %_arg_GlobalId, ptr addrspace(3) %_arg_LocalA) {
+entry:
+ %var = alloca i32
+ %p0 = load i64, ptr %_arg_GlobalId
+ %add = getelementptr inbounds i32, ptr addrspace(1) %_arg_GlobalA, i64 %p0
+ %p2 = load i64, ptr addrspace(1) @__spirv_BuiltInGlobalInvocationId
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %add, i64 %p2
+ %var1 = addrspacecast ptr addrspace(1) %idx to ptr addrspace(4)
+ %var2 = addrspacecast ptr addrspace(3) %_arg_LocalA to ptr addrspace(4)
+ %var3 = addrspacecast ptr %var to ptr addrspace(4)
+ %G = call spir_func ptr addrspace(1) @_Z33__spirv_GenericCastToPtr_ToGlobalPvi(ptr addrspace(4) %var1, i32 5)
+ %L = call spir_func ptr addrspace(3) @_Z32__spirv_GenericCastToPtr_ToLocalPvi(ptr addrspace(4) %var2, i32 4)
+ %P = call spir_func ptr @_Z34__spirv_GenericCastToPtr_ToPrivatePvi(ptr addrspace(4) %var3, i32 7)
+ ret void
+}
+
+define spir_kernel void @test2(ptr addrspace(1) %_arg_GlobalA, ptr byval(%id) %_arg_GlobalId, ptr addrspace(3) %_arg_LocalA) {
+entry:
+ %var = alloca i32
+ %p0 = load i64, ptr %_arg_GlobalId
+ %add = getelementptr inbounds i32, ptr addrspace(1) %_arg_GlobalA, i64 %p0
+ %p2 = load i64, ptr addrspace(1) @__spirv_BuiltInGlobalInvocationId
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %add, i64 %p2
+ %var1 = addrspacecast ptr addrspace(1) %idx to ptr addrspace(4)
+ %var2 = addrspacecast ptr addrspace(3) %_arg_LocalA to ptr addrspace(4)
+ %var3 = addrspacecast ptr %var to ptr addrspace(4)
+ %G = call spir_func ptr addrspace(1) @_Z9to_globalPv(ptr addrspace(4) %var1)
+ %L = call spir_func ptr addrspace(3) @_Z8to_localPv(ptr addrspace(4) %var2)
+ %P = call spir_func ptr @_Z10to_privatePv(ptr addrspace(4) %var3)
+ ret void
+}
+
+declare spir_func ptr addrspace(1) @_Z33__spirv_GenericCastToPtr_ToGlobalPvi(ptr addrspace(4), i32)
+declare spir_func ptr addrspace(3) @_Z32__spirv_GenericCastToPtr_ToLocalPvi(ptr addrspace(4), i32)
+declare spir_func ptr @_Z34__spirv_GenericCastToPtr_ToPrivatePvi(ptr addrspace(4), i32)
+
+declare spir_func ptr addrspace(1) @_Z9to_globalPv(ptr addrspace(4))
+declare spir_func ptr addrspace(3) @_Z8to_localPv(ptr addrspace(4))
+declare spir_func ptr @_Z10to_privatePv(ptr addrspace(4))
+
+; No mangling
+
+; CHECK-SPIRV: OpFunction
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericCharPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#GlobalIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#LocalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#PrivateIntPtr]]
+; CHECK-SPIRV: OpFunctionEnd
+
+; CHECK-SPIRV: OpFunction
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericCharPtr]]
+; CHECK-SPIRV: OpPtrCastToGeneric %[[#GenericIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#GlobalIntPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#LocalCharPtr]]
+; CHECK-SPIRV: OpGenericCastToPtr %[[#PrivateIntPtr]]
+; CHECK-SPIRV: OpFunctionEnd
+
+define spir_kernel void @test3(ptr addrspace(1) %_arg_GlobalA, ptr byval(%id) %_arg_GlobalId, ptr addrspace(3) %_arg_LocalA) {
+entry:
+ %var = alloca i32
+ %p0 = load i64, ptr %_arg_GlobalId
+ %add = getelementptr inbounds i32, ptr addrspace(1) %_arg_GlobalA, i64 %p0
+ %p2 = load i64, ptr addrspace(1) @__spirv_BuiltInGlobalInvocationId
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %add, i64 %p2
+ %var1 = addrspacecast ptr addrspace(1) %idx to ptr addrspace(4)
+ %var2 = addrspacecast ptr addrspace(3) %_arg_LocalA to ptr addrspace(4)
+ %var3 = addrspacecast ptr %var to ptr addrspace(4)
+ %G = call spir_func ptr addrspace(1) @__spirv_GenericCastToPtr_ToGlobal(ptr addrspace(4) %var1, i32 5)
+ %L = call spir_func ptr addrspace(3) @__spirv_GenericCastToPtr_ToLocal(ptr addrspace(4) %var2, i32 4)
+ %P = call spir_func ptr @__spirv_GenericCastToPtr_ToPrivate(ptr addrspace(4) %var3, i32 7)
+ ret void
+}
+
+define spir_kernel void @test4(ptr addrspace(1) %_arg_GlobalA, ptr byval(%id) %_arg_GlobalId, ptr addrspace(3) %_arg_LocalA) {
+entry:
+ %var = alloca i32
+ %p0 = load i64, ptr %_arg_GlobalId
+ %add = getelementptr inbounds i32, ptr addrspace(1) %_arg_GlobalA, i64 %p0
+ %p2 = load i64, ptr addrspace(1) @__spirv_BuiltInGlobalInvocationId
+ %idx = getelementptr inbounds i32, ptr addrspace(1) %add, i64 %p2
+ %var1 = addrspacecast ptr addrspace(1) %idx to ptr addrspace(4)
+ %var2 = addrspacecast ptr addrspace(3) %_arg_LocalA to ptr addrspace(4)
+ %var3 = addrspacecast ptr %var to ptr addrspace(4)
+ %G = call spir_func ptr addrspace(1) @to_global(ptr addrspace(4) %var1)
+ %L = call spir_func ptr addrspace(3) @to_local(ptr addrspace(4) %var2)
+ %P = call spir_func ptr @to_private(ptr addrspace(4) %var3)
+ ret void
+}
+
+declare spir_func ptr addrspace(1) @__spirv_GenericCastToPtr_ToGlobal(ptr addrspace(4), i32)
+declare spir_func ptr addrspace(3) @__spirv_GenericCastToPtr_ToLocal(ptr addrspace(4), i32)
+declare spir_func ptr @__spirv_GenericCastToPtr_ToPrivate(ptr addrspace(4), i32)
+
+declare spir_func ptr addrspace(1) @to_global(ptr addrspace(4))
+declare spir_func ptr addrspace(3) @to_local(ptr addrspace(4))
+declare spir_func ptr @to_private(ptr addrspace(4))
More information about the llvm-commits
mailing list