Updated spirv-tools.

This commit is contained in:
Бранимир Караџић 2019-11-15 21:32:44 -08:00
parent dca534e77a
commit e3ef70dd0f
21 changed files with 403 additions and 642 deletions

View File

@ -49,9 +49,11 @@ version. An API call reports the software version as a C-style string.
### Assembler, binary parser, and disassembler
* Support for SPIR-V 1.0, 1.1, 1.2, and 1.3
* Support for SPIR-V 1.0, through 1.5
* Based on SPIR-V syntax described by JSON grammar files in the
[SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) repository.
* Usually, support for a new version of SPIR-V is ready within days after
publication.
* Support for extended instruction sets:
* GLSL std450 version 1.0 Rev 3
* OpenCL version 1.0 Rev 2
@ -88,14 +90,22 @@ limits accepted by a more than minimally capable SPIR-V consumer.
### Optimizer
*Note:* The optimizer is still under development.
The optimizer is a collection of code transforms, or "passes".
Transforms are written for a diverse set of reasons:
Currently supported optimizations:
* General
* To restructure, simplify, or normalize the code for further processing.
* To eliminate undesirable code.
* To improve code quality in some metric such as size or performance.
**Note**: These transforms are not guaranteed to actually improve any
given metric. Users should always measure results for their own situation.
As of this writing, there are 67 transforms including examples such as:
* Simplification
* Strip debug info
* Strip reflection info
* Specialization Constants
* Set spec constant default value
* Freeze spec constant
* Freeze spec constant to default value
* Fold `OpSpecConstantOp` and `OpSpecConstantComposite`
* Unify constants
* Eliminate dead constant
@ -112,6 +122,29 @@ Currently supported optimizations:
* Eliminate common uniform loads
* Remove duplicates: Capabilities, extended instruction imports, types, and
decorations.
* Normalization
* Compact IDs
* CFG cleanup
* Flatten decorations
* Merge returns
* Convert AMD-specific instructions to KHR instructions
* Code improvement
* Conditional constant propagation
* If-conversion
* Loop fission
* Loop fusion
* Loop-invariant code motion
* Loop unroll
* Other
* Generate WebGPU initializers
* Graphics robust access
* Upgrade memory model to VulkanKHR
Additionally, certain sets of transformations have been packaged into
higher-level recipes. These include:
* Optimization for size (`spirv-opt -Os`)
* Optimization for performance (`spirv-opt -O`)
For the latest list with detailed documentation, please refer to
[`include/spirv-tools/optimizer.hpp`](include/spirv-tools/optimizer.hpp).
@ -319,11 +352,11 @@ installed regardless of your OS:
targets, you need to install CMake Version 2.8.12 or later.
- [Python 3](http://www.python.org/): for utility scripts and running the test
suite.
- [Bazel](https://baze.build/) (optional): if building the source with Bazel,
- [Bazel](https://bazel.build/) (optional): if building the source with Bazel,
you need to install Bazel Version 0.29.1 on your machine. Other versions may
also work, but are not verified.
SPIRV-Tools is regularly tested with the the following compilers:
SPIRV-Tools is regularly tested with the following compilers:
On Linux
- GCC version 4.8.5

View File

@ -1 +1 @@
"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-164-g3e4abc9a"
"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-172-gc3f22f7c"

View File

@ -51,7 +51,7 @@ protobufs::IdUseDescriptor MakeIdUseDescriptor(
protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse(
opt::IRContext* context, opt::Instruction* inst,
uint32_t in_operand_index) {
auto in_operand = inst->GetInOperand(in_operand_index);
const auto& in_operand = inst->GetInOperand(in_operand_index);
assert(in_operand.type == SPV_OPERAND_TYPE_ID);
return MakeIdUseDescriptor(in_operand.words[0],
MakeInstructionDescriptor(context, inst),

View File

@ -36,6 +36,45 @@ const uint32_t kFMixYIdInIdx = 3;
const uint32_t kFMixAIdInIdx = 4;
const uint32_t kStoreObjectInIdx = 1;
// Some image instructions may contain an "image operands" argument.
// Returns the operand index for the "image operands".
// Returns -1 if the instruction does not have image operands.
int32_t ImageOperandsMaskInOperandIndex(Instruction* inst) {
const auto opcode = inst->opcode();
switch (opcode) {
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod:
case SpvOpImageSampleProjImplicitLod:
case SpvOpImageSampleProjExplicitLod:
case SpvOpImageFetch:
case SpvOpImageRead:
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod:
case SpvOpImageSparseSampleProjImplicitLod:
case SpvOpImageSparseSampleProjExplicitLod:
case SpvOpImageSparseFetch:
case SpvOpImageSparseRead:
return inst->NumOperands() > 4 ? 2 : -1;
case SpvOpImageSampleDrefImplicitLod:
case SpvOpImageSampleDrefExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageGather:
case SpvOpImageDrefGather:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod:
case SpvOpImageSparseSampleProjDrefImplicitLod:
case SpvOpImageSparseSampleProjDrefExplicitLod:
case SpvOpImageSparseGather:
case SpvOpImageSparseDrefGather:
return inst->NumOperands() > 5 ? 3 : -1;
case SpvOpImageWrite:
return inst->NumOperands() > 3 ? 3 : -1;
default:
return -1;
}
}
// Returns the element width of |type|.
uint32_t ElementWidth(const analysis::Type* type) {
if (const analysis::Vector* vec_type = type->AsVector()) {
@ -2316,6 +2355,64 @@ FoldingRule RemoveRedundantOperands() {
};
}
// If an image instruction's operand is a constant, updates the image operand
// flag from Offset to ConstOffset.
FoldingRule UpdateImageOperands() {
return [](IRContext*, Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
const auto opcode = inst->opcode();
(void)opcode;
assert((opcode == SpvOpImageSampleImplicitLod ||
opcode == SpvOpImageSampleExplicitLod ||
opcode == SpvOpImageSampleDrefImplicitLod ||
opcode == SpvOpImageSampleDrefExplicitLod ||
opcode == SpvOpImageSampleProjImplicitLod ||
opcode == SpvOpImageSampleProjExplicitLod ||
opcode == SpvOpImageSampleProjDrefImplicitLod ||
opcode == SpvOpImageSampleProjDrefExplicitLod ||
opcode == SpvOpImageFetch || opcode == SpvOpImageGather ||
opcode == SpvOpImageDrefGather || opcode == SpvOpImageRead ||
opcode == SpvOpImageWrite ||
opcode == SpvOpImageSparseSampleImplicitLod ||
opcode == SpvOpImageSparseSampleExplicitLod ||
opcode == SpvOpImageSparseSampleDrefImplicitLod ||
opcode == SpvOpImageSparseSampleDrefExplicitLod ||
opcode == SpvOpImageSparseSampleProjImplicitLod ||
opcode == SpvOpImageSparseSampleProjExplicitLod ||
opcode == SpvOpImageSparseSampleProjDrefImplicitLod ||
opcode == SpvOpImageSparseSampleProjDrefExplicitLod ||
opcode == SpvOpImageSparseFetch ||
opcode == SpvOpImageSparseGather ||
opcode == SpvOpImageSparseDrefGather ||
opcode == SpvOpImageSparseRead) &&
"Wrong opcode. Should be an image instruction.");
int32_t operand_index = ImageOperandsMaskInOperandIndex(inst);
if (operand_index >= 0) {
auto image_operands = inst->GetSingleWordInOperand(operand_index);
if (image_operands & SpvImageOperandsOffsetMask) {
uint32_t offset_operand_index = operand_index + 1;
if (image_operands & SpvImageOperandsBiasMask) offset_operand_index++;
if (image_operands & SpvImageOperandsLodMask) offset_operand_index++;
if (image_operands & SpvImageOperandsGradMask)
offset_operand_index += 2;
assert(((image_operands & SpvImageOperandsConstOffsetMask) == 0) &&
"Offset and ConstOffset may not be used together");
if (offset_operand_index < inst->NumOperands()) {
if (constants[offset_operand_index]) {
image_operands = image_operands | SpvImageOperandsConstOffsetMask;
image_operands = image_operands & ~SpvImageOperandsOffsetMask;
inst->SetInOperand(operand_index, {image_operands});
return true;
}
}
}
}
return false;
};
}
} // namespace
void FoldingRules::AddFoldingRules() {
@ -2392,6 +2489,38 @@ void FoldingRules::AddFoldingRules() {
rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle());
rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleExplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleDrefImplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleDrefExplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleProjImplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleProjExplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleProjDrefImplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSampleProjDrefExplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageFetch].push_back(UpdateImageOperands());
rules_[SpvOpImageGather].push_back(UpdateImageOperands());
rules_[SpvOpImageDrefGather].push_back(UpdateImageOperands());
rules_[SpvOpImageRead].push_back(UpdateImageOperands());
rules_[SpvOpImageWrite].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseSampleImplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseSampleExplicitLod].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseSampleDrefImplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseSampleDrefExplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseSampleProjImplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseSampleProjExplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseSampleProjDrefImplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseSampleProjDrefExplicitLod].push_back(
UpdateImageOperands());
rules_[SpvOpImageSparseFetch].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseGather].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseDrefGather].push_back(UpdateImageOperands());
rules_[SpvOpImageSparseRead].push_back(UpdateImageOperands());
FeatureManager* feature_manager = context_->get_feature_mgr();
// Add rules for GLSLstd450
uint32_t ext_inst_glslstd450_id =

View File

@ -429,7 +429,7 @@ std::pair<bool, bool> UpgradeMemoryModel::CheckType(
} else {
assert(spvOpcodeIsComposite(element_inst->opcode()));
element_inst = context()->get_def_use_mgr()->GetDef(
element_inst->GetSingleWordInOperand(1u));
element_inst->GetSingleWordInOperand(0u));
}
}

