mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-06 22:53:35 +00:00
Rename StorageClass to AddressSpace.
This CL updates the internals to use AddressSpace instead of the old StorageClass name. Bug: tint:1404 Change-Id: Iecc208e839453437f4d630f65e0152206a52db7e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/104420 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
d5b64ecd78
commit
ff7cf21021
@ -63,7 +63,7 @@ Quoting single word identifiers or keywords from the source is not discouraged.
|
|||||||
**Don't:**
|
**Don't:**
|
||||||
|
|
||||||
```
|
```
|
||||||
shader.wgsl:5:11 error: type cannot be used in storage class 'storage' as it is non-host-shareable
|
shader.wgsl:5:11 error: type cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
|
|
||||||
cond : bool;
|
cond : bool;
|
||||||
^^^^
|
^^^^
|
||||||
@ -72,7 +72,7 @@ shader.wgsl:5:11 error: type cannot be used in storage class 'storage' as it is
|
|||||||
**Do:**
|
**Do:**
|
||||||
|
|
||||||
```
|
```
|
||||||
shader.wgsl:5:11 error: type cannot be used in storage class 'storage' as it is non-host-shareable
|
shader.wgsl:5:11 error: type cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
|
|
||||||
cond : bool;
|
cond : bool;
|
||||||
^^^^
|
^^^^
|
||||||
|
@ -12,7 +12,7 @@ Specification work in the WebGPU group hasn't started.
|
|||||||
|
|
||||||
## Pseudo-specification
|
## Pseudo-specification
|
||||||
|
|
||||||
This extension adds a new `push_constant` storage class that's only allowed on global variable declarations.
|
This extension adds a new `push_constant` address space that's only allowed on global variable declarations.
|
||||||
Push constant variables must only contain 32bit data types (or aggregates of such types).
|
Push constant variables must only contain 32bit data types (or aggregates of such types).
|
||||||
Push constant variable declarations must not have an initializer.
|
Push constant variable declarations must not have an initializer.
|
||||||
It is an error for a entry point to statically use more than one `push_constant` variable.
|
It is an error for a entry point to statically use more than one `push_constant` variable.
|
||||||
|
@ -15,7 +15,7 @@ as variables at module scope.
|
|||||||
## Vulkan SPIR-V today
|
## Vulkan SPIR-V today
|
||||||
|
|
||||||
SPIR-V for Vulkan models inputs and outputs as module-scope variables in
|
SPIR-V for Vulkan models inputs and outputs as module-scope variables in
|
||||||
the Input and Output storage classes, respectively.
|
the Input and Output address spaces, respectively.
|
||||||
|
|
||||||
The `OpEntryPoint` instruction has a list of module-scope variables that must
|
The `OpEntryPoint` instruction has a list of module-scope variables that must
|
||||||
be a superset of all the input and output variables that are statically
|
be a superset of all the input and output variables that are statically
|
||||||
|
@ -141,7 +141,7 @@ TODO(dsinclair): Nested if's
|
|||||||
## SPIR-V
|
## SPIR-V
|
||||||
TODO(dsinclair): Nested if's
|
TODO(dsinclair): Nested if's
|
||||||
|
|
||||||
# Storage classes
|
# Address spaces
|
||||||
TODO(dsinclair): do ...
|
TODO(dsinclair): do ...
|
||||||
|
|
||||||
# Storage buffers
|
# Storage buffers
|
||||||
@ -155,7 +155,7 @@ TODO(dsinclair): Rewrite with bools
|
|||||||
## MSL
|
## MSL
|
||||||
TODO(dsinclair): Rewrite with bools
|
TODO(dsinclair): Rewrite with bools
|
||||||
|
|
||||||
# Input / Output storage class
|
# Input / Output address spaces
|
||||||
## HLSL
|
## HLSL
|
||||||
TODO(dsinclair): Structs and params
|
TODO(dsinclair): Structs and params
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ ResultOrError<ComputePipelineBase*> GetOrCreateIndirectDispatchValidationPipelin
|
|||||||
|
|
||||||
// TODO(https://crbug.com/dawn/1108): Propagate validation feedback from this
|
// TODO(https://crbug.com/dawn/1108): Propagate validation feedback from this
|
||||||
// shader in various failure modes.
|
// shader in various failure modes.
|
||||||
// Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable.
|
// Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable.
|
||||||
Ref<ShaderModuleBase> shaderModule;
|
Ref<ShaderModuleBase> shaderModule;
|
||||||
DAWN_TRY_ASSIGN(shaderModule, utils::CreateShaderModule(device, R"(
|
DAWN_TRY_ASSIGN(shaderModule, utils::CreateShaderModule(device, R"(
|
||||||
struct UniformParams {
|
struct UniformParams {
|
||||||
@ -258,7 +258,7 @@ ComputePassEncoder::TransformIndirectDispatchBuffer(Ref<BufferBase> indirectBuff
|
|||||||
kDispatchIndirectSize + clientOffsetFromAlignedBoundary;
|
kDispatchIndirectSize + clientOffsetFromAlignedBoundary;
|
||||||
|
|
||||||
// Neither 'enableValidation' nor 'duplicateNumWorkgroups' can be declared as 'bool' as
|
// Neither 'enableValidation' nor 'duplicateNumWorkgroups' can be declared as 'bool' as
|
||||||
// currently in WGSL type 'bool' cannot be used in storage class 'uniform' as 'it is
|
// currently in WGSL type 'bool' cannot be used in address space 'uniform' as 'it is
|
||||||
// non-host-shareable'.
|
// non-host-shareable'.
|
||||||
struct UniformParams {
|
struct UniformParams {
|
||||||
uint32_t maxComputeWorkgroupsPerDimension;
|
uint32_t maxComputeWorkgroupsPerDimension;
|
||||||
|
@ -34,18 +34,18 @@ std::string ReplaceAll(std::string str, const std::string& substr, const std::st
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageClass is an enumerator of storage classes used by ComputeLayoutMemoryBufferTests.Fields
|
// AddressSpace is an enumerator of address spaces used by ComputeLayoutMemoryBufferTests.Fields
|
||||||
enum class StorageClass {
|
enum class AddressSpace {
|
||||||
Uniform,
|
Uniform,
|
||||||
Storage,
|
Storage,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, StorageClass storageClass) {
|
std::ostream& operator<<(std::ostream& o, AddressSpace addressSpace) {
|
||||||
switch (storageClass) {
|
switch (addressSpace) {
|
||||||
case StorageClass::Uniform:
|
case AddressSpace::Uniform:
|
||||||
o << "uniform";
|
o << "uniform";
|
||||||
break;
|
break;
|
||||||
case StorageClass::Storage:
|
case AddressSpace::Storage:
|
||||||
o << "storage";
|
o << "storage";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -441,7 +441,7 @@ void RunComputeShaderWithBuffers(const wgpu::Device& device,
|
|||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_TEST_PARAM_STRUCT(ComputeLayoutMemoryBufferTestParams, StorageClass, Field);
|
DAWN_TEST_PARAM_STRUCT(ComputeLayoutMemoryBufferTestParams, AddressSpace, Field);
|
||||||
|
|
||||||
class ComputeLayoutMemoryBufferTests
|
class ComputeLayoutMemoryBufferTests
|
||||||
: public DawnTestWithParams<ComputeLayoutMemoryBufferTestParams> {
|
: public DawnTestWithParams<ComputeLayoutMemoryBufferTestParams> {
|
||||||
@ -472,7 +472,7 @@ TEST_P(ComputeLayoutMemoryBufferTests, StructMember) {
|
|||||||
|
|
||||||
const Field& field = GetParam().mField;
|
const Field& field = GetParam().mField;
|
||||||
|
|
||||||
const bool isUniform = GetParam().mStorageClass == StorageClass::Uniform;
|
const bool isUniform = GetParam().mAddressSpace == AddressSpace::Uniform;
|
||||||
|
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
struct Data {
|
struct Data {
|
||||||
@ -619,7 +619,7 @@ TEST_P(ComputeLayoutMemoryBufferTests, NonStructMember) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool isUniform = GetParam().mStorageClass == StorageClass::Uniform;
|
const bool isUniform = GetParam().mAddressSpace == AddressSpace::Uniform;
|
||||||
|
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
@group(0) @binding(0) var<{input_qualifiers}> input : {field_type};
|
@group(0) @binding(0) var<{input_qualifiers}> input : {field_type};
|
||||||
@ -685,7 +685,7 @@ auto GenerateParams() {
|
|||||||
OpenGLBackend(),
|
OpenGLBackend(),
|
||||||
OpenGLESBackend(),
|
OpenGLESBackend(),
|
||||||
},
|
},
|
||||||
{StorageClass::Storage, StorageClass::Uniform},
|
{AddressSpace::Storage, AddressSpace::Uniform},
|
||||||
{
|
{
|
||||||
// See https://www.w3.org/TR/WGSL/#alignment-and-size
|
// See https://www.w3.org/TR/WGSL/#alignment-and-size
|
||||||
// Scalar types with no custom alignment or size
|
// Scalar types with no custom alignment or size
|
||||||
@ -851,7 +851,7 @@ auto GenerateParams() {
|
|||||||
|
|
||||||
std::vector<ComputeLayoutMemoryBufferTestParams> filtered;
|
std::vector<ComputeLayoutMemoryBufferTestParams> filtered;
|
||||||
for (auto param : params) {
|
for (auto param : params) {
|
||||||
if (param.mStorageClass != StorageClass::Storage && param.mField.IsStorageBufferOnly()) {
|
if (param.mAddressSpace != AddressSpace::Storage && param.mField.IsStorageBufferOnly()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
filtered.emplace_back(param);
|
filtered.emplace_back(param);
|
||||||
|
@ -180,6 +180,8 @@ libtint_source_set("libtint_core_all_src") {
|
|||||||
sources = [
|
sources = [
|
||||||
"ast/access.cc",
|
"ast/access.cc",
|
||||||
"ast/access.h",
|
"ast/access.h",
|
||||||
|
"ast/address_space.cc",
|
||||||
|
"ast/address_space.h",
|
||||||
"ast/alias.cc",
|
"ast/alias.cc",
|
||||||
"ast/alias.h",
|
"ast/alias.h",
|
||||||
"ast/array.cc",
|
"ast/array.cc",
|
||||||
@ -312,8 +314,6 @@ libtint_source_set("libtint_core_all_src") {
|
|||||||
"ast/statement.h",
|
"ast/statement.h",
|
||||||
"ast/static_assert.cc",
|
"ast/static_assert.cc",
|
||||||
"ast/static_assert.h",
|
"ast/static_assert.h",
|
||||||
"ast/storage_class.cc",
|
|
||||||
"ast/storage_class.h",
|
|
||||||
"ast/storage_texture.cc",
|
"ast/storage_texture.cc",
|
||||||
"ast/storage_texture.h",
|
"ast/storage_texture.h",
|
||||||
"ast/stride_attribute.cc",
|
"ast/stride_attribute.cc",
|
||||||
@ -998,6 +998,7 @@ if (tint_build_unittests) {
|
|||||||
|
|
||||||
tint_unittests_source_set("tint_unittests_ast_src") {
|
tint_unittests_source_set("tint_unittests_ast_src") {
|
||||||
sources = [
|
sources = [
|
||||||
|
"ast/address_space_test.cc",
|
||||||
"ast/alias_test.cc",
|
"ast/alias_test.cc",
|
||||||
"ast/array_test.cc",
|
"ast/array_test.cc",
|
||||||
"ast/assignment_statement_test.cc",
|
"ast/assignment_statement_test.cc",
|
||||||
@ -1054,7 +1055,6 @@ if (tint_build_unittests) {
|
|||||||
"ast/sampler_test.cc",
|
"ast/sampler_test.cc",
|
||||||
"ast/stage_attribute_test.cc",
|
"ast/stage_attribute_test.cc",
|
||||||
"ast/static_assert_test.cc",
|
"ast/static_assert_test.cc",
|
||||||
"ast/storage_class_test.cc",
|
|
||||||
"ast/storage_texture_test.cc",
|
"ast/storage_texture_test.cc",
|
||||||
"ast/stride_attribute_test.cc",
|
"ast/stride_attribute_test.cc",
|
||||||
"ast/struct_member_align_attribute_test.cc",
|
"ast/struct_member_align_attribute_test.cc",
|
||||||
@ -1097,6 +1097,8 @@ if (tint_build_unittests) {
|
|||||||
|
|
||||||
tint_unittests_source_set("tint_unittests_resolver_src") {
|
tint_unittests_source_set("tint_unittests_resolver_src") {
|
||||||
sources = [
|
sources = [
|
||||||
|
"resolver/address_space_layout_validation_test.cc",
|
||||||
|
"resolver/address_space_validation_test.cc",
|
||||||
"resolver/array_accessor_test.cc",
|
"resolver/array_accessor_test.cc",
|
||||||
"resolver/assignment_validation_test.cc",
|
"resolver/assignment_validation_test.cc",
|
||||||
"resolver/atomics_test.cc",
|
"resolver/atomics_test.cc",
|
||||||
@ -1133,11 +1135,9 @@ if (tint_build_unittests) {
|
|||||||
"resolver/side_effects_test.cc",
|
"resolver/side_effects_test.cc",
|
||||||
"resolver/source_variable_test.cc",
|
"resolver/source_variable_test.cc",
|
||||||
"resolver/static_assert_test.cc",
|
"resolver/static_assert_test.cc",
|
||||||
"resolver/storage_class_layout_validation_test.cc",
|
"resolver/struct_address_space_use_test.cc",
|
||||||
"resolver/storage_class_validation_test.cc",
|
|
||||||
"resolver/struct_layout_test.cc",
|
"resolver/struct_layout_test.cc",
|
||||||
"resolver/struct_pipeline_stage_use_test.cc",
|
"resolver/struct_pipeline_stage_use_test.cc",
|
||||||
"resolver/struct_storage_class_use_test.cc",
|
|
||||||
"resolver/type_constructor_validation_test.cc",
|
"resolver/type_constructor_validation_test.cc",
|
||||||
"resolver/type_validation_test.cc",
|
"resolver/type_validation_test.cc",
|
||||||
"resolver/uniformity_test.cc",
|
"resolver/uniformity_test.cc",
|
||||||
@ -1354,6 +1354,7 @@ if (tint_build_unittests) {
|
|||||||
sources = [
|
sources = [
|
||||||
"reader/wgsl/lexer_test.cc",
|
"reader/wgsl/lexer_test.cc",
|
||||||
"reader/wgsl/parser_impl_additive_expression_test.cc",
|
"reader/wgsl/parser_impl_additive_expression_test.cc",
|
||||||
|
"reader/wgsl/parser_impl_address_space_test.cc",
|
||||||
"reader/wgsl/parser_impl_argument_expression_list_test.cc",
|
"reader/wgsl/parser_impl_argument_expression_list_test.cc",
|
||||||
"reader/wgsl/parser_impl_assignment_stmt_test.cc",
|
"reader/wgsl/parser_impl_assignment_stmt_test.cc",
|
||||||
"reader/wgsl/parser_impl_bitwise_expression_test.cc",
|
"reader/wgsl/parser_impl_bitwise_expression_test.cc",
|
||||||
@ -1400,7 +1401,6 @@ if (tint_build_unittests) {
|
|||||||
"reader/wgsl/parser_impl_singular_expression_test.cc",
|
"reader/wgsl/parser_impl_singular_expression_test.cc",
|
||||||
"reader/wgsl/parser_impl_statement_test.cc",
|
"reader/wgsl/parser_impl_statement_test.cc",
|
||||||
"reader/wgsl/parser_impl_statements_test.cc",
|
"reader/wgsl/parser_impl_statements_test.cc",
|
||||||
"reader/wgsl/parser_impl_storage_class_test.cc",
|
|
||||||
"reader/wgsl/parser_impl_storage_texture_test.cc",
|
"reader/wgsl/parser_impl_storage_texture_test.cc",
|
||||||
"reader/wgsl/parser_impl_struct_attribute_decl_test.cc",
|
"reader/wgsl/parser_impl_struct_attribute_decl_test.cc",
|
||||||
"reader/wgsl/parser_impl_struct_body_decl_test.cc",
|
"reader/wgsl/parser_impl_struct_body_decl_test.cc",
|
||||||
|
@ -182,8 +182,8 @@ set(TINT_LIB_SRCS
|
|||||||
ast/statement.h
|
ast/statement.h
|
||||||
ast/static_assert.cc
|
ast/static_assert.cc
|
||||||
ast/static_assert.h
|
ast/static_assert.h
|
||||||
ast/storage_class.cc
|
ast/address_space.cc
|
||||||
ast/storage_class.h
|
ast/address_space.h
|
||||||
ast/storage_texture.cc
|
ast/storage_texture.cc
|
||||||
ast/storage_texture.h
|
ast/storage_texture.h
|
||||||
ast/stride_attribute.cc
|
ast/stride_attribute.cc
|
||||||
@ -747,7 +747,7 @@ if(TINT_BUILD_TESTS)
|
|||||||
ast/sampler_test.cc
|
ast/sampler_test.cc
|
||||||
ast/stage_attribute_test.cc
|
ast/stage_attribute_test.cc
|
||||||
ast/static_assert_test.cc
|
ast/static_assert_test.cc
|
||||||
ast/storage_class_test.cc
|
ast/address_space_test.cc
|
||||||
ast/storage_texture_test.cc
|
ast/storage_texture_test.cc
|
||||||
ast/stride_attribute_test.cc
|
ast/stride_attribute_test.cc
|
||||||
ast/struct_member_align_attribute_test.cc
|
ast/struct_member_align_attribute_test.cc
|
||||||
@ -814,11 +814,11 @@ if(TINT_BUILD_TESTS)
|
|||||||
resolver/side_effects_test.cc
|
resolver/side_effects_test.cc
|
||||||
resolver/static_assert_test.cc
|
resolver/static_assert_test.cc
|
||||||
resolver/source_variable_test.cc
|
resolver/source_variable_test.cc
|
||||||
resolver/storage_class_layout_validation_test.cc
|
resolver/address_space_layout_validation_test.cc
|
||||||
resolver/storage_class_validation_test.cc
|
resolver/address_space_validation_test.cc
|
||||||
resolver/struct_layout_test.cc
|
resolver/struct_layout_test.cc
|
||||||
resolver/struct_pipeline_stage_use_test.cc
|
resolver/struct_pipeline_stage_use_test.cc
|
||||||
resolver/struct_storage_class_use_test.cc
|
resolver/struct_address_space_use_test.cc
|
||||||
resolver/type_constructor_validation_test.cc
|
resolver/type_constructor_validation_test.cc
|
||||||
resolver/type_validation_test.cc
|
resolver/type_validation_test.cc
|
||||||
resolver/validation_test.cc
|
resolver/validation_test.cc
|
||||||
@ -992,7 +992,7 @@ if(TINT_BUILD_TESTS)
|
|||||||
reader/wgsl/parser_impl_singular_expression_test.cc
|
reader/wgsl/parser_impl_singular_expression_test.cc
|
||||||
reader/wgsl/parser_impl_statement_test.cc
|
reader/wgsl/parser_impl_statement_test.cc
|
||||||
reader/wgsl/parser_impl_statements_test.cc
|
reader/wgsl/parser_impl_statements_test.cc
|
||||||
reader/wgsl/parser_impl_storage_class_test.cc
|
reader/wgsl/parser_impl_address_space_test.cc
|
||||||
reader/wgsl/parser_impl_storage_texture_test.cc
|
reader/wgsl/parser_impl_storage_texture_test.cc
|
||||||
reader/wgsl/parser_impl_struct_body_decl_test.cc
|
reader/wgsl/parser_impl_struct_body_decl_test.cc
|
||||||
reader/wgsl/parser_impl_struct_decl_test.cc
|
reader/wgsl/parser_impl_struct_decl_test.cc
|
||||||
@ -1300,7 +1300,7 @@ if(TINT_BUILD_BENCHMARKS)
|
|||||||
set(TINT_BENCHMARK_SRC
|
set(TINT_BENCHMARK_SRC
|
||||||
"castable_bench.cc"
|
"castable_bench.cc"
|
||||||
"ast/extension_bench.cc"
|
"ast/extension_bench.cc"
|
||||||
"ast/storage_class_bench.cc"
|
"ast/address_space_bench.cc"
|
||||||
"ast/texel_format_bench.cc"
|
"ast/texel_format_bench.cc"
|
||||||
"bench/benchmark.cc"
|
"bench/benchmark.cc"
|
||||||
"reader/wgsl/parser_bench.cc"
|
"reader/wgsl/parser_bench.cc"
|
||||||
|
@ -15,63 +15,63 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// File generated by tools/src/cmd/gen
|
// File generated by tools/src/cmd/gen
|
||||||
// using the template:
|
// using the template:
|
||||||
// src/tint/ast/storage_class.cc.tmpl
|
// src/tint/ast/address_space.cc.tmpl
|
||||||
//
|
//
|
||||||
// Do not modify this file directly
|
// Do not modify this file directly
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
||||||
/// ParseStorageClass parses a StorageClass from a string.
|
/// ParseAddressSpace parses a AddressSpace from a string.
|
||||||
/// @param str the string to parse
|
/// @param str the string to parse
|
||||||
/// @returns the parsed enum, or StorageClass::kInvalid if the string could not be parsed.
|
/// @returns the parsed enum, or AddressSpace::kInvalid if the string could not be parsed.
|
||||||
StorageClass ParseStorageClass(std::string_view str) {
|
AddressSpace ParseAddressSpace(std::string_view str) {
|
||||||
if (str == "function") {
|
if (str == "function") {
|
||||||
return StorageClass::kFunction;
|
return AddressSpace::kFunction;
|
||||||
}
|
}
|
||||||
if (str == "private") {
|
if (str == "private") {
|
||||||
return StorageClass::kPrivate;
|
return AddressSpace::kPrivate;
|
||||||
}
|
}
|
||||||
if (str == "workgroup") {
|
if (str == "workgroup") {
|
||||||
return StorageClass::kWorkgroup;
|
return AddressSpace::kWorkgroup;
|
||||||
}
|
}
|
||||||
if (str == "uniform") {
|
if (str == "uniform") {
|
||||||
return StorageClass::kUniform;
|
return AddressSpace::kUniform;
|
||||||
}
|
}
|
||||||
if (str == "storage") {
|
if (str == "storage") {
|
||||||
return StorageClass::kStorage;
|
return AddressSpace::kStorage;
|
||||||
}
|
}
|
||||||
if (str == "push_constant") {
|
if (str == "push_constant") {
|
||||||
return StorageClass::kPushConstant;
|
return AddressSpace::kPushConstant;
|
||||||
}
|
}
|
||||||
return StorageClass::kInvalid;
|
return AddressSpace::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, StorageClass value) {
|
std::ostream& operator<<(std::ostream& out, AddressSpace value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case StorageClass::kInvalid:
|
case AddressSpace::kInvalid:
|
||||||
return out << "invalid";
|
return out << "invalid";
|
||||||
case StorageClass::kNone:
|
case AddressSpace::kNone:
|
||||||
return out << "none";
|
return out << "none";
|
||||||
case StorageClass::kFunction:
|
case AddressSpace::kFunction:
|
||||||
return out << "function";
|
return out << "function";
|
||||||
case StorageClass::kPrivate:
|
case AddressSpace::kPrivate:
|
||||||
return out << "private";
|
return out << "private";
|
||||||
case StorageClass::kWorkgroup:
|
case AddressSpace::kWorkgroup:
|
||||||
return out << "workgroup";
|
return out << "workgroup";
|
||||||
case StorageClass::kUniform:
|
case AddressSpace::kUniform:
|
||||||
return out << "uniform";
|
return out << "uniform";
|
||||||
case StorageClass::kStorage:
|
case AddressSpace::kStorage:
|
||||||
return out << "storage";
|
return out << "storage";
|
||||||
case StorageClass::kPushConstant:
|
case AddressSpace::kPushConstant:
|
||||||
return out << "push_constant";
|
return out << "push_constant";
|
||||||
case StorageClass::kHandle:
|
case AddressSpace::kHandle:
|
||||||
return out << "handle";
|
return out << "handle";
|
||||||
case StorageClass::kIn:
|
case AddressSpace::kIn:
|
||||||
return out << "in";
|
return out << "in";
|
||||||
case StorageClass::kOut:
|
case AddressSpace::kOut:
|
||||||
return out << "out";
|
return out << "out";
|
||||||
}
|
}
|
||||||
return out << "<unknown>";
|
return out << "<unknown>";
|
@ -1,6 +1,6 @@
|
|||||||
{{- /*
|
{{- /*
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Template file for use with tools/src/cmd/gen to generate storage_class.cc
|
Template file for use with tools/src/cmd/gen to generate address_space.cc
|
||||||
|
|
||||||
To update the generated file, run:
|
To update the generated file, run:
|
||||||
./tools/run gen
|
./tools/run gen
|
||||||
@ -12,9 +12,9 @@ See:
|
|||||||
*/ -}}
|
*/ -}}
|
||||||
|
|
||||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
{{- $enum := (Sem.Enum "storage_class") -}}
|
{{- $enum := (Sem.Enum "address_space") -}}
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
@ -15,20 +15,20 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// File generated by tools/src/cmd/gen
|
// File generated by tools/src/cmd/gen
|
||||||
// using the template:
|
// using the template:
|
||||||
// src/tint/ast/storage_class.h.tmpl
|
// src/tint/ast/address_space.h.tmpl
|
||||||
//
|
//
|
||||||
// Do not modify this file directly
|
// Do not modify this file directly
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef SRC_TINT_AST_STORAGE_CLASS_H_
|
#ifndef SRC_TINT_AST_ADDRESS_SPACE_H_
|
||||||
#define SRC_TINT_AST_STORAGE_CLASS_H_
|
#define SRC_TINT_AST_ADDRESS_SPACE_H_
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
||||||
/// Storage class of a given pointer.
|
/// Address space of a given pointer.
|
||||||
enum class StorageClass {
|
enum class AddressSpace {
|
||||||
kInvalid,
|
kInvalid,
|
||||||
kNone, // Tint-internal enum entry - not parsed
|
kNone, // Tint-internal enum entry - not parsed
|
||||||
kFunction,
|
kFunction,
|
||||||
@ -43,23 +43,24 @@ enum class StorageClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// @param out the std::ostream to write to
|
/// @param out the std::ostream to write to
|
||||||
/// @param value the StorageClass
|
/// @param value the AddressSpace
|
||||||
/// @returns `out` so calls can be chained
|
/// @returns `out` so calls can be chained
|
||||||
std::ostream& operator<<(std::ostream& out, StorageClass value);
|
std::ostream& operator<<(std::ostream& out, AddressSpace value);
|
||||||
|
|
||||||
/// ParseStorageClass parses a StorageClass from a string.
|
/// ParseAddressSpace parses a AddressSpace from a string.
|
||||||
/// @param str the string to parse
|
/// @param str the string to parse
|
||||||
/// @returns the parsed enum, or StorageClass::kInvalid if the string could not be parsed.
|
/// @returns the parsed enum, or AddressSpace::kInvalid if the string could not be parsed.
|
||||||
StorageClass ParseStorageClass(std::string_view str);
|
AddressSpace ParseAddressSpace(std::string_view str);
|
||||||
|
|
||||||
/// @returns true if the StorageClass is host-shareable
|
/// @returns true if the AddressSpace is host-shareable
|
||||||
/// @param sc the StorageClass
|
/// @param address_space the AddressSpace
|
||||||
/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
|
/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
|
||||||
inline bool IsHostShareable(StorageClass sc) {
|
inline bool IsHostShareable(AddressSpace address_space) {
|
||||||
return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage ||
|
return address_space == ast::AddressSpace::kUniform ||
|
||||||
sc == ast::StorageClass::kPushConstant;
|
address_space == ast::AddressSpace::kStorage ||
|
||||||
|
address_space == ast::AddressSpace::kPushConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
|
|
||||||
#endif // SRC_TINT_AST_STORAGE_CLASS_H_
|
#endif // SRC_TINT_AST_ADDRESS_SPACE_H_
|
@ -1,6 +1,6 @@
|
|||||||
{{- /*
|
{{- /*
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Template file for use with tools/src/cmd/gen to generate storage_class.h
|
Template file for use with tools/src/cmd/gen to generate address_space.h
|
||||||
|
|
||||||
To update the generated file, run:
|
To update the generated file, run:
|
||||||
./tools/run gen
|
./tools/run gen
|
||||||
@ -12,26 +12,26 @@ See:
|
|||||||
*/ -}}
|
*/ -}}
|
||||||
|
|
||||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
{{- $enum := (Sem.Enum "storage_class") -}}
|
{{- $enum := (Sem.Enum "address_space") -}}
|
||||||
|
|
||||||
#ifndef SRC_TINT_AST_STORAGE_CLASS_H_
|
#ifndef SRC_TINT_AST_ADDRESS_SPACE_H_
|
||||||
#define SRC_TINT_AST_STORAGE_CLASS_H_
|
#define SRC_TINT_AST_ADDRESS_SPACE_H_
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
||||||
/// Storage class of a given pointer.
|
/// Address space of a given pointer.
|
||||||
{{ Eval "DeclareEnum" $enum}}
|
{{ Eval "DeclareEnum" $enum}}
|
||||||
|
|
||||||
/// @returns true if the StorageClass is host-shareable
|
/// @returns true if the AddressSpace is host-shareable
|
||||||
/// @param sc the StorageClass
|
/// @param address_space the AddressSpace
|
||||||
/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
|
/// @see https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable
|
||||||
inline bool IsHostShareable(StorageClass sc) {
|
inline bool IsHostShareable(AddressSpace address_space) {
|
||||||
return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage ||
|
return address_space == ast::AddressSpace::kUniform || address_space == ast::AddressSpace::kStorage ||
|
||||||
sc == ast::StorageClass::kPushConstant;
|
address_space == ast::AddressSpace::kPushConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
|
|
||||||
#endif // SRC_TINT_AST_STORAGE_CLASS_H_
|
#endif // SRC_TINT_AST_ADDRESS_SPACE_H_
|
@ -15,12 +15,12 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// File generated by tools/src/cmd/gen
|
// File generated by tools/src/cmd/gen
|
||||||
// using the template:
|
// using the template:
|
||||||
// src/tint/ast/storage_class_bench.cc.tmpl
|
// src/tint/ast/address_space_bench.cc.tmpl
|
||||||
//
|
//
|
||||||
// Do not modify this file directly
|
// Do not modify this file directly
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
@ -29,7 +29,7 @@
|
|||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void StorageClassParser(::benchmark::State& state) {
|
void AddressSpaceParser(::benchmark::State& state) {
|
||||||
std::array kStrings{
|
std::array kStrings{
|
||||||
"fccnctin",
|
"fccnctin",
|
||||||
"ucti3",
|
"ucti3",
|
||||||
@ -76,13 +76,13 @@ void StorageClassParser(::benchmark::State& state) {
|
|||||||
};
|
};
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
for (auto& str : kStrings) {
|
for (auto& str : kStrings) {
|
||||||
auto result = ParseStorageClass(str);
|
auto result = ParseAddressSpace(str);
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(StorageClassParser);
|
BENCHMARK(AddressSpaceParser);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
@ -1,6 +1,6 @@
|
|||||||
{{- /*
|
{{- /*
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Template file for use with tools/src/cmd/gen to generate storage_class_bench.cc
|
Template file for use with tools/src/cmd/gen to generate address_space_bench.cc
|
||||||
|
|
||||||
To update the generated file, run:
|
To update the generated file, run:
|
||||||
./tools/run gen
|
./tools/run gen
|
||||||
@ -12,9 +12,9 @@ See:
|
|||||||
*/ -}}
|
*/ -}}
|
||||||
|
|
||||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
{{- $enum := (Sem.Enum "storage_class") -}}
|
{{- $enum := (Sem.Enum "address_space") -}}
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
86
src/tint/ast/address_space_test.cc
Normal file
86
src/tint/ast/address_space_test.cc
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2022 The Tint Authors.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File generated by tools/src/cmd/gen
|
||||||
|
// using the template:
|
||||||
|
// src/tint/ast/address_space_test.cc.tmpl
|
||||||
|
//
|
||||||
|
// Do not modify this file directly
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "src/tint/ast/test_helper.h"
|
||||||
|
#include "src/tint/utils/string.h"
|
||||||
|
|
||||||
|
namespace tint::ast {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace parse_print_tests {
|
||||||
|
|
||||||
|
struct Case {
|
||||||
|
const char* string;
|
||||||
|
AddressSpace value;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, Case c) {
|
||||||
|
return out << "'" << std::string(c.string) << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Case kValidCases[] = {
|
||||||
|
{"function", AddressSpace::kFunction}, {"private", AddressSpace::kPrivate},
|
||||||
|
{"workgroup", AddressSpace::kWorkgroup}, {"uniform", AddressSpace::kUniform},
|
||||||
|
{"storage", AddressSpace::kStorage}, {"push_constant", AddressSpace::kPushConstant},
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Case kInvalidCases[] = {
|
||||||
|
{"fccnctin", AddressSpace::kInvalid}, {"ucti3", AddressSpace::kInvalid},
|
||||||
|
{"functVon", AddressSpace::kInvalid}, {"priv1te", AddressSpace::kInvalid},
|
||||||
|
{"pqiJate", AddressSpace::kInvalid}, {"privat7ll", AddressSpace::kInvalid},
|
||||||
|
{"workroppqHH", AddressSpace::kInvalid}, {"workru", AddressSpace::kInvalid},
|
||||||
|
{"wbkgGoup", AddressSpace::kInvalid}, {"unifiivm", AddressSpace::kInvalid},
|
||||||
|
{"8WWiform", AddressSpace::kInvalid}, {"uxxform", AddressSpace::kInvalid},
|
||||||
|
{"sXraggg", AddressSpace::kInvalid}, {"traXe", AddressSpace::kInvalid},
|
||||||
|
{"stor3ge", AddressSpace::kInvalid}, {"push_constanE", AddressSpace::kInvalid},
|
||||||
|
{"push_TTPnstant", AddressSpace::kInvalid}, {"puxxdh_constan", AddressSpace::kInvalid},
|
||||||
|
};
|
||||||
|
|
||||||
|
using AddressSpaceParseTest = testing::TestWithParam<Case>;
|
||||||
|
|
||||||
|
TEST_P(AddressSpaceParseTest, Parse) {
|
||||||
|
const char* string = GetParam().string;
|
||||||
|
AddressSpace expect = GetParam().value;
|
||||||
|
EXPECT_EQ(expect, ParseAddressSpace(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidCases, AddressSpaceParseTest, testing::ValuesIn(kValidCases));
|
||||||
|
INSTANTIATE_TEST_SUITE_P(InvalidCases, AddressSpaceParseTest, testing::ValuesIn(kInvalidCases));
|
||||||
|
|
||||||
|
using AddressSpacePrintTest = testing::TestWithParam<Case>;
|
||||||
|
|
||||||
|
TEST_P(AddressSpacePrintTest, Print) {
|
||||||
|
AddressSpace value = GetParam().value;
|
||||||
|
const char* expect = GetParam().string;
|
||||||
|
EXPECT_EQ(expect, utils::ToString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidCases, AddressSpacePrintTest, testing::ValuesIn(kValidCases));
|
||||||
|
|
||||||
|
} // namespace parse_print_tests
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::ast
|
@ -1,6 +1,6 @@
|
|||||||
{{- /*
|
{{- /*
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Template file for use with tools/src/cmd/gen to generate storage_class_test.cc
|
Template file for use with tools/src/cmd/gen to generate address_space_test.cc
|
||||||
|
|
||||||
To update the generated file, run:
|
To update the generated file, run:
|
||||||
./tools/run gen
|
./tools/run gen
|
||||||
@ -12,9 +12,9 @@ See:
|
|||||||
*/ -}}
|
*/ -}}
|
||||||
|
|
||||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
{{- $enum := (Sem.Enum "storage_class") -}}
|
{{- $enum := (Sem.Enum "address_space") -}}
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -33,8 +33,8 @@ std::string DisableValidationAttribute::InternalName() const {
|
|||||||
return "disable_validation__function_has_no_body";
|
return "disable_validation__function_has_no_body";
|
||||||
case DisabledValidation::kBindingPointCollision:
|
case DisabledValidation::kBindingPointCollision:
|
||||||
return "disable_validation__binding_point_collision";
|
return "disable_validation__binding_point_collision";
|
||||||
case DisabledValidation::kIgnoreStorageClass:
|
case DisabledValidation::kIgnoreAddressSpace:
|
||||||
return "disable_validation__ignore_storage_class";
|
return "disable_validation__ignore_address_space";
|
||||||
case DisabledValidation::kEntryPointParameter:
|
case DisabledValidation::kEntryPointParameter:
|
||||||
return "disable_validation__entry_point_parameter";
|
return "disable_validation__entry_point_parameter";
|
||||||
case DisabledValidation::kFunctionParameter:
|
case DisabledValidation::kFunctionParameter:
|
||||||
|
@ -29,9 +29,9 @@ enum class DisabledValidation {
|
|||||||
/// When applied to a module-scoped variable, the validator will not complain if two resource
|
/// When applied to a module-scoped variable, the validator will not complain if two resource
|
||||||
/// variables have the same binding points.
|
/// variables have the same binding points.
|
||||||
kBindingPointCollision,
|
kBindingPointCollision,
|
||||||
/// When applied to a variable, the validator will not complain about the declared storage
|
/// When applied to a variable, the validator will not complain about the declared address
|
||||||
/// class.
|
/// space.
|
||||||
kIgnoreStorageClass,
|
kIgnoreAddressSpace,
|
||||||
/// When applied to an entry-point function parameter, the validator will not check for entry IO
|
/// When applied to an entry-point function parameter, the validator will not check for entry IO
|
||||||
/// attributes.
|
/// attributes.
|
||||||
kEntryPointParameter,
|
kEntryPointParameter,
|
||||||
|
@ -72,7 +72,7 @@ TEST_F(ModuleTest, Assert_DifferentProgramID_GlobalVariable) {
|
|||||||
{
|
{
|
||||||
ProgramBuilder b1;
|
ProgramBuilder b1;
|
||||||
ProgramBuilder b2;
|
ProgramBuilder b2;
|
||||||
b1.AST().AddGlobalVariable(b2.Var("var", b2.ty.i32(), ast::StorageClass::kPrivate));
|
b1.AST().AddGlobalVariable(b2.Var("var", b2.ty.i32(), ast::AddressSpace::kPrivate));
|
||||||
},
|
},
|
||||||
"internal compiler error");
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ TEST_F(ModuleTest, CloneOrder) {
|
|||||||
ProgramBuilder b;
|
ProgramBuilder b;
|
||||||
b.Func("F", {}, b.ty.void_(), {});
|
b.Func("F", {}, b.ty.void_(), {});
|
||||||
b.Alias("A", b.ty.u32());
|
b.Alias("A", b.ty.u32());
|
||||||
b.GlobalVar("V", b.ty.i32(), ast::StorageClass::kPrivate);
|
b.GlobalVar("V", b.ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
return Program(std::move(b));
|
return Program(std::move(b));
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -24,15 +24,15 @@ Pointer::Pointer(ProgramID pid,
|
|||||||
NodeID nid,
|
NodeID nid,
|
||||||
const Source& src,
|
const Source& src,
|
||||||
const Type* const subtype,
|
const Type* const subtype,
|
||||||
ast::StorageClass sc,
|
ast::AddressSpace addr_space,
|
||||||
ast::Access ac)
|
ast::Access ac)
|
||||||
: Base(pid, nid, src), type(subtype), storage_class(sc), access(ac) {}
|
: Base(pid, nid, src), type(subtype), address_space(addr_space), access(ac) {}
|
||||||
|
|
||||||
std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
|
std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "ptr<";
|
out << "ptr<";
|
||||||
if (storage_class != ast::StorageClass::kNone) {
|
if (address_space != ast::AddressSpace::kNone) {
|
||||||
out << storage_class << ", ";
|
out << address_space << ", ";
|
||||||
}
|
}
|
||||||
out << type->FriendlyName(symbols);
|
out << type->FriendlyName(symbols);
|
||||||
if (access != ast::Access::kUndefined) {
|
if (access != ast::Access::kUndefined) {
|
||||||
@ -50,7 +50,7 @@ const Pointer* Pointer::Clone(CloneContext* ctx) const {
|
|||||||
// Clone arguments outside of create() call to have deterministic ordering
|
// Clone arguments outside of create() call to have deterministic ordering
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto* ty = ctx->Clone(type);
|
auto* ty = ctx->Clone(type);
|
||||||
return ctx->dst->create<Pointer>(src, ty, storage_class, access);
|
return ctx->dst->create<Pointer>(src, ty, address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "src/tint/ast/access.h"
|
#include "src/tint/ast/access.h"
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/address_space.h"
|
||||||
#include "src/tint/ast/type.h"
|
#include "src/tint/ast/type.h"
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
@ -31,13 +31,13 @@ class Pointer final : public Castable<Pointer, Type> {
|
|||||||
/// @param nid the unique node identifier
|
/// @param nid the unique node identifier
|
||||||
/// @param src the source of this node
|
/// @param src the source of this node
|
||||||
/// @param subtype the pointee type
|
/// @param subtype the pointee type
|
||||||
/// @param storage_class the storage class of the pointer
|
/// @param address_space the address space of the pointer
|
||||||
/// @param access the access control of the pointer
|
/// @param access the access control of the pointer
|
||||||
Pointer(ProgramID pid,
|
Pointer(ProgramID pid,
|
||||||
NodeID nid,
|
NodeID nid,
|
||||||
const Source& src,
|
const Source& src,
|
||||||
const Type* const subtype,
|
const Type* const subtype,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
ast::Access access);
|
ast::Access access);
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
Pointer(Pointer&&);
|
Pointer(Pointer&&);
|
||||||
@ -56,8 +56,8 @@ class Pointer final : public Castable<Pointer, Type> {
|
|||||||
/// The pointee type
|
/// The pointee type
|
||||||
const Type* const type;
|
const Type* const type;
|
||||||
|
|
||||||
/// The storage class of the pointer
|
/// The address space of the pointer
|
||||||
ast::StorageClass const storage_class;
|
ast::AddressSpace const address_space;
|
||||||
|
|
||||||
/// The access control of the pointer
|
/// The access control of the pointer
|
||||||
ast::Access const access;
|
ast::Access const access;
|
||||||
|
@ -24,21 +24,21 @@ using AstPointerTest = TestHelper;
|
|||||||
|
|
||||||
TEST_F(AstPointerTest, Creation) {
|
TEST_F(AstPointerTest, Creation) {
|
||||||
auto* i32 = create<I32>();
|
auto* i32 = create<I32>();
|
||||||
auto* p = create<Pointer>(i32, ast::StorageClass::kStorage, Access::kRead);
|
auto* p = create<Pointer>(i32, ast::AddressSpace::kStorage, Access::kRead);
|
||||||
EXPECT_EQ(p->type, i32);
|
EXPECT_EQ(p->type, i32);
|
||||||
EXPECT_EQ(p->storage_class, ast::StorageClass::kStorage);
|
EXPECT_EQ(p->address_space, ast::AddressSpace::kStorage);
|
||||||
EXPECT_EQ(p->access, Access::kRead);
|
EXPECT_EQ(p->access, Access::kRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AstPointerTest, FriendlyName) {
|
TEST_F(AstPointerTest, FriendlyName) {
|
||||||
auto* i32 = create<I32>();
|
auto* i32 = create<I32>();
|
||||||
auto* p = create<Pointer>(i32, ast::StorageClass::kWorkgroup, Access::kUndefined);
|
auto* p = create<Pointer>(i32, ast::AddressSpace::kWorkgroup, Access::kUndefined);
|
||||||
EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<workgroup, i32>");
|
EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<workgroup, i32>");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AstPointerTest, FriendlyNameWithAccess) {
|
TEST_F(AstPointerTest, FriendlyNameWithAccess) {
|
||||||
auto* i32 = create<I32>();
|
auto* i32 = create<I32>();
|
||||||
auto* p = create<Pointer>(i32, ast::StorageClass::kStorage, Access::kReadWrite);
|
auto* p = create<Pointer>(i32, ast::AddressSpace::kStorage, Access::kReadWrite);
|
||||||
EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<storage, i32, read_write>");
|
EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<storage, i32, read_write>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright 2022 The Tint Authors.
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// File generated by tools/src/cmd/gen
|
|
||||||
// using the template:
|
|
||||||
// src/tint/ast/storage_class_test.cc.tmpl
|
|
||||||
//
|
|
||||||
// Do not modify this file directly
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "src/tint/ast/storage_class.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "src/tint/ast/test_helper.h"
|
|
||||||
#include "src/tint/utils/string.h"
|
|
||||||
|
|
||||||
namespace tint::ast {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
namespace parse_print_tests {
|
|
||||||
|
|
||||||
struct Case {
|
|
||||||
const char* string;
|
|
||||||
StorageClass value;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, Case c) {
|
|
||||||
return out << "'" << std::string(c.string) << "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr Case kValidCases[] = {
|
|
||||||
{"function", StorageClass::kFunction}, {"private", StorageClass::kPrivate},
|
|
||||||
{"workgroup", StorageClass::kWorkgroup}, {"uniform", StorageClass::kUniform},
|
|
||||||
{"storage", StorageClass::kStorage}, {"push_constant", StorageClass::kPushConstant},
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr Case kInvalidCases[] = {
|
|
||||||
{"fccnctin", StorageClass::kInvalid}, {"ucti3", StorageClass::kInvalid},
|
|
||||||
{"functVon", StorageClass::kInvalid}, {"priv1te", StorageClass::kInvalid},
|
|
||||||
{"pqiJate", StorageClass::kInvalid}, {"privat7ll", StorageClass::kInvalid},
|
|
||||||
{"workroppqHH", StorageClass::kInvalid}, {"workru", StorageClass::kInvalid},
|
|
||||||
{"wbkgGoup", StorageClass::kInvalid}, {"unifiivm", StorageClass::kInvalid},
|
|
||||||
{"8WWiform", StorageClass::kInvalid}, {"uxxform", StorageClass::kInvalid},
|
|
||||||
{"sXraggg", StorageClass::kInvalid}, {"traXe", StorageClass::kInvalid},
|
|
||||||
{"stor3ge", StorageClass::kInvalid}, {"push_constanE", StorageClass::kInvalid},
|
|
||||||
{"push_TTPnstant", StorageClass::kInvalid}, {"puxxdh_constan", StorageClass::kInvalid},
|
|
||||||
};
|
|
||||||
|
|
||||||
using StorageClassParseTest = testing::TestWithParam<Case>;
|
|
||||||
|
|
||||||
TEST_P(StorageClassParseTest, Parse) {
|
|
||||||
const char* string = GetParam().string;
|
|
||||||
StorageClass expect = GetParam().value;
|
|
||||||
EXPECT_EQ(expect, ParseStorageClass(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassParseTest, testing::ValuesIn(kValidCases));
|
|
||||||
INSTANTIATE_TEST_SUITE_P(InvalidCases, StorageClassParseTest, testing::ValuesIn(kInvalidCases));
|
|
||||||
|
|
||||||
using StorageClassPrintTest = testing::TestWithParam<Case>;
|
|
||||||
|
|
||||||
TEST_P(StorageClassPrintTest, Print) {
|
|
||||||
StorageClass value = GetParam().value;
|
|
||||||
const char* expect = GetParam().string;
|
|
||||||
EXPECT_EQ(expect, utils::ToString(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(ValidCases, StorageClassPrintTest, testing::ValuesIn(kValidCases));
|
|
||||||
|
|
||||||
} // namespace parse_print_tests
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace tint::ast
|
|
@ -25,12 +25,12 @@ Var::Var(ProgramID pid,
|
|||||||
const Source& src,
|
const Source& src,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
const ast::Type* ty,
|
const ast::Type* ty,
|
||||||
StorageClass storage_class,
|
AddressSpace address_space,
|
||||||
Access access,
|
Access access,
|
||||||
const Expression* ctor,
|
const Expression* ctor,
|
||||||
utils::VectorRef<const Attribute*> attrs)
|
utils::VectorRef<const Attribute*> attrs)
|
||||||
: Base(pid, nid, src, sym, ty, ctor, std::move(attrs)),
|
: Base(pid, nid, src, sym, ty, ctor, std::move(attrs)),
|
||||||
declared_storage_class(storage_class),
|
declared_address_space(address_space),
|
||||||
declared_access(access) {}
|
declared_access(access) {}
|
||||||
|
|
||||||
Var::Var(Var&&) = default;
|
Var::Var(Var&&) = default;
|
||||||
@ -47,7 +47,7 @@ const Var* Var::Clone(CloneContext* ctx) const {
|
|||||||
auto* ty = ctx->Clone(type);
|
auto* ty = ctx->Clone(type);
|
||||||
auto* ctor = ctx->Clone(constructor);
|
auto* ctor = ctx->Clone(constructor);
|
||||||
auto attrs = ctx->Clone(attributes);
|
auto attrs = ctx->Clone(attributes);
|
||||||
return ctx->dst->create<Var>(src, sym, ty, declared_storage_class, declared_access, ctor,
|
return ctx->dst->create<Var>(src, sym, ty, declared_address_space, declared_access, ctor,
|
||||||
std::move(attrs));
|
std::move(attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ namespace tint::ast {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// // Declared outside a function, i.e. at module scope, requires
|
/// // Declared outside a function, i.e. at module scope, requires
|
||||||
/// // a storage class.
|
/// // a address space.
|
||||||
/// var<workgroup> width : i32; // no initializer
|
/// var<workgroup> width : i32; // no initializer
|
||||||
/// var<private> height : i32 = 3; // with initializer
|
/// var<private> height : i32 = 3; // with initializer
|
||||||
///
|
///
|
||||||
/// // A variable declared inside a function doesn't take a storage class,
|
/// // A variable declared inside a function doesn't take a address space,
|
||||||
/// // and maps to SPIR-V Function storage.
|
/// // and maps to SPIR-V Function storage.
|
||||||
/// var computed_depth : i32;
|
/// var computed_depth : i32;
|
||||||
/// var area : i32 = compute_area(width, height);
|
/// var area : i32 = compute_area(width, height);
|
||||||
@ -47,7 +47,7 @@ class Var final : public Castable<Var, Variable> {
|
|||||||
/// @param source the variable source
|
/// @param source the variable source
|
||||||
/// @param sym the variable symbol
|
/// @param sym the variable symbol
|
||||||
/// @param type the declared variable type
|
/// @param type the declared variable type
|
||||||
/// @param declared_storage_class the declared storage class
|
/// @param declared_address_space the declared address space
|
||||||
/// @param declared_access the declared access control
|
/// @param declared_access the declared access control
|
||||||
/// @param constructor the constructor expression
|
/// @param constructor the constructor expression
|
||||||
/// @param attributes the variable attributes
|
/// @param attributes the variable attributes
|
||||||
@ -56,7 +56,7 @@ class Var final : public Castable<Var, Variable> {
|
|||||||
const Source& source,
|
const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
const ast::Type* type,
|
const ast::Type* type,
|
||||||
StorageClass declared_storage_class,
|
AddressSpace declared_address_space,
|
||||||
Access declared_access,
|
Access declared_access,
|
||||||
const Expression* constructor,
|
const Expression* constructor,
|
||||||
utils::VectorRef<const Attribute*> attributes);
|
utils::VectorRef<const Attribute*> attributes);
|
||||||
@ -76,8 +76,8 @@ class Var final : public Castable<Var, Variable> {
|
|||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
const Var* Clone(CloneContext* ctx) const override;
|
const Var* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// The declared storage class
|
/// The declared address space
|
||||||
const StorageClass declared_storage_class;
|
const AddressSpace declared_address_space;
|
||||||
|
|
||||||
/// The declared access control
|
/// The declared access control
|
||||||
const Access declared_access;
|
const Access declared_access;
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/tint/ast/access.h"
|
#include "src/tint/ast/access.h"
|
||||||
|
#include "src/tint/ast/address_space.h"
|
||||||
#include "src/tint/ast/attribute.h"
|
#include "src/tint/ast/attribute.h"
|
||||||
#include "src/tint/ast/binding_attribute.h"
|
#include "src/tint/ast/binding_attribute.h"
|
||||||
#include "src/tint/ast/expression.h"
|
#include "src/tint/ast/expression.h"
|
||||||
#include "src/tint/ast/group_attribute.h"
|
#include "src/tint/ast/group_attribute.h"
|
||||||
#include "src/tint/ast/storage_class.h"
|
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
@ -25,10 +25,10 @@ namespace {
|
|||||||
using VariableTest = TestHelper;
|
using VariableTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(VariableTest, Creation) {
|
TEST_F(VariableTest, Creation) {
|
||||||
auto* v = Var("my_var", ty.i32(), StorageClass::kFunction);
|
auto* v = Var("my_var", ty.i32(), AddressSpace::kFunction);
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class, StorageClass::kFunction);
|
EXPECT_EQ(v->declared_address_space, AddressSpace::kFunction);
|
||||||
EXPECT_TRUE(v->type->Is<ast::I32>());
|
EXPECT_TRUE(v->type->Is<ast::I32>());
|
||||||
EXPECT_EQ(v->source.range.begin.line, 0u);
|
EXPECT_EQ(v->source.range.begin.line, 0u);
|
||||||
EXPECT_EQ(v->source.range.begin.column, 0u);
|
EXPECT_EQ(v->source.range.begin.column, 0u);
|
||||||
@ -38,10 +38,10 @@ TEST_F(VariableTest, Creation) {
|
|||||||
|
|
||||||
TEST_F(VariableTest, CreationWithSource) {
|
TEST_F(VariableTest, CreationWithSource) {
|
||||||
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
|
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
|
||||||
ty.f32(), StorageClass::kPrivate, utils::Empty);
|
ty.f32(), AddressSpace::kPrivate, utils::Empty);
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate);
|
EXPECT_EQ(v->declared_address_space, AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(v->type->Is<ast::F32>());
|
EXPECT_TRUE(v->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(v->source.range.begin.line, 27u);
|
EXPECT_EQ(v->source.range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source.range.begin.column, 4u);
|
EXPECT_EQ(v->source.range.begin.column, 4u);
|
||||||
@ -51,10 +51,10 @@ TEST_F(VariableTest, CreationWithSource) {
|
|||||||
|
|
||||||
TEST_F(VariableTest, CreationEmpty) {
|
TEST_F(VariableTest, CreationEmpty) {
|
||||||
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
|
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
|
||||||
ty.i32(), StorageClass::kWorkgroup, utils::Empty);
|
ty.i32(), AddressSpace::kWorkgroup, utils::Empty);
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
EXPECT_EQ(v->symbol, Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup);
|
EXPECT_EQ(v->declared_address_space, AddressSpace::kWorkgroup);
|
||||||
EXPECT_TRUE(v->type->Is<ast::I32>());
|
EXPECT_TRUE(v->type->Is<ast::I32>());
|
||||||
EXPECT_EQ(v->source.range.begin.line, 27u);
|
EXPECT_EQ(v->source.range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source.range.begin.column, 4u);
|
EXPECT_EQ(v->source.range.begin.column, 4u);
|
||||||
@ -92,7 +92,7 @@ TEST_F(VariableTest, Assert_DifferentProgramID_Constructor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, WithAttributes) {
|
TEST_F(VariableTest, WithAttributes) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Location(1_u),
|
auto* var = Var("my_var", ty.i32(), AddressSpace::kFunction, Location(1_u),
|
||||||
Builtin(BuiltinValue::kPosition), Id(1200_u));
|
Builtin(BuiltinValue::kPosition), Id(1200_u));
|
||||||
|
|
||||||
auto& attributes = var->attributes;
|
auto& attributes = var->attributes;
|
||||||
@ -107,22 +107,22 @@ TEST_F(VariableTest, WithAttributes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, HasBindingPoint_BothProvided) {
|
TEST_F(VariableTest, HasBindingPoint_BothProvided) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2_a), Group(1_a));
|
auto* var = Var("my_var", ty.i32(), AddressSpace::kFunction, Binding(2_a), Group(1_a));
|
||||||
EXPECT_TRUE(var->HasBindingPoint());
|
EXPECT_TRUE(var->HasBindingPoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, HasBindingPoint_NeitherProvided) {
|
TEST_F(VariableTest, HasBindingPoint_NeitherProvided) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, utils::Empty);
|
auto* var = Var("my_var", ty.i32(), AddressSpace::kFunction, utils::Empty);
|
||||||
EXPECT_FALSE(var->HasBindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, HasBindingPoint_MissingGroupAttribute) {
|
TEST_F(VariableTest, HasBindingPoint_MissingGroupAttribute) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2_a));
|
auto* var = Var("my_var", ty.i32(), AddressSpace::kFunction, Binding(2_a));
|
||||||
EXPECT_FALSE(var->HasBindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, HasBindingPoint_MissingBindingAttribute) {
|
TEST_F(VariableTest, HasBindingPoint_MissingBindingAttribute) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Group(1_a));
|
auto* var = Var("my_var", ty.i32(), AddressSpace::kFunction, Group(1_a));
|
||||||
EXPECT_FALSE(var->HasBindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ fn f(b: i32) {
|
|||||||
|
|
||||||
TEST(ReplaceIdentifierTest, NotApplicable5) {
|
TEST(ReplaceIdentifierTest, NotApplicable5) {
|
||||||
// Can't replace `a` with `b` since the latter has a wrong access mode
|
// Can't replace `a` with `b` since the latter has a wrong access mode
|
||||||
// (`read` for uniform storage class).
|
// (`read` for uniform address space).
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
struct S {
|
struct S {
|
||||||
a: i32
|
a: i32
|
||||||
@ -343,7 +343,7 @@ fn f() {
|
|||||||
|
|
||||||
TEST(ReplaceIdentifierTest, NotApplicable8) {
|
TEST(ReplaceIdentifierTest, NotApplicable8) {
|
||||||
// Can't replace `ptr_b` with `c` since the latter has a wrong access mode and
|
// Can't replace `ptr_b` with `c` since the latter has a wrong access mode and
|
||||||
// storage class.
|
// address space.
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
struct S {
|
struct S {
|
||||||
a: i32
|
a: i32
|
||||||
@ -451,7 +451,7 @@ fn f() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ReplaceIdentifierTest, Applicable1) {
|
TEST(ReplaceIdentifierTest, Applicable1) {
|
||||||
// Can replace `a` with `b` (same storage class).
|
// Can replace `a` with `b` (same address space).
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
fn f() {
|
fn f() {
|
||||||
var b : vec2<u32>;
|
var b : vec2<u32>;
|
||||||
@ -611,7 +611,7 @@ fn f() {
|
|||||||
|
|
||||||
TEST(ReplaceIdentifierTest, NotApplicable14) {
|
TEST(ReplaceIdentifierTest, NotApplicable14) {
|
||||||
// Can't replace `ptr_a` with `ptr_b` (both are pointers with different
|
// Can't replace `ptr_a` with `ptr_b` (both are pointers with different
|
||||||
// storage class).
|
// address space).
|
||||||
std::string shader = R"(
|
std::string shader = R"(
|
||||||
var<private> b: vec2<u32>;
|
var<private> b: vec2<u32>;
|
||||||
fn f() {
|
fn f() {
|
||||||
|
@ -565,7 +565,7 @@ uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) {
|
|||||||
uint32_t total_size = 0;
|
uint32_t total_size = 0;
|
||||||
auto* func_sem = program_->Sem().Get(func);
|
auto* func_sem = program_->Sem().Get(func);
|
||||||
for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
|
for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
|
||||||
if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
|
if (var->AddressSpace() == ast::AddressSpace::kWorkgroup) {
|
||||||
auto* ty = var->Type()->UnwrapRef();
|
auto* ty = var->Type()->UnwrapRef();
|
||||||
uint32_t align = ty->Align();
|
uint32_t align = ty->Align();
|
||||||
uint32_t size = ty->Size();
|
uint32_t size = ty->Size();
|
||||||
|
@ -126,11 +126,11 @@ void InspectorBuilder::AddUniformBuffer(const std::string& name,
|
|||||||
const ast::Type* type,
|
const ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
GlobalVar(name, type, ast::StorageClass::kUniform, Binding(AInt(binding)), Group(AInt(group)));
|
GlobalVar(name, type, ast::AddressSpace::kUniform, Binding(AInt(binding)), Group(AInt(group)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InspectorBuilder::AddWorkgroupStorage(const std::string& name, const ast::Type* type) {
|
void InspectorBuilder::AddWorkgroupStorage(const std::string& name, const ast::Type* type) {
|
||||||
GlobalVar(name, type, ast::StorageClass::kWorkgroup);
|
GlobalVar(name, type, ast::AddressSpace::kWorkgroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InspectorBuilder::AddStorageBuffer(const std::string& name,
|
void InspectorBuilder::AddStorageBuffer(const std::string& name,
|
||||||
@ -138,7 +138,7 @@ void InspectorBuilder::AddStorageBuffer(const std::string& name,
|
|||||||
ast::Access access,
|
ast::Access access,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
GlobalVar(name, type, ast::StorageClass::kStorage, access, Binding(AInt(binding)),
|
GlobalVar(name, type, ast::AddressSpace::kStorage, access, Binding(AInt(binding)),
|
||||||
Group(AInt(group)));
|
Group(AInt(group)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ void InspectorBuilder::AddResource(const std::string& name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InspectorBuilder::AddGlobalVariable(const std::string& name, const ast::Type* type) {
|
void InspectorBuilder::AddGlobalVariable(const std::string& name, const ast::Type* type) {
|
||||||
GlobalVar(name, type, ast::StorageClass::kPrivate);
|
GlobalVar(name, type, ast::AddressSpace::kPrivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
|
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
|
||||||
|
@ -54,7 +54,7 @@ enum extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
||||||
enum storage_class {
|
enum address_space {
|
||||||
@internal none
|
@internal none
|
||||||
function
|
function
|
||||||
private
|
private
|
||||||
@ -125,7 +125,7 @@ type mat4x3<T>
|
|||||||
type mat4x4<T>
|
type mat4x4<T>
|
||||||
@display("vec{N}<{T}>") type vec<N: num, T>
|
@display("vec{N}<{T}>") type vec<N: num, T>
|
||||||
@display("mat{N}x{M}<{T}>") type mat<N: num, M: num, T>
|
@display("mat{N}x{M}<{T}>") type mat<N: num, M: num, T>
|
||||||
type ptr<S: storage_class, T, A: access>
|
type ptr<S: address_space, T, A: access>
|
||||||
type atomic<T>
|
type atomic<T>
|
||||||
type array<T>
|
type array<T>
|
||||||
type sampler
|
type sampler
|
||||||
@ -214,14 +214,14 @@ match write: access.write
|
|||||||
match read_write: access.read_write
|
match read_write: access.read_write
|
||||||
|
|
||||||
match function_private_workgroup
|
match function_private_workgroup
|
||||||
: storage_class.function
|
: address_space.function
|
||||||
| storage_class.private
|
| address_space.private
|
||||||
| storage_class.workgroup
|
| address_space.workgroup
|
||||||
match workgroup_or_storage
|
match workgroup_or_storage
|
||||||
: storage_class.workgroup
|
: address_space.workgroup
|
||||||
| storage_class.storage
|
| address_space.storage
|
||||||
match storage
|
match storage
|
||||||
: storage_class.storage
|
: address_space.storage
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Builtin Functions //
|
// Builtin Functions //
|
||||||
|
@ -172,14 +172,14 @@ class ProgramBuilder {
|
|||||||
~VarOptions();
|
~VarOptions();
|
||||||
|
|
||||||
const ast::Type* type = nullptr;
|
const ast::Type* type = nullptr;
|
||||||
ast::StorageClass storage = ast::StorageClass::kNone;
|
ast::AddressSpace address_space = ast::AddressSpace::kNone;
|
||||||
ast::Access access = ast::Access::kUndefined;
|
ast::Access access = ast::Access::kUndefined;
|
||||||
const ast::Expression* constructor = nullptr;
|
const ast::Expression* constructor = nullptr;
|
||||||
utils::Vector<const ast::Attribute*, 4> attributes;
|
utils::Vector<const ast::Attribute*, 4> attributes;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Set(const ast::Type* t) { type = t; }
|
void Set(const ast::Type* t) { type = t; }
|
||||||
void Set(ast::StorageClass sc) { storage = sc; }
|
void Set(ast::AddressSpace addr_space) { address_space = addr_space; }
|
||||||
void Set(ast::Access ac) { access = ac; }
|
void Set(ast::Access ac) { access = ac; }
|
||||||
void Set(const ast::Expression* c) { constructor = c; }
|
void Set(const ast::Expression* c) { constructor = c; }
|
||||||
void Set(utils::VectorRef<const ast::Attribute*> l) { attributes = std::move(l); }
|
void Set(utils::VectorRef<const ast::Attribute*> l) { attributes = std::move(l); }
|
||||||
@ -902,45 +902,45 @@ class ProgramBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @param type the type of the pointer
|
/// @param type the type of the pointer
|
||||||
/// @param storage_class the storage class of the pointer
|
/// @param address_space the address space of the pointer
|
||||||
/// @param access the optional access control of the pointer
|
/// @param access the optional access control of the pointer
|
||||||
/// @return the pointer to `type` with the given ast::StorageClass
|
/// @return the pointer to `type` with the given ast::AddressSpace
|
||||||
const ast::Pointer* pointer(const ast::Type* type,
|
const ast::Pointer* pointer(const ast::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
ast::Access access = ast::Access::kUndefined) const {
|
ast::Access access = ast::Access::kUndefined) const {
|
||||||
return builder->create<ast::Pointer>(type, storage_class, access);
|
return builder->create<ast::Pointer>(type, address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param source the Source of the node
|
/// @param source the Source of the node
|
||||||
/// @param type the type of the pointer
|
/// @param type the type of the pointer
|
||||||
/// @param storage_class the storage class of the pointer
|
/// @param address_space the address space of the pointer
|
||||||
/// @param access the optional access control of the pointer
|
/// @param access the optional access control of the pointer
|
||||||
/// @return the pointer to `type` with the given ast::StorageClass
|
/// @return the pointer to `type` with the given ast::AddressSpace
|
||||||
const ast::Pointer* pointer(const Source& source,
|
const ast::Pointer* pointer(const Source& source,
|
||||||
const ast::Type* type,
|
const ast::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
ast::Access access = ast::Access::kUndefined) const {
|
ast::Access access = ast::Access::kUndefined) const {
|
||||||
return builder->create<ast::Pointer>(source, type, storage_class, access);
|
return builder->create<ast::Pointer>(source, type, address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param storage_class the storage class of the pointer
|
/// @param address_space the address space of the pointer
|
||||||
/// @param access the optional access control of the pointer
|
/// @param access the optional access control of the pointer
|
||||||
/// @return the pointer to type `T` with the given ast::StorageClass.
|
/// @return the pointer to type `T` with the given ast::AddressSpace.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const ast::Pointer* pointer(ast::StorageClass storage_class,
|
const ast::Pointer* pointer(ast::AddressSpace address_space,
|
||||||
ast::Access access = ast::Access::kUndefined) const {
|
ast::Access access = ast::Access::kUndefined) const {
|
||||||
return pointer(Of<T>(), storage_class, access);
|
return pointer(Of<T>(), address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param source the Source of the node
|
/// @param source the Source of the node
|
||||||
/// @param storage_class the storage class of the pointer
|
/// @param address_space the address space of the pointer
|
||||||
/// @param access the optional access control of the pointer
|
/// @param access the optional access control of the pointer
|
||||||
/// @return the pointer to type `T` with the given ast::StorageClass.
|
/// @return the pointer to type `T` with the given ast::AddressSpace.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const ast::Pointer* pointer(const Source& source,
|
const ast::Pointer* pointer(const Source& source,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
ast::Access access = ast::Access::kUndefined) const {
|
ast::Access access = ast::Access::kUndefined) const {
|
||||||
return pointer(source, Of<T>(), storage_class, access);
|
return pointer(source, Of<T>(), address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param source the Source of the node
|
/// @param source the Source of the node
|
||||||
@ -1651,7 +1651,7 @@ class ProgramBuilder {
|
|||||||
/// @param options the extra options passed to the ast::Var constructor
|
/// @param options the extra options passed to the ast::Var constructor
|
||||||
/// Can be any of the following, in any order:
|
/// Can be any of the following, in any order:
|
||||||
/// * ast::Type* - specifies the variable type
|
/// * ast::Type* - specifies the variable type
|
||||||
/// * ast::StorageClass - specifies the variable storage class
|
/// * ast::AddressSpace - specifies the variable address space
|
||||||
/// * ast::Access - specifies the variable's access control
|
/// * ast::Access - specifies the variable's access control
|
||||||
/// * ast::Expression* - specifies the variable's initializer expression
|
/// * ast::Expression* - specifies the variable's initializer expression
|
||||||
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
||||||
@ -1661,8 +1661,8 @@ class ProgramBuilder {
|
|||||||
template <typename NAME, typename... OPTIONS, typename = DisableIfSource<NAME>>
|
template <typename NAME, typename... OPTIONS, typename = DisableIfSource<NAME>>
|
||||||
const ast::Var* Var(NAME&& name, OPTIONS&&... options) {
|
const ast::Var* Var(NAME&& name, OPTIONS&&... options) {
|
||||||
VarOptions opts(std::forward<OPTIONS>(options)...);
|
VarOptions opts(std::forward<OPTIONS>(options)...);
|
||||||
return create<ast::Var>(Sym(std::forward<NAME>(name)), opts.type, opts.storage, opts.access,
|
return create<ast::Var>(Sym(std::forward<NAME>(name)), opts.type, opts.address_space,
|
||||||
opts.constructor, std::move(opts.attributes));
|
opts.access, opts.constructor, std::move(opts.attributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param source the variable source
|
/// @param source the variable source
|
||||||
@ -1670,17 +1670,18 @@ class ProgramBuilder {
|
|||||||
/// @param options the extra options passed to the ast::Var constructor
|
/// @param options the extra options passed to the ast::Var constructor
|
||||||
/// Can be any of the following, in any order:
|
/// Can be any of the following, in any order:
|
||||||
/// * ast::Type* - specifies the variable type
|
/// * ast::Type* - specifies the variable type
|
||||||
/// * ast::StorageClass - specifies the variable storage class
|
/// * ast::AddressSpace - specifies the variable address space
|
||||||
/// * ast::Access - specifies the variable's access control
|
/// * ast::Access - specifies the variable's access control
|
||||||
/// * ast::Expression* - specifies the variable's initializer expression
|
/// * ast::Expression* - specifies the variable's initializer expression
|
||||||
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
||||||
/// Note that non-repeatable arguments of the same type will use the last argument's value.
|
/// Note that non-repeatable arguments of the same type will use the last argument's value.
|
||||||
/// @returns a `ast::Var` with the given name, storage and type
|
/// @returns a `ast::Var` with the given name, address_space and type
|
||||||
template <typename NAME, typename... OPTIONS>
|
template <typename NAME, typename... OPTIONS>
|
||||||
const ast::Var* Var(const Source& source, NAME&& name, OPTIONS&&... options) {
|
const ast::Var* Var(const Source& source, NAME&& name, OPTIONS&&... options) {
|
||||||
VarOptions opts(std::forward<OPTIONS>(options)...);
|
VarOptions opts(std::forward<OPTIONS>(options)...);
|
||||||
return create<ast::Var>(source, Sym(std::forward<NAME>(name)), opts.type, opts.storage,
|
return create<ast::Var>(source, Sym(std::forward<NAME>(name)), opts.type,
|
||||||
opts.access, opts.constructor, std::move(opts.attributes));
|
opts.address_space, opts.access, opts.constructor,
|
||||||
|
std::move(opts.attributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param name the variable name
|
/// @param name the variable name
|
||||||
@ -1773,7 +1774,7 @@ class ProgramBuilder {
|
|||||||
/// @param options the extra options passed to the ast::Var constructor
|
/// @param options the extra options passed to the ast::Var constructor
|
||||||
/// Can be any of the following, in any order:
|
/// Can be any of the following, in any order:
|
||||||
/// * ast::Type* - specifies the variable type
|
/// * ast::Type* - specifies the variable type
|
||||||
/// * ast::StorageClass - specifies the variable storage class
|
/// * ast::AddressSpace - specifies the variable address space
|
||||||
/// * ast::Access - specifies the variable's access control
|
/// * ast::Access - specifies the variable's access control
|
||||||
/// * ast::Expression* - specifies the variable's initializer expression
|
/// * ast::Expression* - specifies the variable's initializer expression
|
||||||
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
||||||
@ -1792,7 +1793,7 @@ class ProgramBuilder {
|
|||||||
/// @param options the extra options passed to the ast::Var constructor
|
/// @param options the extra options passed to the ast::Var constructor
|
||||||
/// Can be any of the following, in any order:
|
/// Can be any of the following, in any order:
|
||||||
/// * ast::Type* - specifies the variable type
|
/// * ast::Type* - specifies the variable type
|
||||||
/// * ast::StorageClass - specifies the variable storage class
|
/// * ast::AddressSpace - specifies the variable address space
|
||||||
/// * ast::Access - specifies the variable's access control
|
/// * ast::Access - specifies the variable's access control
|
||||||
/// * ast::Expression* - specifies the variable's initializer expression
|
/// * ast::Expression* - specifies the variable's initializer expression
|
||||||
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
/// * ast::Attribute* - specifies the variable's attributes (repeatable, or vector)
|
||||||
|
@ -46,7 +46,7 @@ TEST_F(ProgramTest, IDsAreUnique) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, Assert_GlobalVariable) {
|
TEST_F(ProgramTest, Assert_GlobalVariable) {
|
||||||
GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
Program program(std::move(*this));
|
Program program(std::move(*this));
|
||||||
EXPECT_TRUE(program.IsValid());
|
EXPECT_TRUE(program.IsValid());
|
||||||
|
@ -36,30 +36,30 @@ ast::PipelineStage EnumConverter::ToPipelineStage(SpvExecutionModel model) {
|
|||||||
return ast::PipelineStage::kNone;
|
return ast::PipelineStage::kNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
|
ast::AddressSpace EnumConverter::ToAddressSpace(const SpvStorageClass sc) {
|
||||||
switch (sc) {
|
switch (sc) {
|
||||||
case SpvStorageClassInput:
|
case SpvStorageClassInput:
|
||||||
return ast::StorageClass::kIn;
|
return ast::AddressSpace::kIn;
|
||||||
case SpvStorageClassOutput:
|
case SpvStorageClassOutput:
|
||||||
return ast::StorageClass::kOut;
|
return ast::AddressSpace::kOut;
|
||||||
case SpvStorageClassUniform:
|
case SpvStorageClassUniform:
|
||||||
return ast::StorageClass::kUniform;
|
return ast::AddressSpace::kUniform;
|
||||||
case SpvStorageClassWorkgroup:
|
case SpvStorageClassWorkgroup:
|
||||||
return ast::StorageClass::kWorkgroup;
|
return ast::AddressSpace::kWorkgroup;
|
||||||
case SpvStorageClassUniformConstant:
|
case SpvStorageClassUniformConstant:
|
||||||
return ast::StorageClass::kNone;
|
return ast::AddressSpace::kNone;
|
||||||
case SpvStorageClassStorageBuffer:
|
case SpvStorageClassStorageBuffer:
|
||||||
return ast::StorageClass::kStorage;
|
return ast::AddressSpace::kStorage;
|
||||||
case SpvStorageClassPrivate:
|
case SpvStorageClassPrivate:
|
||||||
return ast::StorageClass::kPrivate;
|
return ast::AddressSpace::kPrivate;
|
||||||
case SpvStorageClassFunction:
|
case SpvStorageClassFunction:
|
||||||
return ast::StorageClass::kFunction;
|
return ast::AddressSpace::kFunction;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
|
Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
|
||||||
return ast::StorageClass::kInvalid;
|
return ast::AddressSpace::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::BuiltinValue EnumConverter::ToBuiltin(SpvBuiltIn b) {
|
ast::BuiltinValue EnumConverter::ToBuiltin(SpvBuiltIn b) {
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
#define SRC_TINT_READER_SPIRV_ENUM_CONVERTER_H_
|
#define SRC_TINT_READER_SPIRV_ENUM_CONVERTER_H_
|
||||||
|
|
||||||
#include "spirv/unified1/spirv.h"
|
#include "spirv/unified1/spirv.h"
|
||||||
|
#include "src/tint/ast/address_space.h"
|
||||||
#include "src/tint/ast/builtin_value.h"
|
#include "src/tint/ast/builtin_value.h"
|
||||||
#include "src/tint/ast/pipeline_stage.h"
|
#include "src/tint/ast/pipeline_stage.h"
|
||||||
#include "src/tint/ast/storage_class.h"
|
|
||||||
#include "src/tint/reader/spirv/fail_stream.h"
|
#include "src/tint/reader/spirv/fail_stream.h"
|
||||||
#include "src/tint/sem/storage_texture.h"
|
#include "src/tint/sem/storage_texture.h"
|
||||||
|
|
||||||
@ -39,11 +39,11 @@ class EnumConverter {
|
|||||||
/// @returns a Tint AST pipeline stage
|
/// @returns a Tint AST pipeline stage
|
||||||
ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
|
ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
|
||||||
|
|
||||||
/// Converts a SPIR-V storage class to a Tint storage class.
|
/// Converts a SPIR-V storage class to a Tint address space.
|
||||||
/// On failure, logs an error and returns kNone
|
/// On failure, logs an error and returns kNone
|
||||||
/// @param sc the SPIR-V storage class
|
/// @param sc the SPIR-V storage class
|
||||||
/// @returns a Tint AST storage class
|
/// @returns a Tint AST address space
|
||||||
ast::StorageClass ToStorageClass(const SpvStorageClass sc);
|
ast::AddressSpace ToAddressSpace(const SpvStorageClass sc);
|
||||||
|
|
||||||
/// Converts a SPIR-V Builtin value a Tint Builtin.
|
/// Converts a SPIR-V Builtin value a Tint Builtin.
|
||||||
/// On failure, logs an error and returns kNone
|
/// On failure, logs an error and returns kNone
|
||||||
|
@ -84,7 +84,7 @@ INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
|
|||||||
struct StorageClassCase {
|
struct StorageClassCase {
|
||||||
SpvStorageClass sc;
|
SpvStorageClass sc;
|
||||||
bool expect_success;
|
bool expect_success;
|
||||||
ast::StorageClass expected;
|
ast::AddressSpace expected;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
|
inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
|
||||||
out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
|
out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
|
||||||
@ -110,7 +110,7 @@ class SpvStorageClassTest : public testing::TestWithParam<StorageClassCase> {
|
|||||||
TEST_P(SpvStorageClassTest, Samples) {
|
TEST_P(SpvStorageClassTest, Samples) {
|
||||||
const auto params = GetParam();
|
const auto params = GetParam();
|
||||||
|
|
||||||
const auto result = converter_.ToStorageClass(params.sc);
|
const auto result = converter_.ToAddressSpace(params.sc);
|
||||||
EXPECT_EQ(success_, params.expect_success);
|
EXPECT_EQ(success_, params.expect_success);
|
||||||
if (params.expect_success) {
|
if (params.expect_success) {
|
||||||
EXPECT_EQ(result, params.expected);
|
EXPECT_EQ(result, params.expected);
|
||||||
@ -125,19 +125,19 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
EnumConverterGood,
|
EnumConverterGood,
|
||||||
SpvStorageClassTest,
|
SpvStorageClassTest,
|
||||||
testing::Values(
|
testing::Values(
|
||||||
StorageClassCase{SpvStorageClassInput, true, ast::StorageClass::kIn},
|
StorageClassCase{SpvStorageClassInput, true, ast::AddressSpace::kIn},
|
||||||
StorageClassCase{SpvStorageClassOutput, true, ast::StorageClass::kOut},
|
StorageClassCase{SpvStorageClassOutput, true, ast::AddressSpace::kOut},
|
||||||
StorageClassCase{SpvStorageClassUniform, true, ast::StorageClass::kUniform},
|
StorageClassCase{SpvStorageClassUniform, true, ast::AddressSpace::kUniform},
|
||||||
StorageClassCase{SpvStorageClassWorkgroup, true, ast::StorageClass::kWorkgroup},
|
StorageClassCase{SpvStorageClassWorkgroup, true, ast::AddressSpace::kWorkgroup},
|
||||||
StorageClassCase{SpvStorageClassUniformConstant, true, ast::StorageClass::kNone},
|
StorageClassCase{SpvStorageClassUniformConstant, true, ast::AddressSpace::kNone},
|
||||||
StorageClassCase{SpvStorageClassStorageBuffer, true, ast::StorageClass::kStorage},
|
StorageClassCase{SpvStorageClassStorageBuffer, true, ast::AddressSpace::kStorage},
|
||||||
StorageClassCase{SpvStorageClassPrivate, true, ast::StorageClass::kPrivate},
|
StorageClassCase{SpvStorageClassPrivate, true, ast::AddressSpace::kPrivate},
|
||||||
StorageClassCase{SpvStorageClassFunction, true, ast::StorageClass::kFunction}));
|
StorageClassCase{SpvStorageClassFunction, true, ast::AddressSpace::kFunction}));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
|
INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
|
||||||
SpvStorageClassTest,
|
SpvStorageClassTest,
|
||||||
testing::Values(StorageClassCase{static_cast<SpvStorageClass>(9999), false,
|
testing::Values(StorageClassCase{static_cast<SpvStorageClass>(9999), false,
|
||||||
ast::StorageClass::kInvalid}));
|
ast::AddressSpace::kInvalid}));
|
||||||
|
|
||||||
// Builtin
|
// Builtin
|
||||||
|
|
||||||
|
@ -2500,11 +2500,11 @@ bool FunctionEmitter::EmitFunctionVariables() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto* var = parser_impl_.MakeVar(inst.result_id(), ast::StorageClass::kNone, var_store_type,
|
auto* var = parser_impl_.MakeVar(inst.result_id(), ast::AddressSpace::kNone, var_store_type,
|
||||||
constructor, AttributeList{});
|
constructor, AttributeList{});
|
||||||
auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
|
auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
|
||||||
AddStatement(var_decl_stmt);
|
AddStatement(var_decl_stmt);
|
||||||
auto* var_type = ty_.Reference(var_store_type, ast::StorageClass::kNone);
|
auto* var_type = ty_.Reference(var_store_type, ast::AddressSpace::kNone);
|
||||||
identifier_types_.emplace(inst.result_id(), var_type);
|
identifier_types_.emplace(inst.result_id(), var_type);
|
||||||
}
|
}
|
||||||
return success();
|
return success();
|
||||||
@ -3356,11 +3356,11 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
|
|||||||
for (auto id : sorted_by_index(block_info.hoisted_ids)) {
|
for (auto id : sorted_by_index(block_info.hoisted_ids)) {
|
||||||
const auto* def_inst = def_use_mgr_->GetDef(id);
|
const auto* def_inst = def_use_mgr_->GetDef(id);
|
||||||
TINT_ASSERT(Reader, def_inst);
|
TINT_ASSERT(Reader, def_inst);
|
||||||
auto* storage_type = RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
|
auto* storage_type = RemapAddressSpace(parser_impl_.ConvertType(def_inst->type_id()), id);
|
||||||
AddStatement(create<ast::VariableDeclStatement>(
|
AddStatement(create<ast::VariableDeclStatement>(
|
||||||
Source{}, parser_impl_.MakeVar(id, ast::StorageClass::kNone, storage_type, nullptr,
|
Source{}, parser_impl_.MakeVar(id, ast::AddressSpace::kNone, storage_type, nullptr,
|
||||||
AttributeList{})));
|
AttributeList{})));
|
||||||
auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
|
auto* type = ty_.Reference(storage_type, ast::AddressSpace::kNone);
|
||||||
identifier_types_.emplace(id, type);
|
identifier_types_.emplace(id, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3720,7 +3720,7 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||||||
if (!expr) {
|
if (!expr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
expr.type = RemapStorageClass(expr.type, result_id);
|
expr.type = RemapAddressSpace(expr.type, result_id);
|
||||||
return EmitConstDefOrWriteToHoistedVar(inst, expr);
|
return EmitConstDefOrWriteToHoistedVar(inst, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3777,15 +3777,15 @@ TypedExpression FunctionEmitter::MakeOperand(const spvtools::opt::Instruction& i
|
|||||||
return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
|
return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedExpression FunctionEmitter::InferFunctionStorageClass(TypedExpression expr) {
|
TypedExpression FunctionEmitter::InferFunctionAddressSpace(TypedExpression expr) {
|
||||||
TypedExpression result(expr);
|
TypedExpression result(expr);
|
||||||
if (const auto* ref = expr.type->UnwrapAlias()->As<Reference>()) {
|
if (const auto* ref = expr.type->UnwrapAlias()->As<Reference>()) {
|
||||||
if (ref->storage_class == ast::StorageClass::kNone) {
|
if (ref->address_space == ast::AddressSpace::kNone) {
|
||||||
expr.type = ty_.Reference(ref->type, ast::StorageClass::kFunction);
|
expr.type = ty_.Reference(ref->type, ast::AddressSpace::kFunction);
|
||||||
}
|
}
|
||||||
} else if (const auto* ptr = expr.type->UnwrapAlias()->As<Pointer>()) {
|
} else if (const auto* ptr = expr.type->UnwrapAlias()->As<Pointer>()) {
|
||||||
if (ptr->storage_class == ast::StorageClass::kNone) {
|
if (ptr->address_space == ast::AddressSpace::kNone) {
|
||||||
expr.type = ty_.Pointer(ptr->type, ast::StorageClass::kFunction);
|
expr.type = ty_.Pointer(ptr->type, ast::AddressSpace::kFunction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
@ -4418,7 +4418,7 @@ TypedExpression FunctionEmitter::MakeAccessChain(const spvtools::opt::Instructio
|
|||||||
// ever-deeper nested indexing expressions. Start off with an expression
|
// ever-deeper nested indexing expressions. Start off with an expression
|
||||||
// for the base, and then bury that inside nested indexing expressions.
|
// for the base, and then bury that inside nested indexing expressions.
|
||||||
if (!current_expr) {
|
if (!current_expr) {
|
||||||
current_expr = InferFunctionStorageClass(MakeOperand(inst, 0));
|
current_expr = InferFunctionAddressSpace(MakeOperand(inst, 0));
|
||||||
if (current_expr.type->Is<Pointer>()) {
|
if (current_expr.type->Is<Pointer>()) {
|
||||||
current_expr = Dereference(current_expr);
|
current_expr = Dereference(current_expr);
|
||||||
}
|
}
|
||||||
@ -4430,7 +4430,7 @@ TypedExpression FunctionEmitter::MakeAccessChain(const spvtools::opt::Instructio
|
|||||||
Fail() << "Access chain %" << inst.result_id() << " base pointer is not of pointer type";
|
Fail() << "Access chain %" << inst.result_id() << " base pointer is not of pointer type";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
SpvStorageClass storage_class =
|
SpvStorageClass address_space =
|
||||||
static_cast<SpvStorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
|
static_cast<SpvStorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
|
||||||
uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
|
uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
|
||||||
|
|
||||||
@ -4521,7 +4521,7 @@ TypedExpression FunctionEmitter::MakeAccessChain(const spvtools::opt::Instructio
|
|||||||
<< ": " << pointee_type_inst->PrettyPrint();
|
<< ": " << pointee_type_inst->PrettyPrint();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const auto pointer_type_id = type_mgr_->FindPointerToType(pointee_type_id, storage_class);
|
const auto pointer_type_id = type_mgr_->FindPointerToType(pointee_type_id, address_space);
|
||||||
auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
|
auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
|
||||||
TINT_ASSERT(Reader, type && type->Is<Reference>());
|
TINT_ASSERT(Reader, type && type->Is<Reference>());
|
||||||
current_expr = TypedExpression{type, next_expr};
|
current_expr = TypedExpression{type, next_expr};
|
||||||
@ -4799,8 +4799,8 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||||||
++index;
|
++index;
|
||||||
auto& info = def_info_[result_id];
|
auto& info = def_info_[result_id];
|
||||||
|
|
||||||
// Determine storage class for pointer values. Do this in order because
|
// Determine address space for pointer values. Do this in order because
|
||||||
// we might rely on the storage class for a previously-visited definition.
|
// we might rely on the address space for a previously-visited definition.
|
||||||
// Logical pointers can't be transmitted through OpPhi, so remaining
|
// Logical pointers can't be transmitted through OpPhi, so remaining
|
||||||
// pointer definitions are SSA values, and their definitions must be
|
// pointer definitions are SSA values, and their definitions must be
|
||||||
// visited before their uses.
|
// visited before their uses.
|
||||||
@ -4809,7 +4809,7 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||||||
if (type->AsPointer()) {
|
if (type->AsPointer()) {
|
||||||
if (auto* ast_type = parser_impl_.ConvertType(inst.type_id())) {
|
if (auto* ast_type = parser_impl_.ConvertType(inst.type_id())) {
|
||||||
if (auto* ptr = ast_type->As<Pointer>()) {
|
if (auto* ptr = ast_type->As<Pointer>()) {
|
||||||
info->storage_class = ptr->storage_class;
|
info->address_space = ptr->address_space;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (inst.opcode()) {
|
switch (inst.opcode()) {
|
||||||
@ -4823,8 +4823,8 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||||||
case SpvOpCopyObject:
|
case SpvOpCopyObject:
|
||||||
// Inherit from the first operand. We need this so we can pick up
|
// Inherit from the first operand. We need this so we can pick up
|
||||||
// a remapped storage buffer.
|
// a remapped storage buffer.
|
||||||
info->storage_class =
|
info->address_space =
|
||||||
GetStorageClassForPointerValue(inst.GetSingleWordInOperand(0));
|
GetAddressSpaceForPointerValue(inst.GetSingleWordInOperand(0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return Fail() << "pointer defined in function from unknown opcode: "
|
return Fail() << "pointer defined in function from unknown opcode: "
|
||||||
@ -4846,11 +4846,11 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::StorageClass FunctionEmitter::GetStorageClassForPointerValue(uint32_t id) {
|
ast::AddressSpace FunctionEmitter::GetAddressSpaceForPointerValue(uint32_t id) {
|
||||||
auto where = def_info_.find(id);
|
auto where = def_info_.find(id);
|
||||||
if (where != def_info_.end()) {
|
if (where != def_info_.end()) {
|
||||||
auto candidate = where->second.get()->storage_class;
|
auto candidate = where->second.get()->address_space;
|
||||||
if (candidate != ast::StorageClass::kInvalid) {
|
if (candidate != ast::AddressSpace::kInvalid) {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4858,19 +4858,19 @@ ast::StorageClass FunctionEmitter::GetStorageClassForPointerValue(uint32_t id) {
|
|||||||
if (type_id) {
|
if (type_id) {
|
||||||
auto* ast_type = parser_impl_.ConvertType(type_id);
|
auto* ast_type = parser_impl_.ConvertType(type_id);
|
||||||
if (auto* ptr = As<Pointer>(ast_type)) {
|
if (auto* ptr = As<Pointer>(ast_type)) {
|
||||||
return ptr->storage_class;
|
return ptr->address_space;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast::StorageClass::kInvalid;
|
return ast::AddressSpace::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type* FunctionEmitter::RemapStorageClass(const Type* type, uint32_t result_id) {
|
const Type* FunctionEmitter::RemapAddressSpace(const Type* type, uint32_t result_id) {
|
||||||
if (auto* ast_ptr_type = As<Pointer>(type)) {
|
if (auto* ast_ptr_type = As<Pointer>(type)) {
|
||||||
// Remap an old-style storage buffer pointer to a new-style storage
|
// Remap an old-style storage buffer pointer to a new-style storage
|
||||||
// buffer pointer.
|
// buffer pointer.
|
||||||
const auto sc = GetStorageClassForPointerValue(result_id);
|
const auto addr_space = GetAddressSpaceForPointerValue(result_id);
|
||||||
if (ast_ptr_type->storage_class != sc) {
|
if (ast_ptr_type->address_space != addr_space) {
|
||||||
return ty_.Pointer(ast_ptr_type->type, sc);
|
return ty_.Pointer(ast_ptr_type->type, addr_space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
@ -5053,7 +5053,7 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
|
|||||||
// Avoid moving combinatorial values across constructs. This is a
|
// Avoid moving combinatorial values across constructs. This is a
|
||||||
// simple heuristic to avoid changing the cost of an operation
|
// simple heuristic to avoid changing the cost of an operation
|
||||||
// by moving it into or out of a loop, for example.
|
// by moving it into or out of a loop, for example.
|
||||||
if ((def_info->storage_class == ast::StorageClass::kInvalid) &&
|
if ((def_info->address_space == ast::AddressSpace::kInvalid) &&
|
||||||
local_def.used_in_another_construct) {
|
local_def.used_in_another_construct) {
|
||||||
should_hoist_to_let = true;
|
should_hoist_to_let = true;
|
||||||
}
|
}
|
||||||
@ -6170,7 +6170,7 @@ bool FunctionEmitter::MakeVectorInsertDynamic(const spvtools::opt::Instruction&
|
|||||||
// API in parser_impl_.
|
// API in parser_impl_.
|
||||||
var_name = namer_.MakeDerivedName(original_value_name);
|
var_name = namer_.MakeDerivedName(original_value_name);
|
||||||
|
|
||||||
auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::StorageClass::kNone,
|
auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::AddressSpace::kNone,
|
||||||
src_vector.expr);
|
src_vector.expr);
|
||||||
|
|
||||||
AddStatement(builder_.Decl({}, temp_var));
|
AddStatement(builder_.Decl({}, temp_var));
|
||||||
@ -6240,7 +6240,7 @@ bool FunctionEmitter::MakeCompositeInsert(const spvtools::opt::Instruction& inst
|
|||||||
// It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
|
// It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
|
||||||
// API in parser_impl_.
|
// API in parser_impl_.
|
||||||
var_name = namer_.MakeDerivedName(original_value_name);
|
var_name = namer_.MakeDerivedName(original_value_name);
|
||||||
auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::StorageClass::kNone,
|
auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::AddressSpace::kNone,
|
||||||
src_composite.expr);
|
src_composite.expr);
|
||||||
AddStatement(builder_.Decl({}, temp_var));
|
AddStatement(builder_.Decl({}, temp_var));
|
||||||
}
|
}
|
||||||
@ -6271,7 +6271,7 @@ TypedExpression FunctionEmitter::AddressOf(TypedExpression expr) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ty_.Pointer(ref->type, ref->storage_class),
|
ty_.Pointer(ref->type, ref->address_space),
|
||||||
create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kAddressOf, expr.expr),
|
create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kAddressOf, expr.expr),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -325,12 +325,12 @@ struct DefInfo {
|
|||||||
/// example, pointers. crbug.com/tint/98
|
/// example, pointers. crbug.com/tint/98
|
||||||
bool requires_hoisted_var_def = false;
|
bool requires_hoisted_var_def = false;
|
||||||
|
|
||||||
/// The storage class to use for this value, if it is of pointer type.
|
/// The address space to use for this value, if it is of pointer type.
|
||||||
/// This is required to carry a storage class override from a storage
|
/// This is required to carry an address space override from a storage
|
||||||
/// buffer expressed in the old style (with Uniform storage class)
|
/// buffer expressed in the old style (with Uniform address space)
|
||||||
/// that needs to be remapped to StorageBuffer storage class.
|
/// that needs to be remapped to StorageBuffer address space.
|
||||||
/// This is kInvalid for non-pointers.
|
/// This is kInvalid for non-pointers.
|
||||||
ast::StorageClass storage_class = ast::StorageClass::kInvalid;
|
ast::AddressSpace address_space = ast::AddressSpace::kInvalid;
|
||||||
|
|
||||||
/// The expression to use when sinking pointers into their use.
|
/// The expression to use when sinking pointers into their use.
|
||||||
/// When encountering a use of this instruction, we will emit this expression
|
/// When encountering a use of this instruction, we will emit this expression
|
||||||
@ -360,8 +360,8 @@ inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
|
|||||||
}
|
}
|
||||||
o << " requires_named_let_def: " << (di.requires_named_let_def ? "true" : "false")
|
o << " requires_named_let_def: " << (di.requires_named_let_def ? "true" : "false")
|
||||||
<< " requires_hoisted_var_def: " << (di.requires_hoisted_var_def ? "true" : "false");
|
<< " requires_hoisted_var_def: " << (di.requires_hoisted_var_def ? "true" : "false");
|
||||||
if (di.storage_class != ast::StorageClass::kNone) {
|
if (di.address_space != ast::AddressSpace::kNone) {
|
||||||
o << " sc:" << int(di.storage_class);
|
o << " sc:" << int(di.address_space);
|
||||||
}
|
}
|
||||||
switch (di.skip) {
|
switch (di.skip) {
|
||||||
case SkipReason::kDontSkip:
|
case SkipReason::kDontSkip:
|
||||||
@ -470,7 +470,7 @@ class FunctionEmitter {
|
|||||||
/// by the `index_prefix`, which successively indexes into the variable.
|
/// by the `index_prefix`, which successively indexes into the variable.
|
||||||
/// Also generates the assignment statements that copy the input parameter
|
/// Also generates the assignment statements that copy the input parameter
|
||||||
/// to the corresponding part of the variable. Assumes the variable
|
/// to the corresponding part of the variable. Assumes the variable
|
||||||
/// has already been created in the Private storage class.
|
/// has already been created in the Private address space.
|
||||||
/// @param var_name The name of the variable
|
/// @param var_name The name of the variable
|
||||||
/// @param var_type The store type of the variable
|
/// @param var_type The store type of the variable
|
||||||
/// @param decos The variable's decorations
|
/// @param decos The variable's decorations
|
||||||
@ -496,8 +496,7 @@ class FunctionEmitter {
|
|||||||
/// expressions that compute the value they contribute to the entry point
|
/// expressions that compute the value they contribute to the entry point
|
||||||
/// return value. The part of the output variable is specfied
|
/// return value. The part of the output variable is specfied
|
||||||
/// by the `index_prefix`, which successively indexes into the variable.
|
/// by the `index_prefix`, which successively indexes into the variable.
|
||||||
/// Assumes the variable has already been created in the Private storage
|
/// Assumes the variable has already been created in the Private address space
|
||||||
/// class.
|
|
||||||
/// @param var_name The name of the variable
|
/// @param var_name The name of the variable
|
||||||
/// @param var_type The store type of the variable
|
/// @param var_type The store type of the variable
|
||||||
/// @param decos The variable's decorations
|
/// @param decos The variable's decorations
|
||||||
@ -612,19 +611,19 @@ class FunctionEmitter {
|
|||||||
/// @returns false on failure
|
/// @returns false on failure
|
||||||
bool RegisterLocallyDefinedValues();
|
bool RegisterLocallyDefinedValues();
|
||||||
|
|
||||||
/// Returns the Tint storage class for the given SPIR-V ID that is a
|
/// Returns the Tint address space for the given SPIR-V ID that is a
|
||||||
/// pointer value.
|
/// pointer value.
|
||||||
/// @param id a SPIR-V ID for a pointer value
|
/// @param id a SPIR-V ID for a pointer value
|
||||||
/// @returns the storage class
|
/// @returns the address space
|
||||||
ast::StorageClass GetStorageClassForPointerValue(uint32_t id);
|
ast::AddressSpace GetAddressSpaceForPointerValue(uint32_t id);
|
||||||
|
|
||||||
/// Remaps the storage class for the type of a locally-defined value,
|
/// Remaps the address space for the type of a locally-defined value,
|
||||||
/// if necessary. If it's not a pointer type, or if its storage class
|
/// if necessary. If it's not a pointer type, or if its address space
|
||||||
/// already matches, then the result is a copy of the `type` argument.
|
/// already matches, then the result is a copy of the `type` argument.
|
||||||
/// @param type the AST type
|
/// @param type the AST type
|
||||||
/// @param result_id the SPIR-V ID for the locally defined value
|
/// @param result_id the SPIR-V ID for the locally defined value
|
||||||
/// @returns an possibly updated type
|
/// @returns an possibly updated type
|
||||||
const Type* RemapStorageClass(const Type* type, uint32_t result_id);
|
const Type* RemapAddressSpace(const Type* type, uint32_t result_id);
|
||||||
|
|
||||||
/// Marks locally defined values when they should get a 'let'
|
/// Marks locally defined values when they should get a 'let'
|
||||||
/// definition in WGSL, or a 'var' definition at an outer scope.
|
/// definition in WGSL, or a 'var' definition at an outer scope.
|
||||||
@ -1005,11 +1004,11 @@ class FunctionEmitter {
|
|||||||
TypedExpression MakeOperand(const spvtools::opt::Instruction& inst, uint32_t operand_index);
|
TypedExpression MakeOperand(const spvtools::opt::Instruction& inst, uint32_t operand_index);
|
||||||
|
|
||||||
/// Copies a typed expression to the result, but when the type is a pointer
|
/// Copies a typed expression to the result, but when the type is a pointer
|
||||||
/// or reference type, ensures the storage class is not defaulted. That is,
|
/// or reference type, ensures the address space is not defaulted. That is,
|
||||||
/// it changes a storage class of "none" to "function".
|
/// it changes a address space of "none" to "function".
|
||||||
/// @param expr a typed expression
|
/// @param expr a typed expression
|
||||||
/// @results a copy of the expression, with possibly updated type
|
/// @results a copy of the expression, with possibly updated type
|
||||||
TypedExpression InferFunctionStorageClass(TypedExpression expr);
|
TypedExpression InferFunctionAddressSpace(TypedExpression expr);
|
||||||
|
|
||||||
/// Returns an expression for a SPIR-V OpFMod instruction.
|
/// Returns an expression for a SPIR-V OpFMod instruction.
|
||||||
/// @param inst the SPIR-V instruction
|
/// @param inst the SPIR-V instruction
|
||||||
|
@ -818,11 +818,11 @@ fn main() {
|
|||||||
EXPECT_EQ(got, expected) << got;
|
EXPECT_EQ(got, expected) << got;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_InferFunctionStorageClass) {
|
TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_InferFunctionAddressSpace) {
|
||||||
// An access chain can have no indices. When the base is a Function variable,
|
// An access chain can have no indices. When the base is a Function variable,
|
||||||
// the reference type has no explicit storage class in the AST representation.
|
// the reference type has no explicit address space in the AST representation.
|
||||||
// But the pointer type for the let declaration must have an explicit
|
// But the pointer type for the let declaration must have an explicit
|
||||||
// 'function' storage class. From crbug.com/tint/807
|
// 'function' address space. From crbug.com/tint/807
|
||||||
const std::string assembly = R"(
|
const std::string assembly = R"(
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpMemoryModel Logical Simple
|
OpMemoryModel Logical Simple
|
||||||
@ -993,7 +993,7 @@ TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughAccessChain_Cascaded) {
|
|||||||
|
|
||||||
TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughCopyObject_WithoutHoisting) {
|
TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughCopyObject_WithoutHoisting) {
|
||||||
// Generates a const declaration directly.
|
// Generates a const declaration directly.
|
||||||
// We have to do a bunch of storage class tracking for locally
|
// We have to do a bunch of address space tracking for locally
|
||||||
// defined values in order to get the right pointer-to-storage-buffer
|
// defined values in order to get the right pointer-to-storage-buffer
|
||||||
// value type for the const declration.
|
// value type for the const declration.
|
||||||
const auto assembly = OldStorageBufferPreamble() + R"(
|
const auto assembly = OldStorageBufferPreamble() + R"(
|
||||||
|
@ -1205,28 +1205,28 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ast_storage_class = enum_converter_.ToStorageClass(storage_class);
|
auto ast_address_space = enum_converter_.ToAddressSpace(storage_class);
|
||||||
if (ast_storage_class == ast::StorageClass::kInvalid) {
|
if (ast_address_space == ast::AddressSpace::kInvalid) {
|
||||||
Fail() << "SPIR-V pointer type with ID " << type_id << " has invalid storage class "
|
Fail() << "SPIR-V pointer type with ID " << type_id << " has invalid storage class "
|
||||||
<< static_cast<uint32_t>(storage_class);
|
<< static_cast<uint32_t>(storage_class);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (ast_storage_class == ast::StorageClass::kUniform &&
|
if (ast_address_space == ast::AddressSpace::kUniform &&
|
||||||
remap_buffer_block_type_.count(pointee_type_id)) {
|
remap_buffer_block_type_.count(pointee_type_id)) {
|
||||||
ast_storage_class = ast::StorageClass::kStorage;
|
ast_address_space = ast::AddressSpace::kStorage;
|
||||||
remap_buffer_block_type_.insert(type_id);
|
remap_buffer_block_type_.insert(type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pipeline input and output variables map to private variables.
|
// Pipeline input and output variables map to private variables.
|
||||||
if (ast_storage_class == ast::StorageClass::kIn ||
|
if (ast_address_space == ast::AddressSpace::kIn ||
|
||||||
ast_storage_class == ast::StorageClass::kOut) {
|
ast_address_space == ast::AddressSpace::kOut) {
|
||||||
ast_storage_class = ast::StorageClass::kPrivate;
|
ast_address_space = ast::AddressSpace::kPrivate;
|
||||||
}
|
}
|
||||||
switch (ptr_as) {
|
switch (ptr_as) {
|
||||||
case PtrAs::Ref:
|
case PtrAs::Ref:
|
||||||
return ty_.Reference(ast_elem_ty, ast_storage_class);
|
return ty_.Reference(ast_elem_ty, ast_address_space);
|
||||||
case PtrAs::Ptr:
|
case PtrAs::Ptr:
|
||||||
return ty_.Pointer(ast_elem_ty, ast_storage_class);
|
return ty_.Pointer(ast_elem_ty, ast_address_space);
|
||||||
}
|
}
|
||||||
Fail() << "invalid value for ptr_as: " << static_cast<int>(ptr_as);
|
Fail() << "invalid value for ptr_as: " << static_cast<int>(ptr_as);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1443,15 +1443,15 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||||||
var.NumInOperands() > 1 ? var.GetSingleWordInOperand(1) : 0u;
|
var.NumInOperands() > 1 ? var.GetSingleWordInOperand(1) : 0u;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
|
switch (enum_converter_.ToAddressSpace(spirv_storage_class)) {
|
||||||
case ast::StorageClass::kNone:
|
case ast::AddressSpace::kNone:
|
||||||
case ast::StorageClass::kIn:
|
case ast::AddressSpace::kIn:
|
||||||
case ast::StorageClass::kOut:
|
case ast::AddressSpace::kOut:
|
||||||
case ast::StorageClass::kUniform:
|
case ast::AddressSpace::kUniform:
|
||||||
case ast::StorageClass::kHandle:
|
case ast::AddressSpace::kHandle:
|
||||||
case ast::StorageClass::kStorage:
|
case ast::AddressSpace::kStorage:
|
||||||
case ast::StorageClass::kWorkgroup:
|
case ast::AddressSpace::kWorkgroup:
|
||||||
case ast::StorageClass::kPrivate:
|
case ast::AddressSpace::kPrivate:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return Fail() << "invalid SPIR-V storage class " << int(spirv_storage_class)
|
return Fail() << "invalid SPIR-V storage class " << int(spirv_storage_class)
|
||||||
@ -1481,7 +1481,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* ast_store_type = ast_type->As<Pointer>()->type;
|
auto* ast_store_type = ast_type->As<Pointer>()->type;
|
||||||
auto ast_storage_class = ast_type->As<Pointer>()->storage_class;
|
auto ast_address_space = ast_type->As<Pointer>()->address_space;
|
||||||
const ast::Expression* ast_constructor = nullptr;
|
const ast::Expression* ast_constructor = nullptr;
|
||||||
if (var.NumInOperands() > 1) {
|
if (var.NumInOperands() > 1) {
|
||||||
// SPIR-V initializers are always constants.
|
// SPIR-V initializers are always constants.
|
||||||
@ -1489,7 +1489,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||||||
// here.)
|
// here.)
|
||||||
ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
|
ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
|
||||||
}
|
}
|
||||||
auto* ast_var = MakeVar(var.result_id(), ast_storage_class, ast_store_type, ast_constructor,
|
auto* ast_var = MakeVar(var.result_id(), ast_address_space, ast_store_type, ast_constructor,
|
||||||
utils::Empty);
|
utils::Empty);
|
||||||
// TODO(dneto): initializers (a.k.a. constructor expression)
|
// TODO(dneto): initializers (a.k.a. constructor expression)
|
||||||
if (ast_var) {
|
if (ast_var) {
|
||||||
@ -1522,7 +1522,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||||||
}
|
}
|
||||||
auto* ast_var =
|
auto* ast_var =
|
||||||
MakeVar(builtin_position_.per_vertex_var_id,
|
MakeVar(builtin_position_.per_vertex_var_id,
|
||||||
enum_converter_.ToStorageClass(builtin_position_.storage_class),
|
enum_converter_.ToAddressSpace(builtin_position_.storage_class),
|
||||||
ConvertType(builtin_position_.position_member_type_id), ast_constructor, {});
|
ConvertType(builtin_position_.position_member_type_id), ast_constructor, {});
|
||||||
|
|
||||||
builder_.AST().AddGlobalVariable(ast_var);
|
builder_.AST().AddGlobalVariable(ast_var);
|
||||||
@ -1554,7 +1554,7 @@ const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(uint32_t va
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast::Var* ParserImpl::MakeVar(uint32_t id,
|
ast::Var* ParserImpl::MakeVar(uint32_t id,
|
||||||
ast::StorageClass sc,
|
ast::AddressSpace address_space,
|
||||||
const Type* storage_type,
|
const Type* storage_type,
|
||||||
const ast::Expression* constructor,
|
const ast::Expression* constructor,
|
||||||
AttributeList decorations) {
|
AttributeList decorations) {
|
||||||
@ -1564,7 +1564,7 @@ ast::Var* ParserImpl::MakeVar(uint32_t id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast::Access access = ast::Access::kUndefined;
|
ast::Access access = ast::Access::kUndefined;
|
||||||
if (sc == ast::StorageClass::kStorage) {
|
if (address_space == ast::AddressSpace::kStorage) {
|
||||||
bool read_only = false;
|
bool read_only = false;
|
||||||
if (auto* tn = storage_type->As<Named>()) {
|
if (auto* tn = storage_type->As<Named>()) {
|
||||||
read_only = read_only_struct_types_.count(tn->name) > 0;
|
read_only = read_only_struct_types_.count(tn->name) > 0;
|
||||||
@ -1575,19 +1575,19 @@ ast::Var* ParserImpl::MakeVar(uint32_t id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle variables (textures and samplers) are always in the handle
|
// Handle variables (textures and samplers) are always in the handle
|
||||||
// storage class, so we don't mention the storage class.
|
// address space, so we don't mention the address space.
|
||||||
if (sc == ast::StorageClass::kHandle) {
|
if (address_space == ast::AddressSpace::kHandle) {
|
||||||
sc = ast::StorageClass::kNone;
|
address_space = ast::AddressSpace::kNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ConvertDecorationsForVariable(id, &storage_type, &decorations,
|
if (!ConvertDecorationsForVariable(id, &storage_type, &decorations,
|
||||||
sc != ast::StorageClass::kPrivate)) {
|
address_space != ast::AddressSpace::kPrivate)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sym = builder_.Symbols().Register(namer_.Name(id));
|
auto sym = builder_.Symbols().Register(namer_.Name(id));
|
||||||
return create<ast::Var>(Source{}, sym, storage_type->Build(builder_), sc, access, constructor,
|
return create<ast::Var>(Source{}, sym, storage_type->Build(builder_), address_space, access,
|
||||||
decorations);
|
constructor, decorations);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Let* ParserImpl::MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor) {
|
ast::Let* ParserImpl::MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor) {
|
||||||
@ -2486,7 +2486,7 @@ const Pointer* ParserImpl::GetTypeForHandleVar(const spvtools::opt::Instruction&
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Form the pointer type.
|
// Form the pointer type.
|
||||||
auto* result = ty_.Pointer(ast_store_type, ast::StorageClass::kHandle);
|
auto* result = ty_.Pointer(ast_store_type, ast::AddressSpace::kHandle);
|
||||||
// Remember it for later.
|
// Remember it for later.
|
||||||
handle_type_[&var] = result;
|
handle_type_[&var] = result;
|
||||||
return result;
|
return result;
|
||||||
|
@ -50,7 +50,7 @@ TINT_END_DISABLE_WARNING(NEWLINE_EOF);
|
|||||||
///
|
///
|
||||||
/// A WGSL "handle" is an opaque object used for accessing a resource via
|
/// A WGSL "handle" is an opaque object used for accessing a resource via
|
||||||
/// special builtins. In SPIR-V, a handle is stored a variable in the
|
/// special builtins. In SPIR-V, a handle is stored a variable in the
|
||||||
/// UniformConstant storage class. The handles supported by SPIR-V are:
|
/// UniformConstant address space. The handles supported by SPIR-V are:
|
||||||
/// - images, both sampled texture and storage image
|
/// - images, both sampled texture and storage image
|
||||||
/// - samplers
|
/// - samplers
|
||||||
/// - combined image+sampler
|
/// - combined image+sampler
|
||||||
@ -424,14 +424,14 @@ class ParserImpl : Reader {
|
|||||||
/// Creates an AST 'var' node for a SPIR-V ID, including any attached decorations, unless it's
|
/// Creates an AST 'var' node for a SPIR-V ID, including any attached decorations, unless it's
|
||||||
/// an ignorable builtin variable.
|
/// an ignorable builtin variable.
|
||||||
/// @param id the SPIR-V result ID
|
/// @param id the SPIR-V result ID
|
||||||
/// @param sc the storage class, which cannot be ast::StorageClass::kNone
|
/// @param address_space the address space, which cannot be ast::AddressSpace::kNone
|
||||||
/// @param storage_type the storage type of the variable
|
/// @param storage_type the storage type of the variable
|
||||||
/// @param constructor the variable constructor
|
/// @param constructor the variable constructor
|
||||||
/// @param decorations the variable decorations
|
/// @param decorations the variable decorations
|
||||||
/// @returns a new Variable node, or null in the ignorable variable case and
|
/// @returns a new Variable node, or null in the ignorable variable case and
|
||||||
/// in the error case
|
/// in the error case
|
||||||
ast::Var* MakeVar(uint32_t id,
|
ast::Var* MakeVar(uint32_t id,
|
||||||
ast::StorageClass sc,
|
ast::AddressSpace address_space,
|
||||||
const Type* storage_type,
|
const Type* storage_type,
|
||||||
const ast::Expression* constructor,
|
const ast::Expression* constructor,
|
||||||
AttributeList decorations);
|
AttributeList decorations);
|
||||||
@ -583,7 +583,7 @@ class ParserImpl : Reader {
|
|||||||
/// The ID of the type of a pointer to the struct in the Output storage
|
/// The ID of the type of a pointer to the struct in the Output storage
|
||||||
/// class class.
|
/// class class.
|
||||||
uint32_t pointer_type_id = 0;
|
uint32_t pointer_type_id = 0;
|
||||||
/// The SPIR-V storage class.
|
/// The SPIR-V address space.
|
||||||
SpvStorageClass storage_class = SpvStorageClassOutput;
|
SpvStorageClass storage_class = SpvStorageClassOutput;
|
||||||
/// The ID of the type of a pointer to the Position member.
|
/// The ID of the type of a pointer to the Position member.
|
||||||
uint32_t position_member_pointer_type_id = 0;
|
uint32_t position_member_pointer_type_id = 0;
|
||||||
@ -640,8 +640,8 @@ class ParserImpl : Reader {
|
|||||||
Usage GetHandleUsage(uint32_t id) const;
|
Usage GetHandleUsage(uint32_t id) const;
|
||||||
|
|
||||||
/// Returns the SPIR-V type for the sampler or image type for the given
|
/// Returns the SPIR-V type for the sampler or image type for the given
|
||||||
/// variable in UniformConstant storage class, or function parameter pointing
|
/// variable in UniformConstant address space, or function parameter pointing
|
||||||
/// into the UniformConstant storage class . Returns null and emits an
|
/// into the UniformConstant address space . Returns null and emits an
|
||||||
/// error on failure.
|
/// error on failure.
|
||||||
/// @param var the OpVariable instruction or OpFunctionParameter
|
/// @param var the OpVariable instruction or OpFunctionParameter
|
||||||
/// @returns the Tint AST type for the sampler or texture, or null on error
|
/// @returns the Tint AST type for the sampler or texture, or null on error
|
||||||
@ -649,7 +649,7 @@ class ParserImpl : Reader {
|
|||||||
const spvtools::opt::Instruction& var);
|
const spvtools::opt::Instruction& var);
|
||||||
|
|
||||||
/// Returns the AST type for the pointer-to-sampler or pointer-to-texture type
|
/// Returns the AST type for the pointer-to-sampler or pointer-to-texture type
|
||||||
/// for the given variable in UniformConstant storage class. Returns null and
|
/// for the given variable in UniformConstant address space. Returns null and
|
||||||
/// emits an error on failure.
|
/// emits an error on failure.
|
||||||
/// @param var the OpVariable instruction
|
/// @param var the OpVariable instruction
|
||||||
/// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
|
/// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
|
||||||
@ -841,8 +841,8 @@ class ParserImpl : Reader {
|
|||||||
// - an array, runtime array containing one of these
|
// - an array, runtime array containing one of these
|
||||||
// - a pointer type to one of these
|
// - a pointer type to one of these
|
||||||
// These are the types "enclosing" a buffer block with the old style
|
// These are the types "enclosing" a buffer block with the old style
|
||||||
// representation: using Uniform storage class and BufferBlock decoration
|
// representation: using Uniform address space and BufferBlock decoration
|
||||||
// on the struct. The new style is to use the StorageBuffer storage class
|
// on the struct. The new style is to use the StorageBuffer address space
|
||||||
// and Block decoration.
|
// and Block decoration.
|
||||||
std::unordered_set<uint32_t> remap_buffer_block_type_;
|
std::unordered_set<uint32_t> remap_buffer_block_type_;
|
||||||
|
|
||||||
|
@ -709,11 +709,11 @@ OpFunctionEnd
|
|||||||
EXPECT_THAT(p->error(), Eq("SPIR-V pointer type with ID 3 has invalid pointee type 42"));
|
EXPECT_THAT(p->error(), Eq("SPIR-V pointer type with ID 3 has invalid pointee type 42"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidStorageClass) {
|
TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidAddressSpace) {
|
||||||
// Disallow invalid storage class
|
// Disallow invalid address space
|
||||||
auto p = parser(test::Assemble(Preamble() + R"(
|
auto p = parser(test::Assemble(Preamble() + R"(
|
||||||
%1 = OpTypeFloat 32
|
%1 = OpTypeFloat 32
|
||||||
%3 = OpTypePointer !999 %1 ; Special syntax to inject 999 as the storage class
|
%3 = OpTypePointer !999 %1 ; Special syntax to inject 999 as the address space
|
||||||
)" + MainBody()));
|
)" + MainBody()));
|
||||||
// TODO(dneto): I can't get it past module building.
|
// TODO(dneto): I can't get it past module building.
|
||||||
EXPECT_FALSE(p->BuildInternalModule()) << p->error();
|
EXPECT_FALSE(p->BuildInternalModule()) << p->error();
|
||||||
@ -731,7 +731,7 @@ TEST_F(SpvParserTest, ConvertType_PointerInput) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +747,7 @@ TEST_F(SpvParserTest, ConvertType_PointerOutput) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +763,7 @@ TEST_F(SpvParserTest, ConvertType_PointerUniform) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniform);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kUniform);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,7 +779,7 @@ TEST_F(SpvParserTest, ConvertType_PointerWorkgroup) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kWorkgroup);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kWorkgroup);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,7 +795,7 @@ TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kNone);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kNone);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,7 +811,7 @@ TEST_F(SpvParserTest, ConvertType_PointerStorageBuffer) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kStorage);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kStorage);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,7 +827,7 @@ TEST_F(SpvParserTest, ConvertType_PointerPrivate) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +843,7 @@ TEST_F(SpvParserTest, ConvertType_PointerFunction) {
|
|||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kFunction);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kFunction);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,12 +862,12 @@ TEST_F(SpvParserTest, ConvertType_PointerToPointer) {
|
|||||||
|
|
||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(ptr_ty->address_space, ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
|
EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
|
||||||
|
|
||||||
auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
|
auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ptr_ty, nullptr);
|
EXPECT_NE(ptr_ptr_ty, nullptr);
|
||||||
EXPECT_EQ(ptr_ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(ptr_ptr_ty->address_space, ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
|
||||||
|
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
|
@ -119,7 +119,7 @@ TEST_F(SpvModuleScopeVarParserTest, NoVar) {
|
|||||||
EXPECT_THAT(module_ast, Not(HasSubstr("Variable"))) << module_ast;
|
EXPECT_THAT(module_ast, Not(HasSubstr("Variable"))) << module_ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvModuleScopeVarParserTest, BadStorageClass_NotAWebGPUStorageClass) {
|
TEST_F(SpvModuleScopeVarParserTest, BadAddressSpace_NotAWebGPUAddressSpace) {
|
||||||
auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
|
auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
|
||||||
%float = OpTypeFloat 32
|
%float = OpTypeFloat 32
|
||||||
%ptr = OpTypePointer CrossWorkgroup %float
|
%ptr = OpTypePointer CrossWorkgroup %float
|
||||||
@ -135,7 +135,7 @@ TEST_F(SpvModuleScopeVarParserTest, BadStorageClass_NotAWebGPUStorageClass) {
|
|||||||
EXPECT_THAT(p->error(), HasSubstr("unknown SPIR-V storage class: 5"));
|
EXPECT_THAT(p->error(), HasSubstr("unknown SPIR-V storage class: 5"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvModuleScopeVarParserTest, BadStorageClass_Function) {
|
TEST_F(SpvModuleScopeVarParserTest, BadAddressSpace_Function) {
|
||||||
auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
|
auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
|
||||||
%float = OpTypeFloat 32
|
%float = OpTypeFloat 32
|
||||||
%ptr = OpTypePointer Function %float
|
%ptr = OpTypePointer Function %float
|
||||||
|
@ -50,11 +50,11 @@ namespace tint::reader::spirv {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct PointerHasher {
|
struct PointerHasher {
|
||||||
size_t operator()(const Pointer& t) const { return utils::Hash(t.type, t.storage_class); }
|
size_t operator()(const Pointer& t) const { return utils::Hash(t.type, t.address_space); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReferenceHasher {
|
struct ReferenceHasher {
|
||||||
size_t operator()(const Reference& t) const { return utils::Hash(t.type, t.storage_class); }
|
size_t operator()(const Reference& t) const { return utils::Hash(t.type, t.address_space); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VectorHasher {
|
struct VectorHasher {
|
||||||
@ -107,10 +107,10 @@ struct StorageTextureHasher {
|
|||||||
// Equality operators
|
// Equality operators
|
||||||
//! @cond Doxygen_Suppress
|
//! @cond Doxygen_Suppress
|
||||||
static bool operator==(const Pointer& a, const Pointer& b) {
|
static bool operator==(const Pointer& a, const Pointer& b) {
|
||||||
return a.type == b.type && a.storage_class == b.storage_class;
|
return a.type == b.type && a.address_space == b.address_space;
|
||||||
}
|
}
|
||||||
static bool operator==(const Reference& a, const Reference& b) {
|
static bool operator==(const Reference& a, const Reference& b) {
|
||||||
return a.type == b.type && a.storage_class == b.storage_class;
|
return a.type == b.type && a.address_space == b.address_space;
|
||||||
}
|
}
|
||||||
static bool operator==(const Vector& a, const Vector& b) {
|
static bool operator==(const Vector& a, const Vector& b) {
|
||||||
return a.type == b.type && a.size == b.size;
|
return a.type == b.type && a.size == b.size;
|
||||||
@ -170,14 +170,14 @@ Type::~Type() = default;
|
|||||||
|
|
||||||
Texture::~Texture() = default;
|
Texture::~Texture() = default;
|
||||||
|
|
||||||
Pointer::Pointer(const Type* t, ast::StorageClass s) : type(t), storage_class(s) {}
|
Pointer::Pointer(const Type* t, ast::AddressSpace s) : type(t), address_space(s) {}
|
||||||
Pointer::Pointer(const Pointer&) = default;
|
Pointer::Pointer(const Pointer&) = default;
|
||||||
|
|
||||||
const ast::Type* Pointer::Build(ProgramBuilder& b) const {
|
const ast::Type* Pointer::Build(ProgramBuilder& b) const {
|
||||||
return b.ty.pointer(type->Build(b), storage_class);
|
return b.ty.pointer(type->Build(b), address_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference::Reference(const Type* t, ast::StorageClass s) : type(t), storage_class(s) {}
|
Reference::Reference(const Type* t, ast::AddressSpace s) : type(t), address_space(s) {}
|
||||||
Reference::Reference(const Reference&) = default;
|
Reference::Reference(const Reference&) = default;
|
||||||
|
|
||||||
const ast::Type* Reference::Build(ProgramBuilder& b) const {
|
const ast::Type* Reference::Build(ProgramBuilder& b) const {
|
||||||
@ -438,12 +438,12 @@ const spirv::I32* TypeManager::I32() {
|
|||||||
return state->i32_;
|
return state->i32_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const spirv::Pointer* TypeManager::Pointer(const Type* el, ast::StorageClass sc) {
|
const spirv::Pointer* TypeManager::Pointer(const Type* el, ast::AddressSpace address_space) {
|
||||||
return state->pointers_.Get(el, sc);
|
return state->pointers_.Get(el, address_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
const spirv::Reference* TypeManager::Reference(const Type* el, ast::StorageClass sc) {
|
const spirv::Reference* TypeManager::Reference(const Type* el, ast::AddressSpace address_space) {
|
||||||
return state->references_.Get(el, sc);
|
return state->references_.Get(el, address_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
const spirv::Vector* TypeManager::Vector(const Type* el, uint32_t size) {
|
const spirv::Vector* TypeManager::Vector(const Type* el, uint32_t size) {
|
||||||
@ -519,13 +519,13 @@ std::string I32::String() const {
|
|||||||
|
|
||||||
std::string Pointer::String() const {
|
std::string Pointer::String() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "ptr<" << utils::ToString(storage_class) << ", " << type->String() + ">";
|
ss << "ptr<" << utils::ToString(address_space) << ", " << type->String() + ">";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Reference::String() const {
|
std::string Reference::String() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "ref<" + utils::ToString(storage_class) << ", " << type->String() << ">";
|
ss << "ref<" + utils::ToString(address_space) << ", " << type->String() << ">";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/tint/ast/access.h"
|
#include "src/tint/ast/access.h"
|
||||||
|
#include "src/tint/ast/address_space.h"
|
||||||
#include "src/tint/ast/sampler.h"
|
#include "src/tint/ast/sampler.h"
|
||||||
#include "src/tint/ast/storage_class.h"
|
|
||||||
#include "src/tint/ast/storage_texture.h"
|
#include "src/tint/ast/storage_texture.h"
|
||||||
#include "src/tint/ast/texture.h"
|
#include "src/tint/ast/texture.h"
|
||||||
#include "src/tint/castable.h"
|
#include "src/tint/castable.h"
|
||||||
@ -161,8 +161,8 @@ struct I32 final : public Castable<I32, Type> {
|
|||||||
struct Pointer final : public Castable<Pointer, Type> {
|
struct Pointer final : public Castable<Pointer, Type> {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param ty the store type
|
/// @param ty the store type
|
||||||
/// @param sc the pointer storage class
|
/// @param sc the pointer address space
|
||||||
Pointer(const Type* ty, ast::StorageClass sc);
|
Pointer(const Type* ty, ast::AddressSpace sc);
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
/// @param other the other type to copy
|
/// @param other the other type to copy
|
||||||
@ -179,8 +179,8 @@ struct Pointer final : public Castable<Pointer, Type> {
|
|||||||
|
|
||||||
/// the store type
|
/// the store type
|
||||||
Type const* const type;
|
Type const* const type;
|
||||||
/// the pointer storage class
|
/// the pointer address space
|
||||||
ast::StorageClass const storage_class;
|
ast::AddressSpace const address_space;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `ref<SC, T>` type
|
/// `ref<SC, T>` type
|
||||||
@ -189,8 +189,8 @@ struct Pointer final : public Castable<Pointer, Type> {
|
|||||||
struct Reference final : public Castable<Reference, Type> {
|
struct Reference final : public Castable<Reference, Type> {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param ty the referenced type
|
/// @param ty the referenced type
|
||||||
/// @param sc the reference storage class
|
/// @param sc the reference address space
|
||||||
Reference(const Type* ty, ast::StorageClass sc);
|
Reference(const Type* ty, ast::AddressSpace sc);
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
/// @param other the other type to copy
|
/// @param other the other type to copy
|
||||||
@ -207,8 +207,8 @@ struct Reference final : public Castable<Reference, Type> {
|
|||||||
|
|
||||||
/// the store type
|
/// the store type
|
||||||
Type const* const type;
|
Type const* const type;
|
||||||
/// the pointer storage class
|
/// the pointer address space
|
||||||
ast::StorageClass const storage_class;
|
ast::AddressSpace const address_space;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `vecN<T>` type
|
/// `vecN<T>` type
|
||||||
@ -534,15 +534,15 @@ class TypeManager {
|
|||||||
/// @return a I32 type. Repeated calls will return the same pointer.
|
/// @return a I32 type. Repeated calls will return the same pointer.
|
||||||
const spirv::I32* I32();
|
const spirv::I32* I32();
|
||||||
/// @param ty the store type
|
/// @param ty the store type
|
||||||
/// @param sc the pointer storage class
|
/// @param address_space the pointer address space
|
||||||
/// @return a Pointer type. Repeated calls with the same arguments will return
|
/// @return a Pointer type. Repeated calls with the same arguments will return
|
||||||
/// the same pointer.
|
/// the same pointer.
|
||||||
const spirv::Pointer* Pointer(const Type* ty, ast::StorageClass sc);
|
const spirv::Pointer* Pointer(const Type* ty, ast::AddressSpace address_space);
|
||||||
/// @param ty the referenced type
|
/// @param ty the referenced type
|
||||||
/// @param sc the reference storage class
|
/// @param address_space the reference address space
|
||||||
/// @return a Reference type. Repeated calls with the same arguments will
|
/// @return a Reference type. Repeated calls with the same arguments will
|
||||||
/// return the same pointer.
|
/// return the same pointer.
|
||||||
const spirv::Reference* Reference(const Type* ty, ast::StorageClass sc);
|
const spirv::Reference* Reference(const Type* ty, ast::AddressSpace address_space);
|
||||||
/// @param ty the element type
|
/// @param ty the element type
|
||||||
/// @param sz the number of elements in the vector
|
/// @param sz the number of elements in the vector
|
||||||
/// @return a Vector type. Repeated calls with the same arguments will return
|
/// @return a Vector type. Repeated calls with the same arguments will return
|
||||||
|
@ -28,8 +28,8 @@ TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
|
|||||||
EXPECT_EQ(ty.U32(), ty.U32());
|
EXPECT_EQ(ty.U32(), ty.U32());
|
||||||
EXPECT_EQ(ty.F32(), ty.F32());
|
EXPECT_EQ(ty.F32(), ty.F32());
|
||||||
EXPECT_EQ(ty.I32(), ty.I32());
|
EXPECT_EQ(ty.I32(), ty.I32());
|
||||||
EXPECT_EQ(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
EXPECT_EQ(ty.Pointer(ty.I32(), ast::AddressSpace::kNone),
|
||||||
ty.Pointer(ty.I32(), ast::StorageClass::kNone));
|
ty.Pointer(ty.I32(), ast::AddressSpace::kNone));
|
||||||
EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
|
EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
|
||||||
EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
|
EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
|
||||||
EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
|
EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
|
||||||
@ -53,10 +53,10 @@ TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
|
|||||||
Symbol sym_b(Symbol(2, {}));
|
Symbol sym_b(Symbol(2, {}));
|
||||||
|
|
||||||
TypeManager ty;
|
TypeManager ty;
|
||||||
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
EXPECT_NE(ty.Pointer(ty.I32(), ast::AddressSpace::kNone),
|
||||||
ty.Pointer(ty.U32(), ast::StorageClass::kNone));
|
ty.Pointer(ty.U32(), ast::AddressSpace::kNone));
|
||||||
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
EXPECT_NE(ty.Pointer(ty.I32(), ast::AddressSpace::kNone),
|
||||||
ty.Pointer(ty.I32(), ast::StorageClass::kIn));
|
ty.Pointer(ty.I32(), ast::AddressSpace::kIn));
|
||||||
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
|
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
|
||||||
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
|
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
|
||||||
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
|
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
|
||||||
|
@ -206,12 +206,12 @@ ParserImpl::VarDeclInfo::VarDeclInfo(const VarDeclInfo&) = default;
|
|||||||
|
|
||||||
ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
|
ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
|
||||||
std::string name_in,
|
std::string name_in,
|
||||||
ast::StorageClass storage_class_in,
|
ast::AddressSpace address_space_in,
|
||||||
ast::Access access_in,
|
ast::Access access_in,
|
||||||
const ast::Type* type_in)
|
const ast::Type* type_in)
|
||||||
: source(std::move(source_in)),
|
: source(std::move(source_in)),
|
||||||
name(std::move(name_in)),
|
name(std::move(name_in)),
|
||||||
storage_class(storage_class_in),
|
address_space(address_space_in),
|
||||||
access(access_in),
|
access(access_in),
|
||||||
type(type_in) {}
|
type(type_in) {}
|
||||||
|
|
||||||
@ -594,7 +594,7 @@ Maybe<const ast::Variable*> ParserImpl::global_variable_decl(AttributeList& attr
|
|||||||
return create<ast::Var>(decl->source, // source
|
return create<ast::Var>(decl->source, // source
|
||||||
builder_.Symbols().Register(decl->name), // symbol
|
builder_.Symbols().Register(decl->name), // symbol
|
||||||
decl->type, // type
|
decl->type, // type
|
||||||
decl->storage_class, // storage class
|
decl->address_space, // address space
|
||||||
decl->access, // access control
|
decl->access, // access control
|
||||||
initializer, // initializer
|
initializer, // initializer
|
||||||
std::move(attrs)); // attributes
|
std::move(attrs)); // attributes
|
||||||
@ -697,7 +697,7 @@ Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl() {
|
|||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
return VarDeclInfo{decl->source, decl->name, vq.storage_class, vq.access, decl->type};
|
return VarDeclInfo{decl->source, decl->name, vq.address_space, vq.access, decl->type};
|
||||||
}
|
}
|
||||||
|
|
||||||
// texture_and_sampler_types
|
// texture_and_sampler_types
|
||||||
@ -1208,7 +1208,7 @@ Expect<const ast::Type*> ParserImpl::expect_type(std::string_view use) {
|
|||||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Source& s) {
|
Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Source& s) {
|
||||||
const char* use = "ptr declaration";
|
const char* use = "ptr declaration";
|
||||||
|
|
||||||
auto storage_class = ast::StorageClass::kNone;
|
auto address_space = ast::AddressSpace::kNone;
|
||||||
auto access = ast::Access::kUndefined;
|
auto access = ast::Access::kUndefined;
|
||||||
|
|
||||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
|
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
|
||||||
@ -1216,7 +1216,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Source& s) {
|
|||||||
if (sc.errored) {
|
if (sc.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
storage_class = sc.value;
|
address_space = sc.value;
|
||||||
|
|
||||||
if (!expect(use, Token::Type::kComma)) {
|
if (!expect(use, Token::Type::kComma)) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
@ -1242,7 +1242,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Source& s) {
|
|||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder_.ty.pointer(make_source_range_from(s), subtype.value, storage_class, access);
|
return builder_.ty.pointer(make_source_range_from(s), subtype.value, address_space, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LESS_THAN type_decl GREATER_THAN
|
// LESS_THAN type_decl GREATER_THAN
|
||||||
@ -1329,19 +1329,19 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(const Source& s,
|
|||||||
// | 'storage'
|
// | 'storage'
|
||||||
//
|
//
|
||||||
// Note, we also parse `push_constant` from the experimental extension
|
// Note, we also parse `push_constant` from the experimental extension
|
||||||
Expect<ast::StorageClass> ParserImpl::expect_address_space(std::string_view use) {
|
Expect<ast::AddressSpace> ParserImpl::expect_address_space(std::string_view use) {
|
||||||
auto& t = peek();
|
auto& t = peek();
|
||||||
auto ident = expect_ident("storage class");
|
auto ident = expect_ident("address space");
|
||||||
if (ident.errored) {
|
if (ident.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto storage_class = ast::ParseStorageClass(ident.value);
|
auto address_space = ast::ParseAddressSpace(ident.value);
|
||||||
if (storage_class == ast::StorageClass::kInvalid) {
|
if (address_space == ast::AddressSpace::kInvalid) {
|
||||||
return add_error(t.source(), "invalid storage class", use);
|
return add_error(t.source(), "invalid address space", use);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {storage_class, t.source()};
|
return {address_space, t.source()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct_decl
|
// struct_decl
|
||||||
@ -1988,7 +1988,7 @@ Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_statement() {
|
|||||||
auto* var = create<ast::Var>(decl->source, // source
|
auto* var = create<ast::Var>(decl->source, // source
|
||||||
builder_.Symbols().Register(decl->name), // symbol
|
builder_.Symbols().Register(decl->name), // symbol
|
||||||
decl->type, // type
|
decl->type, // type
|
||||||
decl->storage_class, // storage class
|
decl->address_space, // address space
|
||||||
decl->access, // access control
|
decl->access, // access control
|
||||||
initializer, // initializer
|
initializer, // initializer
|
||||||
utils::Empty); // attributes
|
utils::Empty); // attributes
|
||||||
|
@ -278,12 +278,12 @@ class ParserImpl {
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param source_in variable declaration source
|
/// @param source_in variable declaration source
|
||||||
/// @param name_in variable name
|
/// @param name_in variable name
|
||||||
/// @param storage_class_in variable storage class
|
/// @param address_space_in variable address space
|
||||||
/// @param access_in variable access control
|
/// @param access_in variable access control
|
||||||
/// @param type_in variable type
|
/// @param type_in variable type
|
||||||
VarDeclInfo(Source source_in,
|
VarDeclInfo(Source source_in,
|
||||||
std::string name_in,
|
std::string name_in,
|
||||||
ast::StorageClass storage_class_in,
|
ast::AddressSpace address_space_in,
|
||||||
ast::Access access_in,
|
ast::Access access_in,
|
||||||
const ast::Type* type_in);
|
const ast::Type* type_in);
|
||||||
/// Destructor
|
/// Destructor
|
||||||
@ -293,8 +293,8 @@ class ParserImpl {
|
|||||||
Source source;
|
Source source;
|
||||||
/// Variable name
|
/// Variable name
|
||||||
std::string name;
|
std::string name;
|
||||||
/// Variable storage class
|
/// Variable address space
|
||||||
ast::StorageClass storage_class = ast::StorageClass::kNone;
|
ast::AddressSpace address_space = ast::AddressSpace::kNone;
|
||||||
/// Variable access control
|
/// Variable access control
|
||||||
ast::Access access = ast::Access::kUndefined;
|
ast::Access access = ast::Access::kUndefined;
|
||||||
/// Variable type
|
/// Variable type
|
||||||
@ -303,8 +303,8 @@ class ParserImpl {
|
|||||||
|
|
||||||
/// VariableQualifier contains the parsed information for a variable qualifier
|
/// VariableQualifier contains the parsed information for a variable qualifier
|
||||||
struct VariableQualifier {
|
struct VariableQualifier {
|
||||||
/// The variable's storage class
|
/// The variable's address space
|
||||||
ast::StorageClass storage_class = ast::StorageClass::kNone;
|
ast::AddressSpace address_space = ast::AddressSpace::kNone;
|
||||||
/// The variable's access control
|
/// The variable's access control
|
||||||
ast::Access access = ast::Access::kUndefined;
|
ast::Access access = ast::Access::kUndefined;
|
||||||
};
|
};
|
||||||
@ -460,8 +460,8 @@ class ParserImpl {
|
|||||||
Maybe<const ast::Type*> type_decl();
|
Maybe<const ast::Type*> type_decl();
|
||||||
/// Parses an `address_space` grammar element, erroring on parse failure.
|
/// Parses an `address_space` grammar element, erroring on parse failure.
|
||||||
/// @param use a description of what was being parsed if an error was raised.
|
/// @param use a description of what was being parsed if an error was raised.
|
||||||
/// @returns the address space or StorageClass::kNone if none matched
|
/// @returns the address space or ast::AddressSpace::kNone if none matched
|
||||||
Expect<ast::StorageClass> expect_address_space(std::string_view use);
|
Expect<ast::AddressSpace> expect_address_space(std::string_view use);
|
||||||
/// Parses a `struct_decl` grammar element.
|
/// Parses a `struct_decl` grammar element.
|
||||||
/// @returns the struct type or nullptr on error
|
/// @returns the struct type or nullptr on error
|
||||||
Maybe<const ast::Struct*> struct_decl();
|
Maybe<const ast::Struct*> struct_decl();
|
||||||
|
@ -17,18 +17,18 @@
|
|||||||
namespace tint::reader::wgsl {
|
namespace tint::reader::wgsl {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct StorageClassData {
|
struct AddressSpaceData {
|
||||||
const char* input;
|
const char* input;
|
||||||
ast::StorageClass result;
|
ast::AddressSpace result;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& out, StorageClassData data) {
|
inline std::ostream& operator<<(std::ostream& out, AddressSpaceData data) {
|
||||||
out << std::string(data.input);
|
out << std::string(data.input);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParserStorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
|
class ParserAddressSpaceTest : public ParserImplTestWithParam<AddressSpaceData> {};
|
||||||
|
|
||||||
TEST_P(ParserStorageClassTest, Parses) {
|
TEST_P(ParserAddressSpaceTest, Parses) {
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
auto p = parser(params.input);
|
auto p = parser(params.input);
|
||||||
|
|
||||||
@ -42,19 +42,19 @@ TEST_P(ParserStorageClassTest, Parses) {
|
|||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
ParserImplTest,
|
ParserImplTest,
|
||||||
ParserStorageClassTest,
|
ParserAddressSpaceTest,
|
||||||
testing::Values(StorageClassData{"uniform", ast::StorageClass::kUniform},
|
testing::Values(AddressSpaceData{"uniform", ast::AddressSpace::kUniform},
|
||||||
StorageClassData{"workgroup", ast::StorageClass::kWorkgroup},
|
AddressSpaceData{"workgroup", ast::AddressSpace::kWorkgroup},
|
||||||
StorageClassData{"storage", ast::StorageClass::kStorage},
|
AddressSpaceData{"storage", ast::AddressSpace::kStorage},
|
||||||
StorageClassData{"private", ast::StorageClass::kPrivate},
|
AddressSpaceData{"private", ast::AddressSpace::kPrivate},
|
||||||
StorageClassData{"function", ast::StorageClass::kFunction}));
|
AddressSpaceData{"function", ast::AddressSpace::kFunction}));
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StorageClass_NoMatch) {
|
TEST_F(ParserImplTest, AddressSpace_NoMatch) {
|
||||||
auto p = parser("not-a-storage-class");
|
auto p = parser("not-a-address-space");
|
||||||
auto sc = p->expect_address_space("test");
|
auto sc = p->expect_address_space("test");
|
||||||
EXPECT_EQ(sc.errored, true);
|
EXPECT_EQ(sc.errored, true);
|
||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:1: invalid storage class for test");
|
EXPECT_EQ(p->error(), "1:1: invalid address space for test");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -1105,9 +1105,9 @@ var i : ptr<private u32>;
|
|||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingStorageClass) {
|
TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingAddressSpace) {
|
||||||
EXPECT("var i : ptr<meow, u32>;",
|
EXPECT("var i : ptr<meow, u32>;",
|
||||||
R"(test.wgsl:1:13 error: invalid storage class for ptr declaration
|
R"(test.wgsl:1:13 error: invalid address space for ptr declaration
|
||||||
var i : ptr<meow, u32>;
|
var i : ptr<meow, u32>;
|
||||||
^^^^
|
^^^^
|
||||||
)");
|
)");
|
||||||
@ -1139,7 +1139,7 @@ var i : atomic<u32 x;
|
|||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
|
TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
|
||||||
EXPECT("var<fish> i : i32",
|
EXPECT("var<fish> i : i32",
|
||||||
R"(test.wgsl:1:5 error: invalid storage class for variable declaration
|
R"(test.wgsl:1:5 error: invalid address space for variable declaration
|
||||||
var<fish> i : i32
|
var<fish> i : i32
|
||||||
^^^^
|
^^^^
|
||||||
)");
|
)");
|
||||||
|
@ -31,7 +31,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
|
|||||||
|
|
||||||
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(var->type->Is<ast::F32>());
|
EXPECT_TRUE(var->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(var->declared_address_space, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_EQ(var->source.range.begin.line, 1u);
|
EXPECT_EQ(var->source.range.begin.line, 1u);
|
||||||
EXPECT_EQ(var->source.range.begin.column, 14u);
|
EXPECT_EQ(var->source.range.begin.column, 14u);
|
||||||
@ -55,7 +55,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
|
|||||||
|
|
||||||
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(var->type->Is<ast::F32>());
|
EXPECT_TRUE(var->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(var->declared_address_space, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_EQ(var->source.range.begin.line, 1u);
|
EXPECT_EQ(var->source.range.begin.line, 1u);
|
||||||
EXPECT_EQ(var->source.range.begin.column, 14u);
|
EXPECT_EQ(var->source.range.begin.column, 14u);
|
||||||
@ -81,7 +81,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute) {
|
|||||||
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(var->type, nullptr);
|
ASSERT_NE(var->type, nullptr);
|
||||||
EXPECT_TRUE(var->type->Is<ast::F32>());
|
EXPECT_TRUE(var->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kUniform);
|
EXPECT_EQ(var->declared_address_space, ast::AddressSpace::kUniform);
|
||||||
|
|
||||||
EXPECT_EQ(var->source.range.begin.line, 1u);
|
EXPECT_EQ(var->source.range.begin.line, 1u);
|
||||||
EXPECT_EQ(var->source.range.begin.column, 36u);
|
EXPECT_EQ(var->source.range.begin.column, 36u);
|
||||||
@ -112,7 +112,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute_MulitpleGroups) {
|
|||||||
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
EXPECT_EQ(var->symbol, p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(var->type, nullptr);
|
ASSERT_NE(var->type, nullptr);
|
||||||
EXPECT_TRUE(var->type->Is<ast::F32>());
|
EXPECT_TRUE(var->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(var->declared_storage_class, ast::StorageClass::kUniform);
|
EXPECT_EQ(var->declared_address_space, ast::AddressSpace::kUniform);
|
||||||
|
|
||||||
EXPECT_EQ(var->source.range.begin.line, 1u);
|
EXPECT_EQ(var->source.range.begin.line, 1u);
|
||||||
EXPECT_EQ(var->source.range.begin.column, 36u);
|
EXPECT_EQ(var->source.range.begin.column, 36u);
|
||||||
@ -165,7 +165,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
|
|||||||
EXPECT_TRUE(e.errored);
|
EXPECT_TRUE(e.errored);
|
||||||
EXPECT_FALSE(e.matched);
|
EXPECT_FALSE(e.matched);
|
||||||
EXPECT_EQ(e.value, nullptr);
|
EXPECT_EQ(e.value, nullptr);
|
||||||
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
|
EXPECT_EQ(p->error(), "1:5: invalid address space for variable declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -176,7 +176,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_WithAccess) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
ASSERT_EQ(ptr->access, ast::Access::kRead);
|
ASSERT_EQ(ptr->access, ast::Access::kRead);
|
||||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::Vector>());
|
ASSERT_TRUE(ptr->type->Is<ast::Vector>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
|
|
||||||
auto* vec = ptr->type->As<ast::Vector>();
|
auto* vec = ptr->type->As<ast::Vector>();
|
||||||
ASSERT_EQ(vec->width, 2u);
|
ASSERT_EQ(vec->width, 2u);
|
||||||
@ -245,7 +245,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThanAfterAccess) {
|
|||||||
ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
|
ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterStorageClass) {
|
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterAddressSpace) {
|
||||||
auto p = parser("ptr<function f32>");
|
auto p = parser("ptr<function f32>");
|
||||||
auto t = p->type_decl();
|
auto t = p->type_decl();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
@ -265,14 +265,14 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterAccess) {
|
|||||||
ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
|
ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
|
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingAddressSpace) {
|
||||||
auto p = parser("ptr<, f32>");
|
auto p = parser("ptr<, f32>");
|
||||||
auto t = p->type_decl();
|
auto t = p->type_decl();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
ASSERT_EQ(p->error(), "1:5: expected identifier for address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
|
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
|
||||||
@ -302,17 +302,17 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
|
|||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
ASSERT_EQ(p->error(), "1:5: expected identifier for address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
|
TEST_F(ParserImplTest, TypeDecl_Ptr_BadAddressSpace) {
|
||||||
auto p = parser("ptr<unknown, f32>");
|
auto p = parser("ptr<unknown, f32>");
|
||||||
auto t = p->type_decl();
|
auto t = p->type_decl();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
|
ASSERT_EQ(p->error(), "1:5: invalid address space for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDecl_Ptr_BadAccess) {
|
TEST_F(ParserImplTest, TypeDecl_Ptr_BadAccess) {
|
||||||
|
@ -167,7 +167,7 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_WithAccess) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
ASSERT_EQ(ptr->access, ast::Access::kRead);
|
ASSERT_EQ(ptr->access, ast::Access::kRead);
|
||||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_ToVec) {
|
|||||||
|
|
||||||
auto* ptr = t.value->As<ast::Pointer>();
|
auto* ptr = t.value->As<ast::Pointer>();
|
||||||
ASSERT_TRUE(ptr->type->Is<ast::Vector>());
|
ASSERT_TRUE(ptr->type->Is<ast::Vector>());
|
||||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
ASSERT_EQ(ptr->address_space, ast::AddressSpace::kFunction);
|
||||||
|
|
||||||
auto* vec = ptr->type->As<ast::Vector>();
|
auto* vec = ptr->type->As<ast::Vector>();
|
||||||
ASSERT_EQ(vec->width, 2u);
|
ASSERT_EQ(vec->width, 2u);
|
||||||
@ -236,7 +236,7 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingGreaterThanAfterAccess) {
|
|||||||
ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
|
ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterStorageClass) {
|
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterAddressSpace) {
|
||||||
auto p = parser("ptr<function f32>");
|
auto p = parser("ptr<function f32>");
|
||||||
auto t = p->type_decl_without_ident();
|
auto t = p->type_decl_without_ident();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
@ -256,14 +256,14 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterAccess) {
|
|||||||
ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
|
ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingStorageClass) {
|
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingAddressSpace) {
|
||||||
auto p = parser("ptr<, f32>");
|
auto p = parser("ptr<, f32>");
|
||||||
auto t = p->type_decl_without_ident();
|
auto t = p->type_decl_without_ident();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
ASSERT_EQ(p->error(), "1:5: expected identifier for address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingType) {
|
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingType) {
|
||||||
@ -293,17 +293,17 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingParams) {
|
|||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
ASSERT_EQ(p->error(), "1:5: expected identifier for address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadStorageClass) {
|
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAddressSpace) {
|
||||||
auto p = parser("ptr<unknown, f32>");
|
auto p = parser("ptr<unknown, f32>");
|
||||||
auto t = p->type_decl_without_ident();
|
auto t = p->type_decl_without_ident();
|
||||||
EXPECT_TRUE(t.errored);
|
EXPECT_TRUE(t.errored);
|
||||||
EXPECT_FALSE(t.matched);
|
EXPECT_FALSE(t.matched);
|
||||||
ASSERT_EQ(t.value, nullptr);
|
ASSERT_EQ(t.value, nullptr);
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
|
ASSERT_EQ(p->error(), "1:5: invalid address space for ptr declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAccess) {
|
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAccess) {
|
||||||
|
@ -72,7 +72,7 @@ TEST_F(ParserImplTest, VariableDecl_MissingVar) {
|
|||||||
ASSERT_TRUE(t.IsIdentifier());
|
ASSERT_TRUE(t.IsIdentifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
|
TEST_F(ParserImplTest, VariableDecl_WithAddressSpace) {
|
||||||
auto p = parser("var<private> my_var : f32");
|
auto p = parser("var<private> my_var : f32");
|
||||||
auto v = p->variable_decl();
|
auto v = p->variable_decl();
|
||||||
EXPECT_TRUE(v.matched);
|
EXPECT_TRUE(v.matched);
|
||||||
@ -80,7 +80,7 @@ TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
|
|||||||
EXPECT_FALSE(p->has_error());
|
EXPECT_FALSE(p->has_error());
|
||||||
EXPECT_EQ(v->name, "my_var");
|
EXPECT_EQ(v->name, "my_var");
|
||||||
EXPECT_TRUE(v->type->Is<ast::F32>());
|
EXPECT_TRUE(v->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(v->storage_class, ast::StorageClass::kPrivate);
|
EXPECT_EQ(v->address_space, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_EQ(v->source.range.begin.line, 1u);
|
EXPECT_EQ(v->source.range.begin.line, 1u);
|
||||||
EXPECT_EQ(v->source.range.begin.column, 14u);
|
EXPECT_EQ(v->source.range.begin.column, 14u);
|
||||||
@ -96,16 +96,16 @@ TEST_F(ParserImplTest, VariableDecl_WithPushConstant) {
|
|||||||
EXPECT_FALSE(p->has_error());
|
EXPECT_FALSE(p->has_error());
|
||||||
EXPECT_EQ(v->name, "my_var");
|
EXPECT_EQ(v->name, "my_var");
|
||||||
EXPECT_TRUE(v->type->Is<ast::F32>());
|
EXPECT_TRUE(v->type->Is<ast::F32>());
|
||||||
EXPECT_EQ(v->storage_class, ast::StorageClass::kPushConstant);
|
EXPECT_EQ(v->address_space, ast::AddressSpace::kPushConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
|
TEST_F(ParserImplTest, VariableDecl_InvalidAddressSpace) {
|
||||||
auto p = parser("var<unknown> my_var : f32");
|
auto p = parser("var<unknown> my_var : f32");
|
||||||
auto v = p->variable_decl();
|
auto v = p->variable_decl();
|
||||||
EXPECT_FALSE(v.matched);
|
EXPECT_FALSE(v.matched);
|
||||||
EXPECT_TRUE(v.errored);
|
EXPECT_TRUE(v.errored);
|
||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
|
EXPECT_EQ(p->error(), "1:5: invalid address space for variable declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -19,7 +19,7 @@ namespace {
|
|||||||
|
|
||||||
struct VariableStorageData {
|
struct VariableStorageData {
|
||||||
const char* input;
|
const char* input;
|
||||||
ast::StorageClass storage_class;
|
ast::AddressSpace address_space;
|
||||||
ast::Access access;
|
ast::Access access;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
|
inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
|
||||||
@ -29,7 +29,7 @@ inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
|
|||||||
|
|
||||||
class VariableQualifierTest : public ParserImplTestWithParam<VariableStorageData> {};
|
class VariableQualifierTest : public ParserImplTestWithParam<VariableStorageData> {};
|
||||||
|
|
||||||
TEST_P(VariableQualifierTest, ParsesStorageClass) {
|
TEST_P(VariableQualifierTest, ParsesAddressSpace) {
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
auto p = parser(std::string("<") + params.input + ">");
|
auto p = parser(std::string("<") + params.input + ">");
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ TEST_P(VariableQualifierTest, ParsesStorageClass) {
|
|||||||
EXPECT_FALSE(p->has_error());
|
EXPECT_FALSE(p->has_error());
|
||||||
EXPECT_FALSE(sc.errored);
|
EXPECT_FALSE(sc.errored);
|
||||||
EXPECT_TRUE(sc.matched);
|
EXPECT_TRUE(sc.matched);
|
||||||
EXPECT_EQ(sc->storage_class, params.storage_class);
|
EXPECT_EQ(sc->address_space, params.address_space);
|
||||||
EXPECT_EQ(sc->access, params.access);
|
EXPECT_EQ(sc->access, params.access);
|
||||||
|
|
||||||
auto& t = p->next();
|
auto& t = p->next();
|
||||||
@ -47,14 +47,14 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
ParserImplTest,
|
ParserImplTest,
|
||||||
VariableQualifierTest,
|
VariableQualifierTest,
|
||||||
testing::Values(
|
testing::Values(
|
||||||
VariableStorageData{"uniform", ast::StorageClass::kUniform, ast::Access::kUndefined},
|
VariableStorageData{"uniform", ast::AddressSpace::kUniform, ast::Access::kUndefined},
|
||||||
VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup, ast::Access::kUndefined},
|
VariableStorageData{"workgroup", ast::AddressSpace::kWorkgroup, ast::Access::kUndefined},
|
||||||
VariableStorageData{"storage", ast::StorageClass::kStorage, ast::Access::kUndefined},
|
VariableStorageData{"storage", ast::AddressSpace::kStorage, ast::Access::kUndefined},
|
||||||
VariableStorageData{"private", ast::StorageClass::kPrivate, ast::Access::kUndefined},
|
VariableStorageData{"private", ast::AddressSpace::kPrivate, ast::Access::kUndefined},
|
||||||
VariableStorageData{"function", ast::StorageClass::kFunction, ast::Access::kUndefined},
|
VariableStorageData{"function", ast::AddressSpace::kFunction, ast::Access::kUndefined},
|
||||||
VariableStorageData{"storage, read", ast::StorageClass::kStorage, ast::Access::kRead},
|
VariableStorageData{"storage, read", ast::AddressSpace::kStorage, ast::Access::kRead},
|
||||||
VariableStorageData{"storage, write", ast::StorageClass::kStorage, ast::Access::kWrite},
|
VariableStorageData{"storage, write", ast::AddressSpace::kStorage, ast::Access::kWrite},
|
||||||
VariableStorageData{"storage, read_write", ast::StorageClass::kStorage,
|
VariableStorageData{"storage, read_write", ast::AddressSpace::kStorage,
|
||||||
ast::Access::kReadWrite}));
|
ast::Access::kReadWrite}));
|
||||||
|
|
||||||
TEST_F(ParserImplTest, VariableQualifier_NoMatch) {
|
TEST_F(ParserImplTest, VariableQualifier_NoMatch) {
|
||||||
@ -63,7 +63,7 @@ TEST_F(ParserImplTest, VariableQualifier_NoMatch) {
|
|||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_TRUE(sc.errored);
|
EXPECT_TRUE(sc.errored);
|
||||||
EXPECT_FALSE(sc.matched);
|
EXPECT_FALSE(sc.matched);
|
||||||
EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
|
EXPECT_EQ(p->error(), "1:2: invalid address space for variable declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, VariableQualifier_Empty) {
|
TEST_F(ParserImplTest, VariableQualifier_Empty) {
|
||||||
@ -72,7 +72,7 @@ TEST_F(ParserImplTest, VariableQualifier_Empty) {
|
|||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_TRUE(sc.errored);
|
EXPECT_TRUE(sc.errored);
|
||||||
EXPECT_FALSE(sc.matched);
|
EXPECT_FALSE(sc.matched);
|
||||||
EXPECT_EQ(p->error(), "1:2: expected identifier for storage class");
|
EXPECT_EQ(p->error(), "1:2: expected identifier for address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
|
TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
|
||||||
|
@ -22,10 +22,10 @@ using namespace tint::number_suffixes; // NOLINT
|
|||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ResolverStorageClassLayoutValidationTest = ResolverTest;
|
using ResolverAddressSpaceLayoutValidationTest = ResolverTest;
|
||||||
|
|
||||||
// Detect unaligned member for storage buffers
|
// Detect unaligned member for storage buffers
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, StorageBuffer_UnalignedMember) {
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(5) a : f32;
|
// @size(5) a : f32;
|
||||||
// @align(1) b : f32;
|
// @align(1) b : f32;
|
||||||
@ -39,13 +39,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember)
|
|||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)}),
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::AddressSpace::kStorage, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
|
R"(34:56 error: the offset of a struct member of type 'f32' in address space 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
|
||||||
12:34 note: see layout of struct:
|
12:34 note: see layout of struct:
|
||||||
/* align(4) size(12) */ struct S {
|
/* align(4) size(12) */ struct S {
|
||||||
/* offset(0) align(4) size( 5) */ a : f32;
|
/* offset(0) align(4) size( 5) */ a : f32;
|
||||||
@ -55,7 +55,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember)
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember_SuggestedFix) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, StorageBuffer_UnalignedMember_SuggestedFix) {
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(5) a : f32;
|
// @size(5) a : f32;
|
||||||
// @align(4) b : f32;
|
// @align(4) b : f32;
|
||||||
@ -69,14 +69,14 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember_S
|
|||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_i)}),
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::AddressSpace::kStorage, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect unaligned struct member for uniform buffers
|
// Detect unaligned struct member for uniform buffers
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Struct) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_UnalignedMember_Struct) {
|
||||||
// struct Inner {
|
// struct Inner {
|
||||||
// scalar : i32;
|
// scalar : i32;
|
||||||
// };
|
// };
|
||||||
@ -100,13 +100,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_S
|
|||||||
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
|
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: the offset of a struct member of type 'Inner' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
|
R"(56:78 error: the offset of a struct member of type 'Inner' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
|
||||||
34:56 note: see layout of struct:
|
34:56 note: see layout of struct:
|
||||||
/* align(4) size(8) */ struct Outer {
|
/* align(4) size(8) */ struct Outer {
|
||||||
/* offset(0) align(4) size(4) */ scalar : f32;
|
/* offset(0) align(4) size(4) */ scalar : f32;
|
||||||
@ -119,7 +119,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_S
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest,
|
TEST_F(ResolverAddressSpaceLayoutValidationTest,
|
||||||
UniformBuffer_UnalignedMember_Struct_SuggestedFix) {
|
UniformBuffer_UnalignedMember_Struct_SuggestedFix) {
|
||||||
// struct Inner {
|
// struct Inner {
|
||||||
// scalar : i32;
|
// scalar : i32;
|
||||||
@ -145,14 +145,14 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
|
|||||||
utils::Vector{MemberAlign(16_i)}),
|
utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect unaligned array member for uniform buffers
|
// Detect unaligned array member for uniform buffers
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Array) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_UnalignedMember_Array) {
|
||||||
// type Inner = @stride(16) array<f32, 10u>;
|
// type Inner = @stride(16) array<f32, 10u>;
|
||||||
//
|
//
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
@ -170,13 +170,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
|
|||||||
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
|
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
|
R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in address space 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
|
||||||
12:34 note: see layout of struct:
|
12:34 note: see layout of struct:
|
||||||
/* align(4) size(164) */ struct Outer {
|
/* align(4) size(164) */ struct Outer {
|
||||||
/* offset( 0) align(4) size( 4) */ scalar : f32;
|
/* offset( 0) align(4) size( 4) */ scalar : f32;
|
||||||
@ -185,7 +185,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Array_SuggestedFix) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_UnalignedMember_Array_SuggestedFix) {
|
||||||
// type Inner = @stride(16) array<f32, 10u>;
|
// type Inner = @stride(16) array<f32, 10u>;
|
||||||
//
|
//
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
@ -204,7 +204,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
|
|||||||
utils::Vector{MemberAlign(16_i)}),
|
utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -212,7 +212,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A
|
|||||||
|
|
||||||
// Detect uniform buffers with byte offset between 2 members that is not a
|
// Detect uniform buffers with byte offset between 2 members that is not a
|
||||||
// multiple of 16 bytes
|
// multiple of 16 bytes
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotMultipleOf16) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_MembersOffsetNotMultipleOf16) {
|
||||||
// struct Inner {
|
// struct Inner {
|
||||||
// @align(1) @size(5) scalar : i32;
|
// @align(1) @size(5) scalar : i32;
|
||||||
// };
|
// };
|
||||||
@ -236,7 +236,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotM
|
|||||||
Member(Source{{78, 90}}, "scalar", ty.i32()),
|
Member(Source{{78, 90}}, "scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -257,7 +257,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotM
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See https://crbug.com/tint/1344
|
// See https://crbug.com/tint/1344
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest,
|
TEST_F(ResolverAddressSpaceLayoutValidationTest,
|
||||||
UniformBuffer_MembersOffsetNotMultipleOf16_InnerMoreMembersThanOuter) {
|
UniformBuffer_MembersOffsetNotMultipleOf16_InnerMoreMembersThanOuter) {
|
||||||
// struct Inner {
|
// struct Inner {
|
||||||
// a : i32;
|
// a : i32;
|
||||||
@ -288,7 +288,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
|
|||||||
Member(Source{{78, 90}}, "scalar", ty.i32()),
|
Member(Source{{78, 90}}, "scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -311,7 +311,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
|
|||||||
22:24 note: see declaration of variable)");
|
22:24 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest,
|
TEST_F(ResolverAddressSpaceLayoutValidationTest,
|
||||||
UniformBuffer_MembersOffsetNotMultipleOf16_SuggestedFix) {
|
UniformBuffer_MembersOffsetNotMultipleOf16_SuggestedFix) {
|
||||||
// struct Inner {
|
// struct Inner {
|
||||||
// @align(1) @size(5) scalar : i32;
|
// @align(1) @size(5) scalar : i32;
|
||||||
@ -336,7 +336,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
|
|||||||
Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16_i)}),
|
Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -344,7 +344,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
|
|||||||
|
|
||||||
// Make sure that this doesn't fail validation because vec3's align is 16, but
|
// Make sure that this doesn't fail validation because vec3's align is 16, but
|
||||||
// size is 12. 's' should be at offset 12, which is okay here.
|
// size is 12. 's' should be at offset 12, which is okay here.
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_Vec3MemberOffset_NoFail) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_Vec3MemberOffset_NoFail) {
|
||||||
// struct ScalarPackedAtEndOfVec3 {
|
// struct ScalarPackedAtEndOfVec3 {
|
||||||
// v : vec3<f32>;
|
// v : vec3<f32>;
|
||||||
// s : f32;
|
// s : f32;
|
||||||
@ -358,13 +358,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_Vec3MemberOffset_
|
|||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
|
||||||
ast::StorageClass::kUniform, Group(0_a), Binding(0_a));
|
ast::AddressSpace::kUniform, Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect array stride must be a multiple of 16 bytes for uniform buffers
|
// Detect array stride must be a multiple of 16 bytes for uniform buffers
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Scalar) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_Scalar) {
|
||||||
// type Inner = array<f32, 10u>;
|
// type Inner = array<f32, 10u>;
|
||||||
//
|
//
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
@ -383,7 +383,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
Member("scalar", ty.i32()),
|
Member("scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -398,7 +398,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Vector) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_Vector) {
|
||||||
// type Inner = array<vec2<f32>, 10u>;
|
// type Inner = array<vec2<f32>, 10u>;
|
||||||
//
|
//
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
@ -417,7 +417,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
Member("scalar", ty.i32()),
|
Member("scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -433,7 +433,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Struct) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_Struct) {
|
||||||
// struct ArrayElem {
|
// struct ArrayElem {
|
||||||
// a : f32;
|
// a : f32;
|
||||||
// b : i32;
|
// b : i32;
|
||||||
@ -460,7 +460,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
Member("scalar", ty.i32()),
|
Member("scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -475,11 +475,11 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_TopLevelArray) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_TopLevelArray) {
|
||||||
// @group(0) @binding(0)
|
// @group(0) @binding(0)
|
||||||
// var<uniform> a : array<f32, 4u>;
|
// var<uniform> a : array<f32, 4u>;
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
|
GlobalVar(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
|
||||||
ast::StorageClass::kUniform, Group(0_a), Binding(0_a));
|
ast::AddressSpace::kUniform, Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
@ -487,7 +487,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.)");
|
R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_NestedArray) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_NestedArray) {
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
// inner : array<array<f32, 4u>, 4u>
|
// inner : array<array<f32, 4u>, 4u>
|
||||||
// };
|
// };
|
||||||
@ -500,7 +500,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4_u), 4_u)),
|
Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4_u), 4_u)),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -514,7 +514,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_SuggestedFix) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, UniformBuffer_InvalidArrayStride_SuggestedFix) {
|
||||||
// type Inner = @stride(16) array<f32, 10u>;
|
// type Inner = @stride(16) array<f32, 10u>;
|
||||||
//
|
//
|
||||||
// struct Outer {
|
// struct Outer {
|
||||||
@ -533,14 +533,14 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStrid
|
|||||||
Member("scalar", ty.i32()),
|
Member("scalar", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::AddressSpace::kUniform, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect unaligned member for push constants buffers
|
// Detect unaligned member for push constants buffers
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, PushConstant_UnalignedMember) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(5) a : f32;
|
// @size(5) a : f32;
|
||||||
@ -552,12 +552,12 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) {
|
|||||||
Source{{12, 34}}, "S",
|
Source{{12, 34}}, "S",
|
||||||
utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)})});
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)})});
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'push_constant' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
|
R"(34:56 error: the offset of a struct member of type 'f32' in address space 'push_constant' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
|
||||||
12:34 note: see layout of struct:
|
12:34 note: see layout of struct:
|
||||||
/* align(4) size(12) */ struct S {
|
/* align(4) size(12) */ struct S {
|
||||||
/* offset(0) align(4) size( 5) */ a : f32;
|
/* offset(0) align(4) size( 5) */ a : f32;
|
||||||
@ -567,7 +567,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) {
|
|||||||
78:90 note: see declaration of variable)");
|
78:90 note: see declaration of variable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_Aligned) {
|
TEST_F(ResolverAddressSpaceLayoutValidationTest, PushConstant_Aligned) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(5) a : f32;
|
// @size(5) a : f32;
|
||||||
@ -577,7 +577,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_Aligned) {
|
|||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member("b", ty.f32(), utils::Vector{MemberAlign(4_i)})});
|
Member("b", ty.f32(), utils::Vector{MemberAlign(4_i)})});
|
||||||
GlobalVar("a", ty.type_name("S"), ast::StorageClass::kPushConstant);
|
GlobalVar("a", ty.type_name("S"), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
@ -25,169 +25,169 @@ namespace {
|
|||||||
|
|
||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
|
|
||||||
using ResolverStorageClassValidationTest = ResolverTest;
|
using ResolverAddressSpaceValidationTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
|
TEST_F(ResolverAddressSpaceValidationTest, GlobalVariableNoAddressSpace_Fail) {
|
||||||
// var g : f32;
|
// var g : f32;
|
||||||
GlobalVar(Source{{12, 34}}, "g", ty.f32());
|
GlobalVar(Source{{12, 34}}, "g", ty.f32());
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: module-scope 'var' declaration must have a storage class");
|
"12:34 error: module-scope 'var' declaration must have a address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, GlobalVariableFunctionStorageClass_Fail) {
|
TEST_F(ResolverAddressSpaceValidationTest, GlobalVariableFunctionAddressSpace_Fail) {
|
||||||
// var<function> g : f32;
|
// var<function> g : f32;
|
||||||
GlobalVar(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kFunction);
|
GlobalVar(Source{{12, 34}}, "g", ty.f32(), ast::AddressSpace::kFunction);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: module-scope 'var' must not use storage class 'function'");
|
"12:34 error: module-scope 'var' must not use address space 'function'");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArray) {
|
TEST_F(ResolverAddressSpaceValidationTest, Private_RuntimeArray) {
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
12:34 note: while instantiating 'var' v)");
|
12:34 note: while instantiating 'var' v)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArrayInStruct) {
|
TEST_F(ResolverAddressSpaceValidationTest, Private_RuntimeArrayInStruct) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
note: while analysing structure member S.m
|
note: while analysing structure member S.m
|
||||||
12:34 note: while instantiating 'var' v)");
|
12:34 note: while instantiating 'var' v)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArray) {
|
TEST_F(ResolverAddressSpaceValidationTest, Workgroup_RuntimeArray) {
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
12:34 note: while instantiating 'var' v)");
|
12:34 note: while instantiating 'var' v)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArrayInStruct) {
|
TEST_F(ResolverAddressSpaceValidationTest, Workgroup_RuntimeArrayInStruct) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.array(ty.i32()))});
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
note: while analysing structure member S.m
|
note: while analysing structure member S.m
|
||||||
12:34 note: while instantiating 'var' v)");
|
12:34 note: while instantiating 'var' v)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferBool) {
|
||||||
// var<storage> g : bool;
|
// var<storage> g : bool;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::AddressSpace::kStorage, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferBoolAlias) {
|
||||||
// type a = bool;
|
// type a = bool;
|
||||||
// var<storage, read> g : a;
|
// var<storage, read> g : a;
|
||||||
auto* a = Alias("a", ty.bool_());
|
auto* a = Alias("a", ty.bool_());
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::AddressSpace::kStorage, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// F16 types in storage and uniform buffer is not implemented yet.
|
// F16 types in storage and uniform buffer is not implemented yet.
|
||||||
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferF16_TemporallyBan) {
|
||||||
// var<storage> g : f16;
|
// var<storage> g : f16;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kStorage, Binding(0_a), Group(0_a));
|
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::AddressSpace::kStorage, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'storage' storage class is not "
|
"56:78 error: using f16 types in 'storage' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferF16Alias_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferF16Alias_TemporallyBan) {
|
||||||
// type a = f16;
|
// type a = f16;
|
||||||
// var<storage, read> g : a;
|
// var<storage, read> g : a;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* a = Alias("a", ty.f16());
|
auto* a = Alias("a", ty.f16());
|
||||||
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kStorage,
|
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::AddressSpace::kStorage,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'storage' storage class is not "
|
"56:78 error: using f16 types in 'storage' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferVectorF16_TemporallyBan) {
|
||||||
// var<storage> g : vec4<f16>;
|
// var<storage> g : vec4<f16>;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kStorage,
|
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::AddressSpace::kStorage,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'storage' storage class is not "
|
"56:78 error: using f16 types in 'storage' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferArrayF16_TemporallyBan) {
|
||||||
// struct S { a : f16 };
|
// struct S { a : f16 };
|
||||||
// var<storage, read> g : array<S, 3u>;
|
// var<storage, read> g : array<S, 3u>;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}))});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}))});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar("g", a, ast::StorageClass::kStorage, ast::Access::kRead, Binding(0_a), Group(0_a));
|
GlobalVar("g", a, ast::AddressSpace::kStorage, ast::Access::kRead, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'storage' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'storage' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferStructF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferStructF16_TemporallyBan) {
|
||||||
// struct S { x : f16 };
|
// struct S { x : f16 };
|
||||||
// var<storage, read> g : S;
|
// var<storage, read> g : S;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0_a),
|
GlobalVar("g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructF16Aliases_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferNoErrorStructF16Aliases_TemporallyBan) {
|
||||||
// struct S { x : f16 };
|
// struct S { x : f16 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<storage, read> g : a1;
|
// var<storage, read> g : a1;
|
||||||
@ -196,84 +196,84 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructF16Aliases_
|
|||||||
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
auto* a1 = Alias("a1", ty.Of(s));
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
auto* a2 = Alias("a2", ty.Of(a1));
|
auto* a2 = Alias("a2", ty.Of(a1));
|
||||||
GlobalVar("g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0_a),
|
GlobalVar("g", ty.Of(a2), ast::AddressSpace::kStorage, ast::Access::kRead, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'storage' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferPointer) {
|
||||||
// var<storage> g : ptr<private, f32>;
|
// var<storage> g : ptr<private, f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::AddressSpace::kPrivate),
|
||||||
ast::StorageClass::kStorage, Binding(0_a), Group(0_a));
|
ast::AddressSpace::kStorage, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferIntScalar) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferIntScalar) {
|
||||||
// var<storage> g : i32;
|
// var<storage> g : i32;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::AddressSpace::kStorage, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferVectorF32) {
|
||||||
// var<storage> g : vec4<f32>;
|
// var<storage> g : vec4<f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::AddressSpace::kStorage, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferArrayF32) {
|
||||||
// var<storage, read> g : array<S, 3u>;
|
// var<storage, read> g : array<S, 3u>;
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", a, ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
|
TEST_F(ResolverAddressSpaceValidationTest, NotStorage_AccessMode) {
|
||||||
// var<private, read> g : a;
|
// var<private, read> g : a;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
|
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::AddressSpace::kPrivate, ast::Access::kRead);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
|
R"(56:78 error: only variables in <storage> address space may declare an access mode)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Storage_ReadAccessMode) {
|
TEST_F(ResolverAddressSpaceValidationTest, Storage_ReadAccessMode) {
|
||||||
// @group(0) @binding(0) var<storage, read> a : i32;
|
// @group(0) @binding(0) var<storage, read> a : i32;
|
||||||
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Storage_ReadWriteAccessMode) {
|
TEST_F(ResolverAddressSpaceValidationTest, Storage_ReadWriteAccessMode) {
|
||||||
// @group(0) @binding(0) var<storage, read_write> a : i32;
|
// @group(0) @binding(0) var<storage, read_write> a : i32;
|
||||||
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, Storage_WriteAccessMode) {
|
TEST_F(ResolverAddressSpaceValidationTest, Storage_WriteAccessMode) {
|
||||||
// @group(0) @binding(0) var<storage, read_write> a : i32;
|
// @group(0) @binding(0) var<storage, read_write> a : i32;
|
||||||
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kWrite,
|
GlobalVar(Source{{56, 78}}, "a", ty.i32(), ast::AddressSpace::kStorage, ast::Access::kWrite,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
@ -282,117 +282,117 @@ TEST_F(ResolverStorageClassValidationTest, Storage_WriteAccessMode) {
|
|||||||
R"(56:78 error: access mode 'write' is not valid for the 'storage' address space)");
|
R"(56:78 error: access mode 'write' is not valid for the 'storage' address space)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferStructI32) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferStructI32) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<storage, read> g : S;
|
// var<storage, read> g : S;
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve());
|
ASSERT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructI32Aliases) {
|
TEST_F(ResolverAddressSpaceValidationTest, StorageBufferNoErrorStructI32Aliases) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<storage, read> g : a1;
|
// var<storage, read> g : a1;
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
auto* a1 = Alias("a1", ty.Of(s));
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
auto* a2 = Alias("a2", ty.Of(a1));
|
auto* a2 = Alias("a2", ty.Of(a1));
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve());
|
ASSERT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBuffer_Struct_Runtime) {
|
||||||
// struct S { m: array<f32>; };
|
// struct S { m: array<f32>; };
|
||||||
// @group(0) @binding(0) var<uniform, > svar : S;
|
// @group(0) @binding(0) var<uniform, > svar : S;
|
||||||
|
|
||||||
auto* s = Structure(Source{{12, 34}}, "S", utils::Vector{Member("m", ty.array<i32>())});
|
auto* s = Structure(Source{{12, 34}}, "S", utils::Vector{Member("m", ty.array<i32>())});
|
||||||
|
|
||||||
GlobalVar(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "svar", ty.Of(s), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(56:78 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
note: while analysing structure member S.m
|
note: while analysing structure member S.m
|
||||||
56:78 note: while instantiating 'var' svar)");
|
56:78 note: while instantiating 'var' svar)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferBool) {
|
||||||
// var<uniform> g : bool;
|
// var<uniform> g : bool;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferBoolAlias) {
|
||||||
// type a = bool;
|
// type a = bool;
|
||||||
// var<uniform> g : a;
|
// var<uniform> g : a;
|
||||||
auto* a = Alias("a", ty.bool_());
|
auto* a = Alias("a", ty.bool_());
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'uniform' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// F16 types in storage and uniform buffer is not implemented yet.
|
// F16 types in storage and uniform buffer is not implemented yet.
|
||||||
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferF16_TemporallyBan) {
|
||||||
// var<uniform> g : f16;
|
// var<uniform> g : f16;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'uniform' storage class is not "
|
"56:78 error: using f16 types in 'uniform' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferF16Alias_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferF16Alias_TemporallyBan) {
|
||||||
// type a = f16;
|
// type a = f16;
|
||||||
// var<uniform> g : a;
|
// var<uniform> g : a;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* a = Alias("a", ty.f16());
|
auto* a = Alias("a", ty.f16());
|
||||||
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kUniform,
|
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::AddressSpace::kUniform,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'uniform' storage class is not "
|
"56:78 error: using f16 types in 'uniform' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferVectorF16_TemporallyBan) {
|
||||||
// var<uniform> g : vec4<f16>;
|
// var<uniform> g : vec4<f16>;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kUniform,
|
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::AddressSpace::kUniform,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferArrayF16_TemporallyBan) {
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(16) f : f16;
|
// @size(16) f : f16;
|
||||||
// }
|
// }
|
||||||
@ -402,29 +402,29 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF16_TemporallyBan)
|
|||||||
auto* s = Structure(
|
auto* s = Structure(
|
||||||
"S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}), utils::Vector{MemberSize(16_a)})});
|
"S", utils::Vector{Member("a", ty.f16(Source{{56, 78}}), utils::Vector{MemberSize(16_a)})});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar("g", a, ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("g", a, ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("56:78 error: using f16 types in 'uniform' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferStructF16_TemporallyBan) {
|
||||||
// struct S { x : f16 };
|
// struct S { x : f16 };
|
||||||
// var<uniform> g : S;
|
// var<uniform> g : S;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
GlobalVar("g", ty.Of(s), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("g", ty.Of(s), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16Aliases_TemporallyBan) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferStructF16Aliases_TemporallyBan) {
|
||||||
// struct S { x : f16 };
|
// struct S { x : f16 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<uniform> g : a1;
|
// var<uniform> g : a1;
|
||||||
@ -432,159 +432,159 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16Aliases_Tempora
|
|||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
auto* s = Structure("S", utils::Vector{Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
auto* a1 = Alias("a1", ty.Of(s));
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
GlobalVar("g", ty.Of(a1), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("g", ty.Of(a1), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' storage "
|
EXPECT_THAT(r()->error(), HasSubstr("12:34 error: using f16 types in 'uniform' address "
|
||||||
"class is not implemented yet"));
|
"space is not implemented yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferPointer) {
|
||||||
// var<uniform> g : ptr<private, f32>;
|
// var<uniform> g : ptr<private, f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::AddressSpace::kPrivate),
|
||||||
ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'uniform' as it is non-host-shareable
|
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'uniform' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferIntScalar) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferIntScalar) {
|
||||||
// var<uniform> g : i32;
|
// var<uniform> g : i32;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferVectorF32) {
|
||||||
// var<uniform> g : vec4<f32>;
|
// var<uniform> g : vec4<f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferArrayF32) {
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(16) f : f32;
|
// @size(16) f : f32;
|
||||||
// }
|
// }
|
||||||
// var<uniform> g : array<S, 3u>;
|
// var<uniform> g : array<S, 3u>;
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16_a)})});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16_a)})});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar(Source{{56, 78}}, "g", a, ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferStructI32) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<uniform> g : S;
|
// var<uniform> g : S;
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32Aliases) {
|
TEST_F(ResolverAddressSpaceValidationTest, UniformBufferStructI32Aliases) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<uniform> g : a1;
|
// var<uniform> g : a1;
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
auto* a1 = Alias("a1", ty.Of(s));
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform, Binding(0_a),
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a1), ast::AddressSpace::kUniform, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantBool) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantBool) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> g : bool;
|
// var<push_constant> g : bool;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{56, 78}}, "g", ty.bool_(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'push_constant' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'push_constant' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantF16) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantF16) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// enable f16;
|
// enable f16;
|
||||||
// var<push_constant> g : f16;
|
// var<push_constant> g : f16;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kPushConstant);
|
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"56:78 error: using f16 types in 'push_constant' storage class is not "
|
"56:78 error: using f16 types in 'push_constant' address space is not "
|
||||||
"implemented yet");
|
"implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantPointer) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantPointer) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> g : ptr<private, f32>;
|
// var<push_constant> g : ptr<private, f32>;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::AddressSpace::kPrivate),
|
||||||
ast::StorageClass::kPushConstant);
|
ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'push_constant' as it is non-host-shareable
|
R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in address space 'push_constant' as it is non-host-shareable
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantIntScalar) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantIntScalar) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> g : i32;
|
// var<push_constant> g : i32;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("g", ty.i32(), ast::StorageClass::kPushConstant);
|
GlobalVar("g", ty.i32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantVectorF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantVectorF32) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> g : vec4<f32>;
|
// var<push_constant> g : vec4<f32>;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPushConstant);
|
GlobalVar("g", ty.vec4<f32>(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantArrayF32) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantArrayF32) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// struct S { a : f32}
|
// struct S { a : f32}
|
||||||
// var<push_constant> g : array<S, 3u>;
|
// var<push_constant> g : array<S, 3u>;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar("g", a, ast::StorageClass::kPushConstant);
|
GlobalVar("g", a, ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, PushConstantWithInitializer) {
|
TEST_F(ResolverAddressSpaceValidationTest, PushConstantWithInitializer) {
|
||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> a : u32 = 0u;
|
// var<push_constant> a : u32 = 0u;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), ast::StorageClass::kPushConstant,
|
GlobalVar(Source{{1u, 2u}}, "a", ty.u32(), ast::AddressSpace::kPushConstant,
|
||||||
Expr(Source{{3u, 4u}}, u32(0)));
|
Expr(Source{{3u, 4u}}, u32(0)));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(1:2 error: var of storage class 'push_constant' cannot have an initializer. var initializers are only supported for the storage classes 'private' and 'function')");
|
R"(1:2 error: var of address space 'push_constant' cannot have an initializer. var initializers are only supported for the address spacees 'private' and 'function')");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -27,7 +27,7 @@ namespace {
|
|||||||
using ResolverIndexAccessorTest = ResolverTest;
|
using ResolverIndexAccessorTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
|
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
|
||||||
GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.mat2x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1_f));
|
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1_f));
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
|
TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
|
||||||
GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.mat2x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
|
auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
|
||||||
auto* acc = IndexAccessor("my_var", idx);
|
auto* acc = IndexAccessor("my_var", idx);
|
||||||
WrapInFunction(Decl(idx), acc);
|
WrapInFunction(Decl(idx), acc);
|
||||||
@ -50,7 +50,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
|
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
|
||||||
GlobalVar("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.mat4x4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* idx = Var("idx", ty.u32(), Expr(3_u));
|
auto* idx = Var("idx", ty.u32(), Expr(3_u));
|
||||||
auto* idy = Var("idy", ty.u32(), Expr(2_u));
|
auto* idy = Var("idy", ty.u32(), Expr(2_u));
|
||||||
auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
|
auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
|
||||||
@ -100,7 +100,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Matrix) {
|
TEST_F(ResolverIndexAccessorTest, Matrix) {
|
||||||
GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.mat2x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* acc = IndexAccessor("my_var", 1_i);
|
auto* acc = IndexAccessor("my_var", 1_i);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
@ -121,7 +121,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
|
TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
|
||||||
GlobalVar("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.mat2x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* acc = IndexAccessor(IndexAccessor("my_var", 0_i), 1_i);
|
auto* acc = IndexAccessor(IndexAccessor("my_var", 0_i), 1_i);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
@ -141,7 +141,7 @@ TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Vector_F32) {
|
TEST_F(ResolverIndexAccessorTest, Vector_F32) {
|
||||||
GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2_f));
|
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2_f));
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ TEST_F(ResolverIndexAccessorTest, Vector_F32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
|
TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
|
||||||
GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* idx = Var("idx", ty.i32(), Expr(2_i));
|
auto* idx = Var("idx", ty.i32(), Expr(2_i));
|
||||||
auto* acc = IndexAccessor("my_var", idx);
|
auto* acc = IndexAccessor("my_var", idx);
|
||||||
WrapInFunction(Decl(idx), acc);
|
WrapInFunction(Decl(idx), acc);
|
||||||
@ -173,7 +173,7 @@ TEST_F(ResolverIndexAccessorTest, Vector_Dynamic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Vector) {
|
TEST_F(ResolverIndexAccessorTest, Vector) {
|
||||||
GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* acc = IndexAccessor("my_var", 2_i);
|
auto* acc = IndexAccessor("my_var", 2_i);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
@ -193,7 +193,7 @@ TEST_F(ResolverIndexAccessorTest, Vector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
|
TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
|
||||||
GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.array<f32, 3>(), ast::AddressSpace::kPrivate);
|
||||||
auto* acc = IndexAccessor("my_var", 2_i);
|
auto* acc = IndexAccessor("my_var", 2_i);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -209,7 +209,7 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_i32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
|
TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
|
||||||
GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.array<f32, 3>(), ast::AddressSpace::kPrivate);
|
||||||
auto* acc = IndexAccessor("my_var", 2_u);
|
auto* acc = IndexAccessor("my_var", 2_u);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -225,7 +225,7 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
|
TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
|
||||||
GlobalVar("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.array<f32, 3>(), ast::AddressSpace::kPrivate);
|
||||||
auto* acc = IndexAccessor("my_var", 2_a);
|
auto* acc = IndexAccessor("my_var", 2_a);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -243,7 +243,7 @@ TEST_F(ResolverIndexAccessorTest, Array_Literal_AInt) {
|
|||||||
TEST_F(ResolverIndexAccessorTest, Alias_Array) {
|
TEST_F(ResolverIndexAccessorTest, Alias_Array) {
|
||||||
auto* aary = Alias("myarrty", ty.array<f32, 3>());
|
auto* aary = Alias("myarrty", ty.array<f32, 3>());
|
||||||
|
|
||||||
GlobalVar("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.Of(aary), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* acc = IndexAccessor("my_var", 2_i);
|
auto* acc = IndexAccessor("my_var", 2_i);
|
||||||
WrapInFunction(acc);
|
WrapInFunction(acc);
|
||||||
@ -337,7 +337,7 @@ TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncGoodParent) {
|
|||||||
// let x: f32 = (*p)[idx];
|
// let x: f32 = (*p)[idx];
|
||||||
// return x;
|
// return x;
|
||||||
// }
|
// }
|
||||||
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
|
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
|
||||||
auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
|
auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
|
||||||
auto* star_p = Deref(p);
|
auto* star_p = Deref(p);
|
||||||
auto* acc = IndexAccessor(Source{{12, 34}}, star_p, idx);
|
auto* acc = IndexAccessor(Source{{12, 34}}, star_p, idx);
|
||||||
@ -358,7 +358,7 @@ TEST_F(ResolverIndexAccessorTest, Expr_Deref_FuncBadParent) {
|
|||||||
// let x: f32 = *p[idx];
|
// let x: f32 = *p[idx];
|
||||||
// return x;
|
// return x;
|
||||||
// }
|
// }
|
||||||
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
|
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
|
||||||
auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
|
auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
|
||||||
auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
|
auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
|
||||||
auto* star_p = Deref(accessor_expr);
|
auto* star_p = Deref(accessor_expr);
|
||||||
|
@ -32,7 +32,7 @@ TEST_F(ResolverAssignmentValidationTest, ReadOnlyBuffer) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("m", ty.i32()),
|
Member("m", ty.i32()),
|
||||||
});
|
});
|
||||||
GlobalVar(Source{{12, 34}}, "a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{12, 34}}, "a", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1_i));
|
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1_i));
|
||||||
@ -192,7 +192,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignThroughPointer_Pass) {
|
|||||||
// var a : i32;
|
// var a : i32;
|
||||||
// let b : ptr<function,i32> = &a;
|
// let b : ptr<function,i32> = &a;
|
||||||
// *b = 2i;
|
// *b = 2i;
|
||||||
const auto func = ast::StorageClass::kFunction;
|
const auto func = ast::AddressSpace::kFunction;
|
||||||
WrapInFunction(Var("a", ty.i32(), func, Expr(2_i)), //
|
WrapInFunction(Var("a", ty.i32(), func, Expr(2_i)), //
|
||||||
Let("b", ty.pointer<i32>(func), AddressOf(Expr("a"))), //
|
Let("b", ty.pointer<i32>(func), AddressOf(Expr("a"))), //
|
||||||
Assign(Deref("b"), 2_i));
|
Assign(Deref("b"), 2_i));
|
||||||
@ -204,7 +204,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignMaterializedThroughPointer_Pass)
|
|||||||
// var a : i32;
|
// var a : i32;
|
||||||
// let b : ptr<function,i32> = &a;
|
// let b : ptr<function,i32> = &a;
|
||||||
// *b = 2;
|
// *b = 2;
|
||||||
const auto func = ast::StorageClass::kFunction;
|
const auto func = ast::AddressSpace::kFunction;
|
||||||
auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
|
auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
|
||||||
auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
|
auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
|
||||||
WrapInFunction(var_a, var_b, Assign(Deref("b"), 2_a));
|
WrapInFunction(var_a, var_b, Assign(Deref("b"), 2_a));
|
||||||
@ -251,7 +251,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("a", ty.atomic(ty.i32())),
|
Member("a", ty.atomic(ty.i32())),
|
||||||
});
|
});
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
|
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
|
||||||
@ -268,7 +268,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_RuntimeArray) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("a", ty.array(ty.f32())),
|
Member("a", ty.array(ty.f32())),
|
||||||
});
|
});
|
||||||
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
GlobalVar(Source{{12, 34}}, "v", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
|
WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
|
||||||
@ -288,7 +288,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_NonConstructibleStruct_Fa
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("arr", ty.array<i32>()),
|
Member("arr", ty.array<i32>()),
|
||||||
});
|
});
|
||||||
GlobalVar("s", ty.Of(s), ast::StorageClass::kStorage, Group(0_a), Binding(0_a));
|
GlobalVar("s", ty.Of(s), ast::AddressSpace::kStorage, Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
|
WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_DynamicArray_Fail) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("arr", ty.array<i32>()),
|
Member("arr", ty.array<i32>()),
|
||||||
});
|
});
|
||||||
GlobalVar("s", ty.Of(s), ast::StorageClass::kStorage, Group(0_a), Binding(0_a));
|
GlobalVar("s", ty.Of(s), ast::AddressSpace::kStorage, Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
|
WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
|
||||||
|
|
||||||
@ -363,9 +363,9 @@ TEST_F(ResolverAssignmentValidationTest, AssignToPhony_Pass) {
|
|||||||
GlobalVar("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), Group(0_a),
|
GlobalVar("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
GlobalVar("smp", ty.sampler(ast::SamplerKind::kSampler), Group(0_a), Binding(1_a));
|
GlobalVar("smp", ty.sampler(ast::SamplerKind::kSampler), Group(0_a), Binding(1_a));
|
||||||
GlobalVar("u", ty.Of(U), ast::StorageClass::kUniform, Group(0_a), Binding(2_a));
|
GlobalVar("u", ty.Of(U), ast::AddressSpace::kUniform, Group(0_a), Binding(2_a));
|
||||||
GlobalVar("s", ty.Of(S), ast::StorageClass::kStorage, Group(0_a), Binding(3_a));
|
GlobalVar("s", ty.Of(S), ast::AddressSpace::kStorage, Group(0_a), Binding(3_a));
|
||||||
GlobalVar("wg", ty.array<f32, 10>(), ast::StorageClass::kWorkgroup);
|
GlobalVar("wg", ty.array<f32, 10>(), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
WrapInFunction(Assign(Phony(), 1_i), //
|
WrapInFunction(Assign(Phony(), 1_i), //
|
||||||
Assign(Phony(), 2_u), //
|
Assign(Phony(), 2_u), //
|
||||||
|
@ -27,7 +27,7 @@ using namespace tint::number_suffixes; // NOLINT
|
|||||||
struct ResolverAtomicTest : public resolver::TestHelper, public testing::Test {};
|
struct ResolverAtomicTest : public resolver::TestHelper, public testing::Test {};
|
||||||
|
|
||||||
TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
|
TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
|
||||||
auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
|
auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
||||||
@ -37,7 +37,7 @@ TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
|
TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
|
||||||
auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.u32()), ast::StorageClass::kWorkgroup);
|
auto* g = GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.u32()), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
||||||
@ -48,7 +48,7 @@ TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
|
|||||||
|
|
||||||
TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
|
TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
|
||||||
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
auto* g = GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
auto* g = GlobalVar("g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
@ -26,64 +26,64 @@ namespace {
|
|||||||
|
|
||||||
struct ResolverAtomicValidationTest : public resolver::TestHelper, public testing::Test {};
|
struct ResolverAtomicValidationTest : public resolver::TestHelper, public testing::Test {};
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, StorageClass_WorkGroup) {
|
TEST_F(ResolverAtomicValidationTest, AddressSpace_WorkGroup) {
|
||||||
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
|
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve());
|
EXPECT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, StorageClass_Storage) {
|
TEST_F(ResolverAtomicValidationTest, AddressSpace_Storage) {
|
||||||
GlobalVar("g", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kStorage,
|
GlobalVar("g", ty.atomic(Source{{12, 34}}, ty.i32()), ast::AddressSpace::kStorage,
|
||||||
ast::Access::kReadWrite, Group(0_a), Binding(0_a));
|
ast::Access::kReadWrite, Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, StorageClass_Storage_Struct) {
|
TEST_F(ResolverAtomicValidationTest, AddressSpace_Storage_Struct) {
|
||||||
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite, Group(0_a),
|
GlobalVar("g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kReadWrite, Group(0_a),
|
||||||
Binding(0_a));
|
Binding(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidType) {
|
TEST_F(ResolverAtomicValidationTest, InvalidType) {
|
||||||
GlobalVar("a", ty.atomic(ty.f32(Source{{12, 34}})), ast::StorageClass::kWorkgroup);
|
GlobalVar("a", ty.atomic(ty.f32(Source{{12, 34}})), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
|
EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Simple) {
|
||||||
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: atomic variables must have <storage> or <workgroup> "
|
"12:34 error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class");
|
"address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Array) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Array) {
|
||||||
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: atomic variables must have <storage> or <workgroup> "
|
"12:34 error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class");
|
"address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Struct) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Struct) {
|
||||||
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(s), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"note: atomic sub-type of 's' is declared here");
|
"note: atomic sub-type of 's' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStruct) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_StructOfStruct) {
|
||||||
// struct Inner { m : atomic<i32>; };
|
// struct Inner { m : atomic<i32>; };
|
||||||
// struct Outer { m : array<Inner, 4>; };
|
// struct Outer { m : array<Inner, 4>; };
|
||||||
// var<private> g : Outer;
|
// var<private> g : Outer;
|
||||||
@ -91,16 +91,16 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStruct) {
|
|||||||
auto* Inner =
|
auto* Inner =
|
||||||
Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
||||||
GlobalVar("g", ty.Of(Outer), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(Outer), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"note: atomic sub-type of 'Outer' is declared here");
|
"note: atomic sub-type of 'Outer' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStructOfArray) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_StructOfStructOfArray) {
|
||||||
// struct Inner { m : array<atomic<i32>, 4>; };
|
// struct Inner { m : array<atomic<i32>, 4>; };
|
||||||
// struct Outer { m : array<Inner, 4>; };
|
// struct Outer { m : array<Inner, 4>; };
|
||||||
// var<private> g : Outer;
|
// var<private> g : Outer;
|
||||||
@ -108,46 +108,46 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStructOfArray)
|
|||||||
auto* Inner =
|
auto* Inner =
|
||||||
Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
|
Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
|
||||||
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
||||||
GlobalVar("g", ty.Of(Outer), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(Outer), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"12:34 note: atomic sub-type of 'Outer' is declared here");
|
"12:34 note: atomic sub-type of 'Outer' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfArray) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_ArrayOfArray) {
|
||||||
// type AtomicArray = array<atomic<i32>, 5>;
|
// type AtomicArray = array<atomic<i32>, 5>;
|
||||||
// var<private> v: array<s, 5>;
|
// var<private> v: array<s, 5>;
|
||||||
|
|
||||||
auto* atomic_array =
|
auto* atomic_array =
|
||||||
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
|
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
|
||||||
GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{56, 78}}, "v", ty.Of(atomic_array), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class");
|
"address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStruct) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_ArrayOfStruct) {
|
||||||
// struct S{
|
// struct S{
|
||||||
// m: atomic<u32>;
|
// m: atomic<u32>;
|
||||||
// };
|
// };
|
||||||
// var<private> v: array<S, 5u>;
|
// var<private> v: array<S, 5u>;
|
||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.atomic<u32>())});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.atomic<u32>())});
|
||||||
GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"note: atomic sub-type of 'array<S, 5>' is declared here");
|
"note: atomic sub-type of 'array<S, 5>' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStructOfArray) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_ArrayOfStructOfArray) {
|
||||||
// type AtomicArray = array<atomic<i32>, 5u>;
|
// type AtomicArray = array<atomic<i32>, 5u>;
|
||||||
// struct S{
|
// struct S{
|
||||||
// m: AtomicArray;
|
// m: AtomicArray;
|
||||||
@ -157,16 +157,16 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStructOfArray) {
|
|||||||
auto* atomic_array =
|
auto* atomic_array =
|
||||||
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
|
Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.Of(atomic_array))});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.Of(atomic_array))});
|
||||||
GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"note: atomic sub-type of 'array<S, 5>' is declared here");
|
"note: atomic sub-type of 'array<S, 5>' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAddressSpace_Complex) {
|
||||||
// type AtomicArray = array<atomic<i32>, 5u>;
|
// type AtomicArray = array<atomic<i32>, 5u>;
|
||||||
// struct S6 { x: array<i32, 4>; };
|
// struct S6 { x: array<i32, 4>; };
|
||||||
// struct S5 { x: S6;
|
// struct S5 { x: S6;
|
||||||
@ -198,35 +198,35 @@ TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
|
|||||||
auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
|
auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
|
||||||
auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
|
auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
|
||||||
auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
|
auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables must have <storage> or <workgroup> "
|
"error: atomic variables must have <storage> or <workgroup> "
|
||||||
"storage class\n"
|
"address space\n"
|
||||||
"note: atomic sub-type of 'S0' is declared here");
|
"note: atomic sub-type of 'S0' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
|
TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
|
||||||
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables in <storage> storage class must have read_write "
|
"error: atomic variables in <storage> address space must have read_write "
|
||||||
"access mode\n"
|
"access mode\n"
|
||||||
"note: atomic sub-type of 's' is declared here");
|
"note: atomic sub-type of 's' is declared here");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
|
TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
|
||||||
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
auto* s = Structure("s", utils::Vector{Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables in <storage> storage class must have read_write "
|
"error: atomic variables in <storage> address space must have read_write "
|
||||||
"access mode\n"
|
"access mode\n"
|
||||||
"note: atomic sub-type of 's' is declared here");
|
"note: atomic sub-type of 's' is declared here");
|
||||||
}
|
}
|
||||||
@ -239,12 +239,12 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStruct) {
|
|||||||
auto* Inner =
|
auto* Inner =
|
||||||
Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
Structure("Inner", utils::Vector{Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||||
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables in <storage> storage class must have read_write "
|
"error: atomic variables in <storage> address space must have read_write "
|
||||||
"access mode\n"
|
"access mode\n"
|
||||||
"note: atomic sub-type of 'Outer' is declared here");
|
"note: atomic sub-type of 'Outer' is declared here");
|
||||||
}
|
}
|
||||||
@ -257,12 +257,12 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStructOfArray) {
|
|||||||
auto* Inner =
|
auto* Inner =
|
||||||
Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
|
Structure("Inner", utils::Vector{Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
|
||||||
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
auto* Outer = Structure("Outer", utils::Vector{Member("m", ty.Of(Inner))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(Outer), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables in <storage> storage class must have "
|
"error: atomic variables in <storage> address space must have "
|
||||||
"read_write access mode\n"
|
"read_write access mode\n"
|
||||||
"12:34 note: atomic sub-type of 'Outer' is declared here");
|
"12:34 note: atomic sub-type of 'Outer' is declared here");
|
||||||
}
|
}
|
||||||
@ -299,12 +299,12 @@ TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Complex) {
|
|||||||
auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
|
auto* s2 = Structure("S2", utils::Vector{Member("x", ty.Of(s3))});
|
||||||
auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
|
auto* s1 = Structure("S1", utils::Vector{Member("x", ty.Of(s2))});
|
||||||
auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
|
auto* s0 = Structure("S0", utils::Vector{Member("x", ty.Of(s1))});
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s0), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: atomic variables in <storage> storage class must have "
|
"error: atomic variables in <storage> address space must have "
|
||||||
"read_write access mode\n"
|
"read_write access mode\n"
|
||||||
"note: atomic sub-type of 'S0' is declared here");
|
"note: atomic sub-type of 'S0' is declared here");
|
||||||
}
|
}
|
||||||
|
@ -721,7 +721,7 @@ TEST_F(StructMemberAttributeTest, Align_Attribute_ConstAFloat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructMemberAttributeTest, Align_Attribute_Var) {
|
TEST_F(StructMemberAttributeTest, Align_Attribute_Var) {
|
||||||
GlobalVar(Source{{1, 2}}, "val", ty.f32(), ast::StorageClass::kPrivate, ast::Access::kUndefined,
|
GlobalVar(Source{{1, 2}}, "val", ty.f32(), ast::AddressSpace::kPrivate, ast::Access::kUndefined,
|
||||||
Expr(1.23_f));
|
Expr(1.23_f));
|
||||||
|
|
||||||
Structure(Source{{6, 4}}, "mystruct",
|
Structure(Source{{6, 4}}, "mystruct",
|
||||||
@ -785,7 +785,7 @@ TEST_P(VariableAttributeTest, IsValid) {
|
|||||||
if (IsBindingAttribute(params.kind)) {
|
if (IsBindingAttribute(params.kind)) {
|
||||||
GlobalVar("a", ty.sampler(ast::SamplerKind::kSampler), attrs);
|
GlobalVar("a", ty.sampler(ast::SamplerKind::kSampler), attrs);
|
||||||
} else {
|
} else {
|
||||||
GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate, attrs);
|
GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.should_pass) {
|
if (params.should_pass) {
|
||||||
@ -956,7 +956,7 @@ TEST_P(ArrayStrideTest, All) {
|
|||||||
create<ast::StrideAttribute>(Source{{12, 34}}, params.stride),
|
create<ast::StrideAttribute>(Source{{12, 34}}, params.stride),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar("myarray", arr, ast::StorageClass::kPrivate);
|
GlobalVar("myarray", arr, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
if (params.should_pass) {
|
if (params.should_pass) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -1039,7 +1039,7 @@ TEST_F(ArrayStrideTest, DuplicateAttribute) {
|
|||||||
create<ast::StrideAttribute>(Source{{56, 78}}, 4u),
|
create<ast::StrideAttribute>(Source{{56, 78}}, 4u),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar("myarray", arr, ast::StorageClass::kPrivate);
|
GlobalVar("myarray", arr, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -1058,7 +1058,7 @@ TEST_F(ResourceAttributeTest, UniformBufferMissingBinding) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("x", ty.i32()),
|
Member("x", ty.i32()),
|
||||||
});
|
});
|
||||||
GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
|
GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::AddressSpace::kUniform);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -1069,7 +1069,7 @@ TEST_F(ResourceAttributeTest, StorageBufferMissingBinding) {
|
|||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("x", ty.i32()),
|
Member("x", ty.i32()),
|
||||||
});
|
});
|
||||||
GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead);
|
GlobalVar(Source{{12, 34}}, "G", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -1155,7 +1155,7 @@ TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByDifferentEntryPoints) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResourceAttributeTest, BindingPointOnNonResource) {
|
TEST_F(ResourceAttributeTest, BindingPointOnNonResource) {
|
||||||
GlobalVar(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate, Binding(1_a),
|
GlobalVar(Source{{12, 34}}, "G", ty.f32(), ast::AddressSpace::kPrivate, Binding(1_a),
|
||||||
Group(2_a));
|
Group(2_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -78,7 +78,7 @@ using ResolverBuiltinTest_BoolMethod = ResolverTestWithParam<std::string>;
|
|||||||
TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
|
TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
|
||||||
auto name = GetParam();
|
auto name = GetParam();
|
||||||
|
|
||||||
GlobalVar("my_var", ty.bool_(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.bool_(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call(name, "my_var");
|
auto* expr = Call(name, "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -91,7 +91,7 @@ TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
|
|||||||
TEST_P(ResolverBuiltinTest_BoolMethod, Vector) {
|
TEST_P(ResolverBuiltinTest_BoolMethod, Vector) {
|
||||||
auto name = GetParam();
|
auto name = GetParam();
|
||||||
|
|
||||||
GlobalVar("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<bool>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call(name, "my_var");
|
auto* expr = Call(name, "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -106,9 +106,9 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
|||||||
testing::Values("any", "all"));
|
testing::Values("any", "all"));
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Select) {
|
TEST_F(ResolverBuiltinTest, Select) {
|
||||||
GlobalVar("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
GlobalVar("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
|
GlobalVar("bool_var", ty.vec3<bool>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call("select", "my_var", "my_var", "bool_var");
|
auto* expr = Call("select", "my_var", "my_var", "bool_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -212,7 +212,7 @@ using ResolverBuiltinArrayTest = ResolverTest;
|
|||||||
TEST_F(ResolverBuiltinArrayTest, ArrayLength_Vector) {
|
TEST_F(ResolverBuiltinArrayTest, ArrayLength_Vector) {
|
||||||
auto* ary = ty.array<i32>();
|
auto* ary = ty.array<i32>();
|
||||||
auto* str = Structure("S", utils::Vector{Member("x", ary)});
|
auto* str = Structure("S", utils::Vector{Member("x", ary)});
|
||||||
GlobalVar("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0_a),
|
GlobalVar("a", ty.Of(str), ast::AddressSpace::kStorage, ast::Access::kRead, Binding(0_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
|
|
||||||
auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
|
auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
|
||||||
@ -225,7 +225,7 @@ TEST_F(ResolverBuiltinArrayTest, ArrayLength_Vector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinArrayTest, ArrayLength_Error_ArraySized) {
|
TEST_F(ResolverBuiltinArrayTest, ArrayLength_Error_ArraySized) {
|
||||||
GlobalVar("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
|
GlobalVar("arr", ty.array<i32, 4>(), ast::AddressSpace::kPrivate);
|
||||||
auto* call = Call("arrayLength", AddressOf("arr"));
|
auto* call = Call("arrayLength", AddressOf("arr"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1029,7 +1029,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpVector_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_FirstParamInt) {
|
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_FirstParamInt) {
|
||||||
GlobalVar("v", ty.i32(), ast::StorageClass::kWorkgroup);
|
GlobalVar("v", ty.i32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("frexp", 1_i, AddressOf("v"));
|
auto* call = Call("frexp", 1_i, AddressOf("v"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1045,7 +1045,7 @@ TEST_F(ResolverBuiltinFloatTest, Frexp_Error_FirstParamInt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_SecondParamFloatPtr) {
|
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_SecondParamFloatPtr) {
|
||||||
GlobalVar("v", ty.f32(), ast::StorageClass::kWorkgroup);
|
GlobalVar("v", ty.f32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("frexp", 1_f, AddressOf("v"));
|
auto* call = Call("frexp", 1_f, AddressOf("v"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1075,7 +1075,7 @@ TEST_F(ResolverBuiltinFloatTest, Frexp_Error_SecondParamNotAPointer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_VectorSizesDontMatch) {
|
TEST_F(ResolverBuiltinFloatTest, Frexp_Error_VectorSizesDontMatch) {
|
||||||
GlobalVar("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
|
GlobalVar("v", ty.vec4<i32>(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("frexp", vec2<f32>(1_f, 2_f), AddressOf("v"));
|
auto* call = Call("frexp", vec2<f32>(1_f, 2_f), AddressOf("v"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1324,7 +1324,7 @@ TEST_F(ResolverBuiltinFloatTest, ModfVector_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Modf_Error_FirstParamInt) {
|
TEST_F(ResolverBuiltinFloatTest, Modf_Error_FirstParamInt) {
|
||||||
GlobalVar("whole", ty.f32(), ast::StorageClass::kWorkgroup);
|
GlobalVar("whole", ty.f32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("modf", 1_i, AddressOf("whole"));
|
auto* call = Call("modf", 1_i, AddressOf("whole"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1340,7 +1340,7 @@ TEST_F(ResolverBuiltinFloatTest, Modf_Error_FirstParamInt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamIntPtr) {
|
TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamIntPtr) {
|
||||||
GlobalVar("whole", ty.i32(), ast::StorageClass::kWorkgroup);
|
GlobalVar("whole", ty.i32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("modf", 1_f, AddressOf("whole"));
|
auto* call = Call("modf", 1_f, AddressOf("whole"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1370,7 +1370,7 @@ TEST_F(ResolverBuiltinFloatTest, Modf_Error_SecondParamNotAPointer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinFloatTest, Modf_Error_VectorSizesDontMatch) {
|
TEST_F(ResolverBuiltinFloatTest, Modf_Error_VectorSizesDontMatch) {
|
||||||
GlobalVar("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
|
GlobalVar("whole", ty.vec4<f32>(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* call = Call("modf", vec2<f32>(1_f, 2_f), AddressOf("whole"));
|
auto* call = Call("modf", vec2<f32>(1_f, 2_f), AddressOf("whole"));
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
|
|
||||||
@ -1850,7 +1850,7 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
namespace matrix_builtin_tests {
|
namespace matrix_builtin_tests {
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Determinant_2x2_f32) {
|
TEST_F(ResolverBuiltinTest, Determinant_2x2_f32) {
|
||||||
GlobalVar("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat2x2<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1864,7 +1864,7 @@ TEST_F(ResolverBuiltinTest, Determinant_2x2_f32) {
|
|||||||
TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
|
TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("var", ty.mat2x2<f16>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat2x2<f16>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1876,7 +1876,7 @@ TEST_F(ResolverBuiltinTest, Determinant_2x2_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Determinant_3x3_f32) {
|
TEST_F(ResolverBuiltinTest, Determinant_3x3_f32) {
|
||||||
GlobalVar("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat3x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1890,7 +1890,7 @@ TEST_F(ResolverBuiltinTest, Determinant_3x3_f32) {
|
|||||||
TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
|
TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("var", ty.mat3x3<f16>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat3x3<f16>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1902,7 +1902,7 @@ TEST_F(ResolverBuiltinTest, Determinant_3x3_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Determinant_4x4_f32) {
|
TEST_F(ResolverBuiltinTest, Determinant_4x4_f32) {
|
||||||
GlobalVar("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat4x4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1916,7 +1916,7 @@ TEST_F(ResolverBuiltinTest, Determinant_4x4_f32) {
|
|||||||
TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
|
TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("var", ty.mat4x4<f16>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat4x4<f16>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1928,7 +1928,7 @@ TEST_F(ResolverBuiltinTest, Determinant_4x4_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
|
TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
|
||||||
GlobalVar("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.mat2x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1943,7 +1943,7 @@ TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
|
TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
|
||||||
GlobalVar("var", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* call = Call("determinant", "var");
|
auto* call = Call("determinant", "var");
|
||||||
WrapInFunction(call);
|
WrapInFunction(call);
|
||||||
@ -1963,7 +1963,7 @@ TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
|
|||||||
namespace vector_builtin_tests {
|
namespace vector_builtin_tests {
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Dot_Vec2_f32) {
|
TEST_F(ResolverBuiltinTest, Dot_Vec2_f32) {
|
||||||
GlobalVar("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec2<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call("dot", "my_var", "my_var");
|
auto* expr = Call("dot", "my_var", "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1977,7 +1977,7 @@ TEST_F(ResolverBuiltinTest, Dot_Vec2_f32) {
|
|||||||
TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
|
TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("my_var", ty.vec2<f16>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec2<f16>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call("dot", "my_var", "my_var");
|
auto* expr = Call("dot", "my_var", "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1989,7 +1989,7 @@ TEST_F(ResolverBuiltinTest, Dot_Vec2_f16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Dot_Vec3_i32) {
|
TEST_F(ResolverBuiltinTest, Dot_Vec3_i32) {
|
||||||
GlobalVar("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec3<i32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call("dot", "my_var", "my_var");
|
auto* expr = Call("dot", "my_var", "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -2001,7 +2001,7 @@ TEST_F(ResolverBuiltinTest, Dot_Vec3_i32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinTest, Dot_Vec4_u32) {
|
TEST_F(ResolverBuiltinTest, Dot_Vec4_u32) {
|
||||||
GlobalVar("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_var", ty.vec4<u32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call("dot", "my_var", "my_var");
|
auto* expr = Call("dot", "my_var", "my_var");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -2036,7 +2036,7 @@ using ResolverBuiltinDerivativeTest = ResolverTestWithParam<std::string>;
|
|||||||
TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
|
TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
|
||||||
auto name = GetParam();
|
auto name = GetParam();
|
||||||
|
|
||||||
GlobalVar("ident", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call(name, "ident");
|
auto* expr = Call(name, "ident");
|
||||||
Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
||||||
@ -2050,7 +2050,7 @@ TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
|
|||||||
|
|
||||||
TEST_P(ResolverBuiltinDerivativeTest, Vector) {
|
TEST_P(ResolverBuiltinDerivativeTest, Vector) {
|
||||||
auto name = GetParam();
|
auto name = GetParam();
|
||||||
GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Call(name, "ident");
|
auto* expr = Call(name, "ident");
|
||||||
Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
Func("func", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
||||||
@ -2146,7 +2146,7 @@ class ResolverBuiltinTest_TextureOperation : public ResolverTestWithParam<Textur
|
|||||||
GlobalVar(name, type, Binding(0_a), Group(0_a));
|
GlobalVar(name, type, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GlobalVar(name, type, ast::StorageClass::kPrivate);
|
GlobalVar(name, type, ast::AddressSpace::kPrivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
call_params->Push(Expr(name));
|
call_params->Push(Expr(name));
|
||||||
|
@ -113,7 +113,7 @@ TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalConst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVar) {
|
TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVar) {
|
||||||
GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
@ -100,7 +100,7 @@ using ResolverBuiltinsStageTest = ResolverTestWithParam<Params>;
|
|||||||
TEST_P(ResolverBuiltinsStageTest, All_input) {
|
TEST_P(ResolverBuiltinsStageTest, All_input) {
|
||||||
const Params& params = GetParam();
|
const Params& params = GetParam();
|
||||||
|
|
||||||
auto* p = GlobalVar("p", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
auto* p = GlobalVar("p", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* input = Param("input", params.type(*this),
|
auto* input = Param("input", params.type(*this),
|
||||||
utils::Vector{Builtin(Source{{12, 34}}, params.builtin)});
|
utils::Vector{Builtin(Source{{12, 34}}, params.builtin)});
|
||||||
switch (params.stage) {
|
switch (params.stage) {
|
||||||
|
@ -103,7 +103,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr) {
|
|||||||
// var z: i32 = 1i;
|
// var z: i32 = 1i;
|
||||||
// foo(&z);
|
// foo(&z);
|
||||||
// }
|
// }
|
||||||
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
|
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
|
||||||
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -120,7 +120,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_ConstIdentExpr) {
|
|||||||
// let z: i32 = 1i;
|
// let z: i32 = 1i;
|
||||||
// foo(&z);
|
// foo(&z);
|
||||||
// }
|
// }
|
||||||
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
|
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
|
||||||
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -142,7 +142,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_NotIdentExprVar) {
|
|||||||
auto* S = Structure("S", utils::Vector{
|
auto* S = Structure("S", utils::Vector{
|
||||||
Member("m", ty.i32()),
|
Member("m", ty.i32()),
|
||||||
});
|
});
|
||||||
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
|
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
|
||||||
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -166,7 +166,7 @@ TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfMemberAccessor) {
|
|||||||
auto* S = Structure("S", utils::Vector{
|
auto* S = Structure("S", utils::Vector{
|
||||||
Member("m", ty.i32()),
|
Member("m", ty.i32()),
|
||||||
});
|
});
|
||||||
auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
|
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
|
||||||
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -185,12 +185,12 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) {
|
|||||||
// }
|
// }
|
||||||
Func("foo",
|
Func("foo",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
|
||||||
},
|
},
|
||||||
ty.void_(), utils::Empty);
|
ty.void_(), utils::Empty);
|
||||||
Func("bar",
|
Func("bar",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
|
||||||
},
|
},
|
||||||
ty.void_(),
|
ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -212,12 +212,12 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
|
|||||||
// }
|
// }
|
||||||
Func("foo",
|
Func("foo",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
|
||||||
},
|
},
|
||||||
ty.void_(), utils::Empty);
|
ty.void_(), utils::Empty);
|
||||||
Func("bar",
|
Func("bar",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
|
||||||
},
|
},
|
||||||
ty.void_(),
|
ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -245,11 +245,11 @@ TEST_F(ResolverCallValidationTest, LetPointer) {
|
|||||||
// }
|
// }
|
||||||
Func("x",
|
Func("x",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kFunction)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
|
||||||
},
|
},
|
||||||
ty.void_(), utils::Empty);
|
ty.void_(), utils::Empty);
|
||||||
auto* v = Var("v", ty.i32());
|
auto* v = Var("v", ty.i32());
|
||||||
auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(v));
|
auto* p = Let("p", ty.pointer(ty.i32(), ast::AddressSpace::kFunction), AddressOf(v));
|
||||||
auto* c = Var("c", ty.i32(), Call("x", Expr(Source{{12, 34}}, p)));
|
auto* c = Var("c", ty.i32(), Call("x", Expr(Source{{12, 34}}, p)));
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -276,11 +276,11 @@ TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
|
|||||||
// }
|
// }
|
||||||
Func("foo",
|
Func("foo",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate)),
|
Param("p", ty.pointer<i32>(ast::AddressSpace::kPrivate)),
|
||||||
},
|
},
|
||||||
ty.void_(), utils::Empty);
|
ty.void_(), utils::Empty);
|
||||||
auto* v = GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
|
auto* v = GlobalVar("v", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kPrivate), AddressOf(v));
|
auto* p = Let("p", ty.pointer(ty.i32(), ast::AddressSpace::kPrivate), AddressOf(v));
|
||||||
auto* c = Var("c", ty.i32(), Call("foo", Expr(Source{{12, 34}}, p)));
|
auto* c = Var("c", ty.i32(), Call("foo", Expr(Source{{12, 34}}, p)));
|
||||||
Func("main", utils::Empty, ty.void_(),
|
Func("main", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -301,7 +301,7 @@ TEST_F(ResolverCallValidationTest, CallVariable) {
|
|||||||
// fn f() {
|
// fn f() {
|
||||||
// v();
|
// v();
|
||||||
// }
|
// }
|
||||||
GlobalVar("v", ty.i32(), ast::StorageClass::kPrivate);
|
GlobalVar("v", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
Func("f", utils::Empty, ty.void_(),
|
Func("f", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
CallStmt(Call(Source{{12, 34}}, "v")),
|
CallStmt(Call(Source{{12, 34}}, "v")),
|
||||||
|
@ -51,7 +51,7 @@ TEST_F(ResolverCompoundAssignmentValidationTest, CompatibleTypesAssignThroughPoi
|
|||||||
// var a : i32;
|
// var a : i32;
|
||||||
// let b : ptr<function,i32> = &a;
|
// let b : ptr<function,i32> = &a;
|
||||||
// *b += 2;
|
// *b += 2;
|
||||||
const auto func = ast::StorageClass::kFunction;
|
const auto func = ast::AddressSpace::kFunction;
|
||||||
auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
|
auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
|
||||||
auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
|
auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
|
||||||
WrapInFunction(var_a, var_b,
|
WrapInFunction(var_a, var_b,
|
||||||
@ -233,7 +233,7 @@ TEST_F(ResolverCompoundAssignmentValidationTest, ReadOnlyBuffer) {
|
|||||||
// {
|
// {
|
||||||
// a += 1i;
|
// a += 1i;
|
||||||
// }
|
// }
|
||||||
GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1_i, ast::BinaryOp::kAdd));
|
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1_i, ast::BinaryOp::kAdd));
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ TEST_F(ResolverCompoundAssignmentValidationTest, LhsLiteral) {
|
|||||||
TEST_F(ResolverCompoundAssignmentValidationTest, LhsAtomic) {
|
TEST_F(ResolverCompoundAssignmentValidationTest, LhsAtomic) {
|
||||||
// var<workgroup> a : atomic<i32>;
|
// var<workgroup> a : atomic<i32>;
|
||||||
// a += a;
|
// a += a;
|
||||||
GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
|
WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -2666,7 +2666,7 @@ TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_Low) {
|
|||||||
|
|
||||||
TEST_F(ResolverConstEvalTest, RuntimeArray_vec3_f32_Index_OOB_Low) {
|
TEST_F(ResolverConstEvalTest, RuntimeArray_vec3_f32_Index_OOB_Low) {
|
||||||
auto* sb = GlobalVar("sb", ty.array(ty.vec3<f32>()), Group(0_a), Binding(0_a),
|
auto* sb = GlobalVar("sb", ty.array(ty.vec3<f32>()), Group(0_a), Binding(0_a),
|
||||||
ast::StorageClass::kStorage);
|
ast::AddressSpace::kStorage);
|
||||||
auto* expr = IndexAccessor(sb, Expr(Source{{12, 34}}, -2_i));
|
auto* expr = IndexAccessor(sb, Expr(Source{{12, 34}}, -2_i));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
@ -425,7 +425,7 @@ const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Sourc
|
|||||||
auto& b = *builder;
|
auto& b = *builder;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolDeclKind::GlobalVar:
|
case SymbolDeclKind::GlobalVar:
|
||||||
return b.GlobalVar(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
|
return b.GlobalVar(source, symbol, b.ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
case SymbolDeclKind::GlobalConst:
|
case SymbolDeclKind::GlobalConst:
|
||||||
return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
|
return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
|
||||||
case SymbolDeclKind::Alias:
|
case SymbolDeclKind::Alias:
|
||||||
@ -468,27 +468,27 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolUseKind::GlobalVarType: {
|
case SymbolUseKind::GlobalVarType: {
|
||||||
auto* node = b.ty.type_name(source, symbol);
|
auto* node = b.ty.type_name(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), node, ast::StorageClass::kPrivate);
|
b.GlobalVar(b.Sym(), node, ast::AddressSpace::kPrivate);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarArrayElemType: {
|
case SymbolUseKind::GlobalVarArrayElemType: {
|
||||||
auto* node = b.ty.type_name(source, symbol);
|
auto* node = b.ty.type_name(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), ast::StorageClass::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.array(node, 4_i), ast::AddressSpace::kPrivate);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarArraySizeValue: {
|
case SymbolUseKind::GlobalVarArraySizeValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), ast::StorageClass::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.array(b.ty.i32(), node), ast::AddressSpace::kPrivate);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarVectorElemType: {
|
case SymbolUseKind::GlobalVarVectorElemType: {
|
||||||
auto* node = b.ty.type_name(source, symbol);
|
auto* node = b.ty.type_name(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.vec3(node), ast::AddressSpace::kPrivate);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarMatrixElemType: {
|
case SymbolUseKind::GlobalVarMatrixElemType: {
|
||||||
auto* node = b.ty.type_name(source, symbol);
|
auto* node = b.ty.type_name(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
|
b.GlobalVar(b.Sym(), b.ty.mat3x4(node), ast::AddressSpace::kPrivate);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarSampledTexElemType: {
|
case SymbolUseKind::GlobalVarSampledTexElemType: {
|
||||||
@ -503,7 +503,7 @@ const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source
|
|||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalVarValue: {
|
case SymbolUseKind::GlobalVarValue: {
|
||||||
auto* node = b.Expr(source, symbol);
|
auto* node = b.Expr(source, symbol);
|
||||||
b.GlobalVar(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
|
b.GlobalVar(b.Sym(), b.ty.i32(), ast::AddressSpace::kPrivate, node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SymbolUseKind::GlobalConstType: {
|
case SymbolUseKind::GlobalConstType: {
|
||||||
@ -724,7 +724,7 @@ TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, VarUsed) {
|
|||||||
Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14_f)),
|
Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14_f)),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
|
GlobalVar(Source{{56, 78}}, "G", ty.f32(), ast::AddressSpace::kPrivate, Expr(2.1_f));
|
||||||
|
|
||||||
Build();
|
Build();
|
||||||
}
|
}
|
||||||
@ -1207,7 +1207,7 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
|||||||
const auto type_sym = Sym("TYPE");
|
const auto type_sym = Sym("TYPE");
|
||||||
const auto func_sym = Sym("FUNC");
|
const auto func_sym = Sym("FUNC");
|
||||||
|
|
||||||
const auto* value_decl = GlobalVar(value_sym, ty.i32(), ast::StorageClass::kPrivate);
|
const auto* value_decl = GlobalVar(value_sym, ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
const auto* type_decl = Alias(type_sym, ty.i32());
|
const auto* type_decl = Alias(type_sym, ty.i32());
|
||||||
const auto* func_decl = Func(func_sym, utils::Empty, ty.void_(), utils::Empty);
|
const auto* func_decl = Func(func_sym, utils::Empty, ty.void_(), utils::Empty);
|
||||||
|
|
||||||
@ -1278,7 +1278,7 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
|||||||
GlobalVar(Sym(), ty.array(T, V, 4));
|
GlobalVar(Sym(), ty.array(T, V, 4));
|
||||||
GlobalVar(Sym(), ty.vec3(T));
|
GlobalVar(Sym(), ty.vec3(T));
|
||||||
GlobalVar(Sym(), ty.mat3x2(T));
|
GlobalVar(Sym(), ty.mat3x2(T));
|
||||||
GlobalVar(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
|
GlobalVar(Sym(), ty.pointer(T, ast::AddressSpace::kPrivate));
|
||||||
GlobalVar(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
|
GlobalVar(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
|
||||||
GlobalVar(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
|
GlobalVar(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
|
||||||
GlobalVar(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
|
GlobalVar(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
|
||||||
|
@ -453,25 +453,25 @@ TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithEnable) {
|
|||||||
// enable chromium_experimental_push_constant;
|
// enable chromium_experimental_push_constant;
|
||||||
// var<push_constant> a : u32;
|
// var<push_constant> a : u32;
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve());
|
EXPECT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
|
TEST_F(ResolverEntryPointValidationTest, PushConstantDisallowedWithoutEnable) {
|
||||||
// var<push_constant> a : u32;
|
// var<push_constant> a : u32;
|
||||||
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"1:2 error: use of variable storage class 'push_constant' requires enabling "
|
"1:2 error: use of variable address space 'push_constant' requires enabling "
|
||||||
"extension 'chromium_experimental_push_constant'");
|
"extension 'chromium_experimental_push_constant'");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreStorageClassAttribute) {
|
TEST_F(ResolverEntryPointValidationTest, PushConstantAllowedWithIgnoreAddressSpaceAttribute) {
|
||||||
// var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreStorageClass
|
// var<push_constant> a : u32; // With ast::DisabledValidation::kIgnoreAddressSpace
|
||||||
GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant,
|
GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant,
|
||||||
utils::Vector{Disable(ast::DisabledValidation::kIgnoreStorageClass)});
|
utils::Vector{Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve());
|
EXPECT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
@ -483,7 +483,7 @@ TEST_F(ResolverEntryPointValidationTest, PushConstantOneVariableUsedInEntryPoint
|
|||||||
// _ = a;
|
// _ = a;
|
||||||
// }
|
// }
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
|
Func("main", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
|
||||||
utils::Vector{Stage(ast::PipelineStage::kCompute),
|
utils::Vector{Stage(ast::PipelineStage::kCompute),
|
||||||
@ -501,8 +501,8 @@ TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInEntryPoin
|
|||||||
// _ = b;
|
// _ = b;
|
||||||
// }
|
// }
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
Func(Source{{5, 6}}, "main", {}, ty.void_(),
|
Func(Source{{5, 6}}, "main", {}, ty.void_(),
|
||||||
utils::Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
|
utils::Vector{Assign(Phony(), "a"), Assign(Phony(), "b")},
|
||||||
@ -532,8 +532,8 @@ TEST_F(ResolverEntryPointValidationTest,
|
|||||||
// uses_b();
|
// uses_b();
|
||||||
// }
|
// }
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{1, 2}}, "a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar(Source{{3, 4}}, "b", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")});
|
Func(Source{{5, 6}}, "uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")});
|
||||||
Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")});
|
Func(Source{{7, 8}}, "uses_b", {}, ty.void_(), utils::Vector{Assign(Phony(), "b")});
|
||||||
@ -565,8 +565,8 @@ TEST_F(ResolverEntryPointValidationTest, PushConstantTwoVariablesUsedInDifferent
|
|||||||
// _ = a;
|
// _ = a;
|
||||||
// }
|
// }
|
||||||
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
Enable(ast::Extension::kChromiumExperimentalPushConstant);
|
||||||
GlobalVar("a", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar("a", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
GlobalVar("b", ty.u32(), ast::StorageClass::kPushConstant);
|
GlobalVar("b", ty.u32(), ast::AddressSpace::kPushConstant);
|
||||||
|
|
||||||
Func("uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
|
Func("uses_a", {}, ty.void_(), utils::Vector{Assign(Phony(), "a")},
|
||||||
utils::Vector{Stage(ast::PipelineStage::kCompute),
|
utils::Vector{Stage(ast::PipelineStage::kCompute),
|
||||||
|
@ -39,7 +39,7 @@ TEST_F(ResolverFunctionValidationTest, DuplicateParameterName) {
|
|||||||
TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
|
TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
|
||||||
// var<private> common_name : f32;
|
// var<private> common_name : f32;
|
||||||
// fn func(common_name : f32) { }
|
// fn func(common_name : f32) { }
|
||||||
GlobalVar("common_name", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("common_name", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
Func("func", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
|
Func("func", utils::Vector{Param("common_name", ty.f32())}, ty.void_(), utils::Empty);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -388,7 +388,7 @@ TEST_F(ResolverFunctionValidationTest, CannotCallFunctionAtModuleScope) {
|
|||||||
utils::Vector{
|
utils::Vector{
|
||||||
Return(1_i),
|
Return(1_i),
|
||||||
});
|
});
|
||||||
GlobalVar("x", Call(Source{{12, 34}}, "F"), ast::StorageClass::kPrivate);
|
GlobalVar("x", Call(Source{{12, 34}}, "F"), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), R"(12:34 error: functions cannot be called at module-scope)");
|
EXPECT_EQ(r()->error(), R"(12:34 error: functions cannot be called at module-scope)");
|
||||||
@ -771,7 +771,7 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
|
|||||||
// var<private> x = 64i;
|
// var<private> x = 64i;
|
||||||
// @compute @workgroup_size(x)
|
// @compute @workgroup_size(x)
|
||||||
// fn main() {}
|
// fn main() {}
|
||||||
GlobalVar("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64_i));
|
GlobalVar("x", ty.i32(), ast::AddressSpace::kPrivate, Expr(64_i));
|
||||||
Func("main", utils::Empty, ty.void_(), utils::Empty,
|
Func("main", utils::Empty, ty.void_(), utils::Empty,
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Stage(ast::PipelineStage::kCompute),
|
Stage(ast::PipelineStage::kCompute),
|
||||||
@ -830,7 +830,7 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr_z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
|
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
|
||||||
auto* ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
|
auto* ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), ast::AddressSpace::kFunction);
|
||||||
Func("f", utils::Empty, ret_type, utils::Empty);
|
Func("f", utils::Empty, ret_type, utils::Empty);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
@ -939,16 +939,16 @@ TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TestParams {
|
struct TestParams {
|
||||||
ast::StorageClass storage_class;
|
ast::AddressSpace address_space;
|
||||||
bool should_pass;
|
bool should_pass;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestWithParams : ResolverTestWithParam<TestParams> {};
|
struct TestWithParams : ResolverTestWithParam<TestParams> {};
|
||||||
|
|
||||||
using ResolverFunctionParameterValidationTest = TestWithParams;
|
using ResolverFunctionParameterValidationTest = TestWithParams;
|
||||||
TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
|
TEST_P(ResolverFunctionParameterValidationTest, AddressSpace) {
|
||||||
auto& param = GetParam();
|
auto& param = GetParam();
|
||||||
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
|
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.address_space);
|
||||||
auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
|
auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
|
||||||
Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
|
Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
|
||||||
|
|
||||||
@ -956,23 +956,23 @@ TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
|
|||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
} else {
|
} else {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << param.storage_class;
|
ss << param.address_space;
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: function parameter of pointer type cannot be in '" +
|
EXPECT_EQ(r()->error(), "12:34 error: function parameter of pointer type cannot be in '" +
|
||||||
ss.str() + "' storage class");
|
ss.str() + "' address space");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
||||||
ResolverFunctionParameterValidationTest,
|
ResolverFunctionParameterValidationTest,
|
||||||
testing::Values(TestParams{ast::StorageClass::kNone, false},
|
testing::Values(TestParams{ast::AddressSpace::kNone, false},
|
||||||
TestParams{ast::StorageClass::kIn, false},
|
TestParams{ast::AddressSpace::kIn, false},
|
||||||
TestParams{ast::StorageClass::kOut, false},
|
TestParams{ast::AddressSpace::kOut, false},
|
||||||
TestParams{ast::StorageClass::kUniform, false},
|
TestParams{ast::AddressSpace::kUniform, false},
|
||||||
TestParams{ast::StorageClass::kWorkgroup, true},
|
TestParams{ast::AddressSpace::kWorkgroup, true},
|
||||||
TestParams{ast::StorageClass::kHandle, false},
|
TestParams{ast::AddressSpace::kHandle, false},
|
||||||
TestParams{ast::StorageClass::kStorage, false},
|
TestParams{ast::AddressSpace::kStorage, false},
|
||||||
TestParams{ast::StorageClass::kPrivate, true},
|
TestParams{ast::AddressSpace::kPrivate, true},
|
||||||
TestParams{ast::StorageClass::kFunction, true}));
|
TestParams{ast::AddressSpace::kFunction, true}));
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
@ -28,14 +28,14 @@ using ResolverHostShareableValidationTest = ResolverTest;
|
|||||||
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.bool_())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.bool_())});
|
||||||
|
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
12:34 note: while analysing structure member S.x
|
12:34 note: while analysing structure member S.x
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
@ -43,14 +43,14 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
|||||||
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
|
||||||
|
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'vec3<bool>' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'vec3<bool>' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
12:34 note: while analysing structure member S.x
|
12:34 note: while analysing structure member S.x
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
@ -59,14 +59,14 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
|||||||
auto* a1 = Alias("a1", ty.bool_());
|
auto* a1 = Alias("a1", ty.bool_());
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.Of(a1))});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.Of(a1))});
|
||||||
auto* a2 = Alias("a2", ty.Of(s));
|
auto* a2 = Alias("a2", ty.Of(s));
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a2), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(56:78 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
12:34 note: while analysing structure member S.x
|
12:34 note: while analysing structure member S.x
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
@ -78,14 +78,14 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
|||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
|
auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
|
||||||
|
|
||||||
GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(9:10 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
R"(9:10 error: Type 'bool' cannot be used in address space 'storage' as it is non-host-shareable
|
||||||
1:2 note: while analysing structure member I1.x
|
1:2 note: while analysing structure member I1.x
|
||||||
3:4 note: while analysing structure member I2.y
|
3:4 note: while analysing structure member I2.y
|
||||||
5:6 note: while analysing structure member I3.z
|
5:6 note: while analysing structure member I3.z
|
||||||
@ -117,7 +117,7 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
|||||||
|
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
|
auto* s = Structure("S", utils::Vector{Member(Source{{7, 8}}, "m", ty.Of(i3))});
|
||||||
|
|
||||||
GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{9, 10}}, "g", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
@ -64,8 +64,8 @@ TEST_F(ResolverIncrementDecrementValidationTest, ThroughPointer) {
|
|||||||
// var a : i32;
|
// var a : i32;
|
||||||
// let b : ptr<function,i32> = &a;
|
// let b : ptr<function,i32> = &a;
|
||||||
// *b++;
|
// *b++;
|
||||||
auto* var_a = Var("a", ty.i32(), ast::StorageClass::kFunction);
|
auto* var_a = Var("a", ty.i32(), ast::AddressSpace::kFunction);
|
||||||
auto* var_b = Let("b", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(Expr("a")));
|
auto* var_b = Let("b", ty.pointer<i32>(ast::AddressSpace::kFunction), AddressOf(Expr("a")));
|
||||||
WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
|
WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -127,7 +127,7 @@ TEST_F(ResolverIncrementDecrementValidationTest, Vector) {
|
|||||||
TEST_F(ResolverIncrementDecrementValidationTest, Atomic) {
|
TEST_F(ResolverIncrementDecrementValidationTest, Atomic) {
|
||||||
// var<workgroup> a : atomic<i32>;
|
// var<workgroup> a : atomic<i32>;
|
||||||
// a++;
|
// a++;
|
||||||
GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
|
WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
@ -193,7 +193,7 @@ TEST_F(ResolverIncrementDecrementValidationTest, ReadOnlyBuffer) {
|
|||||||
// {
|
// {
|
||||||
// a++;
|
// a++;
|
||||||
// }
|
// }
|
||||||
GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
|
GlobalVar(Source{{12, 34}}, "a", ty.i32(), ast::AddressSpace::kStorage, ast::Access::kRead,
|
||||||
Group(0_a), Binding(0_a));
|
Group(0_a), Binding(0_a));
|
||||||
WrapInFunction(Increment(Source{{56, 78}}, "a"));
|
WrapInFunction(Increment(Source{{56, 78}}, "a"));
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ TEST_P(ResolverInferredTypeParamTest, GlobalVar_Pass) {
|
|||||||
|
|
||||||
// var a = <type constructor>;
|
// var a = <type constructor>;
|
||||||
auto* ctor_expr = params.create_value(*this, 0);
|
auto* ctor_expr = params.create_value(*this, 0);
|
||||||
auto* var = GlobalVar("a", ast::StorageClass::kPrivate, ctor_expr);
|
auto* var = GlobalVar("a", ast::AddressSpace::kPrivate, ctor_expr);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
|
EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
|
||||||
@ -124,7 +124,7 @@ TEST_P(ResolverInferredTypeParamTest, LocalVar_Pass) {
|
|||||||
|
|
||||||
// var a = <type constructor>;
|
// var a = <type constructor>;
|
||||||
auto* ctor_expr = params.create_value(*this, 0);
|
auto* ctor_expr = params.create_value(*this, 0);
|
||||||
auto* var = Var("a", ast::StorageClass::kFunction, ctor_expr);
|
auto* var = Var("a", ast::AddressSpace::kFunction, ctor_expr);
|
||||||
WrapInFunction(var);
|
WrapInFunction(var);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -139,7 +139,7 @@ TEST_F(ResolverInferredTypeTest, InferArray_Pass) {
|
|||||||
create<sem::Array>(create<sem::U32>(), sem::ConstantArrayCount{10u}, 4u, 4u * 10u, 4u, 4u);
|
create<sem::Array>(create<sem::U32>(), sem::ConstantArrayCount{10u}, 4u, 4u * 10u, 4u, 4u);
|
||||||
|
|
||||||
auto* ctor_expr = Construct(type);
|
auto* ctor_expr = Construct(type);
|
||||||
auto* var = Var("a", ast::StorageClass::kFunction, ctor_expr);
|
auto* var = Var("a", ast::AddressSpace::kFunction, ctor_expr);
|
||||||
WrapInFunction(var);
|
WrapInFunction(var);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -158,7 +158,7 @@ TEST_F(ResolverInferredTypeTest, InferStruct_Pass) {
|
|||||||
|
|
||||||
auto* ctor_expr = Construct(ty.Of(str));
|
auto* ctor_expr = Construct(ty.Of(str));
|
||||||
|
|
||||||
auto* var = Var("a", ast::StorageClass::kFunction, ctor_expr);
|
auto* var = Var("a", ast::AddressSpace::kFunction, ctor_expr);
|
||||||
WrapInFunction(var);
|
WrapInFunction(var);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
@ -321,7 +321,7 @@ class TemplateNumberMatcher : public NumberMatcher {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
using TexelFormat = ast::TexelFormat;
|
using TexelFormat = ast::TexelFormat;
|
||||||
using Access = ast::Access;
|
using Access = ast::Access;
|
||||||
using StorageClass = ast::StorageClass;
|
using AddressSpace = ast::AddressSpace;
|
||||||
using ParameterUsage = sem::ParameterUsage;
|
using ParameterUsage = sem::ParameterUsage;
|
||||||
using PipelineStage = ast::PipelineStage;
|
using PipelineStage = ast::PipelineStage;
|
||||||
|
|
||||||
@ -539,7 +539,7 @@ bool match_ptr(const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto* p = ty->As<sem::Pointer>()) {
|
if (auto* p = ty->As<sem::Pointer>()) {
|
||||||
S = Number(static_cast<uint32_t>(p->StorageClass()));
|
S = Number(static_cast<uint32_t>(p->AddressSpace()));
|
||||||
T = p->StoreType();
|
T = p->StoreType();
|
||||||
A = Number(static_cast<uint32_t>(p->Access()));
|
A = Number(static_cast<uint32_t>(p->Access()));
|
||||||
return true;
|
return true;
|
||||||
@ -548,7 +548,7 @@ bool match_ptr(const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Pointer* build_ptr(MatchState& state, Number S, const sem::Type* T, Number& A) {
|
const sem::Pointer* build_ptr(MatchState& state, Number S, const sem::Type* T, Number& A) {
|
||||||
return state.builder.create<sem::Pointer>(T, static_cast<ast::StorageClass>(S.Value()),
|
return state.builder.create<sem::Pointer>(T, static_cast<ast::AddressSpace>(S.Value()),
|
||||||
static_cast<ast::Access>(A.Value()));
|
static_cast<ast::Access>(A.Value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1158,7 +1158,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
|
|||||||
params.Reserve(match.parameters.Length());
|
params.Reserve(match.parameters.Length());
|
||||||
for (auto& p : match.parameters) {
|
for (auto& p : match.parameters) {
|
||||||
params.Push(builder.create<sem::Parameter>(
|
params.Push(builder.create<sem::Parameter>(
|
||||||
nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::StorageClass::kNone,
|
nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, p.usage));
|
ast::Access::kUndefined, p.usage));
|
||||||
}
|
}
|
||||||
sem::PipelineStageSet supported_stages;
|
sem::PipelineStageSet supported_stages;
|
||||||
@ -1356,7 +1356,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
|
|||||||
params.Reserve(match.parameters.Length());
|
params.Reserve(match.parameters.Length());
|
||||||
for (auto& p : match.parameters) {
|
for (auto& p : match.parameters) {
|
||||||
params.Push(builder.create<sem::Parameter>(
|
params.Push(builder.create<sem::Parameter>(
|
||||||
nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::StorageClass::kNone,
|
nullptr, static_cast<uint32_t>(params.Length()), p.type, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, p.usage));
|
ast::Access::kUndefined, p.usage));
|
||||||
}
|
}
|
||||||
auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
|
auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
|
||||||
@ -1371,7 +1371,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
|
|||||||
// Conversion.
|
// Conversion.
|
||||||
auto* target = utils::GetOrCreate(converters, match, [&]() {
|
auto* target = utils::GetOrCreate(converters, match, [&]() {
|
||||||
auto param = builder.create<sem::Parameter>(
|
auto param = builder.create<sem::Parameter>(
|
||||||
nullptr, 0u, match.parameters[0].type, ast::StorageClass::kNone,
|
nullptr, 0u, match.parameters[0].type, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, match.parameters[0].usage);
|
ast::Access::kUndefined, match.parameters[0].usage);
|
||||||
auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
|
auto eval_stage = match.overload->const_eval_fn ? sem::EvaluationStage::kConstant
|
||||||
: sem::EvaluationStage::kRuntime;
|
: sem::EvaluationStage::kRuntime;
|
||||||
|
@ -2457,10 +2457,10 @@ class FunctionPrivateWorkgroup : public NumberMatcher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Number FunctionPrivateWorkgroup::Match(MatchState&, Number number) const {
|
Number FunctionPrivateWorkgroup::Match(MatchState&, Number number) const {
|
||||||
switch (static_cast<StorageClass>(number.Value())) {
|
switch (static_cast<AddressSpace>(number.Value())) {
|
||||||
case StorageClass::kFunction:
|
case AddressSpace::kFunction:
|
||||||
case StorageClass::kPrivate:
|
case AddressSpace::kPrivate:
|
||||||
case StorageClass::kWorkgroup:
|
case AddressSpace::kWorkgroup:
|
||||||
return number;
|
return number;
|
||||||
default:
|
default:
|
||||||
return Number::invalid;
|
return Number::invalid;
|
||||||
@ -2486,9 +2486,9 @@ class WorkgroupOrStorage : public NumberMatcher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Number WorkgroupOrStorage::Match(MatchState&, Number number) const {
|
Number WorkgroupOrStorage::Match(MatchState&, Number number) const {
|
||||||
switch (static_cast<StorageClass>(number.Value())) {
|
switch (static_cast<AddressSpace>(number.Value())) {
|
||||||
case StorageClass::kWorkgroup:
|
case AddressSpace::kWorkgroup:
|
||||||
case StorageClass::kStorage:
|
case AddressSpace::kStorage:
|
||||||
return number;
|
return number;
|
||||||
default:
|
default:
|
||||||
return Number::invalid;
|
return Number::invalid;
|
||||||
@ -2514,8 +2514,8 @@ class Storage : public NumberMatcher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Number Storage::Match(MatchState&, Number number) const {
|
Number Storage::Match(MatchState&, Number number) const {
|
||||||
if (number.IsAny() || number.Value() == static_cast<uint32_t>(StorageClass::kStorage)) {
|
if (number.IsAny() || number.Value() == static_cast<uint32_t>(AddressSpace::kStorage)) {
|
||||||
return Number(static_cast<uint32_t>(StorageClass::kStorage));
|
return Number(static_cast<uint32_t>(AddressSpace::kStorage));
|
||||||
}
|
}
|
||||||
return Number::invalid;
|
return Number::invalid;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ TEST_F(IntrinsicTableTest, MatchPointer) {
|
|||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* atomicI32 = create<sem::Atomic>(i32);
|
auto* atomicI32 = create<sem::Atomic>(i32);
|
||||||
auto* ptr =
|
auto* ptr =
|
||||||
create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite);
|
create<sem::Pointer>(atomicI32, ast::AddressSpace::kWorkgroup, ast::Access::kReadWrite);
|
||||||
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr}, Source{});
|
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr}, Source{});
|
||||||
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
||||||
ASSERT_EQ(Diagnostics().str(), "");
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
@ -236,7 +236,7 @@ TEST_F(IntrinsicTableTest, MismatchPointer) {
|
|||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MatchArray) {
|
TEST_F(IntrinsicTableTest, MatchArray) {
|
||||||
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
|
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
|
||||||
auto* arr_ptr = create<sem::Pointer>(arr, ast::StorageClass::kStorage, ast::Access::kReadWrite);
|
auto* arr_ptr = create<sem::Pointer>(arr, ast::AddressSpace::kStorage, ast::Access::kReadWrite);
|
||||||
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr}, Source{});
|
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr}, Source{});
|
||||||
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
||||||
ASSERT_EQ(Diagnostics().str(), "");
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
@ -424,7 +424,7 @@ TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
|
|||||||
auto result = table->Lookup(
|
auto result = table->Lookup(
|
||||||
BuiltinType::kCos,
|
BuiltinType::kCos,
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
create<sem::Reference>(f32, ast::StorageClass::kFunction, ast::Access::kReadWrite),
|
create<sem::Reference>(f32, ast::AddressSpace::kFunction, ast::Access::kReadWrite),
|
||||||
},
|
},
|
||||||
Source{});
|
Source{});
|
||||||
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
||||||
|
@ -95,7 +95,7 @@ TEST_F(ResolverIsHostShareable, Matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsHostShareable, Pointer) {
|
TEST_F(ResolverIsHostShareable, Pointer) {
|
||||||
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
|
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::AddressSpace::kPrivate,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
EXPECT_FALSE(r()->IsHostShareable(ptr));
|
EXPECT_FALSE(r()->IsHostShareable(ptr));
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ TEST_F(ResolverIsStorableTest, Matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Pointer) {
|
TEST_F(ResolverIsStorableTest, Pointer) {
|
||||||
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
|
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::AddressSpace::kPrivate,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
EXPECT_FALSE(r()->IsStorable(ptr));
|
EXPECT_FALSE(r()->IsStorable(ptr));
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
|
|||||||
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
||||||
Structure("S", utils::Vector{
|
Structure("S", utils::Vector{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
|
Member("b", ty.pointer<i32>(ast::AddressSpace::kPrivate)),
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
@ -137,7 +137,7 @@ TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
|
|||||||
auto* non_storable =
|
auto* non_storable =
|
||||||
Structure("nonstorable", utils::Vector{
|
Structure("nonstorable", utils::Vector{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
|
Member("b", ty.pointer<i32>(ast::AddressSpace::kPrivate)),
|
||||||
});
|
});
|
||||||
Structure("S", utils::Vector{
|
Structure("S", utils::Vector{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
|
@ -902,7 +902,7 @@ TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
|
|||||||
utils::Vector{WorkgroupSize(abstract_expr()), Stage(ast::PipelineStage::kCompute)});
|
utils::Vector{WorkgroupSize(abstract_expr()), Stage(ast::PipelineStage::kCompute)});
|
||||||
break;
|
break;
|
||||||
case Method::kIndex:
|
case Method::kIndex:
|
||||||
GlobalVar("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
|
GlobalVar("arr", ty.array<i32, 4>(), ast::AddressSpace::kPrivate);
|
||||||
WrapInFunction(IndexAccessor("arr", abstract_expr()));
|
WrapInFunction(IndexAccessor("arr", abstract_expr()));
|
||||||
break;
|
break;
|
||||||
case Method::kRuntimeIndex:
|
case Method::kRuntimeIndex:
|
||||||
|
@ -38,7 +38,7 @@ TEST_F(ResolverPtrRefTest, AddressOf) {
|
|||||||
|
|
||||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::Pointer>());
|
ASSERT_TRUE(TypeOf(expr)->Is<sem::Pointer>());
|
||||||
EXPECT_TRUE(TypeOf(expr)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
|
EXPECT_TRUE(TypeOf(expr)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
|
||||||
EXPECT_EQ(TypeOf(expr)->As<sem::Pointer>()->StorageClass(), ast::StorageClass::kFunction);
|
EXPECT_EQ(TypeOf(expr)->As<sem::Pointer>()->AddressSpace(), ast::AddressSpace::kFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
|
TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
|
||||||
@ -56,28 +56,28 @@ TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
|
|||||||
EXPECT_TRUE(TypeOf(expr)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
EXPECT_TRUE(TypeOf(expr)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPtrRefTest, DefaultPtrStorageClass) {
|
TEST_F(ResolverPtrRefTest, DefaultPtrAddressSpace) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
||||||
|
|
||||||
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
||||||
auto* function = Var("f", ty.i32());
|
auto* function = Var("f", ty.i32());
|
||||||
auto* private_ = GlobalVar("p", ty.i32(), ast::StorageClass::kPrivate);
|
auto* private_ = GlobalVar("p", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* workgroup = GlobalVar("w", ty.i32(), ast::StorageClass::kWorkgroup);
|
auto* workgroup = GlobalVar("w", ty.i32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* uniform =
|
auto* uniform =
|
||||||
GlobalVar("ub", ty.Of(buf), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("ub", ty.Of(buf), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
auto* storage =
|
auto* storage =
|
||||||
GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage, Binding(1_a), Group(0_a));
|
GlobalVar("sb", ty.Of(buf), ast::AddressSpace::kStorage, Binding(1_a), Group(0_a));
|
||||||
|
|
||||||
auto* function_ptr =
|
auto* function_ptr =
|
||||||
Let("f_ptr", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(function));
|
Let("f_ptr", ty.pointer(ty.i32(), ast::AddressSpace::kFunction), AddressOf(function));
|
||||||
auto* private_ptr =
|
auto* private_ptr =
|
||||||
Let("p_ptr", ty.pointer(ty.i32(), ast::StorageClass::kPrivate), AddressOf(private_));
|
Let("p_ptr", ty.pointer(ty.i32(), ast::AddressSpace::kPrivate), AddressOf(private_));
|
||||||
auto* workgroup_ptr =
|
auto* workgroup_ptr =
|
||||||
Let("w_ptr", ty.pointer(ty.i32(), ast::StorageClass::kWorkgroup), AddressOf(workgroup));
|
Let("w_ptr", ty.pointer(ty.i32(), ast::AddressSpace::kWorkgroup), AddressOf(workgroup));
|
||||||
auto* uniform_ptr =
|
auto* uniform_ptr =
|
||||||
Let("ub_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kUniform), AddressOf(uniform));
|
Let("ub_ptr", ty.pointer(ty.Of(buf), ast::AddressSpace::kUniform), AddressOf(uniform));
|
||||||
auto* storage_ptr =
|
auto* storage_ptr =
|
||||||
Let("sb_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kStorage), AddressOf(storage));
|
Let("sb_ptr", ty.pointer(ty.Of(buf), ast::AddressSpace::kStorage), AddressOf(storage));
|
||||||
|
|
||||||
WrapInFunction(function, function_ptr, private_ptr, workgroup_ptr, uniform_ptr, storage_ptr);
|
WrapInFunction(function, function_ptr, private_ptr, workgroup_ptr, uniform_ptr, storage_ptr);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ TEST_F(ResolverPtrRefValidationTest, AddressOfHandle) {
|
|||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: cannot take the address of expression in handle "
|
"12:34 error: cannot take the address of expression in handle "
|
||||||
"storage class");
|
"address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_MemberAccessor) {
|
TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_MemberAccessor) {
|
||||||
@ -102,7 +102,7 @@ TEST_F(ResolverPtrRefValidationTest, IndirectOfAddressOfHandle) {
|
|||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: cannot take the address of expression in handle "
|
"12:34 error: cannot take the address of expression in handle "
|
||||||
"storage class");
|
"address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPtrRefValidationTest, DerefOfLiteral) {
|
TEST_F(ResolverPtrRefValidationTest, DerefOfLiteral) {
|
||||||
@ -143,12 +143,12 @@ TEST_F(ResolverPtrRefValidationTest, InferredPtrAccessMismatch) {
|
|||||||
// }
|
// }
|
||||||
auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
|
auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
|
||||||
auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
|
auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
|
||||||
auto* storage = GlobalVar("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
auto* storage = GlobalVar("s", ty.Of(buf), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
|
auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
|
||||||
auto* ptr =
|
auto* ptr =
|
||||||
Let(Source{{12, 34}}, "p", ty.pointer<i32>(ast::StorageClass::kStorage), AddressOf(expr));
|
Let(Source{{12, 34}}, "p", ty.pointer<i32>(ast::AddressSpace::kStorage), AddressOf(expr));
|
||||||
|
|
||||||
WrapInFunction(ptr);
|
WrapInFunction(ptr);
|
||||||
|
|
||||||
|
@ -247,9 +247,9 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||||||
if (auto* el = Type(t->type)) {
|
if (auto* el = Type(t->type)) {
|
||||||
auto access = t->access;
|
auto access = t->access;
|
||||||
if (access == ast::kUndefined) {
|
if (access == ast::kUndefined) {
|
||||||
access = DefaultAccessForStorageClass(t->storage_class);
|
access = DefaultAccessForAddressSpace(t->address_space);
|
||||||
}
|
}
|
||||||
return builder_->create<sem::Pointer>(el, t->storage_class, access);
|
return builder_->create<sem::Pointer>(el, t->address_space, access);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
},
|
},
|
||||||
@ -368,11 +368,11 @@ sem::Variable* Resolver::Let(const ast::Let* v, bool is_global) {
|
|||||||
ty = rhs->Type()->UnwrapRef(); // Implicit load of RHS
|
ty = rhs->Type()->UnwrapRef(); // Implicit load of RHS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs && !validator_.VariableInitializer(v, ast::StorageClass::kNone, ty, rhs)) {
|
if (rhs && !validator_.VariableInitializer(v, ast::AddressSpace::kNone, ty, rhs)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
|
if (!ApplyAddressSpaceUsageToType(ast::AddressSpace::kNone, const_cast<sem::Type*>(ty),
|
||||||
v->source)) {
|
v->source)) {
|
||||||
AddNote("while instantiating 'let' " + builder_->Symbols().NameFor(v->symbol), v->source);
|
AddNote("while instantiating 'let' " + builder_->Symbols().NameFor(v->symbol), v->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -381,12 +381,12 @@ sem::Variable* Resolver::Let(const ast::Let* v, bool is_global) {
|
|||||||
sem::Variable* sem = nullptr;
|
sem::Variable* sem = nullptr;
|
||||||
if (is_global) {
|
if (is_global) {
|
||||||
sem = builder_->create<sem::GlobalVariable>(
|
sem = builder_->create<sem::GlobalVariable>(
|
||||||
v, ty, sem::EvaluationStage::kRuntime, ast::StorageClass::kNone,
|
v, ty, sem::EvaluationStage::kRuntime, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, /* constant_value */ nullptr, sem::BindingPoint{},
|
ast::Access::kUndefined, /* constant_value */ nullptr, sem::BindingPoint{},
|
||||||
std::nullopt);
|
std::nullopt);
|
||||||
} else {
|
} else {
|
||||||
sem = builder_->create<sem::LocalVariable>(v, ty, sem::EvaluationStage::kRuntime,
|
sem = builder_->create<sem::LocalVariable>(v, ty, sem::EvaluationStage::kRuntime,
|
||||||
ast::StorageClass::kNone,
|
ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, current_statement_,
|
ast::Access::kUndefined, current_statement_,
|
||||||
/* constant_value */ nullptr);
|
/* constant_value */ nullptr);
|
||||||
}
|
}
|
||||||
@ -425,11 +425,11 @@ sem::Variable* Resolver::Override(const ast::Override* v) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs && !validator_.VariableInitializer(v, ast::StorageClass::kNone, ty, rhs)) {
|
if (rhs && !validator_.VariableInitializer(v, ast::AddressSpace::kNone, ty, rhs)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
|
if (!ApplyAddressSpaceUsageToType(ast::AddressSpace::kNone, const_cast<sem::Type*>(ty),
|
||||||
v->source)) {
|
v->source)) {
|
||||||
AddNote("while instantiating 'override' " + builder_->Symbols().NameFor(v->symbol),
|
AddNote("while instantiating 'override' " + builder_->Symbols().NameFor(v->symbol),
|
||||||
v->source);
|
v->source);
|
||||||
@ -437,7 +437,7 @@ sem::Variable* Resolver::Override(const ast::Override* v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = builder_->create<sem::GlobalVariable>(
|
auto* sem = builder_->create<sem::GlobalVariable>(
|
||||||
v, ty, sem::EvaluationStage::kOverride, ast::StorageClass::kNone, ast::Access::kUndefined,
|
v, ty, sem::EvaluationStage::kOverride, ast::AddressSpace::kNone, ast::Access::kUndefined,
|
||||||
/* constant_value */ nullptr, sem::BindingPoint{}, std::nullopt);
|
/* constant_value */ nullptr, sem::BindingPoint{}, std::nullopt);
|
||||||
sem->SetConstructor(rhs);
|
sem->SetConstructor(rhs);
|
||||||
|
|
||||||
@ -510,21 +510,21 @@ sem::Variable* Resolver::Const(const ast::Const* c, bool is_global) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validator_.VariableInitializer(c, ast::StorageClass::kNone, ty, rhs)) {
|
if (!validator_.VariableInitializer(c, ast::AddressSpace::kNone, ty, rhs)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, const_cast<sem::Type*>(ty),
|
if (!ApplyAddressSpaceUsageToType(ast::AddressSpace::kNone, const_cast<sem::Type*>(ty),
|
||||||
c->source)) {
|
c->source)) {
|
||||||
AddNote("while instantiating 'const' " + builder_->Symbols().NameFor(c->symbol), c->source);
|
AddNote("while instantiating 'const' " + builder_->Symbols().NameFor(c->symbol), c->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = is_global ? static_cast<sem::Variable*>(builder_->create<sem::GlobalVariable>(
|
auto* sem = is_global ? static_cast<sem::Variable*>(builder_->create<sem::GlobalVariable>(
|
||||||
c, ty, sem::EvaluationStage::kConstant, ast::StorageClass::kNone,
|
c, ty, sem::EvaluationStage::kConstant, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, value, sem::BindingPoint{}, std::nullopt))
|
ast::Access::kUndefined, value, sem::BindingPoint{}, std::nullopt))
|
||||||
: static_cast<sem::Variable*>(builder_->create<sem::LocalVariable>(
|
: static_cast<sem::Variable*>(builder_->create<sem::LocalVariable>(
|
||||||
c, ty, sem::EvaluationStage::kConstant, ast::StorageClass::kNone,
|
c, ty, sem::EvaluationStage::kConstant, ast::AddressSpace::kNone,
|
||||||
ast::Access::kUndefined, current_statement_, value));
|
ast::Access::kUndefined, current_statement_, value));
|
||||||
|
|
||||||
sem->SetConstructor(rhs);
|
sem->SetConstructor(rhs);
|
||||||
@ -562,39 +562,39 @@ sem::Variable* Resolver::Var(const ast::Var* var, bool is_global) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto storage_class = var->declared_storage_class;
|
auto address_space = var->declared_address_space;
|
||||||
if (storage_class == ast::StorageClass::kNone) {
|
if (address_space == ast::AddressSpace::kNone) {
|
||||||
// No declared storage class. Infer from usage / type.
|
// No declared address space. Infer from usage / type.
|
||||||
if (!is_global) {
|
if (!is_global) {
|
||||||
storage_class = ast::StorageClass::kFunction;
|
address_space = ast::AddressSpace::kFunction;
|
||||||
} else if (storage_ty->UnwrapRef()->is_handle()) {
|
} else if (storage_ty->UnwrapRef()->is_handle()) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
||||||
// If the store type is a texture type or a sampler type, then the
|
// If the store type is a texture type or a sampler type, then the
|
||||||
// variable declaration must not have a storage class attribute. The
|
// variable declaration must not have a address space attribute. The
|
||||||
// storage class will always be handle.
|
// address space will always be handle.
|
||||||
storage_class = ast::StorageClass::kHandle;
|
address_space = ast::AddressSpace::kHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_global && storage_class != ast::StorageClass::kFunction &&
|
if (!is_global && address_space != ast::AddressSpace::kFunction &&
|
||||||
validator_.IsValidationEnabled(var->attributes,
|
validator_.IsValidationEnabled(var->attributes,
|
||||||
ast::DisabledValidation::kIgnoreStorageClass)) {
|
ast::DisabledValidation::kIgnoreAddressSpace)) {
|
||||||
AddError("function-scope 'var' declaration must use 'function' storage class", var->source);
|
AddError("function-scope 'var' declaration must use 'function' address space", var->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto access = var->declared_access;
|
auto access = var->declared_access;
|
||||||
if (access == ast::Access::kUndefined) {
|
if (access == ast::Access::kUndefined) {
|
||||||
access = DefaultAccessForStorageClass(storage_class);
|
access = DefaultAccessForAddressSpace(address_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs && !validator_.VariableInitializer(var, storage_class, storage_ty, rhs)) {
|
if (rhs && !validator_.VariableInitializer(var, address_space, storage_ty, rhs)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* var_ty = builder_->create<sem::Reference>(storage_ty, storage_class, access);
|
auto* var_ty = builder_->create<sem::Reference>(storage_ty, address_space, access);
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(storage_class, var_ty, var->source)) {
|
if (!ApplyAddressSpaceUsageToType(address_space, var_ty, var->source)) {
|
||||||
AddNote("while instantiating 'var' " + builder_->Symbols().NameFor(var->symbol),
|
AddNote("while instantiating 'var' " + builder_->Symbols().NameFor(var->symbol),
|
||||||
var->source);
|
var->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -654,12 +654,12 @@ sem::Variable* Resolver::Var(const ast::Var* var, bool is_global) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sem = builder_->create<sem::GlobalVariable>(
|
sem = builder_->create<sem::GlobalVariable>(
|
||||||
var, var_ty, sem::EvaluationStage::kRuntime, storage_class, access,
|
var, var_ty, sem::EvaluationStage::kRuntime, address_space, access,
|
||||||
/* constant_value */ nullptr, binding_point, location);
|
/* constant_value */ nullptr, binding_point, location);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
sem = builder_->create<sem::LocalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
|
sem = builder_->create<sem::LocalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
|
||||||
storage_class, access, current_statement_,
|
address_space, access, current_statement_,
|
||||||
/* constant_value */ nullptr);
|
/* constant_value */ nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,7 +686,7 @@ sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, ty, param->source)) {
|
if (!ApplyAddressSpaceUsageToType(ast::AddressSpace::kNone, ty, param->source)) {
|
||||||
add_note();
|
add_note();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -694,8 +694,8 @@ sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index)
|
|||||||
if (auto* ptr = ty->As<sem::Pointer>()) {
|
if (auto* ptr = ty->As<sem::Pointer>()) {
|
||||||
// For MSL, we push module-scope variables into the entry point as pointer
|
// For MSL, we push module-scope variables into the entry point as pointer
|
||||||
// parameters, so we also need to handle their store type.
|
// parameters, so we also need to handle their store type.
|
||||||
if (!ApplyStorageClassUsageToType(
|
if (!ApplyAddressSpaceUsageToType(
|
||||||
ptr->StorageClass(), const_cast<sem::Type*>(ptr->StoreType()), param->source)) {
|
ptr->AddressSpace(), const_cast<sem::Type*>(ptr->StoreType()), param->source)) {
|
||||||
add_note();
|
add_note();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -749,18 +749,18 @@ sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = builder_->create<sem::Parameter>(
|
auto* sem = builder_->create<sem::Parameter>(
|
||||||
param, index, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
|
param, index, ty, ast::AddressSpace::kNone, ast::Access::kUndefined,
|
||||||
sem::ParameterUsage::kNone, binding_point, location);
|
sem::ParameterUsage::kNone, binding_point, location);
|
||||||
builder_->Sem().Add(param, sem);
|
builder_->Sem().Add(param, sem);
|
||||||
return sem;
|
return sem;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Access Resolver::DefaultAccessForStorageClass(ast::StorageClass storage_class) {
|
ast::Access Resolver::DefaultAccessForAddressSpace(ast::AddressSpace address_space) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
||||||
switch (storage_class) {
|
switch (address_space) {
|
||||||
case ast::StorageClass::kStorage:
|
case ast::AddressSpace::kStorage:
|
||||||
case ast::StorageClass::kUniform:
|
case ast::AddressSpace::kUniform:
|
||||||
case ast::StorageClass::kHandle:
|
case ast::AddressSpace::kHandle:
|
||||||
return ast::Access::kRead;
|
return ast::Access::kRead;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -845,7 +845,7 @@ sem::GlobalVariable* Resolver::GlobalVariable(const ast::Variable* v) {
|
|||||||
|
|
||||||
// TODO(bclayton): Call this at the end of resolve on all uniform and storage
|
// TODO(bclayton): Call this at the end of resolve on all uniform and storage
|
||||||
// referenced structs
|
// referenced structs
|
||||||
if (!validator_.StorageClassLayout(sem, enabled_extensions_, valid_type_storage_layouts_)) {
|
if (!validator_.AddressSpaceLayout(sem, enabled_extensions_, valid_type_storage_layouts_)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,7 +962,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto* str = return_type->As<sem::Struct>()) {
|
if (auto* str = return_type->As<sem::Struct>()) {
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str, decl->source)) {
|
if (!ApplyAddressSpaceUsageToType(ast::AddressSpace::kNone, str, decl->source)) {
|
||||||
AddNote(
|
AddNote(
|
||||||
"while instantiating return type for " + builder_->Symbols().NameFor(decl->symbol),
|
"while instantiating return type for " + builder_->Symbols().NameFor(decl->symbol),
|
||||||
decl->source);
|
decl->source);
|
||||||
@ -1625,7 +1625,7 @@ sem::Expression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* exp
|
|||||||
|
|
||||||
// If we're extracting from a reference, we return a reference.
|
// If we're extracting from a reference, we return a reference.
|
||||||
if (auto* ref = obj_raw_ty->As<sem::Reference>()) {
|
if (auto* ref = obj_raw_ty->As<sem::Reference>()) {
|
||||||
ty = builder_->create<sem::Reference>(ty, ref->StorageClass(), ref->Access());
|
ty = builder_->create<sem::Reference>(ty, ref->AddressSpace(), ref->Access());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stage = sem::EarliestStage(obj->Stage(), idx->Stage());
|
auto stage = sem::EarliestStage(obj->Stage(), idx->Stage());
|
||||||
@ -1783,7 +1783,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
nullptr, // declaration
|
nullptr, // declaration
|
||||||
static_cast<uint32_t>(i), // index
|
static_cast<uint32_t>(i), // index
|
||||||
arr->ElemType(), // type
|
arr->ElemType(), // type
|
||||||
ast::StorageClass::kNone, // storage_class
|
ast::AddressSpace::kNone, // address_space
|
||||||
ast::Access::kUndefined);
|
ast::Access::kUndefined);
|
||||||
});
|
});
|
||||||
return builder_->create<sem::TypeConstructor>(arr, std::move(params),
|
return builder_->create<sem::TypeConstructor>(arr, std::move(params),
|
||||||
@ -1812,7 +1812,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
nullptr, // declaration
|
nullptr, // declaration
|
||||||
static_cast<uint32_t>(i), // index
|
static_cast<uint32_t>(i), // index
|
||||||
str->Members()[i]->Type(), // type
|
str->Members()[i]->Type(), // type
|
||||||
ast::StorageClass::kNone, // storage_class
|
ast::AddressSpace::kNone, // address_space
|
||||||
ast::Access::kUndefined); // access
|
ast::Access::kUndefined); // access
|
||||||
}
|
}
|
||||||
return builder_->create<sem::TypeConstructor>(str, std::move(params),
|
return builder_->create<sem::TypeConstructor>(str, std::move(params),
|
||||||
@ -2321,7 +2321,7 @@ sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* e
|
|||||||
|
|
||||||
// If we're extracting from a reference, we return a reference.
|
// If we're extracting from a reference, we return a reference.
|
||||||
if (auto* ref = structure->As<sem::Reference>()) {
|
if (auto* ref = structure->As<sem::Reference>()) {
|
||||||
ty = builder_->create<sem::Reference>(ty, ref->StorageClass(), ref->Access());
|
ty = builder_->create<sem::Reference>(ty, ref->AddressSpace(), ref->Access());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = const_eval_.MemberAccess(object, member);
|
auto val = const_eval_.MemberAccess(object, member);
|
||||||
@ -2390,7 +2390,7 @@ sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* e
|
|||||||
ty = vec->type();
|
ty = vec->type();
|
||||||
// If we're extracting from a reference, we return a reference.
|
// If we're extracting from a reference, we return a reference.
|
||||||
if (auto* ref = structure->As<sem::Reference>()) {
|
if (auto* ref = structure->As<sem::Reference>()) {
|
||||||
ty = builder_->create<sem::Reference>(ty, ref->StorageClass(), ref->Access());
|
ty = builder_->create<sem::Reference>(ty, ref->AddressSpace(), ref->Access());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The vector will have a number of components equal to the length of
|
// The vector will have a number of components equal to the length of
|
||||||
@ -2483,7 +2483,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
|||||||
case ast::UnaryOp::kAddressOf:
|
case ast::UnaryOp::kAddressOf:
|
||||||
if (auto* ref = expr_ty->As<sem::Reference>()) {
|
if (auto* ref = expr_ty->As<sem::Reference>()) {
|
||||||
if (ref->StoreType()->UnwrapRef()->is_handle()) {
|
if (ref->StoreType()->UnwrapRef()->is_handle()) {
|
||||||
AddError("cannot take the address of expression in handle storage class",
|
AddError("cannot take the address of expression in handle address space",
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -2496,7 +2496,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ty = builder_->create<sem::Pointer>(ref->StoreType(), ref->StorageClass(),
|
ty = builder_->create<sem::Pointer>(ref->StoreType(), ref->AddressSpace(),
|
||||||
ref->Access());
|
ref->Access());
|
||||||
|
|
||||||
source_var = expr->SourceVariable();
|
source_var = expr->SourceVariable();
|
||||||
@ -2508,7 +2508,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
|||||||
|
|
||||||
case ast::UnaryOp::kIndirection:
|
case ast::UnaryOp::kIndirection:
|
||||||
if (auto* ptr = expr_ty->As<sem::Pointer>()) {
|
if (auto* ptr = expr_ty->As<sem::Pointer>()) {
|
||||||
ty = builder_->create<sem::Reference>(ptr->StoreType(), ptr->StorageClass(),
|
ty = builder_->create<sem::Reference>(ptr->StoreType(), ptr->AddressSpace(),
|
||||||
ptr->Access());
|
ptr->Access());
|
||||||
source_var = expr->SourceVariable();
|
source_var = expr->SourceVariable();
|
||||||
} else {
|
} else {
|
||||||
@ -3205,20 +3205,20 @@ sem::Statement* Resolver::IncrementDecrementStatement(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
bool Resolver::ApplyAddressSpaceUsageToType(ast::AddressSpace sc,
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
const Source& usage) {
|
const Source& usage) {
|
||||||
ty = const_cast<sem::Type*>(ty->UnwrapRef());
|
ty = const_cast<sem::Type*>(ty->UnwrapRef());
|
||||||
|
|
||||||
if (auto* str = ty->As<sem::Struct>()) {
|
if (auto* str = ty->As<sem::Struct>()) {
|
||||||
if (str->StorageClassUsage().count(sc)) {
|
if (str->AddressSpaceUsage().count(sc)) {
|
||||||
return true; // Already applied
|
return true; // Already applied
|
||||||
}
|
}
|
||||||
|
|
||||||
str->AddUsage(sc);
|
str->AddUsage(sc);
|
||||||
|
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (!ApplyStorageClassUsageToType(sc, const_cast<sem::Type*>(member->Type()), usage)) {
|
if (!ApplyAddressSpaceUsageToType(sc, const_cast<sem::Type*>(member->Type()), usage)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "while analysing structure member " << sem_.TypeNameOf(str) << "."
|
err << "while analysing structure member " << sem_.TypeNameOf(str) << "."
|
||||||
<< builder_->Symbols().NameFor(member->Declaration()->symbol);
|
<< builder_->Symbols().NameFor(member->Declaration()->symbol);
|
||||||
@ -3230,20 +3230,20 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto* arr = ty->As<sem::Array>()) {
|
if (auto* arr = ty->As<sem::Array>()) {
|
||||||
if (arr->IsRuntimeSized() && sc != ast::StorageClass::kStorage) {
|
if (arr->IsRuntimeSized() && sc != ast::AddressSpace::kStorage) {
|
||||||
AddError(
|
AddError(
|
||||||
"runtime-sized arrays can only be used in the <storage> storage "
|
"runtime-sized arrays can only be used in the <storage> address "
|
||||||
"class",
|
"space",
|
||||||
usage);
|
usage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApplyStorageClassUsageToType(sc, const_cast<sem::Type*>(arr->ElemType()), usage);
|
return ApplyAddressSpaceUsageToType(sc, const_cast<sem::Type*>(arr->ElemType()), usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast::IsHostShareable(sc) && !validator_.IsHostShareable(ty)) {
|
if (ast::IsHostShareable(sc) && !validator_.IsHostShareable(ty)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in storage class '" << sc
|
err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '" << sc
|
||||||
<< "' as it is non-host-shareable";
|
<< "' as it is non-host-shareable";
|
||||||
AddError(err.str(), usage);
|
AddError(err.str(), usage);
|
||||||
return false;
|
return false;
|
||||||
|
@ -387,20 +387,20 @@ class Resolver {
|
|||||||
/// @param index the index of the parameter
|
/// @param index the index of the parameter
|
||||||
sem::Parameter* Parameter(const ast::Parameter* param, uint32_t index);
|
sem::Parameter* Parameter(const ast::Parameter* param, uint32_t index);
|
||||||
|
|
||||||
/// Records the storage class usage for the given type, and any transient
|
/// Records the address space usage for the given type, and any transient
|
||||||
/// dependencies of the type. Validates that the type can be used for the
|
/// dependencies of the type. Validates that the type can be used for the
|
||||||
/// given storage class, erroring if it cannot.
|
/// given address space, erroring if it cannot.
|
||||||
/// @param sc the storage class to apply to the type and transitent types
|
/// @param sc the address space to apply to the type and transitent types
|
||||||
/// @param ty the type to apply the storage class on
|
/// @param ty the type to apply the address space on
|
||||||
/// @param usage the Source of the root variable declaration that uses the
|
/// @param usage the Source of the root variable declaration that uses the
|
||||||
/// given type and storage class. Used for generating sensible error
|
/// given type and address space. Used for generating sensible error
|
||||||
/// messages.
|
/// messages.
|
||||||
/// @returns true on success, false on error
|
/// @returns true on success, false on error
|
||||||
bool ApplyStorageClassUsageToType(ast::StorageClass sc, sem::Type* ty, const Source& usage);
|
bool ApplyAddressSpaceUsageToType(ast::AddressSpace sc, sem::Type* ty, const Source& usage);
|
||||||
|
|
||||||
/// @param storage_class the storage class
|
/// @param address_space the address space
|
||||||
/// @returns the default access control for the given storage class
|
/// @returns the default access control for the given address space
|
||||||
ast::Access DefaultAccessForStorageClass(ast::StorageClass storage_class);
|
ast::Access DefaultAccessForAddressSpace(ast::AddressSpace address_space);
|
||||||
|
|
||||||
/// Allocate constant IDs for pipeline-overridable constants.
|
/// Allocate constant IDs for pipeline-overridable constants.
|
||||||
/// @returns true on success, false on error
|
/// @returns true on success, false on error
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
// Copyright 2021 The Tint Authors.
|
|
||||||
//
|
|
||||||
// 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 "src/tint/resolver/resolver.h"
|
|
||||||
|
|
||||||
#include "gmock/gmock.h"
|
|
||||||
#include "src/tint/resolver/resolver_test_helper.h"
|
|
||||||
#include "src/tint/sem/atomic.h"
|
|
||||||
|
|
||||||
namespace tint::resolver {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using ResolverIsStorableTest = ResolverTest;
|
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
|
|
||||||
Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.f32()),
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
|
||||||
Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
|
||||||
EXPECT_EQ(
|
|
||||||
r()->error(),
|
|
||||||
R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
|
|
||||||
auto* storable = Structure("Storable", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.f32()),
|
|
||||||
});
|
|
||||||
Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.Of(storable)),
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
|
|
||||||
auto* non_storable =
|
|
||||||
Structure("nonstorable", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
|
|
||||||
});
|
|
||||||
Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.Of(non_storable)),
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
|
||||||
EXPECT_EQ(
|
|
||||||
r()->error(),
|
|
||||||
R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace tint::resolver
|
|
@ -316,7 +316,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_Alias) {
|
|||||||
|
|
||||||
TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
|
TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
|
||||||
auto* init = Expr(2_i);
|
auto* init = Expr(2_i);
|
||||||
GlobalVar("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
|
GlobalVar("my_var", ty.i32(), ast::AddressSpace::kPrivate, init);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
|
|||||||
Func("func_i32", utils::Empty, ty.void_(), utils::Vector{fn_i32_decl});
|
Func("func_i32", utils::Empty, ty.void_(), utils::Vector{fn_i32_decl});
|
||||||
|
|
||||||
// Declare f32 "foo" at module scope
|
// Declare f32 "foo" at module scope
|
||||||
auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(2_f));
|
auto* mod_f32 = Var("foo", ty.f32(), ast::AddressSpace::kPrivate, Expr(2_f));
|
||||||
auto* mod_init = mod_f32->constructor;
|
auto* mod_init = mod_f32->constructor;
|
||||||
AST().AddGlobalVariable(mod_f32);
|
AST().AddGlobalVariable(mod_f32);
|
||||||
|
|
||||||
@ -424,7 +424,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
|
|||||||
|
|
||||||
TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
|
TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
|
||||||
// var<private> a : array<f32, 10u>;
|
// var<private> a : array<f32, 10u>;
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_u)), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_u)), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -437,7 +437,7 @@ TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
|
|||||||
|
|
||||||
TEST_F(ResolverTest, ArraySize_SignedLiteral) {
|
TEST_F(ResolverTest, ArraySize_SignedLiteral) {
|
||||||
// var<private> a : array<f32, 10i>;
|
// var<private> a : array<f32, 10i>;
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_i)), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr(10_i)), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -452,7 +452,7 @@ TEST_F(ResolverTest, ArraySize_UnsignedConst) {
|
|||||||
// const size = 10u;
|
// const size = 10u;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(10_u));
|
GlobalConst("size", Expr(10_u));
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -467,7 +467,7 @@ TEST_F(ResolverTest, ArraySize_SignedConst) {
|
|||||||
// const size = 0;
|
// const size = 0;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(10_i));
|
GlobalConst("size", Expr(10_i));
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -482,7 +482,7 @@ TEST_F(ResolverTest, ArraySize_Override) {
|
|||||||
// override size = 0;
|
// override size = 0;
|
||||||
// var<workgroup> a : array<f32, size>;
|
// var<workgroup> a : array<f32, size>;
|
||||||
auto* override = Override("size", Expr(10_i));
|
auto* override = Override("size", Expr(10_i));
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kWorkgroup);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -500,8 +500,8 @@ TEST_F(ResolverTest, ArraySize_Override_Equivalence) {
|
|||||||
// var<workgroup> a : array<f32, size>;
|
// var<workgroup> a : array<f32, size>;
|
||||||
// var<workgroup> b : array<f32, size>;
|
// var<workgroup> b : array<f32, size>;
|
||||||
auto* override = Override("size", Expr(10_i));
|
auto* override = Override("size", Expr(10_i));
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kWorkgroup);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), Expr("size")), ast::AddressSpace::kWorkgroup);
|
||||||
auto* b = GlobalVar("b", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kWorkgroup);
|
auto* b = GlobalVar("b", ty.array(ty.f32(), Expr("size")), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -523,7 +523,7 @@ TEST_F(ResolverTest, ArraySize_Override_Equivalence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Bitcast) {
|
TEST_F(ResolverTest, Expr_Bitcast) {
|
||||||
GlobalVar("name", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("name", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr("name"));
|
auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr("name"));
|
||||||
WrapInFunction(bitcast);
|
WrapInFunction(bitcast);
|
||||||
@ -586,7 +586,7 @@ TEST_F(ResolverTest, Expr_Call_Builtin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Cast) {
|
TEST_F(ResolverTest, Expr_Cast) {
|
||||||
GlobalVar("name", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("name", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* cast = Construct(ty.f32(), "name");
|
auto* cast = Construct(ty.f32(), "name");
|
||||||
WrapInFunction(cast);
|
WrapInFunction(cast);
|
||||||
@ -644,7 +644,7 @@ TEST_F(ResolverTest, Expr_Constructor_Type_Vec4) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
|
TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
|
||||||
auto* my_var = GlobalVar("my_var", ty.f32(), ast::StorageClass::kPrivate);
|
auto* my_var = GlobalVar("my_var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* ident = Expr("my_var");
|
auto* ident = Expr("my_var");
|
||||||
WrapInFunction(ident);
|
WrapInFunction(ident);
|
||||||
@ -747,7 +747,7 @@ TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
|
|||||||
auto* v = Expr("v");
|
auto* v = Expr("v");
|
||||||
auto* p = Expr("p");
|
auto* p = Expr("p");
|
||||||
auto* v_decl = Decl(Var("v", ty.f32()));
|
auto* v_decl = Decl(Var("v", ty.f32()));
|
||||||
auto* p_decl = Decl(Let("p", ty.pointer<f32>(ast::StorageClass::kFunction), AddressOf(v)));
|
auto* p_decl = Decl(Let("p", ty.pointer<f32>(ast::AddressSpace::kFunction), AddressOf(v)));
|
||||||
auto* assign = Assign(Deref(p), 1.23_f);
|
auto* assign = Assign(Deref(p), 1.23_f);
|
||||||
Func("my_func", utils::Empty, ty.void_(),
|
Func("my_func", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -822,7 +822,7 @@ TEST_F(ResolverTest, Function_Parameters_Locations) {
|
|||||||
auto* param_b = Param("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kVertexIndex)});
|
auto* param_b = Param("b", ty.u32(), utils::Vector{Builtin(ast::BuiltinValue::kVertexIndex)});
|
||||||
auto* param_c = Param("c", ty.u32(), utils::Vector{Location(1_a)});
|
auto* param_c = Param("c", ty.u32(), utils::Vector{Location(1_a)});
|
||||||
|
|
||||||
GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* func = Func("my_func",
|
auto* func = Func("my_func",
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
param_a,
|
param_a,
|
||||||
@ -852,8 +852,8 @@ TEST_F(ResolverTest, Function_Parameters_Locations) {
|
|||||||
|
|
||||||
TEST_F(ResolverTest, Function_GlobalVariable_Location) {
|
TEST_F(ResolverTest, Function_GlobalVariable_Location) {
|
||||||
auto* var = GlobalVar(
|
auto* var = GlobalVar(
|
||||||
"my_vec", ty.vec4<f32>(), ast::StorageClass::kIn,
|
"my_vec", ty.vec4<f32>(), ast::AddressSpace::kIn,
|
||||||
utils::Vector{Location(3_a), Disable(ast::DisabledValidation::kIgnoreStorageClass)});
|
utils::Vector{Location(3_a), Disable(ast::DisabledValidation::kIgnoreAddressSpace)});
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
@ -865,10 +865,10 @@ TEST_F(ResolverTest, Function_GlobalVariable_Location) {
|
|||||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
|
||||||
|
|
||||||
auto* sb_var = GlobalVar("sb_var", ty.Of(s), ast::StorageClass::kStorage,
|
auto* sb_var = GlobalVar("sb_var", ty.Of(s), ast::AddressSpace::kStorage,
|
||||||
ast::Access::kReadWrite, Binding(0_a), Group(0_a));
|
ast::Access::kReadWrite, Binding(0_a), Group(0_a));
|
||||||
auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
|
auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::StorageClass::kPrivate);
|
auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* func = Func("my_func", utils::Empty, ty.void_(),
|
auto* func = Func("my_func", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -911,7 +911,7 @@ TEST_F(ResolverTest, Function_ReturnType_Location) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Function_ReturnType_NoLocation) {
|
TEST_F(ResolverTest, Function_ReturnType_NoLocation) {
|
||||||
GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* func = Func("my_func", utils::Empty, ty.vec4<f32>(),
|
auto* func = Func("my_func", utils::Empty, ty.vec4<f32>(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Return("my_vec"),
|
Return("my_vec"),
|
||||||
@ -933,10 +933,10 @@ TEST_F(ResolverTest, Function_ReturnType_NoLocation) {
|
|||||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
|
auto* s = Structure("S", utils::Vector{Member("m", ty.u32())});
|
||||||
|
|
||||||
auto* sb_var = GlobalVar("sb_var", ty.Of(s), ast::StorageClass::kStorage,
|
auto* sb_var = GlobalVar("sb_var", ty.Of(s), ast::AddressSpace::kStorage,
|
||||||
ast::Access::kReadWrite, Binding(0_a), Group(0_a));
|
ast::Access::kReadWrite, Binding(0_a), Group(0_a));
|
||||||
auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
|
auto* wg_var = GlobalVar("wg_var", ty.f32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::StorageClass::kPrivate);
|
auto* priv_var = GlobalVar("priv_var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
Func("my_func", utils::Empty, ty.f32(),
|
Func("my_func", utils::Empty, ty.f32(),
|
||||||
utils::Vector{Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
|
utils::Vector{Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
|
||||||
@ -1187,7 +1187,7 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
|
|||||||
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
||||||
auto* st = Structure(
|
auto* st = Structure(
|
||||||
"S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
|
"S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
|
||||||
GlobalVar("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
|
GlobalVar("my_struct", ty.Of(st), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* mem = MemberAccessor("my_struct", "second_member");
|
auto* mem = MemberAccessor("my_struct", "second_member");
|
||||||
WrapInFunction(mem);
|
WrapInFunction(mem);
|
||||||
@ -1211,7 +1211,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
|
|||||||
auto* st = Structure(
|
auto* st = Structure(
|
||||||
"S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
|
"S", utils::Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
|
||||||
auto* alias = Alias("alias", ty.Of(st));
|
auto* alias = Alias("alias", ty.Of(st));
|
||||||
GlobalVar("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
|
GlobalVar("my_struct", ty.Of(alias), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* mem = MemberAccessor("my_struct", "second_member");
|
auto* mem = MemberAccessor("my_struct", "second_member");
|
||||||
WrapInFunction(mem);
|
WrapInFunction(mem);
|
||||||
@ -1231,7 +1231,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
|
||||||
GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* mem = MemberAccessor("my_vec", "xzyw");
|
auto* mem = MemberAccessor("my_vec", "xzyw");
|
||||||
WrapInFunction(mem);
|
WrapInFunction(mem);
|
||||||
@ -1249,7 +1249,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
|
||||||
GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* mem = MemberAccessor("my_vec", "b");
|
auto* mem = MemberAccessor("my_vec", "b");
|
||||||
WrapInFunction(mem);
|
WrapInFunction(mem);
|
||||||
@ -1285,7 +1285,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
|||||||
|
|
||||||
auto* stB = Structure("B", utils::Vector{Member("foo", ty.vec4<f32>())});
|
auto* stB = Structure("B", utils::Vector{Member("foo", ty.vec4<f32>())});
|
||||||
auto* stA = Structure("A", utils::Vector{Member("mem", ty.array(ty.Of(stB), 3_i))});
|
auto* stA = Structure("A", utils::Vector{Member("mem", ty.array(ty.Of(stB), 3_i))});
|
||||||
GlobalVar("c", ty.Of(stA), ast::StorageClass::kPrivate);
|
GlobalVar("c", ty.Of(stA), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* mem =
|
auto* mem =
|
||||||
MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0_i), "foo"), "yx");
|
MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0_i), "foo"), "yx");
|
||||||
@ -1303,7 +1303,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
|||||||
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
|
||||||
auto* st = Structure(
|
auto* st = Structure(
|
||||||
"S", utils::Vector{Member("first_member", ty.f32()), Member("second_member", ty.f32())});
|
"S", utils::Vector{Member("first_member", ty.f32()), Member("second_member", ty.f32())});
|
||||||
GlobalVar("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
|
GlobalVar("my_struct", ty.Of(st), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Add(MemberAccessor("my_struct", "first_member"),
|
auto* expr = Add(MemberAccessor("my_struct", "first_member"),
|
||||||
MemberAccessor("my_struct", "second_member"));
|
MemberAccessor("my_struct", "second_member"));
|
||||||
@ -1606,8 +1606,8 @@ TEST_P(Expr_Binary_Test_Valid, All) {
|
|||||||
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
|
ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("lhs", lhs_type, ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("rhs", rhs_type, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
|
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1641,8 +1641,8 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
|
|||||||
<< FriendlyName(rhs_type);
|
<< FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("lhs", lhs_type, ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("rhs", rhs_type, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
|
auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1687,8 +1687,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
|
|||||||
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
|
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("lhs", lhs_type, ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("rhs", rhs_type, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), Expr("rhs"));
|
auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), Expr("rhs"));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1727,8 +1727,8 @@ TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
|
|||||||
is_valid_expr = vec_size == mat_cols;
|
is_valid_expr = vec_size == mat_cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("lhs", lhs_type, ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("rhs", rhs_type, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
|
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1764,8 +1764,8 @@ TEST_P(Expr_Binary_Test_Invalid_MatrixMatrixMultiply, All) {
|
|||||||
auto* col = create<sem::Vector>(f32, lhs_mat_rows);
|
auto* col = create<sem::Vector>(f32, lhs_mat_rows);
|
||||||
auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
|
auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
|
||||||
|
|
||||||
GlobalVar("lhs", lhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("lhs", lhs_type, ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("rhs", rhs_type, ast::StorageClass::kPrivate);
|
GlobalVar("rhs", rhs_type, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
|
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
@ -1793,11 +1793,11 @@ TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
|
|||||||
auto op = GetParam();
|
auto op = GetParam();
|
||||||
|
|
||||||
if (op == ast::UnaryOp::kNot) {
|
if (op == ast::UnaryOp::kNot) {
|
||||||
GlobalVar("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<bool>(), ast::AddressSpace::kPrivate);
|
||||||
} else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
|
} else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
|
||||||
GlobalVar("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<i32>(), ast::AddressSpace::kPrivate);
|
||||||
} else {
|
} else {
|
||||||
GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
}
|
}
|
||||||
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
|
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
|
||||||
WrapInFunction(der);
|
WrapInFunction(der);
|
||||||
@ -1821,7 +1821,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
|||||||
ast::UnaryOp::kNegation,
|
ast::UnaryOp::kNegation,
|
||||||
ast::UnaryOp::kNot));
|
ast::UnaryOp::kNot));
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
|
TEST_F(ResolverTest, AddressSpace_SetsIfMissing) {
|
||||||
auto* var = Var("var", ty.i32());
|
auto* var = Var("var", ty.i32());
|
||||||
|
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
@ -1829,42 +1829,42 @@ TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
|
|||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kFunction);
|
EXPECT_EQ(Sem().Get(var)->AddressSpace(), ast::AddressSpace::kFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_SetForSampler) {
|
TEST_F(ResolverTest, AddressSpace_SetForSampler) {
|
||||||
auto* t = ty.sampler(ast::SamplerKind::kSampler);
|
auto* t = ty.sampler(ast::SamplerKind::kSampler);
|
||||||
auto* var = GlobalVar("var", t, Binding(0_a), Group(0_a));
|
auto* var = GlobalVar("var", t, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kHandle);
|
EXPECT_EQ(Sem().Get(var)->AddressSpace(), ast::AddressSpace::kHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_SetForTexture) {
|
TEST_F(ResolverTest, AddressSpace_SetForTexture) {
|
||||||
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||||
auto* var = GlobalVar("var", t, Binding(0_a), Group(0_a));
|
auto* var = GlobalVar("var", t, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kHandle);
|
EXPECT_EQ(Sem().Get(var)->AddressSpace(), ast::AddressSpace::kHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
|
TEST_F(ResolverTest, AddressSpace_DoesNotSetOnConst) {
|
||||||
auto* var = Let("var", ty.i32(), Construct(ty.i32()));
|
auto* var = Let("var", ty.i32(), Construct(ty.i32()));
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
Func("func", utils::Empty, ty.void_(), utils::Vector{stmt});
|
Func("func", utils::Empty, ty.void_(), utils::Vector{stmt});
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kNone);
|
EXPECT_EQ(Sem().Get(var)->AddressSpace(), ast::AddressSpace::kNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Access_SetForStorageBuffer) {
|
TEST_F(ResolverTest, Access_SetForStorageBuffer) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<storage> g : S;
|
// var<storage> g : S;
|
||||||
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", utils::Vector{Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
auto* var = GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
|
auto* var = GlobalVar(Source{{56, 78}}, "g", ty.Of(s), ast::AddressSpace::kStorage,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -1897,11 +1897,11 @@ TEST_F(ResolverTest, Function_EntryPoints_StageAttribute) {
|
|||||||
// ep_1 -> {}
|
// ep_1 -> {}
|
||||||
// ep_2 -> {}
|
// ep_2 -> {}
|
||||||
|
|
||||||
GlobalVar("first", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("first", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("second", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("second", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("call_a", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("call_a", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("call_b", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("call_b", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("call_c", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("call_c", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* func_b = Func("b", utils::Empty, ty.f32(),
|
auto* func_b = Func("b", utils::Empty, ty.f32(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -2041,8 +2041,8 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) {
|
|||||||
{
|
{
|
||||||
ProgramBuilder b;
|
ProgramBuilder b;
|
||||||
auto* expr = b.Expr(1_i);
|
auto* expr = b.Expr(1_i);
|
||||||
b.GlobalVar("a", b.ty.i32(), ast::StorageClass::kPrivate, expr);
|
b.GlobalVar("a", b.ty.i32(), ast::AddressSpace::kPrivate, expr);
|
||||||
b.GlobalVar("b", b.ty.i32(), ast::StorageClass::kPrivate, expr);
|
b.GlobalVar("b", b.ty.i32(), ast::AddressSpace::kPrivate, expr);
|
||||||
Resolver(&b).Resolve();
|
Resolver(&b).Resolve();
|
||||||
},
|
},
|
||||||
"internal compiler error: AST node 'tint::ast::IntLiteralExpression' was encountered twice "
|
"internal compiler error: AST node 'tint::ast::IntLiteralExpression' was encountered twice "
|
||||||
@ -2050,7 +2050,7 @@ TEST_F(ResolverTest, ASTNodeReachedTwice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, UnaryOp_Not) {
|
TEST_F(ResolverTest, UnaryOp_Not) {
|
||||||
GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(Source{{12, 34}}, "ident"));
|
auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(Source{{12, 34}}, "ident"));
|
||||||
WrapInFunction(der);
|
WrapInFunction(der);
|
||||||
|
|
||||||
@ -2059,7 +2059,7 @@ TEST_F(ResolverTest, UnaryOp_Not) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, UnaryOp_Complement) {
|
TEST_F(ResolverTest, UnaryOp_Complement) {
|
||||||
GlobalVar("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* der =
|
auto* der =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(Source{{12, 34}}, "ident"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(Source{{12, 34}}, "ident"));
|
||||||
WrapInFunction(der);
|
WrapInFunction(der);
|
||||||
@ -2069,7 +2069,7 @@ TEST_F(ResolverTest, UnaryOp_Complement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, UnaryOp_Negation) {
|
TEST_F(ResolverTest, UnaryOp_Negation) {
|
||||||
GlobalVar("ident", ty.u32(), ast::StorageClass::kPrivate);
|
GlobalVar("ident", ty.u32(), ast::AddressSpace::kPrivate);
|
||||||
auto* der =
|
auto* der =
|
||||||
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(Source{{12, 34}}, "ident"));
|
create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(Source{{12, 34}}, "ident"));
|
||||||
WrapInFunction(der);
|
WrapInFunction(der);
|
||||||
@ -2214,15 +2214,15 @@ TEST_F(ResolverTest, TextureSampler_TextureDimensions) {
|
|||||||
|
|
||||||
TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
|
TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
|
||||||
auto* f0 = Func("f0", utils::Empty, ty.void_(), utils::Empty);
|
auto* f0 = Func("f0", utils::Empty, ty.void_(), utils::Empty);
|
||||||
auto* v0 = GlobalVar("v0", ty.i32(), ast::StorageClass::kPrivate);
|
auto* v0 = GlobalVar("v0", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* a0 = Alias("a0", ty.i32());
|
auto* a0 = Alias("a0", ty.i32());
|
||||||
auto* s0 = Structure("s0", utils::Vector{Member("m", ty.i32())});
|
auto* s0 = Structure("s0", utils::Vector{Member("m", ty.i32())});
|
||||||
auto* f1 = Func("f1", utils::Empty, ty.void_(), utils::Empty);
|
auto* f1 = Func("f1", utils::Empty, ty.void_(), utils::Empty);
|
||||||
auto* v1 = GlobalVar("v1", ty.i32(), ast::StorageClass::kPrivate);
|
auto* v1 = GlobalVar("v1", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* a1 = Alias("a1", ty.i32());
|
auto* a1 = Alias("a1", ty.i32());
|
||||||
auto* s1 = Structure("s1", utils::Vector{Member("m", ty.i32())});
|
auto* s1 = Structure("s1", utils::Vector{Member("m", ty.i32())});
|
||||||
auto* f2 = Func("f2", utils::Empty, ty.void_(), utils::Empty);
|
auto* f2 = Func("f2", utils::Empty, ty.void_(), utils::Empty);
|
||||||
auto* v2 = GlobalVar("v2", ty.i32(), ast::StorageClass::kPrivate);
|
auto* v2 = GlobalVar("v2", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* a2 = Alias("a2", ty.i32());
|
auto* a2 = Alias("a2", ty.i32());
|
||||||
auto* s2 = Structure("s2", utils::Vector{Member("m", ty.i32())});
|
auto* s2 = Structure("s2", utils::Vector{Member("m", ty.i32())});
|
||||||
|
|
||||||
|
@ -604,13 +604,13 @@ struct DataType<ptr<T>> {
|
|||||||
/// @param b the ProgramBuilder
|
/// @param b the ProgramBuilder
|
||||||
/// @return a new AST alias type
|
/// @return a new AST alias type
|
||||||
static inline const ast::Type* AST(ProgramBuilder& b) {
|
static inline const ast::Type* AST(ProgramBuilder& b) {
|
||||||
return b.create<ast::Pointer>(DataType<T>::AST(b), ast::StorageClass::kPrivate,
|
return b.create<ast::Pointer>(DataType<T>::AST(b), ast::AddressSpace::kPrivate,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
}
|
}
|
||||||
/// @param b the ProgramBuilder
|
/// @param b the ProgramBuilder
|
||||||
/// @return the semantic aliased type
|
/// @return the semantic aliased type
|
||||||
static inline const sem::Type* Sem(ProgramBuilder& b) {
|
static inline const sem::Type* Sem(ProgramBuilder& b) {
|
||||||
return b.create<sem::Pointer>(DataType<T>::Sem(b), ast::StorageClass::kPrivate,
|
return b.create<sem::Pointer>(DataType<T>::Sem(b), ast::AddressSpace::kPrivate,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +618,7 @@ struct DataType<ptr<T>> {
|
|||||||
/// @return a new AST expression of the pointer type
|
/// @return a new AST expression of the pointer type
|
||||||
static inline const ast::Expression* Expr(ProgramBuilder& b, ScalarArgs /*unused*/) {
|
static inline const ast::Expression* Expr(ProgramBuilder& b, ScalarArgs /*unused*/) {
|
||||||
auto sym = b.Symbols().New("global_for_ptr");
|
auto sym = b.Symbols().New("global_for_ptr");
|
||||||
b.GlobalVar(sym, DataType<T>::AST(b), ast::StorageClass::kPrivate);
|
b.GlobalVar(sym, DataType<T>::AST(b), ast::AddressSpace::kPrivate);
|
||||||
return b.AddressOf(sym);
|
return b.AddressOf(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ struct SideEffectsTest : ResolverTest {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void MakeSideEffectFunc(const char* name) {
|
void MakeSideEffectFunc(const char* name) {
|
||||||
auto global = Sym();
|
auto global = Sym();
|
||||||
GlobalVar(global, ty.Of<T>(), ast::StorageClass::kPrivate);
|
GlobalVar(global, ty.Of<T>(), ast::AddressSpace::kPrivate);
|
||||||
auto local = Sym();
|
auto local = Sym();
|
||||||
Func(name, utils::Empty, ty.Of<T>(),
|
Func(name, utils::Empty, ty.Of<T>(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -43,7 +43,7 @@ struct SideEffectsTest : ResolverTest {
|
|||||||
template <typename MAKE_TYPE_FUNC>
|
template <typename MAKE_TYPE_FUNC>
|
||||||
void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
|
void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
|
||||||
auto global = Sym();
|
auto global = Sym();
|
||||||
GlobalVar(global, make_type(), ast::StorageClass::kPrivate);
|
GlobalVar(global, make_type(), ast::AddressSpace::kPrivate);
|
||||||
auto local = Sym();
|
auto local = Sym();
|
||||||
Func(name, utils::Empty, make_type(),
|
Func(name, utils::Empty, make_type(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -88,7 +88,7 @@ TEST_F(SideEffectsTest, VariableUser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
|
TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
|
||||||
GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
auto* expr = Call("dpdx", "a");
|
auto* expr = Call("dpdx", "a");
|
||||||
Func("f", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
Func("f", utils::Empty, ty.void_(), utils::Vector{Ignore(expr)},
|
||||||
utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
|
utils::Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
|
||||||
@ -114,7 +114,7 @@ TEST_F(SideEffectsTest, Call_Builtin_NoSE_WithSEArg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SideEffectsTest, Call_Builtin_SE) {
|
TEST_F(SideEffectsTest, Call_Builtin_SE) {
|
||||||
GlobalVar("a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
|
GlobalVar("a", ty.atomic(ty.i32()), ast::AddressSpace::kWorkgroup);
|
||||||
auto* expr = Call("atomicAdd", AddressOf("a"), 1_i);
|
auto* expr = Call("atomicAdd", AddressOf("a"), 1_i);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -163,20 +163,20 @@ TEST_P(SideEffectsBuiltinTest, Test) {
|
|||||||
auto& c = GetParam();
|
auto& c = GetParam();
|
||||||
|
|
||||||
uint32_t next_binding = 0;
|
uint32_t next_binding = 0;
|
||||||
GlobalVar("f", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar("f", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("i", ty.i32(), ast::StorageClass::kPrivate);
|
GlobalVar("i", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("u", ty.u32(), ast::StorageClass::kPrivate);
|
GlobalVar("u", ty.u32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
|
GlobalVar("b", ty.bool_(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("vf", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("vf", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("vf2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("vf2", ty.vec2<f32>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("vi2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
|
GlobalVar("vi2", ty.vec2<i32>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("vf4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("vf4", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("vb", ty.vec3<bool>(), ast::StorageClass::kPrivate);
|
GlobalVar("vb", ty.vec3<bool>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("m", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("m", ty.mat3x3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("arr", ty.array<f32, 10>(), ast::StorageClass::kPrivate);
|
GlobalVar("arr", ty.array<f32, 10>(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("storage_arr", ty.array<f32>(), ast::StorageClass::kStorage, Group(0_a),
|
GlobalVar("storage_arr", ty.array<f32>(), ast::AddressSpace::kStorage, Group(0_a),
|
||||||
Binding(AInt(next_binding++)));
|
Binding(AInt(next_binding++)));
|
||||||
GlobalVar("a", ty.atomic(ty.i32()), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
GlobalVar("a", ty.atomic(ty.i32()), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Group(0_a), Binding(AInt(next_binding++)));
|
Group(0_a), Binding(AInt(next_binding++)));
|
||||||
if (c.pipeline_stage != ast::PipelineStage::kCompute) {
|
if (c.pipeline_stage != ast::PipelineStage::kCompute) {
|
||||||
GlobalVar("t2d", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), Group(0_a),
|
GlobalVar("t2d", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), Group(0_a),
|
||||||
|
@ -26,7 +26,7 @@ namespace {
|
|||||||
class ResolverSourceVariableTest : public ResolverTest {};
|
class ResolverSourceVariableTest : public ResolverTest {};
|
||||||
|
|
||||||
TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
|
TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
|
||||||
auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
auto* expr = Expr(a);
|
auto* expr = Expr(a);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
|
TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
|
||||||
auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kWorkgroup);
|
auto* a = GlobalVar("a", ty.f32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* expr = Expr(a);
|
auto* expr = Expr(a);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
|
TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
|
||||||
auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kStorage, Group(0_a), Binding(0_a));
|
auto* a = GlobalVar("a", ty.f32(), ast::AddressSpace::kStorage, Group(0_a), Binding(0_a));
|
||||||
auto* expr = Expr(a);
|
auto* expr = Expr(a);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
|
TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
|
||||||
auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kUniform, Group(0_a), Binding(0_a));
|
auto* a = GlobalVar("a", ty.f32(), ast::AddressSpace::kUniform, Group(0_a), Binding(0_a));
|
||||||
auto* expr = Expr(a);
|
auto* expr = Expr(a);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
|
|||||||
|
|
||||||
TEST_F(ResolverSourceVariableTest, GlobalTextureVar) {
|
TEST_F(ResolverSourceVariableTest, GlobalTextureVar) {
|
||||||
auto* a = GlobalVar("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
|
auto* a = GlobalVar("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
|
||||||
ast::StorageClass::kNone, Group(0_a), Binding(0_a));
|
ast::AddressSpace::kNone, Group(0_a), Binding(0_a));
|
||||||
auto* expr = Expr(a);
|
auto* expr = Expr(a);
|
||||||
WrapInFunction(Call("textureDimensions", expr));
|
WrapInFunction(Call("textureDimensions", expr));
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ TEST_F(ResolverSourceVariableTest, PointerParameter) {
|
|||||||
// {
|
// {
|
||||||
// let b = a;
|
// let b = a;
|
||||||
// }
|
// }
|
||||||
auto* param = Param("a", ty.pointer(ty.f32(), ast::StorageClass::kFunction));
|
auto* param = Param("a", ty.pointer(ty.f32(), ast::AddressSpace::kFunction));
|
||||||
auto* expr_param = Expr(param);
|
auto* expr_param = Expr(param);
|
||||||
auto* let = Let("b", expr_param);
|
auto* let = Let("b", expr_param);
|
||||||
auto* expr_let = Expr("b");
|
auto* expr_let = Expr("b");
|
||||||
@ -198,7 +198,7 @@ TEST_F(ResolverSourceVariableTest, ThroughIndexAccessor) {
|
|||||||
// {
|
// {
|
||||||
// a[2i]
|
// a[2i]
|
||||||
// }
|
// }
|
||||||
auto* a = GlobalVar("a", ty.array(ty.f32(), 4_u), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.array(ty.f32(), 4_u), ast::AddressSpace::kPrivate);
|
||||||
auto* expr = IndexAccessor(a, 2_i);
|
auto* expr = IndexAccessor(a, 2_i);
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ TEST_F(ResolverSourceVariableTest, ThroughMemberAccessor) {
|
|||||||
// a.f
|
// a.f
|
||||||
// }
|
// }
|
||||||
auto* S = Structure("S", utils::Vector{Member("f", ty.f32())});
|
auto* S = Structure("S", utils::Vector{Member("f", ty.f32())});
|
||||||
auto* a = GlobalVar("a", ty.Of(S), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.Of(S), ast::AddressSpace::kPrivate);
|
||||||
auto* expr = MemberAccessor(a, "f");
|
auto* expr = MemberAccessor(a, "f");
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ TEST_F(ResolverSourceVariableTest, ThroughPointers) {
|
|||||||
// let a_ptr1 = &*&a;
|
// let a_ptr1 = &*&a;
|
||||||
// let a_ptr2 = &*a_ptr1;
|
// let a_ptr2 = &*a_ptr1;
|
||||||
// }
|
// }
|
||||||
auto* a = GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate);
|
auto* a = GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
auto* address_of_1 = AddressOf(a);
|
auto* address_of_1 = AddressOf(a);
|
||||||
auto* deref_1 = Deref(address_of_1);
|
auto* deref_1 = Deref(address_of_1);
|
||||||
auto* address_of_2 = AddressOf(deref_1);
|
auto* address_of_2 = AddressOf(deref_1);
|
||||||
|
@ -86,7 +86,7 @@ TEST_F(ResolverStaticAssertTest, Local_Const_Fail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStaticAssertTest, Local_NonConst) {
|
TEST_F(ResolverStaticAssertTest, Local_NonConst) {
|
||||||
GlobalVar("V", ty.bool_(), Expr(true), ast::StorageClass::kPrivate);
|
GlobalVar("V", ty.bool_(), Expr(true), ast::AddressSpace::kPrivate);
|
||||||
WrapInFunction(StaticAssert(Expr(Source{{12, 34}}, "V")));
|
WrapInFunction(StaticAssert(Expr(Source{{12, 34}}, "V")));
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
|
@ -25,19 +25,19 @@ using namespace tint::number_suffixes; // NOLINT
|
|||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ResolverStorageClassUseTest = ResolverTest;
|
using ResolverAddressSpaceUseTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
|
TEST_F(ResolverAddressSpaceUseTest, UnreachableStruct) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->StorageClassUsage().empty());
|
EXPECT_TRUE(sem->AddressSpaceUsage().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableFromParameter) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
|
|
||||||
Func("f", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty, utils::Empty);
|
Func("f", utils::Vector{Param("param", ty.Of(s))}, ty.void_(), utils::Empty, utils::Empty);
|
||||||
@ -46,10 +46,10 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kNone));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kNone));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableFromReturnType) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
|
|
||||||
Func("f", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s)))}, utils::Empty);
|
Func("f", utils::Empty, ty.Of(s), utils::Vector{Return(Construct(ty.Of(s)))}, utils::Empty);
|
||||||
@ -58,58 +58,58 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kNone));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kNone));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableFromGlobal) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
|
|
||||||
GlobalVar("g", ty.Of(s), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(s), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalAlias) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = Alias("A", ty.Of(s));
|
auto* a = Alias("A", ty.Of(s));
|
||||||
GlobalVar("g", ty.Of(a), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(a), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalStruct) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
|
auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
|
||||||
GlobalVar("g", ty.Of(o), ast::StorageClass::kPrivate);
|
GlobalVar("g", ty.Of(o), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaGlobalArray) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
GlobalVar("g", a, ast::StorageClass::kPrivate);
|
GlobalVar("g", a, ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableFromLocal) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
|
|
||||||
WrapInFunction(Var("g", ty.Of(s)));
|
WrapInFunction(Var("g", ty.Of(s)));
|
||||||
@ -118,10 +118,10 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalAlias) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = Alias("A", ty.Of(s));
|
auto* a = Alias("A", ty.Of(s));
|
||||||
WrapInFunction(Var("g", ty.Of(a)));
|
WrapInFunction(Var("g", ty.Of(a)));
|
||||||
@ -130,10 +130,10 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalStruct) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
|
auto* o = Structure("O", utils::Vector{Member("a", ty.Of(s))});
|
||||||
WrapInFunction(Var("g", ty.Of(o)));
|
WrapInFunction(Var("g", ty.Of(o)));
|
||||||
@ -142,10 +142,10 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
|
TEST_F(ResolverAddressSpaceUseTest, StructReachableViaLocalArray) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
WrapInFunction(Var("g", a));
|
WrapInFunction(Var("g", a));
|
||||||
@ -154,13 +154,13 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
|
EXPECT_THAT(sem->AddressSpaceUsage(), UnorderedElementsAre(ast::AddressSpace::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
TEST_F(ResolverAddressSpaceUseTest, StructMultipleAddressSpaceUses) {
|
||||||
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
auto* s = Structure("S", utils::Vector{Member("a", ty.f32())});
|
||||||
GlobalVar("x", ty.Of(s), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("x", ty.Of(s), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
GlobalVar("y", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(1_a),
|
GlobalVar("y", ty.Of(s), ast::AddressSpace::kStorage, ast::Access::kRead, Binding(1_a),
|
||||||
Group(0_a));
|
Group(0_a));
|
||||||
WrapInFunction(Var("g", ty.Of(s)));
|
WrapInFunction(Var("g", ty.Of(s)));
|
||||||
|
|
||||||
@ -168,9 +168,9 @@ TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
|||||||
|
|
||||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->AddressSpaceUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kUniform, ast::StorageClass::kStorage,
|
UnorderedElementsAre(ast::AddressSpace::kUniform, ast::AddressSpace::kStorage,
|
||||||
ast::StorageClass::kFunction));
|
ast::AddressSpace::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -69,10 +69,10 @@ TEST_F(ResolverTypeConstructorValidationTest, InferTypeTest_Simple) {
|
|||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_TRUE(TypeOf(a_ident)->Is<sem::Reference>());
|
ASSERT_TRUE(TypeOf(a_ident)->Is<sem::Reference>());
|
||||||
EXPECT_TRUE(TypeOf(a_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
EXPECT_TRUE(TypeOf(a_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
||||||
EXPECT_EQ(TypeOf(a_ident)->As<sem::Reference>()->StorageClass(), ast::StorageClass::kFunction);
|
EXPECT_EQ(TypeOf(a_ident)->As<sem::Reference>()->AddressSpace(), ast::AddressSpace::kFunction);
|
||||||
ASSERT_TRUE(TypeOf(b_ident)->Is<sem::Reference>());
|
ASSERT_TRUE(TypeOf(b_ident)->Is<sem::Reference>());
|
||||||
EXPECT_TRUE(TypeOf(b_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
EXPECT_TRUE(TypeOf(b_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
|
||||||
EXPECT_EQ(TypeOf(b_ident)->As<sem::Reference>()->StorageClass(), ast::StorageClass::kFunction);
|
EXPECT_EQ(TypeOf(b_ident)->As<sem::Reference>()->AddressSpace(), ast::AddressSpace::kFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
using InferTypeTest_FromConstructorExpression = ResolverTestWithParam<Params>;
|
using InferTypeTest_FromConstructorExpression = ResolverTestWithParam<Params>;
|
||||||
@ -96,7 +96,7 @@ TEST_P(InferTypeTest_FromConstructorExpression, All) {
|
|||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* got = TypeOf(a_ident);
|
auto* got = TypeOf(a_ident);
|
||||||
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
||||||
ast::StorageClass::kFunction, ast::Access::kReadWrite);
|
ast::AddressSpace::kFunction, ast::Access::kReadWrite);
|
||||||
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
<< "expected: " << FriendlyName(expected) << "\n";
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ TEST_P(InferTypeTest_FromArithmeticExpression, All) {
|
|||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* got = TypeOf(a_ident);
|
auto* got = TypeOf(a_ident);
|
||||||
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
||||||
ast::StorageClass::kFunction, ast::Access::kReadWrite);
|
ast::AddressSpace::kFunction, ast::Access::kReadWrite);
|
||||||
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
<< "expected: " << FriendlyName(expected) << "\n";
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ TEST_P(InferTypeTest_FromCallExpression, All) {
|
|||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* got = TypeOf(a_ident);
|
auto* got = TypeOf(a_ident);
|
||||||
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
|
||||||
ast::StorageClass::kFunction, ast::Access::kReadWrite);
|
ast::AddressSpace::kFunction, ast::Access::kReadWrite);
|
||||||
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
<< "expected: " << FriendlyName(expected) << "\n";
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
@ -1968,7 +1968,7 @@ TEST_F(ResolverTypeConstructorValidationTest, NestedVectorConstructors_Success)
|
|||||||
|
|
||||||
TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Error) {
|
TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Error) {
|
||||||
auto* alias = Alias("UnsignedInt", ty.u32());
|
auto* alias = Alias("UnsignedInt", ty.u32());
|
||||||
GlobalVar("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
|
GlobalVar("uint_var", ty.Of(alias), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* tc = vec2<f32>(Source{{12, 34}}, "uint_var");
|
auto* tc = vec2<f32>(Source{{12, 34}}, "uint_var");
|
||||||
WrapInFunction(tc);
|
WrapInFunction(tc);
|
||||||
@ -1980,8 +1980,8 @@ TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Error) {
|
|||||||
TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Success) {
|
TEST_F(ResolverTypeConstructorValidationTest, Vector_Alias_Argument_Success) {
|
||||||
auto* f32_alias = Alias("Float32", ty.f32());
|
auto* f32_alias = Alias("Float32", ty.f32());
|
||||||
auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
|
auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
|
||||||
GlobalVar("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
|
GlobalVar("my_f32", ty.Of(f32_alias), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec2", ty.Of(vec2_alias), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* tc = vec3<f32>("my_vec2", "my_f32");
|
auto* tc = vec3<f32>("my_vec2", "my_f32");
|
||||||
WrapInFunction(tc);
|
WrapInFunction(tc);
|
||||||
|
@ -80,14 +80,14 @@ TEST_F(ResolverTypeValidationTest, GlobalOverrideNoConstructor_Pass) {
|
|||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
|
TEST_F(ResolverTypeValidationTest, GlobalVariableWithAddressSpace_Pass) {
|
||||||
// var<private> global_var: f32;
|
// var<private> global_var: f32;
|
||||||
GlobalVar(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{12, 34}}, "global_var", ty.f32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
|
TEST_F(ResolverTypeValidationTest, GlobalConstNoAddressSpace_Pass) {
|
||||||
// const global_const: f32 = f32();
|
// const global_const: f32 = f32();
|
||||||
GlobalConst(Source{{12, 34}}, "global_const", ty.f32(), Construct(ty.f32()));
|
GlobalConst(Source{{12, 34}}, "global_const", ty.f32(), Construct(ty.f32()));
|
||||||
|
|
||||||
@ -98,9 +98,9 @@ TEST_F(ResolverTypeValidationTest, GlobalVariableUnique_Pass) {
|
|||||||
// var global_var0 : f32 = 0.1;
|
// var global_var0 : f32 = 0.1;
|
||||||
// var global_var1 : i32 = 0;
|
// var global_var1 : i32 = 0;
|
||||||
|
|
||||||
GlobalVar("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1_f));
|
GlobalVar("global_var0", ty.f32(), ast::AddressSpace::kPrivate, Expr(0.1_f));
|
||||||
|
|
||||||
GlobalVar(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate, Expr(1_f));
|
GlobalVar(Source{{12, 34}}, "global_var1", ty.f32(), ast::AddressSpace::kPrivate, Expr(1_f));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ TEST_F(ResolverTypeValidationTest, GlobalVariableFunctionVariableNotUnique_Pass)
|
|||||||
Decl(Var("a", ty.f32(), Expr(2_f))),
|
Decl(Var("a", ty.f32(), Expr(2_f))),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
|
GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate, Expr(2.1_f));
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
@ -180,19 +180,19 @@ TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierDifferentFunctions_Pass)
|
|||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Pass) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Pass) {
|
||||||
// var<private> a : array<f32, 4>;
|
// var<private> a : array<f32, 4>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_a)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
|
||||||
// var<private> a : array<f32, 4u>;
|
// var<private> a : array<f32, 4u>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
|
||||||
// var<private> a : array<f32, 4i>;
|
// var<private> a : array<f32, 4i>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConst_Pass) {
|
|||||||
// const size = 4u;
|
// const size = 4u;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(4_u));
|
GlobalConst("size", Expr(4_u));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,34 +208,34 @@ TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Pass) {
|
|||||||
// const size = 4i;
|
// const size = 4i;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(4_i));
|
GlobalConst("size", Expr(4_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Zero) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_AIntLiteral_Zero) {
|
||||||
// var<private> a : array<f32, 0>;
|
// var<private> a : array<f32, 0>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_a)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
|
||||||
// var<private> a : array<f32, 0u>;
|
// var<private> a : array<f32, 0u>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
|
||||||
// var<private> a : array<f32, 0i>;
|
// var<private> a : array<f32, 0i>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
|
||||||
// var<private> a : array<f32, -10i>;
|
// var<private> a : array<f32, -10i>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10_i)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConst_Zero) {
|
|||||||
// const size = 0u;
|
// const size = 0u;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(0_u));
|
GlobalConst("size", Expr(0_u));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Zero) {
|
|||||||
// const size = 0i;
|
// const size = 0i;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(0_i));
|
GlobalConst("size", Expr(0_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (0) must be greater than 0");
|
||||||
}
|
}
|
||||||
@ -262,14 +262,14 @@ TEST_F(ResolverTypeValidationTest, ArraySize_SignedConst_Negative) {
|
|||||||
// const size = -10i;
|
// const size = -10i;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(-10_i));
|
GlobalConst("size", Expr(-10_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
|
EXPECT_EQ(r()->error(), "12:34 error: array size (-10) must be greater than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
|
||||||
// var<private> a : array<f32, 10.0>;
|
// var<private> a : array<f32, 10.0>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10_f)), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
||||||
@ -279,7 +279,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
|
|||||||
TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
|
||||||
// var<private> a : array<f32, vec2<i32>(10, 10)>;
|
// var<private> a : array<f32, vec2<i32>(10, 10)>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
|
GlobalVar("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
||||||
@ -290,7 +290,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_FloatConst) {
|
|||||||
// const size = 10.0;
|
// const size = 10.0;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Expr(10_f));
|
GlobalConst("size", Expr(10_f));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
||||||
@ -301,7 +301,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_IVecConst) {
|
|||||||
// const size = vec2<i32>(100, 100);
|
// const size = vec2<i32>(100, 100);
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalConst("size", Construct(ty.vec2<i32>(), 100_i, 100_i));
|
GlobalConst("size", Construct(ty.vec2<i32>(), 100_i, 100_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
"12:34 error: array size must evaluate to a constant integer expression, but is type "
|
||||||
@ -311,7 +311,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_IVecConst) {
|
|||||||
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
|
||||||
// var<private> a : array<f32, 0x40000000u>;
|
// var<private> a : array<f32, 0x40000000u>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0x40000000_u)),
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0x40000000_u)),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
|
"12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
|
||||||
@ -320,7 +320,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
|
|||||||
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
|
||||||
// var<private> a : @stride(8) array<f32, 0x20000000u>;
|
// var<private> a : @stride(8) array<f32, 0x20000000u>;
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0x20000000_u), 8),
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0x20000000_u), 8),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
|
"12:34 error: array size (0x100000000) must not exceed 0xffffffff bytes");
|
||||||
@ -330,7 +330,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Override_PrivateVar) {
|
|||||||
// override size = 10i;
|
// override size = 10i;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), "size"), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(Source{{12, 34}}, ty.f32(), "size"), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array with an 'override' element count can only be used as the store "
|
"12:34 error: array with an 'override' element count can only be used as the store "
|
||||||
@ -342,7 +342,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Override_ComplexExpr) {
|
|||||||
// var<workgroup> a : array<f32, size + 1>;
|
// var<workgroup> a : array<f32, size + 1>;
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Add(Source{{12, 34}}, "size", 1_i)),
|
GlobalVar("a", ty.array(ty.f32(), Add(Source{{12, 34}}, "size", 1_i)),
|
||||||
ast::StorageClass::kWorkgroup);
|
ast::AddressSpace::kWorkgroup);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array size must evaluate to a constant integer expression or override "
|
"12:34 error: array size must evaluate to a constant integer expression or override "
|
||||||
@ -354,7 +354,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Override_InArray) {
|
|||||||
// var<workgroup> a : array<array<f32, size>, 4>;
|
// var<workgroup> a : array<array<f32, size>, 4>;
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("a", ty.array(ty.array(Source{{12, 34}}, ty.f32(), "size"), 4_a),
|
GlobalVar("a", ty.array(ty.array(Source{{12, 34}}, ty.f32(), "size"), 4_a),
|
||||||
ast::StorageClass::kWorkgroup);
|
ast::AddressSpace::kWorkgroup);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: array with an 'override' element count can only be used as the store "
|
"12:34 error: array with an 'override' element count can only be used as the store "
|
||||||
@ -413,7 +413,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Override_FunctionVar_Implicit) {
|
|||||||
// var a = w;
|
// var a = w;
|
||||||
// }
|
// }
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("w", ty.array(ty.f32(), "size"), ast::StorageClass::kWorkgroup);
|
GlobalVar("w", ty.array(ty.f32(), "size"), ast::AddressSpace::kWorkgroup);
|
||||||
Func("f", utils::Empty, ty.void_(),
|
Func("f", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Decl(Var("a", Expr(Source{{12, 34}}, "w"))),
|
Decl(Var("a", Expr(Source{{12, 34}}, "w"))),
|
||||||
@ -431,7 +431,7 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Override_FunctionLet_Implicit) {
|
|||||||
// let a = w;
|
// let a = w;
|
||||||
// }
|
// }
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("w", ty.array(ty.f32(), "size"), ast::StorageClass::kWorkgroup);
|
GlobalVar("w", ty.array(ty.f32(), "size"), ast::AddressSpace::kWorkgroup);
|
||||||
Func("f", utils::Empty, ty.void_(),
|
Func("f", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
Decl(Let("a", Expr(Source{{12, 34}}, "w"))),
|
Decl(Let("a", Expr(Source{{12, 34}}, "w"))),
|
||||||
@ -468,15 +468,15 @@ TEST_F(ResolverTypeValidationTest, ArraySize_Workgroup_Overridable) {
|
|||||||
// var<workgroup> a : array<f32, size>;
|
// var<workgroup> a : array<f32, size>;
|
||||||
Override("size", Expr(10_i));
|
Override("size", Expr(10_i));
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||||
ast::StorageClass::kWorkgroup);
|
ast::AddressSpace::kWorkgroup);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
|
TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
|
||||||
// var<private> size : i32 = 10i;
|
// var<private> size : i32 = 10i;
|
||||||
// var<private> a : array<f32, size>;
|
// var<private> a : array<f32, size>;
|
||||||
GlobalVar("size", ty.i32(), Expr(10_i), ast::StorageClass::kPrivate);
|
GlobalVar("size", ty.i32(), Expr(10_i), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: var 'size' cannot be referenced at module-scope
|
R"(12:34 error: var 'size' cannot be referenced at module-scope
|
||||||
@ -531,7 +531,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
|
|||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
12:34 note: while instantiating 'var' a)");
|
12:34 note: while instantiating 'var' a)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +631,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInArray) {
|
|||||||
|
|
||||||
Structure("Foo", utils::Vector{Member("rt", ty.array<f32>())});
|
Structure("Foo", utils::Vector{Member("rt", ty.array<f32>())});
|
||||||
GlobalVar("v", ty.array(ty.type_name(Source{{12, 34}}, "Foo"), 4_u),
|
GlobalVar("v", ty.array(ty.type_name(Source{{12, 34}}, "Foo"), 4_u),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -676,12 +676,12 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayIsNotLast_Fail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
|
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
|
GlobalVar(Source{{56, 78}}, "g", ty.array<i32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(56:78 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,7 +692,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
|
|||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(56:78 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,7 +717,7 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
|
|||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
12:34 note: while instantiating parameter a)");
|
12:34 note: while instantiating parameter a)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,7 +725,7 @@ TEST_F(ResolverTypeValidationTest, PtrToRuntimeArrayAsParameter_Fail) {
|
|||||||
// fn func(a : ptr<workgroup, array<u32>>) {}
|
// fn func(a : ptr<workgroup, array<u32>>) {}
|
||||||
|
|
||||||
auto* param =
|
auto* param =
|
||||||
Param(Source{{12, 34}}, "a", ty.pointer(ty.array<i32>(), ast::StorageClass::kWorkgroup));
|
Param(Source{{12, 34}}, "a", ty.pointer(ty.array<i32>(), ast::AddressSpace::kWorkgroup));
|
||||||
|
|
||||||
Func("func", utils::Vector{param}, ty.void_(),
|
Func("func", utils::Vector{param}, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -734,7 +734,7 @@ TEST_F(ResolverTypeValidationTest, PtrToRuntimeArrayAsParameter_Fail) {
|
|||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
|
R"(12:34 error: runtime-sized arrays can only be used in the <storage> address space
|
||||||
12:34 note: while instantiating parameter a)");
|
12:34 note: while instantiating parameter a)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,7 +774,7 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
|
|||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
|
TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
|
||||||
auto* tex_ty = ty.sampled_texture(Source{{12, 34}}, ast::TextureDimension::k2d, ty.f32());
|
auto* tex_ty = ty.sampled_texture(Source{{12, 34}}, ast::TextureDimension::k2d, ty.f32());
|
||||||
GlobalVar("arr", ty.array(tex_ty, 4_i), ast::StorageClass::kPrivate);
|
GlobalVar("arr", ty.array(tex_ty, 4_i), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -784,8 +784,8 @@ TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
|
|||||||
TEST_F(ResolverTypeValidationTest, VariableAsType) {
|
TEST_F(ResolverTypeValidationTest, VariableAsType) {
|
||||||
// var<private> a : i32;
|
// var<private> a : i32;
|
||||||
// var<private> b : a;
|
// var<private> b : a;
|
||||||
GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
GlobalVar("b", ty.type_name("a"), ast::StorageClass::kPrivate);
|
GlobalVar("b", ty.type_name("a"), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -797,7 +797,7 @@ TEST_F(ResolverTypeValidationTest, FunctionAsType) {
|
|||||||
// fn f() {}
|
// fn f() {}
|
||||||
// var<private> v : f;
|
// var<private> v : f;
|
||||||
Func("f", utils::Empty, ty.void_(), {});
|
Func("f", utils::Empty, ty.void_(), {});
|
||||||
GlobalVar("v", ty.type_name("f"), ast::StorageClass::kPrivate);
|
GlobalVar("v", ty.type_name("f"), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
@ -807,7 +807,7 @@ note: 'f' declared here)");
|
|||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, BuiltinAsType) {
|
TEST_F(ResolverTypeValidationTest, BuiltinAsType) {
|
||||||
// var<private> v : max;
|
// var<private> v : max;
|
||||||
GlobalVar("v", ty.type_name("max"), ast::StorageClass::kPrivate);
|
GlobalVar("v", ty.type_name("max"), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
|
EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
|
||||||
@ -818,14 +818,14 @@ TEST_F(ResolverTypeValidationTest, F16TypeUsedWithExtension) {
|
|||||||
// var<private> v : f16;
|
// var<private> v : f16;
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("v", ty.f16(), ast::StorageClass::kPrivate);
|
GlobalVar("v", ty.f16(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTypeValidationTest, F16TypeUsedWithoutExtension) {
|
TEST_F(ResolverTypeValidationTest, F16TypeUsedWithoutExtension) {
|
||||||
// var<private> v : f16;
|
// var<private> v : f16;
|
||||||
GlobalVar("v", ty.f16(), ast::StorageClass::kPrivate);
|
GlobalVar("v", ty.f16(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "error: f16 used without 'f16' extension enabled");
|
EXPECT_EQ(r()->error(), "error: f16 used without 'f16' extension enabled");
|
||||||
@ -1179,7 +1179,7 @@ TEST_P(ValidMatrixTypes, Okay) {
|
|||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
|
GlobalVar("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
||||||
@ -1217,7 +1217,7 @@ TEST_P(InvalidMatrixElementTypes, InvalidElementType) {
|
|||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("a", ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns, params.rows),
|
GlobalVar("a", ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns, params.rows),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32' or 'f16'");
|
EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32' or 'f16'");
|
||||||
}
|
}
|
||||||
@ -1258,7 +1258,7 @@ TEST_P(ValidVectorTypes, Okay) {
|
|||||||
|
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), ast::StorageClass::kPrivate);
|
GlobalVar("a", ty.vec(params.elem_ty(*this), params.width), ast::AddressSpace::kPrivate);
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
||||||
@ -1292,7 +1292,7 @@ TEST_P(InvalidVectorElementTypes, InvalidElementType) {
|
|||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
GlobalVar("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
|
GlobalVar("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
|
||||||
ast::StorageClass::kPrivate);
|
ast::AddressSpace::kPrivate);
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' "
|
"12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' "
|
||||||
|
@ -1468,14 +1468,14 @@ class UniformityGraph {
|
|||||||
[&](const ast::IdentifierExpression* ident) {
|
[&](const ast::IdentifierExpression* ident) {
|
||||||
std::string var_type = "";
|
std::string var_type = "";
|
||||||
auto* var = sem_.Get<sem::VariableUser>(ident)->Variable();
|
auto* var = sem_.Get<sem::VariableUser>(ident)->Variable();
|
||||||
switch (var->StorageClass()) {
|
switch (var->AddressSpace()) {
|
||||||
case ast::StorageClass::kStorage:
|
case ast::AddressSpace::kStorage:
|
||||||
var_type = "read_write storage buffer ";
|
var_type = "read_write storage buffer ";
|
||||||
break;
|
break;
|
||||||
case ast::StorageClass::kWorkgroup:
|
case ast::AddressSpace::kWorkgroup:
|
||||||
var_type = "workgroup storage variable ";
|
var_type = "workgroup storage variable ";
|
||||||
break;
|
break;
|
||||||
case ast::StorageClass::kPrivate:
|
case ast::AddressSpace::kPrivate:
|
||||||
var_type = "module-scope private variable ";
|
var_type = "module-scope private variable ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -5291,7 +5291,7 @@ TEST_F(UniformityAnalysisTest, MaximumNumberOfPointerParameters) {
|
|||||||
foo_body.Push(b.Decl(b.Let("rhs", rhs_init)));
|
foo_body.Push(b.Decl(b.Let("rhs", rhs_init)));
|
||||||
for (int i = 0; i < 255; i++) {
|
for (int i = 0; i < 255; i++) {
|
||||||
params.Push(
|
params.Push(
|
||||||
b.Param("p" + std::to_string(i), ty.pointer(ty.i32(), ast::StorageClass::kFunction)));
|
b.Param("p" + std::to_string(i), ty.pointer(ty.i32(), ast::AddressSpace::kFunction)));
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
foo_body.Push(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
|
foo_body.Push(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
|
||||||
}
|
}
|
||||||
@ -5310,7 +5310,7 @@ TEST_F(UniformityAnalysisTest, MaximumNumberOfPointerParameters) {
|
|||||||
// workgroupBarrier();
|
// workgroupBarrier();
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
b.GlobalVar("non_uniform_global", ty.i32(), ast::StorageClass::kPrivate);
|
b.GlobalVar("non_uniform_global", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
utils::Vector<const ast::Statement*, 8> main_body;
|
utils::Vector<const ast::Statement*, 8> main_body;
|
||||||
utils::Vector<const ast::Expression*, 8> args;
|
utils::Vector<const ast::Expression*, 8> args;
|
||||||
for (int i = 0; i < 255; i++) {
|
for (int i = 0; i < 255; i++) {
|
||||||
@ -6519,7 +6519,7 @@ TEST_F(UniformityAnalysisTest, StressGraphTraversalDepth) {
|
|||||||
// workgroupBarrier();
|
// workgroupBarrier();
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
b.GlobalVar("v0", ty.i32(), ast::StorageClass::kPrivate, b.Expr(0_i));
|
b.GlobalVar("v0", ty.i32(), ast::AddressSpace::kPrivate, b.Expr(0_i));
|
||||||
utils::Vector<const ast::Statement*, 8> foo_body;
|
utils::Vector<const ast::Statement*, 8> foo_body;
|
||||||
std::string v_last = "v0";
|
std::string v_last = "v0";
|
||||||
for (int i = 1; i < 100000; i++) {
|
for (int i = 1; i < 100000; i++) {
|
||||||
|
@ -61,8 +61,8 @@ class FakeExpr final : public Castable<FakeExpr, ast::Expression> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
|
TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
|
||||||
GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::AddressSpace::kWorkgroup);
|
||||||
GlobalVar("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("dst", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
|
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
|
||||||
|
|
||||||
Func(Source{{9, 10}}, "f0", utils::Empty, ty.vec4<f32>(),
|
Func(Source{{9, 10}}, "f0", utils::Empty, ty.vec4<f32>(),
|
||||||
@ -93,8 +93,8 @@ TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInFragmentStage) {
|
|||||||
// f1();
|
// f1();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
|
GlobalVar(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::AddressSpace::kWorkgroup);
|
||||||
GlobalVar("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("dst", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
|
auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
|
||||||
|
|
||||||
Func(Source{{5, 6}}, "f2", utils::Empty, ty.void_(), utils::Vector{stmt});
|
Func(Source{{5, 6}}, "f2", utils::Empty, ty.void_(), utils::Vector{stmt});
|
||||||
@ -226,7 +226,7 @@ TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
GlobalVar("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1_f));
|
GlobalVar("global_var", ty.f32(), ast::AddressSpace::kPrivate, Expr(2.1_f));
|
||||||
|
|
||||||
Func("my_func", utils::Empty, ty.void_(),
|
Func("my_func", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -299,8 +299,8 @@ TEST_F(ResolverValidationTest, UsingUndefinedVariableDifferentScope_Fail) {
|
|||||||
EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
|
EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, StorageClass_FunctionVariableWorkgroupClass) {
|
TEST_F(ResolverValidationTest, AddressSpace_FunctionVariableWorkgroupClass) {
|
||||||
auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
|
auto* var = Var("var", ty.i32(), ast::AddressSpace::kWorkgroup);
|
||||||
|
|
||||||
Func("func", utils::Empty, ty.void_(),
|
Func("func", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -310,11 +310,11 @@ TEST_F(ResolverValidationTest, StorageClass_FunctionVariableWorkgroupClass) {
|
|||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: function-scope 'var' declaration must use 'function' storage class");
|
"error: function-scope 'var' declaration must use 'function' address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, StorageClass_FunctionVariableI32) {
|
TEST_F(ResolverValidationTest, AddressSpace_FunctionVariableI32) {
|
||||||
auto* var = Var("s", ty.i32(), ast::StorageClass::kPrivate);
|
auto* var = Var("s", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
Func("func", utils::Empty, ty.void_(),
|
Func("func", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -324,31 +324,31 @@ TEST_F(ResolverValidationTest, StorageClass_FunctionVariableI32) {
|
|||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: function-scope 'var' declaration must use 'function' storage class");
|
"error: function-scope 'var' declaration must use 'function' address space");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
|
TEST_F(ResolverValidationTest, AddressSpace_SamplerExplicitAddressSpace) {
|
||||||
auto* t = ty.sampler(ast::SamplerKind::kSampler);
|
auto* t = ty.sampler(ast::SamplerKind::kSampler);
|
||||||
GlobalVar(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle, Binding(0_a), Group(0_a));
|
GlobalVar(Source{{12, 34}}, "var", t, ast::AddressSpace::kHandle, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: variables of type 'sampler' must not have a storage class)");
|
R"(12:34 error: variables of type 'sampler' must not have a address space)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
|
TEST_F(ResolverValidationTest, AddressSpace_TextureExplicitAddressSpace) {
|
||||||
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||||
GlobalVar(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle, Binding(0_a), Group(0_a));
|
GlobalVar(Source{{12, 34}}, "var", t, ast::AddressSpace::kHandle, Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
R"(12:34 error: variables of type 'texture_1d<f32>' must not have a storage class)");
|
R"(12:34 error: variables of type 'texture_1d<f32>' must not have a address space)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
|
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
|
||||||
GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
|
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
|
||||||
|
|
||||||
@ -360,7 +360,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
|
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
|
||||||
GlobalVar("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec4<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
|
auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
|
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
|
||||||
GlobalVar("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec3<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
|
auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
|
||||||
auto* mem = MemberAccessor("my_vec", ident);
|
auto* mem = MemberAccessor("my_vec", ident);
|
||||||
@ -384,7 +384,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
|
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
|
||||||
GlobalVar("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
|
GlobalVar("my_vec", ty.vec2<f32>(), ast::AddressSpace::kPrivate);
|
||||||
|
|
||||||
auto* ident = Expr(Source{{3, 3}}, "z");
|
auto* ident = Expr(Source{{3, 3}}, "z");
|
||||||
auto* mem = MemberAccessor("my_vec", ident);
|
auto* mem = MemberAccessor("my_vec", ident);
|
||||||
@ -417,7 +417,7 @@ TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
|
|||||||
// let x: f32 = (*p).z;
|
// let x: f32 = (*p).z;
|
||||||
// return x;
|
// return x;
|
||||||
// }
|
// }
|
||||||
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
|
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
|
||||||
auto* star_p = Deref(p);
|
auto* star_p = Deref(p);
|
||||||
auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
|
auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
|
||||||
auto* accessor_expr = MemberAccessor(star_p, z);
|
auto* accessor_expr = MemberAccessor(star_p, z);
|
||||||
@ -435,7 +435,7 @@ TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncBadParent) {
|
|||||||
// let x: f32 = *p.z;
|
// let x: f32 = *p.z;
|
||||||
// return x;
|
// return x;
|
||||||
// }
|
// }
|
||||||
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
|
auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::AddressSpace::kFunction));
|
||||||
auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
|
auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
|
||||||
auto* accessor_expr = MemberAccessor(p, z);
|
auto* accessor_expr = MemberAccessor(p, z);
|
||||||
auto* star_p = Deref(accessor_expr);
|
auto* star_p = Deref(accessor_expr);
|
||||||
@ -1312,8 +1312,8 @@ TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) {
|
|||||||
TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
|
TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
|
||||||
auto* vf = Var("vf", ty.f32());
|
auto* vf = Var("vf", ty.f32());
|
||||||
auto* c =
|
auto* c =
|
||||||
Construct(Source{{12, 34}}, ty.pointer<i32>(ast::StorageClass::kFunction), ExprList(vf));
|
Construct(Source{{12, 34}}, ty.pointer<i32>(ast::AddressSpace::kFunction), ExprList(vf));
|
||||||
auto* ip = Let("ip", ty.pointer<i32>(ast::StorageClass::kFunction), c);
|
auto* ip = Let("ip", ty.pointer<i32>(ast::AddressSpace::kFunction), c);
|
||||||
WrapInFunction(Decl(vf), Decl(ip));
|
WrapInFunction(Decl(vf), Decl(ip));
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -322,7 +322,7 @@ bool Validator::Materialize(const sem::Type* to,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Validator::VariableInitializer(const ast::Variable* v,
|
bool Validator::VariableInitializer(const ast::Variable* v,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
const sem::Type* storage_ty,
|
const sem::Type* storage_ty,
|
||||||
const sem::Expression* initializer) const {
|
const sem::Expression* initializer) const {
|
||||||
auto* initializer_ty = initializer->Type();
|
auto* initializer_ty = initializer->Type();
|
||||||
@ -338,17 +338,17 @@ bool Validator::VariableInitializer(const ast::Variable* v,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (v->Is<ast::Var>()) {
|
if (v->Is<ast::Var>()) {
|
||||||
switch (storage_class) {
|
switch (address_space) {
|
||||||
case ast::StorageClass::kPrivate:
|
case ast::AddressSpace::kPrivate:
|
||||||
case ast::StorageClass::kFunction:
|
case ast::AddressSpace::kFunction:
|
||||||
break; // Allowed an initializer
|
break; // Allowed an initializer
|
||||||
default:
|
default:
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
|
// https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
|
||||||
// Optionally has an initializer expression, if the variable is in the
|
// Optionally has an initializer expression, if the variable is in the
|
||||||
// private or function storage classes.
|
// private or function address spacees.
|
||||||
AddError("var of storage class '" + utils::ToString(storage_class) +
|
AddError("var of address space '" + utils::ToString(address_space) +
|
||||||
"' cannot have an initializer. var initializers are only "
|
"' cannot have an initializer. var initializers are only "
|
||||||
"supported for the storage classes "
|
"supported for the address spacees "
|
||||||
"'private' and 'function'",
|
"'private' and 'function'",
|
||||||
v->source);
|
v->source);
|
||||||
return false;
|
return false;
|
||||||
@ -358,18 +358,19 @@ bool Validator::VariableInitializer(const ast::Variable* v,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
bool Validator::AddressSpaceLayout(const sem::Type* store_ty,
|
||||||
ast::StorageClass sc,
|
ast::AddressSpace address_space,
|
||||||
Source source,
|
Source source,
|
||||||
ValidTypeStorageLayouts& layouts) const {
|
ValidTypeStorageLayouts& layouts) const {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
|
||||||
|
|
||||||
auto is_uniform_struct_or_array = [sc](const sem::Type* ty) {
|
auto is_uniform_struct_or_array = [address_space](const sem::Type* ty) {
|
||||||
return sc == ast::StorageClass::kUniform && ty->IsAnyOf<sem::Array, sem::Struct>();
|
return address_space == ast::AddressSpace::kUniform &&
|
||||||
|
ty->IsAnyOf<sem::Array, sem::Struct>();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto is_uniform_struct = [sc](const sem::Type* ty) {
|
auto is_uniform_struct = [address_space](const sem::Type* ty) {
|
||||||
return sc == ast::StorageClass::kUniform && ty->Is<sem::Struct>();
|
return address_space == ast::AddressSpace::kUniform && ty->Is<sem::Struct>();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto required_alignment_of = [&](const sem::Type* ty) {
|
auto required_alignment_of = [&](const sem::Type* ty) {
|
||||||
@ -385,22 +386,22 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
|||||||
return symbols_.NameFor(sm->Declaration()->symbol);
|
return symbols_.NameFor(sm->Declaration()->symbol);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cache result of type + storage class pair.
|
// Cache result of type + address space pair.
|
||||||
if (!layouts.emplace(store_ty, sc).second) {
|
if (!layouts.emplace(store_ty, address_space).second) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ast::IsHostShareable(sc)) {
|
if (!ast::IsHostShareable(address_space)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporally forbid using f16 types in "uniform" and "storage" storage class.
|
// Temporally forbid using f16 types in "uniform" and "storage" address space.
|
||||||
// TODO(tint:1473, tint:1502): Remove this error after f16 is supported in "uniform" and
|
// TODO(tint:1473, tint:1502): Remove this error after f16 is supported in "uniform" and
|
||||||
// "storage" storage class but keep for "push_constant" storage class.
|
// "storage" address space but keep for "push_constant" address space.
|
||||||
if (Is<sem::F16>(sem::Type::DeepestElementOf(store_ty))) {
|
if (Is<sem::F16>(sem::Type::DeepestElementOf(store_ty))) {
|
||||||
AddError(
|
AddError("using f16 types in '" + utils::ToString(address_space) +
|
||||||
"using f16 types in '" + utils::ToString(sc) + "' storage class is not implemented yet",
|
"' address space is not implemented yet",
|
||||||
source);
|
source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +411,8 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
|||||||
uint32_t required_align = required_alignment_of(m->Type());
|
uint32_t required_align = required_alignment_of(m->Type());
|
||||||
|
|
||||||
// Recurse into the member type.
|
// Recurse into the member type.
|
||||||
if (!StorageClassLayout(m->Type(), sc, m->Declaration()->type->source, layouts)) {
|
if (!AddressSpaceLayout(m->Type(), address_space, m->Declaration()->type->source,
|
||||||
|
layouts)) {
|
||||||
AddNote("see layout of struct:\n" + str->Layout(symbols_),
|
AddNote("see layout of struct:\n" + str->Layout(symbols_),
|
||||||
str->Declaration()->source);
|
str->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
@ -420,7 +422,7 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
|||||||
if (m->Offset() % required_align != 0) {
|
if (m->Offset() % required_align != 0) {
|
||||||
AddError("the offset of a struct member of type '" +
|
AddError("the offset of a struct member of type '" +
|
||||||
m->Type()->UnwrapRef()->FriendlyName(symbols_) +
|
m->Type()->UnwrapRef()->FriendlyName(symbols_) +
|
||||||
"' in storage class '" + utils::ToString(sc) +
|
"' in address space '" + utils::ToString(address_space) +
|
||||||
"' must be a multiple of " + std::to_string(required_align) +
|
"' must be a multiple of " + std::to_string(required_align) +
|
||||||
" bytes, but '" + member_name_of(m) + "' is currently at offset " +
|
" bytes, but '" + member_name_of(m) + "' is currently at offset " +
|
||||||
std::to_string(m->Offset()) + ". Consider setting @align(" +
|
std::to_string(m->Offset()) + ". Consider setting @align(" +
|
||||||
@ -474,11 +476,11 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
|||||||
// TODO(crbug.com/tint/1388): Ideally we'd pass the source for nested
|
// TODO(crbug.com/tint/1388): Ideally we'd pass the source for nested
|
||||||
// element type here, but we can't easily get that from the semantic node.
|
// element type here, but we can't easily get that from the semantic node.
|
||||||
// We should consider recursing through the AST type nodes instead.
|
// We should consider recursing through the AST type nodes instead.
|
||||||
if (!StorageClassLayout(arr->ElemType(), sc, source, layouts)) {
|
if (!AddressSpaceLayout(arr->ElemType(), address_space, source, layouts)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc == ast::StorageClass::kUniform) {
|
if (address_space == ast::AddressSpace::kUniform) {
|
||||||
// We already validated that this array member is itself aligned to 16
|
// We already validated that this array member is itself aligned to 16
|
||||||
// bytes above, so we only need to validate that stride is a multiple
|
// bytes above, so we only need to validate that stride is a multiple
|
||||||
// of 16 bytes.
|
// of 16 bytes.
|
||||||
@ -516,22 +518,22 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Validator::StorageClassLayout(const sem::Variable* var,
|
bool Validator::AddressSpaceLayout(const sem::Variable* var,
|
||||||
const ast::Extensions& enabled_extensions,
|
const ast::Extensions& enabled_extensions,
|
||||||
ValidTypeStorageLayouts& layouts) const {
|
ValidTypeStorageLayouts& layouts) const {
|
||||||
if (var->StorageClass() == ast::StorageClass::kPushConstant &&
|
if (var->AddressSpace() == ast::AddressSpace::kPushConstant &&
|
||||||
!enabled_extensions.Contains(ast::Extension::kChromiumExperimentalPushConstant) &&
|
!enabled_extensions.Contains(ast::Extension::kChromiumExperimentalPushConstant) &&
|
||||||
IsValidationEnabled(var->Declaration()->attributes,
|
IsValidationEnabled(var->Declaration()->attributes,
|
||||||
ast::DisabledValidation::kIgnoreStorageClass)) {
|
ast::DisabledValidation::kIgnoreAddressSpace)) {
|
||||||
AddError(
|
AddError(
|
||||||
"use of variable storage class 'push_constant' requires enabling extension "
|
"use of variable address space 'push_constant' requires enabling extension "
|
||||||
"'chromium_experimental_push_constant'",
|
"'chromium_experimental_push_constant'",
|
||||||
var->Declaration()->source);
|
var->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* str = var->Type()->UnwrapRef()->As<sem::Struct>()) {
|
if (auto* str = var->Type()->UnwrapRef()->As<sem::Struct>()) {
|
||||||
if (!StorageClassLayout(str, var->StorageClass(), str->Declaration()->source, layouts)) {
|
if (!AddressSpaceLayout(str, var->AddressSpace(), str->Declaration()->source, layouts)) {
|
||||||
AddNote("see declaration of variable", var->Declaration()->source);
|
AddNote("see declaration of variable", var->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -540,7 +542,7 @@ bool Validator::StorageClassLayout(const sem::Variable* var,
|
|||||||
if (var->Declaration()->type) {
|
if (var->Declaration()->type) {
|
||||||
source = var->Declaration()->type->source;
|
source = var->Declaration()->type->source;
|
||||||
}
|
}
|
||||||
if (!StorageClassLayout(var->Type()->UnwrapRef(), var->StorageClass(), source, layouts)) {
|
if (!AddressSpaceLayout(var->Type()->UnwrapRef(), var->AddressSpace(), source, layouts)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -559,7 +561,7 @@ bool Validator::LocalVariable(const sem::Variable* local) const {
|
|||||||
decl, //
|
decl, //
|
||||||
[&](const ast::Var* var) {
|
[&](const ast::Var* var) {
|
||||||
if (IsValidationEnabled(var->attributes,
|
if (IsValidationEnabled(var->attributes,
|
||||||
ast::DisabledValidation::kIgnoreStorageClass)) {
|
ast::DisabledValidation::kIgnoreAddressSpace)) {
|
||||||
if (!local->Type()->UnwrapRef()->IsConstructible()) {
|
if (!local->Type()->UnwrapRef()->IsConstructible()) {
|
||||||
AddError("function-scope 'var' must have a constructible type",
|
AddError("function-scope 'var' must have a constructible type",
|
||||||
var->type ? var->type->source : var->source);
|
var->type ? var->type->source : var->source);
|
||||||
@ -583,7 +585,7 @@ bool Validator::GlobalVariable(
|
|||||||
const std::unordered_map<OverrideId, const sem::Variable*>& override_ids,
|
const std::unordered_map<OverrideId, const sem::Variable*>& override_ids,
|
||||||
const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const {
|
const std::unordered_map<const sem::Type*, const Source&>& atomic_composite_info) const {
|
||||||
auto* decl = global->Declaration();
|
auto* decl = global->Declaration();
|
||||||
if (global->StorageClass() != ast::StorageClass::kWorkgroup &&
|
if (global->AddressSpace() != ast::AddressSpace::kWorkgroup &&
|
||||||
IsArrayWithOverrideCount(global->Type())) {
|
IsArrayWithOverrideCount(global->Type())) {
|
||||||
RaiseArrayWithOverrideCountError(decl->type ? decl->type->source
|
RaiseArrayWithOverrideCountError(decl->type ? decl->type->source
|
||||||
: decl->constructor->source);
|
: decl->constructor->source);
|
||||||
@ -599,8 +601,8 @@ bool Validator::GlobalVariable(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global->StorageClass() == ast::StorageClass::kNone) {
|
if (global->AddressSpace() == ast::AddressSpace::kNone) {
|
||||||
AddError("module-scope 'var' declaration must have a storage class", decl->source);
|
AddError("module-scope 'var' declaration must have a address space", decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,11 +610,11 @@ bool Validator::GlobalVariable(
|
|||||||
bool is_shader_io_attribute =
|
bool is_shader_io_attribute =
|
||||||
attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
|
attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
|
||||||
ast::InvariantAttribute, ast::LocationAttribute>();
|
ast::InvariantAttribute, ast::LocationAttribute>();
|
||||||
bool has_io_storage_class = global->StorageClass() == ast::StorageClass::kIn ||
|
bool has_io_address_space = global->AddressSpace() == ast::AddressSpace::kIn ||
|
||||||
global->StorageClass() == ast::StorageClass::kOut;
|
global->AddressSpace() == ast::AddressSpace::kOut;
|
||||||
if (!attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
|
if (!attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
|
||||||
ast::InternalAttribute>() &&
|
ast::InternalAttribute>() &&
|
||||||
(!is_shader_io_attribute || !has_io_storage_class)) {
|
(!is_shader_io_attribute || !has_io_address_space)) {
|
||||||
AddError("attribute '" + attr->Name() + "' is not valid for module-scope 'var'",
|
AddError("attribute '" + attr->Name() + "' is not valid for module-scope 'var'",
|
||||||
attr->source);
|
attr->source);
|
||||||
return false;
|
return false;
|
||||||
@ -621,9 +623,9 @@ bool Validator::GlobalVariable(
|
|||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
|
// https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
|
||||||
// The access mode always has a default, and except for variables in the
|
// The access mode always has a default, and except for variables in the
|
||||||
// storage storage class, must not be written.
|
// storage address space, must not be written.
|
||||||
if (var->declared_access != ast::Access::kUndefined) {
|
if (var->declared_access != ast::Access::kUndefined) {
|
||||||
if (global->StorageClass() == ast::StorageClass::kStorage) {
|
if (global->AddressSpace() == ast::AddressSpace::kStorage) {
|
||||||
// The access mode for the storage address space can only be 'read' or
|
// The access mode for the storage address space can only be 'read' or
|
||||||
// 'read_write'.
|
// 'read_write'.
|
||||||
if (var->declared_access == ast::Access::kWrite) {
|
if (var->declared_access == ast::Access::kWrite) {
|
||||||
@ -632,7 +634,7 @@ bool Validator::GlobalVariable(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AddError("only variables in <storage> storage class may declare an access mode",
|
AddError("only variables in <storage> address space may declare an access mode",
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -672,15 +674,15 @@ bool Validator::GlobalVariable(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global->StorageClass() == ast::StorageClass::kFunction) {
|
if (global->AddressSpace() == ast::AddressSpace::kFunction) {
|
||||||
AddError("module-scope 'var' must not use storage class 'function'", decl->source);
|
AddError("module-scope 'var' must not use address space 'function'", decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (global->StorageClass()) {
|
switch (global->AddressSpace()) {
|
||||||
case ast::StorageClass::kUniform:
|
case ast::AddressSpace::kUniform:
|
||||||
case ast::StorageClass::kStorage:
|
case ast::AddressSpace::kStorage:
|
||||||
case ast::StorageClass::kHandle: {
|
case ast::AddressSpace::kHandle: {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
|
// https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
|
||||||
// Each resource variable must be declared with both group and binding
|
// Each resource variable must be declared with both group and binding
|
||||||
// attributes.
|
// attributes.
|
||||||
@ -712,29 +714,32 @@ bool Validator::GlobalVariable(
|
|||||||
bool Validator::AtomicVariable(
|
bool Validator::AtomicVariable(
|
||||||
const sem::Variable* var,
|
const sem::Variable* var,
|
||||||
std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const {
|
std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const {
|
||||||
auto sc = var->StorageClass();
|
auto address_space = var->AddressSpace();
|
||||||
auto* decl = var->Declaration();
|
auto* decl = var->Declaration();
|
||||||
auto access = var->Access();
|
auto access = var->Access();
|
||||||
auto* type = var->Type()->UnwrapRef();
|
auto* type = var->Type()->UnwrapRef();
|
||||||
auto source = decl->type ? decl->type->source : decl->source;
|
auto source = decl->type ? decl->type->source : decl->source;
|
||||||
|
|
||||||
if (type->Is<sem::Atomic>()) {
|
if (type->Is<sem::Atomic>()) {
|
||||||
if (sc != ast::StorageClass::kWorkgroup && sc != ast::StorageClass::kStorage) {
|
if (address_space != ast::AddressSpace::kWorkgroup &&
|
||||||
AddError("atomic variables must have <storage> or <workgroup> storage class", source);
|
address_space != ast::AddressSpace::kStorage) {
|
||||||
|
AddError("atomic variables must have <storage> or <workgroup> address space", source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (type->IsAnyOf<sem::Struct, sem::Array>()) {
|
} else if (type->IsAnyOf<sem::Struct, sem::Array>()) {
|
||||||
auto found = atomic_composite_info.find(type);
|
auto found = atomic_composite_info.find(type);
|
||||||
if (found != atomic_composite_info.end()) {
|
if (found != atomic_composite_info.end()) {
|
||||||
if (sc != ast::StorageClass::kStorage && sc != ast::StorageClass::kWorkgroup) {
|
if (address_space != ast::AddressSpace::kStorage &&
|
||||||
AddError("atomic variables must have <storage> or <workgroup> storage class",
|
address_space != ast::AddressSpace::kWorkgroup) {
|
||||||
|
AddError("atomic variables must have <storage> or <workgroup> address space",
|
||||||
source);
|
source);
|
||||||
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
|
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
|
||||||
found->second);
|
found->second);
|
||||||
return false;
|
return false;
|
||||||
} else if (sc == ast::StorageClass::kStorage && access != ast::Access::kReadWrite) {
|
} else if (address_space == ast::AddressSpace::kStorage &&
|
||||||
|
access != ast::Access::kReadWrite) {
|
||||||
AddError(
|
AddError(
|
||||||
"atomic variables in <storage> storage class must have read_write "
|
"atomic variables in <storage> address space must have read_write "
|
||||||
"access mode",
|
"access mode",
|
||||||
source);
|
source);
|
||||||
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
|
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
|
||||||
@ -756,21 +761,21 @@ bool Validator::Var(const sem::Variable* v) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage_ty->is_handle() && var->declared_storage_class != ast::StorageClass::kNone) {
|
if (storage_ty->is_handle() && var->declared_address_space != ast::AddressSpace::kNone) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
||||||
// If the store type is a texture type or a sampler type, then the
|
// If the store type is a texture type or a sampler type, then the
|
||||||
// variable declaration must not have a storage class attribute. The
|
// variable declaration must not have a address space attribute. The
|
||||||
// storage class will always be handle.
|
// address space will always be handle.
|
||||||
AddError(
|
AddError(
|
||||||
"variables of type '" + sem_.TypeNameOf(storage_ty) + "' must not have a storage class",
|
"variables of type '" + sem_.TypeNameOf(storage_ty) + "' must not have a address space",
|
||||||
var->source);
|
var->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidationEnabled(var->attributes, ast::DisabledValidation::kIgnoreStorageClass) &&
|
if (IsValidationEnabled(var->attributes, ast::DisabledValidation::kIgnoreAddressSpace) &&
|
||||||
(var->declared_storage_class == ast::StorageClass::kIn ||
|
(var->declared_address_space == ast::AddressSpace::kIn ||
|
||||||
var->declared_storage_class == ast::StorageClass::kOut)) {
|
var->declared_address_space == ast::AddressSpace::kOut)) {
|
||||||
AddError("invalid use of input/output storage class", var->source);
|
AddError("invalid use of input/output address space", var->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -873,12 +878,14 @@ bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto* ref = var->Type()->As<sem::Pointer>()) {
|
if (auto* ref = var->Type()->As<sem::Pointer>()) {
|
||||||
auto sc = ref->StorageClass();
|
auto address_space = ref->AddressSpace();
|
||||||
if (!(sc == ast::StorageClass::kFunction || sc == ast::StorageClass::kPrivate ||
|
if (!(address_space == ast::AddressSpace::kFunction ||
|
||||||
sc == ast::StorageClass::kWorkgroup) &&
|
address_space == ast::AddressSpace::kPrivate ||
|
||||||
IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass)) {
|
address_space == ast::AddressSpace::kWorkgroup) &&
|
||||||
|
IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreAddressSpace)) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "function parameter of pointer type cannot be in '" << sc << "' storage class";
|
ss << "function parameter of pointer type cannot be in '" << address_space
|
||||||
|
<< "' address space";
|
||||||
AddError(ss.str(), decl->source);
|
AddError(ss.str(), decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1954,7 +1961,7 @@ bool Validator::PipelineStages(const std::vector<sem::Function*>& entry_points)
|
|||||||
auto stage = entry_point->Declaration()->PipelineStage();
|
auto stage = entry_point->Declaration()->PipelineStage();
|
||||||
if (stage != ast::PipelineStage::kCompute) {
|
if (stage != ast::PipelineStage::kCompute) {
|
||||||
for (auto* var : func->DirectlyReferencedGlobals()) {
|
for (auto* var : func->DirectlyReferencedGlobals()) {
|
||||||
if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
|
if (var->AddressSpace() == ast::AddressSpace::kWorkgroup) {
|
||||||
std::stringstream stage_name;
|
std::stringstream stage_name;
|
||||||
stage_name << stage;
|
stage_name << stage;
|
||||||
for (auto* user : var->Users()) {
|
for (auto* user : var->Users()) {
|
||||||
@ -2042,7 +2049,7 @@ bool Validator::PushConstants(const std::vector<sem::Function*>& entry_points) c
|
|||||||
|
|
||||||
auto check_push_constant = [&](const sem::Function* func, const sem::Function* ep) {
|
auto check_push_constant = [&](const sem::Function* func, const sem::Function* ep) {
|
||||||
for (auto* var : func->DirectlyReferencedGlobals()) {
|
for (auto* var : func->DirectlyReferencedGlobals()) {
|
||||||
if (var->StorageClass() != ast::StorageClass::kPushConstant ||
|
if (var->AddressSpace() != ast::AddressSpace::kPushConstant ||
|
||||||
var == push_constant_var) {
|
var == push_constant_var) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ namespace tint::resolver {
|
|||||||
class Validator {
|
class Validator {
|
||||||
public:
|
public:
|
||||||
/// The valid type storage layouts typedef
|
/// The valid type storage layouts typedef
|
||||||
using ValidTypeStorageLayouts = std::set<std::pair<const sem::Type*, ast::StorageClass>>;
|
using ValidTypeStorageLayouts = std::set<std::pair<const sem::Type*, ast::AddressSpace>>;
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param builder the program builder
|
/// @param builder the program builder
|
||||||
@ -389,12 +389,12 @@ class Validator {
|
|||||||
|
|
||||||
/// Validates a variable initializer
|
/// Validates a variable initializer
|
||||||
/// @param v the variable to validate
|
/// @param v the variable to validate
|
||||||
/// @param storage_class the storage class of the variable
|
/// @param address_space the address space of the variable
|
||||||
/// @param storage_type the type of the storage
|
/// @param storage_type the type of the storage
|
||||||
/// @param initializer the RHS initializer expression
|
/// @param initializer the RHS initializer expression
|
||||||
/// @returns true on succes, false otherwise
|
/// @returns true on succes, false otherwise
|
||||||
bool VariableInitializer(const ast::Variable* v,
|
bool VariableInitializer(const ast::Variable* v,
|
||||||
ast::StorageClass storage_class,
|
ast::AddressSpace address_space,
|
||||||
const sem::Type* storage_type,
|
const sem::Type* storage_type,
|
||||||
const sem::Expression* initializer) const;
|
const sem::Expression* initializer) const;
|
||||||
|
|
||||||
@ -427,23 +427,23 @@ class Validator {
|
|||||||
/// @returns true on success, false otherwise.
|
/// @returns true on success, false otherwise.
|
||||||
bool NoDuplicateAttributes(utils::VectorRef<const ast::Attribute*> attributes) const;
|
bool NoDuplicateAttributes(utils::VectorRef<const ast::Attribute*> attributes) const;
|
||||||
|
|
||||||
/// Validates a storage class layout
|
/// Validates a address space layout
|
||||||
/// @param type the type to validate
|
/// @param type the type to validate
|
||||||
/// @param sc the storage class
|
/// @param sc the address space
|
||||||
/// @param source the source of the type
|
/// @param source the source of the type
|
||||||
/// @param layouts previously validated storage layouts
|
/// @param layouts previously validated storage layouts
|
||||||
/// @returns true on success, false otherwise
|
/// @returns true on success, false otherwise
|
||||||
bool StorageClassLayout(const sem::Type* type,
|
bool AddressSpaceLayout(const sem::Type* type,
|
||||||
ast::StorageClass sc,
|
ast::AddressSpace sc,
|
||||||
Source source,
|
Source source,
|
||||||
ValidTypeStorageLayouts& layouts) const;
|
ValidTypeStorageLayouts& layouts) const;
|
||||||
|
|
||||||
/// Validates a storage class layout
|
/// Validates a address space layout
|
||||||
/// @param var the variable to validate
|
/// @param var the variable to validate
|
||||||
/// @param layouts previously validated storage layouts
|
/// @param layouts previously validated storage layouts
|
||||||
/// @param enabled_extensions all the extensions declared in current module
|
/// @param enabled_extensions all the extensions declared in current module
|
||||||
/// @returns true on success, false otherwise.
|
/// @returns true on success, false otherwise.
|
||||||
bool StorageClassLayout(const sem::Variable* var,
|
bool AddressSpaceLayout(const sem::Variable* var,
|
||||||
const ast::Extensions& enabled_extensions,
|
const ast::Extensions& enabled_extensions,
|
||||||
ValidTypeStorageLayouts& layouts) const;
|
ValidTypeStorageLayouts& layouts) const;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ TEST_F(ValidatorIsStorableTest, Matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidatorIsStorableTest, Pointer) {
|
TEST_F(ValidatorIsStorableTest, Pointer) {
|
||||||
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
|
auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::AddressSpace::kPrivate,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
EXPECT_FALSE(v()->IsStorable(ptr));
|
EXPECT_FALSE(v()->IsStorable(ptr));
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalVar) {
|
|||||||
// var a = a;
|
// var a = a;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
|
auto* g = GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* v = Var("a", Expr("a"));
|
auto* v = Var("a", Expr("a"));
|
||||||
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
|
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(v)});
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ TEST_F(ResolverVariableTest, LocalLet) {
|
|||||||
auto* b = Let("b", ty.bool_(), b_c);
|
auto* b = Let("b", ty.bool_(), b_c);
|
||||||
auto* s = Let("s", ty.Of(S), s_c);
|
auto* s = Let("s", ty.Of(S), s_c);
|
||||||
auto* a = Let("a", ty.Of(A), a_c);
|
auto* a = Let("a", ty.Of(A), a_c);
|
||||||
auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
|
auto* p = Let("p", ty.pointer<i32>(ast::AddressSpace::kFunction), p_c);
|
||||||
|
|
||||||
Func("F", utils::Empty, ty.void_(),
|
Func("F", utils::Empty, ty.void_(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
@ -470,7 +470,7 @@ TEST_F(ResolverVariableTest, LocalLet_InheritsAccessFromOriginatingVariable) {
|
|||||||
// }
|
// }
|
||||||
auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
|
auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
|
||||||
auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
|
auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
|
||||||
auto* storage = GlobalVar("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
auto* storage = GlobalVar("s", ty.Of(buf), ast::AddressSpace::kStorage, ast::Access::kReadWrite,
|
||||||
Binding(0_a), Group(0_a));
|
Binding(0_a), Group(0_a));
|
||||||
|
|
||||||
auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 3_i);
|
auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 3_i);
|
||||||
@ -552,7 +552,7 @@ TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalVar) {
|
|||||||
// let a = a;
|
// let a = a;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
|
auto* g = GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* l = Let("a", Expr("a"));
|
auto* l = Let("a", Expr("a"));
|
||||||
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
|
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(l)});
|
||||||
|
|
||||||
@ -762,7 +762,7 @@ TEST_F(ResolverVariableTest, LocalConst_ShadowsGlobalVar) {
|
|||||||
// const a = 1i;
|
// const a = 1i;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
|
auto* g = GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* c = Const("a", Expr(1_i));
|
auto* c = Const("a", Expr(1_i));
|
||||||
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
|
Func("F", utils::Empty, ty.void_(), utils::Vector{Decl(c)});
|
||||||
|
|
||||||
@ -1030,16 +1030,16 @@ TEST_F(ResolverVariableTest, DISABLED_LocalConst_ConstEval) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Module-scope 'var'
|
// Module-scope 'var'
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
TEST_F(ResolverVariableTest, GlobalVar_StorageClass) {
|
TEST_F(ResolverVariableTest, GlobalVar_AddressSpace) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
||||||
|
|
||||||
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
||||||
auto* private_ = GlobalVar("p", ty.i32(), ast::StorageClass::kPrivate);
|
auto* private_ = GlobalVar("p", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* workgroup = GlobalVar("w", ty.i32(), ast::StorageClass::kWorkgroup);
|
auto* workgroup = GlobalVar("w", ty.i32(), ast::AddressSpace::kWorkgroup);
|
||||||
auto* uniform =
|
auto* uniform =
|
||||||
GlobalVar("ub", ty.Of(buf), ast::StorageClass::kUniform, Binding(0_a), Group(0_a));
|
GlobalVar("ub", ty.Of(buf), ast::AddressSpace::kUniform, Binding(0_a), Group(0_a));
|
||||||
auto* storage =
|
auto* storage =
|
||||||
GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage, Binding(1_a), Group(0_a));
|
GlobalVar("sb", ty.Of(buf), ast::AddressSpace::kStorage, Binding(1_a), Group(0_a));
|
||||||
auto* handle =
|
auto* handle =
|
||||||
GlobalVar("h", ty.depth_texture(ast::TextureDimension::k2d), Binding(2_a), Group(0_a));
|
GlobalVar("h", ty.depth_texture(ast::TextureDimension::k2d), Binding(2_a), Group(0_a));
|
||||||
|
|
||||||
@ -1058,11 +1058,11 @@ TEST_F(ResolverVariableTest, GlobalVar_StorageClass) {
|
|||||||
EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
|
EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverVariableTest, GlobalVar_ExplicitStorageClass) {
|
TEST_F(ResolverVariableTest, GlobalVar_ExplicitAddressSpace) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
|
||||||
|
|
||||||
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
auto* buf = Structure("S", utils::Vector{Member("m", ty.i32())});
|
||||||
auto* storage = GlobalVar("sb", ty.Of(buf), ast::StorageClass::kStorage,
|
auto* storage = GlobalVar("sb", ty.Of(buf), ast::AddressSpace::kStorage,
|
||||||
ast::Access::kReadWrite, Binding(1_a), Group(0_a));
|
ast::Access::kReadWrite, Binding(1_a), Group(0_a));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
@ -1220,7 +1220,7 @@ TEST_F(ResolverVariableTest, Param_ShadowsGlobalVar) {
|
|||||||
// fn F(a : bool) {
|
// fn F(a : bool) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto* g = GlobalVar("a", ty.i32(), ast::StorageClass::kPrivate);
|
auto* g = GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate);
|
||||||
auto* p = Param("a", ty.bool_());
|
auto* p = Param("a", ty.bool_());
|
||||||
Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
|
Func("F", utils::Vector{p}, ty.void_(), utils::Empty);
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user