Skip to content

Commit fd5820b

Browse files
wenju-hesys-ce-bb
authored andcommitted
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. Original commit: KhronosGroup/SPIRV-LLVM-Translator@0aab124
1 parent 8cae952 commit fd5820b

File tree

4 files changed

+337
-0
lines changed

4 files changed

+337
-0
lines changed

llvm-spirv/lib/SPIRV/SPIRVInternal.h

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

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

llvm-spirv/lib/SPIRV/SPIRVUtil.cpp

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

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

llvm-spirv/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 {
@@ -6009,6 +6048,47 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI,
60096048
transValue(Image, BB),
60106049
transValue(Sampler, BB), BB);
60116050
}
6051+
case OpImageRead:
6052+
case OpImageSampleExplicitLod:
6053+
case OpImageWrite: {
6054+
// Image Op needs handling of SignExtend or ZeroExtend image operands.
6055+
auto Args = getArguments(CI);
6056+
SPIRVType *SPRetTy =
6057+
CI->getType()->isVoidTy() ? nullptr : transScavengedType(CI);
6058+
auto *SPI = SPIRVInstTemplateBase::create(OC);
6059+
std::vector<SPIRVWord> SPArgs;
6060+
for (size_t I = 0, E = Args.size(); I != E; ++I) {
6061+
if (Args[I]->getType()->isPointerTy()) {
6062+
[[maybe_unused]] Value *Pointee = Args[I]->stripPointerCasts();
6063+
assert((Pointee == Args[I] || !isa<Function>(Pointee)) &&
6064+
"Illegal use of a function pointer type");
6065+
}
6066+
SPArgs.push_back(SPI->isOperandLiteral(I)
6067+
? cast<ConstantInt>(Args[I])->getZExtValue()
6068+
: transValue(Args[I], BB)->getId());
6069+
}
6070+
if (BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_4)) {
6071+
size_t ImOpIdx = getImageOperandsIndex(OC);
6072+
if (Args.size() > ImOpIdx) {
6073+
// Update existing ImageOperands with SignExtendMask/ZeroExtendMask.
6074+
if (auto *ImOp = dyn_cast<ConstantInt>(Args[ImOpIdx])) {
6075+
uint64_t ImOpVal = ImOp->getZExtValue();
6076+
unsigned SignZeroExtMasks =
6077+
ImageOperandsMask::ImageOperandsSignExtendMask |
6078+
ImageOperandsMask::ImageOperandsZeroExtendMask;
6079+
if (!(ImOpVal & SignZeroExtMasks))
6080+
if (int SignZeroExt = getImageSignZeroExt(CI->getCalledFunction()))
6081+
SPArgs[ImOpIdx] = ImOpVal | SignZeroExt;
6082+
}
6083+
} else {
6084+
// Add new ImageOperands argument.
6085+
if (int SignZeroExt = getImageSignZeroExt(CI->getCalledFunction()))
6086+
SPArgs.push_back(SignZeroExt);
6087+
}
6088+
}
6089+
BM->addInstTemplate(SPI, SPArgs, BB, SPRetTy);
6090+
return SPI;
6091+
}
60126092
case OpFixedSqrtINTEL:
60136093
case OpFixedRecipINTEL:
60146094
case OpFixedRsqrtINTEL:

0 commit comments

Comments
 (0)