Skip to content

Commit 2f9d8d6

Browse files
vmaksimojsji
authored andcommitted
SPV_KHR_untyped_pointers - implement OpUntypedVariableKHR (#2709)
This continues #2687 by introducing untyped variables. Spec: https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_untyped_pointers.html Original commit: KhronosGroup/SPIRV-LLVM-Translator@484e4070adb0a95
1 parent 7523238 commit 2f9d8d6

File tree

15 files changed

+336
-81
lines changed

15 files changed

+336
-81
lines changed

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,9 +1529,15 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
15291529
case OpUndef:
15301530
return mapValue(BV, UndefValue::get(transType(BV->getType())));
15311531

1532-
case OpVariable: {
1533-
auto *BVar = static_cast<SPIRVVariable *>(BV);
1534-
auto *PreTransTy = BVar->getType()->getPointerElementType();
1532+
case OpVariable:
1533+
case OpUntypedVariableKHR: {
1534+
auto *BVar = static_cast<SPIRVVariableBase *>(BV);
1535+
SPIRVType *PreTransTy = BVar->getType()->getPointerElementType();
1536+
if (BVar->getType()->isTypeUntypedPointerKHR()) {
1537+
auto *UntypedVar = static_cast<SPIRVUntypedVariableKHR *>(BVar);
1538+
if (SPIRVType *DT = UntypedVar->getDataType())
1539+
PreTransTy = DT;
1540+
}
15351541
auto *Ty = transType(PreTransTy);
15361542
bool IsConst = BVar->isConstant();
15371543
llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar);
@@ -4062,7 +4068,7 @@ bool SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) {
40624068
return true;
40634069
}
40644070

4065-
void SPIRVToLLVM::transGlobalCtorDtors(SPIRVVariable *BV) {
4071+
void SPIRVToLLVM::transGlobalCtorDtors(SPIRVVariableBase *BV) {
40664072
if (BV->getName() != "llvm.global_ctors" &&
40674073
BV->getName() != "llvm.global_dtors")
40684074
return;
@@ -4907,15 +4913,17 @@ SPIRVToLLVM::transLinkageType(const SPIRVValue *V) {
49074913
return GlobalValue::ExternalLinkage;
49084914
}
49094915
// Variable declaration
4910-
if (V->getOpCode() == OpVariable) {
4911-
if (static_cast<const SPIRVVariable *>(V)->getInitializer() == 0)
4916+
if (V->getOpCode() == OpVariable ||
4917+
V->getOpCode() == OpUntypedVariableKHR) {
4918+
if (static_cast<const SPIRVVariableBase *>(V)->getInitializer() == 0)
49124919
return GlobalValue::ExternalLinkage;
49134920
}
49144921
// Definition
49154922
return GlobalValue::AvailableExternallyLinkage;
49164923
case LinkageTypeExport:
4917-
if (V->getOpCode() == OpVariable) {
4918-
if (static_cast<const SPIRVVariable *>(V)->getInitializer() == 0)
4924+
if (V->getOpCode() == OpVariable ||
4925+
V->getOpCode() == OpUntypedVariableKHR) {
4926+
if (static_cast<const SPIRVVariableBase *>(V)->getInitializer() == 0)
49194927
// Tentative definition
49204928
return GlobalValue::CommonLinkage;
49214929
}

llvm-spirv/lib/SPIRV/SPIRVReader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ class SPIRVToLLVM : private BuiltinCallHelper {
251251

252252
void transUserSemantic(SPIRV::SPIRVFunction *Fun);
253253
void transGlobalAnnotations();
254-
void transGlobalCtorDtors(SPIRVVariable *BV);
254+
void transGlobalCtorDtors(SPIRVVariableBase *BV);
255255
void createCXXStructor(const char *ListName,
256256
SmallVectorImpl<Function *> &Funcs);
257257
void transIntelFPGADecorations(SPIRVValue *BV, Value *V);

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,8 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(SPIRVType *ET, unsigned AddrSpc) {
755755

756756
SPIRVType *TranslatedTy = nullptr;
757757
if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) &&
758-
!(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeImage() ||
759-
ET->isTypeSampler() || ET->isTypePipe())) {
758+
!(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeStruct() ||
759+
ET->isTypeImage() || ET->isTypeSampler() || ET->isTypePipe())) {
760760
TranslatedTy = BM->addUntypedPointerKHRType(
761761
SPIRSPIRVAddrSpaceMap::map(static_cast<SPIRAddressSpace>(AddrSpc)));
762762
} else {
@@ -1317,7 +1317,8 @@ SPIRVValue *LLVMToSPIRVBase::transConstantUse(Constant *C,
13171317
if (Trans->getType() == ExpectedType || Trans->getType()->isTypePipeStorage())
13181318
return Trans;
13191319

1320-
assert(C->getType()->isPointerTy() &&
1320+
assert((C->getType()->isPointerTy() ||
1321+
ExpectedType->isTypeUntypedPointerKHR()) &&
13211322
"Only pointer type mismatches should be possible");
13221323
// In the common case of strings ([N x i8] GVs), see if we can emit a GEP
13231324
// instruction.
@@ -2055,8 +2056,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
20552056
}
20562057
}
20572058
}
2058-
SPIRVType *TransTy = transType(Ty);
2059-
BVarInit = transConstantUse(Init, TransTy->getPointerElementType());
2059+
if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers)) {
2060+
BVarInit = transConstantUse(Init, transType(Init->getType()));
2061+
} else {
2062+
SPIRVType *TransTy = transType(Ty);
2063+
BVarInit = transConstantUse(Init, TransTy->getPointerElementType());
2064+
}
20602065
}
20612066

20622067
SPIRVStorageClassKind StorageClass;
@@ -2089,9 +2094,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
20892094
}
20902095

20912096
SPIRVType *TranslatedTy = transType(Ty);
2092-
auto *BVar = static_cast<SPIRVVariable *>(
2093-
BM->addVariable(TranslatedTy, GV->isConstant(), transLinkageType(GV),
2094-
BVarInit, GV->getName().str(), StorageClass, nullptr));
2097+
auto *BVar = static_cast<SPIRVVariableBase *>(BM->addVariable(
2098+
TranslatedTy,
2099+
TranslatedTy->isTypeUntypedPointerKHR() ? transType(GV->getValueType())
2100+
: nullptr,
2101+
GV->isConstant(), transLinkageType(GV), BVarInit, GV->getName().str(),
2102+
StorageClass, nullptr));
20952103

20962104
if (IsVectorCompute) {
20972105
BVar->addDecorate(DecorationVectorComputeVariableINTEL);
@@ -2280,8 +2288,9 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
22802288
StorageClassFunction,
22812289
BM->addArrayType(transType(Alc->getAllocatedType()), Length));
22822290
SPIRVValue *Arr = BM->addVariable(
2283-
AllocationType, false, spv::internal::LinkageTypeInternal, nullptr,
2284-
Alc->getName().str() + "_alloca", StorageClassFunction, BB);
2291+
AllocationType, nullptr, false, spv::internal::LinkageTypeInternal,
2292+
nullptr, Alc->getName().str() + "_alloca", StorageClassFunction,
2293+
BB);
22852294
// Manually set alignment. OpBitcast created below will be decorated as
22862295
// that's the SPIR-V value mapped to the original LLVM one.
22872296
transAlign(Alc, Arr);
@@ -2305,7 +2314,10 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
23052314
TranslatedTy->getPointerElementType())
23062315
: TranslatedTy;
23072316
SPIRVValue *Var = BM->addVariable(
2308-
VarTy, false, spv::internal::LinkageTypeInternal, nullptr,
2317+
VarTy,
2318+
VarTy->isTypeUntypedPointerKHR() ? transType(Alc->getAllocatedType())
2319+
: nullptr,
2320+
false, spv::internal::LinkageTypeInternal, nullptr,
23092321
Alc->getName().str(), StorageClassFunction, BB);
23102322
if (V->getType()->getPointerAddressSpace() == SPIRAS_Generic) {
23112323
SPIRVValue *Cast =
@@ -2750,7 +2762,7 @@ void checkIsGlobalVar(SPIRVEntry *E, Decoration Dec) {
27502762
E->getErrorLog().checkError(E->isVariable(), SPIRVEC_InvalidModule, ErrStr);
27512763

27522764
auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap(
2753-
static_cast<SPIRVVariable *>(E)->getStorageClass());
2765+
static_cast<SPIRVVariableBase *>(E)->getStorageClass());
27542766
ErrStr += " in a global (module) scope";
27552767
E->getErrorLog().checkError(AddrSpace == SPIRAS_Global, SPIRVEC_InvalidModule,
27562768
ErrStr);
@@ -2898,10 +2910,11 @@ static void transMetadataDecorations(Metadata *MD, SPIRVValue *Target) {
28982910
case spv::internal::DecorationInitModeINTEL:
28992911
case DecorationInitModeINTEL: {
29002912
checkIsGlobalVar(Target, DecoKind);
2901-
ErrLog.checkError(static_cast<SPIRVVariable *>(Target)->getInitializer(),
2902-
SPIRVEC_InvalidLlvmModule,
2903-
"InitModeINTEL only be applied to a global (module "
2904-
"scope) variable which has an Initializer operand");
2913+
ErrLog.checkError(
2914+
static_cast<SPIRVVariableBase *>(Target)->getInitializer(),
2915+
SPIRVEC_InvalidLlvmModule,
2916+
"InitModeINTEL only be applied to a global (module "
2917+
"scope) variable which has an Initializer operand");
29052918

29062919
ErrLog.checkError(NumOperands == 2, SPIRVEC_InvalidLlvmModule,
29072920
"InitModeINTEL requires exactly 1 extra operand");
@@ -4143,14 +4156,18 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
41434156
SPIRVType *FTy = transType(II->getType()->getStructElementType(0));
41444157
SPIRVTypePointer *ITy = static_cast<SPIRVTypePointer *>(transPointerType(
41454158
II->getType()->getStructElementType(1), SPIRAS_Private));
4146-
4147-
unsigned BitWidth = ITy->getElementType()->getBitWidth();
4148-
BM->getErrorLog().checkError(BitWidth == 32, SPIRVEC_InvalidBitWidth,
4149-
std::to_string(BitWidth));
4150-
4159+
if (!ITy->isTypeUntypedPointerKHR()) {
4160+
unsigned BitWidth = ITy->getElementType()->getBitWidth();
4161+
BM->getErrorLog().checkError(BitWidth == 32, SPIRVEC_InvalidBitWidth,
4162+
std::to_string(BitWidth));
4163+
}
41514164
SPIRVValue *IntVal =
4152-
BM->addVariable(ITy, false, spv::internal::LinkageTypeInternal, nullptr,
4153-
"", ITy->getStorageClass(), BB);
4165+
BM->addVariable(ITy,
4166+
ITy->isTypeUntypedPointerKHR()
4167+
? transType(II->getType()->getStructElementType(1))
4168+
: nullptr,
4169+
false, spv::internal::LinkageTypeInternal, nullptr, "",
4170+
ITy->getStorageClass(), BB);
41544171

41554172
std::vector<SPIRVValue *> Ops{transValue(II->getArgOperand(0), BB), IntVal};
41564173

@@ -4572,7 +4589,7 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
45724589
Init = BM->addCompositeConstant(CompositeTy, Elts);
45734590
}
45744591
SPIRVType *VarTy = transPointerType(AT, SPIRV::SPIRAS_Constant);
4575-
SPIRVValue *Var = BM->addVariable(VarTy, /*isConstant*/ true,
4592+
SPIRVValue *Var = BM->addVariable(VarTy, nullptr, /*isConstant*/ true,
45764593
spv::internal::LinkageTypeInternal, Init,
45774594
"", StorageClassUniformConstant, nullptr);
45784595
SPIRVType *SourceTy =

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ SPIRVInstruction *SPIRVBasicBlock::getVariableInsertionPoint() const {
9494
isa<OpNoLine>(Inst) ||
9595
// Note: OpVariable and OpPhi instructions do not belong to the
9696
// same block in a valid SPIR-V module.
97-
isa<OpPhi>(Inst));
97+
isa<OpPhi>(Inst) || isa<OpUntypedVariableKHR>(Inst));
9898
});
9999
if (IP == InstVec.end())
100100
return nullptr;

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ class SPIRVBasicBlock : public SPIRVValue {
7777
const SPIRVInstruction *getTerminateInstr() const {
7878
return InstVec.empty() ? nullptr : InstVec.back();
7979
}
80-
// OpVariable instructions must be the first instructions in the block,
80+
// Variables must be the first instructions in the block,
8181
// intermixed with OpLine and OpNoLine instructions. Return first instruction
82-
// not being an OpVariable, OpLine or OpNoLine.
82+
// not being an OpVariable, OpUntypedVariableKHR, OpLine or OpNoLine.
8383
SPIRVInstruction *getVariableInsertionPoint() const;
8484

8585
void setScope(SPIRVEntry *Scope) override;

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,8 @@ SPIRVEntry::getDecorationIds(Decoration Kind) const {
559559
}
560560

561561
bool SPIRVEntry::hasLinkageType() const {
562-
return OpCode == OpFunction || OpCode == OpVariable;
562+
return OpCode == OpFunction || OpCode == OpVariable ||
563+
OpCode == OpUntypedVariableKHR;
563564
}
564565

565566
bool SPIRVEntry::isExtInst(const SPIRVExtInstSetKind InstSet) const {

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ class SPIRVEntry {
339339
bool isUndef() const { return OpCode == OpUndef; }
340340
bool isControlBarrier() const { return OpCode == OpControlBarrier; }
341341
bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier; }
342-
bool isVariable() const { return OpCode == OpVariable; }
342+
bool isVariable() const {
343+
return OpCode == OpVariable || OpCode == OpUntypedVariableKHR;
344+
}
343345
bool isEndOfBlock() const;
344346
virtual bool isInst() const { return false; }
345347
virtual bool isOperandLiteral(unsigned Index) const {

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h

Lines changed: 90 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -452,24 +452,25 @@ class SPIRVMemoryAccess {
452452
SPIRVId NoAliasInstID;
453453
};
454454

455-
class SPIRVVariable : public SPIRVInstruction {
455+
class SPIRVVariableBase : public SPIRVInstruction {
456456
public:
457457
// Complete constructor for integer constant
458-
SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheInitializer,
459-
const std::string &TheName,
460-
SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB,
461-
SPIRVModule *TheM)
462-
: SPIRVInstruction(TheInitializer && !TheInitializer->isUndef() ? 5 : 4,
463-
OpVariable, TheType, TheId, TheBB, TheM),
458+
SPIRVVariableBase(Op OC, SPIRVType *TheType, SPIRVId TheId,
459+
SPIRVValue *TheInitializer, const std::string &TheName,
460+
SPIRVStorageClassKind TheStorageClass,
461+
SPIRVBasicBlock *TheBB, SPIRVModule *TheM, SPIRVWord WC)
462+
: SPIRVInstruction(WC, OC, TheType, TheId, TheBB, TheM),
464463
StorageClass(TheStorageClass) {
465464
if (TheInitializer && !TheInitializer->isUndef())
466465
Initializer.push_back(TheInitializer->getId());
467466
Name = TheName;
468467
validate();
469468
}
470-
// Incomplete constructor
471-
SPIRVVariable()
472-
: SPIRVInstruction(OpVariable), StorageClass(StorageClassFunction) {}
469+
// Incomplete constructors
470+
SPIRVVariableBase(Op OC)
471+
: SPIRVInstruction(OC), StorageClass(StorageClassFunction) {}
472+
SPIRVVariableBase()
473+
: SPIRVInstruction(OpNop), StorageClass(StorageClassFunction) {}
473474

474475
SPIRVStorageClassKind getStorageClass() const { return StorageClass; }
475476
SPIRVValue *getInitializer() const {
@@ -521,6 +522,77 @@ class SPIRVVariable : public SPIRVInstruction {
521522
std::vector<SPIRVId> Initializer;
522523
};
523524

525+
class SPIRVVariable : public SPIRVVariableBase {
526+
public:
527+
// Complete constructor for integer constant
528+
SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheInitializer,
529+
const std::string &TheName,
530+
SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB,
531+
SPIRVModule *TheM)
532+
: SPIRVVariableBase(OpVariable, TheType, TheId, TheInitializer, TheName,
533+
TheStorageClass, TheBB, TheM,
534+
TheInitializer && !TheInitializer->isUndef() ? 5
535+
: 4) {}
536+
// Incomplete constructor
537+
SPIRVVariable() : SPIRVVariableBase(OpVariable) {}
538+
};
539+
540+
class SPIRVUntypedVariableKHR : public SPIRVVariableBase {
541+
public:
542+
SPIRVUntypedVariableKHR(SPIRVType *TheType, SPIRVId TheId,
543+
SPIRVType *TheDataType, SPIRVValue *TheInitializer,
544+
const std::string &TheName,
545+
SPIRVStorageClassKind TheStorageClass,
546+
SPIRVBasicBlock *TheBB, SPIRVModule *TheM)
547+
: SPIRVVariableBase(
548+
OpUntypedVariableKHR, TheType, TheId, TheInitializer, TheName,
549+
TheStorageClass, TheBB, TheM,
550+
TheDataType && !TheDataType->isUndef()
551+
? (TheInitializer && !TheInitializer->isUndef() ? 6 : 5)
552+
: 4) {
553+
if (TheDataType && !TheDataType->isUndef())
554+
DataType.push_back(TheDataType->getId());
555+
validate();
556+
}
557+
SPIRVUntypedVariableKHR() : SPIRVVariableBase(OpUntypedVariableKHR) {}
558+
SPIRVType *getDataType() const {
559+
if (DataType.empty())
560+
return nullptr;
561+
assert(DataType.size() == 1);
562+
return get<SPIRVType>(DataType[0]);
563+
}
564+
std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
565+
std::vector<SPIRVEntry *> Vec;
566+
if (SPIRVType *T = getDataType())
567+
Vec.push_back(T);
568+
if (SPIRVValue *V = getInitializer())
569+
Vec.push_back(V);
570+
return Vec;
571+
}
572+
std::optional<ExtensionID> getRequiredExtension() const override {
573+
return ExtensionID::SPV_KHR_untyped_pointers;
574+
}
575+
SPIRVCapVec getRequiredCapability() const override {
576+
return getVec(CapabilityUntypedPointersKHR);
577+
}
578+
579+
protected:
580+
void validate() const override {
581+
SPIRVVariableBase::validate();
582+
assert(DataType.size() == 1 || DataType.empty());
583+
}
584+
void setWordCount(SPIRVWord TheWordCount) override {
585+
SPIRVEntry::setWordCount(TheWordCount);
586+
if (TheWordCount > 4)
587+
DataType.resize(1);
588+
if (TheWordCount > 5)
589+
Initializer.resize(1);
590+
}
591+
_SPIRV_DEF_ENCDEC5(Type, Id, StorageClass, DataType, Initializer)
592+
593+
std::vector<SPIRVId> DataType;
594+
};
595+
524596
class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess {
525597
public:
526598
const static SPIRVWord FixedWords = 3;
@@ -572,9 +644,6 @@ class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess {
572644
(getValueType(PtrId)
573645
->getPointerElementType()
574646
->isTypeUntypedPointerKHR() ||
575-
// TODO: This check should be removed once we support untyped
576-
// variables.
577-
getValueType(ValId)->isTypeUntypedPointerKHR() ||
578647
getValueType(PtrId)->getPointerElementType() == getValueType(ValId)) &&
579648
"Inconsistent operand types");
580649
}
@@ -629,8 +698,6 @@ class SPIRVLoad : public SPIRVInstruction, public SPIRVMemoryAccess {
629698
getValueType(PtrId)
630699
->getPointerElementType()
631700
->isTypeUntypedPointerKHR() ||
632-
// TODO: This check should be removed once we support untyped
633-
// variables.
634701
Type->isTypeUntypedPointerKHR() ||
635702
Type == getValueType(PtrId)->getPointerElementType()) &&
636703
"Inconsistent types");
@@ -688,9 +755,14 @@ class SPIRVBinary : public SPIRVInstTemplateBase {
688755
} else if (isBinaryPtrOpCode(OpCode)) {
689756
assert((Op1Ty->isTypePointer() && Op2Ty->isTypePointer()) &&
690757
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
691-
assert(static_cast<SPIRVTypePointer *>(Op1Ty)->getElementType() ==
692-
static_cast<SPIRVTypePointer *>(Op2Ty)->getElementType() &&
693-
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
758+
if (!Op1Ty->isTypeUntypedPointerKHR() ||
759+
!Op2Ty->isTypeUntypedPointerKHR())
760+
assert(
761+
static_cast<SPIRVTypePointer *>(Op1Ty)->getElementType() ==
762+
static_cast<SPIRVTypePointer *>(Op2Ty)->getElementType() &&
763+
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
764+
else if (OpCode == OpPtrDiff)
765+
assert(Op1Ty == Op2Ty && "Invalid types for PtrDiff instruction");
694766
} else {
695767
assert(0 && "Invalid op code!");
696768
}

0 commit comments

Comments
 (0)