Merge pull request #456 from steve-lunarg/remapper-literal64
SPIRV: Remapper: allow 64 bit literals in OperandVariableLiteralId iteration
This commit is contained in:
		
						commit
						ad08b30f69
					
				| @ -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
 | ||||
|  | ||||
| @ -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
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 John Kessenich
						John Kessenich