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