Make friendly names for built-in variables.

Handles only OpDecorate

Does not handle:
- decorations on struct members
- decoration via OpGroupDecorate
This commit is contained in:
David Neto 2016-09-13 12:38:42 -04:00
parent 247e024c72
commit e0dd033414
4 changed files with 158 additions and 3 deletions

View File

@ -1,6 +1,7 @@
Revision history for SPIRV-Tools
v2016.5-dev 2016-09-12
- Disassembler: Generate friendly names for built-in variables.
- Partial fixes:
#359: Add Emacs helper for automatically diassembling/assembling a SPIR-V
binary on file load/save.

View File

@ -14,6 +14,7 @@
#include "name_mapper.h"
#include <cassert>
#include <algorithm>
#include <iterator>
#include <sstream>
@ -95,6 +96,70 @@ void FriendlyNameMapper::SaveName(uint32_t id,
name_for_id_[id] = name;
}
void FriendlyNameMapper::SaveBuiltInName(uint32_t target_id,
uint32_t built_in) {
#define GLCASE(name) \
case SpvBuiltIn##name: \
SaveName(target_id, "gl_" #name); \
return;
#define GLCASE2(name, suggested) \
case SpvBuiltIn##name: \
SaveName(target_id, "gl_" #suggested); \
return;
#define CASE(name) \
case SpvBuiltIn##name: \
SaveName(target_id, #name); \
return;
switch (built_in) {
GLCASE(Position)
GLCASE(PointSize)
GLCASE(ClipDistance)
GLCASE(CullDistance)
GLCASE2(VertexId, VertexID)
GLCASE2(InstanceId, InstanceID)
GLCASE2(PrimitiveId, PrimitiveID)
GLCASE2(InvocationId, InvocationID)
GLCASE(Layer)
GLCASE(ViewportIndex)
GLCASE(TessLevelOuter)
GLCASE(TessLevelInner)
GLCASE(TessCoord)
GLCASE(PatchVertices)
GLCASE(FragCoord)
GLCASE(PointCoord)
GLCASE(FrontFacing)
GLCASE2(SampleId, SampleID)
GLCASE(SamplePosition)
GLCASE(SampleMask)
GLCASE(FragDepth)
GLCASE(HelperInvocation)
GLCASE2(NumWorkgroups, NumWorkGroups)
GLCASE2(WorkgroupSize, WorkGroupSize)
GLCASE2(WorkgroupId, WorkGroupID)
GLCASE2(LocalInvocationId, LocalInvocationID)
GLCASE2(GlobalInvocationId, GlobalInvocationID)
GLCASE(LocalInvocationIndex)
CASE(WorkDim)
CASE(GlobalSize)
CASE(EnqueuedWorkgroupSize)
CASE(GlobalOffset)
CASE(GlobalLinearId)
CASE(SubgroupSize)
CASE(SubgroupMaxSize)
CASE(NumSubgroups)
CASE(NumEnqueuedSubgroups)
CASE(SubgroupId)
CASE(SubgroupLocalInvocationId)
GLCASE(VertexIndex)
GLCASE(InstanceIndex)
default:
break;
}
#undef GLCASE
#undef GLCASE2
#undef CASE
}
spv_result_t FriendlyNameMapper::ParseInstruction(
const spv_parsed_instruction_t& inst) {
const auto result_id = inst.result_id;
@ -102,6 +167,17 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
case SpvOpName:
SaveName(inst.words[1], reinterpret_cast<const char*>(inst.words + 2));
break;
case SpvOpDecorate:
// Decorations come after OpName. So OpName will take precedence over
// decorations.
//
// In theory, we should also handle OpGroupDecorate. But that's unlikely
// to occur.
if (inst.words[2] == SpvDecorationBuiltIn) {
assert(inst.num_words > 3);
SaveBuiltInName(inst.words[1], inst.words[3]);
}
break;
case SpvOpTypeVoid:
SaveName(result_id, "void");
break;

View File

@ -56,6 +56,7 @@ NameMapper GetTrivialNameMapper();
// human readable names.
// - A struct type maps to "_struct_" followed by the raw Id number. That's
// pretty simplistic, but workable.
// - A built-in variable maps to its GLSL variable name.
class FriendlyNameMapper {
public:
// Construct a friendly name mapper, and determine friendly names for each
@ -80,11 +81,16 @@ class FriendlyNameMapper {
// assembly language. Two distinct inputs can map to the same output.
std::string Sanitize(const std::string& suggested_name);
// Records a name for the given id. Use the given suggested_name if it
// hasn't already been taken, and otherwise generate a new (unused) name
// based on the suggested name.
// Records a name for the given id. If this id already has a name, then
// this is a no-op. If the id doesn't have a name, use the given
// suggested_name if it hasn't already been taken, and otherwise generate
// a new (unused) name based on the suggested name.
void SaveName(uint32_t id, const std::string& suggested_name);
// Records a built-in variable name for target_id. If target_id already
// has a name then this is a no-op.
void SaveBuiltInName(uint32_t target_id, uint32_t built_in);
// Collects information from the given parsed instruction to populate
// name_for_id_. Returns SPV_SUCCESS;
spv_result_t ParseInstruction(const spv_parsed_instruction_t& inst);

View File

@ -205,4 +205,76 @@ INSTANTIATE_TEST_CASE_P(ExoticTypes, FriendlyNameTest,
{"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"},
}), );
// Makes a test case for a BuiltIn variable declaration.
NameIdCase BuiltInCase(std::string assembly_name, std::string expected) {
return NameIdCase{std::string("OpDecorate %1 BuiltIn ") + assembly_name +
" %1 = OpVariable %2 Input",
1, expected};
}
// Makes a test case for a BuiltIn variable declaration. In this overload,
// the expected result is the same as the assembly name.
NameIdCase BuiltInCase(std::string assembly_name) {
return BuiltInCase(assembly_name, assembly_name);
}
// Makes a test case for a BuiltIn variable declaration. In this overload,
// the expected result is the same as the assembly name, but with a "gl_"
// prefix.
NameIdCase BuiltInGLCase(std::string assembly_name) {
return BuiltInCase(assembly_name, std::string("gl_") + assembly_name);
}
INSTANTIATE_TEST_CASE_P(
BuiltIns, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
BuiltInGLCase("Position"),
BuiltInGLCase("PointSize"),
BuiltInGLCase("ClipDistance"),
BuiltInGLCase("CullDistance"),
BuiltInCase("VertexId", "gl_VertexID"),
BuiltInCase("InstanceId", "gl_InstanceID"),
BuiltInCase("PrimitiveId", "gl_PrimitiveID"),
BuiltInCase("InvocationId", "gl_InvocationID"),
BuiltInGLCase("Layer"),
BuiltInGLCase("ViewportIndex"),
BuiltInGLCase("TessLevelOuter"),
BuiltInGLCase("TessLevelInner"),
BuiltInGLCase("TessCoord"),
BuiltInGLCase("PatchVertices"),
BuiltInGLCase("FragCoord"),
BuiltInGLCase("PointCoord"),
BuiltInGLCase("FrontFacing"),
BuiltInCase("SampleId", "gl_SampleID"),
BuiltInGLCase("SamplePosition"),
BuiltInGLCase("SampleMask"),
BuiltInGLCase("FragDepth"),
BuiltInGLCase("HelperInvocation"),
BuiltInCase("NumWorkgroups", "gl_NumWorkGroups"),
BuiltInCase("WorkgroupSize", "gl_WorkGroupSize"),
BuiltInCase("WorkgroupId", "gl_WorkGroupID"),
BuiltInCase("LocalInvocationId", "gl_LocalInvocationID"),
BuiltInCase("GlobalInvocationId", "gl_GlobalInvocationID"),
BuiltInGLCase("LocalInvocationIndex"),
BuiltInCase("WorkDim"),
BuiltInCase("GlobalSize"),
BuiltInCase("EnqueuedWorkgroupSize"),
BuiltInCase("GlobalOffset"),
BuiltInCase("GlobalLinearId"),
BuiltInCase("SubgroupSize"),
BuiltInCase("SubgroupMaxSize"),
BuiltInCase("NumSubgroups"),
BuiltInCase("NumEnqueuedSubgroups"),
BuiltInCase("SubgroupId"),
BuiltInCase("SubgroupLocalInvocationId"),
BuiltInGLCase("VertexIndex"),
BuiltInGLCase("InstanceIndex"),
}), );
INSTANTIATE_TEST_CASE_P(DebugNameOverridesBuiltin, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"OpName %1 \"foo\" OpDecorate %1 BuiltIn WorkDim "
"%1 = OpVariable %2 Input",
1, "foo"}}), );
} // anonymous namespace