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