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 "Type-Declaration" section of the
16 // SPIR-V spec.
17 
18 #include <string>
19 #include <vector>
20 
21 #include "gmock/gmock.h"
22 #include "test/test_fixture.h"
23 #include "test/unit_spirv.h"
24 
25 namespace spvtools {
26 namespace {
27 
28 using spvtest::EnumCase;
29 using spvtest::MakeInstruction;
30 using ::testing::Eq;
31 
32 // Test Dim enums via OpTypeImage
33 
34 using DimTest =
35     spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvDim>>>;
36 
TEST_P(DimTest,AnyDim)37 TEST_P(DimTest, AnyDim) {
38   const std::string input =
39       "%1 = OpTypeImage %2 " + GetParam().name() + " 2 3 0 4 Rgba8\n";
40   EXPECT_THAT(
41       CompiledInstructions(input),
42       Eq(MakeInstruction(SpvOpTypeImage, {1, 2, GetParam().value(), 2, 3, 0, 4,
43                                           SpvImageFormatRgba8})));
44 
45   // Check the disassembler as well.
46   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
47 }
48 
49 // clang-format off
50 #define CASE(NAME) {SpvDim##NAME, #NAME}
51 INSTANTIATE_TEST_SUITE_P(
52     TextToBinaryDim, DimTest,
53     ::testing::ValuesIn(std::vector<EnumCase<SpvDim>>{
54         CASE(1D),
55         CASE(2D),
56         CASE(3D),
57         CASE(Cube),
58         CASE(Rect),
59         CASE(Buffer),
60         CASE(SubpassData),
61     }));
62 #undef CASE
63 // clang-format on
64 
TEST_F(DimTest,WrongDim)65 TEST_F(DimTest, WrongDim) {
66   EXPECT_THAT(CompileFailure("%i = OpTypeImage %t xxyyzz 1 2 3 4 R8"),
67               Eq("Invalid dimensionality 'xxyyzz'."));
68 }
69 
70 // Test ImageFormat enums via OpTypeImage
71 
72 using ImageFormatTest = spvtest::TextToBinaryTestBase<
73     ::testing::TestWithParam<EnumCase<SpvImageFormat>>>;
74 
TEST_P(ImageFormatTest,AnyImageFormatAndNoAccessQualifier)75 TEST_P(ImageFormatTest, AnyImageFormatAndNoAccessQualifier) {
76   const std::string input =
77       "%1 = OpTypeImage %2 1D 2 3 0 4 " + GetParam().name() + "\n";
78   EXPECT_THAT(CompiledInstructions(input),
79               Eq(MakeInstruction(SpvOpTypeImage, {1, 2, SpvDim1D, 2, 3, 0, 4,
80                                                   GetParam().value()})));
81   // Check the disassembler as well.
82   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
83 }
84 
85 // clang-format off
86 #define CASE(NAME) {SpvImageFormat##NAME, #NAME}
87 INSTANTIATE_TEST_SUITE_P(
88     TextToBinaryImageFormat, ImageFormatTest,
89     ::testing::ValuesIn(std::vector<EnumCase<SpvImageFormat>>{
90         CASE(Unknown),
91         CASE(Rgba32f),
92         CASE(Rgba16f),
93         CASE(R32f),
94         CASE(Rgba8),
95         CASE(Rgba8Snorm),
96         CASE(Rg32f),
97         CASE(Rg16f),
98         CASE(R11fG11fB10f),
99         CASE(R16f),
100         CASE(Rgba16),
101         CASE(Rgb10A2),
102         CASE(Rg16),
103         CASE(Rg8),
104         CASE(R16),
105         CASE(R8),
106         CASE(Rgba16Snorm),
107         CASE(Rg16Snorm),
108         CASE(Rg8Snorm),
109         CASE(R16Snorm),
110         CASE(R8Snorm),
111         CASE(Rgba32i),
112         CASE(Rgba16i),
113         CASE(Rgba8i),
114         CASE(R32i),
115         CASE(Rg32i),
116         CASE(Rg16i),
117         CASE(Rg8i),
118         CASE(R16i),
119         CASE(R8i),
120         CASE(Rgba32ui),
121         CASE(Rgba16ui),
122         CASE(Rgba8ui),
123         CASE(R32ui),
124         CASE(Rgb10a2ui),
125         CASE(Rg32ui),
126         CASE(Rg16ui),
127         CASE(Rg8ui),
128         CASE(R16ui),
129         CASE(R8ui),
130     }));
131 #undef CASE
132 // clang-format on
133 
TEST_F(ImageFormatTest,WrongFormat)134 TEST_F(ImageFormatTest, WrongFormat) {
135   EXPECT_THAT(CompileFailure("%r = OpTypeImage %t 1D  2 3 0 4 xxyyzz"),
136               Eq("Invalid image format 'xxyyzz'."));
137 }
138 
139 // Test AccessQualifier enums via OpTypeImage.
140 using ImageAccessQualifierTest = spvtest::TextToBinaryTestBase<
141     ::testing::TestWithParam<EnumCase<SpvAccessQualifier>>>;
142 
TEST_P(ImageAccessQualifierTest,AnyAccessQualifier)143 TEST_P(ImageAccessQualifierTest, AnyAccessQualifier) {
144   const std::string input =
145       "%1 = OpTypeImage %2 1D 2 3 0 4 Rgba8 " + GetParam().name() + "\n";
146   EXPECT_THAT(CompiledInstructions(input),
147               Eq(MakeInstruction(SpvOpTypeImage,
148                                  {1, 2, SpvDim1D, 2, 3, 0, 4,
149                                   SpvImageFormatRgba8, GetParam().value()})));
150   // Check the disassembler as well.
151   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
152 }
153 
154 // clang-format off
155 #define CASE(NAME) {SpvAccessQualifier##NAME, #NAME}
156 INSTANTIATE_TEST_SUITE_P(
157     AccessQualifier, ImageAccessQualifierTest,
158     ::testing::ValuesIn(std::vector<EnumCase<SpvAccessQualifier>>{
159       CASE(ReadOnly),
160       CASE(WriteOnly),
161       CASE(ReadWrite),
162     }));
163 // clang-format on
164 #undef CASE
165 
166 // Test AccessQualifier enums via OpTypePipe.
167 
168 using OpTypePipeTest = spvtest::TextToBinaryTestBase<
169     ::testing::TestWithParam<EnumCase<SpvAccessQualifier>>>;
170 
TEST_P(OpTypePipeTest,AnyAccessQualifier)171 TEST_P(OpTypePipeTest, AnyAccessQualifier) {
172   const std::string input = "%1 = OpTypePipe " + GetParam().name() + "\n";
173   EXPECT_THAT(CompiledInstructions(input),
174               Eq(MakeInstruction(SpvOpTypePipe, {1, GetParam().value()})));
175   // Check the disassembler as well.
176   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
177 }
178 
179 // clang-format off
180 #define CASE(NAME) {SpvAccessQualifier##NAME, #NAME}
181 INSTANTIATE_TEST_SUITE_P(
182     TextToBinaryTypePipe, OpTypePipeTest,
183     ::testing::ValuesIn(std::vector<EnumCase<SpvAccessQualifier>>{
184                             CASE(ReadOnly),
185                             CASE(WriteOnly),
186                             CASE(ReadWrite),
187     }));
188 #undef CASE
189 // clang-format on
190 
TEST_F(OpTypePipeTest,WrongAccessQualifier)191 TEST_F(OpTypePipeTest, WrongAccessQualifier) {
192   EXPECT_THAT(CompileFailure("%1 = OpTypePipe xxyyzz"),
193               Eq("Invalid access qualifier 'xxyyzz'."));
194 }
195 
196 using OpTypeForwardPointerTest = spvtest::TextToBinaryTest;
197 
198 #define CASE(storage_class)                                               \
199   do {                                                                    \
200     EXPECT_THAT(                                                          \
201         CompiledInstructions("OpTypeForwardPointer %pt " #storage_class), \
202         Eq(MakeInstruction(SpvOpTypeForwardPointer,                       \
203                            {1, SpvStorageClass##storage_class})));        \
204   } while (0)
205 
TEST_F(OpTypeForwardPointerTest,ValidStorageClass)206 TEST_F(OpTypeForwardPointerTest, ValidStorageClass) {
207   CASE(UniformConstant);
208   CASE(Input);
209   CASE(Uniform);
210   CASE(Output);
211   CASE(Workgroup);
212   CASE(CrossWorkgroup);
213   CASE(Private);
214   CASE(Function);
215   CASE(Generic);
216   CASE(PushConstant);
217   CASE(AtomicCounter);
218   CASE(Image);
219   CASE(StorageBuffer);
220 }
221 
222 #undef CASE
223 
TEST_F(OpTypeForwardPointerTest,MissingType)224 TEST_F(OpTypeForwardPointerTest, MissingType) {
225   EXPECT_THAT(CompileFailure("OpTypeForwardPointer"),
226               Eq("Expected operand, found end of stream."));
227 }
228 
TEST_F(OpTypeForwardPointerTest,MissingClass)229 TEST_F(OpTypeForwardPointerTest, MissingClass) {
230   EXPECT_THAT(CompileFailure("OpTypeForwardPointer %pt"),
231               Eq("Expected operand, found end of stream."));
232 }
233 
TEST_F(OpTypeForwardPointerTest,WrongClass)234 TEST_F(OpTypeForwardPointerTest, WrongClass) {
235   EXPECT_THAT(CompileFailure("OpTypeForwardPointer %pt xxyyzz"),
236               Eq("Invalid storage class 'xxyyzz'."));
237 }
238 
239 using OpSizeOfTest = spvtest::TextToBinaryTest;
240 
241 // We should be able to assemble it.  Validation checks are in another test
242 // file.
TEST_F(OpSizeOfTest,OpcodeAssemblesInV10)243 TEST_F(OpSizeOfTest, OpcodeAssemblesInV10) {
244   EXPECT_THAT(
245       CompiledInstructions("%1 = OpSizeOf %2 %3", SPV_ENV_UNIVERSAL_1_0),
246       Eq(MakeInstruction(SpvOpSizeOf, {1, 2, 3})));
247 }
248 
TEST_F(OpSizeOfTest,ArgumentCount)249 TEST_F(OpSizeOfTest, ArgumentCount) {
250   EXPECT_THAT(
251       CompileFailure("OpSizeOf", SPV_ENV_UNIVERSAL_1_1),
252       Eq("Expected <result-id> at the beginning of an instruction, found "
253          "'OpSizeOf'."));
254   EXPECT_THAT(CompileFailure("%res = OpSizeOf OpNop", SPV_ENV_UNIVERSAL_1_1),
255               Eq("Expected operand, found next instruction instead."));
256   EXPECT_THAT(
257       CompiledInstructions("%1 = OpSizeOf %2 %3", SPV_ENV_UNIVERSAL_1_1),
258       Eq(MakeInstruction(SpvOpSizeOf, {1, 2, 3})));
259   EXPECT_THAT(
260       CompileFailure("%1 = OpSizeOf %2 %3 44 55 ", SPV_ENV_UNIVERSAL_1_1),
261       Eq("Expected <opcode> or <result-id> at the beginning of an instruction, "
262          "found '44'."));
263 }
264 
TEST_F(OpSizeOfTest,ArgumentTypes)265 TEST_F(OpSizeOfTest, ArgumentTypes) {
266   EXPECT_THAT(CompileFailure("%1 = OpSizeOf 2 %3", SPV_ENV_UNIVERSAL_1_1),
267               Eq("Expected id to start with %."));
268   EXPECT_THAT(CompileFailure("%1 = OpSizeOf %2 \"abc\"", SPV_ENV_UNIVERSAL_1_1),
269               Eq("Expected id to start with %."));
270 }
271 
272 // TODO(dneto): OpTypeVoid
273 // TODO(dneto): OpTypeBool
274 // TODO(dneto): OpTypeInt
275 // TODO(dneto): OpTypeFloat
276 // TODO(dneto): OpTypeVector
277 // TODO(dneto): OpTypeMatrix
278 // TODO(dneto): OpTypeImage
279 // TODO(dneto): OpTypeSampler
280 // TODO(dneto): OpTypeSampledImage
281 // TODO(dneto): OpTypeArray
282 // TODO(dneto): OpTypeRuntimeArray
283 // TODO(dneto): OpTypeStruct
284 // TODO(dneto): OpTypeOpaque
285 // TODO(dneto): OpTypePointer
286 // TODO(dneto): OpTypeFunction
287 // TODO(dneto): OpTypeEvent
288 // TODO(dneto): OpTypeDeviceEvent
289 // TODO(dneto): OpTypeReserveId
290 // TODO(dneto): OpTypeQueue
291 
292 }  // namespace
293 }  // namespace spvtools
294