1fd4e5da5Sopenharmony_ci// Copyright (c) 2015-2016 The Khronos Group 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// Validation tests for Logical Layout
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include <functional>
18fd4e5da5Sopenharmony_ci#include <string>
19fd4e5da5Sopenharmony_ci#include <tuple>
20fd4e5da5Sopenharmony_ci#include <utility>
21fd4e5da5Sopenharmony_ci#include <vector>
22fd4e5da5Sopenharmony_ci
23fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
24fd4e5da5Sopenharmony_ci#include "source/diagnostic.h"
25fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h"
26fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h"
27fd4e5da5Sopenharmony_ci
28fd4e5da5Sopenharmony_cinamespace spvtools {
29fd4e5da5Sopenharmony_cinamespace val {
30fd4e5da5Sopenharmony_cinamespace {
31fd4e5da5Sopenharmony_ci
32fd4e5da5Sopenharmony_ciusing ::testing::Eq;
33fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr;
34fd4e5da5Sopenharmony_ciusing ::testing::StrEq;
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_ciusing pred_type = std::function<spv_result_t(int)>;
37fd4e5da5Sopenharmony_ciusing ValidateLayout = spvtest::ValidateBase<
38fd4e5da5Sopenharmony_ci    std::tuple<int, std::tuple<std::string, pred_type, pred_type>>>;
39fd4e5da5Sopenharmony_ci
40fd4e5da5Sopenharmony_ci// returns true if order is equal to VAL
41fd4e5da5Sopenharmony_citemplate <int VAL, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
42fd4e5da5Sopenharmony_cispv_result_t Equals(int order) {
43fd4e5da5Sopenharmony_ci  return order == VAL ? SPV_SUCCESS : RET;
44fd4e5da5Sopenharmony_ci}
45fd4e5da5Sopenharmony_ci
46fd4e5da5Sopenharmony_ci// returns true if order is between MIN and MAX(inclusive)
47fd4e5da5Sopenharmony_citemplate <int MIN, int MAX, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
48fd4e5da5Sopenharmony_cistruct Range {
49fd4e5da5Sopenharmony_ci  explicit Range(bool inverse = false) : inverse_(inverse) {}
50fd4e5da5Sopenharmony_ci  spv_result_t operator()(int order) {
51fd4e5da5Sopenharmony_ci    return (inverse_ ^ (order >= MIN && order <= MAX)) ? SPV_SUCCESS : RET;
52fd4e5da5Sopenharmony_ci  }
53fd4e5da5Sopenharmony_ci
54fd4e5da5Sopenharmony_ci private:
55fd4e5da5Sopenharmony_ci  bool inverse_;
56fd4e5da5Sopenharmony_ci};
57fd4e5da5Sopenharmony_ci
58fd4e5da5Sopenharmony_ci// SPIRV source used to test the logical layout
59fd4e5da5Sopenharmony_ciconst std::vector<std::string>& getInstructions() {
60fd4e5da5Sopenharmony_ci  // clang-format off
61fd4e5da5Sopenharmony_ci  static const std::vector<std::string> instructions = {
62fd4e5da5Sopenharmony_ci    "OpCapability Shader",
63fd4e5da5Sopenharmony_ci    "OpExtension \"TestExtension\"",
64fd4e5da5Sopenharmony_ci    "%inst = OpExtInstImport \"GLSL.std.450\"",
65fd4e5da5Sopenharmony_ci    "OpMemoryModel Logical GLSL450",
66fd4e5da5Sopenharmony_ci    "OpEntryPoint GLCompute %func \"\"",
67fd4e5da5Sopenharmony_ci    "OpExecutionMode %func LocalSize 1 1 1",
68fd4e5da5Sopenharmony_ci    "OpExecutionModeId %func LocalSizeId %one %one %one",
69fd4e5da5Sopenharmony_ci    "%str = OpString \"Test String\"",
70fd4e5da5Sopenharmony_ci    "%str2 = OpString \"blabla\"",
71fd4e5da5Sopenharmony_ci    "OpSource GLSL 450 %str \"uniform vec3 var = vec3(4.0);\"",
72fd4e5da5Sopenharmony_ci    "OpSourceContinued \"void main(){return;}\"",
73fd4e5da5Sopenharmony_ci    "OpSourceExtension \"Test extension\"",
74fd4e5da5Sopenharmony_ci    "OpName %func \"MyFunction\"",
75fd4e5da5Sopenharmony_ci    "OpMemberName %struct 1 \"my_member\"",
76fd4e5da5Sopenharmony_ci    "OpDecorate %dgrp RowMajor",
77fd4e5da5Sopenharmony_ci    "OpMemberDecorate %struct 1 RowMajor",
78fd4e5da5Sopenharmony_ci    "%dgrp   = OpDecorationGroup",
79fd4e5da5Sopenharmony_ci    "OpGroupDecorate %dgrp %mat33 %mat44",
80fd4e5da5Sopenharmony_ci    "%intt     = OpTypeInt 32 1",
81fd4e5da5Sopenharmony_ci    "%floatt   = OpTypeFloat 32",
82fd4e5da5Sopenharmony_ci    "%voidt    = OpTypeVoid",
83fd4e5da5Sopenharmony_ci    "%boolt    = OpTypeBool",
84fd4e5da5Sopenharmony_ci    "%vec4     = OpTypeVector %floatt 4",
85fd4e5da5Sopenharmony_ci    "%vec3     = OpTypeVector %floatt 3",
86fd4e5da5Sopenharmony_ci    "%mat33    = OpTypeMatrix %vec3 3",
87fd4e5da5Sopenharmony_ci    "%mat44    = OpTypeMatrix %vec4 4",
88fd4e5da5Sopenharmony_ci    "%struct   = OpTypeStruct %intt %mat33",
89fd4e5da5Sopenharmony_ci    "%vfunct   = OpTypeFunction %voidt",
90fd4e5da5Sopenharmony_ci    "%viifunct = OpTypeFunction %voidt %intt %intt",
91fd4e5da5Sopenharmony_ci    "%one      = OpConstant %intt 1",
92fd4e5da5Sopenharmony_ci    // TODO(umar): OpConstant fails because the type is not defined
93fd4e5da5Sopenharmony_ci    // TODO(umar): OpGroupMemberDecorate
94fd4e5da5Sopenharmony_ci    "OpLine %str 3 4",
95fd4e5da5Sopenharmony_ci    "OpNoLine",
96fd4e5da5Sopenharmony_ci    "%func     = OpFunction %voidt None %vfunct",
97fd4e5da5Sopenharmony_ci    "%l = OpLabel",
98fd4e5da5Sopenharmony_ci    "OpReturn ; %func return",
99fd4e5da5Sopenharmony_ci    "OpFunctionEnd ; %func end",
100fd4e5da5Sopenharmony_ci    "%func2    = OpFunction %voidt None %viifunct",
101fd4e5da5Sopenharmony_ci    "%funcp1   = OpFunctionParameter %intt",
102fd4e5da5Sopenharmony_ci    "%funcp2   = OpFunctionParameter %intt",
103fd4e5da5Sopenharmony_ci    "%fLabel   = OpLabel",
104fd4e5da5Sopenharmony_ci    "OpNop",
105fd4e5da5Sopenharmony_ci    "OpReturn ; %func2 return",
106fd4e5da5Sopenharmony_ci    "OpFunctionEnd"
107fd4e5da5Sopenharmony_ci  };
108fd4e5da5Sopenharmony_ci  return instructions;
109fd4e5da5Sopenharmony_ci}
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_cistatic const int kRangeEnd = 1000;
112fd4e5da5Sopenharmony_cipred_type All = Range<0, kRangeEnd>();
113fd4e5da5Sopenharmony_ci
114fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(InstructionsOrder,
115fd4e5da5Sopenharmony_ci    ValidateLayout,
116fd4e5da5Sopenharmony_ci    ::testing::Combine(::testing::Range((int)0, (int)getInstructions().size()),
117fd4e5da5Sopenharmony_ci    // Note: Because of ID dependencies between instructions, some instructions
118fd4e5da5Sopenharmony_ci    // are not free to be placed anywhere without triggering an non-layout
119fd4e5da5Sopenharmony_ci    // validation error. Therefore, "Lines to compile" for some instructions
120fd4e5da5Sopenharmony_ci    // are not "All" in the below.
121fd4e5da5Sopenharmony_ci    //
122fd4e5da5Sopenharmony_ci    //                                            | Instruction                | Line(s) valid          | Lines to compile
123fd4e5da5Sopenharmony_ci    ::testing::Values(std::make_tuple(std::string("OpCapability")              , Equals<0>              , Range<0, 2>())
124fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpExtension")               , Equals<1>              , All)
125fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpExtInstImport")           , Equals<2>              , All)
126fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpMemoryModel")             , Equals<3>              , Range<1, kRangeEnd>())
127fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpEntryPoint")              , Equals<4>              , All)
128fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpExecutionMode ")          , Range<5, 6>()          , All)
129fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpExecutionModeId")         , Range<5, 6>()          , All)
130fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpSource ")                 , Range<7, 11>()         , Range<8, kRangeEnd>())
131fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpSourceContinued ")        , Range<7, 11>()         , All)
132fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpSourceExtension ")        , Range<7, 11>()         , All)
133fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("%str2 = OpString ")         , Range<7, 11>()         , All)
134fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpName ")                   , Range<12, 13>()        , All)
135fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpMemberName ")             , Range<12, 13>()        , All)
136fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpDecorate ")               , Range<14, 17>()        , All)
137fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpMemberDecorate ")         , Range<14, 17>()        , All)
138fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpGroupDecorate ")          , Range<14, 17>()        , Range<17, kRangeEnd>())
139fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpDecorationGroup")         , Range<14, 17>()        , Range<0, 16>())
140fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeBool")                , Range<18, 31>()        , All)
141fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeVoid")                , Range<18, 31>()        , Range<0, 26>())
142fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeFloat")               , Range<18, 31>()        , Range<0,21>())
143fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeInt")                 , Range<18, 31>()        , Range<0, 21>())
144fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeVector %floatt 4")    , Range<18, 31>()        , Range<20, 24>())
145fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeMatrix %vec4 4")      , Range<18, 31>()        , Range<23, kRangeEnd>())
146fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpTypeStruct")              , Range<18, 31>()        , Range<25, kRangeEnd>())
147fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("%vfunct   = OpTypeFunction"), Range<18, 31>()        , Range<21, 31>())
148fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpConstant")                , Range<18, 31>()        , Range<21, kRangeEnd>())
149fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpLine ")                   , Range<18, kRangeEnd>() , Range<8, kRangeEnd>())
150fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpNoLine")                  , Range<18, kRangeEnd>() , All)
151fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("%fLabel   = OpLabel")       , Equals<39>             , All)
152fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpNop")                     , Equals<40>             , Range<40,kRangeEnd>())
153fd4e5da5Sopenharmony_ci                    , std::make_tuple(std::string("OpReturn ; %func2 return")  , Equals<41>             , All)
154fd4e5da5Sopenharmony_ci    )));
155fd4e5da5Sopenharmony_ci// clang-format on
156fd4e5da5Sopenharmony_ci
157fd4e5da5Sopenharmony_ci// Creates a new vector which removes the string if the substr is found in the
158fd4e5da5Sopenharmony_ci// instructions vector and reinserts it in the location specified by order.
159fd4e5da5Sopenharmony_ci// NOTE: This will not work correctly if there are two instances of substr in
160fd4e5da5Sopenharmony_ci// instructions
161fd4e5da5Sopenharmony_cistd::vector<std::string> GenerateCode(std::string substr, int order) {
162fd4e5da5Sopenharmony_ci  std::vector<std::string> code(getInstructions().size());
163fd4e5da5Sopenharmony_ci  std::vector<std::string> inst(1);
164fd4e5da5Sopenharmony_ci  partition_copy(std::begin(getInstructions()), std::end(getInstructions()),
165fd4e5da5Sopenharmony_ci                 std::begin(code), std::begin(inst),
166fd4e5da5Sopenharmony_ci                 [=](const std::string& str) {
167fd4e5da5Sopenharmony_ci                   return std::string::npos == str.find(substr);
168fd4e5da5Sopenharmony_ci                 });
169fd4e5da5Sopenharmony_ci
170fd4e5da5Sopenharmony_ci  code.insert(std::begin(code) + order, inst.front());
171fd4e5da5Sopenharmony_ci  return code;
172fd4e5da5Sopenharmony_ci}
173fd4e5da5Sopenharmony_ci
174fd4e5da5Sopenharmony_ci// This test will check the logical layout of a binary by removing each
175fd4e5da5Sopenharmony_ci// instruction in the pair of the INSTANTIATE_TEST_SUITE_P call and moving it in
176fd4e5da5Sopenharmony_ci// the SPIRV source formed by combining the vector "instructions".
177fd4e5da5Sopenharmony_ciTEST_P(ValidateLayout, Layout) {
178fd4e5da5Sopenharmony_ci  int order;
179fd4e5da5Sopenharmony_ci  std::string instruction;
180fd4e5da5Sopenharmony_ci  pred_type pred;
181fd4e5da5Sopenharmony_ci  pred_type test_pred;  // Predicate to determine if the test should be build
182fd4e5da5Sopenharmony_ci  std::tuple<std::string, pred_type, pred_type> testCase;
183fd4e5da5Sopenharmony_ci
184fd4e5da5Sopenharmony_ci  std::tie(order, testCase) = GetParam();
185fd4e5da5Sopenharmony_ci  std::tie(instruction, pred, test_pred) = testCase;
186fd4e5da5Sopenharmony_ci
187fd4e5da5Sopenharmony_ci  // Skip test which break the code generation
188fd4e5da5Sopenharmony_ci  if (test_pred(order)) return;
189fd4e5da5Sopenharmony_ci
190fd4e5da5Sopenharmony_ci  std::vector<std::string> code = GenerateCode(instruction, order);
191fd4e5da5Sopenharmony_ci
192fd4e5da5Sopenharmony_ci  std::stringstream ss;
193fd4e5da5Sopenharmony_ci  std::copy(std::begin(code), std::end(code),
194fd4e5da5Sopenharmony_ci            std::ostream_iterator<std::string>(ss, "\n"));
195fd4e5da5Sopenharmony_ci
196fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
197fd4e5da5Sopenharmony_ci  // printf("code: \n%s\n", ss.str().c_str());
198fd4e5da5Sopenharmony_ci  CompileSuccessfully(ss.str(), env);
199fd4e5da5Sopenharmony_ci  spv_result_t result;
200fd4e5da5Sopenharmony_ci  // clang-format off
201fd4e5da5Sopenharmony_ci  ASSERT_EQ(pred(order), result = ValidateInstructions(env))
202fd4e5da5Sopenharmony_ci    << "Actual: "        << spvResultToString(result)
203fd4e5da5Sopenharmony_ci    << "\nExpected: "    << spvResultToString(pred(order))
204fd4e5da5Sopenharmony_ci    << "\nOrder: "       << order
205fd4e5da5Sopenharmony_ci    << "\nInstruction: " << instruction
206fd4e5da5Sopenharmony_ci    << "\nCode: \n"      << ss.str();
207fd4e5da5Sopenharmony_ci  // clang-format on
208fd4e5da5Sopenharmony_ci}
209fd4e5da5Sopenharmony_ci
210fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelMissingBeforeEntryPoint) {
211fd4e5da5Sopenharmony_ci  std::string str = R"(
212fd4e5da5Sopenharmony_ci    OpCapability Matrix
213fd4e5da5Sopenharmony_ci    OpExtension "TestExtension"
214fd4e5da5Sopenharmony_ci    %inst = OpExtInstImport "GLSL.std.450"
215fd4e5da5Sopenharmony_ci    OpEntryPoint GLCompute %func ""
216fd4e5da5Sopenharmony_ci    OpExecutionMode %func LocalSize 1 1 1
217fd4e5da5Sopenharmony_ci    )";
218fd4e5da5Sopenharmony_ci
219fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
220fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
221fd4e5da5Sopenharmony_ci  EXPECT_THAT(
222fd4e5da5Sopenharmony_ci      getDiagnosticString(),
223fd4e5da5Sopenharmony_ci      HasSubstr(
224fd4e5da5Sopenharmony_ci          "EntryPoint cannot appear before the memory model instruction"));
225fd4e5da5Sopenharmony_ci}
226fd4e5da5Sopenharmony_ci
227fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelMissing) {
228fd4e5da5Sopenharmony_ci  char str[] = R"(OpCapability Linkage)";
229fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
230fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
231fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
232fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
233fd4e5da5Sopenharmony_ci              HasSubstr("Missing required OpMemoryModel instruction"));
234fd4e5da5Sopenharmony_ci}
235fd4e5da5Sopenharmony_ci
236fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelSpecifiedTwice) {
237fd4e5da5Sopenharmony_ci  char str[] = R"(
238fd4e5da5Sopenharmony_ci    OpCapability Linkage
239fd4e5da5Sopenharmony_ci    OpCapability Shader
240fd4e5da5Sopenharmony_ci    OpMemoryModel Logical Simple
241fd4e5da5Sopenharmony_ci    OpMemoryModel Logical Simple
242fd4e5da5Sopenharmony_ci    )";
243fd4e5da5Sopenharmony_ci
244fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
245fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
246fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
247fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
248fd4e5da5Sopenharmony_ci              HasSubstr("OpMemoryModel should only be provided once"));
249fd4e5da5Sopenharmony_ci}
250fd4e5da5Sopenharmony_ci
251fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, FunctionDefinitionBeforeDeclarationBad) {
252fd4e5da5Sopenharmony_ci  char str[] = R"(
253fd4e5da5Sopenharmony_ci           OpCapability Shader
254fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
255fd4e5da5Sopenharmony_ci           OpDecorate %var Restrict
256fd4e5da5Sopenharmony_ci%intt    = OpTypeInt 32 1
257fd4e5da5Sopenharmony_ci%voidt   = OpTypeVoid
258fd4e5da5Sopenharmony_ci%vfunct  = OpTypeFunction %voidt
259fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt
260fd4e5da5Sopenharmony_ci%ptrt    = OpTypePointer Function %intt
261fd4e5da5Sopenharmony_ci%func    = OpFunction %voidt None %vfunct
262fd4e5da5Sopenharmony_ci%funcl   = OpLabel
263fd4e5da5Sopenharmony_ci           OpNop
264fd4e5da5Sopenharmony_ci           OpReturn
265fd4e5da5Sopenharmony_ci           OpFunctionEnd
266fd4e5da5Sopenharmony_ci%func2   = OpFunction %voidt None %vifunct ; must appear before definition
267fd4e5da5Sopenharmony_ci%func2p  = OpFunctionParameter %intt
268fd4e5da5Sopenharmony_ci           OpFunctionEnd
269fd4e5da5Sopenharmony_ci)";
270fd4e5da5Sopenharmony_ci
271fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
272fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
273fd4e5da5Sopenharmony_ci  EXPECT_THAT(
274fd4e5da5Sopenharmony_ci      getDiagnosticString(),
275fd4e5da5Sopenharmony_ci      HasSubstr(
276fd4e5da5Sopenharmony_ci          "Function declarations must appear before function definitions."));
277fd4e5da5Sopenharmony_ci}
278fd4e5da5Sopenharmony_ci
279fd4e5da5Sopenharmony_ci// TODO(umar): Passes but gives incorrect error message. Should be fixed after
280fd4e5da5Sopenharmony_ci// type checking
281fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, LabelBeforeFunctionParameterBad) {
282fd4e5da5Sopenharmony_ci  char str[] = R"(
283fd4e5da5Sopenharmony_ci           OpCapability Shader
284fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
285fd4e5da5Sopenharmony_ci           OpDecorate %var Restrict
286fd4e5da5Sopenharmony_ci%intt    = OpTypeInt 32 1
287fd4e5da5Sopenharmony_ci%voidt   = OpTypeVoid
288fd4e5da5Sopenharmony_ci%vfunct  = OpTypeFunction %voidt
289fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt
290fd4e5da5Sopenharmony_ci%ptrt    = OpTypePointer Function %intt
291fd4e5da5Sopenharmony_ci%func    = OpFunction %voidt None %vifunct
292fd4e5da5Sopenharmony_ci%funcl   = OpLabel                    ; Label appears before function parameter
293fd4e5da5Sopenharmony_ci%func2p  = OpFunctionParameter %intt
294fd4e5da5Sopenharmony_ci           OpNop
295fd4e5da5Sopenharmony_ci           OpReturn
296fd4e5da5Sopenharmony_ci           OpFunctionEnd
297fd4e5da5Sopenharmony_ci)";
298fd4e5da5Sopenharmony_ci
299fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
300fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
301fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
302fd4e5da5Sopenharmony_ci              HasSubstr("Function parameters must only appear immediately "
303fd4e5da5Sopenharmony_ci                        "after the function definition"));
304fd4e5da5Sopenharmony_ci}
305fd4e5da5Sopenharmony_ci
306fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, FuncParameterNotImmediatlyAfterFuncBad) {
307fd4e5da5Sopenharmony_ci  char str[] = R"(
308fd4e5da5Sopenharmony_ci           OpCapability Shader
309fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
310fd4e5da5Sopenharmony_ci           OpDecorate %var Restrict
311fd4e5da5Sopenharmony_ci%intt    = OpTypeInt 32 1
312fd4e5da5Sopenharmony_ci%voidt   = OpTypeVoid
313fd4e5da5Sopenharmony_ci%vfunct  = OpTypeFunction %voidt
314fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt
315fd4e5da5Sopenharmony_ci%ptrt    = OpTypePointer Function %intt
316fd4e5da5Sopenharmony_ci%func    = OpFunction %voidt None %vifunct
317fd4e5da5Sopenharmony_ci%funcl   = OpLabel
318fd4e5da5Sopenharmony_ci           OpNop
319fd4e5da5Sopenharmony_ci           OpBranch %next
320fd4e5da5Sopenharmony_ci%func2p  = OpFunctionParameter %intt        ;FunctionParameter appears in a function but not immediately afterwards
321fd4e5da5Sopenharmony_ci%next    = OpLabel
322fd4e5da5Sopenharmony_ci           OpNop
323fd4e5da5Sopenharmony_ci           OpReturn
324fd4e5da5Sopenharmony_ci           OpFunctionEnd
325fd4e5da5Sopenharmony_ci)";
326fd4e5da5Sopenharmony_ci
327fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
328fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
329fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
330fd4e5da5Sopenharmony_ci              HasSubstr("Function parameters must only appear immediately "
331fd4e5da5Sopenharmony_ci                        "after the function definition"));
332fd4e5da5Sopenharmony_ci}
333fd4e5da5Sopenharmony_ci
334fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, OpUndefCanAppearInTypeDeclarationSection) {
335fd4e5da5Sopenharmony_ci  std::string str = R"(
336fd4e5da5Sopenharmony_ci         OpCapability Kernel
337fd4e5da5Sopenharmony_ci         OpCapability Linkage
338fd4e5da5Sopenharmony_ci         OpMemoryModel Logical OpenCL
339fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid
340fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0
341fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt
342fd4e5da5Sopenharmony_ci%udef  = OpUndef %uintt
343fd4e5da5Sopenharmony_ci%func  = OpFunction %voidt None %funct
344fd4e5da5Sopenharmony_ci%entry = OpLabel
345fd4e5da5Sopenharmony_ci         OpReturn
346fd4e5da5Sopenharmony_ci         OpFunctionEnd
347fd4e5da5Sopenharmony_ci)";
348fd4e5da5Sopenharmony_ci
349fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
350fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
351fd4e5da5Sopenharmony_ci}
352fd4e5da5Sopenharmony_ci
353fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, OpUndefCanAppearInBlock) {
354fd4e5da5Sopenharmony_ci  std::string str = R"(
355fd4e5da5Sopenharmony_ci         OpCapability Kernel
356fd4e5da5Sopenharmony_ci         OpCapability Linkage
357fd4e5da5Sopenharmony_ci         OpMemoryModel Logical OpenCL
358fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid
359fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0
360fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt
361fd4e5da5Sopenharmony_ci%func  = OpFunction %voidt None %funct
362fd4e5da5Sopenharmony_ci%entry = OpLabel
363fd4e5da5Sopenharmony_ci%udef  = OpUndef %uintt
364fd4e5da5Sopenharmony_ci         OpReturn
365fd4e5da5Sopenharmony_ci         OpFunctionEnd
366fd4e5da5Sopenharmony_ci)";
367fd4e5da5Sopenharmony_ci
368fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
369fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
370fd4e5da5Sopenharmony_ci}
371fd4e5da5Sopenharmony_ci
372fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingFunctionEndForFunctionWithBody) {
373fd4e5da5Sopenharmony_ci  const auto s = R"(
374fd4e5da5Sopenharmony_ciOpCapability Shader
375fd4e5da5Sopenharmony_ciOpCapability Linkage
376fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
377fd4e5da5Sopenharmony_ci%void = OpTypeVoid
378fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %void
379fd4e5da5Sopenharmony_ci%f = OpFunction %void None %tf
380fd4e5da5Sopenharmony_ci%l = OpLabel
381fd4e5da5Sopenharmony_ciOpReturn
382fd4e5da5Sopenharmony_ci)";
383fd4e5da5Sopenharmony_ci
384fd4e5da5Sopenharmony_ci  CompileSuccessfully(s);
385fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
386fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
387fd4e5da5Sopenharmony_ci              StrEq("Missing OpFunctionEnd at end of module."));
388fd4e5da5Sopenharmony_ci}
389fd4e5da5Sopenharmony_ci
390fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingFunctionEndForFunctionPrototype) {
391fd4e5da5Sopenharmony_ci  const auto s = R"(
392fd4e5da5Sopenharmony_ciOpCapability Shader
393fd4e5da5Sopenharmony_ciOpCapability Linkage
394fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
395fd4e5da5Sopenharmony_ci%void = OpTypeVoid
396fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %void
397fd4e5da5Sopenharmony_ci%f = OpFunction %void None %tf
398fd4e5da5Sopenharmony_ci)";
399fd4e5da5Sopenharmony_ci
400fd4e5da5Sopenharmony_ci  CompileSuccessfully(s);
401fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
402fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
403fd4e5da5Sopenharmony_ci              StrEq("Missing OpFunctionEnd at end of module."));
404fd4e5da5Sopenharmony_ci}
405fd4e5da5Sopenharmony_ci
406fd4e5da5Sopenharmony_ciusing ValidateOpFunctionParameter = spvtest::ValidateBase<int>;
407fd4e5da5Sopenharmony_ci
408fd4e5da5Sopenharmony_ciTEST_F(ValidateOpFunctionParameter, OpLineBetweenParameters) {
409fd4e5da5Sopenharmony_ci  const auto s = R"(
410fd4e5da5Sopenharmony_ciOpCapability Shader
411fd4e5da5Sopenharmony_ciOpCapability Linkage
412fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
413fd4e5da5Sopenharmony_ci%foo_frag = OpString "foo.frag"
414fd4e5da5Sopenharmony_ci%i32 = OpTypeInt 32 1
415fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %i32 %i32 %i32
416fd4e5da5Sopenharmony_ci%c = OpConstant %i32 123
417fd4e5da5Sopenharmony_ci%f = OpFunction %i32 None %tf
418fd4e5da5Sopenharmony_ciOpLine %foo_frag 1 1
419fd4e5da5Sopenharmony_ci%p1 = OpFunctionParameter %i32
420fd4e5da5Sopenharmony_ciOpNoLine
421fd4e5da5Sopenharmony_ci%p2 = OpFunctionParameter %i32
422fd4e5da5Sopenharmony_ci%l = OpLabel
423fd4e5da5Sopenharmony_ciOpReturnValue %c
424fd4e5da5Sopenharmony_ciOpFunctionEnd
425fd4e5da5Sopenharmony_ci)";
426fd4e5da5Sopenharmony_ci  CompileSuccessfully(s);
427fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
428fd4e5da5Sopenharmony_ci}
429fd4e5da5Sopenharmony_ci
430fd4e5da5Sopenharmony_ciTEST_F(ValidateOpFunctionParameter, TooManyParameters) {
431fd4e5da5Sopenharmony_ci  const auto s = R"(
432fd4e5da5Sopenharmony_ciOpCapability Shader
433fd4e5da5Sopenharmony_ciOpCapability Linkage
434fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
435fd4e5da5Sopenharmony_ci%i32 = OpTypeInt 32 1
436fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %i32 %i32 %i32
437fd4e5da5Sopenharmony_ci%c = OpConstant %i32 123
438fd4e5da5Sopenharmony_ci%f = OpFunction %i32 None %tf
439fd4e5da5Sopenharmony_ci%p1 = OpFunctionParameter %i32
440fd4e5da5Sopenharmony_ci%p2 = OpFunctionParameter %i32
441fd4e5da5Sopenharmony_ci%xp3 = OpFunctionParameter %i32
442fd4e5da5Sopenharmony_ci%xp4 = OpFunctionParameter %i32
443fd4e5da5Sopenharmony_ci%xp5 = OpFunctionParameter %i32
444fd4e5da5Sopenharmony_ci%xp6 = OpFunctionParameter %i32
445fd4e5da5Sopenharmony_ci%xp7 = OpFunctionParameter %i32
446fd4e5da5Sopenharmony_ci%l = OpLabel
447fd4e5da5Sopenharmony_ciOpReturnValue %c
448fd4e5da5Sopenharmony_ciOpFunctionEnd
449fd4e5da5Sopenharmony_ci)";
450fd4e5da5Sopenharmony_ci  CompileSuccessfully(s);
451fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
452fd4e5da5Sopenharmony_ci}
453fd4e5da5Sopenharmony_ci
454fd4e5da5Sopenharmony_ciusing ValidateEntryPoint = spvtest::ValidateBase<bool>;
455fd4e5da5Sopenharmony_ci
456fd4e5da5Sopenharmony_ci// Tests that not having OpEntryPoint causes an error.
457fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, NoEntryPointBad) {
458fd4e5da5Sopenharmony_ci  std::string spirv = R"(
459fd4e5da5Sopenharmony_ci      OpCapability Shader
460fd4e5da5Sopenharmony_ci      OpMemoryModel Logical GLSL450)";
461fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
462fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
463fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
464fd4e5da5Sopenharmony_ci              HasSubstr("No OpEntryPoint instruction was found. This is only "
465fd4e5da5Sopenharmony_ci                        "allowed if the Linkage capability is being used."));
466fd4e5da5Sopenharmony_ci}
467fd4e5da5Sopenharmony_ci
468fd4e5da5Sopenharmony_ci// Invalid. A function may not be a target of both OpEntryPoint and
469fd4e5da5Sopenharmony_ci// OpFunctionCall.
470fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) {
471fd4e5da5Sopenharmony_ci  std::string spirv = R"(
472fd4e5da5Sopenharmony_ci           OpCapability Shader
473fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
474fd4e5da5Sopenharmony_ci           OpEntryPoint Fragment %foo "foo"
475fd4e5da5Sopenharmony_ci           OpExecutionMode %foo OriginUpperLeft
476fd4e5da5Sopenharmony_ci%voidt   = OpTypeVoid
477fd4e5da5Sopenharmony_ci%funct   = OpTypeFunction %voidt
478fd4e5da5Sopenharmony_ci%foo     = OpFunction %voidt None %funct
479fd4e5da5Sopenharmony_ci%entry   = OpLabel
480fd4e5da5Sopenharmony_ci%recurse = OpFunctionCall %voidt %foo
481fd4e5da5Sopenharmony_ci           OpReturn
482fd4e5da5Sopenharmony_ci           OpFunctionEnd
483fd4e5da5Sopenharmony_ci      )";
484fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
485fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
486fd4e5da5Sopenharmony_ci  EXPECT_THAT(
487fd4e5da5Sopenharmony_ci      getDiagnosticString(),
488fd4e5da5Sopenharmony_ci      HasSubstr("A function (1) may not be targeted by both an OpEntryPoint "
489fd4e5da5Sopenharmony_ci                "instruction and an OpFunctionCall instruction."));
490fd4e5da5Sopenharmony_ci}
491fd4e5da5Sopenharmony_ci
492fd4e5da5Sopenharmony_ci// Invalid. Must be within a function to make a function call.
493fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, FunctionCallOutsideFunctionBody) {
494fd4e5da5Sopenharmony_ci  std::string spirv = R"(
495fd4e5da5Sopenharmony_ci               OpCapability Shader
496fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
497fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
498fd4e5da5Sopenharmony_ci               OpName %variableName "variableName"
499fd4e5da5Sopenharmony_ci         %34 = OpFunctionCall %variableName %1
500fd4e5da5Sopenharmony_ci      )";
501fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
502fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
503fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
504fd4e5da5Sopenharmony_ci              HasSubstr("FunctionCall must happen within a function body."));
505fd4e5da5Sopenharmony_ci}
506fd4e5da5Sopenharmony_ci
507fd4e5da5Sopenharmony_ci// Valid. Module with a function but no entry point is valid when Linkage
508fd4e5da5Sopenharmony_ci// Capability is used.
509fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, NoEntryPointWithLinkageCapGood) {
510fd4e5da5Sopenharmony_ci  std::string spirv = R"(
511fd4e5da5Sopenharmony_ci           OpCapability Shader
512fd4e5da5Sopenharmony_ci           OpCapability Linkage
513fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
514fd4e5da5Sopenharmony_ci%voidt   = OpTypeVoid
515fd4e5da5Sopenharmony_ci%funct   = OpTypeFunction %voidt
516fd4e5da5Sopenharmony_ci%foo     = OpFunction %voidt None %funct
517fd4e5da5Sopenharmony_ci%entry   = OpLabel
518fd4e5da5Sopenharmony_ci           OpReturn
519fd4e5da5Sopenharmony_ci           OpFunctionEnd
520fd4e5da5Sopenharmony_ci  )";
521fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
522fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
523fd4e5da5Sopenharmony_ci}
524fd4e5da5Sopenharmony_ci
525fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidIn10) {
526fd4e5da5Sopenharmony_ci  char str[] = R"(
527fd4e5da5Sopenharmony_ci           OpCapability Shader
528fd4e5da5Sopenharmony_ci           OpCapability Linkage
529fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
530fd4e5da5Sopenharmony_ci           OpName %void "void"
531fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is ok in 1.1 and later"
532fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
533fd4e5da5Sopenharmony_ci)";
534fd4e5da5Sopenharmony_ci
535fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
536fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_WRONG_VERSION,
537fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
538fd4e5da5Sopenharmony_ci  // In a 1.0 environment the version check fails.
539fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
540fd4e5da5Sopenharmony_ci              HasSubstr("Invalid SPIR-V binary version 1.1 for target "
541fd4e5da5Sopenharmony_ci                        "environment SPIR-V 1.0."));
542fd4e5da5Sopenharmony_ci}
543fd4e5da5Sopenharmony_ci
544fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedValidIn11) {
545fd4e5da5Sopenharmony_ci  char str[] = R"(
546fd4e5da5Sopenharmony_ci           OpCapability Shader
547fd4e5da5Sopenharmony_ci           OpCapability Linkage
548fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
549fd4e5da5Sopenharmony_ci           OpName %void "void"
550fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is ok in 1.1 and later"
551fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
552fd4e5da5Sopenharmony_ci)";
553fd4e5da5Sopenharmony_ci
554fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
555fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
556fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(), Eq(""));
557fd4e5da5Sopenharmony_ci}
558fd4e5da5Sopenharmony_ci
559fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, LayoutOrderMixedUp) {
560fd4e5da5Sopenharmony_ci  char str[] = R"(
561fd4e5da5Sopenharmony_ci           OpCapability Shader
562fd4e5da5Sopenharmony_ci           OpCapability Linkage
563fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
564fd4e5da5Sopenharmony_ci           OpEntryPoint Fragment %fragmentFloat "fragmentFloat"
565fd4e5da5Sopenharmony_ci           OpExecutionMode %fragmentFloat OriginUpperLeft
566fd4e5da5Sopenharmony_ci           OpEntryPoint Fragment %fragmentUint "fragmentUint"
567fd4e5da5Sopenharmony_ci           OpExecutionMode %fragmentUint OriginUpperLeft
568fd4e5da5Sopenharmony_ci)";
569fd4e5da5Sopenharmony_ci
570fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
571fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
572fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
573fd4e5da5Sopenharmony_ci  // By the mechanics of the validator, we assume ModuleProcessed is in the
574fd4e5da5Sopenharmony_ci  // right spot, but then that OpName is in the wrong spot.
575fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
576fd4e5da5Sopenharmony_ci              HasSubstr("EntryPoint is in an invalid layout section"));
577fd4e5da5Sopenharmony_ci}
578fd4e5da5Sopenharmony_ci
579fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedBeforeLastNameIsTooEarly) {
580fd4e5da5Sopenharmony_ci  char str[] = R"(
581fd4e5da5Sopenharmony_ci           OpCapability Shader
582fd4e5da5Sopenharmony_ci           OpCapability Linkage
583fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
584fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is too early"
585fd4e5da5Sopenharmony_ci           OpName %void "void"
586fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
587fd4e5da5Sopenharmony_ci)";
588fd4e5da5Sopenharmony_ci
589fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
590fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
591fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
592fd4e5da5Sopenharmony_ci  // By the mechanics of the validator, we assume ModuleProcessed is in the
593fd4e5da5Sopenharmony_ci  // right spot, but then that OpName is in the wrong spot.
594fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
595fd4e5da5Sopenharmony_ci              HasSubstr("Name is in an invalid layout section"));
596fd4e5da5Sopenharmony_ci}
597fd4e5da5Sopenharmony_ci
598fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidAfterFirstAnnotation) {
599fd4e5da5Sopenharmony_ci  char str[] = R"(
600fd4e5da5Sopenharmony_ci           OpCapability Shader
601fd4e5da5Sopenharmony_ci           OpCapability Linkage
602fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
603fd4e5da5Sopenharmony_ci           OpDecorate %void Volatile ; this is bogus, but keeps the example short
604fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is too late"
605fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
606fd4e5da5Sopenharmony_ci)";
607fd4e5da5Sopenharmony_ci
608fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
609fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
610fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
611fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
612fd4e5da5Sopenharmony_ci              HasSubstr("ModuleProcessed is in an invalid layout section"));
613fd4e5da5Sopenharmony_ci}
614fd4e5da5Sopenharmony_ci
615fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidInFunctionBeforeLabel) {
616fd4e5da5Sopenharmony_ci  char str[] = R"(
617fd4e5da5Sopenharmony_ci           OpCapability Shader
618fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
619fd4e5da5Sopenharmony_ci           OpEntryPoint GLCompute %main "main"
620fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
621fd4e5da5Sopenharmony_ci%voidfn  = OpTypeFunction %void
622fd4e5da5Sopenharmony_ci%main    = OpFunction %void None %voidfn
623fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is too late, in function before label"
624fd4e5da5Sopenharmony_ci%entry  =  OpLabel
625fd4e5da5Sopenharmony_ci           OpReturn
626fd4e5da5Sopenharmony_ci           OpFunctionEnd
627fd4e5da5Sopenharmony_ci)";
628fd4e5da5Sopenharmony_ci
629fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
630fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
631fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
632fd4e5da5Sopenharmony_ci  EXPECT_THAT(
633fd4e5da5Sopenharmony_ci      getDiagnosticString(),
634fd4e5da5Sopenharmony_ci      HasSubstr("ModuleProcessed cannot appear in a function declaration"));
635fd4e5da5Sopenharmony_ci}
636fd4e5da5Sopenharmony_ci
637fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) {
638fd4e5da5Sopenharmony_ci  char str[] = R"(
639fd4e5da5Sopenharmony_ci           OpCapability Shader
640fd4e5da5Sopenharmony_ci           OpMemoryModel Logical GLSL450
641fd4e5da5Sopenharmony_ci           OpEntryPoint GLCompute %main "main"
642fd4e5da5Sopenharmony_ci%void    = OpTypeVoid
643fd4e5da5Sopenharmony_ci%voidfn  = OpTypeFunction %void
644fd4e5da5Sopenharmony_ci%main    = OpFunction %void None %voidfn
645fd4e5da5Sopenharmony_ci%entry   = OpLabel
646fd4e5da5Sopenharmony_ci           OpModuleProcessed "this is too late, in basic block"
647fd4e5da5Sopenharmony_ci           OpReturn
648fd4e5da5Sopenharmony_ci           OpFunctionEnd
649fd4e5da5Sopenharmony_ci)";
650fd4e5da5Sopenharmony_ci
651fd4e5da5Sopenharmony_ci  CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
652fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
653fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
654fd4e5da5Sopenharmony_ci  EXPECT_THAT(
655fd4e5da5Sopenharmony_ci      getDiagnosticString(),
656fd4e5da5Sopenharmony_ci      HasSubstr("ModuleProcessed cannot appear in a function declaration"));
657fd4e5da5Sopenharmony_ci}
658fd4e5da5Sopenharmony_ci
659fd4e5da5Sopenharmony_ci// TODO(umar): Test optional instructions
660fd4e5da5Sopenharmony_ci
661fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ValidNVBindlessTexturelayout) {
662fd4e5da5Sopenharmony_ci  std::string str = R"(
663fd4e5da5Sopenharmony_ci         OpCapability Shader
664fd4e5da5Sopenharmony_ci         OpCapability BindlessTextureNV
665fd4e5da5Sopenharmony_ci         OpExtension "SPV_NV_bindless_texture"
666fd4e5da5Sopenharmony_ci         OpMemoryModel Logical GLSL450
667fd4e5da5Sopenharmony_ci         OpSamplerImageAddressingModeNV 64
668fd4e5da5Sopenharmony_ci         OpEntryPoint GLCompute %func "main"
669fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid
670fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0
671fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt
672fd4e5da5Sopenharmony_ci%func  = OpFunction %voidt None %funct
673fd4e5da5Sopenharmony_ci%entry = OpLabel
674fd4e5da5Sopenharmony_ci%udef  = OpUndef %uintt
675fd4e5da5Sopenharmony_ci         OpReturn
676fd4e5da5Sopenharmony_ci         OpFunctionEnd
677fd4e5da5Sopenharmony_ci)";
678fd4e5da5Sopenharmony_ci
679fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
680fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
681fd4e5da5Sopenharmony_ci}
682fd4e5da5Sopenharmony_ci
683fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, InvalidValidNVBindlessTexturelayout) {
684fd4e5da5Sopenharmony_ci  std::string str = R"(
685fd4e5da5Sopenharmony_ci         OpCapability Shader
686fd4e5da5Sopenharmony_ci         OpCapability BindlessTextureNV
687fd4e5da5Sopenharmony_ci         OpExtension "SPV_NV_bindless_texture"
688fd4e5da5Sopenharmony_ci         OpMemoryModel Logical GLSL450
689fd4e5da5Sopenharmony_ci         OpEntryPoint GLCompute %func "main"
690fd4e5da5Sopenharmony_ci         OpSamplerImageAddressingModeNV 64
691fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid
692fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0
693fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt
694fd4e5da5Sopenharmony_ci%func  = OpFunction %voidt None %funct
695fd4e5da5Sopenharmony_ci%entry = OpLabel
696fd4e5da5Sopenharmony_ci%udef  = OpUndef %uintt
697fd4e5da5Sopenharmony_ci         OpReturn
698fd4e5da5Sopenharmony_ci         OpFunctionEnd
699fd4e5da5Sopenharmony_ci)";
700fd4e5da5Sopenharmony_ci
701fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
702fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
703fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
704fd4e5da5Sopenharmony_ci  EXPECT_THAT(
705fd4e5da5Sopenharmony_ci      getDiagnosticString(),
706fd4e5da5Sopenharmony_ci      HasSubstr(
707fd4e5da5Sopenharmony_ci          "SamplerImageAddressingModeNV is in an invalid layout section"));
708fd4e5da5Sopenharmony_ci}
709fd4e5da5Sopenharmony_ci
710fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingNVBindlessAddressModeFromLayout) {
711fd4e5da5Sopenharmony_ci  std::string str = R"(
712fd4e5da5Sopenharmony_ci         OpCapability Shader
713fd4e5da5Sopenharmony_ci         OpCapability BindlessTextureNV
714fd4e5da5Sopenharmony_ci         OpExtension "SPV_NV_bindless_texture"
715fd4e5da5Sopenharmony_ci         OpMemoryModel Logical GLSL450
716fd4e5da5Sopenharmony_ci         OpEntryPoint GLCompute %func "main"
717fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid
718fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0
719fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt
720fd4e5da5Sopenharmony_ci%func  = OpFunction %voidt None %funct
721fd4e5da5Sopenharmony_ci%entry = OpLabel
722fd4e5da5Sopenharmony_ci%udef  = OpUndef %uintt
723fd4e5da5Sopenharmony_ci         OpReturn
724fd4e5da5Sopenharmony_ci         OpFunctionEnd
725fd4e5da5Sopenharmony_ci)";
726fd4e5da5Sopenharmony_ci
727fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
728fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
729fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
730fd4e5da5Sopenharmony_ci  EXPECT_THAT(
731fd4e5da5Sopenharmony_ci      getDiagnosticString(),
732fd4e5da5Sopenharmony_ci      HasSubstr("Missing required OpSamplerImageAddressingModeNV instruction"));
733fd4e5da5Sopenharmony_ci}
734fd4e5da5Sopenharmony_ci
735fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, NVBindlessAddressModeFromLayoutSpecifiedTwice) {
736fd4e5da5Sopenharmony_ci  std::string str = R"(
737fd4e5da5Sopenharmony_ci        OpCapability Shader
738fd4e5da5Sopenharmony_ci        OpCapability BindlessTextureNV
739fd4e5da5Sopenharmony_ci        OpExtension "SPV_NV_bindless_texture"
740fd4e5da5Sopenharmony_ci        OpMemoryModel Logical GLSL450
741fd4e5da5Sopenharmony_ci        OpSamplerImageAddressingModeNV 64
742fd4e5da5Sopenharmony_ci        OpSamplerImageAddressingModeNV 64
743fd4e5da5Sopenharmony_ci)";
744fd4e5da5Sopenharmony_ci
745fd4e5da5Sopenharmony_ci  CompileSuccessfully(str);
746fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
747fd4e5da5Sopenharmony_ci            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
748fd4e5da5Sopenharmony_ci  EXPECT_THAT(
749fd4e5da5Sopenharmony_ci      getDiagnosticString(),
750fd4e5da5Sopenharmony_ci      HasSubstr("OpSamplerImageAddressingModeNV should only be provided once"));
751fd4e5da5Sopenharmony_ci}
752fd4e5da5Sopenharmony_ci
753fd4e5da5Sopenharmony_ci}  // namespace
754fd4e5da5Sopenharmony_ci}  // namespace val
755fd4e5da5Sopenharmony_ci}  // namespace spvtools
756