1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Assembler tests for instructions in the "Mode-Setting" section of the
16 // SPIR-V spec.
17 
18 #include <string>
19 #include <tuple>
20 #include <vector>
21 
22 #include "gmock/gmock.h"
23 #include "source/util/string_utils.h"
24 #include "test/test_fixture.h"
25 #include "test/unit_spirv.h"
26 
27 namespace spvtools {
28 namespace {
29 
30 using spvtest::EnumCase;
31 using spvtest::MakeInstruction;
32 using utils::MakeVector;
33 using ::testing::Combine;
34 using ::testing::Eq;
35 using ::testing::TestWithParam;
36 using ::testing::Values;
37 using ::testing::ValuesIn;
38 
39 // Test OpMemoryModel
40 
41 // An example case for OpMemoryModel
42 struct MemoryModelCase {
get_addressing_valuespvtools::__anond7e013350111::MemoryModelCase43   uint32_t get_addressing_value() const {
44     return static_cast<uint32_t>(addressing_value);
45   }
get_memory_valuespvtools::__anond7e013350111::MemoryModelCase46   uint32_t get_memory_value() const {
47     return static_cast<uint32_t>(memory_value);
48   }
49   SpvAddressingModel addressing_value;
50   std::string addressing_name;
51   SpvMemoryModel memory_value;
52   std::string memory_name;
53 };
54 
55 using OpMemoryModelTest =
56     spvtest::TextToBinaryTestBase<TestWithParam<MemoryModelCase>>;
57 
TEST_P(OpMemoryModelTest,AnyMemoryModelCase)58 TEST_P(OpMemoryModelTest, AnyMemoryModelCase) {
59   const std::string input = "OpMemoryModel " + GetParam().addressing_name +
60                             " " + GetParam().memory_name;
61   EXPECT_THAT(
62       CompiledInstructions(input),
63       Eq(MakeInstruction(SpvOpMemoryModel, {GetParam().get_addressing_value(),
64                                             GetParam().get_memory_value()})));
65 }
66 
67 #define CASE(ADDRESSING, MEMORY)                                         \
68   {                                                                      \
69     SpvAddressingModel##ADDRESSING, #ADDRESSING, SpvMemoryModel##MEMORY, \
70         #MEMORY                                                          \
71   }
72 // clang-format off
73 INSTANTIATE_TEST_SUITE_P(TextToBinaryMemoryModel, OpMemoryModelTest,
74                         ValuesIn(std::vector<MemoryModelCase>{
75                           // These cases exercise each addressing model, and
76                           // each memory model, but not necessarily in
77                           // combination.
78                             CASE(Logical,Simple),
79                             CASE(Logical,GLSL450),
80                             CASE(Physical32,OpenCL),
81                             CASE(Physical64,OpenCL),
82                         }));
83 #undef CASE
84 // clang-format on
85 
TEST_F(OpMemoryModelTest,WrongModel)86 TEST_F(OpMemoryModelTest, WrongModel) {
87   EXPECT_THAT(CompileFailure("OpMemoryModel xxyyzz Simple"),
88               Eq("Invalid addressing model 'xxyyzz'."));
89   EXPECT_THAT(CompileFailure("OpMemoryModel Logical xxyyzz"),
90               Eq("Invalid memory model 'xxyyzz'."));
91 }
92 
93 // Test OpEntryPoint
94 
95 // An example case for OpEntryPoint
96 struct EntryPointCase {
get_execution_valuespvtools::__anond7e013350111::EntryPointCase97   uint32_t get_execution_value() const {
98     return static_cast<uint32_t>(execution_value);
99   }
100   SpvExecutionModel execution_value;
101   std::string execution_name;
102   std::string entry_point_name;
103 };
104 
105 using OpEntryPointTest =
106     spvtest::TextToBinaryTestBase<TestWithParam<EntryPointCase>>;
107 
TEST_P(OpEntryPointTest,AnyEntryPointCase)108 TEST_P(OpEntryPointTest, AnyEntryPointCase) {
109   // TODO(dneto): utf-8, escaping, quoting cases for entry point name.
110   const std::string input = "OpEntryPoint " + GetParam().execution_name +
111                             " %1 \"" + GetParam().entry_point_name + "\"";
112   EXPECT_THAT(
113       CompiledInstructions(input),
114       Eq(MakeInstruction(SpvOpEntryPoint, {GetParam().get_execution_value(), 1},
115                          MakeVector(GetParam().entry_point_name))));
116 }
117 
118 // clang-format off
119 #define CASE(NAME) SpvExecutionModel##NAME, #NAME
120 INSTANTIATE_TEST_SUITE_P(TextToBinaryEntryPoint, OpEntryPointTest,
121                         ValuesIn(std::vector<EntryPointCase>{
122                           { CASE(Vertex), "" },
123                           { CASE(TessellationControl), "my tess" },
124                           { CASE(TessellationEvaluation), "really fancy" },
125                           { CASE(Geometry), "Euclid" },
126                           { CASE(Fragment), "FAT32" },
127                           { CASE(GLCompute), "cubic" },
128                           { CASE(Kernel), "Sanders" },
129                         }));
130 #undef CASE
131 // clang-format on
132 
TEST_F(OpEntryPointTest,WrongModel)133 TEST_F(OpEntryPointTest, WrongModel) {
134   EXPECT_THAT(CompileFailure("OpEntryPoint xxyyzz %1 \"fun\""),
135               Eq("Invalid execution model 'xxyyzz'."));
136 }
137 
138 // Test OpExecutionMode
139 using OpExecutionModeTest = spvtest::TextToBinaryTestBase<
140     TestWithParam<std::tuple<spv_target_env, EnumCase<SpvExecutionMode>>>>;
141 
TEST_P(OpExecutionModeTest,AnyExecutionMode)142 TEST_P(OpExecutionModeTest, AnyExecutionMode) {
143   // This string should assemble, but should not validate.
144   std::stringstream input;
145   input << "OpExecutionMode %1 " << std::get<1>(GetParam()).name();
146   for (auto operand : std::get<1>(GetParam()).operands())
147     input << " " << operand;
148   EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())),
149               Eq(MakeInstruction(SpvOpExecutionMode,
150                                  {1, std::get<1>(GetParam()).value()},
151                                  std::get<1>(GetParam()).operands())));
152 }
153 
154 #define CASE(NAME) SpvExecutionMode##NAME, #NAME
155 INSTANTIATE_TEST_SUITE_P(
156     TextToBinaryExecutionMode, OpExecutionModeTest,
157     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
158             ValuesIn(std::vector<EnumCase<SpvExecutionMode>>{
159                 // The operand literal values are arbitrarily chosen,
160                 // but there are the right number of them.
161                 {CASE(Invocations), {101}},
162                 {CASE(SpacingEqual), {}},
163                 {CASE(SpacingFractionalEven), {}},
164                 {CASE(SpacingFractionalOdd), {}},
165                 {CASE(VertexOrderCw), {}},
166                 {CASE(VertexOrderCcw), {}},
167                 {CASE(PixelCenterInteger), {}},
168                 {CASE(OriginUpperLeft), {}},
169                 {CASE(OriginLowerLeft), {}},
170                 {CASE(EarlyFragmentTests), {}},
171                 {CASE(PointMode), {}},
172                 {CASE(Xfb), {}},
173                 {CASE(DepthReplacing), {}},
174                 {CASE(DepthGreater), {}},
175                 {CASE(DepthLess), {}},
176                 {CASE(DepthUnchanged), {}},
177                 {CASE(LocalSize), {64, 1, 2}},
178                 {CASE(LocalSizeHint), {8, 2, 4}},
179                 {CASE(InputPoints), {}},
180                 {CASE(InputLines), {}},
181                 {CASE(InputLinesAdjacency), {}},
182                 {CASE(Triangles), {}},
183                 {CASE(InputTrianglesAdjacency), {}},
184                 {CASE(Quads), {}},
185                 {CASE(Isolines), {}},
186                 {CASE(OutputVertices), {21}},
187                 {CASE(OutputPoints), {}},
188                 {CASE(OutputLineStrip), {}},
189                 {CASE(OutputTriangleStrip), {}},
190                 {CASE(VecTypeHint), {96}},
191                 {CASE(ContractionOff), {}},
192                 {CASE(SubgroupUniformControlFlowKHR), {}},
193             })));
194 
195 INSTANTIATE_TEST_SUITE_P(
196     TextToBinaryExecutionModeV11, OpExecutionModeTest,
197     Combine(Values(SPV_ENV_UNIVERSAL_1_1),
198             ValuesIn(std::vector<EnumCase<SpvExecutionMode>>{
199                 {CASE(Initializer)},
200                 {CASE(Finalizer)},
201                 {CASE(SubgroupSize), {12}},
202                 {CASE(SubgroupsPerWorkgroup), {64}}})));
203 #undef CASE
204 
TEST_F(OpExecutionModeTest,WrongMode)205 TEST_F(OpExecutionModeTest, WrongMode) {
206   EXPECT_THAT(CompileFailure("OpExecutionMode %1 xxyyzz"),
207               Eq("Invalid execution mode 'xxyyzz'."));
208 }
209 
TEST_F(OpExecutionModeTest,TooManyModes)210 TEST_F(OpExecutionModeTest, TooManyModes) {
211   EXPECT_THAT(CompileFailure("OpExecutionMode %1 Xfb PointMode"),
212               Eq("Expected <opcode> or <result-id> at the beginning of an "
213                  "instruction, found 'PointMode'."));
214 }
215 
216 // Test OpCapability
217 
218 using OpCapabilityTest =
219     spvtest::TextToBinaryTestBase<TestWithParam<EnumCase<SpvCapability>>>;
220 
TEST_P(OpCapabilityTest,AnyCapability)221 TEST_P(OpCapabilityTest, AnyCapability) {
222   const std::string input = "OpCapability " + GetParam().name();
223   EXPECT_THAT(CompiledInstructions(input),
224               Eq(MakeInstruction(SpvOpCapability, {GetParam().value()})));
225 }
226 
227 // clang-format off
228 #define CASE(NAME) { SpvCapability##NAME, #NAME }
229 INSTANTIATE_TEST_SUITE_P(TextToBinaryCapability, OpCapabilityTest,
230                         ValuesIn(std::vector<EnumCase<SpvCapability>>{
231                             CASE(Matrix),
232                             CASE(Shader),
233                             CASE(Geometry),
234                             CASE(Tessellation),
235                             CASE(Addresses),
236                             CASE(Linkage),
237                             CASE(Kernel),
238                             CASE(Vector16),
239                             CASE(Float16Buffer),
240                             CASE(Float16),
241                             CASE(Float64),
242                             CASE(Int64),
243                             CASE(Int64Atomics),
244                             CASE(ImageBasic),
245                             CASE(ImageReadWrite),
246                             CASE(ImageMipmap),
247                             // Value 16 intentionally missing
248                             CASE(Pipes),
249                             CASE(Groups),
250                             CASE(DeviceEnqueue),
251                             CASE(LiteralSampler),
252                             CASE(AtomicStorage),
253                             CASE(Int16),
254                             CASE(TessellationPointSize),
255                             CASE(GeometryPointSize),
256                             CASE(ImageGatherExtended),
257                             // Value 26 intentionally missing
258                             CASE(StorageImageMultisample),
259                             CASE(UniformBufferArrayDynamicIndexing),
260                             CASE(SampledImageArrayDynamicIndexing),
261                             CASE(StorageBufferArrayDynamicIndexing),
262                             CASE(StorageImageArrayDynamicIndexing),
263                             CASE(ClipDistance),
264                             CASE(CullDistance),
265                             CASE(ImageCubeArray),
266                             CASE(SampleRateShading),
267                             CASE(ImageRect),
268                             CASE(SampledRect),
269                             CASE(GenericPointer),
270                             CASE(Int8),
271                             CASE(InputAttachment),
272                             CASE(SparseResidency),
273                             CASE(MinLod),
274                             CASE(Sampled1D),
275                             CASE(Image1D),
276                             CASE(SampledCubeArray),
277                             CASE(SampledBuffer),
278                             CASE(ImageBuffer),
279                             CASE(ImageMSArray),
280                             CASE(StorageImageExtendedFormats),
281                             CASE(ImageQuery),
282                             CASE(DerivativeControl),
283                             CASE(InterpolationFunction),
284                             CASE(TransformFeedback),
285                         }));
286 #undef CASE
287 // clang-format on
288 
289 using TextToBinaryCapability = spvtest::TextToBinaryTest;
290 
TEST_F(TextToBinaryCapability,BadMissingCapability)291 TEST_F(TextToBinaryCapability, BadMissingCapability) {
292   EXPECT_THAT(CompileFailure("OpCapability"),
293               Eq("Expected operand, found end of stream."));
294 }
295 
TEST_F(TextToBinaryCapability,BadInvalidCapability)296 TEST_F(TextToBinaryCapability, BadInvalidCapability) {
297   EXPECT_THAT(CompileFailure("OpCapability 123"),
298               Eq("Invalid capability '123'."));
299 }
300 
301 // TODO(dneto): OpExecutionMode
302 
303 }  // namespace
304 }  // namespace spvtools
305