View File

@ -522,10 +522,13 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
const auto typeId = array_inst->word(2);
const auto element_inst = vstate.FindDef(typeId);
// Check array stride.
auto array_stride = 0;
uint32_t array_stride = 0;
for (auto& decoration : vstate.id_decorations(array_inst->id())) {
if (SpvDecorationArrayStride == decoration.dec_type()) {
array_stride = decoration.params()[0];
if (array_stride == 0) {
return fail(memberIdx) << "contains an array with stride 0";
}
if (!IsAlignedTo(array_stride, array_alignment))
return fail(memberIdx)
<< "contains an array with stride " << decoration.params()[0]
@ -563,6 +566,14 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
? getScalarAlignment(array_inst->id(), vstate)
: getBaseAlignment(array_inst->id(), blockRules,
constraint, constraints, vstate);
const auto element_size =
getSize(element_inst->id(), constraint, constraints, vstate);
if (element_size > array_stride) {
return fail(memberIdx)
<< "contains an array with stride " << array_stride
<< ", but with an element size of " << element_size;
}
}
nextValidOffset = offset + size;
if (!scalar_block_layout && blockRules &&

View File

@ -561,6 +561,7 @@ TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) {
OpName %main "main"
OpDecorate %_Globals DescriptorSet 0
OpDecorate %_Globals Binding 0
OpDecorate %_runtimearr_float ArrayStride 16
OpMemberDecorate %type__Globals 0 Offset 0
OpMemberDecorate %type__Globals 1 Offset 4
OpMemberDecorate %type__Globals 2 Offset 16

View File

@ -7058,6 +7058,96 @@ INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
1, false)
));
std::string ImageOperandsTestBody(const std::string& image_instruction) {
std::string body = R"(
OpCapability Shader
OpCapability ImageGatherExtended
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %Texture DescriptorSet 0
OpDecorate %Texture Binding 0
%int = OpTypeInt 32 1
%int_n1 = OpConstant %int -1
%5 = OpConstant %int 0
%float = OpTypeFloat 32
%float_0 = OpConstant %float 0
%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
%type_sampled_image = OpTypeSampledImage %type_2d_image
%type_sampler = OpTypeSampler
%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
%_ptr_int = OpTypePointer Function %int
%v2int = OpTypeVector %int 2
%10 = OpTypeVector %float 4
%void = OpTypeVoid
%22 = OpTypeFunction %void
%v2float = OpTypeVector %float 2
%v3int = OpTypeVector %int 3
%Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
%gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
%101 = OpConstantComposite %v2int %int_n1 %int_n1
%20 = OpConstantComposite %v2float %float_0 %float_0
%main = OpFunction %void None %22
%23 = OpLabel
%var = OpVariable %_ptr_int Function
%88 = OpLoad %type_2d_image %Texture
%val = OpLoad %int %var
%sampler = OpLoad %type_sampler %gSampler
%26 = OpSampledImage %type_sampled_image %88 %sampler
)" + image_instruction + R"(
OpReturn
OpFunctionEnd
)";
return body;
}
INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
::testing::Values(
// Test case 0: OpImageFetch without Offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
"%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
, 89, false),
// Test case 1: OpImageFetch with non-const offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
"%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
, 89, false),
// Test case 2: OpImageFetch with Lod and Offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n"
"; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
, 89, true),
// Test case 3: OpImageFetch with Bias and Offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n"
"; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
, 89, true),
// Test case 4: OpImageFetch with Grad and Offset.
// Grad adds 2 operands to the instruction.
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n"
"; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
, 89, true),
// Test case 5: OpImageFetch with Offset and MinLod.
// This is an example of a case where the bitmask bit-offset is larger than
// that of the Offset.
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n"
"; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
, 89, true),
// Test case 6: OpImageGather with constant Offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n"
"; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
, 89, true),
// Test case 7: OpImageWrite with constant Offset
InstructionFoldingCase<bool>(ImageOperandsTestBody(
" OpImageWrite %88 %5 %101 Offset %101 \n"
"; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
, 0 /* No result-id */, true)
));
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -898,7 +898,7 @@ TEST_F(GraphicsRobustAccessTest, ACStructNegativeFail) {
TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC() << "OpMemberDecorate %ssbo_s 0 ArrayStride 4 "
shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %uint %uint %rtarr
@ -924,9 +924,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralShortIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int16\n"
<< ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesShort() << TypesFloat() << R"(
<< ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %short %short %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -954,9 +953,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int16\n"
<< ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesShort() << TypesFloat() << R"(
<< ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %short %short %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -983,9 +981,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) {
TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -1000,8 +997,9 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1
; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] UClamp %i %int_0 %[[max]]
)" << MainPrefix()
<< ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
)"
<< MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
<< MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@ -1009,9 +1007,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) {
TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 "
<< DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -1026,8 +1023,9 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) {
; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2
; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1
; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UClamp %i %uint_0 %[[max]]
)" << MainPrefix()
<< ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
)"
<< MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
<< MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@ -1036,8 +1034,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesInt() << TypesLong() << TypesFloat() << R"(
<< "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
<< TypesInt() << TypesLong() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -1053,9 +1051,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) {
; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
; CHECK: %[[max:\w+]] = OpISub %long %[[arrlen_ext]] %long_1
; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] UClamp %i %long_0 %[[max]]
)"
<< MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
<< MainSuffix();
)" << MainPrefix()
<< ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@ -1064,8 +1061,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << "OpCapability Int64" << ShaderPreambleAC({"i"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 4 " << DecoSSBO()
<< TypesVoid() << TypesInt() << TypesLong() << TypesFloat() << R"(
<< "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid()
<< TypesInt() << TypesLong() << TypesFloat() << R"(
%rtarr = OpTypeRuntimeArray %float
%ssbo_s = OpTypeStruct %int %int %rtarr
%var_ty = OpTypePointer Uniform %ssbo_s
@ -1081,9 +1078,8 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) {
; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]]
; CHECK: %[[max:\w+]] = OpISub %ulong %[[arrlen_ext]] %ulong_1
; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UClamp %i %ulong_0 %[[max]]
)"
<< MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]")
<< MainSuffix();
)" << MainPrefix()
<< ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix();
SinglePassRunAndMatch<GraphicsRobustAccessPass>(shaders.str(), true);
}
}
@ -1095,7 +1091,7 @@ TEST_F(GraphicsRobustAccessTest, ACRTArrayStructVectorElem) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "j"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
<< "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@ -1131,7 +1127,7 @@ TEST_F(GraphicsRobustAccessTest, ACArrayRTArrayStructVectorElem) {
for (auto* ac : AccessChains()) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "ssbo_s"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
<< "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@ -1175,7 +1171,7 @@ TEST_F(GraphicsRobustAccessTest, ACSplitACArrayRTArrayStructVectorElem) {
std::ostringstream shaders;
shaders << ShaderPreambleAC({"i", "j", "k", "ssbo_s", "ssbo_pty",
"rtarr_pty", "ac_ssbo", "ac_rtarr"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
<< "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(
@ -1238,7 +1234,7 @@ TEST_F(GraphicsRobustAccessTest,
shaders << ShaderPreambleAC({"i", "j", "k", "bb1", "bb2", "ssbo_s",
"ssbo_pty", "rtarr_pty", "ac_ssbo",
"ac_rtarr"})
<< "OpMemberDecorate %ssbo_s 0 ArrayStride 32\n"
<< "OpDecorate %rtarr ArrayStride 32\n"
<< DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n"
<< "OpMemberDecorate %rtelem 1 Offset 16\n"
<< TypesVoid() << TypesInt() << TypesFloat() << R"(

View File

@ -2236,4 +2236,37 @@ OpFunctionEnd
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
}
TEST_F(UpgradeMemoryModelTest, CoherentStructMemberInArray) {
const std::string text = R"(
; CHECK-NOT: OpMemberDecorate
; CHECK: [[int:%[a-zA-Z0-9_]+]] = OpTypeInt 32 0
; CHECK: [[device:%[a-zA-Z0-9_]+]] = OpConstant [[int]] 1
; CHECK: OpLoad [[int]] {{.*}} MakePointerVisible|NonPrivatePointer
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpMemberDecorate %inner 1 Coherent
%void = OpTypeVoid
%int = OpTypeInt 32 0
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%int_4 = OpConstant %int 4
%inner = OpTypeStruct %int %int
%array = OpTypeArray %inner %int_4
%struct = OpTypeStruct %array
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
%ssbo_var = OpVariable %ptr_ssbo_struct StorageBuffer
%void_fn = OpTypeFunction %void
%func = OpFunction %void None %void_fn
%entry = OpLabel
%gep = OpAccessChain %ptr_ssbo_int %ssbo_var %int_0 %int_0 %int_1
%ld = OpLoad %int %gep
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
}
} // namespace

View File

@ -6929,6 +6929,72 @@ OpFunctionEnd
"identified with a Block or BufferBlock decoration"));
}
TEST_F(ValidateDecorations, VulkanArrayStrideZero) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpDecorate %var DescriptorSet 0
OpDecorate %var Binding 0
OpDecorate %struct Block
OpMemberDecorate %struct 0 Offset 0
OpDecorate %array ArrayStride 0
%void = OpTypeVoid
%int = OpTypeInt 32 0
%int_4 = OpConstant %int 4
%array = OpTypeArray %int %int_4
%struct = OpTypeStruct %array
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
%var = OpVariable %ptr_ssbo_struct StorageBuffer
%void_fn = OpTypeFunction %void
%main = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("contains an array with stride 0"));
}
TEST_F(ValidateDecorations, VulkanArrayStrideTooSmall) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpDecorate %var DescriptorSet 0
OpDecorate %var Binding 0
OpDecorate %struct Block
OpMemberDecorate %struct 0 Offset 0
OpDecorate %inner ArrayStride 4
OpDecorate %outer ArrayStride 4
%void = OpTypeVoid
%int = OpTypeInt 32 0
%int_4 = OpConstant %int 4
%inner = OpTypeArray %int %int_4
%outer = OpTypeArray %inner %int_4
%struct = OpTypeStruct %outer
%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
%var = OpVariable %ptr_ssbo_struct StorageBuffer
%void_fn = OpTypeFunction %void
%main = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"contains an array with stride 4, but with an element size of 16"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -2996,6 +2996,7 @@ OpExtension "SPV_EXT_descriptor_indexing"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
OpDecorate %inner_array_t ArrayStride 4
OpDecorate %array_t ArrayStride 4
OpMemberDecorate %struct_t 0 Offset 0
OpDecorate %struct_t Block
@ -3025,6 +3026,7 @@ OpExtension "SPV_EXT_descriptor_indexing"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
OpDecorate %inner_array_t ArrayStride 4
OpDecorate %array_t ArrayStride 4
OpMemberDecorate %struct_t 0 Offset 0
OpDecorate %struct_t Block

