Skip to content

Commit d6140b0

Browse files
AlexeySotkinvladimirlaz
authored andcommitted
Emit error if WordCount exceeds 16-bit max value
According to the SPIR-V specification(Table 2) the 16 high-order bits of every instruction encode word count(length) of the instruction. This fundamental limitation doesn't allow to have instruction longer than 65535 words. Signed-off-by: Alexey Sotkin <[email protected]>
1 parent fe4e2a8 commit d6140b0

File tree

6 files changed

+50
-5
lines changed

6 files changed

+50
-5
lines changed

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,21 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
10291029
} else
10301030
BVarInit = I->second;
10311031
} else if (Init && !isa<UndefValue>(Init)) {
1032+
if (auto ArrTy = dyn_cast_or_null<ArrayType>(Init->getType())) {
1033+
// First 3 words of OpConstantComposite encode: 1) word count & opcode,
1034+
// 2) Result Type and 3) Result Id.
1035+
// Max length of SPIRV instruction = 65535 words.
1036+
const int MaxNumElements = 65535 - 3;
1037+
if (ArrTy->getNumElements() > MaxNumElements &&
1038+
!isa<ConstantAggregateZero>(Init)) {
1039+
std::stringstream SS;
1040+
SS << "Global variable has a constant array initializer with a number"
1041+
<< " of elements greater than OpConstantComposite can have "
1042+
<< "(65532). Should the array be split?\n Original LLVM value:\n"
1043+
<< toString(GV);
1044+
getErrorLog().checkError(false, SPIRVEC_InvalidWordCount, SS.str());
1045+
}
1046+
}
10321047
BVarInit = transValue(Init, nullptr);
10331048
}
10341049

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ void SPIRVEntry::encodeWordCountOpCode(spv_ostream &O) const {
195195
return;
196196
}
197197
#endif
198-
getEncoder(O) << mkWord(WordCount, OpCode);
198+
assert(WordCount < 65536 && "WordCount must fit into 16-bit value");
199+
SPIRVWord WordCountOpCode = (WordCount << WordCountShift) | OpCode;
200+
getEncoder(O) << WordCountOpCode;
199201
}
200202
// Read words from SPIRV binary and create members for SPIRVEntry.
201203
// The word count and op code has already been read before calling this

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ class SPIRVEntry {
381381
assert(Module && "Invalid module");
382382
assert(OpCode != OpNop && "Invalid op code");
383383
assert((!hasId() || isValidId(Id)) && "Invalid Id");
384+
if (WordCount > 65535) {
385+
std::stringstream SS;
386+
SS << "Id: " << Id << ", OpCode: " << OpCodeNameMap::map(OpCode)
387+
<< ", Name: \"" << Name << "\"\n";
388+
getErrorLog().checkError(false, SPIRVEC_InvalidWordCount, SS.str());
389+
}
384390
}
385391
void validateFunctionControlMask(SPIRVWord FCtlMask) const;
386392
void validateValues(const std::vector<SPIRVId> &) const;

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ typedef uint32_t SPIRVId;
5656

5757
inline bool isValidId(SPIRVId Id) { return Id != SPIRVID_INVALID && Id != 0; }
5858

59-
inline SPIRVWord mkWord(unsigned WordCount, Op OpCode) {
60-
return (WordCount << 16) | OpCode;
61-
}
62-
6359
const static unsigned KSpirvMemOrderSemanticMask = 0x1F;
6460

6561
enum SPIRVGeneratorKind {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ _SPIRV_OP(InvalidModule, "Invalid SPIR-V module:")
1313
_SPIRV_OP(UnimplementedOpCode, "Unimplemented opcode")
1414
_SPIRV_OP(FunctionPointers, "Can't translate function pointer:\n")
1515
_SPIRV_OP(InvalidInstruction, "Can't translate llvm instruction:\n")
16+
_SPIRV_OP(InvalidWordCount,
17+
"Can't encode instruction with word count greater than 65535:\n")

llvm-spirv/test/negative/word_count_limit.ll

Lines changed: 24 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)