* update spirv-cross to a0fba56 * update spirv-tools to v2026.1 * update spirv-headers to 04f10f6 * update glslang to 16.2.0
2457 lines
76 KiB
C++
2457 lines
76 KiB
C++
// Copyright (c) 2025 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "test/unit_spirv.h"
|
|
#include "test/val/val_fixtures.h"
|
|
|
|
namespace spvtools {
|
|
namespace val {
|
|
namespace {
|
|
|
|
using ::testing::Combine;
|
|
using ::testing::Eq;
|
|
using ::testing::HasSubstr;
|
|
using ::testing::Values;
|
|
using ::testing::ValuesIn;
|
|
|
|
using ValidateLogicalPointersTest = spvtest::ValidateBase<bool>;
|
|
|
|
enum class MatrixTrace : uint32_t {
|
|
kNotAMatrix,
|
|
kColumn,
|
|
kComponent,
|
|
};
|
|
|
|
const MatrixTrace traces[] = {MatrixTrace::kNotAMatrix, MatrixTrace::kColumn,
|
|
MatrixTrace::kComponent};
|
|
|
|
using MatrixTraceTypedTest = spvtest::ValidateBase<MatrixTrace>;
|
|
|
|
TEST_P(MatrixTraceTypedTest, PhiLoopOp1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpBranch %loop
|
|
%loop = OpLabel
|
|
%phi = OpPhi )" + type + R"( %gep %entry %copy %continue
|
|
OpLoopMerge %merge %continue None
|
|
OpBranchConditional %bool_cond %merge %continue
|
|
%continue = OpLabel
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %phi
|
|
OpBranch %loop
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, PhiLoopOp2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpBranch %loop
|
|
%loop = OpLabel
|
|
%phi = OpPhi )" + type + R"( %copy %continue %gep %entry
|
|
OpLoopMerge %merge %continue None
|
|
OpBranchConditional %bool_cond %merge %continue
|
|
%continue = OpLabel
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %phi
|
|
OpBranch %loop
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, SelectOp1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %gep
|
|
%sel = OpSelect )" + type + R"( %bool_cond %copy %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, SelectOp2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %gep
|
|
%sel = OpSelect )" + type + R"( %bool_cond %null %copy
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionVariable) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type, ld_type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_func_wg_v2float";
|
|
ld_type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_func_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_func_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_mat2x2 = OpTypePointer Workgroup %mat2x2
|
|
%ptr_func_wg_float = OpTypePointer Function %ptr_wg_float
|
|
%ptr_func_wg_v2float = OpTypePointer Function %ptr_wg_v2float
|
|
%var_mat2x2 = OpVariable %ptr_wg_mat2x2 Workgroup
|
|
%var_float = OpVariable %ptr_wg_float Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%func_var = OpVariable )" + type +
|
|
R"( Function
|
|
%gep = )" + gep + R"(
|
|
OpStore %func_var %gep
|
|
%ld = OpLoad )" + ld_type + R"( %func_var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, PrivateVariable) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type, ld_type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_priv_wg_v2float";
|
|
ld_type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_priv_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_priv_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_mat2x2 = OpTypePointer Workgroup %mat2x2
|
|
%ptr_priv_wg_float = OpTypePointer Private %ptr_wg_float
|
|
%ptr_priv_wg_v2float = OpTypePointer Private %ptr_wg_v2float
|
|
%var_mat2x2 = OpVariable %ptr_wg_mat2x2 Workgroup
|
|
%var_float = OpVariable %ptr_wg_float Workgroup
|
|
%priv_var = OpVariable )" + type +
|
|
R"( Private
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpStore %priv_var %gep
|
|
%ld = OpLoad )" + ld_type + R"( %priv_var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionVariableAggregate) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, var_type, gep_type, ld_type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
var_type = "%ptr_func_wg_struct_v2float";
|
|
gep_type = "%ptr_func_wg_v2float";
|
|
ld_type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
var_type = "%ptr_func_wg_struct_float";
|
|
gep_type = "%ptr_func_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
var_type = "%ptr_func_wg_struct_float";
|
|
gep_type = "%ptr_func_wg_float";
|
|
ld_type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_mat2x2 = OpTypePointer Workgroup %mat2x2
|
|
%func_array_float = OpTypeArray %ptr_wg_float %int_1
|
|
%func_array_v2float = OpTypeArray %ptr_wg_v2float %int_1
|
|
%func_struct_float = OpTypeStruct %func_array_float
|
|
%func_struct_v2float = OpTypeStruct %func_array_v2float
|
|
%ptr_func_wg_struct_float = OpTypePointer Function %func_struct_float
|
|
%ptr_func_wg_struct_v2float = OpTypePointer Function %func_struct_v2float
|
|
%ptr_func_wg_float = OpTypePointer Function %ptr_wg_float
|
|
%ptr_func_wg_v2float = OpTypePointer Function %ptr_wg_v2float
|
|
%var_mat2x2 = OpVariable %ptr_wg_mat2x2 Workgroup
|
|
%var_float = OpVariable %ptr_wg_float Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%func_var = OpVariable )" + var_type +
|
|
R"( Function
|
|
%gep = )" + gep + R"(
|
|
%store_gep = OpAccessChain )" +
|
|
gep_type + R"( %func_var %int_0 %index
|
|
%store_gep_copy = OpCopyObject )" +
|
|
gep_type + R"( %store_gep
|
|
OpStore %store_gep_copy %gep
|
|
%ld_gep = OpAccessChain )" + gep_type +
|
|
R"( %func_var %int_0 %index
|
|
%ld = OpLoad )" + ld_type + R"( %ld_gep
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionCallParam1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_fn = OpTypeFunction %void )" +
|
|
type + R"( %bool
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %gep
|
|
%call = OpFunctionCall %void %foo %copy %bool_cond
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %void None %foo_fn
|
|
%ptr_param = OpFunctionParameter )" +
|
|
type + R"(
|
|
%bool_param = OpFunctionParameter %bool
|
|
%foo_entry = OpLabel
|
|
%sel = OpSelect )" + type + R"( %bool_param %ptr_param %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionCallParam2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_fn = OpTypeFunction %void %bool )" +
|
|
type + R"(
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject )" + type +
|
|
R"( %gep
|
|
%call = OpFunctionCall %void %foo %bool_cond %copy
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %void None %foo_fn
|
|
%bool_param = OpFunctionParameter %bool
|
|
%ptr_param = OpFunctionParameter )" +
|
|
type + R"(
|
|
%foo_entry = OpLabel
|
|
%sel = OpSelect )" + type + R"( %bool_param %ptr_param %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionCall) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction )" +
|
|
type + R"(
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall )" + type +
|
|
R"( %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction )" + type +
|
|
R"( None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpReturnValue %gep
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionCallMultiReturn1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction )" +
|
|
type + R"(
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall )" + type +
|
|
R"( %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction )" + type +
|
|
R"( None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpReturnValue %gep
|
|
%merge = OpLabel
|
|
OpReturnValue %null
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceTypedTest, FunctionCallMultiReturn2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep, type;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
type = "%ptr_wg_v2float";
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
type = "%ptr_wg_float";
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull )" + type +
|
|
R"(
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction )" +
|
|
type + R"(
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall )" + type +
|
|
R"( %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction )" + type +
|
|
R"( None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpReturnValue %null
|
|
%merge = OpLabel
|
|
OpReturnValue %gep
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ValidateLogicalPointersMatrixTraceTyped,
|
|
MatrixTraceTypedTest, ValuesIn(traces));
|
|
|
|
using MatrixTraceUntypedTest = spvtest::ValidateBase<MatrixTrace>;
|
|
|
|
TEST_P(MatrixTraceUntypedTest, PhiLoopOp1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpBranch %loop
|
|
%loop = OpLabel
|
|
%phi = OpPhi %ptr_wg %gep %entry %copy %continue
|
|
OpLoopMerge %merge %continue None
|
|
OpBranchConditional %bool_cond %merge %continue
|
|
%continue = OpLabel
|
|
%copy = OpCopyObject %ptr_wg %phi
|
|
OpBranch %loop
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
TEST_P(MatrixTraceUntypedTest, PhiLoopOp2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpBranch %loop
|
|
%loop = OpLabel
|
|
%phi = OpPhi %ptr_wg %copy %continue %gep %entry
|
|
OpLoopMerge %merge %continue None
|
|
OpBranchConditional %bool_cond %merge %continue
|
|
%continue = OpLabel
|
|
%copy = OpCopyObject %ptr_wg %phi
|
|
OpBranch %loop
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, SelectOp1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject %ptr_wg %gep
|
|
%sel = OpSelect %ptr_wg %bool_cond %copy %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, SelectOp2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject %ptr_wg %gep
|
|
%sel = OpSelect %ptr_wg %bool_cond %null %copy
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionVariable) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%ptr_func_wg = OpTypePointer Function %ptr_wg
|
|
%var_mat2x2 = OpUntypedVariableKHR %ptr_wg Workgroup %mat2x2
|
|
%var_float = OpUntypedVariableKHR %ptr_wg Workgroup %float
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%func_var = OpVariable %ptr_func_wg Function
|
|
%gep = )" + gep + R"(
|
|
OpStore %func_var %gep
|
|
%ld = OpLoad %ptr_wg %func_var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, PrivateVariable) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%ptr_priv_wg = OpTypePointer Private %ptr_wg
|
|
%var_mat2x2 = OpUntypedVariableKHR %ptr_wg Workgroup %mat2x2
|
|
%var_float = OpUntypedVariableKHR %ptr_wg Workgroup %float
|
|
%priv_var = OpVariable %ptr_priv_wg Private
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpStore %priv_var %gep
|
|
%ld = OpLoad %ptr_wg %priv_var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionVariableAggregate) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %mat2x2 %var_mat2x2 %index %index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %float %var_float";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%func_array = OpTypeArray %ptr_wg %int_1
|
|
%func_struct = OpTypeStruct %func_array
|
|
%ptr_func_wg_struct = OpTypePointer Function %func_struct
|
|
%ptr_func_wg = OpTypePointer Function %ptr_wg
|
|
%var_mat2x2 = OpUntypedVariableKHR %ptr_wg Workgroup %mat2x2
|
|
%var_float = OpUntypedVariableKHR %ptr_wg Workgroup %float
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%func_var = OpVariable %ptr_func_wg_struct Function
|
|
%gep = )" + gep + R"(
|
|
%store_gep = OpAccessChain %ptr_func_wg %func_var %int_0 %index
|
|
%store_gep_copy = OpCopyObject %ptr_func_wg %store_gep
|
|
OpStore %store_gep_copy %gep
|
|
%ld_gep = OpAccessChain %ptr_func_wg %func_var %int_0 %index
|
|
%ld = OpLoad %ptr_wg %ld_gep
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionCallParam1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_fn = OpTypeFunction %void %ptr_wg %bool
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject %ptr_wg %gep
|
|
%call = OpFunctionCall %void %foo %copy %bool_cond
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %void None %foo_fn
|
|
%ptr_param = OpFunctionParameter %ptr_wg
|
|
%bool_param = OpFunctionParameter %bool
|
|
%foo_entry = OpLabel
|
|
%sel = OpSelect %ptr_wg %bool_param %ptr_param %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionCallParam2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_fn = OpTypeFunction %void %bool %ptr_wg
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpCopyObject %ptr_wg %gep
|
|
%call = OpFunctionCall %void %foo %bool_cond %copy
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %void None %foo_fn
|
|
%bool_param = OpFunctionParameter %bool
|
|
%ptr_param = OpFunctionParameter %ptr_wg
|
|
%foo_entry = OpLabel
|
|
%sel = OpSelect %ptr_wg %bool_param %ptr_param %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionCall) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction %ptr_wg
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %ptr_wg %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %ptr_wg None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpReturnValue %gep
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionCallMultiReturn1) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction %ptr_wg
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %ptr_wg %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %ptr_wg None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpReturnValue %gep
|
|
%merge = OpLabel
|
|
OpReturnValue %null
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, FunctionCallMultiReturn2) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep =
|
|
"OpUntypedAccessChainKHR %ptr_wg %struct %var %int_0 %index %index "
|
|
"%index";
|
|
break;
|
|
default:
|
|
gep = "OpUntypedAccessChainKHR %ptr_wg %struct %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpUntypedVariableKHR %ptr_wg Workgroup %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%foo_ty = OpTypeFunction %ptr_wg
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%call = OpFunctionCall %ptr_wg %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %ptr_wg None %foo_ty
|
|
%foo_entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpReturnValue %null
|
|
%merge = OpLabel
|
|
OpReturnValue %gep
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
TEST_P(MatrixTraceUntypedTest, MixedTypes) {
|
|
const auto trace_type = GetParam();
|
|
std::string gep;
|
|
switch (trace_type) {
|
|
case MatrixTrace::kColumn:
|
|
gep = "OpAccessChain %ptr_wg_v2float %var %int_0 %index %index";
|
|
break;
|
|
case MatrixTrace::kComponent:
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_0 %index %index %index";
|
|
break;
|
|
default:
|
|
gep = "OpAccessChain %ptr_wg_float %var %int_1";
|
|
break;
|
|
}
|
|
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%index = OpUndef %int
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%array = OpTypeArray %mat2x2 %int_2
|
|
%struct = OpTypeStruct %array %float
|
|
%ptr_wg = OpTypeUntypedPointerKHR Workgroup
|
|
%ptr_wg_struct = OpTypePointer Workgroup %struct
|
|
%ptr_wg_v2float = OpTypePointer Workgroup %v2float
|
|
%ptr_wg_float = OpTypePointer Workgroup %float
|
|
%null = OpConstantNull %ptr_wg
|
|
%var = OpVariable %ptr_wg_struct Workgroup
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = )" + gep + R"(
|
|
%copy = OpUntypedAccessChainKHR %ptr_wg %struct %gep
|
|
%sel = OpSelect %ptr_wg %bool_cond %copy %null
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const auto expected = trace_type == MatrixTrace::kNotAMatrix
|
|
? SPV_SUCCESS
|
|
: SPV_ERROR_INVALID_DATA;
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(expected, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
if (expected) {
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to a column or a "
|
|
"component of a column of a matrix"));
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ValidateLogicalPointersMatrixTraceUntyped,
|
|
MatrixTraceUntypedTest, ValuesIn(traces));
|
|
|
|
TEST_F(ValidateLogicalPointersTest, SelectDifferentBuffersTyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %int
|
|
%ptr_struct = OpTypePointer StorageBuffer %struct
|
|
%v1 = OpVariable %ptr_struct StorageBuffer
|
|
%v2 = OpVariable %ptr_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%select = OpSelect %ptr_struct %bool_cond %v1 %v2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointers must point into the same structure "
|
|
"(or OpConstantNull)"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, SelectDifferentBuffersUntyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpCapability Shader
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %int
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%v1 = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%v2 = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%select = OpSelect %ptr %bool_cond %v1 %v2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointers must point into the same structure "
|
|
"(or OpConstantNull)"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, PhiDifferentBuffersTyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %int
|
|
%ptr_struct = OpTypePointer StorageBuffer %struct
|
|
%v1 = OpVariable %ptr_struct StorageBuffer
|
|
%v2 = OpVariable %ptr_struct StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpBranch %merge
|
|
%merge = OpLabel
|
|
%phi = OpPhi %ptr_struct %v1 %entry %v2 %then
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointers must point into the same structure "
|
|
"(or OpConstantNull)"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, PhiDifferentBuffersUntyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpCapability Shader
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%int = OpTypeInt 32 0
|
|
%struct = OpTypeStruct %int
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%v1 = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%v2 = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpSelectionMerge %merge None
|
|
OpBranchConditional %bool_cond %then %merge
|
|
%then = OpLabel
|
|
OpBranch %merge
|
|
%merge = OpLabel
|
|
%phi = OpPhi %ptr %v1 %entry %v2 %then
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointers must point into the same structure "
|
|
"(or OpConstantNull)"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, BlockArrayTyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_4 = OpConstant %int 4
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%struct = OpTypeStruct %int
|
|
%array = OpTypeArray %struct %int_4
|
|
%ptr_array = OpTypePointer StorageBuffer %array
|
|
%ptr_int = OpTypePointer StorageBuffer %int
|
|
%var = OpVariable %ptr_array StorageBuffer
|
|
%null = OpConstantNull %ptr_array
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%select = OpSelect %ptr_array %bool_cond %null %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to an array of Block- "
|
|
"or BufferBlock-decorated structs"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, BlockArrayUntyped) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %struct Block
|
|
OpMemberDecorate %struct 0 Offset 0
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_4 = OpConstant %int 4
|
|
%bool = OpTypeBool
|
|
%bool_cond = OpUndef %bool
|
|
%struct = OpTypeStruct %int
|
|
%array = OpTypeArray %struct %int_4
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %array
|
|
%null = OpConstantNull %ptr
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%select = OpSelect %ptr %bool_cond %null %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to an array of Block- "
|
|
"or BufferBlock-decorated structs"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, UntypedMatrixLoad) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%struct = OpTypeStruct %mat2x2
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%ld = OpLoad %struct %var
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, UntypedMatrixLoadVariablePointer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%struct = OpTypeStruct %mat2x2
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%null = OpConstantNull %ptr
|
|
%bool = OpTypeBool
|
|
%cond = OpUndef %bool
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%sel = OpSelect %ptr %cond %var %null
|
|
%ld = OpLoad %struct %sel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to an object that is "
|
|
"or contains a matrix"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, UntypedMatrixStore) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%zero = OpConstantNull %mat2x2
|
|
%struct = OpTypeStruct %mat2x2
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpStore %var %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, UntypedMatrixStoreVariablePointer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%v2float = OpTypeVector %float 2
|
|
%mat2x2 = OpTypeMatrix %v2float 2
|
|
%zero = OpConstantNull %mat2x2
|
|
%struct = OpTypeStruct %mat2x2
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%null = OpConstantNull %ptr
|
|
%bool = OpTypeBool
|
|
%cond = OpUndef %bool
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%sel = OpSelect %ptr %cond %var %null
|
|
OpStore %sel %zero
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Variable pointer must not point to an object that is "
|
|
"or contains a matrix"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, LogicalPointerOperandFailure) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Kernel
|
|
OpCapability Addresses
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%v2int = OpTypeVector %int 2
|
|
%ptr_v2int = OpTypePointer StorageBuffer %v2int
|
|
%var = OpVariable %ptr_v2int StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = OpInBoundsPtrAccessChain %ptr_v2int %var %int_0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Instruction may not have a logical pointer operand"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest,
|
|
LogicalPointerOperandVariablePointerStorageBuffer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability Addresses
|
|
OpMemoryModel Logical GLSL450
|
|
OpDecorate %ptr_int ArrayStride 4
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_4 = OpConstant %int 4
|
|
%array = OpTypeArray %int %int_4
|
|
%ptr_array = OpTypePointer StorageBuffer %array
|
|
%ptr_int = OpTypePointer StorageBuffer %int
|
|
%var = OpVariable %ptr_array StorageBuffer
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%foo = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = OpAccessChain %ptr_int %var %int_0
|
|
%ptr_gep = OpPtrAccessChain %ptr_int %gep %int_0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Instruction may only have a logical pointer operand in the "
|
|
"StorageBuffer or "
|
|
"Workgroup storage classes with appropriate variable pointers "
|
|
"capability"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest,
|
|
LogicalPointerOperandVariablePointerWorkgroup) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpMemoryModel Logical GLSL450
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%int_4 = OpConstant %int 4
|
|
%array = OpTypeArray %int %int_4
|
|
%ptr_array = OpTypePointer Workgroup %array
|
|
%ptr_int = OpTypePointer Workgroup %int
|
|
%var = OpVariable %ptr_array Workgroup
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%foo = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%gep = OpAccessChain %ptr_int %var %int_0
|
|
%ptr_gep = OpPtrAccessChain %ptr_int %gep %int_0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Instruction may only have a logical pointer operand in the "
|
|
"StorageBuffer or "
|
|
"Workgroup storage classes with appropriate variable pointers "
|
|
"capability"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest,
|
|
LogicalPointerReturnVariablePointerStorageBuffer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
%int = OpTypeInt 32 0
|
|
%ptr = OpTypePointer StorageBuffer %int
|
|
%null = OpConstantNull %ptr
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Instruction may only return a logical pointer in the "
|
|
"StorageBuffer or "
|
|
"Workgroup storage classes with appropriate variable pointers "
|
|
"capability"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest,
|
|
LogicalPointerReturnVariablePointerWorkgroup) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpMemoryModel Logical GLSL450
|
|
%int = OpTypeInt 32 0
|
|
%ptr = OpTypePointer Workgroup %int
|
|
%null = OpConstantNull %ptr
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(
|
|
getDiagnosticString(),
|
|
HasSubstr("Instruction may only return a logical pointer in the "
|
|
"StorageBuffer or "
|
|
"Workgroup storage classes with appropriate variable pointers "
|
|
"capability"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, ArrayLengthInvalidVariablePointer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%array = OpTypeRuntimeArray %int
|
|
%struct = OpTypeStruct %array
|
|
%ptr = OpTypePointer StorageBuffer %struct
|
|
%var = OpVariable %ptr StorageBuffer
|
|
%null = OpConstantNull %ptr
|
|
%bool = OpTypeBool
|
|
%cond = OpUndef %bool
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%sel = OpSelect %ptr %cond %null %var
|
|
%len = OpArrayLength %int %sel 0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Pointer operand must not be a variable pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, ArrayLengthUntypedInvalidVariablePointer) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpCapability VariablePointers
|
|
OpCapability UntypedPointersKHR
|
|
OpExtension "SPV_KHR_untyped_pointers"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%array = OpTypeRuntimeArray %int
|
|
%struct = OpTypeStruct %array
|
|
%ptr = OpTypeUntypedPointerKHR StorageBuffer
|
|
%var = OpUntypedVariableKHR %ptr StorageBuffer %struct
|
|
%null = OpConstantNull %ptr
|
|
%bool = OpTypeBool
|
|
%cond = OpUndef %bool
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%sel = OpSelect %ptr %cond %null %var
|
|
%len = OpUntypedArrayLengthKHR %int %struct %sel 0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
|
EXPECT_THAT(getDiagnosticString(),
|
|
HasSubstr("Pointer operand must not be a variable pointer"));
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, FunctionParameterOperandOfFunctionCall) {
|
|
const std::string spirv = R"(
|
|
OpCapability ClipDistance
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 " "
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%32 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%35 = OpTypeFunction %float %_ptr_Function_float
|
|
%float_1_35631564en19 = OpConstant %float 1.35631564e-19
|
|
%float_1_35631564en19_0 = OpConstant %float 1.35631564e-19
|
|
%2 = OpFunction %void None %32
|
|
%8447 = OpLabel
|
|
OpUnreachable
|
|
OpFunctionEnd
|
|
%9 = OpFunction %float None %35
|
|
%10 = OpFunctionParameter %_ptr_Function_float
|
|
%65535 = OpLabel
|
|
%217 = OpVariable %_ptr_Function_float Function
|
|
%218 = OpLoad %float %10
|
|
%2097407 = OpFunctionCall %float %9 %10
|
|
%231 = OpLoad %float %217
|
|
%232 = OpFDiv %float %218 %231
|
|
%233 = OpExtInst %float %1 SmoothStep %float_1_35631564en19 %float_1_35631564en19_0 %232
|
|
OpReturnValue %233
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
TEST_F(ValidateLogicalPointersTest, RecursiveCalls) {
|
|
const std::string spirv = R"(
|
|
OpCapability ClipDistance
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 " "
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%32 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%35 = OpTypeFunction %float %_ptr_Function_float
|
|
%float_1_35631564en19 = OpConstant %float 1.35631564e-19
|
|
%float_1_35631564en19_0 = OpConstant %float 1.35631564e-19
|
|
%2 = OpFunction %void None %32
|
|
%8447 = OpLabel
|
|
OpUnreachable
|
|
OpFunctionEnd
|
|
%9 = OpFunction %float None %35
|
|
%10 = OpFunctionParameter %_ptr_Function_float
|
|
%65535 = OpLabel
|
|
%217 = OpVariable %_ptr_Function_float Function
|
|
%218 = OpLoad %float %10
|
|
%2097407 = OpFunctionCall %float %20 %10
|
|
%231 = OpLoad %float %217
|
|
%232 = OpFDiv %float %218 %231
|
|
%233 = OpExtInst %float %1 SmoothStep %float_1_35631564en19 %float_1_35631564en19_0 %232
|
|
OpReturnValue %233
|
|
OpFunctionEnd
|
|
%20 = OpFunction %float None %35
|
|
%21 = OpFunctionParameter %_ptr_Function_float
|
|
%22 = OpLabel
|
|
%23 = OpFunctionCall %float %9 %21
|
|
OpReturnValue %float_1_35631564en19
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
CompileSuccessfully(spirv);
|
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace val
|
|
} // namespace spvtools
|