View File

@ -1 +0,0 @@
cache/

View File

@ -1,7 +0,0 @@
# Visual Studio Code extension for SPIR-V disassembly files
This directory holds a Visual Studio Code extension adding syntax highlighting for SPIR-V disassembly files (.spirv)
## Installing (macOS / Linux)
Simply run `install.sh`

View File

@ -1,26 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2019 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e # Fail on any error.
EXT_PATH=~/.vscode/extensions/google.spirvls-0.0.1
ROOT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/spirv.json.tmpl --out ${ROOT_PATH}/spirv.json
mkdir -p ${EXT_PATH}
cp ${ROOT_PATH}/package.json ${EXT_PATH}
cp ${ROOT_PATH}/spirv.configuration.json ${EXT_PATH}
cp ${ROOT_PATH}/spirv.json ${EXT_PATH}

View File

@ -1,33 +0,0 @@
{
"name": "spirv",
"description": "Language support for SPIR-V disassembly files",
"author": "Google",
"license": "Apache-2.0",
"version": "0.0.1",
"private": true,
"publisher": "Google",
"engines": {
"vscode": "^0.10.10"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": "spirv",
"configuration": "spirv.configuration.json",
"extensions": [
"spvasm"
]
}
],
"grammars": [
{
"language": "spirv",
"scopeName": "source.spirv",
"path": "spirv.json"
}
]
}
}

