Skip to content

Commit ff9babe

Browse files
authored
Implement SPV_INTEL_long_constant_composite extension (#848)
It is not possible to represent constant array initializer with number of elements greater than maximum word count (65532) in SPIR-V. Splitting big array before SPIR-V translation doesn't seem like a robust solution and can cause performance problems. To fix this disadvantage we can use something like OpSource and OpSourceContinued pair of instructions, i.e. invent a new instruction which will hold remaining constituents of a composite constant if resulting number of constituents is greater than maximum word count.
1 parent 7200048 commit ff9babe

16 files changed

+66068
-27
lines changed

include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ EXT(SPV_INTEL_variable_length_array)
3030
EXT(SPV_INTEL_fp_fast_math_mode)
3131
EXT(SPV_INTEL_fpga_cluster_attributes)
3232
EXT(SPV_INTEL_loop_fuse)
33+
EXT(SPV_INTEL_long_constant_composite)

lib/SPIRV/SPIRVReader.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) {
529529
SmallVector<Type *, 4> MT;
530530
for (size_t I = 0, E = ST->getMemberCount(); I != E; ++I)
531531
MT.push_back(transType(ST->getMemberType(I), true));
532+
for (auto &CI : ST->getContinuedInstructions())
533+
for (size_t I = 0, E = CI->getNumElements(); I != E; ++I)
534+
MT.push_back(transType(CI->getMemberType(I), true));
532535
StructTy->setBody(MT, ST->isPacked());
533536
return StructTy;
534537
}
@@ -1618,6 +1621,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
16181621
std::vector<Constant *> CV;
16191622
for (auto &I : BCC->getElements())
16201623
CV.push_back(dyn_cast<Constant>(transValue(I, F, BB)));
1624+
for (auto &CI : BCC->getContinuedInstructions()) {
1625+
for (auto &I : CI->getElements())
1626+
CV.push_back(dyn_cast<Constant>(transValue(I, F, BB)));
1627+
}
16211628
switch (BV->getType()->getOpCode()) {
16221629
case OpTypeVector:
16231630
return mapValue(BV, ConstantVector::get(CV));

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,38 @@ SPIRVType *LLVMToSPIRV::transType(Type *T) {
414414
if (Name == getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage))
415415
return transType(getPipeStorageType(M));
416416

417-
auto *Struct = BM->openStructType(T->getStructNumElements(), Name.str());
417+
constexpr size_t MaxNumElements = MaxWordCount - SPIRVTypeStruct::FixedWC;
418+
const size_t NumElements = ST->getNumElements();
419+
size_t SPIRVStructNumElements = NumElements;
420+
// In case number of elements is greater than maximum WordCount and
421+
// SPV_INTEL_long_constant_composite is not enabled, the error will be
422+
// emitted by validate functionality of SPIRVTypeStruct class.
423+
if (NumElements > MaxNumElements &&
424+
BM->isAllowedToUseExtension(
425+
ExtensionID::SPV_INTEL_long_constant_composite)) {
426+
SPIRVStructNumElements = MaxNumElements;
427+
}
428+
429+
auto *Struct = BM->openStructType(SPIRVStructNumElements, Name.str());
418430
mapType(T, Struct);
419431

432+
if (NumElements > MaxNumElements &&
433+
BM->isAllowedToUseExtension(
434+
ExtensionID::SPV_INTEL_long_constant_composite)) {
435+
uint64_t NumOfContinuedInstructions = NumElements / MaxNumElements - 1;
436+
for (uint64_t J = 0; J < NumOfContinuedInstructions; J++) {
437+
auto *Continued = BM->addTypeStructContinuedINTEL(MaxNumElements);
438+
Struct->addContinuedInstruction(
439+
static_cast<SPIRVTypeStruct::ContinuedInstType>(Continued));
440+
}
441+
uint64_t Remains = NumElements % MaxNumElements;
442+
if (Remains) {
443+
auto *Continued = BM->addTypeStructContinuedINTEL(Remains);
444+
Struct->addContinuedInstruction(
445+
static_cast<SPIRVTypeStruct::ContinuedInstType>(Continued));
446+
}
447+
}
448+
420449
SmallVector<unsigned, 4> ForwardRefs;
421450

422451
for (unsigned I = 0, E = T->getStructNumElements(); I != E; ++I) {
@@ -1246,19 +1275,24 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
12461275
} else
12471276
BVarInit = I->second;
12481277
} else if (Init && !isa<UndefValue>(Init)) {
1249-
if (auto ArrTy = dyn_cast_or_null<ArrayType>(Init->getType())) {
1250-
// First 3 words of OpConstantComposite encode: 1) word count & opcode,
1251-
// 2) Result Type and 3) Result Id.
1252-
// Max length of SPIRV instruction = 65535 words.
1253-
const int MaxNumElements = 65535 - 3;
1254-
if (ArrTy->getNumElements() > MaxNumElements &&
1255-
!isa<ConstantAggregateZero>(Init)) {
1256-
std::stringstream SS;
1257-
SS << "Global variable has a constant array initializer with a number"
1258-
<< " of elements greater than OpConstantComposite can have "
1259-
<< "(65532). Should the array be split?\n Original LLVM value:\n"
1260-
<< toString(GV);
1261-
getErrorLog().checkError(false, SPIRVEC_InvalidWordCount, SS.str());
1278+
if (!BM->isAllowedToUseExtension(
1279+
ExtensionID::SPV_INTEL_long_constant_composite)) {
1280+
if (auto ArrTy = dyn_cast_or_null<ArrayType>(Init->getType())) {
1281+
// First 3 words of OpConstantComposite encode: 1) word count &
1282+
// opcode, 2) Result Type and 3) Result Id. Max length of SPIRV
1283+
// instruction = 65535 words.
1284+
constexpr int MaxNumElements =
1285+
MaxWordCount - SPIRVSpecConstantComposite::FixedWC;
1286+
if (ArrTy->getNumElements() > MaxNumElements &&
1287+
!isa<ConstantAggregateZero>(Init)) {
1288+
std::stringstream SS;
1289+
SS << "Global variable has a constant array initializer with a "
1290+
<< "number of elements greater than OpConstantComposite can "
1291+
<< "have (" << MaxNumElements << "). Should the array be "
1292+
<< "split?\n Original LLVM value:\n"
1293+
<< toString(GV);
1294+
getErrorLog().checkError(false, SPIRVEC_InvalidWordCount, SS.str());
1295+
}
12621296
}
12631297
}
12641298
BVarInit = transValue(Init, nullptr);

lib/SPIRV/libSPIRV/SPIRVEntry.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,4 +662,17 @@ void SPIRVCapability::decode(std::istream &I) {
662662
Module->addCapability(Kind);
663663
}
664664

665+
template <spv::Op OC> void SPIRVContinuedInstINTELBase<OC>::validate() const {
666+
SPIRVEntry::validate();
667+
}
668+
669+
template <spv::Op OC>
670+
void SPIRVContinuedInstINTELBase<OC>::encode(spv_ostream &O) const {
671+
SPIRVEntry::getEncoder(O) << (Elements);
672+
}
673+
template <spv::Op OC>
674+
void SPIRVContinuedInstINTELBase<OC>::decode(std::istream &I) {
675+
SPIRVEntry::getDecoder(I) >> (Elements);
676+
}
677+
665678
} // namespace SPIRV

lib/SPIRV/libSPIRV/SPIRVEntry.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,92 @@ template <spv::Op OC> bool isa(SPIRVEntry *E) {
857857
return E ? E->getOpCode() == OC : false;
858858
}
859859

860+
template <spv::Op OC>
861+
class SPIRVContinuedInstINTELBase : public SPIRVEntryNoId<OC> {
862+
public:
863+
template <spv::Op _OC, class T = void>
864+
using EnableIfStruct =
865+
typename std::enable_if_t<_OC == OpTypeStructContinuedINTEL, T>;
866+
template <spv::Op _OC, class T = void>
867+
using EnableIfCompositeConst =
868+
typename std::enable_if_t<_OC == OpConstantCompositeContinuedINTEL ||
869+
_OC ==
870+
OpSpecConstantCompositeContinuedINTEL,
871+
T>;
872+
// Complete constructor
873+
SPIRVContinuedInstINTELBase(SPIRVModule *M,
874+
const std::vector<SPIRVValue *> &TheElements)
875+
: SPIRVEntryNoId<OC>(M, TheElements.size() + 1) {
876+
877+
Elements = SPIRVEntry::getIds(TheElements);
878+
validate();
879+
}
880+
881+
SPIRVContinuedInstINTELBase(SPIRVModule *M, unsigned NumOfElements)
882+
: SPIRVEntryNoId<OC>(M, NumOfElements + 1) {
883+
Elements.resize(NumOfElements, SPIRVID_INVALID);
884+
validate();
885+
}
886+
887+
// Incomplete constructor
888+
SPIRVContinuedInstINTELBase() : SPIRVEntryNoId<OC>() {}
889+
890+
template <spv::Op OPC = OC>
891+
EnableIfCompositeConst<OPC, std::vector<SPIRVValue *>> getElements() const {
892+
return SPIRVEntry::getValues(Elements);
893+
}
894+
895+
template <spv::Op OPC = OC>
896+
EnableIfStruct<OPC, SPIRVType *> getMemberType(size_t I) const {
897+
return static_cast<SPIRVType *>(SPIRVEntry::getEntry(Elements[I]));
898+
}
899+
900+
SPIRVCapVec getRequiredCapability() const override {
901+
return getVec(CapabilityLongConstantCompositeINTEL);
902+
}
903+
904+
llvm::Optional<ExtensionID> getRequiredExtension() const override {
905+
return ExtensionID::SPV_INTEL_long_constant_composite;
906+
}
907+
908+
void setElementId(size_t I, SPIRVId Id) { Elements[I] = Id; }
909+
SPIRVWord getNumElements() const { return Elements.size(); }
910+
911+
protected:
912+
void validate() const override;
913+
void setWordCount(SPIRVWord WordCount) override {
914+
SPIRVEntry::setWordCount(WordCount);
915+
Elements.resize(WordCount - 1);
916+
}
917+
_SPIRV_DCL_ENCDEC
918+
919+
std::vector<SPIRVId> Elements;
920+
};
921+
922+
using SPIRVTypeStructContinuedINTEL =
923+
SPIRVContinuedInstINTELBase<OpTypeStructContinuedINTEL>;
924+
using SPIRVConstantCompositeContinuedINTEL =
925+
SPIRVContinuedInstINTELBase<OpConstantCompositeContinuedINTEL>;
926+
using SPIRVSpecConstantCompositeContinuedINTEL =
927+
SPIRVContinuedInstINTELBase<OpSpecConstantCompositeContinuedINTEL>;
928+
929+
template <spv::Op OpCode> struct InstToContinued;
930+
931+
template <> struct InstToContinued<OpTypeStruct> {
932+
using Type = SPIRVTypeStructContinuedINTEL *;
933+
constexpr static spv::Op OpCode = OpTypeStructContinuedINTEL;
934+
};
935+
936+
template <> struct InstToContinued<OpConstantComposite> {
937+
using Type = SPIRVConstantCompositeContinuedINTEL *;
938+
constexpr static spv::Op OpCode = OpConstantCompositeContinuedINTEL;
939+
};
940+
941+
template <> struct InstToContinued<OpSpecConstantComposite> {
942+
using Type = SPIRVSpecConstantCompositeContinuedINTEL *;
943+
constexpr static spv::Op OpCode = OpSpecConstantCompositeContinuedINTEL;
944+
};
945+
860946
// ToDo: The following typedef's are place holders for SPIRV entity classes
861947
// to be implemented.
862948
// Each time a new class is implemented, remove the corresponding typedef.

lib/SPIRV/libSPIRV/SPIRVModule.cpp

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ class SPIRVModuleImpl : public SPIRVModule {
239239
SPIRVTypePipeStorage *addPipeStorageType() override;
240240
SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T) override;
241241
SPIRVTypeStruct *openStructType(unsigned, const std::string &) override;
242+
SPIRVEntry *addTypeStructContinuedINTEL(unsigned NumMembers) override;
242243
void closeStructType(SPIRVTypeStruct *T, bool) override;
243244
SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord) override;
244245
SPIRVType *addOpaqueGenericType(Op) override;
@@ -259,9 +260,13 @@ class SPIRVModuleImpl : public SPIRVModule {
259260
SPIRVBasicBlock *) override;
260261
SPIRVValue *addCompositeConstant(SPIRVType *,
261262
const std::vector<SPIRVValue *> &) override;
263+
SPIRVEntry *addCompositeConstantContinuedINTEL(
264+
const std::vector<SPIRVValue *> &) override;
262265
SPIRVValue *
263266
addSpecConstantComposite(SPIRVType *Ty,
264267
const std::vector<SPIRVValue *> &Elements) override;
268+
SPIRVEntry *addSpecConstantCompositeContinuedINTEL(
269+
const std::vector<SPIRVValue *> &) override;
265270
SPIRVValue *addConstFunctionPointerINTEL(SPIRVType *Ty,
266271
SPIRVFunction *F) override;
267272
SPIRVValue *addConstant(SPIRVValue *) override;
@@ -846,6 +851,10 @@ SPIRVTypeStruct *SPIRVModuleImpl::openStructType(unsigned NumMembers,
846851
return T;
847852
}
848853

854+
SPIRVEntry *SPIRVModuleImpl::addTypeStructContinuedINTEL(unsigned NumMembers) {
855+
return add(new SPIRVTypeStructContinuedINTEL(this, NumMembers));
856+
}
857+
849858
void SPIRVModuleImpl::closeStructType(SPIRVTypeStruct *T, bool Packed) {
850859
addType(T);
851860
T->setPacked(Packed);
@@ -1069,13 +1078,72 @@ SPIRVValue *SPIRVModuleImpl::addNullConstant(SPIRVType *Ty) {
10691078

10701079
SPIRVValue *SPIRVModuleImpl::addCompositeConstant(
10711080
SPIRVType *Ty, const std::vector<SPIRVValue *> &Elements) {
1072-
return addConstant(new SPIRVConstantComposite(this, Ty, getId(), Elements));
1081+
constexpr int MaxNumElements = MaxWordCount - SPIRVConstantComposite::FixedWC;
1082+
const int NumElements = Elements.size();
1083+
1084+
// In case number of elements is greater than maximum WordCount and
1085+
// SPV_INTEL_long_constant_composite is not enabled, the error will be emitted
1086+
// by validate functionality of SPIRVCompositeConstant class.
1087+
if (NumElements <= MaxNumElements ||
1088+
!isAllowedToUseExtension(ExtensionID::SPV_INTEL_long_constant_composite))
1089+
return addConstant(new SPIRVConstantComposite(this, Ty, getId(), Elements));
1090+
1091+
auto Start = Elements.begin();
1092+
auto End = Start + MaxNumElements;
1093+
std::vector<SPIRVValue *> Slice(Start, End);
1094+
auto *Res =
1095+
static_cast<SPIRVConstantComposite *>(addCompositeConstant(Ty, Slice));
1096+
for (; End != Elements.end();) {
1097+
Start = End;
1098+
End = ((Elements.end() - End) > MaxNumElements) ? End + MaxNumElements
1099+
: Elements.end();
1100+
Slice.assign(Start, End);
1101+
auto Continued = static_cast<SPIRVConstantComposite::ContinuedInstType>(
1102+
addCompositeConstantContinuedINTEL(Slice));
1103+
Res->addContinuedInstruction(Continued);
1104+
}
1105+
return Res;
1106+
}
1107+
1108+
SPIRVEntry *SPIRVModuleImpl::addCompositeConstantContinuedINTEL(
1109+
const std::vector<SPIRVValue *> &Elements) {
1110+
return add(new SPIRVConstantCompositeContinuedINTEL(this, Elements));
10731111
}
10741112

10751113
SPIRVValue *SPIRVModuleImpl::addSpecConstantComposite(
10761114
SPIRVType *Ty, const std::vector<SPIRVValue *> &Elements) {
1077-
return addConstant(
1078-
new SPIRVSpecConstantComposite(this, Ty, getId(), Elements));
1115+
constexpr int MaxNumElements =
1116+
MaxWordCount - SPIRVSpecConstantComposite::FixedWC;
1117+
const int NumElements = Elements.size();
1118+
1119+
// In case number of elements is greater than maximum WordCount and
1120+
// SPV_INTEL_long_constant_composite is not enabled, the error will be emitted
1121+
// by validate functionality of SPIRVSpecConstantComposite class.
1122+
if (NumElements <= MaxNumElements ||
1123+
!isAllowedToUseExtension(ExtensionID::SPV_INTEL_long_constant_composite))
1124+
return addConstant(
1125+
new SPIRVSpecConstantComposite(this, Ty, getId(), Elements));
1126+
1127+
auto Start = Elements.begin();
1128+
auto End = Start + MaxNumElements;
1129+
std::vector<SPIRVValue *> Slice(Start, End);
1130+
auto *Res = static_cast<SPIRVSpecConstantComposite *>(
1131+
addSpecConstantComposite(Ty, Slice));
1132+
for (; End != Elements.end();) {
1133+
Start = End;
1134+
End = ((Elements.end() - End) > MaxNumElements) ? End + MaxNumElements
1135+
: Elements.end();
1136+
Slice.assign(Start, End);
1137+
auto Continued = static_cast<SPIRVSpecConstantComposite::ContinuedInstType>(
1138+
addSpecConstantCompositeContinuedINTEL(Slice));
1139+
Res->addContinuedInstruction(Continued);
1140+
}
1141+
return Res;
1142+
}
1143+
1144+
SPIRVEntry *SPIRVModuleImpl::addSpecConstantCompositeContinuedINTEL(
1145+
const std::vector<SPIRVValue *> &Elements) {
1146+
return add(new SPIRVSpecConstantCompositeContinuedINTEL(this, Elements));
10791147
}
10801148

10811149
SPIRVValue *SPIRVModuleImpl::addConstFunctionPointerINTEL(SPIRVType *Ty,

lib/SPIRV/libSPIRV/SPIRVModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ class SPIRVModule {
236236
virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind,
237237
SPIRVType *) = 0;
238238
virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &) = 0;
239+
virtual SPIRVEntry *addTypeStructContinuedINTEL(unsigned NumMembers) = 0;
239240
virtual void closeStructType(SPIRVTypeStruct *, bool) = 0;
240241
virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord) = 0;
241242
virtual SPIRVTypeVoid *addVoidType() = 0;
@@ -252,9 +253,13 @@ class SPIRVModule {
252253
// Constants creation functions
253254
virtual SPIRVValue *
254255
addCompositeConstant(SPIRVType *, const std::vector<SPIRVValue *> &) = 0;
256+
virtual SPIRVEntry *
257+
addCompositeConstantContinuedINTEL(const std::vector<SPIRVValue *> &) = 0;
255258
virtual SPIRVValue *
256259
addSpecConstantComposite(SPIRVType *Ty,
257260
const std::vector<SPIRVValue *> &Elements) = 0;
261+
virtual SPIRVEntry *
262+
addSpecConstantCompositeContinuedINTEL(const std::vector<SPIRVValue *> &) = 0;
258263
virtual SPIRVValue *addConstFunctionPointerINTEL(SPIRVType *Ty,
259264
SPIRVFunction *F) = 0;
260265
virtual SPIRVValue *addConstant(SPIRVValue *) = 0;

lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
510510
add(CapabilityFPGAClusterAttributesINTEL, "FPGAClusterAttributesINTEL");
511511
add(CapabilityLoopFuseINTEL, "LoopFuseINTEL");
512512
add(CapabilityMax, "Max");
513+
add(CapabilityLongConstantCompositeINTEL, "LongConstantCompositeINTEL");
513514
}
514515
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)
515516

lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,6 @@ _SPIRV_OP(WritePipeBlockingINTEL, 5947)
528528
_SPIRV_OP(FPGARegINTEL, 5949)
529529
_SPIRV_OP(AtomicFAddEXT, 6035)
530530
_SPIRV_OP(TypeBufferSurfaceINTEL, 6086)
531+
_SPIRV_OP(TypeStructContinuedINTEL, 6090)
532+
_SPIRV_OP(ConstantCompositeContinuedINTEL, 6091)
533+
_SPIRV_OP(SpecConstantCompositeContinuedINTEL, 6092)

0 commit comments

Comments
 (0)