Skip to content

Commit 0aab124

Browse files
authored
[SPV-IR -> SPIRV] Fix image builtin unsigned type not preserved (#2286)
This PR preserves unsigned return type of image read and unsigned texel type of image write builtins as ZeroExtend image operand in SPIRV.
1 parent 9edf714 commit 0aab124

File tree

4 files changed

+337
-0
lines changed

4 files changed

+337
-0
lines changed

lib/SPIRV/SPIRVInternal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,13 @@ inline bool getParameterTypes(CallInst *CI, SmallVectorImpl<Type *> &ArgTys) {
877877
return getParameterTypes(CI->getCalledFunction(), ArgTys);
878878
}
879879

880+
enum class ParamSignedness { Signed = 0, Unsigned, Unknown };
881+
882+
/// Extract signedness of return type and parameter types from a mangled
883+
/// function name.
884+
bool getRetParamSignedness(Function *F, ParamSignedness &RetSignedness,
885+
SmallVectorImpl<ParamSignedness> &ArgSignedness);
886+
880887
/// Mangle a function from OpenCL extended instruction set in SPIR-V friendly IR
881888
/// manner
882889
std::string getSPIRVFriendlyIRFunctionName(OCLExtOpKind ExtOpId,

lib/SPIRV/SPIRVUtil.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,46 @@ bool getParameterTypes(Function *F, SmallVectorImpl<Type *> &ArgTys,
869869
return DemangledSuccessfully;
870870
}
871871

872+
bool getRetParamSignedness(Function *F, ParamSignedness &RetSignedness,
873+
SmallVectorImpl<ParamSignedness> &ArgSignedness) {
874+
using namespace llvm::itanium_demangle;
875+
StringRef Name = F->getName();
876+
if (!Name.starts_with("_Z") || F->arg_empty())
877+
return false;
878+
879+
ManglingParser<DefaultAllocator> Demangler(Name.begin(), Name.end());
880+
// If it's not a function name encoding, bail out.
881+
auto *RootNode = dyn_cast_or_null<FunctionEncoding>(Demangler.parse());
882+
if (!RootNode)
883+
return false;
884+
885+
auto GetSignedness = [](const itanium_demangle::Node *N) {
886+
if (!N)
887+
return ParamSignedness::Unknown;
888+
if (const auto *Vec = dyn_cast<itanium_demangle::VectorType>(N))
889+
N = Vec->getBaseType();
890+
if (const auto *Name = dyn_cast<NameType>(N)) {
891+
StringRef Arg(stringify(Name));
892+
if (Arg.starts_with("unsigned"))
893+
return ParamSignedness::Unsigned;
894+
if (Arg.equals("char") || Arg.equals("short") || Arg.equals("int") ||
895+
Arg.equals("long"))
896+
return ParamSignedness::Signed;
897+
}
898+
return ParamSignedness::Unknown;
899+
};
900+
RetSignedness = GetSignedness(RootNode->getReturnType());
901+
ArgSignedness.resize(F->arg_size());
902+
for (const auto &[I, ParamType] : llvm::enumerate(RootNode->getParams())) {
903+
if (F->getArg(I)->getType()->isIntOrIntVectorTy())
904+
ArgSignedness[I] = GetSignedness(ParamType);
905+
else
906+
ArgSignedness[I] = ParamSignedness::Unknown;
907+
}
908+
909+
return true;
910+
}
911+
872912
CallInst *mutateCallInst(
873913
Module *M, CallInst *CI,
874914
std::function<std::string(CallInst *, std::vector<Value *> &)> ArgMutate,

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,45 @@ static SPIRVWord convertFloatToSPIRVWord(float F) {
117117
return FPMaxError.Spir;
118118
}
119119

120+
/// Return one of the SPIR-V 1.4 SignExtend or ZeroExtend image operands
121+
/// for a function name, or 0 if the function does not return or
122+
/// write an integer type.
123+
int getImageSignZeroExt(Function *F) {
124+
bool IsSigned = false;
125+
bool IsUnsigned = false;
126+
127+
ParamSignedness RetSignedness;
128+
SmallVector<ParamSignedness, 4> ArgSignedness;
129+
if (!getRetParamSignedness(F, RetSignedness, ArgSignedness))
130+
return 0;
131+
132+
StringRef Name = F->getName();
133+
Name = Name.substr(Name.find(kSPIRVName::Prefix));
134+
Name.consume_front(kSPIRVName::Prefix);
135+
if (Name.consume_front("ImageRead") ||
136+
Name.consume_front("ImageSampleExplicitLod")) {
137+
if (RetSignedness == ParamSignedness::Signed)
138+
IsSigned = true;
139+
else if (RetSignedness == ParamSignedness::Unsigned)
140+
IsUnsigned = true;
141+
else if (F->getReturnType()->isIntOrIntVectorTy() &&
142+
Name.consume_front("_R")) {
143+
// Return type is mangled after _R, e.g. _Z23__spirv_ImageRead_Rint2li
144+
IsSigned = isMangledTypeSigned(Name[0]);
145+
IsUnsigned = Name.starts_with("u");
146+
}
147+
} else if (Name.starts_with("ImageWrite")) {
148+
IsSigned = (ArgSignedness[2] == ParamSignedness::Signed);
149+
IsUnsigned = (ArgSignedness[2] == ParamSignedness::Unsigned);
150+
}
151+
152+
if (IsSigned)
153+
return ImageOperandsMask::ImageOperandsSignExtendMask;
154+
if (IsUnsigned)
155+
return ImageOperandsMask::ImageOperandsZeroExtendMask;
156+
return 0;
157+
}
158+
120159
} // namespace
121160

122161
namespace SPIRV {
@@ -5948,6 +5987,47 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI,
59485987
transValue(Image, BB),
59495988
transValue(Sampler, BB), BB);
59505989
}
5990+
case OpImageRead:
5991+
case OpImageSampleExplicitLod:
5992+
case OpImageWrite: {
5993+
// Image Op needs handling of SignExtend or ZeroExtend image operands.
5994+
auto Args = getArguments(CI);
5995+
SPIRVType *SPRetTy =
5996+
CI->getType()->isVoidTy() ? nullptr : transScavengedType(CI);
5997+
auto *SPI = SPIRVInstTemplateBase::create(OC);
5998+
std::vector<SPIRVWord> SPArgs;
5999+
for (size_t I = 0, E = Args.size(); I != E; ++I) {
6000+
if (Args[I]->getType()->isPointerTy()) {
6001+
[[maybe_unused]] Value *Pointee = Args[I]->stripPointerCasts();
6002+
assert((Pointee == Args[I] || !isa<Function>(Pointee)) &&
6003+
"Illegal use of a function pointer type");
6004+
}
6005+
SPArgs.push_back(SPI->isOperandLiteral(I)
6006+
? cast<ConstantInt>(Args[I])->getZExtValue()
6007+
: transValue(Args[I], BB)->getId());
6008+
}
6009+
if (BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_4)) {
6010+
size_t ImOpIdx = getImageOperandsIndex(OC);
6011+
if (Args.size() > ImOpIdx) {
6012+
// Update existing ImageOperands with SignExtendMask/ZeroExtendMask.
6013+
if (auto *ImOp = dyn_cast<ConstantInt>(Args[ImOpIdx])) {
6014+
uint64_t ImOpVal = ImOp->getZExtValue();
6015+
unsigned SignZeroExtMasks =
6016+
ImageOperandsMask::ImageOperandsSignExtendMask |
6017+
ImageOperandsMask::ImageOperandsZeroExtendMask;
6018+
if (!(ImOpVal & SignZeroExtMasks))
6019+
if (int SignZeroExt = getImageSignZeroExt(CI->getCalledFunction()))
6020+
SPArgs[ImOpIdx] = ImOpVal | SignZeroExt;
6021+
}
6022+
} else {
6023+
// Add new ImageOperands argument.
6024+
if (int SignZeroExt = getImageSignZeroExt(CI->getCalledFunction()))
6025+
SPArgs.push_back(SignZeroExt);
6026+
}
6027+
}
6028+
BM->addInstTemplate(SPI, SPArgs, BB, SPRetTy);
6029+
return SPI;
6030+
}
59516031
case OpFixedSqrtINTEL:
59526032
case OpFixedRecipINTEL:
59536033
case OpFixedRsqrtINTEL:

0 commit comments

Comments
 (0)