View File

@ -1,6 +0,0 @@
{
"comments": {
"lineComment": ";"
},
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)"
}

View File

@ -1,212 +0,0 @@
{
"scopeName": "source.spirv",
"name": "SPIR-V",
"comment": "Generated by gen-grammar.go --template=../../spirv.json.tmpl --out=../../spirv.json. Do not modify this file directly.",
"patterns": [
{ "include": "#BitEnum_ImageOperands" },
{ "include": "#BitEnum_FPFastMathMode" },
{ "include": "#BitEnum_SelectionControl" },
{ "include": "#BitEnum_LoopControl" },
{ "include": "#BitEnum_FunctionControl" },
{ "include": "#BitEnum_MemorySemantics" },
{ "include": "#BitEnum_MemoryAccess" },
{ "include": "#BitEnum_KernelProfilingInfo" },
{ "include": "#ValueEnum_SourceLanguage" },
{ "include": "#ValueEnum_ExecutionModel" },
{ "include": "#ValueEnum_AddressingModel" },
{ "include": "#ValueEnum_MemoryModel" },
{ "include": "#ValueEnum_ExecutionMode" },
{ "include": "#ValueEnum_StorageClass" },
{ "include": "#ValueEnum_Dim" },
{ "include": "#ValueEnum_SamplerAddressingMode" },
{ "include": "#ValueEnum_SamplerFilterMode" },
{ "include": "#ValueEnum_ImageFormat" },
{ "include": "#ValueEnum_ImageChannelOrder" },
{ "include": "#ValueEnum_ImageChannelDataType" },
{ "include": "#ValueEnum_FPRoundingMode" },
{ "include": "#ValueEnum_LinkageType" },
{ "include": "#ValueEnum_AccessQualifier" },
{ "include": "#ValueEnum_FunctionParameterAttribute" },
{ "include": "#ValueEnum_Decoration" },
{ "include": "#ValueEnum_BuiltIn" },
{ "include": "#ValueEnum_Scope" },
{ "include": "#ValueEnum_GroupOperation" },
{ "include": "#ValueEnum_KernelEnqueueFlags" },
{ "include": "#ValueEnum_Capability" },
{ "include": "#opcode" },
{ "include": "#identifier" },
{ "include": "#number" },
{ "include": "#string" },
{ "include": "#comment" },
{ "include": "#operator" }
],
"repository": {
"BitEnum_ImageOperands": {
"match": "\\b(None|Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod|MakeTexelAvailable|MakeTexelAvailableKHR|MakeTexelVisible|MakeTexelVisibleKHR|NonPrivateTexel|NonPrivateTexelKHR|VolatileTexel|VolatileTexelKHR|SignExtend|ZeroExtend)\\b",
"name": "keyword.spirv"
},
"BitEnum_FPFastMathMode": {
"match": "\\b(None|NotNaN|NotInf|NSZ|AllowRecip|Fast)\\b",
"name": "keyword.spirv"
},
"BitEnum_SelectionControl": {
"match": "\\b(None|Flatten|DontFlatten)\\b",
"name": "keyword.spirv"
},
"BitEnum_LoopControl": {
"match": "\\b(None|Unroll|DontUnroll|DependencyInfinite|DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount)\\b",
"name": "keyword.spirv"
},
"BitEnum_FunctionControl": {
"match": "\\b(None|Inline|DontInline|Pure|Const)\\b",
"name": "keyword.spirv"
},
"BitEnum_MemorySemantics": {
"match": "\\b(Relaxed|None|Acquire|Release|AcquireRelease|SequentiallyConsistent|UniformMemory|SubgroupMemory|WorkgroupMemory|CrossWorkgroupMemory|AtomicCounterMemory|ImageMemory|OutputMemory|OutputMemoryKHR|MakeAvailable|MakeAvailableKHR|MakeVisible|MakeVisibleKHR|Volatile)\\b",
"name": "keyword.spirv"
},
"BitEnum_MemoryAccess": {
"match": "\\b(None|Volatile|Aligned|Nontemporal|MakePointerAvailable|MakePointerAvailableKHR|MakePointerVisible|MakePointerVisibleKHR|NonPrivatePointer|NonPrivatePointerKHR)\\b",
"name": "keyword.spirv"
},
"BitEnum_KernelProfilingInfo": {
"match": "\\b(None|CmdExecTime)\\b",
"name": "keyword.spirv"
},
"ValueEnum_SourceLanguage": {
"match": "\\b(Unknown|ESSL|GLSL|OpenCL_C|OpenCL_CPP|HLSL)\\b",
"name": "keyword.spirv"
},
"ValueEnum_ExecutionModel": {
"match": "\\b(Vertex|TessellationControl|TessellationEvaluation|Geometry|Fragment|GLCompute|Kernel|TaskNV|MeshNV|RayGenerationNV|IntersectionNV|AnyHitNV|ClosestHitNV|MissNV|CallableNV)\\b",
"name": "keyword.spirv"
},
"ValueEnum_AddressingModel": {
"match": "\\b(Logical|Physical32|Physical64|PhysicalStorageBuffer64|PhysicalStorageBuffer64EXT)\\b",
"name": "keyword.spirv"
},
"ValueEnum_MemoryModel": {
"match": "\\b(Simple|GLSL450|OpenCL|Vulkan|VulkanKHR)\\b",
"name": "keyword.spirv"
},
"ValueEnum_ExecutionMode": {
"match": "\\b(Invocations|SpacingEqual|SpacingFractionalEven|SpacingFractionalOdd|VertexOrderCw|VertexOrderCcw|PixelCenterInteger|OriginUpperLeft|OriginLowerLeft|EarlyFragmentTests|PointMode|Xfb|DepthReplacing|DepthGreater|DepthLess|DepthUnchanged|LocalSize|LocalSizeHint|InputPoints|InputLines|InputLinesAdjacency|Triangles|InputTrianglesAdjacency|Quads|Isolines|OutputVertices|OutputPoints|OutputLineStrip|OutputTriangleStrip|VecTypeHint|ContractionOff|Initializer|Finalizer|SubgroupSize|SubgroupsPerWorkgroup|SubgroupsPerWorkgroupId|LocalSizeId|LocalSizeHintId|PostDepthCoverage|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|StencilRefReplacingEXT|OutputLinesNV|OutputPrimitivesNV|DerivativeGroupQuadsNV|DerivativeGroupLinearNV|OutputTrianglesNV|PixelInterlockOrderedEXT|PixelInterlockUnorderedEXT|SampleInterlockOrderedEXT|SampleInterlockUnorderedEXT|ShadingRateInterlockOrderedEXT|ShadingRateInterlockUnorderedEXT)\\b",
"name": "keyword.spirv"
},
"ValueEnum_StorageClass": {
"match": "\\b(UniformConstant|Input|Uniform|Output|Workgroup|CrossWorkgroup|Private|Function|Generic|PushConstant|AtomicCounter|Image|StorageBuffer|CallableDataNV|IncomingCallableDataNV|RayPayloadNV|HitAttributeNV|IncomingRayPayloadNV|ShaderRecordBufferNV|PhysicalStorageBuffer|PhysicalStorageBufferEXT)\\b",
"name": "keyword.spirv"
},
"ValueEnum_Dim": {
"match": "\\b(1D|2D|3D|Cube|Rect|Buffer|SubpassData)\\b",
"name": "keyword.spirv"
},
"ValueEnum_SamplerAddressingMode": {
"match": "\\b(None|ClampToEdge|Clamp|Repeat|RepeatMirrored)\\b",
"name": "keyword.spirv"
},
"ValueEnum_SamplerFilterMode": {
"match": "\\b(Nearest|Linear)\\b",
"name": "keyword.spirv"
},
"ValueEnum_ImageFormat": {
"match": "\\b(Unknown|Rgba32f|Rgba16f|R32f|Rgba8|Rgba8Snorm|Rg32f|Rg16f|R11fG11fB10f|R16f|Rgba16|Rgb10A2|Rg16|Rg8|R16|R8|Rgba16Snorm|Rg16Snorm|Rg8Snorm|R16Snorm|R8Snorm|Rgba32i|Rgba16i|Rgba8i|R32i|Rg32i|Rg16i|Rg8i|R16i|R8i|Rgba32ui|Rgba16ui|Rgba8ui|R32ui|Rgb10a2ui|Rg32ui|Rg16ui|Rg8ui|R16ui|R8ui)\\b",
"name": "keyword.spirv"
},
"ValueEnum_ImageChannelOrder": {
"match": "\\b(R|A|RG|RA|RGB|RGBA|BGRA|ARGB|Intensity|Luminance|Rx|RGx|RGBx|Depth|DepthStencil|sRGB|sRGBx|sRGBA|sBGRA|ABGR)\\b",
"name": "keyword.spirv"
},
"ValueEnum_ImageChannelDataType": {
"match": "\\b(SnormInt8|SnormInt16|UnormInt8|UnormInt16|UnormShort565|UnormShort555|UnormInt101010|SignedInt8|SignedInt16|SignedInt32|UnsignedInt8|UnsignedInt16|UnsignedInt32|HalfFloat|Float|UnormInt24|UnormInt101010_2)\\b",
"name": "keyword.spirv"
},
"ValueEnum_FPRoundingMode": {
"match": "\\b(RTE|RTZ|RTP|RTN)\\b",
"name": "keyword.spirv"
},
"ValueEnum_LinkageType": {
"match": "\\b(Export|Import)\\b",
"name": "keyword.spirv"
},
"ValueEnum_AccessQualifier": {
"match": "\\b(ReadOnly|WriteOnly|ReadWrite)\\b",
"name": "keyword.spirv"
},
"ValueEnum_FunctionParameterAttribute": {
"match": "\\b(Zext|Sext|ByVal|Sret|NoAlias|NoCapture|NoWrite|NoReadWrite)\\b",
"name": "keyword.spirv"
},
"ValueEnum_Decoration": {
"match": "\\b(RelaxedPrecision|SpecId|Block|BufferBlock|RowMajor|ColMajor|ArrayStride|MatrixStride|GLSLShared|GLSLPacked|CPacked|BuiltIn|NoPerspective|Flat|Patch|Centroid|Sample|Invariant|Restrict|Aliased|Volatile|Constant|Coherent|NonWritable|NonReadable|Uniform|UniformId|SaturatedConversion|Stream|Location|Component|Index|Binding|DescriptorSet|Offset|XfbBuffer|XfbStride|FuncParamAttr|FPRoundingMode|FPFastMathMode|LinkageAttributes|NoContraction|InputAttachmentIndex|Alignment|MaxByteOffset|AlignmentId|MaxByteOffsetId|NoSignedWrap|NoUnsignedWrap|ExplicitInterpAMD|OverrideCoverageNV|PassthroughNV|ViewportRelativeNV|SecondaryViewportRelativeNV|PerPrimitiveNV|PerViewNV|PerTaskNV|PerVertexNV|NonUniform|NonUniformEXT|RestrictPointer|RestrictPointerEXT|AliasedPointer|AliasedPointerEXT|CounterBuffer|HlslCounterBufferGOOGLE|UserSemantic|HlslSemanticGOOGLE|UserTypeGOOGLE)\\b",
"name": "keyword.spirv"
},
"ValueEnum_BuiltIn": {
"match": "\\b(Position|PointSize|ClipDistance|CullDistance|VertexId|InstanceId|PrimitiveId|InvocationId|Layer|ViewportIndex|TessLevelOuter|TessLevelInner|TessCoord|PatchVertices|FragCoord|PointCoord|FrontFacing|SampleId|SamplePosition|SampleMask|FragDepth|HelperInvocation|NumWorkgroups|WorkgroupSize|WorkgroupId|LocalInvocationId|GlobalInvocationId|LocalInvocationIndex|WorkDim|GlobalSize|EnqueuedWorkgroupSize|GlobalOffset|GlobalLinearId|SubgroupSize|SubgroupMaxSize|NumSubgroups|NumEnqueuedSubgroups|SubgroupId|SubgroupLocalInvocationId|VertexIndex|InstanceIndex|SubgroupEqMask|SubgroupGeMask|SubgroupGtMask|SubgroupLeMask|SubgroupLtMask|SubgroupEqMaskKHR|SubgroupGeMaskKHR|SubgroupGtMaskKHR|SubgroupLeMaskKHR|SubgroupLtMaskKHR|BaseVertex|BaseInstance|DrawIndex|DeviceIndex|ViewIndex|BaryCoordNoPerspAMD|BaryCoordNoPerspCentroidAMD|BaryCoordNoPerspSampleAMD|BaryCoordSmoothAMD|BaryCoordSmoothCentroidAMD|BaryCoordSmoothSampleAMD|BaryCoordPullModelAMD|FragStencilRefEXT|ViewportMaskNV|SecondaryPositionNV|SecondaryViewportMaskNV|PositionPerViewNV|ViewportMaskPerViewNV|FullyCoveredEXT|TaskCountNV|PrimitiveCountNV|PrimitiveIndicesNV|ClipDistancePerViewNV|CullDistancePerViewNV|LayerPerViewNV|MeshViewCountNV|MeshViewIndicesNV|BaryCoordNV|BaryCoordNoPerspNV|FragSizeEXT|FragmentSizeNV|FragInvocationCountEXT|InvocationsPerPixelNV|LaunchIdNV|LaunchSizeNV|WorldRayOriginNV|WorldRayDirectionNV|ObjectRayOriginNV|ObjectRayDirectionNV|RayTminNV|RayTmaxNV|InstanceCustomIndexNV|ObjectToWorldNV|WorldToObjectNV|HitTNV|HitKindNV|IncomingRayFlagsNV|WarpsPerSMNV|SMCountNV|WarpIDNV|SMIDNV)\\b",
"name": "keyword.spirv"
},
"ValueEnum_Scope": {
"match": "\\b(CrossDevice|Device|Workgroup|Subgroup|Invocation|QueueFamily|QueueFamilyKHR)\\b",
"name": "keyword.spirv"
},
"ValueEnum_GroupOperation": {
"match": "\\b(Reduce|InclusiveScan|ExclusiveScan|ClusteredReduce|PartitionedReduceNV|PartitionedInclusiveScanNV|PartitionedExclusiveScanNV)\\b",
"name": "keyword.spirv"
},
"ValueEnum_KernelEnqueueFlags": {
"match": "\\b(NoWait|WaitKernel|WaitWorkGroup)\\b",
"name": "keyword.spirv"
},
"ValueEnum_Capability": {
"match": "\\b(Matrix|Shader|Geometry|Tessellation|Addresses|Linkage|Kernel|Vector16|Float16Buffer|Float16|Float64|Int64|Int64Atomics|ImageBasic|ImageReadWrite|ImageMipmap|Pipes|Groups|DeviceEnqueue|LiteralSampler|AtomicStorage|Int16|TessellationPointSize|GeometryPointSize|ImageGatherExtended|StorageImageMultisample|UniformBufferArrayDynamicIndexing|SampledImageArrayDynamicIndexing|StorageBufferArrayDynamicIndexing|StorageImageArrayDynamicIndexing|ClipDistance|CullDistance|ImageCubeArray|SampleRateShading|ImageRect|SampledRect|GenericPointer|Int8|InputAttachment|SparseResidency|MinLod|Sampled1D|Image1D|SampledCubeArray|SampledBuffer|ImageBuffer|ImageMSArray|StorageImageExtendedFormats|ImageQuery|DerivativeControl|InterpolationFunction|TransformFeedback|GeometryStreams|StorageImageReadWithoutFormat|StorageImageWriteWithoutFormat|MultiViewport|SubgroupDispatch|NamedBarrier|PipeStorage|GroupNonUniform|GroupNonUniformVote|GroupNonUniformArithmetic|GroupNonUniformBallot|GroupNonUniformShuffle|GroupNonUniformShuffleRelative|GroupNonUniformClustered|GroupNonUniformQuad|ShaderLayer|ShaderViewportIndex|SubgroupBallotKHR|DrawParameters|SubgroupVoteKHR|StorageBuffer16BitAccess|StorageUniformBufferBlock16|UniformAndStorageBuffer16BitAccess|StorageUniform16|StoragePushConstant16|StorageInputOutput16|DeviceGroup|MultiView|VariablePointersStorageBuffer|VariablePointers|AtomicStorageOps|SampleMaskPostDepthCoverage|StorageBuffer8BitAccess|UniformAndStorageBuffer8BitAccess|StoragePushConstant8|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|Float16ImageAMD|ImageGatherBiasLodAMD|FragmentMaskAMD|StencilExportEXT|ImageReadWriteLodAMD|ShaderClockKHR|SampleMaskOverrideCoverageNV|GeometryShaderPassthroughNV|ShaderViewportIndexLayerEXT|ShaderViewportIndexLayerNV|ShaderViewportMaskNV|ShaderStereoViewNV|PerViewAttributesNV|FragmentFullyCoveredEXT|MeshShadingNV|ImageFootprintNV|FragmentBarycentricNV|ComputeDerivativeGroupQuadsNV|FragmentDensityEXT|ShadingRateNV|GroupNonUniformPartitionedNV|ShaderNonUniform|ShaderNonUniformEXT|RuntimeDescriptorArray|RuntimeDescriptorArrayEXT|InputAttachmentArrayDynamicIndexing|InputAttachmentArrayDynamicIndexingEXT|UniformTexelBufferArrayDynamicIndexing|UniformTexelBufferArrayDynamicIndexingEXT|StorageTexelBufferArrayDynamicIndexing|StorageTexelBufferArrayDynamicIndexingEXT|UniformBufferArrayNonUniformIndexing|UniformBufferArrayNonUniformIndexingEXT|SampledImageArrayNonUniformIndexing|SampledImageArrayNonUniformIndexingEXT|StorageBufferArrayNonUniformIndexing|StorageBufferArrayNonUniformIndexingEXT|StorageImageArrayNonUniformIndexing|StorageImageArrayNonUniformIndexingEXT|InputAttachmentArrayNonUniformIndexing|InputAttachmentArrayNonUniformIndexingEXT|UniformTexelBufferArrayNonUniformIndexing|UniformTexelBufferArrayNonUniformIndexingEXT|StorageTexelBufferArrayNonUniformIndexing|StorageTexelBufferArrayNonUniformIndexingEXT|RayTracingNV|VulkanMemoryModel|VulkanMemoryModelKHR|VulkanMemoryModelDeviceScope|VulkanMemoryModelDeviceScopeKHR|PhysicalStorageBufferAddresses|PhysicalStorageBufferAddressesEXT|ComputeDerivativeGroupLinearNV|CooperativeMatrixNV|FragmentShaderSampleInterlockEXT|FragmentShaderShadingRateInterlockEXT|ShaderSMBuiltinsNV|FragmentShaderPixelInterlockEXT|DemoteToHelperInvocationEXT|SubgroupShuffleINTEL|SubgroupBufferBlockIOINTEL|SubgroupImageBlockIOINTEL|SubgroupImageMediaBlockIOINTEL|IntegerFunctions2INTEL|SubgroupAvcMotionEstimationINTEL|SubgroupAvcMotionEstimationIntraINTEL|SubgroupAvcMotionEstimationChromaINTEL)\\b",
"name": "keyword.spirv"
},
"opcode": {
"match": "(Op[a-zA-Z]+)",
"name": "entity.name.function.spirv"
},
"identifier": {
"match": "%[a-zA-Z0-9_]+",
"name": "variable.spirv"
},
"number": {
"match": "\\b[0-9]+.?[0-9]*\\b",
"name": "constant.numeric.spirv"
},
"comment": {
"match": ";[^\n]*",
"name": "comment.line.spirv"
},
"operator": {
"match": "=",
"name": "keyword.operator.spirv"
},
"string": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.spirv"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.spirv"
}
},
"name": "string.quoted.double.spirv",
"patterns": [ { "include": "#string_escaped_char" } ]
},
"string_escaped_char": {
"patterns": [
{
"match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})",
"name": "constant.character.escape.spirv"
}, {
"match": "\\\\[^0-7xuUabfnrtv\\'\"]",
"name": "invalid.illegal.unknown-escape.spirv"
}
]
}
}
}

