1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 LunarG Inc.
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include <sstream>
16fd4e5da5Sopenharmony_ci#include <string>
17fd4e5da5Sopenharmony_ci
18fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
19fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h"
20fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h"
21fd4e5da5Sopenharmony_ci
22fd4e5da5Sopenharmony_cinamespace spvtools {
23fd4e5da5Sopenharmony_cinamespace val {
24fd4e5da5Sopenharmony_cinamespace {
25fd4e5da5Sopenharmony_ci
26fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr;
27fd4e5da5Sopenharmony_ciusing ::testing::Not;
28fd4e5da5Sopenharmony_ci
29fd4e5da5Sopenharmony_ciusing ValidateAdjacency = spvtest::ValidateBase<bool>;
30fd4e5da5Sopenharmony_ci
31fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiBeginsModuleFail) {
32fd4e5da5Sopenharmony_ci  const std::string module = R"(
33fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
34fd4e5da5Sopenharmony_ciOpCapability Shader
35fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
36fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
37fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
38fd4e5da5Sopenharmony_ci%void = OpTypeVoid
39fd4e5da5Sopenharmony_ci%bool = OpTypeBool
40fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
41fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
42fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
43fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
44fd4e5da5Sopenharmony_ci%main_entry = OpLabel
45fd4e5da5Sopenharmony_ciOpBranch %true_label
46fd4e5da5Sopenharmony_ci%true_label = OpLabel
47fd4e5da5Sopenharmony_ciOpBranch %false_label
48fd4e5da5Sopenharmony_ci%false_label = OpLabel
49fd4e5da5Sopenharmony_ciOpBranch %end_label
50fd4e5da5Sopenharmony_ciOpReturn
51fd4e5da5Sopenharmony_ciOpFunctionEnd
52fd4e5da5Sopenharmony_ci)";
53fd4e5da5Sopenharmony_ci
54fd4e5da5Sopenharmony_ci  CompileSuccessfully(module);
55fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
56fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
57fd4e5da5Sopenharmony_ci              HasSubstr("ID '1[%bool]' has not been defined"));
58fd4e5da5Sopenharmony_ci}
59fd4e5da5Sopenharmony_ci
60fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) {
61fd4e5da5Sopenharmony_ci  const std::string module = R"(
62fd4e5da5Sopenharmony_ciOpCapability Shader
63fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
64fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
65fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
66fd4e5da5Sopenharmony_ci%void = OpTypeVoid
67fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
68fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
69fd4e5da5Sopenharmony_ci%main_entry = OpLabel
70fd4e5da5Sopenharmony_ciOpBranch %loop
71fd4e5da5Sopenharmony_ci%loop = OpLabel
72fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None
73fd4e5da5Sopenharmony_ci)";
74fd4e5da5Sopenharmony_ci
75fd4e5da5Sopenharmony_ci  CompileSuccessfully(module);
76fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
77fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
78fd4e5da5Sopenharmony_ci              HasSubstr("Missing OpFunctionEnd at end of module"));
79fd4e5da5Sopenharmony_ci}
80fd4e5da5Sopenharmony_ci
81fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergeEndsModuleFail) {
82fd4e5da5Sopenharmony_ci  const std::string module = R"(
83fd4e5da5Sopenharmony_ciOpCapability Shader
84fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
85fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
86fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
87fd4e5da5Sopenharmony_ci%void = OpTypeVoid
88fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
89fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
90fd4e5da5Sopenharmony_ci%main_entry = OpLabel
91fd4e5da5Sopenharmony_ciOpBranch %merge
92fd4e5da5Sopenharmony_ci%merge = OpLabel
93fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None
94fd4e5da5Sopenharmony_ci)";
95fd4e5da5Sopenharmony_ci
96fd4e5da5Sopenharmony_ci  CompileSuccessfully(module);
97fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
98fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
99fd4e5da5Sopenharmony_ci              HasSubstr("Missing OpFunctionEnd at end of module"));
100fd4e5da5Sopenharmony_ci}
101fd4e5da5Sopenharmony_ci
102fd4e5da5Sopenharmony_cistd::string GenerateShaderCode(
103fd4e5da5Sopenharmony_ci    const std::string& body,
104fd4e5da5Sopenharmony_ci    const std::string& capabilities_and_extensions = "OpCapability Shader",
105fd4e5da5Sopenharmony_ci    const std::string& execution_model = "Fragment") {
106fd4e5da5Sopenharmony_ci  std::ostringstream ss;
107fd4e5da5Sopenharmony_ci  ss << capabilities_and_extensions << "\n";
108fd4e5da5Sopenharmony_ci  ss << "OpMemoryModel Logical GLSL450\n";
109fd4e5da5Sopenharmony_ci  ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
110fd4e5da5Sopenharmony_ci  if (execution_model == "Fragment") {
111fd4e5da5Sopenharmony_ci    ss << "OpExecutionMode %main OriginUpperLeft\n";
112fd4e5da5Sopenharmony_ci  }
113fd4e5da5Sopenharmony_ci
114fd4e5da5Sopenharmony_ci  ss << R"(
115fd4e5da5Sopenharmony_ci%string = OpString ""
116fd4e5da5Sopenharmony_ci%void = OpTypeVoid
117fd4e5da5Sopenharmony_ci%bool = OpTypeBool
118fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0
119fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
120fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
121fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0
122fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1
123fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
124fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int
125fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
126fd4e5da5Sopenharmony_ci%main_entry = OpLabel
127fd4e5da5Sopenharmony_ci)";
128fd4e5da5Sopenharmony_ci
129fd4e5da5Sopenharmony_ci  ss << body;
130fd4e5da5Sopenharmony_ci
131fd4e5da5Sopenharmony_ci  ss << R"(
132fd4e5da5Sopenharmony_ciOpReturn
133fd4e5da5Sopenharmony_ciOpFunctionEnd)";
134fd4e5da5Sopenharmony_ci
135fd4e5da5Sopenharmony_ci  return ss.str();
136fd4e5da5Sopenharmony_ci}
137fd4e5da5Sopenharmony_ci
138fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLabelSuccess) {
139fd4e5da5Sopenharmony_ci  const std::string body = R"(
140fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
141fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
142fd4e5da5Sopenharmony_ci%true_label = OpLabel
143fd4e5da5Sopenharmony_ciOpBranch %end_label
144fd4e5da5Sopenharmony_ci%false_label = OpLabel
145fd4e5da5Sopenharmony_ciOpBranch %end_label
146fd4e5da5Sopenharmony_ci%end_label = OpLabel
147fd4e5da5Sopenharmony_ciOpLine %string 0 0
148fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
149fd4e5da5Sopenharmony_ci)";
150fd4e5da5Sopenharmony_ci
151fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
152fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
153fd4e5da5Sopenharmony_ci}
154fd4e5da5Sopenharmony_ci
155fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpPhiSuccess) {
156fd4e5da5Sopenharmony_ci  const std::string body = R"(
157fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
158fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
159fd4e5da5Sopenharmony_ci%true_label = OpLabel
160fd4e5da5Sopenharmony_ciOpBranch %end_label
161fd4e5da5Sopenharmony_ci%false_label = OpLabel
162fd4e5da5Sopenharmony_ciOpBranch %end_label
163fd4e5da5Sopenharmony_ci%end_label = OpLabel
164fd4e5da5Sopenharmony_ci%1 = OpPhi %bool %true %true_label %false %false_label
165fd4e5da5Sopenharmony_ci%2 = OpPhi %bool %true %true_label %false %false_label
166fd4e5da5Sopenharmony_ci)";
167fd4e5da5Sopenharmony_ci
168fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
169fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
170fd4e5da5Sopenharmony_ci}
171fd4e5da5Sopenharmony_ci
172fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLineSuccess) {
173fd4e5da5Sopenharmony_ci  const std::string body = R"(
174fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
175fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
176fd4e5da5Sopenharmony_ci%true_label = OpLabel
177fd4e5da5Sopenharmony_ciOpBranch %end_label
178fd4e5da5Sopenharmony_ci%false_label = OpLabel
179fd4e5da5Sopenharmony_ciOpBranch %end_label
180fd4e5da5Sopenharmony_ci%end_label = OpLabel
181fd4e5da5Sopenharmony_ciOpLine %string 0 0
182fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
183fd4e5da5Sopenharmony_ci)";
184fd4e5da5Sopenharmony_ci
185fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
186fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
187fd4e5da5Sopenharmony_ci}
188fd4e5da5Sopenharmony_ci
189fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByBadOpFail) {
190fd4e5da5Sopenharmony_ci  const std::string body = R"(
191fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
192fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
193fd4e5da5Sopenharmony_ci%true_label = OpLabel
194fd4e5da5Sopenharmony_ciOpBranch %end_label
195fd4e5da5Sopenharmony_ci%false_label = OpLabel
196fd4e5da5Sopenharmony_ciOpBranch %end_label
197fd4e5da5Sopenharmony_ci%end_label = OpLabel
198fd4e5da5Sopenharmony_ciOpNop
199fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
200fd4e5da5Sopenharmony_ci)";
201fd4e5da5Sopenharmony_ci
202fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
203fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
204fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
205fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
206fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
207fd4e5da5Sopenharmony_ci}
208fd4e5da5Sopenharmony_ci
209fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLineAndBadOpFail) {
210fd4e5da5Sopenharmony_ci  const std::string body = R"(
211fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
212fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
213fd4e5da5Sopenharmony_ci%true_label = OpLabel
214fd4e5da5Sopenharmony_ciOpBranch %end_label
215fd4e5da5Sopenharmony_ci%false_label = OpLabel
216fd4e5da5Sopenharmony_ciOpBranch %end_label
217fd4e5da5Sopenharmony_ci%end_label = OpLabel
218fd4e5da5Sopenharmony_ciOpNop
219fd4e5da5Sopenharmony_ciOpLine %string 1 1
220fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
221fd4e5da5Sopenharmony_ci)";
222fd4e5da5Sopenharmony_ci
223fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
224fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
225fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
226fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
227fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
228fd4e5da5Sopenharmony_ci}
229fd4e5da5Sopenharmony_ci
230fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiFollowedByOpLineGood) {
231fd4e5da5Sopenharmony_ci  const std::string body = R"(
232fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
233fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
234fd4e5da5Sopenharmony_ci%true_label = OpLabel
235fd4e5da5Sopenharmony_ciOpBranch %end_label
236fd4e5da5Sopenharmony_ci%false_label = OpLabel
237fd4e5da5Sopenharmony_ciOpBranch %end_label
238fd4e5da5Sopenharmony_ci%end_label = OpLabel
239fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
240fd4e5da5Sopenharmony_ciOpLine %string 1 1
241fd4e5da5Sopenharmony_ciOpNop
242fd4e5da5Sopenharmony_ciOpNop
243fd4e5da5Sopenharmony_ciOpLine %string 2 1
244fd4e5da5Sopenharmony_ciOpNop
245fd4e5da5Sopenharmony_ciOpLine %string 3 1
246fd4e5da5Sopenharmony_ci)";
247fd4e5da5Sopenharmony_ci
248fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
249fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
250fd4e5da5Sopenharmony_ci}
251fd4e5da5Sopenharmony_ci
252fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiFail) {
253fd4e5da5Sopenharmony_ci  const std::string body = R"(
254fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
255fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
256fd4e5da5Sopenharmony_ci%true_label = OpLabel
257fd4e5da5Sopenharmony_ciOpBranch %end_label
258fd4e5da5Sopenharmony_ci%false_label = OpLabel
259fd4e5da5Sopenharmony_ciOpBranch %end_label
260fd4e5da5Sopenharmony_ci%end_label = OpLabel
261fd4e5da5Sopenharmony_ciOpLine %string 1 1
262fd4e5da5Sopenharmony_ci%value = OpPhi %int %zero %true_label %int_1 %false_label
263fd4e5da5Sopenharmony_ciOpNop
264fd4e5da5Sopenharmony_ciOpLine %string 2 1
265fd4e5da5Sopenharmony_ciOpNop
266fd4e5da5Sopenharmony_ciOpLine %string 3 1
267fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
268fd4e5da5Sopenharmony_ci)";
269fd4e5da5Sopenharmony_ci
270fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
271fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
272fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
273fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
274fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
275fd4e5da5Sopenharmony_ci}
276fd4e5da5Sopenharmony_ci
277fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiGood) {
278fd4e5da5Sopenharmony_ci  const std::string body = R"(
279fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
280fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
281fd4e5da5Sopenharmony_ci%true_label = OpLabel
282fd4e5da5Sopenharmony_ciOpBranch %end_label
283fd4e5da5Sopenharmony_ci%false_label = OpLabel
284fd4e5da5Sopenharmony_ciOpBranch %end_label
285fd4e5da5Sopenharmony_ci%end_label = OpLabel
286fd4e5da5Sopenharmony_ciOpLine %string 1 1
287fd4e5da5Sopenharmony_ci%value = OpPhi %int %zero %true_label %int_1 %false_label
288fd4e5da5Sopenharmony_ciOpLine %string 2 1
289fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
290fd4e5da5Sopenharmony_ciOpLine %string 3 1
291fd4e5da5Sopenharmony_ciOpNop
292fd4e5da5Sopenharmony_ciOpNop
293fd4e5da5Sopenharmony_ciOpLine %string 4 1
294fd4e5da5Sopenharmony_ciOpNop
295fd4e5da5Sopenharmony_ci)";
296fd4e5da5Sopenharmony_ci
297fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
298fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
299fd4e5da5Sopenharmony_ci}
300fd4e5da5Sopenharmony_ci
301fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiInEntryBlockBad) {
302fd4e5da5Sopenharmony_ci  const std::string body = R"(
303fd4e5da5Sopenharmony_ciOpLine %string 1 1
304fd4e5da5Sopenharmony_ci%value = OpPhi %int
305fd4e5da5Sopenharmony_ciOpLine %string 2 1
306fd4e5da5Sopenharmony_ciOpNop
307fd4e5da5Sopenharmony_ciOpLine %string 3 1
308fd4e5da5Sopenharmony_ciOpNop
309fd4e5da5Sopenharmony_ci)";
310fd4e5da5Sopenharmony_ci
311fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
312fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
313fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
314fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
315fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
316fd4e5da5Sopenharmony_ci}
317fd4e5da5Sopenharmony_ci
318fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBeforeOpPhiBad) {
319fd4e5da5Sopenharmony_ci  const std::string body = R"(
320fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
321fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
322fd4e5da5Sopenharmony_ci%true_label = OpLabel
323fd4e5da5Sopenharmony_ciOpBranch %end_label
324fd4e5da5Sopenharmony_ci%false_label = OpLabel
325fd4e5da5Sopenharmony_ciOpBranch %end_label
326fd4e5da5Sopenharmony_ci%end_label = OpLabel
327fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
328fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
329fd4e5da5Sopenharmony_ci)";
330fd4e5da5Sopenharmony_ci
331fd4e5da5Sopenharmony_ci  const std::string extra = R"(OpCapability Shader
332fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
333fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
334fd4e5da5Sopenharmony_ci)";
335fd4e5da5Sopenharmony_ci
336fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body, extra));
337fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
338fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
339fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
340fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
341fd4e5da5Sopenharmony_ci}
342fd4e5da5Sopenharmony_ci
343fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenOpPhiBad) {
344fd4e5da5Sopenharmony_ci  const std::string body = R"(
345fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
346fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
347fd4e5da5Sopenharmony_ci%true_label = OpLabel
348fd4e5da5Sopenharmony_ciOpBranch %end_label
349fd4e5da5Sopenharmony_ci%false_label = OpLabel
350fd4e5da5Sopenharmony_ciOpBranch %end_label
351fd4e5da5Sopenharmony_ci%end_label = OpLabel
352fd4e5da5Sopenharmony_ci%result1 = OpPhi %bool %true %true_label %false %false_label
353fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
354fd4e5da5Sopenharmony_ci%result2 = OpPhi %bool %true %true_label %false %false_label
355fd4e5da5Sopenharmony_ci)";
356fd4e5da5Sopenharmony_ci
357fd4e5da5Sopenharmony_ci  const std::string extra = R"(OpCapability Shader
358fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
359fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
360fd4e5da5Sopenharmony_ci)";
361fd4e5da5Sopenharmony_ci
362fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body, extra));
363fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
364fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
365fd4e5da5Sopenharmony_ci              HasSubstr("OpPhi must appear within a non-entry block before all "
366fd4e5da5Sopenharmony_ci                        "non-OpPhi instructions"));
367fd4e5da5Sopenharmony_ci}
368fd4e5da5Sopenharmony_ci
369fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticAfterOpPhiGood) {
370fd4e5da5Sopenharmony_ci  const std::string body = R"(
371fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
372fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
373fd4e5da5Sopenharmony_ci%true_label = OpLabel
374fd4e5da5Sopenharmony_ciOpBranch %end_label
375fd4e5da5Sopenharmony_ci%false_label = OpLabel
376fd4e5da5Sopenharmony_ciOpBranch %end_label
377fd4e5da5Sopenharmony_ci%end_label = OpLabel
378fd4e5da5Sopenharmony_ciOpLine %string 0 0
379fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label
380fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
381fd4e5da5Sopenharmony_ci)";
382fd4e5da5Sopenharmony_ci
383fd4e5da5Sopenharmony_ci  const std::string extra = R"(OpCapability Shader
384fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
385fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
386fd4e5da5Sopenharmony_ci)";
387fd4e5da5Sopenharmony_ci
388fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body, extra));
389fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
390fd4e5da5Sopenharmony_ci}
391fd4e5da5Sopenharmony_ci
392fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBeforeOpFunctionParameterBad) {
393fd4e5da5Sopenharmony_ci  const std::string body = R"(
394fd4e5da5Sopenharmony_ciOpCapability Shader
395fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
396fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
397fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
398fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
399fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
400fd4e5da5Sopenharmony_ci
401fd4e5da5Sopenharmony_ci%string = OpString ""
402fd4e5da5Sopenharmony_ci%void = OpTypeVoid
403fd4e5da5Sopenharmony_ci%bool = OpTypeBool
404fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0
405fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
406fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
407fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0
408fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1
409fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
410fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int
411fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int
412fd4e5da5Sopenharmony_ci
413fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type
414fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
415fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int
416fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int
417fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel
418fd4e5da5Sopenharmony_ciOpReturn
419fd4e5da5Sopenharmony_ciOpFunctionEnd
420fd4e5da5Sopenharmony_ci
421fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
422fd4e5da5Sopenharmony_ci%main_entry = OpLabel
423fd4e5da5Sopenharmony_ciOpReturn
424fd4e5da5Sopenharmony_ciOpFunctionEnd
425fd4e5da5Sopenharmony_ci)";
426fd4e5da5Sopenharmony_ci
427fd4e5da5Sopenharmony_ci  CompileSuccessfully(body);
428fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
429fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
430fd4e5da5Sopenharmony_ci              HasSubstr("Non-semantic OpExtInst within function definition "
431fd4e5da5Sopenharmony_ci                        "must appear in a block"));
432fd4e5da5Sopenharmony_ci}
433fd4e5da5Sopenharmony_ci
434fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenOpFunctionParameterBad) {
435fd4e5da5Sopenharmony_ci  const std::string body = R"(
436fd4e5da5Sopenharmony_ciOpCapability Shader
437fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
438fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
439fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
440fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
441fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
442fd4e5da5Sopenharmony_ci
443fd4e5da5Sopenharmony_ci%string = OpString ""
444fd4e5da5Sopenharmony_ci%void = OpTypeVoid
445fd4e5da5Sopenharmony_ci%bool = OpTypeBool
446fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0
447fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
448fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
449fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0
450fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1
451fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
452fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int
453fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int
454fd4e5da5Sopenharmony_ci
455fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type
456fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int
457fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
458fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int
459fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel
460fd4e5da5Sopenharmony_ciOpReturn
461fd4e5da5Sopenharmony_ciOpFunctionEnd
462fd4e5da5Sopenharmony_ci
463fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
464fd4e5da5Sopenharmony_ci%main_entry = OpLabel
465fd4e5da5Sopenharmony_ciOpReturn
466fd4e5da5Sopenharmony_ciOpFunctionEnd
467fd4e5da5Sopenharmony_ci)";
468fd4e5da5Sopenharmony_ci
469fd4e5da5Sopenharmony_ci  CompileSuccessfully(body);
470fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
471fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
472fd4e5da5Sopenharmony_ci              HasSubstr("Non-semantic OpExtInst within function definition "
473fd4e5da5Sopenharmony_ci                        "must appear in a block"));
474fd4e5da5Sopenharmony_ci}
475fd4e5da5Sopenharmony_ci
476fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticAfterOpFunctionParameterGood) {
477fd4e5da5Sopenharmony_ci  const std::string body = R"(
478fd4e5da5Sopenharmony_ciOpCapability Shader
479fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
480fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
481fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
482fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
483fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
484fd4e5da5Sopenharmony_ci
485fd4e5da5Sopenharmony_ci%string = OpString ""
486fd4e5da5Sopenharmony_ci%void = OpTypeVoid
487fd4e5da5Sopenharmony_ci%bool = OpTypeBool
488fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0
489fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
490fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
491fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0
492fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1
493fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
494fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int
495fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int
496fd4e5da5Sopenharmony_ci
497fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type
498fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int
499fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int
500fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel
501fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
502fd4e5da5Sopenharmony_ciOpReturn
503fd4e5da5Sopenharmony_ciOpFunctionEnd
504fd4e5da5Sopenharmony_ci
505fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
506fd4e5da5Sopenharmony_ci%main_entry = OpLabel
507fd4e5da5Sopenharmony_ciOpReturn
508fd4e5da5Sopenharmony_ciOpFunctionEnd
509fd4e5da5Sopenharmony_ci)";
510fd4e5da5Sopenharmony_ci
511fd4e5da5Sopenharmony_ci  CompileSuccessfully(body);
512fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
513fd4e5da5Sopenharmony_ci}
514fd4e5da5Sopenharmony_ci
515fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenFunctionsGood) {
516fd4e5da5Sopenharmony_ci  const std::string body = R"(
517fd4e5da5Sopenharmony_ciOpCapability Shader
518fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info"
519fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set"
520fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
521fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main"
522fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft
523fd4e5da5Sopenharmony_ci
524fd4e5da5Sopenharmony_ci%string = OpString ""
525fd4e5da5Sopenharmony_ci%void = OpTypeVoid
526fd4e5da5Sopenharmony_ci%bool = OpTypeBool
527fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0
528fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool
529fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool
530fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0
531fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1
532fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
533fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int
534fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int
535fd4e5da5Sopenharmony_ci
536fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type
537fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int
538fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int
539fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel
540fd4e5da5Sopenharmony_ciOpReturn
541fd4e5da5Sopenharmony_ciOpFunctionEnd
542fd4e5da5Sopenharmony_ci
543fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1
544fd4e5da5Sopenharmony_ci
545fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
546fd4e5da5Sopenharmony_ci%main_entry = OpLabel
547fd4e5da5Sopenharmony_ciOpReturn
548fd4e5da5Sopenharmony_ciOpFunctionEnd
549fd4e5da5Sopenharmony_ci)";
550fd4e5da5Sopenharmony_ci
551fd4e5da5Sopenharmony_ci  CompileSuccessfully(body);
552fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
553fd4e5da5Sopenharmony_ci}
554fd4e5da5Sopenharmony_ci
555fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionGood) {
556fd4e5da5Sopenharmony_ci  const std::string body = R"(
557fd4e5da5Sopenharmony_ciOpLine %string 1 1
558fd4e5da5Sopenharmony_ci%var = OpVariable %func_int Function
559fd4e5da5Sopenharmony_ciOpLine %string 2 1
560fd4e5da5Sopenharmony_ciOpNop
561fd4e5da5Sopenharmony_ciOpLine %string 3 1
562fd4e5da5Sopenharmony_ciOpNop
563fd4e5da5Sopenharmony_ci)";
564fd4e5da5Sopenharmony_ci
565fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
566fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
567fd4e5da5Sopenharmony_ci}
568fd4e5da5Sopenharmony_ci
569fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionMultipleGood) {
570fd4e5da5Sopenharmony_ci  const std::string body = R"(
571fd4e5da5Sopenharmony_ciOpLine %string 1 1
572fd4e5da5Sopenharmony_ci%1 = OpVariable %func_int Function
573fd4e5da5Sopenharmony_ciOpLine %string 2 1
574fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function
575fd4e5da5Sopenharmony_ci%3 = OpVariable %func_int Function
576fd4e5da5Sopenharmony_ciOpNop
577fd4e5da5Sopenharmony_ciOpLine %string 3 1
578fd4e5da5Sopenharmony_ciOpNop
579fd4e5da5Sopenharmony_ci)";
580fd4e5da5Sopenharmony_ci
581fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
582fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
583fd4e5da5Sopenharmony_ci}
584fd4e5da5Sopenharmony_ci
585fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionBad) {
586fd4e5da5Sopenharmony_ci  const std::string body = R"(
587fd4e5da5Sopenharmony_ci%1 = OpUndef %int
588fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function
589fd4e5da5Sopenharmony_ci)";
590fd4e5da5Sopenharmony_ci
591fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
592fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
593fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
594fd4e5da5Sopenharmony_ci              HasSubstr("All OpVariable instructions in a function must be the "
595fd4e5da5Sopenharmony_ci                        "first instructions"));
596fd4e5da5Sopenharmony_ci}
597fd4e5da5Sopenharmony_ci
598fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionMultipleBad) {
599fd4e5da5Sopenharmony_ci  const std::string body = R"(
600fd4e5da5Sopenharmony_ciOpNop
601fd4e5da5Sopenharmony_ci%1 = OpVariable %func_int Function
602fd4e5da5Sopenharmony_ciOpLine %string 1 1
603fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function
604fd4e5da5Sopenharmony_ciOpNop
605fd4e5da5Sopenharmony_ciOpNop
606fd4e5da5Sopenharmony_ciOpLine %string 2 1
607fd4e5da5Sopenharmony_ci%3 = OpVariable %func_int Function
608fd4e5da5Sopenharmony_ci)";
609fd4e5da5Sopenharmony_ci
610fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
611fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
612fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
613fd4e5da5Sopenharmony_ci              HasSubstr("All OpVariable instructions in a function must be the "
614fd4e5da5Sopenharmony_ci                        "first instructions"));
615fd4e5da5Sopenharmony_ci}
616fd4e5da5Sopenharmony_ci
617fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchSuccess) {
618fd4e5da5Sopenharmony_ci  const std::string body = R"(
619fd4e5da5Sopenharmony_ciOpBranch %loop
620fd4e5da5Sopenharmony_ci%loop = OpLabel
621fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None
622fd4e5da5Sopenharmony_ciOpBranch %loop
623fd4e5da5Sopenharmony_ci%end = OpLabel
624fd4e5da5Sopenharmony_ci)";
625fd4e5da5Sopenharmony_ci
626fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
627fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
628fd4e5da5Sopenharmony_ci}
629fd4e5da5Sopenharmony_ci
630fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchConditionalSuccess) {
631fd4e5da5Sopenharmony_ci  const std::string body = R"(
632fd4e5da5Sopenharmony_ciOpBranch %loop
633fd4e5da5Sopenharmony_ci%loop = OpLabel
634fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None
635fd4e5da5Sopenharmony_ciOpBranchConditional %true %loop %end
636fd4e5da5Sopenharmony_ci%end = OpLabel
637fd4e5da5Sopenharmony_ci)";
638fd4e5da5Sopenharmony_ci
639fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
640fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
641fd4e5da5Sopenharmony_ci}
642fd4e5da5Sopenharmony_ci
643fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsBadOpFail) {
644fd4e5da5Sopenharmony_ci  const std::string body = R"(
645fd4e5da5Sopenharmony_ciOpBranch %loop
646fd4e5da5Sopenharmony_ci%loop = OpLabel
647fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None
648fd4e5da5Sopenharmony_ciOpNop
649fd4e5da5Sopenharmony_ciOpBranchConditional %true %loop %end
650fd4e5da5Sopenharmony_ci%end = OpLabel
651fd4e5da5Sopenharmony_ci)";
652fd4e5da5Sopenharmony_ci
653fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
654fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
655fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
656fd4e5da5Sopenharmony_ci              HasSubstr("OpLoopMerge must immediately precede either an "
657fd4e5da5Sopenharmony_ci                        "OpBranch or OpBranchConditional instruction."));
658fd4e5da5Sopenharmony_ci}
659fd4e5da5Sopenharmony_ci
660fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpBranchConditionalSuccess) {
661fd4e5da5Sopenharmony_ci  const std::string body = R"(
662fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None
663fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label
664fd4e5da5Sopenharmony_ci%true_label = OpLabel
665fd4e5da5Sopenharmony_ciOpBranch %end_label
666fd4e5da5Sopenharmony_ci%false_label = OpLabel
667fd4e5da5Sopenharmony_ciOpBranch %end_label
668fd4e5da5Sopenharmony_ci%end_label = OpLabel
669fd4e5da5Sopenharmony_ci)";
670fd4e5da5Sopenharmony_ci
671fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
672fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
673fd4e5da5Sopenharmony_ci}
674fd4e5da5Sopenharmony_ci
675fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpSwitchSuccess) {
676fd4e5da5Sopenharmony_ci  const std::string body = R"(
677fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None
678fd4e5da5Sopenharmony_ciOpSwitch %zero %merge 0 %label
679fd4e5da5Sopenharmony_ci%label = OpLabel
680fd4e5da5Sopenharmony_ciOpBranch %merge
681fd4e5da5Sopenharmony_ci%merge = OpLabel
682fd4e5da5Sopenharmony_ci)";
683fd4e5da5Sopenharmony_ci
684fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
685fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
686fd4e5da5Sopenharmony_ci}
687fd4e5da5Sopenharmony_ci
688fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsBadOpFail) {
689fd4e5da5Sopenharmony_ci  const std::string body = R"(
690fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None
691fd4e5da5Sopenharmony_ciOpNop
692fd4e5da5Sopenharmony_ciOpSwitch %zero %merge 0 %label
693fd4e5da5Sopenharmony_ci%label = OpLabel
694fd4e5da5Sopenharmony_ciOpBranch %merge
695fd4e5da5Sopenharmony_ci%merge = OpLabel
696fd4e5da5Sopenharmony_ci)";
697fd4e5da5Sopenharmony_ci
698fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body));
699fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
700fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
701fd4e5da5Sopenharmony_ci              HasSubstr("OpSelectionMerge must immediately precede either an "
702fd4e5da5Sopenharmony_ci                        "OpBranchConditional or OpSwitch instruction"));
703fd4e5da5Sopenharmony_ci}
704fd4e5da5Sopenharmony_ci
705fd4e5da5Sopenharmony_ci}  // namespace
706fd4e5da5Sopenharmony_ci}  // namespace val
707fd4e5da5Sopenharmony_ci}  // namespace spvtools
708