| // Copyright (c) 2015-2016 The Khronos Group 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. | |
| // Assembler tests for instructions in the "Mode-Setting" section of the | |
| // SPIR-V spec. | |
| #include <string> | |
| #include <tuple> | |
| #include <vector> | |
| #include "gmock/gmock.h" | |
| #include "source/util/string_utils.h" | |
| #include "test/test_fixture.h" | |
| #include "test/unit_spirv.h" | |
| namespace spvtools { | |
| namespace { | |
| using spvtest::EnumCase; | |
| using spvtest::MakeInstruction; | |
| using utils::MakeVector; | |
| using ::testing::Combine; | |
| using ::testing::Eq; | |
| using ::testing::TestWithParam; | |
| using ::testing::Values; | |
| using ::testing::ValuesIn; | |
| // Test OpMemoryModel | |
| // An example case for OpMemoryModel | |
| struct MemoryModelCase { | |
| uint32_t get_addressing_value() const { | |
| return static_cast<uint32_t>(addressing_value); | |
| } | |
| uint32_t get_memory_value() const { | |
| return static_cast<uint32_t>(memory_value); | |
| } | |
| spv::AddressingModel addressing_value; | |
| std::string addressing_name; | |
| spv::MemoryModel memory_value; | |
| std::string memory_name; | |
| }; | |
| using OpMemoryModelTest = | |
| spvtest::TextToBinaryTestBase<TestWithParam<MemoryModelCase>>; | |
| TEST_P(OpMemoryModelTest, AnyMemoryModelCase) { | |
| const std::string input = "OpMemoryModel " + GetParam().addressing_name + | |
| " " + GetParam().memory_name; | |
| EXPECT_THAT(CompiledInstructions(input), | |
| Eq(MakeInstruction(spv::Op::OpMemoryModel, | |
| {GetParam().get_addressing_value(), | |
| GetParam().get_memory_value()}))); | |
| } | |
| #define CASE(ADDRESSING, MEMORY) \ | |
| { \ | |
| spv::AddressingModel::ADDRESSING, #ADDRESSING, spv::MemoryModel::MEMORY, \ | |
| #MEMORY \ | |
| } | |
| // clang-format off | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryMemoryModel, OpMemoryModelTest, | |
| ValuesIn(std::vector<MemoryModelCase>{ | |
| // These cases exercise each addressing model, and | |
| // each memory model, but not necessarily in | |
| // combination. | |
| CASE(Logical,Simple), | |
| CASE(Logical,GLSL450), | |
| CASE(Physical32,OpenCL), | |
| CASE(Physical64,OpenCL), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpMemoryModelTest, WrongModel) { | |
| EXPECT_THAT(CompileFailure("OpMemoryModel xxyyzz Simple"), | |
| Eq("Invalid addressing model 'xxyyzz'.")); | |
| EXPECT_THAT(CompileFailure("OpMemoryModel Logical xxyyzz"), | |
| Eq("Invalid memory model 'xxyyzz'.")); | |
| } | |
| // Test OpEntryPoint | |
| // An example case for OpEntryPoint | |
| struct EntryPointCase { | |
| uint32_t get_execution_value() const { | |
| return static_cast<uint32_t>(execution_value); | |
| } | |
| spv::ExecutionModel execution_value; | |
| std::string execution_name; | |
| std::string entry_point_name; | |
| }; | |
| using OpEntryPointTest = | |
| spvtest::TextToBinaryTestBase<TestWithParam<EntryPointCase>>; | |
| TEST_P(OpEntryPointTest, AnyEntryPointCase) { | |
| // TODO(dneto): utf-8, escaping, quoting cases for entry point name. | |
| const std::string input = "OpEntryPoint " + GetParam().execution_name + | |
| " %1 \"" + GetParam().entry_point_name + "\""; | |
| EXPECT_THAT(CompiledInstructions(input), | |
| Eq(MakeInstruction(spv::Op::OpEntryPoint, | |
| {GetParam().get_execution_value(), 1}, | |
| MakeVector(GetParam().entry_point_name)))); | |
| } | |
| // clang-format off | |
| #define CASE(NAME) spv::ExecutionModel::NAME, #NAME | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryEntryPoint, OpEntryPointTest, | |
| ValuesIn(std::vector<EntryPointCase>{ | |
| { CASE(Vertex), "" }, | |
| { CASE(TessellationControl), "my tess" }, | |
| { CASE(TessellationEvaluation), "really fancy" }, | |
| { CASE(Geometry), "Euclid" }, | |
| { CASE(Fragment), "FAT32" }, | |
| { CASE(GLCompute), "cubic" }, | |
| { CASE(Kernel), "Sanders" }, | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpEntryPointTest, WrongModel) { | |
| EXPECT_THAT(CompileFailure("OpEntryPoint xxyyzz %1 \"fun\""), | |
| Eq("Invalid execution model 'xxyyzz'.")); | |
| } | |
| // Test OpExecutionMode | |
| using OpExecutionModeTest = spvtest::TextToBinaryTestBase< | |
| TestWithParam<std::tuple<spv_target_env, EnumCase<spv::ExecutionMode>>>>; | |
| TEST_P(OpExecutionModeTest, AnyExecutionMode) { | |
| // This string should assemble, but should not validate. | |
| std::stringstream input; | |
| input << "OpExecutionMode %1 " << std::get<1>(GetParam()).name(); | |
| for (auto operand : std::get<1>(GetParam()).operands()) | |
| input << " " << operand; | |
| EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())), | |
| Eq(MakeInstruction(spv::Op::OpExecutionMode, | |
| {1, std::get<1>(GetParam()).value()}, | |
| std::get<1>(GetParam()).operands()))); | |
| } | |
| #define CASE(NAME) spv::ExecutionMode::NAME, #NAME | |
| INSTANTIATE_TEST_SUITE_P( | |
| TextToBinaryExecutionMode, OpExecutionModeTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), | |
| ValuesIn(std::vector<EnumCase<spv::ExecutionMode>>{ | |
| // The operand literal values are arbitrarily chosen, | |
| // but there are the right number of them. | |
| {CASE(Invocations), {101}}, | |
| {CASE(SpacingEqual), {}}, | |
| {CASE(SpacingFractionalEven), {}}, | |
| {CASE(SpacingFractionalOdd), {}}, | |
| {CASE(VertexOrderCw), {}}, | |
| {CASE(VertexOrderCcw), {}}, | |
| {CASE(PixelCenterInteger), {}}, | |
| {CASE(OriginUpperLeft), {}}, | |
| {CASE(OriginLowerLeft), {}}, | |
| {CASE(EarlyFragmentTests), {}}, | |
| {CASE(PointMode), {}}, | |
| {CASE(Xfb), {}}, | |
| {CASE(DepthReplacing), {}}, | |
| {CASE(DepthGreater), {}}, | |
| {CASE(DepthLess), {}}, | |
| {CASE(DepthUnchanged), {}}, | |
| {CASE(LocalSize), {64, 1, 2}}, | |
| {CASE(LocalSizeHint), {8, 2, 4}}, | |
| {CASE(InputPoints), {}}, | |
| {CASE(InputLines), {}}, | |
| {CASE(InputLinesAdjacency), {}}, | |
| {CASE(Triangles), {}}, | |
| {CASE(InputTrianglesAdjacency), {}}, | |
| {CASE(Quads), {}}, | |
| {CASE(Isolines), {}}, | |
| {CASE(OutputVertices), {21}}, | |
| {CASE(OutputPoints), {}}, | |
| {CASE(OutputLineStrip), {}}, | |
| {CASE(OutputTriangleStrip), {}}, | |
| {CASE(VecTypeHint), {96}}, | |
| {CASE(ContractionOff), {}}, | |
| {CASE(SubgroupUniformControlFlowKHR), {}}, | |
| }))); | |
| INSTANTIATE_TEST_SUITE_P( | |
| TextToBinaryExecutionModeV11, OpExecutionModeTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_1), | |
| ValuesIn(std::vector<EnumCase<spv::ExecutionMode>>{ | |
| {CASE(Initializer)}, | |
| {CASE(Finalizer)}, | |
| {CASE(SubgroupSize), {12}}, | |
| {CASE(SubgroupsPerWorkgroup), {64}}}))); | |
| #undef CASE | |
| TEST_F(OpExecutionModeTest, WrongMode) { | |
| EXPECT_THAT(CompileFailure("OpExecutionMode %1 xxyyzz"), | |
| Eq("Invalid execution mode 'xxyyzz'.")); | |
| } | |
| TEST_F(OpExecutionModeTest, TooManyModes) { | |
| EXPECT_THAT(CompileFailure("OpExecutionMode %1 Xfb PointMode"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found 'PointMode'.")); | |
| } | |
| // Test OpCapability | |
| using OpCapabilityTest = | |
| spvtest::TextToBinaryTestBase<TestWithParam<EnumCase<spv::Capability>>>; | |
| TEST_P(OpCapabilityTest, AnyCapability) { | |
| const std::string input = "OpCapability " + GetParam().name(); | |
| EXPECT_THAT(CompiledInstructions(input), | |
| Eq(MakeInstruction(spv::Op::OpCapability, {GetParam().value()}))); | |
| } | |
| // clang-format off | |
| #define CASE(NAME) { spv::Capability::NAME, #NAME } | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryCapability, OpCapabilityTest, | |
| ValuesIn(std::vector<EnumCase<spv::Capability>>{ | |
| CASE(Matrix), | |
| CASE(Shader), | |
| CASE(Geometry), | |
| CASE(Tessellation), | |
| CASE(Addresses), | |
| CASE(Linkage), | |
| CASE(Kernel), | |
| CASE(Vector16), | |
| CASE(Float16Buffer), | |
| CASE(Float16), | |
| CASE(Float64), | |
| CASE(Int64), | |
| CASE(Int64Atomics), | |
| CASE(ImageBasic), | |
| CASE(ImageReadWrite), | |
| CASE(ImageMipmap), | |
| // Value 16 intentionally missing | |
| CASE(Pipes), | |
| CASE(Groups), | |
| CASE(DeviceEnqueue), | |
| CASE(LiteralSampler), | |
| CASE(AtomicStorage), | |
| CASE(Int16), | |
| CASE(TessellationPointSize), | |
| CASE(GeometryPointSize), | |
| CASE(ImageGatherExtended), | |
| // Value 26 intentionally missing | |
| CASE(StorageImageMultisample), | |
| CASE(UniformBufferArrayDynamicIndexing), | |
| CASE(SampledImageArrayDynamicIndexing), | |
| CASE(StorageBufferArrayDynamicIndexing), | |
| CASE(StorageImageArrayDynamicIndexing), | |
| CASE(ClipDistance), | |
| CASE(CullDistance), | |
| CASE(ImageCubeArray), | |
| CASE(SampleRateShading), | |
| CASE(ImageRect), | |
| CASE(SampledRect), | |
| CASE(GenericPointer), | |
| CASE(Int8), | |
| CASE(InputAttachment), | |
| CASE(SparseResidency), | |
| CASE(MinLod), | |
| CASE(Sampled1D), | |
| CASE(Image1D), | |
| CASE(SampledCubeArray), | |
| CASE(SampledBuffer), | |
| CASE(ImageBuffer), | |
| CASE(ImageMSArray), | |
| CASE(StorageImageExtendedFormats), | |
| CASE(ImageQuery), | |
| CASE(DerivativeControl), | |
| CASE(InterpolationFunction), | |
| CASE(TransformFeedback), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| using TextToBinaryCapability = spvtest::TextToBinaryTest; | |
| TEST_F(TextToBinaryCapability, BadMissingCapability) { | |
| EXPECT_THAT(CompileFailure("OpCapability"), | |
| Eq("Expected operand for OpCapability instruction, but found the " | |
| "end of the stream.")); | |
| } | |
| TEST_F(TextToBinaryCapability, BadInvalidCapability) { | |
| EXPECT_THAT(CompileFailure("OpCapability 123"), | |
| Eq("Invalid capability '123'.")); | |
| } | |
| // TODO(dneto): OpExecutionMode | |
| } // namespace | |
| } // namespace spvtools |