1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google 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 ValidateDerivatives = spvtest::ValidateBase<bool>;
30fd4e5da5Sopenharmony_ci
31fd4e5da5Sopenharmony_cistd::string GenerateShaderCode(
32fd4e5da5Sopenharmony_ci    const std::string& body,
33fd4e5da5Sopenharmony_ci    const std::string& capabilities_and_extensions = "",
34fd4e5da5Sopenharmony_ci    const std::string& execution_model = "Fragment") {
35fd4e5da5Sopenharmony_ci  std::stringstream ss;
36fd4e5da5Sopenharmony_ci  ss << R"(
37fd4e5da5Sopenharmony_ciOpCapability Shader
38fd4e5da5Sopenharmony_ciOpCapability DerivativeControl
39fd4e5da5Sopenharmony_ci)";
40fd4e5da5Sopenharmony_ci
41fd4e5da5Sopenharmony_ci  ss << capabilities_and_extensions;
42fd4e5da5Sopenharmony_ci  ss << "OpMemoryModel Logical GLSL450\n";
43fd4e5da5Sopenharmony_ci  ss << "OpEntryPoint " << execution_model << " %main \"main\""
44fd4e5da5Sopenharmony_ci     << " %f32_var_input"
45fd4e5da5Sopenharmony_ci     << " %f32vec4_var_input"
46fd4e5da5Sopenharmony_ci     << "\n";
47fd4e5da5Sopenharmony_ci  if (execution_model == "Fragment") {
48fd4e5da5Sopenharmony_ci    ss << "OpExecutionMode %main OriginUpperLeft\n";
49fd4e5da5Sopenharmony_ci  }
50fd4e5da5Sopenharmony_ci
51fd4e5da5Sopenharmony_ci  ss << R"(
52fd4e5da5Sopenharmony_ci%void = OpTypeVoid
53fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void
54fd4e5da5Sopenharmony_ci%bool = OpTypeBool
55fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32
56fd4e5da5Sopenharmony_ci%u32 = OpTypeInt 32 0
57fd4e5da5Sopenharmony_ci%s32 = OpTypeInt 32 1
58fd4e5da5Sopenharmony_ci%f32vec4 = OpTypeVector %f32 4
59fd4e5da5Sopenharmony_ci
60fd4e5da5Sopenharmony_ci%f32_ptr_input = OpTypePointer Input %f32
61fd4e5da5Sopenharmony_ci%f32_var_input = OpVariable %f32_ptr_input Input
62fd4e5da5Sopenharmony_ci
63fd4e5da5Sopenharmony_ci%f32vec4_ptr_input = OpTypePointer Input %f32vec4
64fd4e5da5Sopenharmony_ci%f32vec4_var_input = OpVariable %f32vec4_ptr_input Input
65fd4e5da5Sopenharmony_ci)";
66fd4e5da5Sopenharmony_ci
67fd4e5da5Sopenharmony_ci  if (capabilities_and_extensions.find("OpCapability Float16") !=
68fd4e5da5Sopenharmony_ci      std::string::npos) {
69fd4e5da5Sopenharmony_ci    ss << "%f16 = OpTypeFloat 16\n"
70fd4e5da5Sopenharmony_ci       << "%f16vec4 = OpTypeVector %f16 4\n"
71fd4e5da5Sopenharmony_ci       << "%f16_0 = OpConstantNull %f16\n"
72fd4e5da5Sopenharmony_ci       << "%f16vec4_0 = OpConstantNull %f16vec4\n";
73fd4e5da5Sopenharmony_ci  }
74fd4e5da5Sopenharmony_ci
75fd4e5da5Sopenharmony_ci  ss << R"(
76fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func
77fd4e5da5Sopenharmony_ci%main_entry = OpLabel
78fd4e5da5Sopenharmony_ci)";
79fd4e5da5Sopenharmony_ci
80fd4e5da5Sopenharmony_ci  ss << body;
81fd4e5da5Sopenharmony_ci
82fd4e5da5Sopenharmony_ci  ss << R"(
83fd4e5da5Sopenharmony_ciOpReturn
84fd4e5da5Sopenharmony_ciOpFunctionEnd)";
85fd4e5da5Sopenharmony_ci
86fd4e5da5Sopenharmony_ci  return ss.str();
87fd4e5da5Sopenharmony_ci}
88fd4e5da5Sopenharmony_ci
89fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, ScalarSuccess) {
90fd4e5da5Sopenharmony_ci  const std::string body = R"(
91fd4e5da5Sopenharmony_ci%f32_var = OpLoad %f32 %f32_var_input
92fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32 %f32_var
93fd4e5da5Sopenharmony_ci%val2 = OpDPdy %f32 %f32_var
94fd4e5da5Sopenharmony_ci%val3 = OpFwidth %f32 %f32_var
95fd4e5da5Sopenharmony_ci%val4 = OpDPdxFine %f32 %f32_var
96fd4e5da5Sopenharmony_ci%val5 = OpDPdyFine %f32 %f32_var
97fd4e5da5Sopenharmony_ci%val6 = OpFwidthFine %f32 %f32_var
98fd4e5da5Sopenharmony_ci%val7 = OpDPdxCoarse %f32 %f32_var
99fd4e5da5Sopenharmony_ci%val8 = OpDPdyCoarse %f32 %f32_var
100fd4e5da5Sopenharmony_ci%val9 = OpFwidthCoarse %f32 %f32_var
101fd4e5da5Sopenharmony_ci)";
102fd4e5da5Sopenharmony_ci
103fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body).c_str());
104fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
105fd4e5da5Sopenharmony_ci}
106fd4e5da5Sopenharmony_ci
107fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, VectorSuccess) {
108fd4e5da5Sopenharmony_ci  const std::string body = R"(
109fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
110fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32vec4 %f32vec4_var
111fd4e5da5Sopenharmony_ci%val2 = OpDPdy %f32vec4 %f32vec4_var
112fd4e5da5Sopenharmony_ci%val3 = OpFwidth %f32vec4 %f32vec4_var
113fd4e5da5Sopenharmony_ci%val4 = OpDPdxFine %f32vec4 %f32vec4_var
114fd4e5da5Sopenharmony_ci%val5 = OpDPdyFine %f32vec4 %f32vec4_var
115fd4e5da5Sopenharmony_ci%val6 = OpFwidthFine %f32vec4 %f32vec4_var
116fd4e5da5Sopenharmony_ci%val7 = OpDPdxCoarse %f32vec4 %f32vec4_var
117fd4e5da5Sopenharmony_ci%val8 = OpDPdyCoarse %f32vec4 %f32vec4_var
118fd4e5da5Sopenharmony_ci%val9 = OpFwidthCoarse %f32vec4 %f32vec4_var
119fd4e5da5Sopenharmony_ci)";
120fd4e5da5Sopenharmony_ci
121fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body).c_str());
122fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
123fd4e5da5Sopenharmony_ci}
124fd4e5da5Sopenharmony_ci
125fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongResultType) {
126fd4e5da5Sopenharmony_ci  const std::string body = R"(
127fd4e5da5Sopenharmony_ci%f32_var = OpLoad %f32 %f32_var_input
128fd4e5da5Sopenharmony_ci%val1 = OpDPdx %u32 %f32vec4
129fd4e5da5Sopenharmony_ci)";
130fd4e5da5Sopenharmony_ci
131fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body).c_str());
132fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
133fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand '10[%v4float]' cannot "
134fd4e5da5Sopenharmony_ci                                               "be a type"));
135fd4e5da5Sopenharmony_ci}
136fd4e5da5Sopenharmony_ci
137fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongPType) {
138fd4e5da5Sopenharmony_ci  const std::string body = R"(
139fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
140fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32 %f32vec4_var
141fd4e5da5Sopenharmony_ci)";
142fd4e5da5Sopenharmony_ci
143fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body).c_str());
144fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
145fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
146fd4e5da5Sopenharmony_ci              HasSubstr("Expected P type and Result Type to be the same: "
147fd4e5da5Sopenharmony_ci                        "DPdx"));
148fd4e5da5Sopenharmony_ci}
149fd4e5da5Sopenharmony_ci
150fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) {
151fd4e5da5Sopenharmony_ci  const std::string body = R"(
152fd4e5da5Sopenharmony_ci%f32vec4_var = OpLoad %f32vec4 %f32vec4_var_input
153fd4e5da5Sopenharmony_ci%val1 = OpDPdx %f32vec4 %f32vec4_var
154fd4e5da5Sopenharmony_ci)";
155fd4e5da5Sopenharmony_ci
156fd4e5da5Sopenharmony_ci  CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str());
157fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
158fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
159fd4e5da5Sopenharmony_ci              HasSubstr("Derivative instructions require Fragment or GLCompute "
160fd4e5da5Sopenharmony_ci                        "execution model: DPdx"));
161fd4e5da5Sopenharmony_ci}
162fd4e5da5Sopenharmony_ci
163fd4e5da5Sopenharmony_ciTEST_F(ValidateDerivatives, NoExecutionModeGLCompute) {
164fd4e5da5Sopenharmony_ci  const std::string spirv = R"(
165fd4e5da5Sopenharmony_ciOpCapability Shader
166fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
167fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main"
168fd4e5da5Sopenharmony_ci%void = OpTypeVoid
169fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32
170fd4e5da5Sopenharmony_ci%float4 = OpTypeVector %float 4
171fd4e5da5Sopenharmony_ci%undef = OpUndef %float4
172fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void
173fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn
174fd4e5da5Sopenharmony_ci%entry = OpLabel
175fd4e5da5Sopenharmony_ci%derivative = OpDPdy %float4 %undef
176fd4e5da5Sopenharmony_ciOpReturn
177fd4e5da5Sopenharmony_ciOpFunctionEnd
178fd4e5da5Sopenharmony_ci)";
179fd4e5da5Sopenharmony_ci
180fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
181fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
182fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
183fd4e5da5Sopenharmony_ci              HasSubstr("Derivative instructions require "
184fd4e5da5Sopenharmony_ci                        "DerivativeGroupQuadsNV or DerivativeGroupLinearNV "
185fd4e5da5Sopenharmony_ci                        "execution mode for GLCompute execution model"));
186fd4e5da5Sopenharmony_ci}
187fd4e5da5Sopenharmony_ci
188fd4e5da5Sopenharmony_ciusing ValidateHalfDerivatives = spvtest::ValidateBase<std::string>;
189fd4e5da5Sopenharmony_ci
190fd4e5da5Sopenharmony_ciTEST_P(ValidateHalfDerivatives, ScalarFailure) {
191fd4e5da5Sopenharmony_ci  const std::string op = GetParam();
192fd4e5da5Sopenharmony_ci  const std::string body = "%val = " + op + " %f16 %f16_0\n";
193fd4e5da5Sopenharmony_ci
194fd4e5da5Sopenharmony_ci  CompileSuccessfully(
195fd4e5da5Sopenharmony_ci      GenerateShaderCode(body, "OpCapability Float16\n").c_str());
196fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
197fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
198fd4e5da5Sopenharmony_ci              HasSubstr("Result type component width must be 32 bits"));
199fd4e5da5Sopenharmony_ci}
200fd4e5da5Sopenharmony_ci
201fd4e5da5Sopenharmony_ciTEST_P(ValidateHalfDerivatives, VectorFailure) {
202fd4e5da5Sopenharmony_ci  const std::string op = GetParam();
203fd4e5da5Sopenharmony_ci  const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n";
204fd4e5da5Sopenharmony_ci
205fd4e5da5Sopenharmony_ci  CompileSuccessfully(
206fd4e5da5Sopenharmony_ci      GenerateShaderCode(body, "OpCapability Float16\n").c_str());
207fd4e5da5Sopenharmony_ci  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
208fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
209fd4e5da5Sopenharmony_ci              HasSubstr("Result type component width must be 32 bits"));
210fd4e5da5Sopenharmony_ci}
211fd4e5da5Sopenharmony_ci
212fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives,
213fd4e5da5Sopenharmony_ci                         ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth",
214fd4e5da5Sopenharmony_ci                                           "OpDPdxFine", "OpDPdyFine",
215fd4e5da5Sopenharmony_ci                                           "OpFwidthFine", "OpDPdxCoarse",
216fd4e5da5Sopenharmony_ci                                           "OpDPdyCoarse", "OpFwidthCoarse"));
217fd4e5da5Sopenharmony_ci
218fd4e5da5Sopenharmony_ci}  // namespace
219fd4e5da5Sopenharmony_ci}  // namespace val
220fd4e5da5Sopenharmony_ci}  // namespace spvtools
221