SPV compression: Final check-in enabling this on MSVC 2012. All compression submissions from Steve (spvremapper@lunarg.com).
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@31236 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
3c4a276282
commit
01685c3ff8
@ -48,11 +48,11 @@ for Linux. Command line arguments can be provided in any order.
|
|||||||
Perform ID remapping on all shaders in "*.spv", writing new files with
|
Perform ID remapping on all shaders in "*.spv", writing new files with
|
||||||
the same basenames to /tmp/out_dir.
|
the same basenames to /tmp/out_dir.
|
||||||
|
|
||||||
spirv-remap --map all --input *.spv --output /tmp/out_dir
|
spirv-remap -v --map all --input *.spv --output /tmp/out_dir
|
||||||
|
|
||||||
2. Perform all possible size reductions
|
2. Perform all possible size reductions
|
||||||
|
|
||||||
spirv-remap-linux-64 --do-everything --input *.spv --output /tmp/out_dir
|
spirv-remap-linux-64 -v --do-everything --input *.spv --output /tmp/out_dir
|
||||||
|
|
||||||
Note that --do-everything is a synonym for:
|
Note that --do-everything is a synonym for:
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hash opcode, with special handling for OpExtInst
|
// hash opcode, with special handling for OpExtInst
|
||||||
std::uint32_t spirvbin_t::asOpCodeHash(int word)
|
std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)
|
||||||
{
|
{
|
||||||
const spv::Op opCode = asOpCode(word);
|
const spv::Op opCode = asOpCode(word);
|
||||||
|
|
||||||
@ -196,8 +196,8 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto inst_fn_nop = [](spv::Op, int) { return false; };
|
const auto inst_fn_nop = [](spv::Op, unsigned) { return false; };
|
||||||
const auto op_fn_nop = [](spv::Id&) { };
|
const auto op_fn_nop = [](spv::Id&) { };
|
||||||
|
|
||||||
// g++ doesn't like these defined in the class proper in an anonymous namespace.
|
// g++ doesn't like these defined in the class proper in an anonymous namespace.
|
||||||
// Dunno why. Also MSVC doesn't like the constexpr keyword. Also dunno why.
|
// Dunno why. Also MSVC doesn't like the constexpr keyword. Also dunno why.
|
||||||
@ -242,7 +242,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Parse a literal string from the SPIR binary and return it as an std::string
|
// Parse a literal string from the SPIR binary and return it as an std::string
|
||||||
// Due to C++11 RValue references, this doesn't copy the result string.
|
// Due to C++11 RValue references, this doesn't copy the result string.
|
||||||
std::string spirvbin_t::literalString(int word) const
|
std::string spirvbin_t::literalString(unsigned word) const
|
||||||
{
|
{
|
||||||
std::string literal;
|
std::string literal;
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ namespace spv {
|
|||||||
|
|
||||||
// build local Id and name maps
|
// build local Id and name maps
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
// remember opcodes we want to strip later
|
// remember opcodes we want to strip later
|
||||||
if (isStripOp(opCode))
|
if (isStripOp(opCode))
|
||||||
stripInst(start);
|
stripInst(start);
|
||||||
@ -335,7 +335,7 @@ namespace spv {
|
|||||||
|
|
||||||
// build local Id and name maps
|
// build local Id and name maps
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
// remember opcodes we want to strip later
|
// remember opcodes we want to strip later
|
||||||
if ((options & Options::STRIP) && isStripOp(opCode))
|
if ((options & Options::STRIP) && isStripOp(opCode))
|
||||||
stripInst(start);
|
stripInst(start);
|
||||||
@ -358,7 +358,7 @@ namespace spv {
|
|||||||
assert(fnRes != spv::NoResult);
|
assert(fnRes != spv::NoResult);
|
||||||
if (fnStart == 0)
|
if (fnStart == 0)
|
||||||
error("function end without function start");
|
error("function end without function start");
|
||||||
fnPos[fnRes] = {fnStart, start + asWordCount(start)};
|
fnPos[fnRes] = range_t(fnStart, start + asWordCount(start));
|
||||||
fnStart = 0;
|
fnStart = 0;
|
||||||
} else if (isConstOp(opCode)) {
|
} else if (isConstOp(opCode)) {
|
||||||
assert(asId(start + 2) != spv::NoResult);
|
assert(asId(start + 2) != spv::NoResult);
|
||||||
@ -397,7 +397,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int spirvbin_t::processInstruction(int word, instfn_t instFn, idfn_t idFn)
|
int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)
|
||||||
{
|
{
|
||||||
const auto instructionStart = word;
|
const auto instructionStart = word;
|
||||||
const unsigned wordCount = asWordCount(instructionStart);
|
const unsigned wordCount = asWordCount(instructionStart);
|
||||||
@ -501,19 +501,19 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a pass over all the instructions and process them given appropriate functions
|
// Make a pass over all the instructions and process them given appropriate functions
|
||||||
spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, int begin, int end)
|
spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)
|
||||||
{
|
{
|
||||||
// For efficiency, reserve name map space. It can grow if needed.
|
// For efficiency, reserve name map space. It can grow if needed.
|
||||||
nameMap.reserve(32);
|
nameMap.reserve(32);
|
||||||
|
|
||||||
// If begin or end == 0, use defaults
|
// If begin or end == 0, use defaults
|
||||||
begin = (begin == 0 ? header_size : begin);
|
begin = (begin == 0 ? header_size : begin);
|
||||||
end = (end == 0 ? int(spv.size()) : end);
|
end = (end == 0 ? unsigned(spv.size()) : end);
|
||||||
|
|
||||||
// basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...
|
// basic parsing and InstructionDesc table borrowed from SpvDisassemble.cpp...
|
||||||
int nextInst = int(spv.size());
|
unsigned nextInst = unsigned(spv.size());
|
||||||
|
|
||||||
for (int word = begin; word < end; word = nextInst)
|
for (unsigned word = begin; word < end; word = nextInst)
|
||||||
nextInst = processInstruction(word, instFn, idFn);
|
nextInst = processInstruction(word, instFn, idFn);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -544,13 +544,13 @@ namespace spv {
|
|||||||
// Initial approach: go through some high priority opcodes first and assign them
|
// Initial approach: go through some high priority opcodes first and assign them
|
||||||
// hash values.
|
// hash values.
|
||||||
|
|
||||||
spv::Id fnId = spv::NoResult;
|
spv::Id fnId = spv::NoResult;
|
||||||
std::vector<int> instPos;
|
std::vector<unsigned> instPos;
|
||||||
instPos.reserve(int(spv.size()) / 16); // initial estimate; can grow if needed.
|
instPos.reserve(unsigned(spv.size()) / 16); // initial estimate; can grow if needed.
|
||||||
|
|
||||||
// Build local table of instruction start positions
|
// Build local table of instruction start positions
|
||||||
process(
|
process(
|
||||||
[&](spv::Op, int start) { instPos.push_back(start); return true; },
|
[&](spv::Op, unsigned start) { instPos.push_back(start); return true; },
|
||||||
op_fn_nop);
|
op_fn_nop);
|
||||||
|
|
||||||
// Window size for context-sensitive canonicalization values
|
// Window size for context-sensitive canonicalization values
|
||||||
@ -558,11 +558,11 @@ namespace spv {
|
|||||||
// We essentially performa a little convolution around each instruction,
|
// We essentially performa a little convolution around each instruction,
|
||||||
// to capture the flavor of nearby code, to hopefully match to similar
|
// to capture the flavor of nearby code, to hopefully match to similar
|
||||||
// code in other modules.
|
// code in other modules.
|
||||||
static const int windowSize = 2;
|
static const unsigned windowSize = 2;
|
||||||
|
|
||||||
for (int entry = 0; entry < int(instPos.size()); ++entry) {
|
for (unsigned entry = 0; entry < unsigned(instPos.size()); ++entry) {
|
||||||
const int start = instPos[entry];
|
const unsigned start = instPos[entry];
|
||||||
const spv::Op opCode = asOpCode(start);
|
const spv::Op opCode = asOpCode(start);
|
||||||
|
|
||||||
if (opCode == spv::OpFunction)
|
if (opCode == spv::OpFunction)
|
||||||
fnId = asId(start + 2);
|
fnId = asId(start + 2);
|
||||||
@ -571,20 +571,18 @@ namespace spv {
|
|||||||
fnId = spv::NoResult;
|
fnId = spv::NoResult;
|
||||||
|
|
||||||
if (fnId != spv::NoResult) { // if inside a function
|
if (fnId != spv::NoResult) { // if inside a function
|
||||||
const int word = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
|
if (spv::InstructionDesc[opCode].hasResult()) {
|
||||||
const int result = spv::InstructionDesc[opCode].hasResult() ? word : -1;
|
const unsigned word = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
|
||||||
|
const spv::Id resId = asId(word);
|
||||||
|
std::uint32_t hashval = fnId * 17; // small prime
|
||||||
|
|
||||||
if (result > 0) {
|
for (unsigned i = entry-1; i >= entry-windowSize; --i) {
|
||||||
const spv::Id resId = asId(result);
|
|
||||||
std::uint32_t hashval = fnId * 17; // small prime
|
|
||||||
|
|
||||||
for (int i = entry-1; i >= entry-windowSize; --i) {
|
|
||||||
if (asOpCode(instPos[i]) == spv::OpFunction)
|
if (asOpCode(instPos[i]) == spv::OpFunction)
|
||||||
break;
|
break;
|
||||||
hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
|
hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = entry; i <= entry + windowSize; ++i) {
|
for (unsigned i = entry; i <= entry + windowSize; ++i) {
|
||||||
if (asOpCode(instPos[i]) == spv::OpFunctionEnd)
|
if (asOpCode(instPos[i]) == spv::OpFunctionEnd)
|
||||||
break;
|
break;
|
||||||
hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
|
hashval = hashval * 30103 + asOpCodeHash(instPos[i]); // 30103 = semiarbitrary prime
|
||||||
@ -602,7 +600,7 @@ namespace spv {
|
|||||||
fnId = spv::NoResult;
|
fnId = spv::NoResult;
|
||||||
|
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
switch (opCode) {
|
switch (opCode) {
|
||||||
case spv::OpFunction:
|
case spv::OpFunction:
|
||||||
// Reset counters at each function
|
// Reset counters at each function
|
||||||
@ -645,7 +643,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](spv::Id& id) {
|
[&](spv::Id& id) {
|
||||||
if (thisOpCode != spv::OpNop) {
|
if (thisOpCode != spv::OpNop) {
|
||||||
@ -655,63 +653,9 @@ namespace spv {
|
|||||||
if (isOldIdUnmapped(id))
|
if (isOldIdUnmapped(id))
|
||||||
localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
|
localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NOTDEF
|
|
||||||
// remove bodies of uncalled functions
|
|
||||||
void spirvbin_t::offsetIds()
|
|
||||||
{
|
|
||||||
// Count of how many functions each ID appears within
|
|
||||||
std::unordered_map<spv::Id, int> idFnCount;
|
|
||||||
std::unordered_map<spv::Id, int> idDefinedLoc;
|
|
||||||
idset_t idsUsed; // IDs used in a given function
|
|
||||||
|
|
||||||
int instCount = 0;
|
|
||||||
|
|
||||||
// create a count of how many functions each ID is used within
|
|
||||||
process(
|
|
||||||
[&](spv::OpCode opCode, int start) {
|
|
||||||
++instCount;
|
|
||||||
|
|
||||||
switch (opCode) {
|
|
||||||
case spv::OpFunction:
|
|
||||||
for (const auto id : idsUsed)
|
|
||||||
++idFnCount[id];
|
|
||||||
idsUsed.clear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
const int word = start + (spv::InstructionDesc[opCode].hasType() ? 2 : 1);
|
|
||||||
const int result = spv::InstructionDesc[opCode].hasResult() ? word : -1;
|
|
||||||
|
|
||||||
if (result > 0)
|
|
||||||
idDefinedLoc[asId(result)] = instCount;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
[&](spv::Id& id) { idsUsed.insert(id); });
|
|
||||||
|
|
||||||
// For each ID defined in exactly one function, replace uses by
|
|
||||||
// negative offset to definitions in instructions.
|
|
||||||
|
|
||||||
static const int relOffsetLimit = 64;
|
|
||||||
|
|
||||||
instCount = 0;
|
|
||||||
process([&](spv::OpCode, int) { ++instCount; return false; },
|
|
||||||
[&](spv::Id& id) {
|
|
||||||
if (idFnCount[id] == 1 && (instCount - idDefinedLoc[id]) < relOffsetLimit)
|
|
||||||
id = idDefinedLoc[id] - instCount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// EXPERIMENTAL: forward IO and uniform load/stores into operands
|
// EXPERIMENTAL: forward IO and uniform load/stores into operands
|
||||||
// This produces invalid Schema-0 SPIRV
|
// This produces invalid Schema-0 SPIRV
|
||||||
void spirvbin_t::forwardLoadStores()
|
void spirvbin_t::forwardLoadStores()
|
||||||
@ -721,7 +665,7 @@ namespace spv {
|
|||||||
|
|
||||||
// EXPERIMENTAL: Forward input and access chain loads into consumptions
|
// EXPERIMENTAL: Forward input and access chain loads into consumptions
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
// Add inputs and uniforms to the map
|
// Add inputs and uniforms to the map
|
||||||
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
|
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
|
||||||
(spv[start+3] == spv::StorageClassUniform ||
|
(spv[start+3] == spv::StorageClassUniform ||
|
||||||
@ -738,7 +682,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
|
[&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
|
||||||
);
|
);
|
||||||
@ -748,7 +692,7 @@ namespace spv {
|
|||||||
idMap.clear();
|
idMap.clear();
|
||||||
|
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
// Add inputs and uniforms to the map
|
// Add inputs and uniforms to the map
|
||||||
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
|
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
|
||||||
(spv[start+3] == spv::StorageClassOutput))
|
(spv[start+3] == spv::StorageClassOutput))
|
||||||
@ -760,7 +704,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
op_fn_nop);
|
op_fn_nop);
|
||||||
|
|
||||||
process(
|
process(
|
||||||
@ -781,7 +725,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Find all the function local pointers stored at most once, and not via access chains
|
// Find all the function local pointers stored at most once, and not via access chains
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
const int wordCount = asWordCount(start);
|
const int wordCount = asWordCount(start);
|
||||||
|
|
||||||
// Add local variables to the map
|
// Add local variables to the map
|
||||||
@ -826,34 +770,33 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
op_fn_nop);
|
op_fn_nop);
|
||||||
|
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)
|
if (opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0)
|
||||||
idMap[asId(start+2)] = idMap[asId(start+3)];
|
idMap[asId(start+2)] = idMap[asId(start+3)];
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
op_fn_nop);
|
op_fn_nop);
|
||||||
|
|
||||||
// Remove the load/store/variables for the ones we've discovered
|
// Remove the load/store/variables for the ones we've discovered
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
if ((opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) ||
|
if ((opCode == spv::OpLoad && fnLocalVars.count(asId(start+3)) > 0) ||
|
||||||
(opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||
|
(opCode == spv::OpStore && fnLocalVars.count(asId(start+1)) > 0) ||
|
||||||
(opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {
|
(opCode == spv::OpVariable && fnLocalVars.count(asId(start+2)) > 0)) {
|
||||||
stripInst(start);
|
stripInst(start);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
|
[&](spv::Id& id) { if (idMap.find(id) != idMap.end()) id = idMap[id]; }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
strip(); // strip out data we decided to eliminate
|
strip(); // strip out data we decided to eliminate
|
||||||
buildLocalMaps(); // rebuild ID mapping data
|
buildLocalMaps(); // rebuild ID mapping data
|
||||||
}
|
}
|
||||||
@ -884,7 +827,7 @@ namespace spv {
|
|||||||
|
|
||||||
// decrease counts of called functions
|
// decrease counts of called functions
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
if (opCode == spv::Op::OpFunctionCall) {
|
if (opCode == spv::Op::OpFunctionCall) {
|
||||||
const auto call_it = fnCalls.find(asId(start + 3));
|
const auto call_it = fnCalls.find(asId(start + 3));
|
||||||
if (call_it != fnCalls.end()) {
|
if (call_it != fnCalls.end()) {
|
||||||
@ -894,7 +837,7 @@ namespace spv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
op_fn_nop,
|
op_fn_nop,
|
||||||
fn->second.first,
|
fn->second.first,
|
||||||
fn->second.second);
|
fn->second.second);
|
||||||
@ -914,7 +857,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Count function variable use
|
// Count function variable use
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }
|
if (opCode == spv::OpVariable) { ++varUseCount[asId(start+2)]; return true; }
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -924,7 +867,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Remove single-use function variables + associated decorations and names
|
// Remove single-use function variables + associated decorations and names
|
||||||
process(
|
process(
|
||||||
[&](spv::Op opCode, int start) {
|
[&](spv::Op opCode, unsigned start) {
|
||||||
if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1) ||
|
if ((opCode == spv::OpVariable && varUseCount[asId(start+2)] == 1) ||
|
||||||
(opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1) ||
|
(opCode == spv::OpDecorate && varUseCount[asId(start+1)] == 1) ||
|
||||||
(opCode == spv::OpName && varUseCount[asId(start+1)] == 1)) {
|
(opCode == spv::OpName && varUseCount[asId(start+1)] == 1)) {
|
||||||
@ -1041,7 +984,7 @@ namespace spv {
|
|||||||
#endif // NOTDEF
|
#endif // NOTDEF
|
||||||
|
|
||||||
// Return start position in SPV of given type. error if not found.
|
// Return start position in SPV of given type. error if not found.
|
||||||
int spirvbin_t::typePos(spv::Id id) const
|
unsigned spirvbin_t::typePos(spv::Id id) const
|
||||||
{
|
{
|
||||||
const auto tid_it = typeConstPosR.find(id);
|
const auto tid_it = typeConstPosR.find(id);
|
||||||
if (tid_it == typeConstPosR.end())
|
if (tid_it == typeConstPosR.end())
|
||||||
@ -1052,7 +995,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Hash types to canonical values. This can return ID collisions (it's a bit
|
// Hash types to canonical values. This can return ID collisions (it's a bit
|
||||||
// inevitable): it's up to the caller to handle that gracefully.
|
// inevitable): it's up to the caller to handle that gracefully.
|
||||||
std::uint32_t spirvbin_t::hashType(int typeStart) const
|
std::uint32_t spirvbin_t::hashType(unsigned typeStart) const
|
||||||
{
|
{
|
||||||
const unsigned wordCount = asWordCount(typeStart);
|
const unsigned wordCount = asWordCount(typeStart);
|
||||||
const spv::Op opCode = asOpCode(typeStart);
|
const spv::Op opCode = asOpCode(typeStart);
|
||||||
@ -1160,7 +1103,7 @@ namespace spv {
|
|||||||
|
|
||||||
// Allocate a new binary big enough to hold old binary
|
// Allocate a new binary big enough to hold old binary
|
||||||
// We'll step this iterator through the strip ranges as we go through the binary
|
// We'll step this iterator through the strip ranges as we go through the binary
|
||||||
decltype(stripRange)::const_iterator strip_it = stripRange.begin();
|
auto strip_it = stripRange.begin();
|
||||||
|
|
||||||
int strippedPos = 0;
|
int strippedPos = 0;
|
||||||
for (unsigned word = 0; word < unsigned(spv.size()); ++word) {
|
for (unsigned word = 0; word < unsigned(spv.size()); ++word) {
|
||||||
@ -1201,12 +1144,6 @@ namespace spv {
|
|||||||
mapRemainder(); // map any unmapped IDs
|
mapRemainder(); // map any unmapped IDs
|
||||||
applyMap(); // Now remap each shader to the new IDs we've come up with
|
applyMap(); // Now remap each shader to the new IDs we've come up with
|
||||||
strip(); // strip out data we decided to eliminate
|
strip(); // strip out data we decided to eliminate
|
||||||
|
|
||||||
#define EXPERIMENT3 0
|
|
||||||
#if (EXPERIMENT3)
|
|
||||||
// TODO: ... shortcuts for simple single-const access chains and constants,
|
|
||||||
// folded into high half of the ID space.
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remap from a memory image
|
// remap from a memory image
|
||||||
|
@ -43,7 +43,7 @@ namespace spv {
|
|||||||
|
|
||||||
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
|
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
|
||||||
// We handle that here by making our own symbol.
|
// We handle that here by making our own symbol.
|
||||||
#if __cplusplus >= 201103L || _MSC_VER >= 1800
|
#if __cplusplus >= 201103L || _MSC_VER >= 1700
|
||||||
# define use_cpp11 1
|
# define use_cpp11 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -84,6 +84,7 @@ public:
|
|||||||
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
|
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
|
||||||
{
|
{
|
||||||
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
||||||
|
exit(5);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -137,9 +138,9 @@ private:
|
|||||||
|
|
||||||
typedef std::uint32_t spirword_t;
|
typedef std::uint32_t spirword_t;
|
||||||
|
|
||||||
typedef std::pair<int, int> range_t;
|
typedef std::pair<unsigned, unsigned> range_t;
|
||||||
typedef std::function<void(spv::Id&)> idfn_t;
|
typedef std::function<void(spv::Id&)> idfn_t;
|
||||||
typedef std::function<bool(spv::Op, int start)> instfn_t;
|
typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
|
||||||
|
|
||||||
// Special Values for ID map:
|
// Special Values for ID map:
|
||||||
static const spv::Id unmapped; // unchanged from default value
|
static const spv::Id unmapped; // unchanged from default value
|
||||||
@ -168,14 +169,14 @@ private:
|
|||||||
range_t typeRange(spv::Op opCode) const;
|
range_t typeRange(spv::Op opCode) const;
|
||||||
range_t constRange(spv::Op opCode) const;
|
range_t constRange(spv::Op opCode) const;
|
||||||
|
|
||||||
spv::Id& asId(int word) { return spv[word]; }
|
spv::Id& asId(unsigned word) { return spv[word]; }
|
||||||
const spv::Id& asId(int word) const { return spv[word]; }
|
const spv::Id& asId(unsigned word) const { return spv[word]; }
|
||||||
spv::Op asOpCode(int word) const { return opOpCode(spv[word]); }
|
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
|
||||||
std::uint32_t asOpCodeHash(int word);
|
std::uint32_t asOpCodeHash(unsigned word);
|
||||||
spv::Decoration asDecoration(int word) const { return spv::Decoration(spv[word]); }
|
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
|
||||||
unsigned asWordCount(int word) const { return opWordCount(spv[word]); }
|
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
|
||||||
spv::Id asTypeConstId(int word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
|
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
|
||||||
int typePos(spv::Id id) const;
|
unsigned typePos(spv::Id id) const;
|
||||||
|
|
||||||
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
||||||
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
||||||
@ -201,7 +202,7 @@ private:
|
|||||||
inline spv::Id nextUnusedId(spv::Id id);
|
inline spv::Id nextUnusedId(spv::Id id);
|
||||||
|
|
||||||
void buildLocalMaps();
|
void buildLocalMaps();
|
||||||
std::string literalString(int word) const; // Return literal as a std::string
|
std::string literalString(unsigned word) const; // Return literal as a std::string
|
||||||
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
|
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
|
||||||
|
|
||||||
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
|
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
|
||||||
@ -212,10 +213,10 @@ private:
|
|||||||
|
|
||||||
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
|
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
|
||||||
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
|
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
|
||||||
std::uint32_t hashType(int typeStart) const;
|
std::uint32_t hashType(unsigned typeStart) const;
|
||||||
|
|
||||||
spirvbin_t& process(instfn_t, idfn_t, int begin = 0, int end = 0);
|
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
|
||||||
int processInstruction(int word, instfn_t, idfn_t);
|
int processInstruction(unsigned word, instfn_t, idfn_t);
|
||||||
|
|
||||||
void validate() const;
|
void validate() const;
|
||||||
void mapTypeConst();
|
void mapTypeConst();
|
||||||
@ -251,12 +252,12 @@ private:
|
|||||||
|
|
||||||
// Add a strip range for a given instruction starting at 'start'
|
// Add a strip range for a given instruction starting at 'start'
|
||||||
// Note: avoiding brace initializers to please older versions os MSVC.
|
// Note: avoiding brace initializers to please older versions os MSVC.
|
||||||
void stripInst(int start) { stripRange.push_back(std::pair<unsigned, unsigned>(start, start + asWordCount(start))); }
|
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
|
||||||
|
|
||||||
// Function start and end. use unordered_map because we'll have
|
// Function start and end. use unordered_map because we'll have
|
||||||
// many fewer functions than IDs.
|
// many fewer functions than IDs.
|
||||||
std::unordered_map<spv::Id, std::pair<int, int>> fnPos;
|
std::unordered_map<spv::Id, range_t> fnPos;
|
||||||
std::unordered_map<spv::Id, std::pair<int, int>> fnPosDCE; // deleted functions
|
std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
|
||||||
|
|
||||||
// Which functions are called, anywhere in the module, with a call count
|
// Which functions are called, anywhere in the module, with a call count
|
||||||
std::unordered_map<spv::Id, int> fnCalls;
|
std::unordered_map<spv::Id, int> fnCalls;
|
||||||
@ -270,7 +271,7 @@ private:
|
|||||||
spv::Id largestNewId; // biggest new ID we have mapped anything to
|
spv::Id largestNewId; // biggest new ID we have mapped anything to
|
||||||
|
|
||||||
// Sections of the binary to strip, given as [begin,end)
|
// Sections of the binary to strip, given as [begin,end)
|
||||||
std::vector<std::pair<unsigned, unsigned>> stripRange;
|
std::vector<range_t> stripRange;
|
||||||
|
|
||||||
// processing options:
|
// processing options:
|
||||||
std::uint32_t options;
|
std::uint32_t options;
|
||||||
|
@ -33,304 +33,305 @@
|
|||||||
//POSSIBILITY OF SUCH DAMAGE.
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "../SPIRV/SPVRemapper.h"
|
#include "../SPIRV/SPVRemapper.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef unsigned int SpvWord;
|
typedef unsigned int SpvWord;
|
||||||
|
|
||||||
// Poor man's basename: given a complete path, return file portion.
|
// Poor man's basename: given a complete path, return file portion.
|
||||||
// E.g:
|
// E.g:
|
||||||
// Linux: /foo/bar/test -> test
|
// Linux: /foo/bar/test -> test
|
||||||
// Win: c:\foo\bar\test -> test
|
// Win: c:\foo\bar\test -> test
|
||||||
// It's not very efficient, but that doesn't matter for our minimal-duty use.
|
// It's not very efficient, but that doesn't matter for our minimal-duty use.
|
||||||
// Using boost::filesystem would be better in many ways, but want to avoid that dependency.
|
// Using boost::filesystem would be better in many ways, but want to avoid that dependency.
|
||||||
|
|
||||||
// OS dependent path separator (avoiding boost::filesystem dependency)
|
// OS dependent path separator (avoiding boost::filesystem dependency)
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
char path_sep_char() { return '\\'; }
|
char path_sep_char() { return '\\'; }
|
||||||
#else
|
#else
|
||||||
char path_sep_char() { return '/'; }
|
char path_sep_char() { return '/'; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string basename(const std::string filename)
|
std::string basename(const std::string filename)
|
||||||
{
|
{
|
||||||
const size_t sepLoc = filename.find_last_of(path_sep_char());
|
const size_t sepLoc = filename.find_last_of(path_sep_char());
|
||||||
|
|
||||||
return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
|
return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void errHandler(const std::string& str) {
|
void errHandler(const std::string& str) {
|
||||||
std::cout << str << std::endl;
|
std::cout << str << std::endl;
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logHandler(const std::string& str) {
|
void logHandler(const std::string& str) {
|
||||||
std::cout << str << std::endl;
|
std::cout << str << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read word stream from disk
|
// Read word stream from disk
|
||||||
void read(std::vector<SpvWord>& spv, const std::string& inFilename)
|
void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
|
||||||
{
|
{
|
||||||
std::ifstream fp;
|
std::ifstream fp;
|
||||||
|
|
||||||
std::cout << " reading: " << inFilename << std::endl;
|
if (verbosity > 0)
|
||||||
|
logHandler(std::string(" reading: ") + inFilename);
|
||||||
spv.clear();
|
|
||||||
fp.open(inFilename, std::fstream::in | std::fstream::binary);
|
spv.clear();
|
||||||
|
fp.open(inFilename, std::fstream::in | std::fstream::binary);
|
||||||
if (fp.fail())
|
|
||||||
errHandler("error opening file for read: ");
|
if (fp.fail())
|
||||||
|
errHandler("error opening file for read: ");
|
||||||
// Reserve space (for efficiency, not for correctness)
|
|
||||||
fp.seekg(0, fp.end);
|
// Reserve space (for efficiency, not for correctness)
|
||||||
spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
|
fp.seekg(0, fp.end);
|
||||||
fp.seekg(0, fp.beg);
|
spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
|
||||||
|
fp.seekg(0, fp.beg);
|
||||||
while (!fp.eof()) {
|
|
||||||
SpvWord inWord;
|
while (!fp.eof()) {
|
||||||
fp.read((char *)&inWord, sizeof(inWord));
|
SpvWord inWord;
|
||||||
|
fp.read((char *)&inWord, sizeof(inWord));
|
||||||
if (!fp.eof()) {
|
|
||||||
spv.push_back(inWord);
|
if (!fp.eof()) {
|
||||||
if (fp.fail())
|
spv.push_back(inWord);
|
||||||
errHandler(std::string("error reading file: ") + inFilename);
|
if (fp.fail())
|
||||||
}
|
errHandler(std::string("error reading file: ") + inFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void write(std::vector<SpvWord>& spv, const std::string& outFile)
|
|
||||||
{
|
void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
|
||||||
if (outFile.empty())
|
{
|
||||||
errHandler("missing output filename.");
|
if (outFile.empty())
|
||||||
|
errHandler("missing output filename.");
|
||||||
std::ofstream fp;
|
|
||||||
|
std::ofstream fp;
|
||||||
std::cout << " writing: " << outFile << std::endl;
|
|
||||||
|
if (verbosity > 0)
|
||||||
fp.open(outFile, std::fstream::out | std::fstream::binary);
|
logHandler(std::string(" writing: ") + outFile);
|
||||||
|
|
||||||
if (fp.fail())
|
fp.open(outFile, std::fstream::out | std::fstream::binary);
|
||||||
errHandler(std::string("error opening file for write: ") + outFile);
|
|
||||||
|
if (fp.fail())
|
||||||
for (auto word : spv) {
|
errHandler(std::string("error opening file for write: ") + outFile);
|
||||||
fp.write((char *)&word, sizeof(word));
|
|
||||||
if (fp.fail())
|
for (auto word : spv) {
|
||||||
errHandler(std::string("error writing file: ") + outFile);
|
fp.write((char *)&word, sizeof(word));
|
||||||
}
|
if (fp.fail())
|
||||||
|
errHandler(std::string("error writing file: ") + outFile);
|
||||||
// file is closed by destructor
|
}
|
||||||
}
|
|
||||||
|
// file is closed by destructor
|
||||||
// Print helpful usage message to stdout, and exit
|
}
|
||||||
void usage(const char* const name, const char* const msg = 0)
|
|
||||||
{
|
// Print helpful usage message to stdout, and exit
|
||||||
if (msg)
|
void usage(const char* const name, const char* const msg = 0)
|
||||||
std::cout << msg << std::endl << std::endl;
|
{
|
||||||
|
if (msg)
|
||||||
std::cout << "Usage: " << std::endl;
|
std::cout << msg << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " " << basename(name)
|
std::cout << "Usage: " << std::endl;
|
||||||
<< " [-v[v[...]] | --verbose [int]]"
|
|
||||||
<< " [--map (all|types|names|funcs)]"
|
std::cout << " " << basename(name)
|
||||||
<< " [--dce (all|types|funcs)]"
|
<< " [-v[v[...]] | --verbose [int]]"
|
||||||
<< " [--opt (all|loadstore)]"
|
<< " [--map (all|types|names|funcs)]"
|
||||||
<< " [--strip-all | --strip all | -s]"
|
<< " [--dce (all|types|funcs)]"
|
||||||
<< " [--do-everything]"
|
<< " [--opt (all|loadstore)]"
|
||||||
<< " --input | -i file1 [file2...] --output|-o DESTDIR"
|
<< " [--strip-all | --strip all | -s]"
|
||||||
<< std::endl;
|
<< " [--do-everything]"
|
||||||
|
<< " --input | -i file1 [file2...] --output|-o DESTDIR"
|
||||||
std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
|
<< std::endl;
|
||||||
std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
|
|
||||||
|
std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
|
||||||
exit(5);
|
std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
|
||||||
}
|
|
||||||
|
exit(5);
|
||||||
// grind through each SPIR in turn
|
}
|
||||||
void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
|
|
||||||
int opts, int verbosity)
|
// grind through each SPIR in turn
|
||||||
{
|
void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
|
||||||
for (const auto& filename : inputFile) {
|
int opts, int verbosity)
|
||||||
std::vector<SpvWord> spv;
|
{
|
||||||
read(spv, filename);
|
for (const auto& filename : inputFile) {
|
||||||
spv::spirvbin_t(verbosity).remap(spv, opts);
|
std::vector<SpvWord> spv;
|
||||||
|
read(spv, filename, verbosity);
|
||||||
const std::string outfile = outputDir + path_sep_char() + basename(filename);
|
spv::spirvbin_t(verbosity).remap(spv, opts);
|
||||||
|
|
||||||
write(spv, outfile);
|
const std::string outfile = outputDir + path_sep_char() + basename(filename);
|
||||||
}
|
|
||||||
|
write(spv, outfile, verbosity);
|
||||||
if (verbosity > 0)
|
}
|
||||||
std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
|
|
||||||
}
|
if (verbosity > 0)
|
||||||
|
std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
|
||||||
// Parse command line options
|
}
|
||||||
void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
|
|
||||||
std::string& outputDir,
|
// Parse command line options
|
||||||
int& options,
|
void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
|
||||||
int& verbosity)
|
std::string& outputDir,
|
||||||
{
|
int& options,
|
||||||
if (argc < 2)
|
int& verbosity)
|
||||||
usage(argv[0]);
|
{
|
||||||
|
if (argc < 2)
|
||||||
verbosity = 0;
|
usage(argv[0]);
|
||||||
options = spv::spirvbin_t::Options::NONE;
|
|
||||||
|
verbosity = 0;
|
||||||
// Parse command line.
|
options = spv::spirvbin_t::Options::NONE;
|
||||||
// boost::program_options would be quite a bit nicer, but we don't want to
|
|
||||||
// introduce a dependency on boost.
|
// Parse command line.
|
||||||
for (int a=1; a<argc; ) {
|
// boost::program_options would be quite a bit nicer, but we don't want to
|
||||||
const std::string arg = argv[a];
|
// introduce a dependency on boost.
|
||||||
|
for (int a=1; a<argc; ) {
|
||||||
if (arg == "--output" || arg == "-o") {
|
const std::string arg = argv[a];
|
||||||
// Output directory
|
|
||||||
if (++a >= argc)
|
if (arg == "--output" || arg == "-o") {
|
||||||
usage(argv[0], "--output requires an argument");
|
// Output directory
|
||||||
if (!outputDir.empty())
|
if (++a >= argc)
|
||||||
usage(argv[0], "--output can be provided only once");
|
usage(argv[0], "--output requires an argument");
|
||||||
|
if (!outputDir.empty())
|
||||||
outputDir = argv[a++];
|
usage(argv[0], "--output can be provided only once");
|
||||||
|
|
||||||
// Remove trailing directory separator characters
|
outputDir = argv[a++];
|
||||||
while (!outputDir.empty() && outputDir.back() == path_sep_char())
|
|
||||||
outputDir.pop_back();
|
// Remove trailing directory separator characters
|
||||||
|
while (!outputDir.empty() && outputDir.back() == path_sep_char())
|
||||||
}
|
outputDir.pop_back();
|
||||||
else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
|
|
||||||
else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
|
}
|
||||||
else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
|
else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
|
||||||
else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
|
else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
|
||||||
|
else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
|
||||||
else if (arg == "--verbose" || arg == "-v") {
|
else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
|
||||||
++a;
|
|
||||||
verbosity = 1;
|
else if (arg == "--verbose" || arg == "-v") {
|
||||||
|
++a;
|
||||||
if (a < argc) {
|
verbosity = 1;
|
||||||
try {
|
|
||||||
verbosity = std::stoi(argv[a]);
|
if (a < argc) {
|
||||||
++a;
|
try {
|
||||||
} catch (const std::invalid_argument&) { } // ok to have no numeric value
|
verbosity = std::stoi(argv[a]);
|
||||||
}
|
++a;
|
||||||
}
|
} catch (const std::invalid_argument&) { } // ok to have no numeric value
|
||||||
else if (arg == "--version" || arg == "-V") {
|
}
|
||||||
std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
|
}
|
||||||
exit(0);
|
else if (arg == "--version" || arg == "-V") {
|
||||||
} else if (arg == "--input" || arg == "-i") {
|
std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
|
||||||
// Collect input files
|
exit(0);
|
||||||
for (++a; a < argc && argv[a][0] != '-'; ++a)
|
} else if (arg == "--input" || arg == "-i") {
|
||||||
inputFile.push_back(argv[a]);
|
// Collect input files
|
||||||
} else if (arg == "--do-everything") {
|
for (++a; a < argc && argv[a][0] != '-'; ++a)
|
||||||
++a;
|
inputFile.push_back(argv[a]);
|
||||||
options = options | spv::spirvbin_t::Options::DO_EVERYTHING;
|
} else if (arg == "--do-everything") {
|
||||||
} else if (arg == "--strip-all" || arg == "-s") {
|
++a;
|
||||||
++a;
|
options = options | spv::spirvbin_t::Options::DO_EVERYTHING;
|
||||||
options = options | spv::spirvbin_t::Options::STRIP;
|
} else if (arg == "--strip-all" || arg == "-s") {
|
||||||
} else if (arg == "--strip") {
|
++a;
|
||||||
++a;
|
options = options | spv::spirvbin_t::Options::STRIP;
|
||||||
if (strncmp(argv[a], "all", 3) == 0) {
|
} else if (arg == "--strip") {
|
||||||
options = options | spv::spirvbin_t::Options::STRIP;
|
++a;
|
||||||
++a;
|
if (strncmp(argv[a], "all", 3) == 0) {
|
||||||
}
|
options = options | spv::spirvbin_t::Options::STRIP;
|
||||||
} else if (arg == "--dce") {
|
++a;
|
||||||
// Parse comma (or colon, etc) separated list of things to dce
|
}
|
||||||
++a;
|
} else if (arg == "--dce") {
|
||||||
for (const char* c = argv[a]; *c; ++c) {
|
// Parse comma (or colon, etc) separated list of things to dce
|
||||||
if (strncmp(c, "all", 3) == 0) {
|
++a;
|
||||||
options = (options | spv::spirvbin_t::Options::DCE_ALL);
|
for (const char* c = argv[a]; *c; ++c) {
|
||||||
c += 3;
|
if (strncmp(c, "all", 3) == 0) {
|
||||||
} else if (strncmp(c, "*", 1) == 0) {
|
options = (options | spv::spirvbin_t::Options::DCE_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::DCE_ALL);
|
c += 3;
|
||||||
c += 1;
|
} else if (strncmp(c, "*", 1) == 0) {
|
||||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
options = (options | spv::spirvbin_t::Options::DCE_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::DCE_FUNCS);
|
c += 1;
|
||||||
c += 5;
|
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||||
} else if (strncmp(c, "types", 5) == 0) {
|
options = (options | spv::spirvbin_t::Options::DCE_FUNCS);
|
||||||
options = (options | spv::spirvbin_t::Options::DCE_TYPES);
|
c += 5;
|
||||||
c += 5;
|
} else if (strncmp(c, "types", 5) == 0) {
|
||||||
}
|
options = (options | spv::spirvbin_t::Options::DCE_TYPES);
|
||||||
}
|
c += 5;
|
||||||
++a;
|
}
|
||||||
} else if (arg == "--map") {
|
}
|
||||||
// Parse comma (or colon, etc) separated list of things to map
|
++a;
|
||||||
++a;
|
} else if (arg == "--map") {
|
||||||
for (const char* c = argv[a]; *c; ++c) {
|
// Parse comma (or colon, etc) separated list of things to map
|
||||||
if (strncmp(c, "all", 3) == 0) {
|
++a;
|
||||||
options = (options | spv::spirvbin_t::Options::MAP_ALL);
|
for (const char* c = argv[a]; *c; ++c) {
|
||||||
c += 3;
|
if (strncmp(c, "all", 3) == 0) {
|
||||||
} else if (strncmp(c, "*", 1) == 0) {
|
options = (options | spv::spirvbin_t::Options::MAP_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::MAP_ALL);
|
c += 3;
|
||||||
c += 1;
|
} else if (strncmp(c, "*", 1) == 0) {
|
||||||
} else if (strncmp(c, "types", 5) == 0) {
|
options = (options | spv::spirvbin_t::Options::MAP_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::MAP_TYPES);
|
c += 1;
|
||||||
c += 5;
|
} else if (strncmp(c, "types", 5) == 0) {
|
||||||
} else if (strncmp(c, "names", 5) == 0) {
|
options = (options | spv::spirvbin_t::Options::MAP_TYPES);
|
||||||
options = (options | spv::spirvbin_t::Options::MAP_NAMES);
|
c += 5;
|
||||||
c += 5;
|
} else if (strncmp(c, "names", 5) == 0) {
|
||||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
options = (options | spv::spirvbin_t::Options::MAP_NAMES);
|
||||||
options = (options | spv::spirvbin_t::Options::MAP_FUNCS);
|
c += 5;
|
||||||
c += 5;
|
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||||
}
|
options = (options | spv::spirvbin_t::Options::MAP_FUNCS);
|
||||||
}
|
c += 5;
|
||||||
++a;
|
}
|
||||||
} else if (arg == "--opt") {
|
}
|
||||||
++a;
|
++a;
|
||||||
for (const char* c = argv[a]; *c; ++c) {
|
} else if (arg == "--opt") {
|
||||||
if (strncmp(c, "all", 3) == 0) {
|
++a;
|
||||||
options = (options | spv::spirvbin_t::Options::OPT_ALL);
|
for (const char* c = argv[a]; *c; ++c) {
|
||||||
c += 3;
|
if (strncmp(c, "all", 3) == 0) {
|
||||||
} else if (strncmp(c, "*", 1) == 0) {
|
options = (options | spv::spirvbin_t::Options::OPT_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::OPT_ALL);
|
c += 3;
|
||||||
c += 1;
|
} else if (strncmp(c, "*", 1) == 0) {
|
||||||
} else if (strncmp(c, "loadstore", 9) == 0) {
|
options = (options | spv::spirvbin_t::Options::OPT_ALL);
|
||||||
options = (options | spv::spirvbin_t::Options::OPT_LOADSTORE);
|
c += 1;
|
||||||
c += 9;
|
} else if (strncmp(c, "loadstore", 9) == 0) {
|
||||||
}
|
options = (options | spv::spirvbin_t::Options::OPT_LOADSTORE);
|
||||||
}
|
c += 9;
|
||||||
++a;
|
}
|
||||||
} else if (arg == "--help" || arg == "-?") {
|
}
|
||||||
usage(argv[0]);
|
++a;
|
||||||
} else {
|
} else if (arg == "--help" || arg == "-?") {
|
||||||
usage(argv[0], "Unknown command line option");
|
usage(argv[0]);
|
||||||
}
|
} else {
|
||||||
}
|
usage(argv[0], "Unknown command line option");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // namespace
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
#ifdef use_cpp11
|
int main(int argc, char** argv)
|
||||||
std::vector<std::string> inputFile;
|
{
|
||||||
std::string outputDir;
|
std::vector<std::string> inputFile;
|
||||||
int opts;
|
std::string outputDir;
|
||||||
int verbosity;
|
int opts;
|
||||||
|
int verbosity;
|
||||||
// handle errors by exiting
|
|
||||||
spv::spirvbin_t::registerErrorHandler(errHandler);
|
#ifdef use_cpp11
|
||||||
|
// handle errors by exiting
|
||||||
// Log messages to std::cout
|
spv::spirvbin_t::registerErrorHandler(errHandler);
|
||||||
spv::spirvbin_t::registerLogHandler(logHandler);
|
|
||||||
|
// Log messages to std::cout
|
||||||
if (argc < 2)
|
spv::spirvbin_t::registerLogHandler(logHandler);
|
||||||
usage(argv[0]);
|
#endif
|
||||||
|
|
||||||
parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
|
if (argc < 2)
|
||||||
|
usage(argv[0]);
|
||||||
if (outputDir.empty())
|
|
||||||
usage(argv[0], "Output directory required");
|
parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
|
||||||
|
|
||||||
std::string errmsg;
|
if (outputDir.empty())
|
||||||
|
usage(argv[0], "Output directory required");
|
||||||
// Main operations: read, remap, and write.
|
|
||||||
execute(inputFile, outputDir, opts, verbosity);
|
std::string errmsg;
|
||||||
|
|
||||||
#endif
|
// Main operations: read, remap, and write.
|
||||||
|
execute(inputFile, outputDir, opts, verbosity);
|
||||||
// If we get here, everything went OK! Nothing more to be done.
|
|
||||||
}
|
// If we get here, everything went OK! Nothing more to be done.
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user