From ee1b3bb3bb6407ac2be848506061017455f9ab80 Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 18 Sep 2015 11:19:18 -0400 Subject: [PATCH] Assembler support for image operands from Rev31 Rev32 and later add many more image operands, and rearrange their values. --- CMakeLists.txt | 1 + include/libspirv/libspirv.h | 2 + source/operand.cpp | 30 ++++++++++++ source/text.cpp | 4 +- test/TextToBinary.Image.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 test/TextToBinary.Image.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 431300d..2609c15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Debug.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Function.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Group.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Image.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Literal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Memory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Miscellaneous.cpp diff --git a/include/libspirv/libspirv.h b/include/libspirv/libspirv.h index af67d3e..293bdf8 100644 --- a/include/libspirv/libspirv.h +++ b/include/libspirv/libspirv.h @@ -186,6 +186,8 @@ typedef enum spv_operand_type_t { // In an instruction definition, this may only appear at the end of the // operand types. SPV_OPERAND_TYPE_OPTIONAL_ID, + // An optional image operands mask. A set bit in the mask may + // imply that more arguments are required. SPV_OPERAND_TYPE_OPTIONAL_IMAGE, // A literal number or string, but optional. // TODO(antiagainst): change to SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER. diff --git a/source/operand.cpp b/source/operand.cpp index f0909b9..b3a53ee 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -466,6 +466,31 @@ static const spv_operand_desc_t samplerImageFormatEntries[] = { #undef CASE }; +// Image operand definitions. Each enum value is a mask. When that mask +// bit is set, the instruction should have further ID operands. +// Some mask values depend on a capability. +static const spv_operand_desc_t imageOperandEntries[] = { +// Rev32 and later adds many more enums. +#define CASE(NAME) \ + #NAME, spv::ImageOperands##NAME##Mask, SPV_OPCODE_FLAGS_NONE, 0 +#define CASE_CAP(NAME, CAP) \ + #NAME, spv::ImageOperands##NAME##Mask, SPV_OPCODE_FLAGS_CAPABILITIES, CAP +#define ID SPV_OPERAND_TYPE_ID +#define NONE SPV_OPERAND_TYPE_NONE + {"None", spv::ImageOperandsMaskNone, SPV_OPCODE_FLAGS_NONE, 0, {NONE}}, + {CASE_CAP(Bias, CapabilityShader), {ID, NONE}}, + {CASE(Lod), {ID, NONE}}, + {CASE(Grad), {ID, ID, NONE}}, + {CASE(ConstOffset), {ID, NONE}}, + {CASE_CAP(Offset, CapabilityImageGatherExtended), {ID, NONE}}, + {CASE(ConstOffsets), {ID, NONE}}, + {CASE(Sample), {ID, NONE}}, +#undef CASE +#undef CASE_CAP +#undef ID +#undef NONE +}; + static const spv_operand_desc_t fpFastMathModeEntries[] = { {"None", FPFastMathModeMaskNone, @@ -1392,6 +1417,9 @@ static const spv_operand_desc_group_t opcodeEntryTypes[] = { {SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT, sizeof(samplerImageFormatEntries) / sizeof(spv_operand_desc_t), samplerImageFormatEntries}, + {SPV_OPERAND_TYPE_OPTIONAL_IMAGE, + sizeof(imageOperandEntries) / sizeof(spv_operand_desc_t), + imageOperandEntries}, {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, sizeof(fpFastMathModeEntries) / sizeof(spv_operand_desc_t), fpFastMathModeEntries}, @@ -1572,6 +1600,8 @@ const char *spvOperandTypeStr(spv_operand_type_t type) { return "kernel profiling info"; case SPV_OPERAND_TYPE_CAPABILITY: return "capability"; + case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: + return "image operand"; case SPV_OPERAND_TYPE_NONE: return "NONE"; default: diff --git a/source/text.cpp b/source/text.cpp index afb50a9..95b82d9 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -560,12 +560,10 @@ spv_result_t spvTextEncodeOperand( pDiagnostic)) return SPV_ERROR_INVALID_TEXT; } break; - case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: - assert(0 && " Handle optional optional image operands"); - break; case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_LOOP_CONTROL: + case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: { uint32_t value; diff --git a/test/TextToBinary.Image.cpp b/test/TextToBinary.Image.cpp new file mode 100644 index 0000000..911e056 --- /dev/null +++ b/test/TextToBinary.Image.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2015 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and/or associated documentation files (the +// "Materials"), to deal in the Materials without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Materials, and to +// permit persons to whom the Materials are furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT +// https://www.khronos.org/registry/ +// +// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + +// Assembler tests for instructions in the "Image Instructions" section of +// the SPIR-V spec. + +#include "UnitSPIRV.h" + +#include "gmock/gmock.h" +#include "TestFixture.h" + +namespace { + +using spvtest::MakeInstruction; +using ::testing::Eq; + +// An example case for a mask value with operands. +struct ImageOperandsCase { + std::string image_operands; + // The expected mask, followed by its operands. + std::vector expected_mask_and_operands; +}; + +// Test all kinds of image operands. + +using ImageOperandsTest = test_fixture::TextToBinaryTestBase< + ::testing::TestWithParam>; + +TEST_P(ImageOperandsTest, Sample) { + std::string input = + "%result = OpImageFetch %type %image %coord " + GetParam().image_operands; + std::vector expected_operands{1, 2, 3, 4}; + expected_operands.insert(expected_operands.end(), + GetParam().expected_mask_and_operands.begin(), + GetParam().expected_mask_and_operands.end()); + EXPECT_THAT(CompiledInstructions(input), + Eq(MakeInstruction(spv::OpImageFetch, expected_operands))); +} + +#define MASK(NAME) spv::ImageOperands##NAME##Mask +INSTANTIATE_TEST_CASE_P( + TextToBinaryImageOperandsAny, ImageOperandsTest, + ::testing::ValuesIn(std::vector{ + // TODO(dneto): Rev32 adds many more values, and rearranges their + // values. + // Image operands are optional. + {"", {}}, + // Test each kind, alone. + {"Bias %5", {MASK(Bias), 5}}, + {"Lod %10", {MASK(Lod), 10}}, + {"Grad %11 %12", {MASK(Grad), 11, 12}}, + {"ConstOffset %13", {MASK(ConstOffset), 13}}, + {"Offset %14", {MASK(Offset), 14}}, + {"ConstOffsets %15", {MASK(ConstOffsets), 15}}, + {"Sample %16", {MASK(Sample), 16}}, + })); + +INSTANTIATE_TEST_CASE_P( + TextToBinaryImageOperandsCombination, ImageOperandsTest, + ::testing::ValuesIn(std::vector{ + // TODO(dneto): Rev32 adds many more values, and rearranges their + // values. + // Test adjacent pairs, so we can easily debug the values when it fails. + {"Bias|Lod %10 %11", {MASK(Bias) | MASK(Lod), 10, 11}}, + {"Lod|Grad %12 %13 %14", {MASK(Lod) | MASK(Grad), 12, 13, 14}}, + {"Grad|ConstOffset %15 %16 %17", + {MASK(Grad) | MASK(ConstOffset), 15, 16, 17}}, + {"ConstOffset|Offset %18 %19", + {MASK(ConstOffset) | MASK(Offset), 18, 19}}, + {"Offset|ConstOffsets %20 %21", + {MASK(Offset) | MASK(ConstOffsets), 20, 21}}, + {"ConstOffsets|Sample %22 %23", + {MASK(ConstOffsets) | MASK(Sample), 22, 23}}, + // Test all masks together. + {"Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample" + " %5 %10 %11 %12 %13 %14 %15 %16", + {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) | + MASK(Offset) | MASK(ConstOffsets) | MASK(Sample), + 5, 10, 11, 12, 13, 14, 15, 16}}, + // The same, but with mask value names reversed. + {"Sample|ConstOffsets|Offset|ConstOffset|Grad|Lod|Bias" + " %5 %10 %11 %12 %13 %14 %15 %16", + {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) | + MASK(Offset) | MASK(ConstOffsets) | MASK(Sample), + 5, 10, 11, 12, 13, 14, 15, 16}}, + })); +#undef MASK + +} // anonymous namespace -- 2.7.4