View File

@ -1,67 +0,0 @@
{
"scopeName": "source.spirv",
"name": "SPIR-V",
"comment": "Generated by {{GenerateArguments}}. Do not modify this file directly.",
"patterns": [
{{range $o := .OperandKinds}}{{if len $o.Enumerants}} { "include": "#{{$o.Category}}_{{$o.Kind}}" },
{{end}}{{end}} { "include": "#opcode" },
{ "include": "#identifier" },
{ "include": "#number" },
{ "include": "#string" },
{ "include": "#comment" },
{ "include": "#operator" }
],
"repository": { {{range $o := .OperandKinds}}{{if len $o.Enumerants}}
"{{$o.Category}}_{{$o.Kind}}": {
"match": "\\b({{OperandKindsMatch $o}})\\b",
"name": "keyword.spirv"
},{{end}}{{end}}
"opcode": {
"match": "(Op[a-zA-Z]+)",
"name": "entity.name.function.spirv"
},
"identifier": {
"match": "%[a-zA-Z0-9_]+",
"name": "variable.spirv"
},
"number": {
"match": "\\b[0-9]+.?[0-9]*\\b",
"name": "constant.numeric.spirv"
},
"comment": {
"match": ";[^\n]*",
"name": "comment.line.spirv"
},
"operator": {
"match": "=",
"name": "keyword.operator.spirv"
},
"string": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.spirv"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.spirv"
}
},
"name": "string.quoted.double.spirv",
"patterns": [ { "include": "#string_escaped_char" } ]
},
"string_escaped_char": {
"patterns": [
{
"match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})",
"name": "constant.character.escape.spirv"
}, {
"match": "\\\\[^0-7xuUabfnrtv\\'\"]",
"name": "invalid.illegal.unknown-escape.spirv"
}
]
}
}
}

