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
22namespace spvtools {
23namespace val {
24namespace {
25
26using testing::Eq;
27using testing::HasSubstr;
28
29using ValidateOpenCL = spvtest::ValidateBase<bool>;
30
31TEST_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
46TEST_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
63TEST_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
81TEST_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
99TEST_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
118TEST_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
136TEST_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
154TEST_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
191TEST_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
228TEST_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
260TEST_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
292TEST_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
325TEST_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
357TEST_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
388TEST_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
419TEST_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
452TEST_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
486TEST_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