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::__anon393ae91f0111::MemoryModelCase43 uint32_t get_addressing_value() const {
44 return static_cast<uint32_t>(addressing_value);
45 }
get_memory_valuespvtools::__anon393ae91f0111::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::__anon393ae91f0111::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