mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-26 09:41:03 +00:00
Add basic support for SPV_KHR_shader_ballot
Requires use of SPIRV-Headers that has support for SPV_KHR_shader_ballot. Adds assembler, disassembler, binary parser support. Adds general support for allowing an operand to be only enabled by a set of extensions. TODO: Validator support for extension checking.
This commit is contained in:
parent
8654caa565
commit
9382035a22
3
CHANGES
3
CHANGES
@ -1,6 +1,7 @@
|
||||
Revision history for SPIRV-Tools
|
||||
|
||||
v2016.5-dev 2016-09-12
|
||||
v2016.5-dev 2016-09-16
|
||||
- Support SPV_KHR_shader_ballot in assembler, disassembler, parser.
|
||||
- Disassembler: Generate friendly names for built-in variables.
|
||||
- Partial fixes:
|
||||
#359: Add Emacs helper for automatically diassembling/assembling a SPIR-V
|
||||
|
@ -21,6 +21,18 @@
|
||||
#include "message.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
// The known SPIR-V extensions.
|
||||
// TODO(dneto): Consider auto-generating this list?
|
||||
enum class Extension {
|
||||
kSPV_KHR_shader_ballot
|
||||
};
|
||||
|
||||
using ExtensionSet = EnumSet<Extension>;
|
||||
|
||||
} // namespace libspirv
|
||||
|
||||
typedef struct spv_opcode_desc_t {
|
||||
const char* name;
|
||||
const SpvOp opcode;
|
||||
@ -38,6 +50,12 @@ typedef struct spv_operand_desc_t {
|
||||
const char* name;
|
||||
const uint32_t value;
|
||||
const libspirv::CapabilitySet capabilities;
|
||||
// A set of extensions that enable this feature. If empty then this operand
|
||||
// value is always enabled, i.e. it's in core. The assembler, binary parser,
|
||||
// and disassembler ignore this rule, so you can freely process invalid
|
||||
// modules.
|
||||
// TODO(dneto): Add validator support to check extensions.
|
||||
const libspirv::ExtensionSet extensions;
|
||||
const spv_operand_type_t operandTypes[16]; // TODO: Smaller/larger?
|
||||
} spv_operand_desc_t;
|
||||
|
||||
|
@ -28,7 +28,10 @@ using spvtest::Concatenate;
|
||||
using spvtest::MakeInstruction;
|
||||
using spvtest::MakeVector;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using ::testing::Combine;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
|
||||
EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
|
||||
@ -86,4 +89,60 @@ TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
|
||||
}
|
||||
|
||||
|
||||
// SPV_KHR_shader_ballot
|
||||
|
||||
// A test case for assembling into words in an instruction.
|
||||
struct AssemblyCase {
|
||||
std::string input;
|
||||
std::vector<uint32_t> expected;
|
||||
};
|
||||
|
||||
using SPV_KHR_shader_ballot_Test = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
|
||||
|
||||
TEST_P(SPV_KHR_shader_ballot_Test, Samples) {
|
||||
const spv_target_env& env = std::get<0>(GetParam());
|
||||
const AssemblyCase& ac = std::get<1>(GetParam());
|
||||
|
||||
// Check that it assembles correctly.
|
||||
EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
|
||||
|
||||
// Check round trip through the disassembler.
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE, env),
|
||||
Eq(ac.input));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Assembly, SPV_KHR_shader_ballot_Test,
|
||||
// We'll get coverage over operand tables by trying the universal
|
||||
// environments, and at least one specific environment.
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_VULKAN_1_0),
|
||||
ValuesIn(std::vector<AssemblyCase>{
|
||||
{"OpCapability SubgroupBallotKHR\n",
|
||||
MakeInstruction(SpvOpCapability,
|
||||
{SpvCapabilitySubgroupBallotKHR})},
|
||||
{"%2 = OpSubgroupBallotKHR %1 %3\n",
|
||||
MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
|
||||
{"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
|
||||
MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
|
||||
{"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
|
||||
MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
|
||||
SpvBuiltInSubgroupEqMaskKHR})},
|
||||
{"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
|
||||
MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
|
||||
SpvBuiltInSubgroupGeMaskKHR})},
|
||||
{"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
|
||||
MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
|
||||
SpvBuiltInSubgroupGtMaskKHR})},
|
||||
{"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
|
||||
MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
|
||||
SpvBuiltInSubgroupLeMaskKHR})},
|
||||
{"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
|
||||
MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
|
||||
SpvBuiltInSubgroupLtMaskKHR})},
|
||||
})), );
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -53,6 +53,18 @@ def compose_capability_list(caps):
|
||||
return "{" + ", ".join(['SpvCapability{}'.format(c) for c in caps]) + "}"
|
||||
|
||||
|
||||
def compose_extension_list(exts):
|
||||
"""Returns a string containing a braced list of extensions as enums.
|
||||
|
||||
Arguments:
|
||||
- exts: a sequence of extension names
|
||||
|
||||
Returns:
|
||||
a string containing the braced list of SpvCapability* enums named by caps.
|
||||
"""
|
||||
return "{" + ", ".join(['libspirv::Extension::k{}'.format(e) for e in exts]) + "}"
|
||||
|
||||
|
||||
def convert_operand_kind(operand_tuple):
|
||||
"""Returns the corresponding operand type used in spirv-tools for
|
||||
the given operand kind and quantifier used in the JSON grammar.
|
||||
@ -236,27 +248,30 @@ def generate_instruction_table(inst_table, is_ext_inst):
|
||||
class EnumerantInitializer(object):
|
||||
"""Prints an enumerant as the initializer for spv_operand_desc_t."""
|
||||
|
||||
def __init__(self, enumerant, value, caps, parameters):
|
||||
def __init__(self, enumerant, value, caps, exts, parameters):
|
||||
"""Initialization.
|
||||
|
||||
Arguments:
|
||||
- enumerant: enumerant name
|
||||
- value: enumerant value
|
||||
- caps: a sequence of capability names required by this enumerant
|
||||
- exts: a sequence of names of extensions enabling this enumerant
|
||||
- parameters: a sequence of (operand-kind, operand-quantifier) tuples
|
||||
"""
|
||||
self.enumerant = enumerant
|
||||
self.value = value
|
||||
self.caps_mask = compose_capability_list(caps)
|
||||
self.caps = compose_capability_list(caps)
|
||||
self.exts = compose_extension_list(exts)
|
||||
self.parameters = [convert_operand_kind(p) for p in parameters]
|
||||
|
||||
def __str__(self):
|
||||
template = ['{{"{enumerant}"', '{value}',
|
||||
'{caps_mask}', '{{{parameters}}}}}']
|
||||
'{caps}', '{exts}', '{{{parameters}}}}}']
|
||||
return ', '.join(template).format(
|
||||
enumerant=self.enumerant,
|
||||
value=self.value,
|
||||
caps_mask=self.caps_mask,
|
||||
caps=self.caps,
|
||||
exts=self.exts,
|
||||
parameters=', '.join(self.parameters))
|
||||
|
||||
|
||||
@ -272,6 +287,7 @@ def generate_enum_operand_kind_entry(entry):
|
||||
enumerant = entry.get('enumerant')
|
||||
value = entry.get('value')
|
||||
caps = entry.get('capabilities', [])
|
||||
exts = entry.get('exts', [])
|
||||
params = entry.get('parameters', [])
|
||||
params = [p.get('kind') for p in params]
|
||||
params = zip(params, [''] * len(params))
|
||||
@ -279,7 +295,7 @@ def generate_enum_operand_kind_entry(entry):
|
||||
assert enumerant is not None
|
||||
assert value is not None
|
||||
|
||||
return str(EnumerantInitializer(enumerant, value, caps, params))
|
||||
return str(EnumerantInitializer(enumerant, value, caps, exts, params))
|
||||
|
||||
|
||||
def generate_enum_operand_kind(enum):
|
||||
|
Loading…
Reference in New Issue
Block a user