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::__anondf6d11cb0111::MemoryModelCase43   uint32_t get_addressing_value() const {
44     return static_cast<uint32_t>(addressing_value);
45   }
get_memory_valuespvtools::__anondf6d11cb0111::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::__anondf6d11cb0111::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             })));
193 
194 INSTANTIATE_TEST_SUITE_P(
195     TextToBinaryExecutionModeV11, OpExecutionModeTest,
196     Combine(Values(SPV_ENV_UNIVERSAL_1_1),
197             ValuesIn(std::vector<EnumCase<SpvExecutionMode>>{
198                 {CASE(Initializer)},
199                 {CASE(Finalizer)},
200                 {CASE(SubgroupSize), {12}},
201                 {CASE(SubgroupsPerWorkgroup), {64}}})));
202 #undef CASE
203 
TEST_F(OpExecutionModeTest,WrongMode)204 TEST_F(OpExecutionModeTest, WrongMode) {
205   EXPECT_THAT(CompileFailure("OpExecutionMode %1 xxyyzz"),
206               Eq("Invalid execution mode 'xxyyzz'."));
207 }
208 
TEST_F(OpExecutionModeTest,TooManyModes)209 TEST_F(OpExecutionModeTest, TooManyModes) {
210   EXPECT_THAT(CompileFailure("OpExecutionMode %1 Xfb PointMode"),
211               Eq("Expected <opcode> or <result-id> at the beginning of an "
212                  "instruction, found 'PointMode'."));
213 }
214 
215 // Test OpCapability
216 
217 using OpCapabilityTest =
218     spvtest::TextToBinaryTestBase<TestWithParam<EnumCase<SpvCapability>>>;
219 
TEST_P(OpCapabilityTest,AnyCapability)220 TEST_P(OpCapabilityTest, AnyCapability) {
221   const std::string input = "OpCapability " + GetParam().name();
222   EXPECT_THAT(CompiledInstructions(input),
223               Eq(MakeInstruction(SpvOpCapability, {GetParam().value()})));
224 }
225 
226 // clang-format off
227 #define CASE(NAME) { SpvCapability##NAME, #NAME }
228 INSTANTIATE_TEST_SUITE_P(TextToBinaryCapability, OpCapabilityTest,
229                         ValuesIn(std::vector<EnumCase<SpvCapability>>{
230                             CASE(Matrix),
231                             CASE(Shader),
232                             CASE(Geometry),
233                             CASE(Tessellation),
234                             CASE(Addresses),
235                             CASE(Linkage),
236                             CASE(Kernel),
237                             CASE(Vector16),
238                             CASE(Float16Buffer),
239                             CASE(Float16),
240                             CASE(Float64),
241                             CASE(Int64),
242                             CASE(Int64Atomics),
243                             CASE(ImageBasic),
244                             CASE(ImageReadWrite),
245                             CASE(ImageMipmap),
246                             // Value 16 intentionally missing
247                             CASE(Pipes),
248                             CASE(Groups),
249                             CASE(DeviceEnqueue),
250                             CASE(LiteralSampler),
251                             CASE(AtomicStorage),
252                             CASE(Int16),
253                             CASE(TessellationPointSize),
254                             CASE(GeometryPointSize),
255                             CASE(ImageGatherExtended),
256                             // Value 26 intentionally missing
257                             CASE(StorageImageMultisample),
258                             CASE(UniformBufferArrayDynamicIndexing),
259                             CASE(SampledImageArrayDynamicIndexing),
260                             CASE(StorageBufferArrayDynamicIndexing),
261                             CASE(StorageImageArrayDynamicIndexing),
262                             CASE(ClipDistance),
263                             CASE(CullDistance),
264                             CASE(ImageCubeArray),
265                             CASE(SampleRateShading),
266                             CASE(ImageRect),
267                             CASE(SampledRect),
268                             CASE(GenericPointer),
269                             CASE(Int8),
270                             CASE(InputAttachment),
271                             CASE(SparseResidency),
272                             CASE(MinLod),
273                             CASE(Sampled1D),
274                             CASE(Image1D),
275                             CASE(SampledCubeArray),
276                             CASE(SampledBuffer),
277                             CASE(ImageBuffer),
278                             CASE(ImageMSArray),
279                             CASE(StorageImageExtendedFormats),
280                             CASE(ImageQuery),
281                             CASE(DerivativeControl),
282                             CASE(InterpolationFunction),
283                             CASE(TransformFeedback),
284                         }));
285 #undef CASE
286 // clang-format on
287 
288 using TextToBinaryCapability = spvtest::TextToBinaryTest;
289 
TEST_F(TextToBinaryCapability,BadMissingCapability)290 TEST_F(TextToBinaryCapability, BadMissingCapability) {
291   EXPECT_THAT(CompileFailure("OpCapability"),
292               Eq("Expected operand, found end of stream."));
293 }
294 
TEST_F(TextToBinaryCapability,BadInvalidCapability)295 TEST_F(TextToBinaryCapability, BadInvalidCapability) {
296   EXPECT_THAT(CompileFailure("OpCapability 123"),
297               Eq("Invalid capability '123'."));
298 }
299 
300 // TODO(dneto): OpExecutionMode
301 
302 }  // namespace
303 }  // namespace spvtools
304