Skip to content

Commit 76e181e

Browse files
Recover SPIR-V opaque types from demangling function names. (#1477)
The centerpiece of this patch is the addition of getParameterTypes function, which will parse out the pointee struct types using LLVM's built-in Itanium demangling interface (which is unfortunately not easy to use). Passing this information along via llvm StructTypes was chosen to minimize the impact of this change on caller code; it is likely that a future cleanup patch to use an enum or similar mechanism to represent possible SPIR-V struct types would be advisable. A side effect of this change is that several helper methods that query pointer element types can be eliminated, which does lead to some cleanup that got tangled up in the demangler-enabling work. Extra function calls to getPointerElementType() are temporarily added to disentangle this patch from work moving OCLTypeToSPIRV to store pointee types rather than pointer types; this will likely be fixed as part of the effort to get SPIRVWriter working with opaque pointer types.
1 parent 2b32eb9 commit 76e181e

11 files changed

+304
-137
lines changed

lib/SPIRV/OCLToSPIRV.cpp

+23-14
Original file line numberDiff line numberDiff line change
@@ -1200,9 +1200,9 @@ void OCLToSPIRVBase::visitCallReadImageWithSampler(CallInst *CI,
12001200
mutateCallInstSPIRV(
12011201
M, CI,
12021202
[=](CallInst *, std::vector<Value *> &Args, Type *&Ret) {
1203-
auto ImageTy = OCLTypeToSPIRVPtr->getAdaptedType(Args[0]);
1204-
if (isOCLImageType(ImageTy))
1205-
ImageTy = getSPIRVImageTypeFromOCL(M, ImageTy);
1203+
auto *ImageTy =
1204+
OCLTypeToSPIRVPtr->getAdaptedType(Args[0])->getPointerElementType();
1205+
ImageTy = adaptSPIRVImageType(M, ImageTy);
12061206
auto SampledImgTy = getSPIRVTypeByChangeBaseTypeName(
12071207
M, ImageTy, kSPIRVTypeName::Image, kSPIRVTypeName::SampledImg);
12081208
Value *SampledImgArgs[] = {Args[0], Args[1]};
@@ -1251,7 +1251,9 @@ void OCLToSPIRVBase::visitCallGetImageSize(CallInst *CI,
12511251
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
12521252
StringRef TyName;
12531253
SmallVector<StringRef, 4> SubStrs;
1254-
auto IsImg = isOCLImageType(CI->getArgOperand(0)->getType(), &TyName);
1254+
SmallVector<StructType *, 4> ParamTys;
1255+
getParameterTypes(CI, ParamTys);
1256+
auto IsImg = isOCLImageStructType(ParamTys[0], &TyName);
12551257
(void)IsImg;
12561258
assert(IsImg);
12571259
std::string ImageTyName = getImageBaseTypeName(TyName);
@@ -1696,7 +1698,9 @@ static void processSubgroupBlockReadWriteINTEL(CallInst *CI,
16961698
// reads and vector block reads.
16971699
void OCLToSPIRVBase::visitSubgroupBlockReadINTEL(CallInst *CI) {
16981700
OCLBuiltinTransInfo Info;
1699-
if (isOCLImageType(CI->getArgOperand(0)->getType()))
1701+
SmallVector<StructType *, 2> ParamTys;
1702+
getParameterTypes(CI, ParamTys);
1703+
if (isOCLImageStructType(ParamTys[0]))
17001704
Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockReadINTEL);
17011705
else
17021706
Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockReadINTEL);
@@ -1709,7 +1713,9 @@ void OCLToSPIRVBase::visitSubgroupBlockReadINTEL(CallInst *CI) {
17091713
// instructions.
17101714
void OCLToSPIRVBase::visitSubgroupBlockWriteINTEL(CallInst *CI) {
17111715
OCLBuiltinTransInfo Info;
1712-
if (isOCLImageType(CI->getArgOperand(0)->getType()))
1716+
SmallVector<StructType *, 3> ParamTys;
1717+
getParameterTypes(CI, ParamTys);
1718+
if (isOCLImageStructType(ParamTys[0]))
17131719
Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockWriteINTEL);
17141720
else
17151721
Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockWriteINTEL);
@@ -1894,21 +1900,24 @@ void OCLToSPIRVBase::visitSubgroupAVCBuiltinCallWithSampler(
18941900
mutateCallInstSPIRV(
18951901
M, CI,
18961902
[=](CallInst *, std::vector<Value *> &Args) {
1897-
auto SamplerIt = std::find_if(Args.begin(), Args.end(), [](Value *V) {
1898-
return OCLUtil::isSamplerTy(V->getType());
1899-
});
1900-
assert(SamplerIt != Args.end() &&
1903+
SmallVector<StructType *, 4> ParamTys;
1904+
getParameterTypes(CI, ParamTys);
1905+
auto *TyIt =
1906+
std::find_if(ParamTys.begin(), ParamTys.end(), isSamplerStructTy);
1907+
assert(TyIt != ParamTys.end() &&
19011908
"Invalid Subgroup AVC Intel built-in call");
1909+
auto SamplerIt = Args.begin() + (TyIt - ParamTys.begin());
19021910
auto *SamplerVal = *SamplerIt;
19031911
Args.erase(SamplerIt);
1912+
ParamTys.erase(TyIt);
19041913

19051914
for (unsigned I = 0, E = Args.size(); I < E; ++I) {
1906-
if (!isOCLImageType(Args[I]->getType()))
1915+
if (!isOCLImageStructType(ParamTys[I]))
19071916
continue;
19081917

1909-
auto *ImageTy = OCLTypeToSPIRVPtr->getAdaptedType(Args[I]);
1910-
if (isOCLImageType(ImageTy))
1911-
ImageTy = getSPIRVImageTypeFromOCL(M, ImageTy);
1918+
auto *ImageTy = OCLTypeToSPIRVPtr->getAdaptedType(Args[I])
1919+
->getPointerElementType();
1920+
ImageTy = adaptSPIRVImageType(M, ImageTy);
19121921
auto *SampledImgTy = getSPIRVTypeByChangeBaseTypeName(
19131922
M, ImageTy, kSPIRVTypeName::Image, kSPIRVTypeName::VmeImageINTEL);
19141923

lib/SPIRV/OCLTypeToSPIRV.cpp

+8-10
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ void OCLTypeToSPIRVBase::adaptArgumentsBySamplerUse(Module &M) {
204204
AdaptedTy.count(SamplerArg) != 0) // Already traced this, move on.
205205
continue;
206206

207-
if (isSPIRVType(SamplerArg->getType(), kSPIRVTypeName::Sampler))
207+
if (SamplerArg->getType()->isPointerTy() &&
208+
isSPIRVStructType(SamplerArg->getType()->getPointerElementType(),
209+
kSPIRVTypeName::Sampler))
208210
return;
209211

210212
addAdaptedType(SamplerArg, getSamplerType(&M));
@@ -263,19 +265,15 @@ void OCLTypeToSPIRVBase::adaptArgumentsByMetadata(Function *F) {
263265
if (!TypeMD)
264266
return;
265267
bool Changed = false;
266-
auto FT = F->getFunctionType();
267-
auto PI = FT->param_begin();
268268
auto Arg = F->arg_begin();
269-
for (unsigned I = 0, E = TypeMD->getNumOperands(); I != E; ++I, ++PI, ++Arg) {
269+
for (unsigned I = 0, E = TypeMD->getNumOperands(); I != E; ++I, ++Arg) {
270270
auto OCLTyStr = getMDOperandAsString(TypeMD, I);
271-
auto NewTy = *PI;
272-
if (OCLTyStr == OCL_TYPE_NAME_SAMPLER_T && !NewTy->isStructTy()) {
271+
if (OCLTyStr == OCL_TYPE_NAME_SAMPLER_T) {
273272
addAdaptedType(&(*Arg), getSamplerType(M));
274273
Changed = true;
275-
} else if (isPointerToOpaqueStructType(NewTy)) {
276-
auto STName = NewTy->getPointerElementType()->getStructName();
277-
if (STName.startswith(kSPR2TypeName::ImagePrefix)) {
278-
auto Ty = STName.str();
274+
} else if (OCLTyStr.startswith("image") && OCLTyStr.endswith("_t")) {
275+
auto Ty = (Twine("opencl.") + OCLTyStr).str();
276+
if (StructType::getTypeByName(F->getContext(), Ty)) {
279277
auto AccMD = F->getMetadata(SPIR_MD_KERNEL_ARG_ACCESS_QUAL);
280278
assert(AccMD && "Invalid access qualifier metadata");
281279
auto AccStr = getMDOperandAsString(AccMD, I);

lib/SPIRV/OCLUtil.cpp

+1-6
Original file line numberDiff line numberDiff line change
@@ -1369,12 +1369,7 @@ bool isSpecialTypeInitializer(Instruction *Inst) {
13691369
return isSamplerInitializer(Inst) || isPipeStorageInitializer(Inst);
13701370
}
13711371

1372-
bool isSamplerTy(Type *Ty) {
1373-
auto PTy = dyn_cast<PointerType>(Ty);
1374-
if (!PTy)
1375-
return false;
1376-
1377-
auto *STy = dyn_cast<StructType>(PTy->getPointerElementType());
1372+
bool isSamplerStructTy(StructType *STy) {
13781373
return STy && STy->hasName() && STy->getName() == kSPR2TypeName::Sampler;
13791374
}
13801375

lib/SPIRV/OCLUtil.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ bool isEnqueueKernelBI(const StringRef MangledName);
510510
bool isKernelQueryBI(const StringRef MangledName);
511511

512512
/// Check that the type is the sampler_t
513-
bool isSamplerTy(Type *Ty);
513+
bool isSamplerStructTy(StructType *Ty);
514514

515515
// Checks if the binary operator is an unfused fmul + fadd instruction.
516516
bool isUnfusedMulAdd(BinaryOperator *B);

lib/SPIRV/PreprocessMetadata.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ void PreprocessMetadataBase::visit(Module *M) {
272272
// !ip_interface !N
273273
// !N = !{!"streaming", !"stall_free_return"}
274274
for (size_t I = 0; I != Interface->getNumOperands(); ++I)
275-
InterfaceStrSet.insert(getMDOperandAsString(Interface, I));
275+
InterfaceStrSet.insert(getMDOperandAsString(Interface, I).str());
276276
if (InterfaceStrSet.find("streaming") != InterfaceStrSet.end()) {
277277
int32_t InterfaceMode = 0;
278278
if (InterfaceStrSet.find("stall_free_return") != InterfaceStrSet.end())

lib/SPIRV/SPIRVInternal.h

+16-8
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ SPIRVValue *addDecorations(SPIRVValue *Target,
608608

609609
PointerType *getOrCreateOpaquePtrType(Module *M, const std::string &Name,
610610
unsigned AddrSpace = SPIRAS_Global);
611+
StructType *getOrCreateOpaqueStructType(Module *M, StringRef Name);
611612
PointerType *getSamplerType(Module *M);
612613
PointerType *getPipeStorageType(Module *M);
613614
PointerType *getSPIRVOpaquePtrType(Module *M, Op OC);
@@ -650,17 +651,15 @@ Decoration getArgAsDecoration(CallInst *CI, unsigned I);
650651
bool isPointerToOpaqueStructType(llvm::Type *Ty);
651652
bool isPointerToOpaqueStructType(llvm::Type *Ty, const std::string &Name);
652653

653-
/// Check if a type is SPIRV sampler type.
654-
bool isSPIRVSamplerType(llvm::Type *Ty);
655-
656-
/// Check if a type is OCL image type.
654+
/// Check if a type is OCL image type (if pointed to).
657655
/// \return type name without "opencl." prefix.
658-
bool isOCLImageType(llvm::Type *Ty, StringRef *Name = nullptr);
656+
bool isOCLImageStructType(llvm::Type *Ty, StringRef *Name = nullptr);
659657

660658
/// \param BaseTyName is the type name as in spirv.BaseTyName.Postfixes
661659
/// \param Postfix contains postfixes extracted from the SPIR-V image
662660
/// type name as spirv.BaseTyName.Postfixes.
663-
bool isSPIRVType(llvm::Type *Ty, StringRef BaseTyName, StringRef *Postfix = 0);
661+
bool isSPIRVStructType(llvm::Type *Ty, StringRef BaseTyName,
662+
StringRef *Postfix = 0);
664663

665664
bool isSYCLHalfType(llvm::Type *Ty);
666665

@@ -856,7 +855,7 @@ ConstantInt *getSizet(Module *M, uint64_t Value);
856855
int64_t getMDOperandAsInt(MDNode *N, unsigned I);
857856

858857
/// Get metadata operand as string.
859-
std::string getMDOperandAsString(MDNode *N, unsigned I);
858+
StringRef getMDOperandAsString(MDNode *N, unsigned I);
860859

861860
/// Get metadata operand as another metadata node
862861
MDNode *getMDOperandAsMDNode(MDNode *N, unsigned I);
@@ -935,7 +934,7 @@ std::string getSPIRVImageSampledTypeName(SPIRVType *Ty);
935934

936935
/// Translates OpenCL image type names to SPIR-V.
937936
/// E.g. %opencl.image1d_rw_t -> %spirv.Image._void_0_0_0_0_0_0_2
938-
Type *getSPIRVImageTypeFromOCL(Module *M, Type *T);
937+
Type *adaptSPIRVImageType(Module *M, Type *PointeeType);
939938

940939
/// Get LLVM type for sampled type of SPIR-V image type by postfix.
941940
Type *getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix,
@@ -998,6 +997,15 @@ bool containsUnsignedAtomicType(StringRef Name);
998997
std::string mangleBuiltin(StringRef UniqName, ArrayRef<Type *> ArgTypes,
999998
BuiltinFuncMangleInfo *BtnInfo);
1000999

1000+
/// Extract the pointee types of arguments from a mangled function name. If the
1001+
/// corresponding type is not a pointer to a struct type, its value will be a
1002+
/// nullptr instead.
1003+
void getParameterTypes(Function *F, SmallVectorImpl<StructType *> &ArgTys);
1004+
inline void getParameterTypes(CallInst *CI,
1005+
SmallVectorImpl<StructType *> &ArgTys) {
1006+
return getParameterTypes(CI->getCalledFunction(), ArgTys);
1007+
}
1008+
10011009
/// Mangle a function from OpenCL extended instruction set in SPIR-V friendly IR
10021010
/// manner
10031011
std::string getSPIRVFriendlyIRFunctionName(OCLExtOpKind ExtOpId,

lib/SPIRV/SPIRVReader.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1492,13 +1492,14 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
14921492

14931493
case OpVariable: {
14941494
auto BVar = static_cast<SPIRVVariable *>(BV);
1495-
auto Ty = transType(BVar->getType()->getPointerElementType());
1495+
auto *PreTransTy = BVar->getType()->getPointerElementType();
1496+
auto *Ty = transType(PreTransTy);
14961497
bool IsConst = BVar->isConstant();
14971498
llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar);
14981499
SPIRVStorageClassKind BS = BVar->getStorageClass();
14991500
SPIRVValue *Init = BVar->getInitializer();
15001501

1501-
if (isSPIRVSamplerType(Ty) && BS == StorageClassUniformConstant) {
1502+
if (PreTransTy->isTypeSampler() && BS == StorageClassUniformConstant) {
15021503
// Skip generating llvm code during translation of a variable definition,
15031504
// generate code only for its uses
15041505
if (!BB)

lib/SPIRV/SPIRVToOCL.cpp

+54-27
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,12 @@ void SPIRVToOCLBase::visitCastInst(CastInst &Cast) {
250250
}
251251

252252
void SPIRVToOCLBase::visitCallSPRIVImageQuerySize(CallInst *CI) {
253-
Function *Func = CI->getCalledFunction();
254253
// Get image type
255-
Type *ArgTy = Func->getFunctionType()->getParamType(0);
256-
assert(ArgTy->isPointerTy() &&
257-
"argument must be a pointer to opaque structure");
258-
StructType *ImgTy = cast<StructType>(ArgTy->getPointerElementType());
259-
assert(ImgTy->isOpaque() && "image type must be an opaque structure");
254+
SmallVector<StructType *, 4> ParamTys;
255+
getParameterTypes(CI, ParamTys);
256+
StructType *ImgTy = ParamTys[0];
257+
assert(ImgTy && ImgTy->isOpaque() &&
258+
"image type must be an opaque structure");
260259
StringRef ImgTyName = ImgTy->getName();
261260
assert(ImgTyName.startswith("opencl.image") && "not an OCL image type");
262261

@@ -755,18 +754,20 @@ void SPIRVToOCLBase::visitCallSPIRVImageSampleExplicitLodBuiltIn(CallInst *CI,
755754
Op OC) {
756755
assert(CI->getCalledFunction() && "Unexpected indirect call");
757756
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
757+
CallInst *CallSampledImg = cast<CallInst>(CI->getArgOperand(0));
758+
SmallVector<StructType *, 6> ParamTys;
759+
getParameterTypes(CallSampledImg, ParamTys);
758760
StringRef ImageTypeName;
759761
bool IsDepthImage = false;
760-
if (isOCLImageType(
761-
(cast<CallInst>(CI->getOperand(0)))->getArgOperand(0)->getType(),
762-
&ImageTypeName))
762+
if (isOCLImageStructType(ParamTys[0], &ImageTypeName))
763763
IsDepthImage = ImageTypeName.contains("_depth_");
764764

765765
auto ModifyArguments = [=](CallInst *, std::vector<Value *> &Args,
766766
llvm::Type *&RetTy) {
767-
CallInst *CallSampledImg = cast<CallInst>(Args[0]);
768767
auto Img = CallSampledImg->getArgOperand(0);
769-
assert(isOCLImageType(Img->getType()));
768+
if (!Img->getType()->isOpaquePointerTy())
769+
assert(isOCLImageStructType(
770+
Img->getType()->getNonOpaquePointerElementType()));
770771
auto Sampler = CallSampledImg->getArgOperand(1);
771772
Args[0] = Img;
772773
Args.insert(Args.begin() + 1, Sampler);
@@ -1247,27 +1248,53 @@ void SPIRVToOCLBase::translateOpaqueTypes() {
12471248
if (!IsSPIRVOpaque)
12481249
continue;
12491250

1250-
SmallVector<std::string, 8> Postfixes;
1251-
std::string DecodedST = decodeSPIRVTypeName(STName, Postfixes);
1251+
S->setName(translateOpaqueType(STName));
1252+
}
1253+
}
1254+
1255+
std::string SPIRVToOCLBase::translateOpaqueType(StringRef STName) {
1256+
if (!STName.startswith(kSPIRVTypeName::PrefixAndDelim))
1257+
return STName.str();
1258+
1259+
SmallVector<std::string, 8> Postfixes;
1260+
std::string DecodedST = decodeSPIRVTypeName(STName, Postfixes);
1261+
1262+
if (!SPIRVOpaqueTypeOpCodeMap::find(DecodedST))
1263+
return STName.str();
1264+
1265+
Op OP = SPIRVOpaqueTypeOpCodeMap::map(DecodedST);
1266+
std::string OCLOpaqueName;
1267+
if (OP == OpTypeImage)
1268+
OCLOpaqueName = getOCLImageOpaqueType(Postfixes);
1269+
else if (OP == OpTypePipe)
1270+
OCLOpaqueName = getOCLPipeOpaqueType(Postfixes);
1271+
else if (isSubgroupAvcINTELTypeOpCode(OP))
1272+
OCLOpaqueName = OCLSubgroupINTELTypeOpCodeMap::rmap(OP);
1273+
else if (isOpaqueGenericTypeOpCode(OP))
1274+
OCLOpaqueName = OCLOpaqueTypeOpCodeMap::rmap(OP);
1275+
else
1276+
return STName.str();
1277+
1278+
return OCLOpaqueName;
1279+
}
12521280

1253-
if (!SPIRVOpaqueTypeOpCodeMap::find(DecodedST))
1281+
void SPIRVToOCLBase::getParameterTypes(CallInst *CI,
1282+
SmallVectorImpl<StructType *> &Tys) {
1283+
::getParameterTypes(CI, Tys);
1284+
for (auto &Ty : Tys) {
1285+
if (!Ty)
12541286
continue;
1287+
StringRef STName = Ty->getStructName();
1288+
bool IsSPIRVOpaque =
1289+
Ty->isOpaque() && STName.startswith(kSPIRVTypeName::PrefixAndDelim);
12551290

1256-
Op OP = SPIRVOpaqueTypeOpCodeMap::map(DecodedST);
1257-
std::string OCLOpaqueName;
1258-
if (OP == OpTypeImage)
1259-
OCLOpaqueName = getOCLImageOpaqueType(Postfixes);
1260-
else if (OP == OpTypePipe)
1261-
OCLOpaqueName = getOCLPipeOpaqueType(Postfixes);
1262-
else if (isSubgroupAvcINTELTypeOpCode(OP))
1263-
OCLOpaqueName = OCLSubgroupINTELTypeOpCodeMap::rmap(OP);
1264-
else if (isOpaqueGenericTypeOpCode(OP))
1265-
OCLOpaqueName = OCLOpaqueTypeOpCodeMap::rmap(OP);
1266-
else
1291+
if (!IsSPIRVOpaque)
12671292
continue;
12681293

1269-
S->setName(OCLOpaqueName);
1270-
}
1294+
std::string NewName = translateOpaqueType(STName);
1295+
if (NewName != STName)
1296+
Ty = getOrCreateOpaqueStructType(M, NewName);
1297+
};
12711298
}
12721299

12731300
void addSPIRVBIsLoweringPass(ModulePassManager &PassMgr,

lib/SPIRV/SPIRVToOCL.h

+3
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,10 @@ class SPIRVToOCLBase : public InstVisitor<SPIRVToOCLBase> {
262262
/// example: spirv.Pipe._0 => opencl.pipe_ro_t
263263
std::string getOCLPipeOpaqueType(SmallVector<std::string, 8> &Postfixes);
264264

265+
void getParameterTypes(CallInst *CI, SmallVectorImpl<StructType *> &Tys);
266+
265267
void translateOpaqueTypes();
268+
std::string translateOpaqueType(StringRef STName);
266269

267270
Module *M;
268271
LLVMContext *Ctx;

0 commit comments

Comments
 (0)