View File

@ -1,81 +0,0 @@
// Copyright (C) 2019 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package grammar holds the JSON type definitions for the SPIR-V grammar schema.
//
// See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
// for more information.
package grammar
// Root is the top-level structure of the JSON grammar.
type Root struct {
MagicNumber string `json:"magic_number"`
MajorVersion int `json:"major_version"`
MinorVersion int `json:"minor_version"`
Revision int `json:"revision"`
Instructions []Instruction `json:"instructions"`
OperandKinds []OperandKind `json:"operand_kinds"`
}
// Instruction holds information about a specific SPIR-V instruction.
type Instruction struct {
Opname string `json:"opname"`
Class string `json:"class"`
Opcode int `json:"opcode"`
Operands []Operand `json:"operands"`
}
// Operand contains information about a logical operand for an instruction.
type Operand struct {
Kind string `json:"kind"`
Name string `json:"name"`
Quantifier Quantifier `json:"quantifier"`
}
// OperandKind contains information about a specific operand kind.
type OperandKind struct {
Category string `json:"category"`
Kind string `json:"kind"`
Enumerants []Enumerant `json:"enumerants"`
Bases []string `json:"bases"`
}
// Enumerant contains information about an enumerant in an enum.
type Enumerant struct {
Enumerant string `json:"enumerant"`
Value interface{} `json:"value"`
Capabilities []string `json:"capabilities"`
Parameters []Parameter `json:"parameters"`
Version string `json:"version"`
}
// Parameter contains information about a logical parameter for an enumerant.
type Parameter struct {
Kind string `json:"kind"`
Name string `json:"name"`
}
// Quantifier indicates the number of times the quantified term may appear.
type Quantifier string
const (
// Once indicates the quantified term may appear exactly once.
Once Quantifier = ""
// ZeroOrOnce indicates the quantified term may appear zero or one
// time; an optional term.
ZeroOrOnce Quantifier = "?"
// ZeroOrMany indicates the quantified term may appear any number of
// times.
ZeroOrMany Quantifier = "*"
)

