1 // Copyright (c) 2020 Google 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 // Tests for OpExtension validator rules.
16 
17 #include <string>
18 #include <vector>
19 
20 #include "gmock/gmock.h"
21 #include "source/spirv_target_env.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24 
25 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::HasSubstr;
30 using ::testing::Values;
31 using ::testing::ValuesIn;
32 
33 using ValidateSpvExpectAssumeKHR = spvtest::ValidateBase<bool>;
34 
TEST_F(ValidateSpvExpectAssumeKHR, Valid)35 TEST_F(ValidateSpvExpectAssumeKHR, Valid) {
36   const std::string str = R"(
37     OpCapability Kernel
38     OpCapability Addresses
39     OpCapability Linkage
40     OpCapability ExpectAssumeKHR
41     OpExtension "SPV_KHR_expect_assume"
42     OpMemoryModel Physical32 OpenCL
43 
44     %void = OpTypeVoid
45     %voidfn = OpTypeFunction %void
46 
47     %bool = OpTypeBool
48     %true = OpConstantTrue %bool
49     %undef = OpUndef %bool
50 
51     %uint = OpTypeInt 32 0
52     %uint_1 = OpConstant %uint 1
53     %uint_2 = OpConstant %uint 2
54 
55     %v2bool = OpTypeVector %bool 2
56     %v2uint = OpTypeVector %uint 2
57 
58     %null_v2bool = OpConstantNull %v2bool
59     %null_v2uint = OpConstantNull %v2uint
60 
61     %main = OpFunction %void None %voidfn
62     %entry = OpLabel
63     OpAssumeTrueKHR %true
64     OpAssumeTrueKHR %undef       ; probably undefined behaviour
65     %bool_val = OpExpectKHR %bool %true %true
66     %uint_val = OpExpectKHR %uint %uint_1 %uint_2 ; a bad expectation
67     %v2bool_val = OpExpectKHR %v2bool %null_v2bool %null_v2bool
68     %v2uint_val = OpExpectKHR %v2uint %null_v2uint %null_v2uint
69     OpReturn
70     OpFunctionEnd
71 
72 )";
73   CompileSuccessfully(str.c_str());
74   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
75 }
76 
TEST_F(ValidateSpvExpectAssumeKHR, RequiresExtension)77 TEST_F(ValidateSpvExpectAssumeKHR, RequiresExtension) {
78   const std::string str = R"(
79     OpCapability Kernel
80     OpCapability Addresses
81     OpCapability Linkage
82     OpCapability ExpectAssumeKHR
83     OpMemoryModel Physical32 OpenCL
84 
85     %void = OpTypeVoid
86     %voidfn = OpTypeFunction %void
87 
88     %bool = OpTypeBool
89     %true = OpConstantTrue %bool
90     %undef = OpUndef %bool
91 
92     %uint = OpTypeInt 32 0
93     %uint_1 = OpConstant %uint 1
94     %uint_2 = OpConstant %uint 2
95 
96     %main = OpFunction %void None %voidfn
97     %entry = OpLabel
98     OpAssumeTrueKHR %true
99     OpAssumeTrueKHR %undef       ; probably undefined behaviour
100     %val = OpExpectKHR %uint %uint_1 %uint_2 ; a bad expectation
101     OpReturn
102     OpFunctionEnd
103 
104 )";
105   CompileSuccessfully(str.c_str());
106   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
107   EXPECT_THAT(getDiagnosticString(),
108               HasSubstr("Capability: operand ExpectAssumeKHR(5629) requires "
109                         "one of these extensions: SPV_KHR_expect_assume"));
110 }
111 
TEST_F(ValidateSpvExpectAssumeKHR, AssumeTrueKHR_RequiresExpectAssumeCapability)112 TEST_F(ValidateSpvExpectAssumeKHR,
113        AssumeTrueKHR_RequiresExpectAssumeCapability) {
114   const std::string str = R"(
115     OpCapability Kernel
116     OpCapability Addresses
117     OpCapability Linkage
118     OpExtension "SPV_KHR_expect_assume"
119     OpMemoryModel Physical32 OpenCL
120 
121     %void = OpTypeVoid
122     %voidfn = OpTypeFunction %void
123 
124     %bool = OpTypeBool
125     %true = OpConstantTrue %bool
126     %undef = OpUndef %bool
127 
128     %uint = OpTypeInt 32 0
129     %uint_1 = OpConstant %uint 1
130     %uint_2 = OpConstant %uint 2
131 
132     %main = OpFunction %void None %voidfn
133     %entry = OpLabel
134     OpAssumeTrueKHR %true
135     OpAssumeTrueKHR %undef       ; probably undefined behaviour
136     OpReturn
137     OpFunctionEnd
138 )";
139   CompileSuccessfully(str.c_str());
140   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
141   EXPECT_THAT(getDiagnosticString(),
142               HasSubstr("Opcode AssumeTrueKHR requires one of these "
143                         "capabilities: ExpectAssumeKHR \n"
144                         "  OpAssumeTrueKHR %true\n"));
145 }
146 
TEST_F(ValidateSpvExpectAssumeKHR, AssumeTrueKHR_OperandMustBeBool)147 TEST_F(ValidateSpvExpectAssumeKHR, AssumeTrueKHR_OperandMustBeBool) {
148   const std::string str = R"(
149     OpCapability Kernel
150     OpCapability Addresses
151     OpCapability Linkage
152     OpCapability ExpectAssumeKHR
153     OpExtension "SPV_KHR_expect_assume"
154     OpMemoryModel Physical32 OpenCL
155 
156     %void = OpTypeVoid
157     %voidfn = OpTypeFunction %void
158 
159     %bool = OpTypeBool
160     %true = OpConstantTrue %bool
161     %undef = OpUndef %bool
162 
163     %uint = OpTypeInt 32 0
164     %uint_1 = OpConstant %uint 1
165     %uint_2 = OpConstant %uint 2
166 
167     %main = OpFunction %void None %voidfn
168     %entry = OpLabel
169     OpAssumeTrueKHR %uint_1 ; bad type
170     OpReturn
171     OpFunctionEnd
172 )";
173   CompileSuccessfully(str.c_str());
174   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
175   EXPECT_THAT(
176       getDiagnosticString(),
177       HasSubstr("Value operand of OpAssumeTrueKHR must be a boolean scalar\n"
178                 "  OpAssumeTrueKHR %uint_1\n"));
179 }
180 
TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_RequiresExpectAssumeCapability)181 TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_RequiresExpectAssumeCapability) {
182   const std::string str = R"(
183     OpCapability Kernel
184     OpCapability Addresses
185     OpCapability Linkage
186     OpExtension "SPV_KHR_expect_assume"
187     OpMemoryModel Physical32 OpenCL
188 
189     %void = OpTypeVoid
190     %voidfn = OpTypeFunction %void
191 
192     %bool = OpTypeBool
193     %true = OpConstantTrue %bool
194     %undef = OpUndef %bool
195 
196     %uint = OpTypeInt 32 0
197     %uint_1 = OpConstant %uint 1
198     %uint_2 = OpConstant %uint 2
199 
200     %main = OpFunction %void None %voidfn
201     %entry = OpLabel
202     %val = OpExpectKHR %uint %uint_1 %uint_2 ; a bad expectation
203     OpReturn
204     OpFunctionEnd
205 )";
206   CompileSuccessfully(str.c_str());
207   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
208   EXPECT_THAT(getDiagnosticString(),
209               HasSubstr("Opcode ExpectKHR requires one of these capabilities: "
210                         "ExpectAssumeKHR \n"
211                         "  %11 = OpExpectKHR %uint %uint_1 %uint_2\n"));
212 }
213 
TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_ResultMustBeBoolOrIntScalar)214 TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_ResultMustBeBoolOrIntScalar) {
215   const std::string str = R"(
216     OpCapability Kernel
217     OpCapability Addresses
218     OpCapability Linkage
219     OpCapability ExpectAssumeKHR
220     OpExtension "SPV_KHR_expect_assume"
221     OpMemoryModel Physical32 OpenCL
222 
223     %void = OpTypeVoid
224     %voidfn = OpTypeFunction %void
225 
226     %float = OpTypeFloat 32
227 
228     %float_0 = OpConstant %float 0
229 
230     %main = OpFunction %void None %voidfn
231     %entry = OpLabel
232     %val = OpExpectKHR %float %float_0 %float_0
233     OpReturn
234     OpFunctionEnd
235 )";
236   CompileSuccessfully(str.c_str());
237   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
238   EXPECT_THAT(getDiagnosticString(),
239               HasSubstr("Result of OpExpectKHR must be a scalar or vector of "
240                         "integer type or boolean type\n"
241                         "  %7 = OpExpectKHR %float %float_0 %float_0\n"));
242 }
243 
TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_Value0MustMatchResultType)244 TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_Value0MustMatchResultType) {
245   const std::string str = R"(
246     OpCapability Kernel
247     OpCapability Addresses
248     OpCapability Linkage
249     OpCapability ExpectAssumeKHR
250     OpExtension "SPV_KHR_expect_assume"
251     OpMemoryModel Physical32 OpenCL
252 
253     %void = OpTypeVoid
254     %voidfn = OpTypeFunction %void
255 
256     %uint = OpTypeInt 32 0
257     %float = OpTypeFloat 32
258     %float_0 = OpConstant %float 0
259 
260     %main = OpFunction %void None %voidfn
261     %entry = OpLabel
262     %val = OpExpectKHR %uint %float_0 %float_0
263     OpReturn
264     OpFunctionEnd
265 )";
266   CompileSuccessfully(str.c_str());
267   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
268   EXPECT_THAT(getDiagnosticString(),
269               HasSubstr("Type of Value operand of OpExpectKHR does not match "
270                         "the result type \n"
271                         "  %8 = OpExpectKHR %uint %float_0 %float_0\n"));
272 }
273 
TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_Value1MustMatchResultType)274 TEST_F(ValidateSpvExpectAssumeKHR, ExpectKHR_Value1MustMatchResultType) {
275   const std::string str = R"(
276     OpCapability Kernel
277     OpCapability Addresses
278     OpCapability Linkage
279     OpCapability ExpectAssumeKHR
280     OpExtension "SPV_KHR_expect_assume"
281     OpMemoryModel Physical32 OpenCL
282 
283     %void = OpTypeVoid
284     %voidfn = OpTypeFunction %void
285 
286     %uint = OpTypeInt 32 0
287     %uint_0 = OpConstant %uint 0
288     %float = OpTypeFloat 32
289     %float_0 = OpConstant %float 0
290 
291     %main = OpFunction %void None %voidfn
292     %entry = OpLabel
293     %val = OpExpectKHR %uint %uint_0 %float_0
294     OpReturn
295     OpFunctionEnd
296 )";
297   CompileSuccessfully(str.c_str());
298   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
299   EXPECT_THAT(getDiagnosticString(),
300               HasSubstr("Type of ExpectedValue operand of OpExpectKHR does not "
301                         "match the result type \n"
302                         "  %9 = OpExpectKHR %uint %uint_0 %float_0\n"));
303 }
304 
305 }  // namespace
306 }  // namespace val
307 }  // namespace spvtools
308