1 // Copyright (c) 2019 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 // Validation tests for OpenCL env specific checks
16 
17 #include <string>
18 
19 #include "gmock/gmock.h"
20 #include "test/val/val_fixtures.h"
21 
22 namespace spvtools {
23 namespace val {
24 namespace {
25 
26 using testing::Eq;
27 using testing::HasSubstr;
28 
29 using ValidateOpenCL = spvtest::ValidateBase<bool>;
30 
TEST_F(ValidateOpenCL,NonPhysicalAddressingModelBad)31 TEST_F(ValidateOpenCL, NonPhysicalAddressingModelBad) {
32   std::string spirv = R"(
33      OpCapability Kernel
34      OpMemoryModel Logical OpenCL
35 )";
36 
37   CompileSuccessfully(spirv);
38 
39   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
40   EXPECT_THAT(getDiagnosticString(),
41               HasSubstr("Addressing model must be Physical32 or Physical64 "
42                         "in the OpenCL environment.\n  OpMemoryModel Logical "
43                         "OpenCL\n"));
44 }
45 
TEST_F(ValidateOpenCL,NonOpenCLMemoryModelBad)46 TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) {
47   std::string spirv = R"(
48      OpCapability Kernel
49      OpCapability Addresses
50      OpCapability VulkanMemoryModelKHR
51      OpExtension "SPV_KHR_vulkan_memory_model"
52      OpMemoryModel Physical32 VulkanKHR
53 )";
54 
55   CompileSuccessfully(spirv);
56 
57   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
58   EXPECT_THAT(
59       getDiagnosticString(),
60       HasSubstr("Memory model must be OpenCL in the OpenCL environment."));
61 }
62 
TEST_F(ValidateOpenCL,NonVoidSampledTypeImageBad)63 TEST_F(ValidateOpenCL, NonVoidSampledTypeImageBad) {
64   std::string spirv = R"(
65     OpCapability Addresses
66     OpCapability Kernel
67     OpMemoryModel Physical32 OpenCL
68     %1 = OpTypeInt 32 0
69     %2 = OpTypeImage %1 2D 0 0 0 0 Unknown ReadOnly
70 )";
71 
72   CompileSuccessfully(spirv);
73 
74   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
75   EXPECT_THAT(
76       getDiagnosticString(),
77       HasSubstr("Sampled Type must be OpTypeVoid in the OpenCL environment."
78                 "\n  %2 = OpTypeImage %uint 2D 0 0 0 0 Unknown ReadOnly\n"));
79 }
80 
TEST_F(ValidateOpenCL,NonZeroMSImageBad)81 TEST_F(ValidateOpenCL, NonZeroMSImageBad) {
82   std::string spirv = R"(
83     OpCapability Addresses
84     OpCapability Kernel
85     OpMemoryModel Physical32 OpenCL
86     %1 = OpTypeVoid
87     %2 = OpTypeImage %1 2D 0 0 1 0 Unknown ReadOnly
88 )";
89 
90   CompileSuccessfully(spirv);
91 
92   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
93   EXPECT_THAT(
94       getDiagnosticString(),
95       HasSubstr("MS must be 0 in the OpenCL environment."
96                 "\n  %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n"));
97 }
98 
TEST_F(ValidateOpenCL,Non1D2DArrayedImageBad)99 TEST_F(ValidateOpenCL, Non1D2DArrayedImageBad) {
100   std::string spirv = R"(
101     OpCapability Addresses
102     OpCapability Kernel
103     OpMemoryModel Physical32 OpenCL
104     %1 = OpTypeVoid
105     %2 = OpTypeImage %1 3D 0 1 0 0 Unknown ReadOnly
106 )";
107 
108   CompileSuccessfully(spirv);
109 
110   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
111   EXPECT_THAT(
112       getDiagnosticString(),
113       HasSubstr("In the OpenCL environment, Arrayed may only be set to 1 "
114                 "when Dim is either 1D or 2D."
115                 "\n  %2 = OpTypeImage %void 3D 0 1 0 0 Unknown ReadOnly\n"));
116 }
117 
TEST_F(ValidateOpenCL,NonZeroSampledImageBad)118 TEST_F(ValidateOpenCL, NonZeroSampledImageBad) {
119   std::string spirv = R"(
120     OpCapability Addresses
121     OpCapability Kernel
122     OpMemoryModel Physical32 OpenCL
123     %1 = OpTypeVoid
124     %2 = OpTypeImage %1 3D 0 0 0 1 Unknown ReadOnly
125 )";
126 
127   CompileSuccessfully(spirv);
128 
129   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
130   EXPECT_THAT(
131       getDiagnosticString(),
132       HasSubstr("Sampled must be 0 in the OpenCL environment."
133                 "\n  %2 = OpTypeImage %void 3D 0 0 0 1 Unknown ReadOnly\n"));
134 }
135 
TEST_F(ValidateOpenCL,NoAccessQualifierImageBad)136 TEST_F(ValidateOpenCL, NoAccessQualifierImageBad) {
137   std::string spirv = R"(
138     OpCapability Addresses
139     OpCapability Kernel
140     OpMemoryModel Physical32 OpenCL
141     %1 = OpTypeVoid
142     %2 = OpTypeImage %1 3D 0 0 0 0 Unknown
143 )";
144 
145   CompileSuccessfully(spirv);
146 
147   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
148   EXPECT_THAT(getDiagnosticString(),
149               HasSubstr("In the OpenCL environment, the optional "
150                         "Access Qualifier must be present."
151                         "\n  %2 = OpTypeImage %void 3D 0 0 0 0 Unknown\n"));
152 }
153 
TEST_F(ValidateOpenCL,ImageWriteWithOptionalImageOperandsBad)154 TEST_F(ValidateOpenCL, ImageWriteWithOptionalImageOperandsBad) {
155   std::string spirv = R"(
156     OpCapability Addresses
157     OpCapability Kernel
158     OpCapability ImageBasic
159     OpMemoryModel Physical64 OpenCL
160     OpEntryPoint Kernel %5 "test"
161     %uint = OpTypeInt 32 0
162     %uint_7 = OpConstant %uint 7
163     %uint_3 = OpConstant %uint 3
164     %uint_1 = OpConstant %uint 1
165     %uint_2 = OpConstant %uint 2
166     %uint_4 = OpConstant %uint 4
167     %void = OpTypeVoid
168     %3 = OpTypeImage %void 2D 0 0 0 0 Unknown WriteOnly
169     %4 = OpTypeFunction %void %3
170     %v2uint = OpTypeVector %uint 2
171     %v4uint = OpTypeVector %uint 4
172     %12 = OpConstantComposite %v2uint %uint_7 %uint_3
173     %17 = OpConstantComposite %v4uint %uint_1 %uint_2 %uint_3 %uint_4
174     %5 = OpFunction %void None %4
175     %img = OpFunctionParameter %3
176     %entry = OpLabel
177     OpImageWrite %img %12 %17 ConstOffset %12
178     OpReturn
179     OpFunctionEnd
180 )";
181 
182   CompileSuccessfully(spirv);
183 
184   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
185   EXPECT_THAT(getDiagnosticString(),
186               HasSubstr("Optional Image Operands are not allowed in the "
187                         "OpenCL environment."
188                         "\n  OpImageWrite %15 %13 %14 ConstOffset %13\n"));
189 }
190 
TEST_F(ValidateOpenCL,ImageReadWithConstOffsetBad)191 TEST_F(ValidateOpenCL, ImageReadWithConstOffsetBad) {
192   std::string spirv = R"(
193                OpCapability Addresses
194                OpCapability Kernel
195                OpCapability ImageBasic
196                OpMemoryModel Physical64 OpenCL
197                OpEntryPoint Kernel %5 "image_kernel"
198                OpName %img "img"
199                OpName %coord "coord"
200                OpName %call "call"
201        %uint = OpTypeInt 32 0
202      %uint_7 = OpConstant %uint 7
203      %uint_3 = OpConstant %uint 3
204        %void = OpTypeVoid
205           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
206           %4 = OpTypeFunction %void %3
207      %v4uint = OpTypeVector %uint 4
208      %v2uint = OpTypeVector %uint 2
209       %coord = OpConstantComposite %v2uint %uint_7 %uint_3
210           %5 = OpFunction %void None %4
211         %img = OpFunctionParameter %3
212       %entry = OpLabel
213        %call = OpImageRead %v4uint %img %coord ConstOffset %coord
214                OpReturn
215                OpFunctionEnd
216 )";
217 
218   CompileSuccessfully(spirv);
219 
220   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
221   EXPECT_THAT(
222       getDiagnosticString(),
223       HasSubstr(
224           "ConstOffset image operand not allowed in the OpenCL environment."
225           "\n  %call = OpImageRead %v4uint %img %coord ConstOffset %coord\n"));
226 }
227 
TEST_F(ValidateOpenCL,ImageRead_NonDepthScalarFloatResult_Bad)228 TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarFloatResult_Bad) {
229   std::string spirv = R"(
230                OpCapability Addresses
231                OpCapability Kernel
232                OpCapability ImageBasic
233                OpMemoryModel Physical64 OpenCL
234                OpEntryPoint Kernel %5 "image_kernel"
235                OpName %img "img"
236                OpName %coord "coord"
237                OpName %call "call"
238        %uint = OpTypeInt 32 0
239      %v2uint = OpTypeVector %uint 2
240       %coord = OpConstantNull %v2uint
241        %void = OpTypeVoid
242       %float = OpTypeFloat 32
243           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
244           %4 = OpTypeFunction %void %3
245           %5 = OpFunction %void None %4
246         %img = OpFunctionParameter %3
247       %entry = OpLabel
248        %call = OpImageRead %float %img %coord
249                OpReturn
250                OpFunctionEnd
251 )";
252 
253   CompileSuccessfully(spirv);
254 
255   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
256   EXPECT_THAT(getDiagnosticString(),
257               HasSubstr("Expected Result Type to have 4 components"));
258 }
259 
TEST_F(ValidateOpenCL,ImageRead_NonDepthScalarIntResult_Bad)260 TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarIntResult_Bad) {
261   std::string spirv = R"(
262                OpCapability Addresses
263                OpCapability Kernel
264                OpCapability ImageBasic
265                OpMemoryModel Physical64 OpenCL
266                OpEntryPoint Kernel %5 "image_kernel"
267                OpName %img "img"
268                OpName %coord "coord"
269                OpName %call "call"
270        %uint = OpTypeInt 32 0
271      %v2uint = OpTypeVector %uint 2
272       %coord = OpConstantNull %v2uint
273        %void = OpTypeVoid
274       %float = OpTypeFloat 32
275           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
276           %4 = OpTypeFunction %void %3
277           %5 = OpFunction %void None %4
278         %img = OpFunctionParameter %3
279       %entry = OpLabel
280        %call = OpImageRead %uint %img %coord
281                OpReturn
282                OpFunctionEnd
283 )";
284 
285   CompileSuccessfully(spirv);
286 
287   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
288   EXPECT_THAT(getDiagnosticString(),
289               HasSubstr("Expected Result Type to have 4 components"));
290 }
291 
TEST_F(ValidateOpenCL,ImageRead_NonDepthVector3FloatResult_Bad)292 TEST_F(ValidateOpenCL, ImageRead_NonDepthVector3FloatResult_Bad) {
293   std::string spirv = R"(
294                OpCapability Addresses
295                OpCapability Kernel
296                OpCapability ImageBasic
297                OpMemoryModel Physical64 OpenCL
298                OpEntryPoint Kernel %5 "image_kernel"
299                OpName %img "img"
300                OpName %coord "coord"
301                OpName %call "call"
302        %uint = OpTypeInt 32 0
303      %v2uint = OpTypeVector %uint 2
304       %coord = OpConstantNull %v2uint
305        %void = OpTypeVoid
306       %float = OpTypeFloat 32
307     %v3float = OpTypeVector %float 3
308           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
309           %4 = OpTypeFunction %void %3
310           %5 = OpFunction %void None %4
311         %img = OpFunctionParameter %3
312       %entry = OpLabel
313        %call = OpImageRead %v3float %img %coord
314                OpReturn
315                OpFunctionEnd
316 )";
317 
318   CompileSuccessfully(spirv);
319 
320   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
321   EXPECT_THAT(getDiagnosticString(),
322               HasSubstr("Expected Result Type to have 4 components"));
323 }
324 
TEST_F(ValidateOpenCL,ImageRead_NonDepthVector4FloatResult_Ok)325 TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4FloatResult_Ok) {
326   std::string spirv = R"(
327                OpCapability Addresses
328                OpCapability Kernel
329                OpCapability ImageBasic
330                OpMemoryModel Physical64 OpenCL
331                OpEntryPoint Kernel %5 "image_kernel"
332                OpName %img "img"
333                OpName %coord "coord"
334                OpName %call "call"
335        %uint = OpTypeInt 32 0
336      %v2uint = OpTypeVector %uint 2
337       %coord = OpConstantNull %v2uint
338        %void = OpTypeVoid
339       %float = OpTypeFloat 32
340     %v4float = OpTypeVector %float 4
341           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
342           %4 = OpTypeFunction %void %3
343           %5 = OpFunction %void None %4
344         %img = OpFunctionParameter %3
345       %entry = OpLabel
346        %call = OpImageRead %v4float %img %coord
347                OpReturn
348                OpFunctionEnd
349 )";
350 
351   CompileSuccessfully(spirv);
352 
353   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
354   EXPECT_THAT(getDiagnosticString(), Eq(""));
355 }
356 
TEST_F(ValidateOpenCL,ImageRead_NonDepthVector4IntResult_Ok)357 TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4IntResult_Ok) {
358   std::string spirv = R"(
359                OpCapability Addresses
360                OpCapability Kernel
361                OpCapability ImageBasic
362                OpMemoryModel Physical64 OpenCL
363                OpEntryPoint Kernel %5 "image_kernel"
364                OpName %img "img"
365                OpName %coord "coord"
366                OpName %call "call"
367        %uint = OpTypeInt 32 0
368      %v2uint = OpTypeVector %uint 2
369       %coord = OpConstantNull %v2uint
370        %void = OpTypeVoid
371      %v4uint = OpTypeVector %uint 4
372           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
373           %4 = OpTypeFunction %void %3
374           %5 = OpFunction %void None %4
375         %img = OpFunctionParameter %3
376       %entry = OpLabel
377        %call = OpImageRead %v4uint %img %coord
378                OpReturn
379                OpFunctionEnd
380 )";
381 
382   CompileSuccessfully(spirv);
383 
384   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
385   EXPECT_THAT(getDiagnosticString(), Eq(""));
386 }
387 
TEST_F(ValidateOpenCL,ImageRead_DepthScalarFloatResult_Ok)388 TEST_F(ValidateOpenCL, ImageRead_DepthScalarFloatResult_Ok) {
389   std::string spirv = R"(
390                OpCapability Addresses
391                OpCapability Kernel
392                OpCapability ImageBasic
393                OpMemoryModel Physical64 OpenCL
394                OpEntryPoint Kernel %5 "image_kernel"
395                OpName %img "img"
396                OpName %coord "coord"
397                OpName %call "call"
398        %uint = OpTypeInt 32 0
399      %v2uint = OpTypeVector %uint 2
400       %coord = OpConstantNull %v2uint
401        %void = OpTypeVoid
402       %float = OpTypeFloat 32
403           %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
404           %4 = OpTypeFunction %void %3
405           %5 = OpFunction %void None %4
406         %img = OpFunctionParameter %3
407       %entry = OpLabel
408        %call = OpImageRead %float %img %coord
409                OpReturn
410                OpFunctionEnd
411 )";
412 
413   CompileSuccessfully(spirv);
414 
415   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
416   EXPECT_THAT(getDiagnosticString(), Eq(""));
417 }
418 
TEST_F(ValidateOpenCL,ImageRead_DepthScalarIntResult_Bad)419 TEST_F(ValidateOpenCL, ImageRead_DepthScalarIntResult_Bad) {
420   std::string spirv = R"(
421                OpCapability Addresses
422                OpCapability Kernel
423                OpCapability ImageBasic
424                OpMemoryModel Physical64 OpenCL
425                OpEntryPoint Kernel %5 "image_kernel"
426                OpName %img "img"
427                OpName %coord "coord"
428                OpName %call "call"
429        %uint = OpTypeInt 32 0
430      %v2uint = OpTypeVector %uint 2
431       %coord = OpConstantNull %v2uint
432        %void = OpTypeVoid
433       %float = OpTypeFloat 32
434           %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
435           %4 = OpTypeFunction %void %3
436           %5 = OpFunction %void None %4
437         %img = OpFunctionParameter %3
438       %entry = OpLabel
439        %call = OpImageRead %uint %img %coord
440                OpReturn
441                OpFunctionEnd
442 )";
443 
444   CompileSuccessfully(spirv);
445 
446   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
447   EXPECT_THAT(getDiagnosticString(),
448               HasSubstr("Expected Result Type from a depth image "
449                         "read to result in a scalar float value"));
450 }
451 
TEST_F(ValidateOpenCL,ImageRead_DepthVectorFloatResult_Bad)452 TEST_F(ValidateOpenCL, ImageRead_DepthVectorFloatResult_Bad) {
453   std::string spirv = R"(
454                OpCapability Addresses
455                OpCapability Kernel
456                OpCapability ImageBasic
457                OpMemoryModel Physical64 OpenCL
458                OpEntryPoint Kernel %5 "image_kernel"
459                OpName %img "img"
460                OpName %coord "coord"
461                OpName %call "call"
462        %uint = OpTypeInt 32 0
463      %v2uint = OpTypeVector %uint 2
464       %coord = OpConstantNull %v2uint
465        %void = OpTypeVoid
466       %float = OpTypeFloat 32
467     %v4float = OpTypeVector %float 4
468           %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly
469           %4 = OpTypeFunction %void %3
470           %5 = OpFunction %void None %4
471         %img = OpFunctionParameter %3
472       %entry = OpLabel
473        %call = OpImageRead %v4float %img %coord
474                OpReturn
475                OpFunctionEnd
476 )";
477 
478   CompileSuccessfully(spirv);
479 
480   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
481   EXPECT_THAT(getDiagnosticString(),
482               HasSubstr("Expected Result Type from a depth image "
483                         "read to result in a scalar float value"));
484 }
485 
TEST_F(ValidateOpenCL,ImageSampleExplicitLodWithConstOffsetBad)486 TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) {
487   std::string spirv = R"(
488                OpCapability Addresses
489                OpCapability Kernel
490                OpCapability ImageBasic
491                OpCapability LiteralSampler
492                OpMemoryModel Physical64 OpenCL
493                OpEntryPoint Kernel %5 "image_kernel"
494                OpName %img "img"
495                OpName %coord "coord"
496                OpName %call "call"
497        %uint = OpTypeInt 32 0
498      %v2uint = OpTypeVector %uint 2
499       %coord = OpConstantNull %v2uint
500        %void = OpTypeVoid
501           %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly
502           %4 = OpTypeFunction %void %3
503           %8 = OpTypeSampler
504          %10 = OpTypeSampledImage %3
505      %v4uint = OpTypeVector %uint 4
506       %float = OpTypeFloat 32
507           %9 = OpConstantSampler %8 None 0 Nearest
508     %float_0 = OpConstant %float 0
509           %5 = OpFunction %void None %4
510           %6 = OpFunctionParameter %3
511       %entry = OpLabel
512         %img = OpSampledImage %10 %6 %9
513        %call = OpImageSampleExplicitLod %v4uint %img %coord
514                                         Lod|ConstOffset %float_0 %coord
515                OpReturn
516                OpFunctionEnd
517 )";
518 
519   CompileSuccessfully(spirv);
520 
521   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
522   EXPECT_THAT(
523       getDiagnosticString(),
524       HasSubstr(
525           "ConstOffset image operand not allowed in the OpenCL environment."
526           "\n  %call = OpImageSampleExplicitLod %v4uint %img "
527           "%coord Lod|ConstOffset %float_0 %coord\n"));
528 }
529 
530 }  // namespace
531 }  // namespace val
532 }  // namespace spvtools
533