SPIRV: allow 64 bit literals in OperandVariableLiteralId class iteration.

This commit is contained in:
steve-lunarg 2016-08-11 21:07:45 -06:00
parent 28660bb580
commit b249f2fc24
2 changed files with 107 additions and 52 deletions

View File

@ -127,6 +127,37 @@ namespace spv {
}
}
// Return the size of a type in 32-bit words. This currently only
// handles ints and floats, and is only invoked by queries which must be
// integer types. If ever needed, it can be generalized.
unsigned spirvbin_t::typeSizeInWords(spv::Id id) const
{
const unsigned typeStart = idPos(id);
const spv::Op opCode = asOpCode(typeStart);
switch (opCode) {
case spv::OpTypeInt: // fall through...
case spv::OpTypeFloat: return (spv[typeStart+2]+31)/32;
default:
error("unimplemented type size request");
return 0;
}
}
// Looks up the type of a given const or variable ID, and
// returns its size in 32-bit words.
unsigned spirvbin_t::idTypeSizeInWords(spv::Id id) const
{
const unsigned idStart = idPos(id);
const spv::Op opCode = asOpCode(idStart);
if (spv::InstructionDesc[opCode].hasType())
return typeSizeInWords(asId(idStart+1));
error("asked for type of typeless ID");
return 0;
}
// Is this an opcode we should remove when using --strip?
bool spirvbin_t::isStripOp(spv::Op opCode) const
{
@ -140,6 +171,7 @@ namespace spv {
}
}
// Return true if this opcode is flow control
bool spirvbin_t::isFlowCtrl(spv::Op opCode) const
{
switch (opCode) {
@ -155,6 +187,7 @@ namespace spv {
}
}
// Return true if this opcode defines a type
bool spirvbin_t::isTypeOp(spv::Op opCode) const
{
switch (opCode) {
@ -182,6 +215,7 @@ namespace spv {
}
}
// Return true if this opcode defines a constant
bool spirvbin_t::isConstOp(spv::Op opCode) const
{
switch (opCode) {
@ -324,7 +358,7 @@ namespace spv {
fnPosDCE.clear();
fnCalls.clear();
typeConstPos.clear();
typeConstPosR.clear();
idPosR.clear();
entryPoint = spv::NoResult;
largestNewId = 0;
@ -340,6 +374,14 @@ namespace spv {
if ((options & STRIP) && isStripOp(opCode))
stripInst(start);
unsigned word = start+1;
if (spv::InstructionDesc[opCode].hasType())
word++;
if (spv::InstructionDesc[opCode].hasResult())
idPosR[asId(word++)] = start;
if (opCode == spv::Op::OpName) {
const spv::Id target = asId(start+1);
const std::string name = literalString(start+2);
@ -363,11 +405,9 @@ namespace spv {
} else if (isConstOp(opCode)) {
assert(asId(start + 2) != spv::NoResult);
typeConstPos.insert(start);
typeConstPosR[asId(start + 2)] = start;
} else if (isTypeOp(opCode)) {
assert(asId(start + 1) != spv::NoResult);
typeConstPos.insert(start);
typeConstPosR[asId(start + 1)] = start;
}
return false;
@ -459,13 +499,22 @@ namespace spv {
// word += numOperands;
return nextInst;
case spv::OperandVariableLiteralId:
while (numOperands > 0) {
++word; // immediate
idFn(asId(word++)); // ID
numOperands -= 2;
case spv::OperandVariableLiteralId: {
if (opCode == OpSwitch) {
// word-2 is the position of the selector ID. Literals match its type.
const unsigned literalSize = idTypeSizeInWords(asId(word-2));
unsigned numLiteralIdPairs = (nextInst-word) / (1+literalSize);
for (unsigned arg=0; arg<numLiteralIdPairs; ++arg) {
word += literalSize; // literal
idFn(asId(word++)); // label
}
} else {
assert(0); // currentely, only OpSwitch uses OperandVariableLiteralId
}
return nextInst;
}
case spv::OperandLiteralString: {
const int stringWordCount = literalStringWords(literalString(word));
@ -966,23 +1015,27 @@ namespace spv {
std::unordered_map<spv::Id, int> typeUseCount;
// Count total type usage
process(inst_fn_nop,
[&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
);
// This is not the most efficient algorithm, but this is an offline tool, and
// it's easy to write this way. Can be improved opportunistically if needed.
bool changed = true;
while (changed) {
changed = false;
strip();
typeUseCount.clear();
// Remove types from deleted code
for (const auto& fn : fnPosDCE)
// Count total type usage
process(inst_fn_nop,
[&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },
fn.second.first, fn.second.second);
[&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
);
// Remove single reference types
for (const auto typeStart : typeConstPos) {
const spv::Id typeId = asTypeConstId(typeStart);
if (typeUseCount[typeId] == 1) {
--typeUseCount[typeId];
stripInst(typeStart);
// Remove single reference types
for (const auto typeStart : typeConstPos) {
const spv::Id typeId = asTypeConstId(typeStart);
if (typeUseCount[typeId] == 1) {
changed = true;
--typeUseCount[typeId];
stripInst(typeStart);
}
}
}
}
@ -1060,12 +1113,12 @@ namespace spv {
}
#endif // NOTDEF
// Return start position in SPV of given type. error if not found.
unsigned spirvbin_t::typePos(spv::Id id) const
// Return start position in SPV of given Id. error if not found.
unsigned spirvbin_t::idPos(spv::Id id) const
{
const auto tid_it = typeConstPosR.find(id);
if (tid_it == typeConstPosR.end())
error("type ID not found");
const auto tid_it = idPosR.find(id);
if (tid_it == idPosR.end())
error("ID not found");
return tid_it->second;
}
@ -1083,11 +1136,11 @@ namespace spv {
case spv::OpTypeInt: return 3 + (spv[typeStart+3]);
case spv::OpTypeFloat: return 5;
case spv::OpTypeVector:
return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
return 6 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
case spv::OpTypeMatrix:
return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
return 30 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
case spv::OpTypeImage:
return 120 + hashType(typePos(spv[typeStart+2])) +
return 120 + hashType(idPos(spv[typeStart+2])) +
spv[typeStart+3] + // dimensionality
spv[typeStart+4] * 8 * 16 + // depth
spv[typeStart+5] * 4 * 16 + // arrayed
@ -1098,24 +1151,24 @@ namespace spv {
case spv::OpTypeSampledImage:
return 502;
case spv::OpTypeArray:
return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
return 501 + hashType(idPos(spv[typeStart+2])) * spv[typeStart+3];
case spv::OpTypeRuntimeArray:
return 5000 + hashType(typePos(spv[typeStart+2]));
return 5000 + hashType(idPos(spv[typeStart+2]));
case spv::OpTypeStruct:
{
std::uint32_t hash = 10000;
for (unsigned w=2; w < wordCount; ++w)
hash += w * hashType(typePos(spv[typeStart+w]));
hash += w * hashType(idPos(spv[typeStart+w]));
return hash;
}
case spv::OpTypeOpaque: return 6000 + spv[typeStart+2];
case spv::OpTypePointer: return 100000 + hashType(typePos(spv[typeStart+3]));
case spv::OpTypePointer: return 100000 + hashType(idPos(spv[typeStart+3]));
case spv::OpTypeFunction:
{
std::uint32_t hash = 200000;
for (unsigned w=2; w < wordCount; ++w)
hash += w * hashType(typePos(spv[typeStart+w]));
hash += w * hashType(idPos(spv[typeStart+w]));
return hash;
}
@ -1132,14 +1185,14 @@ namespace spv {
case spv::OpConstantFalse: return 300008;
case spv::OpConstantComposite:
{
std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));
std::uint32_t hash = 300011 + hashType(idPos(spv[typeStart+1]));
for (unsigned w=3; w < wordCount; ++w)
hash += w * hashType(typePos(spv[typeStart+w]));
hash += w * hashType(idPos(spv[typeStart+w]));
return hash;
}
case spv::OpConstant:
{
std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));
std::uint32_t hash = 400011 + hashType(idPos(spv[typeStart+1]));
for (unsigned w=3; w < wordCount; ++w)
hash += w * spv[typeStart+w];
return hash;
@ -1212,19 +1265,19 @@ namespace spv {
msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
strip(); // strip out data we decided to eliminate
if (options & OPT_LOADSTORE) optLoadStore();
if (options & OPT_FWD_LS) forwardLoadStores();
if (options & DCE_FUNCS) dceFuncs();
if (options & DCE_VARS) dceVars();
if (options & DCE_TYPES) dceTypes();
strip(); // strip out data we decided to eliminate
if (options & MAP_TYPES) mapTypeConst();
if (options & MAP_NAMES) mapNames();
if (options & MAP_FUNCS) mapFnBodies();
mapRemainder(); // map any unmapped IDs
applyMap(); // Now remap each shader to the new IDs we've come up with
strip(); // strip out data we decided to eliminate
}
// remap from a memory image

View File

@ -162,13 +162,15 @@ private:
// handle error
void error(const std::string& txt) const { errorHandler(txt); }
bool isConstOp(spv::Op opCode) const;
bool isTypeOp(spv::Op opCode) const;
bool isStripOp(spv::Op opCode) const;
bool isFlowCtrl(spv::Op opCode) const;
range_t literalRange(spv::Op opCode) const;
range_t typeRange(spv::Op opCode) const;
range_t constRange(spv::Op opCode) const;
bool isConstOp(spv::Op opCode) const;
bool isTypeOp(spv::Op opCode) const;
bool isStripOp(spv::Op opCode) const;
bool isFlowCtrl(spv::Op opCode) const;
range_t literalRange(spv::Op opCode) const;
range_t typeRange(spv::Op opCode) const;
range_t constRange(spv::Op opCode) const;
unsigned typeSizeInWords(spv::Id id) const;
unsigned idTypeSizeInWords(spv::Id id) const;
spv::Id& asId(unsigned word) { return spv[word]; }
const spv::Id& asId(unsigned word) const { return spv[word]; }
@ -177,10 +179,10 @@ private:
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
unsigned typePos(spv::Id id) const;
unsigned idPos(spv::Id id) const;
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
// Header access & set methods
spirword_t magic() const { return spv[0]; } // return magic number
@ -263,8 +265,8 @@ private:
// Which functions are called, anywhere in the module, with a call count
std::unordered_map<spv::Id, int> fnCalls;
posmap_t typeConstPos; // word positions that define types & consts (ordered)
posmap_rev_t typeConstPosR; // reverse map from IDs to positions
posmap_t typeConstPos; // word positions that define types & consts (ordered)
posmap_rev_t idPosR; // reverse map from IDs to positions
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs