Skip to content

Commit d54f77c

Browse files
authored
[NFC] Split of SPT and SPIR-V in header parsing (#2316)
Translator accepting two formats currently - SPIR-V and SPT. SPT is a textual format used internally for tests without any formal specification. Parsing a textual format is slower than binary format and SPT also is less strict in comparison to SPIRV. Because parsing in Translator is organized around iostream interfaces and implementations are mostly shared, the binary format is parsed much slower than it can be. The commit starts an effort of splitting implementations to make SPIR-V hot path faster and easier to read. In addition to that from both implementations the Decoder class is removed - it doesn't bring any important functionality which couldn't be solved by few lines of explicit simple code.
1 parent 63fd351 commit d54f77c

File tree

1 file changed

+233
-28
lines changed

1 file changed

+233
-28
lines changed

lib/SPIRV/libSPIRV/SPIRVModule.cpp

Lines changed: 233 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,8 @@ class SPIRVModuleImpl : public SPIRVModule {
572572
SPIRVAliasInstMDMap AliasInstMDMap;
573573

574574
void layoutEntry(SPIRVEntry *Entry);
575+
std::istream &parseSPT(std::istream &I);
576+
std::istream &parseSPIRV(std::istream &I);
575577
};
576578

577579
SPIRVModuleImpl::~SPIRVModuleImpl() {
@@ -2123,70 +2125,273 @@ void SPIRVModuleImpl::addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I,
21232125
UnknownStructFieldMap[Struct].push_back(std::make_pair(I, ID));
21242126
}
21252127

2126-
std::istream &operator>>(std::istream &I, SPIRVModule &M) {
2127-
SPIRVDecoder Decoder(I, M);
2128-
SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl *>(&M);
2129-
// Disable automatic capability filling.
2128+
namespace {
2129+
SPIRVEntry *parseAndCreateSPIRVEntry(SPIRVWord &WordCount, Op &OpCode,
2130+
SPIRVEntry *Scope, SPIRVModuleImpl &M,
2131+
std::istream &IS) {
2132+
if (WordCount == 0 || OpCode == OpNop) {
2133+
return nullptr;
2134+
}
2135+
SPIRVEntry *Entry = SPIRVEntry::create(OpCode);
2136+
assert(Entry);
2137+
Entry->setModule(&M);
2138+
if (Scope && !isModuleScopeAllowedOpCode(OpCode)) {
2139+
Entry->setScope(Scope);
2140+
}
2141+
Entry->setWordCount(WordCount);
2142+
if (OpCode != OpLine)
2143+
Entry->setLine(M.getCurrentLine());
2144+
if (!Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_100,
2145+
SPIRVDebug::DebugLine) &&
2146+
!Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
2147+
SPIRVDebug::DebugLine)) {
2148+
Entry->setDebugLine(M.getCurrentDebugLine());
2149+
}
2150+
IS >> *Entry;
2151+
if (Entry->isEndOfBlock() || OpCode == OpNoLine) {
2152+
M.setCurrentLine(nullptr);
2153+
}
2154+
if (Entry->isEndOfBlock() ||
2155+
Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_100,
2156+
SPIRVDebug::DebugNoLine) ||
2157+
Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
2158+
SPIRVDebug::DebugNoLine)) {
2159+
M.setCurrentDebugLine(nullptr);
2160+
}
2161+
2162+
if (OpExtension == OpCode) {
2163+
auto *OpExt = static_cast<SPIRVExtension *>(Entry);
2164+
ExtensionID ExtID = {};
2165+
bool ExtIsKnown = SPIRVMap<ExtensionID, std::string>::rfind(
2166+
OpExt->getExtensionName(), &ExtID);
2167+
if (!M.getErrorLog().checkError(
2168+
ExtIsKnown, SPIRVEC_InvalidModule,
2169+
"input SPIR-V module uses unknown extension '" +
2170+
OpExt->getExtensionName() + "'")) {
2171+
M.setInvalid();
2172+
}
2173+
2174+
if (!M.getErrorLog().checkError(
2175+
M.isAllowedToUseExtension(ExtID), SPIRVEC_InvalidModule,
2176+
"input SPIR-V module uses extension '" + OpExt->getExtensionName() +
2177+
"' which were disabled by --spirv-ext option")) {
2178+
M.setInvalid();
2179+
}
2180+
}
2181+
2182+
if (!M.getErrorLog().checkError(Entry->isImplemented(),
2183+
SPIRVEC_UnimplementedOpCode,
2184+
std::to_string(Entry->getOpCode()))) {
2185+
M.setInvalid();
2186+
}
2187+
2188+
assert(!IS.bad() && !IS.fail() && "SPIRV stream fails");
2189+
return Entry;
2190+
}
2191+
} // namespace
2192+
2193+
std::istream &SPIRVModuleImpl::parseSPT(std::istream &I) {
2194+
SPIRVModuleImpl &MI = *this;
21302195
MI.setAutoAddCapability(false);
21312196
MI.setAutoAddExtensions(false);
2197+
auto ReadSPIRVWord = [](std::istream &I) {
2198+
uint32_t W;
2199+
I >> skipcomment >> W;
2200+
SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = 0\n");
2201+
return W;
2202+
};
2203+
SPIRVErrorLog ErrorLog = MI.getErrorLog();
2204+
SPIRVWord Magic = ReadSPIRVWord(I);
2205+
2206+
if (!ErrorLog.checkError(!I.eof(), SPIRVEC_InvalidModule,
2207+
"input file is empty") ||
2208+
!ErrorLog.checkError(!I.fail(), SPIRVEC_InvalidModule,
2209+
"header parsing error")) {
2210+
MI.setInvalid();
2211+
return I;
2212+
}
21322213

2133-
SPIRVWord Magic;
2134-
Decoder >> Magic;
2135-
if (!M.getErrorLog().checkError(Magic == MagicNumber, SPIRVEC_InvalidModule,
2136-
"invalid magic number")) {
2137-
M.setInvalid();
2214+
if (!ErrorLog.checkError(Magic == MagicNumber, SPIRVEC_InvalidModule,
2215+
"invalid magic number")) {
2216+
MI.setInvalid();
2217+
return I;
2218+
}
2219+
2220+
MI.SPIRVVersion = ReadSPIRVWord(I);
2221+
if (!ErrorLog.checkError(!I.fail(), SPIRVEC_InvalidModule,
2222+
"header parsing error")) {
2223+
MI.setInvalid();
21382224
return I;
21392225
}
21402226

2141-
Decoder >> MI.SPIRVVersion;
21422227
bool SPIRVVersionIsKnown = isSPIRVVersionKnown(MI.SPIRVVersion);
2143-
if (!M.getErrorLog().checkError(
2228+
if (!ErrorLog.checkError(
21442229
SPIRVVersionIsKnown, SPIRVEC_InvalidModule,
21452230
"unsupported SPIR-V version number '" + to_string(MI.SPIRVVersion) +
21462231
"'. Range of supported/known SPIR-V "
21472232
"versions is " +
21482233
to_string(VersionNumber::MinimumVersion) + " - " +
21492234
to_string(VersionNumber::MaximumVersion))) {
2150-
M.setInvalid();
2235+
MI.setInvalid();
21512236
return I;
21522237
}
21532238

2154-
bool SPIRVVersionIsAllowed = M.isAllowedToUseVersion(MI.SPIRVVersion);
2155-
if (!M.getErrorLog().checkError(
2239+
bool SPIRVVersionIsAllowed = MI.isAllowedToUseVersion(MI.SPIRVVersion);
2240+
if (!ErrorLog.checkError(
21562241
SPIRVVersionIsAllowed, SPIRVEC_InvalidModule,
21572242
"incorrect SPIR-V version number " + to_string(MI.SPIRVVersion) +
21582243
" - it conflicts with maximum allowed version which is set to " +
2159-
to_string(M.getMaximumAllowedSPIRVVersion()))) {
2160-
M.setInvalid();
2244+
to_string(MI.getMaximumAllowedSPIRVVersion()))) {
2245+
MI.setInvalid();
2246+
return I;
2247+
}
2248+
2249+
SPIRVWord Generator = ReadSPIRVWord(I);
2250+
if (!ErrorLog.checkError(!I.fail(), SPIRVEC_InvalidModule,
2251+
"header parsing error")) {
2252+
MI.setInvalid();
21612253
return I;
21622254
}
21632255

2164-
SPIRVWord Generator = 0;
2165-
Decoder >> Generator;
21662256
MI.GeneratorId = Generator >> 16;
21672257
MI.GeneratorVer = Generator & 0xFFFF;
21682258

21692259
// Bound for Id
2170-
Decoder >> MI.NextId;
2260+
MI.NextId = ReadSPIRVWord(I);
2261+
if (!ErrorLog.checkError(!I.fail(), SPIRVEC_InvalidModule,
2262+
"header parsing error")) {
2263+
MI.setInvalid();
2264+
return I;
2265+
}
21712266

2172-
Decoder >> MI.InstSchema;
2173-
if (!M.getErrorLog().checkError(MI.InstSchema == SPIRVISCH_Default,
2174-
SPIRVEC_InvalidModule,
2175-
"unsupported instruction schema")) {
2176-
M.setInvalid();
2267+
MI.InstSchema = static_cast<SPIRVInstructionSchemaKind>(ReadSPIRVWord(I));
2268+
if (!ErrorLog.checkError(MI.InstSchema == SPIRVISCH_Default,
2269+
SPIRVEC_InvalidModule,
2270+
"unsupported instruction schema")) {
2271+
MI.setInvalid();
21772272
return I;
21782273
}
21792274

2180-
while (Decoder.getWordCountAndOpCode() && M.isModuleValid()) {
2181-
SPIRVEntry *Entry = Decoder.getEntry();
2182-
if (Entry != nullptr)
2183-
M.add(Entry);
2275+
SPIRVWord WordCount = 0;
2276+
Op OpCode = OpNop;
2277+
SPIRVEntry *Scope = nullptr;
2278+
while (true) {
2279+
WordCount = ReadSPIRVWord(I);
2280+
if (I.fail()) {
2281+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode FAIL 0 0\n");
2282+
break;
2283+
}
2284+
std::string RawOp;
2285+
I >> RawOp;
2286+
OpCode = getNameMap(OpCode).rmap(RawOp);
2287+
SPIRVDBG(spvdbgs() << "Read word: W = " << RawOp << " V = " << OpCode
2288+
<< '\n');
2289+
if (I.fail()) {
2290+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode FAIL 0 0\n");
2291+
break;
2292+
}
2293+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode " << WordCount << " "
2294+
<< OpCodeNameMap::map(OpCode) << '\n');
2295+
if (!MI.isModuleValid()) {
2296+
break;
2297+
}
2298+
2299+
SPIRVEntry *Entry =
2300+
parseAndCreateSPIRVEntry(WordCount, OpCode, Scope, MI, I);
2301+
if (Entry != nullptr) {
2302+
MI.add(Entry);
2303+
}
2304+
if (I.eof()) {
2305+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode EOF 0 0\n");
2306+
break;
2307+
}
21842308
}
21852309

21862310
MI.resolveUnknownStructFields();
21872311
return I;
21882312
}
21892313

2314+
std::istream &SPIRVModuleImpl::parseSPIRV(std::istream &I) {
2315+
SPIRVModuleImpl &MI = *this;
2316+
MI.setAutoAddCapability(false);
2317+
MI.setAutoAddExtensions(false);
2318+
2319+
SPIRVWord Header[5] = {0};
2320+
I.read(reinterpret_cast<char *>(&Header), sizeof(Header));
2321+
2322+
SPIRVErrorLog ErrorLog = MI.getErrorLog();
2323+
if (!ErrorLog.checkError(!I.eof(), SPIRVEC_InvalidModule,
2324+
"input file is empty") ||
2325+
!ErrorLog.checkError(!I.fail(), SPIRVEC_InvalidModule,
2326+
"header parsing error") ||
2327+
!ErrorLog.checkError(Header[0] == MagicNumber, SPIRVEC_InvalidModule,
2328+
"invalid magic number") ||
2329+
!ErrorLog.checkError(
2330+
isSPIRVVersionKnown(Header[1]), SPIRVEC_InvalidModule,
2331+
"unsupported SPIR-V version number '" + to_string(Header[1]) +
2332+
"'. Range of supported/known SPIR-V "
2333+
"versions is " +
2334+
to_string(VersionNumber::MinimumVersion) + " - " +
2335+
to_string(VersionNumber::MaximumVersion)) ||
2336+
!ErrorLog.checkError(
2337+
MI.isAllowedToUseVersion(Header[1]), SPIRVEC_InvalidModule,
2338+
"incorrect SPIR-V version number " + to_string(Header[1]) +
2339+
" - it conflicts with maximum allowed version which is set to " +
2340+
to_string(MI.getMaximumAllowedSPIRVVersion())) ||
2341+
!ErrorLog.checkError(Header[4] == SPIRVISCH_Default,
2342+
SPIRVEC_InvalidModule,
2343+
"unsupported instruction schema")) {
2344+
MI.setInvalid();
2345+
return I;
2346+
}
2347+
2348+
MI.SPIRVVersion = Header[1];
2349+
MI.GeneratorId = Header[2] >> 16;
2350+
MI.GeneratorVer = Header[2] & 0xFFFF;
2351+
MI.NextId = Header[3];
2352+
MI.InstSchema = static_cast<SPIRVInstructionSchemaKind>(Header[4]);
2353+
2354+
SPIRVEntry *Scope = nullptr;
2355+
while (true) {
2356+
SPIRVWord WordCountAndOpCode = 0;
2357+
I.read(reinterpret_cast<char *>(&WordCountAndOpCode), sizeof(SPIRVWord));
2358+
SPIRVDBG(spvdbgs() << "Read word: W = " << WordCountAndOpCode
2359+
<< " V = 0\n");
2360+
SPIRVWord WordCount = WordCountAndOpCode >> 16;
2361+
Op OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF);
2362+
if (I.fail()) {
2363+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode FAIL 0 0\n");
2364+
break;
2365+
}
2366+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode " << WordCount << " "
2367+
<< OpCodeNameMap::map(OpCode) << '\n');
2368+
if (!MI.isModuleValid()) {
2369+
break;
2370+
}
2371+
SPIRVEntry *Entry =
2372+
parseAndCreateSPIRVEntry(WordCount, OpCode, Scope, MI, I);
2373+
if (Entry != nullptr) {
2374+
MI.add(Entry);
2375+
}
2376+
if (I.eof()) {
2377+
SPIRVDBG(spvdbgs() << "getWordCountAndOpCode EOF 0 0\n");
2378+
break;
2379+
}
2380+
}
2381+
MI.resolveUnknownStructFields();
2382+
return I;
2383+
}
2384+
2385+
std::istream &operator>>(std::istream &I, SPIRVModule &M) {
2386+
SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl *>(&M);
2387+
#ifdef _SPIRV_SUPPORT_TEXT_FMT
2388+
if (SPIRVUseTextFormat) {
2389+
return MI.parseSPT(I);
2390+
}
2391+
#endif
2392+
return MI.parseSPIRV(I);
2393+
}
2394+
21902395
SPIRVModule *SPIRVModule::createSPIRVModule() { return new SPIRVModuleImpl(); }
21912396

21922397
SPIRVModule *SPIRVModule::createSPIRVModule(const SPIRV::TranslatorOpts &Opts) {

0 commit comments

Comments
 (0)