View File

@ -1,167 +0,0 @@
// Copyright (C) 2019 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// gen-grammar generates the spirv.json grammar file from the official SPIR-V
// grammar JSON file.
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"text/template"
"github.com/pkg/errors"
"../grammar"
)
const (
spirvGrammarURL = "https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json"
spirvGrammarName = "spirv.core.grammar.json"
)
var (
templatePath = flag.String("template", "", "Path to input template file (required)")
outputPath = flag.String("out", "", "Path to output generated file (required)")
cachePath = flag.String("cache", "", "Cache directory for downloaded files (optional)")
thisDir = func() string {
_, file, _, _ := runtime.Caller(1)
return filepath.Dir(file)
}()
)
func main() {
flag.Parse()
if *templatePath == "" || *outputPath == "" {
flag.Usage()
os.Exit(1)
}
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
tf, err := ioutil.ReadFile(*templatePath)
if err != nil {
return errors.Wrap(err, "Could not open template file")
}
t, err := template.New("tmpl").
Funcs(template.FuncMap{
"GenerateArguments": func() string {
relPath := func(path string) string {
rel, err := filepath.Rel(thisDir, path)
if err != nil {
return path
}
return rel
}
args := []string{
"--template=" + relPath(*templatePath),
"--out=" + relPath(*outputPath),
}
return "gen-grammar.go " + strings.Join(args, " ")
},
"OperandKindsMatch": func(k grammar.OperandKind) string {
sb := strings.Builder{}
for i, e := range k.Enumerants {
if i > 0 {
sb.WriteString("|")
}
sb.WriteString(e.Enumerant)
}
return sb.String()
},
}).Parse(string(tf))
if err != nil {
return errors.Wrap(err, "Failed to parse template")
}
file, err := getOrDownload(spirvGrammarName, spirvGrammarURL)
if err != nil {
return errors.Wrap(err, "Failed to load grammar file")
}
g := grammar.Root{}
if err := json.NewDecoder(bytes.NewReader(file)).Decode(&g); err != nil {
return errors.Wrap(err, "Failed to parse grammar file")
}
buf := bytes.Buffer{}
if err := t.Execute(&buf, g); err != nil {
return errors.Wrap(err, "Failed to execute template")
}
out := buf.String()
out = strings.ReplaceAll(out, "•", "")
if err := ioutil.WriteFile(*outputPath, []byte(out), 0777); err != nil {
return errors.Wrap(err, "Failed to write output file")
}
return nil
}
// getOrDownload loads the specific file from the cache, or downloads the file
// from the given url.
func getOrDownload(name, url string) ([]byte, error) {
if *cachePath != "" {
if err := os.MkdirAll(*cachePath, 0777); err == nil {
path := filepath.Join(*cachePath, name)
if isFile(path) {
return ioutil.ReadFile(path)
}
}
}
resp, err := http.Get(url)
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if *cachePath != "" {
ioutil.WriteFile(filepath.Join(*cachePath, name), data, 0777)
}
return data, nil
}
// isFile returns true if path is a file.
func isFile(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return !s.IsDir()
}
// isDir returns true if path is a directory.
func isDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}