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 "Image Instructions" section of
16 // the 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::MakeInstruction;
29 using spvtest::TextToBinaryTest;
30 using ::testing::Eq;
31
32 // An example case for a mask value with operands.
33 struct ImageOperandsCase {
34 std::string image_operands;
35 // The expected mask, followed by its operands.
36 std::vector<uint32_t> expected_mask_and_operands;
37 };
38
39 // Test all kinds of image operands.
40
41 using ImageOperandsTest =
42 spvtest::TextToBinaryTestBase<::testing::TestWithParam<ImageOperandsCase>>;
43
TEST_P(ImageOperandsTest,Sample)44 TEST_P(ImageOperandsTest, Sample) {
45 const std::string input =
46 "%2 = OpImageFetch %1 %3 %4" + GetParam().image_operands + "\n";
47 EXPECT_THAT(CompiledInstructions(input),
48 Eq(MakeInstruction(SpvOpImageFetch, {1, 2, 3, 4},
49 GetParam().expected_mask_and_operands)));
50 }
51
52 #define MASK(NAME) SpvImageOperands##NAME##Mask
53 INSTANTIATE_TEST_CASE_P(
54 TextToBinaryImageOperandsAny, ImageOperandsTest,
55 ::testing::ValuesIn(std::vector<ImageOperandsCase>{
56 // TODO(dneto): Rev32 adds many more values, and rearranges their
57 // values.
58 // Image operands are optional.
59 {"", {}},
60 // Test each kind, alone.
61 {" Bias %5", {MASK(Bias), 5}},
62 {" Lod %5", {MASK(Lod), 5}},
63 {" Grad %5 %6", {MASK(Grad), 5, 6}},
64 {" ConstOffset %5", {MASK(ConstOffset), 5}},
65 {" Offset %5", {MASK(Offset), 5}},
66 {" ConstOffsets %5", {MASK(ConstOffsets), 5}},
67 {" Sample %5", {MASK(Sample), 5}},
68 {" MinLod %5", {MASK(MinLod), 5}},
69 }), );
70 #undef MASK
71 #define MASK(NAME) static_cast<uint32_t>(SpvImageOperands##NAME##Mask)
72 INSTANTIATE_TEST_CASE_P(
73 TextToBinaryImageOperandsCombination, ImageOperandsTest,
74 ::testing::ValuesIn(std::vector<ImageOperandsCase>{
75 // TODO(dneto): Rev32 adds many more values, and rearranges their
76 // values.
77 // Test adjacent pairs, so we can easily debug the values when it fails.
78 {" Bias|Lod %5 %6", {MASK(Bias) | MASK(Lod), 5, 6}},
79 {" Lod|Grad %5 %6 %7", {MASK(Lod) | MASK(Grad), 5, 6, 7}},
80 {" Grad|ConstOffset %5 %6 %7",
81 {MASK(Grad) | MASK(ConstOffset), 5, 6, 7}},
82 {" ConstOffset|Offset %5 %6", {MASK(ConstOffset) | MASK(Offset), 5, 6}},
83 {" Offset|ConstOffsets %5 %6",
84 {MASK(Offset) | MASK(ConstOffsets), 5, 6}},
85 {" ConstOffsets|Sample %5 %6",
86 {MASK(ConstOffsets) | MASK(Sample), 5, 6}},
87 // Test all masks together.
88 {" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
89 " %5 %6 %7 %8 %9 %10 %11 %12",
90 {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
91 MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
92 5, 6, 7, 8, 9, 10, 11, 12}},
93 // The same, but with mask value names reversed.
94 {" Sample|ConstOffsets|Offset|ConstOffset|Grad|Lod|Bias"
95 " %5 %6 %7 %8 %9 %10 %11 %12",
96 {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
97 MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
98 5, 6, 7, 8, 9, 10, 11, 12}}}), );
99 #undef MASK
100
TEST_F(ImageOperandsTest,WrongOperand)101 TEST_F(ImageOperandsTest, WrongOperand) {
102 EXPECT_THAT(CompileFailure("%r = OpImageFetch %t %i %c xxyyzz"),
103 Eq("Invalid image operand 'xxyyzz'."));
104 }
105
106 // Test OpImage
107
108 using OpImageTest = TextToBinaryTest;
109
TEST_F(OpImageTest,Valid)110 TEST_F(OpImageTest, Valid) {
111 const std::string input = "%2 = OpImage %1 %3\n";
112 EXPECT_THAT(CompiledInstructions(input),
113 Eq(MakeInstruction(SpvOpImage, {1, 2, 3})));
114
115 // Test the disassembler.
116 EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
117 }
118
TEST_F(OpImageTest,InvalidTypeOperand)119 TEST_F(OpImageTest, InvalidTypeOperand) {
120 EXPECT_THAT(CompileFailure("%2 = OpImage 42"),
121 Eq("Expected id to start with %."));
122 }
123
TEST_F(OpImageTest,MissingSampledImageOperand)124 TEST_F(OpImageTest, MissingSampledImageOperand) {
125 EXPECT_THAT(CompileFailure("%2 = OpImage %1"),
126 Eq("Expected operand, found end of stream."));
127 }
128
TEST_F(OpImageTest,InvalidSampledImageOperand)129 TEST_F(OpImageTest, InvalidSampledImageOperand) {
130 EXPECT_THAT(CompileFailure("%2 = OpImage %1 1000"),
131 Eq("Expected id to start with %."));
132 }
133
TEST_F(OpImageTest,TooManyOperands)134 TEST_F(OpImageTest, TooManyOperands) {
135 // We should improve this message, to say what instruction we're trying to
136 // parse.
137 EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 %4"), // an Id
138 Eq("Expected '=', found end of stream."));
139
140 EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 99"), // a number
141 Eq("Expected <opcode> or <result-id> at the beginning of an "
142 "instruction, found '99'."));
143 EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 \"abc\""), // a string
144 Eq("Expected <opcode> or <result-id> at the beginning of an "
145 "instruction, found '\"abc\"'."));
146 }
147
148 // Test OpImageSparseRead
149
150 using OpImageSparseReadTest = TextToBinaryTest;
151
TEST_F(OpImageSparseReadTest,OnlyRequiredOperands)152 TEST_F(OpImageSparseReadTest, OnlyRequiredOperands) {
153 const std::string input = "%2 = OpImageSparseRead %1 %3 %4\n";
154 EXPECT_THAT(CompiledInstructions(input),
155 Eq(MakeInstruction(SpvOpImageSparseRead, {1, 2, 3, 4})));
156 // Test the disassembler.
157 EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
158 }
159
160 // Test all kinds of image operands on OpImageSparseRead
161
162 using ImageSparseReadImageOperandsTest =
163 spvtest::TextToBinaryTestBase<::testing::TestWithParam<ImageOperandsCase>>;
164
TEST_P(ImageSparseReadImageOperandsTest,Sample)165 TEST_P(ImageSparseReadImageOperandsTest, Sample) {
166 const std::string input =
167 "%2 = OpImageSparseRead %1 %3 %4" + GetParam().image_operands + "\n";
168 EXPECT_THAT(CompiledInstructions(input),
169 Eq(MakeInstruction(SpvOpImageSparseRead, {1, 2, 3, 4},
170 GetParam().expected_mask_and_operands)));
171 // Test the disassembler.
172 EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
173 }
174
175 #define MASK(NAME) SpvImageOperands##NAME##Mask
176 INSTANTIATE_TEST_CASE_P(ImageSparseReadImageOperandsAny,
177 ImageSparseReadImageOperandsTest,
178 ::testing::ValuesIn(std::vector<ImageOperandsCase>{
179 // Image operands are optional.
180 {"", {}},
181 // Test each kind, alone.
182 {" Bias %5", {MASK(Bias), 5}},
183 {" Lod %5", {MASK(Lod), 5}},
184 {" Grad %5 %6", {MASK(Grad), 5, 6}},
185 {" ConstOffset %5", {MASK(ConstOffset), 5}},
186 {" Offset %5", {MASK(Offset), 5}},
187 {" ConstOffsets %5", {MASK(ConstOffsets), 5}},
188 {" Sample %5", {MASK(Sample), 5}},
189 {" MinLod %5", {MASK(MinLod), 5}},
190 }), );
191 #undef MASK
192 #define MASK(NAME) static_cast<uint32_t>(SpvImageOperands##NAME##Mask)
193 INSTANTIATE_TEST_CASE_P(
194 ImageSparseReadImageOperandsCombination, ImageSparseReadImageOperandsTest,
195 ::testing::ValuesIn(std::vector<ImageOperandsCase>{
196 // values.
197 // Test adjacent pairs, so we can easily debug the values when it fails.
198 {" Bias|Lod %5 %6", {MASK(Bias) | MASK(Lod), 5, 6}},
199 {" Lod|Grad %5 %6 %7", {MASK(Lod) | MASK(Grad), 5, 6, 7}},
200 {" Grad|ConstOffset %5 %6 %7",
201 {MASK(Grad) | MASK(ConstOffset), 5, 6, 7}},
202 {" ConstOffset|Offset %5 %6", {MASK(ConstOffset) | MASK(Offset), 5, 6}},
203 {" Offset|ConstOffsets %5 %6",
204 {MASK(Offset) | MASK(ConstOffsets), 5, 6}},
205 {" ConstOffsets|Sample %5 %6",
206 {MASK(ConstOffsets) | MASK(Sample), 5, 6}},
207 // Test all masks together.
208 {" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
209 " %5 %6 %7 %8 %9 %10 %11 %12",
210 {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
211 MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
212 5, 6, 7, 8, 9, 10, 11, 12}},
213 // Don't try the masks reversed, since this is a round trip test,
214 // and the disassembler will sort them.
215 }), );
216 #undef MASK
217
TEST_F(OpImageSparseReadTest,InvalidTypeOperand)218 TEST_F(OpImageSparseReadTest, InvalidTypeOperand) {
219 EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead 42"),
220 Eq("Expected id to start with %."));
221 }
222
TEST_F(OpImageSparseReadTest,MissingImageOperand)223 TEST_F(OpImageSparseReadTest, MissingImageOperand) {
224 EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1"),
225 Eq("Expected operand, found end of stream."));
226 }
227
TEST_F(OpImageSparseReadTest,InvalidImageOperand)228 TEST_F(OpImageSparseReadTest, InvalidImageOperand) {
229 EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 1000"),
230 Eq("Expected id to start with %."));
231 }
232
TEST_F(OpImageSparseReadTest,MissingCoordinateOperand)233 TEST_F(OpImageSparseReadTest, MissingCoordinateOperand) {
234 EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 %2"),
235 Eq("Expected operand, found end of stream."));
236 }
237
TEST_F(OpImageSparseReadTest,InvalidCoordinateOperand)238 TEST_F(OpImageSparseReadTest, InvalidCoordinateOperand) {
239 EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 %2 1000"),
240 Eq("Expected id to start with %."));
241 }
242
243 // TODO(dneto): OpSampledImage
244 // TODO(dneto): OpImageSampleImplicitLod
245 // TODO(dneto): OpImageSampleExplicitLod
246 // TODO(dneto): OpImageSampleDrefImplicitLod
247 // TODO(dneto): OpImageSampleDrefExplicitLod
248 // TODO(dneto): OpImageSampleProjImplicitLod
249 // TODO(dneto): OpImageSampleProjExplicitLod
250 // TODO(dneto): OpImageSampleProjDrefImplicitLod
251 // TODO(dneto): OpImageSampleProjDrefExplicitLod
252 // TODO(dneto): OpImageGather
253 // TODO(dneto): OpImageDrefGather
254 // TODO(dneto): OpImageRead
255 // TODO(dneto): OpImageWrite
256 // TODO(dneto): OpImageQueryFormat
257 // TODO(dneto): OpImageQueryOrder
258 // TODO(dneto): OpImageQuerySizeLod
259 // TODO(dneto): OpImageQuerySize
260 // TODO(dneto): OpImageQueryLod
261 // TODO(dneto): OpImageQueryLevels
262 // TODO(dneto): OpImageQuerySamples
263 // TODO(dneto): OpImageSparseSampleImplicitLod
264 // TODO(dneto): OpImageSparseSampleExplicitLod
265 // TODO(dneto): OpImageSparseSampleDrefImplicitLod
266 // TODO(dneto): OpImageSparseSampleDrefExplicitLod
267 // TODO(dneto): OpImageSparseSampleProjImplicitLod
268 // TODO(dneto): OpImageSparseSampleProjExplicitLod
269 // TODO(dneto): OpImageSparseSampleProjDrefImplicitLod
270 // TODO(dneto): OpImageSparseSampleProjDrefExplicitLod
271 // TODO(dneto): OpImageSparseFetch
272 // TODO(dneto): OpImageSparseDrefGather
273 // TODO(dneto): OpImageSparseTexelsResident
274
275 } // namespace
276 } // namespace spvtools
277