Import Tint changes from Dawn
Changes:
- 4f3f45c00f414e6b57782126b4d98c8c44813d8f Tint/transform: Fix insertBits polyfill for HLSL by Zhaoming Jiang <zhaoming.jiang@intel.com>
- a70e365313d31757bc9b75002fa46b3366d551a8 tint: fix extractBits edge case by Antonio Maiorano <amaiorano@google.com>
- c36417343fe1c2a526dc83cc378d96a6db3ce5e5 tint: const eval of cross by Antonio Maiorano <amaiorano@google.com>
- eb949c87ee5aaa819faae6252dd36bfeda649070 spirv-reader: use spirv.hpp11 by David Neto <dneto@google.com>
- 1bdaded736d61e4bdbf18a90c8ebac9f3274cb2f Implemement const-eval for some unpack routines. by dan sinclair <dsinclair@chromium.org>
- ec4b650adb133672f48ed7d76c12459933cb229c Remove fallthrough from fuzzer AST mutation. by dan sinclair <dsinclair@chromium.org>
- ba200e87c5db20d67e3c0d51bfb4ddf3151766fc tint: Bump stack size for MSVC + debug build by Ben Clayton <bclayton@google.com>
- 5071a54af491e05444c02122b48e9cd5d65f82c7 Make reserved words an error. by dan sinclair <dsinclair@chromium.org>
- 2d706a04360dc35409a2df324b936f6735eb1cd8 Implemement const-eval for some pack routines. by dan sinclair <dsinclair@chromium.org>
- 3b2b5484e239fc558871c04eb061c201d0c15c36 Remove module-scope let deprecation. by dan sinclair <dsinclair@chromium.org>
- c027f33cfd88efd155e88623300dc3356fcd6b95 tint: Fix gdb and lldb pretty printers for recently updat... by Antonio Maiorano <amaiorano@google.com>
- ca98b1b1b9d797bf1fc65340036193a2e7a205b1 tint/resolver: Resolve dependencies of parameter attributes by Ben Clayton <bclayton@google.com>
- 6f799d676d8cdec69153cc6b5ca6003598baf19f Change default acos test value. by dan sinclair <dsinclair@chromium.org>
- f218af04610a66598d44ecbba6c2b17bb1e78433 Remove the `@stage` attribute by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: 4f3f45c00f414e6b57782126b4d98c8c44813d8f
Change-Id: Ica3b6cfbfc9b29a0d28600b6f3116001246ad3a2
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/109100
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 337b6a1..39fae60 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -581,8 +581,8 @@
"utils/enum_set.h",
"utils/foreach_macro.h",
"utils/hash.h",
- "utils/hashmap_base.h",
"utils/hashmap.h",
+ "utils/hashmap_base.h",
"utils/hashset.h",
"utils/map.h",
"utils/math.h",
@@ -1423,7 +1423,6 @@
"reader/wgsl/parser_impl_multiplicative_expression_test.cc",
"reader/wgsl/parser_impl_param_list_test.cc",
"reader/wgsl/parser_impl_paren_expression_test.cc",
- "reader/wgsl/parser_impl_pipeline_stage_test.cc",
"reader/wgsl/parser_impl_primary_expression_test.cc",
"reader/wgsl/parser_impl_relational_expression_test.cc",
"reader/wgsl/parser_impl_reserved_keyword_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index a22d9fc..1d39243 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -752,6 +752,7 @@
endif()
endif()
+
################################################################################
# Tests
################################################################################
@@ -1054,7 +1055,6 @@
reader/wgsl/parser_impl_multiplicative_expression_test.cc
reader/wgsl/parser_impl_param_list_test.cc
reader/wgsl/parser_impl_paren_expression_test.cc
- reader/wgsl/parser_impl_pipeline_stage_test.cc
reader/wgsl/parser_impl_primary_expression_test.cc
reader/wgsl/parser_impl_relational_expression_test.cc
reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -1352,7 +1352,16 @@
add_executable(tint_unittests ${TINT_TEST_SRCS})
set_target_properties(${target} PROPERTIES FOLDER "Tests")
- if(NOT MSVC)
+ if(MSVC)
+ # TODO(crbug.com/tint/1749): MSVC debug builds can suffer from stack
+ # overflows when resolving deeply nested expression chains or statements.
+ # Production builds neither use MSVC nor debug, so just bump the stack size
+ # for this build combination.
+ string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
+ if ((NOT ${build_type} STREQUAL "RELEASE") AND (NOT ${build_type} STREQUAL "RELWITHDEBINFO"))
+ target_link_options(tint_unittests PRIVATE "/STACK 2097152") # 2MB, default is 1MB
+ endif()
+ else()
target_compile_options(tint_unittests PRIVATE
-Wno-global-constructors
-Wno-weak-vtables
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
index 05435d0..1ec3ca4 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement.cc
@@ -19,7 +19,6 @@
#include <vector>
#include "src/tint/ast/block_statement.h"
-#include "src/tint/ast/fallthrough_statement.h"
#include "src/tint/ast/for_loop_statement.h"
#include "src/tint/ast/if_statement.h"
#include "src/tint/ast/loop_statement.h"
@@ -151,24 +150,9 @@
}
if (auto* case_statement = statement_node.As<ast::CaseStatement>()) {
- // It is not OK to delete the final case statement in a switch statement if the penultimate
- // case statement falls through to the final case statement.
- auto* switch_statement =
- program.Sem().Get(case_statement)->Parent()->Declaration()->As<ast::SwitchStatement>();
-
- if (switch_statement->body.Length() > 1 &&
- switch_statement->body[switch_statement->body.Length() - 1] == case_statement) {
- // There are at least two case statements, and this is the final case statement.
- auto& penultimate_case_statement_body_statements =
- switch_statement->body[switch_statement->body.Length() - 2]->body->statements;
- if (penultimate_case_statement_body_statements.Length() > 0 &&
- penultimate_case_statement_body_statements
- [penultimate_case_statement_body_statements.Length() - 1]
- ->Is<ast::FallthroughStatement>()) {
- // The penultimate case statement falls through to the final case statement, thus
- // the final case statement cannot be removed.
- return false;
- }
+ // It is not OK to delete the case statement which contains the default selector.
+ if (case_statement->ContainsDefault()) {
+ return false;
}
}
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
index 925ee80..275a19e 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/delete_statement_test.cc
@@ -22,7 +22,6 @@
#include "src/tint/ast/assignment_statement.h"
#include "src/tint/ast/block_statement.h"
#include "src/tint/ast/case_statement.h"
-#include "src/tint/ast/fallthrough_statement.h"
#include "src/tint/ast/for_loop_statement.h"
#include "src/tint/ast/if_statement.h"
#include "src/tint/ast/switch_statement.h"
@@ -151,10 +150,7 @@
switch(1) {
case 0, 1: {
}
- default: {
- fallthrough;
- }
- case 2: {
+ case 2, default: {
}
}
})";
@@ -171,20 +167,14 @@
switch(1) {
case 0, 1: {
}
- default: {
- fallthrough;
- }
- case 2: {
+ case 2, default: {
}
}
})";
auto expected = R"(
fn main() {
switch(1) {
- default: {
- fallthrough;
- }
- case 2: {
+ case 2, default: {
}
}
})";
@@ -199,43 +189,6 @@
CheckStatementDeletionWorks(original, expected, statement_finder);
}
-TEST(DeleteStatementTest, DeleteFallthroughStatement) {
- auto original = R"(
-fn main() {
- switch(1) {
- case 0, 1: {
- }
- default: {
- fallthrough;
- }
- case 2: {
- }
- }
-})";
- auto expected = R"(
-fn main() {
- switch(1) {
- case 0, 1: {
- }
- default: {
- }
- case 2: {
- }
- }
-})";
- auto statement_finder = [](const Program& program) -> const ast::Statement* {
- return program.AST()
- .Functions()[0]
- ->body->statements[0]
- ->As<ast::SwitchStatement>()
- ->body[1]
- ->As<ast::CaseStatement>()
- ->body->statements[0]
- ->As<ast::FallthroughStatement>();
- };
- CheckStatementDeletionWorks(original, expected, statement_finder);
-}
-
TEST(DeleteStatementTest, DeleteElse) {
auto original = R"(
fn main() {
@@ -570,14 +523,11 @@
CheckStatementDeletionNotAllowed(original, statement_finder);
}
-TEST(DeleteStatementTest, DoNotDeleteCaseDueToFallthrough) {
+TEST(DeleteStatementTest, DoNotDeleteCaseDueToDefault) {
auto original = R"(
fn main() {
switch(1) {
- default: {
- fallthrough;
- }
- case 2: {
+ case 2, default: {
}
}
})";
@@ -586,7 +536,7 @@
.Functions()[0]
->body->statements[0]
->As<ast::SwitchStatement>()
- ->body[1]
+ ->body[0]
->As<ast::CaseStatement>();
};
CheckStatementDeletionNotAllowed(original, statement_finder);
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
index ac5743e..8339ac0 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
@@ -386,7 +386,7 @@
}
var<private> a: S;
-let e = 3;
+const e = 3;
@group(1) @binding(1) var<uniform> b: S;
fn f() {
*&a = *&b;
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index f497405..96f6d08 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -406,8 +406,8 @@
// https://gpuweb.github.io/gpuweb/wgsl/#builtin-functions
@const fn abs<T: fia_fiu32_f16>(T) -> T
@const fn abs<N: num, T: fia_fiu32_f16>(vec<N, T>) -> vec<N, T>
-@const fn acos<T: fa_f32_f16>(@test_value(0.87758256189) T) -> T
-@const fn acos<N: num, T: fa_f32_f16>(@test_value(0.87758256189) vec<N, T>) -> vec<N, T>
+@const fn acos<T: fa_f32_f16>(@test_value(0.96891242171) T) -> T
+@const fn acos<N: num, T: fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T>
fn acosh<T: f32_f16>(T) -> T
fn acosh<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
@const fn all(bool) -> bool
@@ -439,7 +439,7 @@
@const fn countOneBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
@const fn countTrailingZeros<T: iu32>(T) -> T
@const fn countTrailingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
-fn cross<T: f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
+@const fn cross<T: fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
fn degrees<T: f32_f16>(T) -> T
fn degrees<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn determinant<N: num, T: f32_f16>(mat<N, N, T>) -> T
@@ -508,10 +508,10 @@
fn modf<N: num, T: f32_f16>(vec<N, T>) -> __modf_result_vec<N, T>
fn normalize<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn pack2x16float(vec2<f32>) -> u32
-fn pack2x16snorm(vec2<f32>) -> u32
-fn pack2x16unorm(vec2<f32>) -> u32
-fn pack4x8snorm(vec4<f32>) -> u32
-fn pack4x8unorm(vec4<f32>) -> u32
+@const fn pack2x16snorm(vec2<f32>) -> u32
+@const fn pack2x16unorm(vec2<f32>) -> u32
+@const fn pack4x8snorm(vec4<f32>) -> u32
+@const fn pack4x8unorm(vec4<f32>) -> u32
fn pow<T: f32_f16>(T, T) -> T
fn pow<N: num, T: f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
@const fn quantizeToF16(f32) -> f32
@@ -550,10 +550,10 @@
fn trunc<T: f32_f16>(T) -> T
fn trunc<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn unpack2x16float(u32) -> vec2<f32>
-fn unpack2x16snorm(u32) -> vec2<f32>
-fn unpack2x16unorm(u32) -> vec2<f32>
-fn unpack4x8snorm(u32) -> vec4<f32>
-fn unpack4x8unorm(u32) -> vec4<f32>
+@const fn unpack2x16snorm(u32) -> vec2<f32>
+@const fn unpack2x16unorm(u32) -> vec2<f32>
+@const fn unpack4x8snorm(u32) -> vec4<f32>
+@const fn unpack4x8unorm(u32) -> vec4<f32>
@stage("compute") fn workgroupBarrier()
fn textureDimensions<T: fiu32>(texture: texture_1d<T>) -> u32
diff --git a/src/tint/reader/spirv/enum_converter.cc b/src/tint/reader/spirv/enum_converter.cc
index 923f250..d590507 100644
--- a/src/tint/reader/spirv/enum_converter.cc
+++ b/src/tint/reader/spirv/enum_converter.cc
@@ -20,13 +20,13 @@
EnumConverter::~EnumConverter() = default;
-ast::PipelineStage EnumConverter::ToPipelineStage(SpvExecutionModel model) {
+ast::PipelineStage EnumConverter::ToPipelineStage(spv::ExecutionModel model) {
switch (model) {
- case SpvExecutionModelVertex:
+ case spv::ExecutionModel::Vertex:
return ast::PipelineStage::kVertex;
- case SpvExecutionModelFragment:
+ case spv::ExecutionModel::Fragment:
return ast::PipelineStage::kFragment;
- case SpvExecutionModelGLCompute:
+ case spv::ExecutionModel::GLCompute:
return ast::PipelineStage::kCompute;
default:
break;
@@ -36,23 +36,23 @@
return ast::PipelineStage::kNone;
}
-ast::AddressSpace EnumConverter::ToAddressSpace(const SpvStorageClass sc) {
+ast::AddressSpace EnumConverter::ToAddressSpace(const spv::StorageClass sc) {
switch (sc) {
- case SpvStorageClassInput:
+ case spv::StorageClass::Input:
return ast::AddressSpace::kIn;
- case SpvStorageClassOutput:
+ case spv::StorageClass::Output:
return ast::AddressSpace::kOut;
- case SpvStorageClassUniform:
+ case spv::StorageClass::Uniform:
return ast::AddressSpace::kUniform;
- case SpvStorageClassWorkgroup:
+ case spv::StorageClass::Workgroup:
return ast::AddressSpace::kWorkgroup;
- case SpvStorageClassUniformConstant:
+ case spv::StorageClass::UniformConstant:
return ast::AddressSpace::kNone;
- case SpvStorageClassStorageBuffer:
+ case spv::StorageClass::StorageBuffer:
return ast::AddressSpace::kStorage;
- case SpvStorageClassPrivate:
+ case spv::StorageClass::Private:
return ast::AddressSpace::kPrivate;
- case SpvStorageClassFunction:
+ case spv::StorageClass::Function:
return ast::AddressSpace::kFunction;
default:
break;
@@ -62,31 +62,31 @@
return ast::AddressSpace::kUndefined;
}
-ast::BuiltinValue EnumConverter::ToBuiltin(SpvBuiltIn b) {
+ast::BuiltinValue EnumConverter::ToBuiltin(spv::BuiltIn b) {
switch (b) {
- case SpvBuiltInPosition:
+ case spv::BuiltIn::Position:
return ast::BuiltinValue::kPosition;
- case SpvBuiltInVertexIndex:
+ case spv::BuiltIn::VertexIndex:
return ast::BuiltinValue::kVertexIndex;
- case SpvBuiltInInstanceIndex:
+ case spv::BuiltIn::InstanceIndex:
return ast::BuiltinValue::kInstanceIndex;
- case SpvBuiltInFrontFacing:
+ case spv::BuiltIn::FrontFacing:
return ast::BuiltinValue::kFrontFacing;
- case SpvBuiltInFragCoord:
+ case spv::BuiltIn::FragCoord:
return ast::BuiltinValue::kPosition;
- case SpvBuiltInFragDepth:
+ case spv::BuiltIn::FragDepth:
return ast::BuiltinValue::kFragDepth;
- case SpvBuiltInLocalInvocationId:
+ case spv::BuiltIn::LocalInvocationId:
return ast::BuiltinValue::kLocalInvocationId;
- case SpvBuiltInLocalInvocationIndex:
+ case spv::BuiltIn::LocalInvocationIndex:
return ast::BuiltinValue::kLocalInvocationIndex;
- case SpvBuiltInGlobalInvocationId:
+ case spv::BuiltIn::GlobalInvocationId:
return ast::BuiltinValue::kGlobalInvocationId;
- case SpvBuiltInWorkgroupId:
+ case spv::BuiltIn::WorkgroupId:
return ast::BuiltinValue::kWorkgroupId;
- case SpvBuiltInSampleId:
+ case spv::BuiltIn::SampleId:
return ast::BuiltinValue::kSampleIndex;
- case SpvBuiltInSampleMask:
+ case spv::BuiltIn::SampleMask:
return ast::BuiltinValue::kSampleMask;
default:
break;
@@ -96,12 +96,12 @@
return ast::BuiltinValue::kUndefined;
}
-ast::TextureDimension EnumConverter::ToDim(SpvDim dim, bool arrayed) {
+ast::TextureDimension EnumConverter::ToDim(spv::Dim dim, bool arrayed) {
if (arrayed) {
switch (dim) {
- case SpvDim2D:
+ case spv::Dim::Dim2D:
return ast::TextureDimension::k2dArray;
- case SpvDimCube:
+ case spv::Dim::Cube:
return ast::TextureDimension::kCubeArray;
default:
break;
@@ -111,13 +111,13 @@
}
// Assume non-arrayed
switch (dim) {
- case SpvDim1D:
+ case spv::Dim::Dim1D:
return ast::TextureDimension::k1d;
- case SpvDim2D:
+ case spv::Dim::Dim2D:
return ast::TextureDimension::k2d;
- case SpvDim3D:
+ case spv::Dim::Dim3D:
return ast::TextureDimension::k3d;
- case SpvDimCube:
+ case spv::Dim::Cube:
return ast::TextureDimension::kCube;
default:
break;
@@ -126,47 +126,47 @@
return ast::TextureDimension::kNone;
}
-ast::TexelFormat EnumConverter::ToTexelFormat(SpvImageFormat fmt) {
+ast::TexelFormat EnumConverter::ToTexelFormat(spv::ImageFormat fmt) {
switch (fmt) {
- case SpvImageFormatUnknown:
+ case spv::ImageFormat::Unknown:
return ast::TexelFormat::kUndefined;
// 8 bit channels
- case SpvImageFormatRgba8:
+ case spv::ImageFormat::Rgba8:
return ast::TexelFormat::kRgba8Unorm;
- case SpvImageFormatRgba8Snorm:
+ case spv::ImageFormat::Rgba8Snorm:
return ast::TexelFormat::kRgba8Snorm;
- case SpvImageFormatRgba8ui:
+ case spv::ImageFormat::Rgba8ui:
return ast::TexelFormat::kRgba8Uint;
- case SpvImageFormatRgba8i:
+ case spv::ImageFormat::Rgba8i:
return ast::TexelFormat::kRgba8Sint;
// 16 bit channels
- case SpvImageFormatRgba16ui:
+ case spv::ImageFormat::Rgba16ui:
return ast::TexelFormat::kRgba16Uint;
- case SpvImageFormatRgba16i:
+ case spv::ImageFormat::Rgba16i:
return ast::TexelFormat::kRgba16Sint;
- case SpvImageFormatRgba16f:
+ case spv::ImageFormat::Rgba16f:
return ast::TexelFormat::kRgba16Float;
// 32 bit channels
- case SpvImageFormatR32ui:
+ case spv::ImageFormat::R32ui:
return ast::TexelFormat::kR32Uint;
- case SpvImageFormatR32i:
+ case spv::ImageFormat::R32i:
return ast::TexelFormat::kR32Sint;
- case SpvImageFormatR32f:
+ case spv::ImageFormat::R32f:
return ast::TexelFormat::kR32Float;
- case SpvImageFormatRg32ui:
+ case spv::ImageFormat::Rg32ui:
return ast::TexelFormat::kRg32Uint;
- case SpvImageFormatRg32i:
+ case spv::ImageFormat::Rg32i:
return ast::TexelFormat::kRg32Sint;
- case SpvImageFormatRg32f:
+ case spv::ImageFormat::Rg32f:
return ast::TexelFormat::kRg32Float;
- case SpvImageFormatRgba32ui:
+ case spv::ImageFormat::Rgba32ui:
return ast::TexelFormat::kRgba32Uint;
- case SpvImageFormatRgba32i:
+ case spv::ImageFormat::Rgba32i:
return ast::TexelFormat::kRgba32Sint;
- case SpvImageFormatRgba32f:
+ case spv::ImageFormat::Rgba32f:
return ast::TexelFormat::kRgba32Float;
default:
break;
diff --git a/src/tint/reader/spirv/enum_converter.h b/src/tint/reader/spirv/enum_converter.h
index 1ebea36..0082499 100644
--- a/src/tint/reader/spirv/enum_converter.h
+++ b/src/tint/reader/spirv/enum_converter.h
@@ -16,6 +16,7 @@
#define SRC_TINT_READER_SPIRV_ENUM_CONVERTER_H_
#include "spirv/unified1/spirv.h"
+#include "spirv/unified1/spirv.hpp11"
#include "src/tint/ast/address_space.h"
#include "src/tint/ast/builtin_value.h"
#include "src/tint/ast/pipeline_stage.h"
@@ -37,32 +38,49 @@
/// On failure, logs an error and returns kNone
/// @param model the SPIR-V entry point execution model
/// @returns a Tint AST pipeline stage
- ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
+ ast::PipelineStage ToPipelineStage(spv::ExecutionModel model);
/// Converts a SPIR-V storage class to a Tint address space.
/// On failure, logs an error and returns kNone
/// @param sc the SPIR-V storage class
/// @returns a Tint AST address space
- ast::AddressSpace ToAddressSpace(const SpvStorageClass sc);
+ ast::AddressSpace ToAddressSpace(const spv::StorageClass sc);
/// Converts a SPIR-V Builtin value a Tint Builtin.
/// On failure, logs an error and returns kNone
/// @param b the SPIR-V builtin
/// @returns a Tint AST builtin
- ast::BuiltinValue ToBuiltin(SpvBuiltIn b);
+ ast::BuiltinValue ToBuiltin(spv::BuiltIn b);
/// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
/// On failure, logs an error and returns kNone
/// @param dim the SPIR-V Dim value
/// @param arrayed true if the texture is arrayed
/// @returns a Tint AST texture dimension
- ast::TextureDimension ToDim(SpvDim dim, bool arrayed);
+ ast::TextureDimension ToDim(spv::Dim dim, bool arrayed);
+
+ /// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
+ /// On failure, logs an error and returns kNone
+ /// @param dim the SPIR-V Dim value
+ /// @param arrayed true if the texture is arrayed
+ /// @returns a Tint AST texture dimension
+ ast::TextureDimension ToDim(SpvDim dim, bool arrayed) {
+ return ToDim(static_cast<spv::Dim>(dim), arrayed);
+ }
/// Converts a SPIR-V Image Format to a TexelFormat
/// On failure, logs an error and returns kNone
/// @param fmt the SPIR-V format
/// @returns a Tint AST format
- ast::TexelFormat ToTexelFormat(SpvImageFormat fmt);
+ ast::TexelFormat ToTexelFormat(spv::ImageFormat fmt);
+
+ /// Converts a SPIR-V Image Format to a TexelFormat
+ /// On failure, logs an error and returns kNone
+ /// @param fmt the SPIR-V format
+ /// @returns a Tint AST format
+ ast::TexelFormat ToTexelFormat(SpvImageFormat fmt) {
+ return ToTexelFormat(static_cast<spv::ImageFormat>(fmt));
+ }
private:
/// Registers a failure and returns a stream for log diagnostics.
diff --git a/src/tint/reader/spirv/enum_converter_test.cc b/src/tint/reader/spirv/enum_converter_test.cc
index 112dc4a..b366ebd 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -24,12 +24,12 @@
// Pipeline stage
struct PipelineStageCase {
- SpvExecutionModel model;
+ spv::ExecutionModel model;
bool expect_success;
ast::PipelineStage expected;
};
inline std::ostream& operator<<(std::ostream& out, PipelineStageCase psc) {
- out << "PipelineStageCase{ SpvExecutionModel:" << int(psc.model)
+ out << "PipelineStageCase{ spv::ExecutionModel:::" << int(psc.model)
<< " expect_success?:" << int(psc.expect_success) << " expected:" << int(psc.expected)
<< "}";
return out;
@@ -65,29 +65,29 @@
INSTANTIATE_TEST_SUITE_P(EnumConverterGood,
SpvPipelineStageTest,
- testing::Values(PipelineStageCase{SpvExecutionModelVertex, true,
+ testing::Values(PipelineStageCase{spv::ExecutionModel::Vertex, true,
ast::PipelineStage::kVertex},
- PipelineStageCase{SpvExecutionModelFragment, true,
+ PipelineStageCase{spv::ExecutionModel::Fragment, true,
ast::PipelineStage::kFragment},
- PipelineStageCase{SpvExecutionModelGLCompute, true,
+ PipelineStageCase{spv::ExecutionModel::GLCompute, true,
ast::PipelineStage::kCompute}));
INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
SpvPipelineStageTest,
- testing::Values(PipelineStageCase{static_cast<SpvExecutionModel>(9999),
+ testing::Values(PipelineStageCase{static_cast<spv::ExecutionModel>(9999),
false, ast::PipelineStage::kNone},
- PipelineStageCase{SpvExecutionModelTessellationControl,
+ PipelineStageCase{spv::ExecutionModel::TessellationControl,
false, ast::PipelineStage::kNone}));
// Storage class
struct StorageClassCase {
- SpvStorageClass sc;
+ spv::StorageClass sc;
bool expect_success;
ast::AddressSpace expected;
};
inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
- out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
+ out << "StorageClassCase{ spv::StorageClass:::" << int(scc.sc)
<< " expect_success?:" << int(scc.expect_success) << " expected:" << int(scc.expected)
<< "}";
return out;
@@ -125,29 +125,29 @@
EnumConverterGood,
SpvStorageClassTest,
testing::Values(
- StorageClassCase{SpvStorageClassInput, true, ast::AddressSpace::kIn},
- StorageClassCase{SpvStorageClassOutput, true, ast::AddressSpace::kOut},
- StorageClassCase{SpvStorageClassUniform, true, ast::AddressSpace::kUniform},
- StorageClassCase{SpvStorageClassWorkgroup, true, ast::AddressSpace::kWorkgroup},
- StorageClassCase{SpvStorageClassUniformConstant, true, ast::AddressSpace::kNone},
- StorageClassCase{SpvStorageClassStorageBuffer, true, ast::AddressSpace::kStorage},
- StorageClassCase{SpvStorageClassPrivate, true, ast::AddressSpace::kPrivate},
- StorageClassCase{SpvStorageClassFunction, true, ast::AddressSpace::kFunction}));
+ StorageClassCase{spv::StorageClass::Input, true, ast::AddressSpace::kIn},
+ StorageClassCase{spv::StorageClass::Output, true, ast::AddressSpace::kOut},
+ StorageClassCase{spv::StorageClass::Uniform, true, ast::AddressSpace::kUniform},
+ StorageClassCase{spv::StorageClass::Workgroup, true, ast::AddressSpace::kWorkgroup},
+ StorageClassCase{spv::StorageClass::UniformConstant, true, ast::AddressSpace::kNone},
+ StorageClassCase{spv::StorageClass::StorageBuffer, true, ast::AddressSpace::kStorage},
+ StorageClassCase{spv::StorageClass::Private, true, ast::AddressSpace::kPrivate},
+ StorageClassCase{spv::StorageClass::Function, true, ast::AddressSpace::kFunction}));
INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
SpvStorageClassTest,
- testing::Values(StorageClassCase{static_cast<SpvStorageClass>(9999), false,
- ast::AddressSpace::kUndefined}));
+ testing::Values(StorageClassCase{static_cast<spv::StorageClass>(9999),
+ false, ast::AddressSpace::kUndefined}));
// Builtin
struct BuiltinCase {
- SpvBuiltIn builtin;
+ spv::BuiltIn builtin;
bool expect_success;
ast::BuiltinValue expected;
};
inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
- out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
+ out << "BuiltinCase{ spv::BuiltIn::" << int(bc.builtin)
<< " expect_success?:" << int(bc.expect_success) << " expected:" << int(bc.expected) << "}";
return out;
}
@@ -184,43 +184,44 @@
EnumConverterGood_Input,
SpvBuiltinTest,
testing::Values(
- BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
- BuiltinCase{SpvBuiltInInstanceIndex, true, ast::BuiltinValue::kInstanceIndex},
- BuiltinCase{SpvBuiltInFrontFacing, true, ast::BuiltinValue::kFrontFacing},
- BuiltinCase{SpvBuiltInFragCoord, true, ast::BuiltinValue::kPosition},
- BuiltinCase{SpvBuiltInLocalInvocationId, true, ast::BuiltinValue::kLocalInvocationId},
- BuiltinCase{SpvBuiltInLocalInvocationIndex, true, ast::BuiltinValue::kLocalInvocationIndex},
- BuiltinCase{SpvBuiltInGlobalInvocationId, true, ast::BuiltinValue::kGlobalInvocationId},
- BuiltinCase{SpvBuiltInWorkgroupId, true, ast::BuiltinValue::kWorkgroupId},
- BuiltinCase{SpvBuiltInSampleId, true, ast::BuiltinValue::kSampleIndex},
- BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
+ BuiltinCase{spv::BuiltIn::Position, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{spv::BuiltIn::InstanceIndex, true, ast::BuiltinValue::kInstanceIndex},
+ BuiltinCase{spv::BuiltIn::FrontFacing, true, ast::BuiltinValue::kFrontFacing},
+ BuiltinCase{spv::BuiltIn::FragCoord, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{spv::BuiltIn::LocalInvocationId, true, ast::BuiltinValue::kLocalInvocationId},
+ BuiltinCase{spv::BuiltIn::LocalInvocationIndex, true,
+ ast::BuiltinValue::kLocalInvocationIndex},
+ BuiltinCase{spv::BuiltIn::GlobalInvocationId, true, ast::BuiltinValue::kGlobalInvocationId},
+ BuiltinCase{spv::BuiltIn::WorkgroupId, true, ast::BuiltinValue::kWorkgroupId},
+ BuiltinCase{spv::BuiltIn::SampleId, true, ast::BuiltinValue::kSampleIndex},
+ BuiltinCase{spv::BuiltIn::SampleMask, true, ast::BuiltinValue::kSampleMask}));
INSTANTIATE_TEST_SUITE_P(
EnumConverterGood_Output,
SpvBuiltinTest,
- testing::Values(BuiltinCase{SpvBuiltInPosition, true, ast::BuiltinValue::kPosition},
- BuiltinCase{SpvBuiltInFragDepth, true, ast::BuiltinValue::kFragDepth},
- BuiltinCase{SpvBuiltInSampleMask, true, ast::BuiltinValue::kSampleMask}));
+ testing::Values(BuiltinCase{spv::BuiltIn::Position, true, ast::BuiltinValue::kPosition},
+ BuiltinCase{spv::BuiltIn::FragDepth, true, ast::BuiltinValue::kFragDepth},
+ BuiltinCase{spv::BuiltIn::SampleMask, true, ast::BuiltinValue::kSampleMask}));
INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
SpvBuiltinTest,
- testing::Values(BuiltinCase{static_cast<SpvBuiltIn>(9999), false,
+ testing::Values(BuiltinCase{static_cast<spv::BuiltIn>(9999), false,
ast::BuiltinValue::kUndefined},
- BuiltinCase{static_cast<SpvBuiltIn>(9999), false,
+ BuiltinCase{static_cast<spv::BuiltIn>(9999), false,
ast::BuiltinValue::kUndefined},
- BuiltinCase{SpvBuiltInNumWorkgroups, false,
+ BuiltinCase{spv::BuiltIn::NumWorkgroups, false,
ast::BuiltinValue::kUndefined}));
// Dim
struct DimCase {
- SpvDim dim;
+ spv::Dim dim;
bool arrayed;
bool expect_success;
ast::TextureDimension expected;
};
inline std::ostream& operator<<(std::ostream& out, DimCase dc) {
- out << "DimCase{ SpvDim:" << int(dc.dim) << " arrayed?:" << int(dc.arrayed)
+ out << "DimCase{ spv::Dim:::" << int(dc.dim) << " arrayed?:" << int(dc.arrayed)
<< " expect_success?:" << int(dc.expect_success) << " expected:" << int(dc.expected) << "}";
return out;
}
@@ -256,40 +257,41 @@
SpvDimTest,
testing::Values(
// Non-arrayed
- DimCase{SpvDim1D, false, true, ast::TextureDimension::k1d},
- DimCase{SpvDim2D, false, true, ast::TextureDimension::k2d},
- DimCase{SpvDim3D, false, true, ast::TextureDimension::k3d},
- DimCase{SpvDimCube, false, true, ast::TextureDimension::kCube},
+ DimCase{spv::Dim::Dim1D, false, true, ast::TextureDimension::k1d},
+ DimCase{spv::Dim::Dim2D, false, true, ast::TextureDimension::k2d},
+ DimCase{spv::Dim::Dim3D, false, true, ast::TextureDimension::k3d},
+ DimCase{spv::Dim::Cube, false, true, ast::TextureDimension::kCube},
// Arrayed
- DimCase{SpvDim2D, true, true, ast::TextureDimension::k2dArray},
- DimCase{SpvDimCube, true, true, ast::TextureDimension::kCubeArray}));
+ DimCase{spv::Dim::Dim2D, true, true, ast::TextureDimension::k2dArray},
+ DimCase{spv::Dim::Cube, true, true,
+ ast::TextureDimension::kCubeArray}));
-INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
- SpvDimTest,
- testing::Values(
- // Invalid SPIR-V dimensionality.
- DimCase{SpvDimMax, false, false, ast::TextureDimension::kNone},
- DimCase{SpvDimMax, true, false, ast::TextureDimension::kNone},
- // Vulkan non-arrayed dimensionalities not supported by WGSL.
- DimCase{SpvDimRect, false, false, ast::TextureDimension::kNone},
- DimCase{SpvDimBuffer, false, false, ast::TextureDimension::kNone},
- DimCase{SpvDimSubpassData, false, false, ast::TextureDimension::kNone},
- // Arrayed dimensionalities not supported by WGSL
- DimCase{SpvDim3D, true, false, ast::TextureDimension::kNone},
- DimCase{SpvDimRect, true, false, ast::TextureDimension::kNone},
- DimCase{SpvDimBuffer, true, false, ast::TextureDimension::kNone},
- DimCase{SpvDimSubpassData, true, false,
- ast::TextureDimension::kNone}));
+INSTANTIATE_TEST_SUITE_P(
+ EnumConverterBad,
+ SpvDimTest,
+ testing::Values(
+ // Invalid SPIR-V dimensionality.
+ DimCase{spv::Dim::Max, false, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::Max, true, false, ast::TextureDimension::kNone},
+ // Vulkan non-arrayed dimensionalities not supported by WGSL.
+ DimCase{spv::Dim::Rect, false, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::Buffer, false, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::SubpassData, false, false, ast::TextureDimension::kNone},
+ // Arrayed dimensionalities not supported by WGSL
+ DimCase{spv::Dim::Dim3D, true, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::Rect, true, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::Buffer, true, false, ast::TextureDimension::kNone},
+ DimCase{spv::Dim::SubpassData, true, false, ast::TextureDimension::kNone}));
// TexelFormat
struct TexelFormatCase {
- SpvImageFormat format;
+ spv::ImageFormat format;
bool expect_success;
ast::TexelFormat expected;
};
inline std::ostream& operator<<(std::ostream& out, TexelFormatCase ifc) {
- out << "TexelFormatCase{ SpvImageFormat:" << int(ifc.format)
+ out << "TexelFormatCase{ spv::ImageFormat:::" << int(ifc.format)
<< " expect_success?:" << int(ifc.expect_success) << " expected:" << int(ifc.expected)
<< "}";
return out;
@@ -328,52 +330,52 @@
SpvImageFormatTest,
testing::Values(
// Unknown. This is used for sampled images.
- TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Unknown, true, ast::TexelFormat::kUndefined},
// 8 bit channels
- TexelFormatCase{SpvImageFormatRgba8, true, ast::TexelFormat::kRgba8Unorm},
- TexelFormatCase{SpvImageFormatRgba8Snorm, true, ast::TexelFormat::kRgba8Snorm},
- TexelFormatCase{SpvImageFormatRgba8ui, true, ast::TexelFormat::kRgba8Uint},
- TexelFormatCase{SpvImageFormatRgba8i, true, ast::TexelFormat::kRgba8Sint},
+ TexelFormatCase{spv::ImageFormat::Rgba8, true, ast::TexelFormat::kRgba8Unorm},
+ TexelFormatCase{spv::ImageFormat::Rgba8Snorm, true, ast::TexelFormat::kRgba8Snorm},
+ TexelFormatCase{spv::ImageFormat::Rgba8ui, true, ast::TexelFormat::kRgba8Uint},
+ TexelFormatCase{spv::ImageFormat::Rgba8i, true, ast::TexelFormat::kRgba8Sint},
// 16 bit channels
- TexelFormatCase{SpvImageFormatRgba16ui, true, ast::TexelFormat::kRgba16Uint},
- TexelFormatCase{SpvImageFormatRgba16i, true, ast::TexelFormat::kRgba16Sint},
- TexelFormatCase{SpvImageFormatRgba16f, true, ast::TexelFormat::kRgba16Float},
+ TexelFormatCase{spv::ImageFormat::Rgba16ui, true, ast::TexelFormat::kRgba16Uint},
+ TexelFormatCase{spv::ImageFormat::Rgba16i, true, ast::TexelFormat::kRgba16Sint},
+ TexelFormatCase{spv::ImageFormat::Rgba16f, true, ast::TexelFormat::kRgba16Float},
// 32 bit channels
// ... 1 channel
- TexelFormatCase{SpvImageFormatR32ui, true, ast::TexelFormat::kR32Uint},
- TexelFormatCase{SpvImageFormatR32i, true, ast::TexelFormat::kR32Sint},
- TexelFormatCase{SpvImageFormatR32f, true, ast::TexelFormat::kR32Float},
+ TexelFormatCase{spv::ImageFormat::R32ui, true, ast::TexelFormat::kR32Uint},
+ TexelFormatCase{spv::ImageFormat::R32i, true, ast::TexelFormat::kR32Sint},
+ TexelFormatCase{spv::ImageFormat::R32f, true, ast::TexelFormat::kR32Float},
// ... 2 channels
- TexelFormatCase{SpvImageFormatRg32ui, true, ast::TexelFormat::kRg32Uint},
- TexelFormatCase{SpvImageFormatRg32i, true, ast::TexelFormat::kRg32Sint},
- TexelFormatCase{SpvImageFormatRg32f, true, ast::TexelFormat::kRg32Float},
+ TexelFormatCase{spv::ImageFormat::Rg32ui, true, ast::TexelFormat::kRg32Uint},
+ TexelFormatCase{spv::ImageFormat::Rg32i, true, ast::TexelFormat::kRg32Sint},
+ TexelFormatCase{spv::ImageFormat::Rg32f, true, ast::TexelFormat::kRg32Float},
// ... 4 channels
- TexelFormatCase{SpvImageFormatRgba32ui, true, ast::TexelFormat::kRgba32Uint},
- TexelFormatCase{SpvImageFormatRgba32i, true, ast::TexelFormat::kRgba32Sint},
- TexelFormatCase{SpvImageFormatRgba32f, true, ast::TexelFormat::kRgba32Float}));
+ TexelFormatCase{spv::ImageFormat::Rgba32ui, true, ast::TexelFormat::kRgba32Uint},
+ TexelFormatCase{spv::ImageFormat::Rgba32i, true, ast::TexelFormat::kRgba32Sint},
+ TexelFormatCase{spv::ImageFormat::Rgba32f, true, ast::TexelFormat::kRgba32Float}));
INSTANTIATE_TEST_SUITE_P(
EnumConverterBad,
SpvImageFormatTest,
testing::Values(
// Scanning in order from the SPIR-V spec.
- TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatR11fG11fB10f, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatR16f, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRgb10A2, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg16, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg8, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatR16, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatR8, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRgba16Snorm, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg16Snorm, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg8Snorm, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg16i, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg8i, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatR8i, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kUndefined},
- TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kUndefined}));
+ TexelFormatCase{spv::ImageFormat::Rg16f, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::R11fG11fB10f, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::R16f, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rgb10A2, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg16, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg8, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::R16, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::R8, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rgba16Snorm, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg16Snorm, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg8Snorm, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg16i, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg8i, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::R8i, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rgb10a2ui, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg16ui, false, ast::TexelFormat::kUndefined},
+ TexelFormatCase{spv::ImageFormat::Rg8ui, false, ast::TexelFormat::kUndefined}));
} // namespace
} // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index d3febf2..0aafdf9 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -144,24 +144,99 @@
namespace tint::reader::spirv {
+namespace three_sided_patch_function_cc {
+// This machinery is only used while SPIRV-Tools is in transition before it fully
+// uses the C++11 header spirv.hpp11
+
+/// Typedef for pointer to member function while the API call uses
+/// SpvStorageClass for its second argument.
+typedef uint32_t (
+ spvtools::opt::analysis::TypeManager::*PointerFinderSpvStorageClass)(uint32_t, SpvStorageClass);
+/// Typedef for pointer to member function while the API call uses
+/// spv::StorageClass for its second argument.
+typedef uint32_t (spvtools::opt::analysis::TypeManager::*PointerFinderSpvStorageClassCpp11)(
+ uint32_t,
+ spv::StorageClass);
+
+/// @param type_manager the SPIRV-Tools optimizer's type manager
+/// @param finder a pointer to member function in the type manager that does the
+/// actual lookup
+/// @param pointee_type_id the ID of the pointee type
+/// @param sc the storage class. SC can be SpvStorageClass or spv::StorageClass
+/// @returns the ID for a SPIR-V pointer to pointee_type_id in storage class sc
+template <typename FinderType, typename SC>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_manager,
+ FinderType finder,
+ uint32_t pointee_type_id,
+ SC sc);
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClass finder,
+ uint32_t pointee_type_id,
+ SpvStorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, sc);
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClass finder,
+ uint32_t pointee_type_id,
+ spv::StorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, static_cast<SpvStorageClass>(sc));
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClassCpp11 finder,
+ uint32_t pointee_type_id,
+ SpvStorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, static_cast<spv::StorageClass>(sc));
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClassCpp11 finder,
+ uint32_t pointee_type_id,
+ spv::StorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, sc);
+}
+} // namespace three_sided_patch_function_cc
+
namespace {
constexpr uint32_t kMaxVectorLen = 4;
+template <typename FromOpcodeType>
+spv::Op ToOpcode(FromOpcodeType oc) {
+ return static_cast<spv::Op>(oc);
+}
+
+/// @param inst a SPIR-V instruction
+/// @returns Returns the opcode for an instruciton
+inline spv::Op opcode(const spvtools::opt::Instruction& inst) {
+ return ToOpcode(inst.opcode());
+}
+/// @param inst a SPIR-V instruction pointer
+/// @returns Returns the opcode for an instruciton
+inline spv::Op opcode(const spvtools::opt::Instruction* inst) {
+ return ToOpcode(inst->opcode());
+}
+
// Gets the AST unary opcode for the given SPIR-V opcode, if any
// @param opcode SPIR-V opcode
// @param ast_unary_op return parameter
// @returns true if it was a unary operation
-bool GetUnaryOp(SpvOp opcode, ast::UnaryOp* ast_unary_op) {
+bool GetUnaryOp(spv::Op opcode, ast::UnaryOp* ast_unary_op) {
switch (opcode) {
- case SpvOpSNegate:
- case SpvOpFNegate:
+ case spv::Op::OpSNegate:
+ case spv::Op::OpFNegate:
*ast_unary_op = ast::UnaryOp::kNegation;
return true;
- case SpvOpLogicalNot:
+ case spv::Op::OpLogicalNot:
*ast_unary_op = ast::UnaryOp::kNot;
return true;
- case SpvOpNot:
+ case spv::Op::OpNot:
*ast_unary_op = ast::UnaryOp::kComplement;
return true;
default:
@@ -173,17 +248,17 @@
/// Converts a SPIR-V opcode for a WGSL builtin function, if there is a
/// direct translation. Returns nullptr otherwise.
/// @returns the WGSL builtin function name for the given opcode, or nullptr.
-const char* GetUnaryBuiltInFunctionName(SpvOp opcode) {
+const char* GetUnaryBuiltInFunctionName(spv::Op opcode) {
switch (opcode) {
- case SpvOpAny:
+ case spv::Op::OpAny:
return "any";
- case SpvOpAll:
+ case spv::Op::OpAll:
return "all";
- case SpvOpIsNan:
+ case spv::Op::OpIsNan:
return "isNan";
- case SpvOpIsInf:
+ case spv::Op::OpIsInf:
return "isInf";
- case SpvOpTranspose:
+ case spv::Op::OpTranspose:
return "transpose";
default:
break;
@@ -194,63 +269,63 @@
// Converts a SPIR-V opcode to its corresponding AST binary opcode, if any
// @param opcode SPIR-V opcode
// @returns the AST binary op for the given opcode, or kNone
-ast::BinaryOp ConvertBinaryOp(SpvOp opcode) {
+ast::BinaryOp ConvertBinaryOp(spv::Op opcode) {
switch (opcode) {
- case SpvOpIAdd:
- case SpvOpFAdd:
+ case spv::Op::OpIAdd:
+ case spv::Op::OpFAdd:
return ast::BinaryOp::kAdd;
- case SpvOpISub:
- case SpvOpFSub:
+ case spv::Op::OpISub:
+ case spv::Op::OpFSub:
return ast::BinaryOp::kSubtract;
- case SpvOpIMul:
- case SpvOpFMul:
- case SpvOpVectorTimesScalar:
- case SpvOpMatrixTimesScalar:
- case SpvOpVectorTimesMatrix:
- case SpvOpMatrixTimesVector:
- case SpvOpMatrixTimesMatrix:
+ case spv::Op::OpIMul:
+ case spv::Op::OpFMul:
+ case spv::Op::OpVectorTimesScalar:
+ case spv::Op::OpMatrixTimesScalar:
+ case spv::Op::OpVectorTimesMatrix:
+ case spv::Op::OpMatrixTimesVector:
+ case spv::Op::OpMatrixTimesMatrix:
return ast::BinaryOp::kMultiply;
- case SpvOpUDiv:
- case SpvOpSDiv:
- case SpvOpFDiv:
+ case spv::Op::OpUDiv:
+ case spv::Op::OpSDiv:
+ case spv::Op::OpFDiv:
return ast::BinaryOp::kDivide;
- case SpvOpUMod:
- case SpvOpSMod:
- case SpvOpFRem:
+ case spv::Op::OpUMod:
+ case spv::Op::OpSMod:
+ case spv::Op::OpFRem:
return ast::BinaryOp::kModulo;
- case SpvOpLogicalEqual:
- case SpvOpIEqual:
- case SpvOpFOrdEqual:
+ case spv::Op::OpLogicalEqual:
+ case spv::Op::OpIEqual:
+ case spv::Op::OpFOrdEqual:
return ast::BinaryOp::kEqual;
- case SpvOpLogicalNotEqual:
- case SpvOpINotEqual:
- case SpvOpFOrdNotEqual:
+ case spv::Op::OpLogicalNotEqual:
+ case spv::Op::OpINotEqual:
+ case spv::Op::OpFOrdNotEqual:
return ast::BinaryOp::kNotEqual;
- case SpvOpBitwiseAnd:
+ case spv::Op::OpBitwiseAnd:
return ast::BinaryOp::kAnd;
- case SpvOpBitwiseOr:
+ case spv::Op::OpBitwiseOr:
return ast::BinaryOp::kOr;
- case SpvOpBitwiseXor:
+ case spv::Op::OpBitwiseXor:
return ast::BinaryOp::kXor;
- case SpvOpLogicalAnd:
+ case spv::Op::OpLogicalAnd:
return ast::BinaryOp::kAnd;
- case SpvOpLogicalOr:
+ case spv::Op::OpLogicalOr:
return ast::BinaryOp::kOr;
- case SpvOpUGreaterThan:
- case SpvOpSGreaterThan:
- case SpvOpFOrdGreaterThan:
+ case spv::Op::OpUGreaterThan:
+ case spv::Op::OpSGreaterThan:
+ case spv::Op::OpFOrdGreaterThan:
return ast::BinaryOp::kGreaterThan;
- case SpvOpUGreaterThanEqual:
- case SpvOpSGreaterThanEqual:
- case SpvOpFOrdGreaterThanEqual:
+ case spv::Op::OpUGreaterThanEqual:
+ case spv::Op::OpSGreaterThanEqual:
+ case spv::Op::OpFOrdGreaterThanEqual:
return ast::BinaryOp::kGreaterThanEqual;
- case SpvOpULessThan:
- case SpvOpSLessThan:
- case SpvOpFOrdLessThan:
+ case spv::Op::OpULessThan:
+ case spv::Op::OpSLessThan:
+ case spv::Op::OpFOrdLessThan:
return ast::BinaryOp::kLessThan;
- case SpvOpULessThanEqual:
- case SpvOpSLessThanEqual:
- case SpvOpFOrdLessThanEqual:
+ case spv::Op::OpULessThanEqual:
+ case spv::Op::OpSLessThanEqual:
+ case spv::Op::OpFOrdLessThanEqual:
return ast::BinaryOp::kLessThanEqual;
default:
break;
@@ -265,19 +340,19 @@
// Othewrise returns BinaryOp::kNone.
// @param opcode SPIR-V opcode
// @returns operation corresponding to negated version of the SPIR-V opcode
-ast::BinaryOp NegatedFloatCompare(SpvOp opcode) {
+ast::BinaryOp NegatedFloatCompare(spv::Op opcode) {
switch (opcode) {
- case SpvOpFUnordEqual:
+ case spv::Op::OpFUnordEqual:
return ast::BinaryOp::kNotEqual;
- case SpvOpFUnordNotEqual:
+ case spv::Op::OpFUnordNotEqual:
return ast::BinaryOp::kEqual;
- case SpvOpFUnordLessThan:
+ case spv::Op::OpFUnordLessThan:
return ast::BinaryOp::kGreaterThanEqual;
- case SpvOpFUnordLessThanEqual:
+ case spv::Op::OpFUnordLessThanEqual:
return ast::BinaryOp::kGreaterThan;
- case SpvOpFUnordGreaterThan:
+ case spv::Op::OpFUnordGreaterThan:
return ast::BinaryOp::kLessThanEqual;
- case SpvOpFUnordGreaterThanEqual:
+ case spv::Op::OpFUnordGreaterThanEqual:
return ast::BinaryOp::kLessThan;
default:
break;
@@ -443,36 +518,36 @@
// Returns the WGSL standard library function builtin for the
// given instruction, or sem::BuiltinType::kNone
-sem::BuiltinType GetBuiltin(SpvOp opcode) {
+sem::BuiltinType GetBuiltin(spv::Op opcode) {
switch (opcode) {
- case SpvOpBitCount:
+ case spv::Op::OpBitCount:
return sem::BuiltinType::kCountOneBits;
- case SpvOpBitFieldInsert:
+ case spv::Op::OpBitFieldInsert:
return sem::BuiltinType::kInsertBits;
- case SpvOpBitFieldSExtract:
- case SpvOpBitFieldUExtract:
+ case spv::Op::OpBitFieldSExtract:
+ case spv::Op::OpBitFieldUExtract:
return sem::BuiltinType::kExtractBits;
- case SpvOpBitReverse:
+ case spv::Op::OpBitReverse:
return sem::BuiltinType::kReverseBits;
- case SpvOpDot:
+ case spv::Op::OpDot:
return sem::BuiltinType::kDot;
- case SpvOpDPdx:
+ case spv::Op::OpDPdx:
return sem::BuiltinType::kDpdx;
- case SpvOpDPdy:
+ case spv::Op::OpDPdy:
return sem::BuiltinType::kDpdy;
- case SpvOpFwidth:
+ case spv::Op::OpFwidth:
return sem::BuiltinType::kFwidth;
- case SpvOpDPdxFine:
+ case spv::Op::OpDPdxFine:
return sem::BuiltinType::kDpdxFine;
- case SpvOpDPdyFine:
+ case spv::Op::OpDPdyFine:
return sem::BuiltinType::kDpdyFine;
- case SpvOpFwidthFine:
+ case spv::Op::OpFwidthFine:
return sem::BuiltinType::kFwidthFine;
- case SpvOpDPdxCoarse:
+ case spv::Op::OpDPdxCoarse:
return sem::BuiltinType::kDpdxCoarse;
- case SpvOpDPdyCoarse:
+ case spv::Op::OpDPdyCoarse:
return sem::BuiltinType::kDpdyCoarse;
- case SpvOpFwidthCoarse:
+ case spv::Op::OpFwidthCoarse:
return sem::BuiltinType::kFwidthCoarse;
default:
break;
@@ -483,20 +558,20 @@
// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image access instruction
// whose first input operand is an OpSampledImage value.
-bool IsSampledImageAccess(SpvOp opcode) {
+bool IsSampledImageAccess(spv::Op opcode) {
switch (opcode) {
- case SpvOpImageSampleImplicitLod:
- case SpvOpImageSampleExplicitLod:
- case SpvOpImageSampleDrefImplicitLod:
- case SpvOpImageSampleDrefExplicitLod:
+ case spv::Op::OpImageSampleImplicitLod:
+ case spv::Op::OpImageSampleExplicitLod:
+ case spv::Op::OpImageSampleDrefImplicitLod:
+ case spv::Op::OpImageSampleDrefExplicitLod:
// WGSL doesn't have *Proj* texturing; spirv reader emulates it.
- case SpvOpImageSampleProjImplicitLod:
- case SpvOpImageSampleProjExplicitLod:
- case SpvOpImageSampleProjDrefImplicitLod:
- case SpvOpImageSampleProjDrefExplicitLod:
- case SpvOpImageGather:
- case SpvOpImageDrefGather:
- case SpvOpImageQueryLod:
+ case spv::Op::OpImageSampleProjImplicitLod:
+ case spv::Op::OpImageSampleProjExplicitLod:
+ case spv::Op::OpImageSampleProjDrefImplicitLod:
+ case spv::Op::OpImageSampleProjDrefExplicitLod:
+ case spv::Op::OpImageGather:
+ case spv::Op::OpImageDrefGather:
+ case spv::Op::OpImageQueryLod:
return true;
default:
break;
@@ -506,29 +581,29 @@
// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an atomic operation.
-bool IsAtomicOp(SpvOp opcode) {
+bool IsAtomicOp(spv::Op opcode) {
switch (opcode) {
- case SpvOpAtomicLoad:
- case SpvOpAtomicStore:
- case SpvOpAtomicExchange:
- case SpvOpAtomicCompareExchange:
- case SpvOpAtomicCompareExchangeWeak:
- case SpvOpAtomicIIncrement:
- case SpvOpAtomicIDecrement:
- case SpvOpAtomicIAdd:
- case SpvOpAtomicISub:
- case SpvOpAtomicSMin:
- case SpvOpAtomicUMin:
- case SpvOpAtomicSMax:
- case SpvOpAtomicUMax:
- case SpvOpAtomicAnd:
- case SpvOpAtomicOr:
- case SpvOpAtomicXor:
- case SpvOpAtomicFlagTestAndSet:
- case SpvOpAtomicFlagClear:
- case SpvOpAtomicFMinEXT:
- case SpvOpAtomicFMaxEXT:
- case SpvOpAtomicFAddEXT:
+ case spv::Op::OpAtomicLoad:
+ case spv::Op::OpAtomicStore:
+ case spv::Op::OpAtomicExchange:
+ case spv::Op::OpAtomicCompareExchange:
+ case spv::Op::OpAtomicCompareExchangeWeak:
+ case spv::Op::OpAtomicIIncrement:
+ case spv::Op::OpAtomicIDecrement:
+ case spv::Op::OpAtomicIAdd:
+ case spv::Op::OpAtomicISub:
+ case spv::Op::OpAtomicSMin:
+ case spv::Op::OpAtomicUMin:
+ case spv::Op::OpAtomicSMax:
+ case spv::Op::OpAtomicUMax:
+ case spv::Op::OpAtomicAnd:
+ case spv::Op::OpAtomicOr:
+ case spv::Op::OpAtomicXor:
+ case spv::Op::OpAtomicFlagTestAndSet:
+ case spv::Op::OpAtomicFlagClear:
+ case spv::Op::OpAtomicFMinEXT:
+ case spv::Op::OpAtomicFMaxEXT:
+ case spv::Op::OpAtomicFAddEXT:
return true;
default:
break;
@@ -539,19 +614,19 @@
// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image sampling, gather,
// or gather-compare operation.
-bool IsImageSamplingOrGatherOrDrefGather(SpvOp opcode) {
+bool IsImageSamplingOrGatherOrDrefGather(spv::Op opcode) {
switch (opcode) {
- case SpvOpImageSampleImplicitLod:
- case SpvOpImageSampleExplicitLod:
- case SpvOpImageSampleDrefImplicitLod:
- case SpvOpImageSampleDrefExplicitLod:
+ case spv::Op::OpImageSampleImplicitLod:
+ case spv::Op::OpImageSampleExplicitLod:
+ case spv::Op::OpImageSampleDrefImplicitLod:
+ case spv::Op::OpImageSampleDrefExplicitLod:
// WGSL doesn't have *Proj* texturing; spirv reader emulates it.
- case SpvOpImageSampleProjImplicitLod:
- case SpvOpImageSampleProjExplicitLod:
- case SpvOpImageSampleProjDrefImplicitLod:
- case SpvOpImageSampleProjDrefExplicitLod:
- case SpvOpImageGather:
- case SpvOpImageDrefGather:
+ case spv::Op::OpImageSampleProjImplicitLod:
+ case spv::Op::OpImageSampleProjExplicitLod:
+ case spv::Op::OpImageSampleProjDrefImplicitLod:
+ case spv::Op::OpImageSampleProjDrefExplicitLod:
+ case spv::Op::OpImageGather:
+ case spv::Op::OpImageDrefGather:
return true;
default:
break;
@@ -562,11 +637,11 @@
// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image access instruction
// whose first input operand is an OpImage value.
-bool IsRawImageAccess(SpvOp opcode) {
+bool IsRawImageAccess(spv::Op opcode) {
switch (opcode) {
- case SpvOpImageRead:
- case SpvOpImageWrite:
- case SpvOpImageFetch:
+ case spv::Op::OpImageRead:
+ case spv::Op::OpImageWrite:
+ case spv::Op::OpImageFetch:
return true;
default:
break;
@@ -576,13 +651,13 @@
// @param opcode a SPIR-V opcode
// @returns true if the given instruction is an image query instruction
-bool IsImageQuery(SpvOp opcode) {
+bool IsImageQuery(spv::Op opcode) {
switch (opcode) {
- case SpvOpImageQuerySize:
- case SpvOpImageQuerySizeLod:
- case SpvOpImageQueryLevels:
- case SpvOpImageQuerySamples:
- case SpvOpImageQueryLod:
+ case spv::Op::OpImageQuerySize:
+ case spv::Op::OpImageQuerySizeLod:
+ case spv::Op::OpImageQueryLevels:
+ case spv::Op::OpImageQuerySamples:
+ case spv::Op::OpImageQueryLod:
return true;
default:
break;
@@ -653,15 +728,15 @@
// Visit successors. We will naturally skip the continue target and merge
// blocks.
auto* terminator = bb->terminator();
- auto opcode = terminator->opcode();
- if (opcode == SpvOpBranchConditional) {
+ auto opcode = ToOpcode(terminator->opcode());
+ if (opcode == spv::Op::OpBranchConditional) {
// Visit the false branch, then the true branch, to make them come
// out in the natural order for an "if".
VisitBackward(terminator->GetSingleWordInOperand(2));
VisitBackward(terminator->GetSingleWordInOperand(1));
- } else if (opcode == SpvOpBranch) {
+ } else if (opcode == spv::Op::OpBranch) {
VisitBackward(terminator->GetSingleWordInOperand(0));
- } else if (opcode == SpvOpSwitch) {
+ } else if (opcode == spv::Op::OpSwitch) {
// TODO(dneto): Consider visiting the labels in literal-value order.
utils::Vector<uint32_t, 32> successors;
bb->ForEachSuccessorLabel(
@@ -1265,7 +1340,7 @@
for (uint32_t var_id : ep_info_->inputs) {
const auto* var = def_use_mgr_->GetDef(var_id);
TINT_ASSERT(Reader, var != nullptr);
- TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
+ TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
auto* store_type = GetVariableStoreType(*var);
auto* forced_param_type = store_type;
AttributeList param_decos;
@@ -1344,7 +1419,7 @@
} else {
const auto* var = def_use_mgr_->GetDef(var_id);
TINT_ASSERT(Reader, var != nullptr);
- TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
+ TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
const Type* store_type = GetVariableStoreType(*var);
const Type* forced_member_type = store_type;
AttributeList out_decos;
@@ -1570,19 +1645,19 @@
}
if (const auto* inst = block.GetMergeInst()) {
- auto terminator_opcode = block.terminator()->opcode();
- switch (inst->opcode()) {
- case SpvOpSelectionMerge:
- if ((terminator_opcode != SpvOpBranchConditional) &&
- (terminator_opcode != SpvOpSwitch)) {
+ auto terminator_opcode = opcode(block.terminator());
+ switch (opcode(inst)) {
+ case spv::Op::OpSelectionMerge:
+ if ((terminator_opcode != spv::Op::OpBranchConditional) &&
+ (terminator_opcode != spv::Op::OpSwitch)) {
return Fail() << "Selection header " << block_id
<< " does not end in an OpBranchConditional or "
"OpSwitch instruction";
}
break;
- case SpvOpLoopMerge:
- if ((terminator_opcode != SpvOpBranchConditional) &&
- (terminator_opcode != SpvOpBranch)) {
+ case spv::Op::OpLoopMerge:
+ if ((terminator_opcode != spv::Op::OpBranchConditional) &&
+ (terminator_opcode != spv::Op::OpBranch)) {
return Fail() << "Loop header " << block_id
<< " does not end in an OpBranch or "
"OpBranchConditional instruction";
@@ -1612,7 +1687,7 @@
merge_info->header_for_merge = header;
header_info->merge_for_header = merge;
- if (inst->opcode() == SpvOpLoopMerge) {
+ if (opcode(inst) == spv::Op::OpLoopMerge) {
if (header == entry_id) {
return Fail() << "Function entry block " << entry_id
<< " cannot be a loop header";
@@ -1867,8 +1942,8 @@
// From the interval rule, the selection construct consists of blocks
// in the block order, starting at the header, until just before the
// merge block.
- const auto branch_opcode = header_info->basic_block->terminator()->opcode();
- const auto kind = (branch_opcode == SpvOpBranchConditional)
+ const auto branch_opcode = opcode(header_info->basic_block->terminator());
+ const auto kind = (branch_opcode == spv::Op::OpBranchConditional)
? Construct::kIfSelection
: Construct::kSwitchSelection;
top = push_construct(depth, kind, header, merge);
@@ -2485,7 +2560,7 @@
return false;
}
for (auto& inst : *function_.entry()) {
- if (inst.opcode() != SpvOpVariable) {
+ if (opcode(inst) != spv::Op::OpVariable) {
continue;
}
auto* var_store_type = GetVariableStoreType(inst);
@@ -2586,8 +2661,8 @@
Fail() << "ID " << id << " does not have a defining SPIR-V instruction";
return {};
}
- switch (inst->opcode()) {
- case SpvOpVariable: {
+ switch (opcode(inst)) {
+ case spv::Op::OpVariable: {
// This occurs for module-scope variables.
auto name = namer_.Name(id);
// Construct the reference type, mapping storage class correctly.
@@ -2596,7 +2671,7 @@
return TypedExpression{type, create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name))};
}
- case SpvOpUndef:
+ case spv::Op::OpUndef:
// Substitute a null value for undef.
// This case occurs when OpUndef appears at module scope, as if it were
// a constant.
@@ -3102,11 +3177,11 @@
bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) {
const auto& terminator = *(block_info.basic_block->terminator());
- switch (terminator.opcode()) {
- case SpvOpReturn:
+ switch (opcode(terminator)) {
+ case spv::Op::OpReturn:
AddStatement(create<ast::ReturnStatement>(Source{}));
return true;
- case SpvOpReturnValue: {
+ case spv::Op::OpReturnValue: {
auto value = MakeExpression(terminator.GetSingleWordInOperand(0));
if (!value) {
return false;
@@ -3114,12 +3189,12 @@
AddStatement(create<ast::ReturnStatement>(Source{}, value.expr));
}
return true;
- case SpvOpKill:
+ case spv::Op::OpKill:
// For now, assume SPIR-V OpKill has same semantics as WGSL discard.
// TODO(dneto): https://github.com/gpuweb/gpuweb/issues/676
AddStatement(create<ast::DiscardStatement>(Source{}));
return true;
- case SpvOpUnreachable:
+ case spv::Op::OpUnreachable:
// Translate as if it's a return. This avoids the problem where WGSL
// requires a return statement at the end of the function body.
{
@@ -3133,12 +3208,12 @@
}
}
return true;
- case SpvOpBranch: {
+ case spv::Op::OpBranch: {
const auto dest_id = terminator.GetSingleWordInOperand(0);
AddStatement(MakeBranch(block_info, *GetBlockInfo(dest_id)));
return true;
}
- case SpvOpBranchConditional: {
+ case spv::Op::OpBranchConditional: {
// If both destinations are the same, then do the same as we would
// for an unconditional branch (OpBranch).
const auto true_dest = terminator.GetSingleWordInOperand(1);
@@ -3191,7 +3266,7 @@
}
return true;
}
- case SpvOpSwitch:
+ case spv::Op::OpSwitch:
// An OpSelectionMerge must precede an OpSwitch. That is clarified
// in the resolution to Khronos-internal SPIR-V issue 115.
// A new enough version of the SPIR-V validator checks this case.
@@ -3377,8 +3452,8 @@
const auto* terminator = bb.terminator();
const auto* merge = bb.GetMergeInst(); // Might be nullptr
for (auto& inst : bb) {
- if (&inst == terminator || &inst == merge || inst.opcode() == SpvOpLabel ||
- inst.opcode() == SpvOpVariable) {
+ if (&inst == terminator || &inst == merge || opcode(inst) == spv::Op::OpLabel ||
+ opcode(inst) == spv::Op::OpVariable) {
continue;
}
if (!EmitStatement(inst)) {
@@ -3546,23 +3621,23 @@
return false;
}
- if (IsImageQuery(inst.opcode())) {
+ if (IsImageQuery(opcode(inst))) {
return EmitImageQuery(inst);
}
- if (IsSampledImageAccess(inst.opcode()) || IsRawImageAccess(inst.opcode())) {
+ if (IsSampledImageAccess(opcode(inst)) || IsRawImageAccess(opcode(inst))) {
return EmitImageAccess(inst);
}
- if (IsAtomicOp(inst.opcode())) {
+ if (IsAtomicOp(opcode(inst))) {
return EmitAtomicOp(inst);
}
- switch (inst.opcode()) {
- case SpvOpNop:
+ switch (opcode(inst)) {
+ case spv::Op::OpNop:
return true;
- case SpvOpStore: {
+ case spv::Op::OpStore: {
auto ptr_id = inst.GetSingleWordInOperand(0);
const auto value_id = inst.GetSingleWordInOperand(1);
@@ -3633,7 +3708,7 @@
return success();
}
- case SpvOpLoad: {
+ case spv::Op::OpLoad: {
// Memory accesses must be issued in SPIR-V program order.
// So represent a load by a new const definition.
const auto ptr_id = inst.GetSingleWordInOperand(0);
@@ -3684,7 +3759,7 @@
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
- case SpvOpCopyMemory: {
+ case spv::Op::OpCopyMemory: {
// Generate an assignment.
auto lhs = MakeOperand(inst, 0);
auto rhs = MakeOperand(inst, 1);
@@ -3713,7 +3788,7 @@
return success();
}
- case SpvOpCopyObject: {
+ case spv::Op::OpCopyObject: {
// Arguably, OpCopyObject is purely combinatorial. On the other hand,
// it exists to make a new name for something. So we choose to make
// a new named constant definition.
@@ -3732,39 +3807,39 @@
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
- case SpvOpPhi: {
+ case spv::Op::OpPhi: {
// The value will be in scope, available for reading from the phi ID.
return true;
}
- case SpvOpOuterProduct:
+ case spv::Op::OpOuterProduct:
// Synthesize an outer product expression in its own statement.
return EmitConstDefOrWriteToHoistedVar(inst, MakeOuterProduct(inst));
- case SpvOpVectorInsertDynamic:
+ case spv::Op::OpVectorInsertDynamic:
// Synthesize a vector insertion in its own statements.
return MakeVectorInsertDynamic(inst);
- case SpvOpCompositeInsert:
+ case spv::Op::OpCompositeInsert:
// Synthesize a composite insertion in its own statements.
return MakeCompositeInsert(inst);
- case SpvOpFunctionCall:
+ case spv::Op::OpFunctionCall:
return EmitFunctionCall(inst);
- case SpvOpControlBarrier:
+ case spv::Op::OpControlBarrier:
return EmitControlBarrier(inst);
- case SpvOpExtInst:
+ case spv::Op::OpExtInst:
if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
return true;
}
break;
- case SpvOpIAddCarry:
- case SpvOpISubBorrow:
- case SpvOpUMulExtended:
- case SpvOpSMulExtended:
+ case spv::Op::OpIAddCarry:
+ case spv::Op::OpISubBorrow:
+ case spv::Op::OpUMulExtended:
+ case spv::Op::OpSMulExtended:
return Fail() << "extended arithmetic is not finalized for WGSL: "
"https://github.com/gpuweb/gpuweb/issues/1565: "
<< inst.PrettyPrint();
@@ -3772,7 +3847,7 @@
default:
break;
}
- return Fail() << "unhandled instruction with opcode " << inst.opcode() << ": "
+ return Fail() << "unhandled instruction with opcode " << uint32_t(opcode(inst)) << ": "
<< inst.PrettyPrint();
}
@@ -3791,7 +3866,7 @@
return {};
}
- const auto opcode = inst.opcode();
+ const auto op = opcode(inst);
const Type* ast_type = nullptr;
if (inst.type_id()) {
@@ -3802,7 +3877,7 @@
}
}
- auto binary_op = ConvertBinaryOp(opcode);
+ auto binary_op = ConvertBinaryOp(op);
if (binary_op != ast::BinaryOp::kNone) {
auto arg0 = MakeOperand(inst, 0);
auto arg1 =
@@ -3817,14 +3892,14 @@
}
auto unary_op = ast::UnaryOp::kNegation;
- if (GetUnaryOp(opcode, &unary_op)) {
+ if (GetUnaryOp(op, &unary_op)) {
auto arg0 = MakeOperand(inst, 0);
auto* unary_expr = create<ast::UnaryOpExpression>(Source{}, unary_op, arg0.expr);
TypedExpression result{ast_type, unary_expr};
return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
}
- const char* unary_builtin_name = GetUnaryBuiltInFunctionName(opcode);
+ const char* unary_builtin_name = GetUnaryBuiltInFunctionName(op);
if (unary_builtin_name != nullptr) {
ExpressionList params;
params.Push(MakeOperand(inst, 0).expr);
@@ -3835,40 +3910,40 @@
std::move(params))};
}
- const auto builtin = GetBuiltin(opcode);
+ const auto builtin = GetBuiltin(op);
if (builtin != sem::BuiltinType::kNone) {
return MakeBuiltinCall(inst);
}
- if (opcode == SpvOpFMod) {
+ if (op == spv::Op::OpFMod) {
return MakeFMod(inst);
}
- if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) {
+ if (op == spv::Op::OpAccessChain || op == spv::Op::OpInBoundsAccessChain) {
return MakeAccessChain(inst);
}
- if (opcode == SpvOpBitcast) {
+ if (op == spv::Op::OpBitcast) {
return {ast_type, create<ast::BitcastExpression>(Source{}, ast_type->Build(builder_),
MakeOperand(inst, 0).expr)};
}
- if (opcode == SpvOpShiftLeftLogical || opcode == SpvOpShiftRightLogical ||
- opcode == SpvOpShiftRightArithmetic) {
+ if (op == spv::Op::OpShiftLeftLogical || op == spv::Op::OpShiftRightLogical ||
+ op == spv::Op::OpShiftRightArithmetic) {
auto arg0 = MakeOperand(inst, 0);
// The second operand must be unsigned. It's ok to wrap the shift amount
// since the shift is modulo the bit width of the first operand.
auto arg1 = parser_impl_.AsUnsigned(MakeOperand(inst, 1));
- switch (opcode) {
- case SpvOpShiftLeftLogical:
+ switch (op) {
+ case spv::Op::OpShiftLeftLogical:
binary_op = ast::BinaryOp::kShiftLeft;
break;
- case SpvOpShiftRightLogical:
+ case spv::Op::OpShiftRightLogical:
arg0 = parser_impl_.AsUnsigned(arg0);
binary_op = ast::BinaryOp::kShiftRight;
break;
- case SpvOpShiftRightArithmetic:
+ case spv::Op::OpShiftRightArithmetic:
arg0 = parser_impl_.AsSigned(arg0);
binary_op = ast::BinaryOp::kShiftRight;
break;
@@ -3880,7 +3955,7 @@
return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
}
- auto negated_op = NegatedFloatCompare(opcode);
+ auto negated_op = NegatedFloatCompare(op);
if (negated_op != ast::BinaryOp::kNone) {
auto arg0 = MakeOperand(inst, 0);
auto arg1 = MakeOperand(inst, 1);
@@ -3891,7 +3966,7 @@
return {ast_type, negated_expr};
}
- if (opcode == SpvOpExtInst) {
+ if (op == spv::Op::OpExtInst) {
if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
// Ignore it but don't error out.
return {};
@@ -3904,7 +3979,7 @@
return EmitGlslStd450ExtInst(inst);
}
- if (opcode == SpvOpCompositeConstruct) {
+ if (op == spv::Op::OpCompositeConstruct) {
ExpressionList operands;
for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
operands.Push(MakeOperand(inst, iarg).expr);
@@ -3913,34 +3988,34 @@
builder_.Construct(Source{}, ast_type->Build(builder_), std::move(operands))};
}
- if (opcode == SpvOpCompositeExtract) {
+ if (op == spv::Op::OpCompositeExtract) {
return MakeCompositeExtract(inst);
}
- if (opcode == SpvOpVectorShuffle) {
+ if (op == spv::Op::OpVectorShuffle) {
return MakeVectorShuffle(inst);
}
- if (opcode == SpvOpVectorExtractDynamic) {
+ if (op == spv::Op::OpVectorExtractDynamic) {
return {ast_type, create<ast::IndexAccessorExpression>(Source{}, MakeOperand(inst, 0).expr,
MakeOperand(inst, 1).expr)};
}
- if (opcode == SpvOpConvertSToF || opcode == SpvOpConvertUToF || opcode == SpvOpConvertFToS ||
- opcode == SpvOpConvertFToU) {
+ if (op == spv::Op::OpConvertSToF || op == spv::Op::OpConvertUToF ||
+ op == spv::Op::OpConvertFToS || op == spv::Op::OpConvertFToU) {
return MakeNumericConversion(inst);
}
- if (opcode == SpvOpUndef) {
+ if (op == spv::Op::OpUndef) {
// Replace undef with the null value.
return parser_impl_.MakeNullExpression(ast_type);
}
- if (opcode == SpvOpSelect) {
+ if (op == spv::Op::OpSelect) {
return MakeSimpleSelect(inst);
}
- if (opcode == SpvOpArrayLength) {
+ if (op == spv::Op::OpArrayLength) {
return MakeArrayLength(inst);
}
@@ -4424,12 +4499,12 @@
const auto constants = constant_mgr_->GetOperandConstants(&inst);
const auto* ptr_type_inst = def_use_mgr_->GetDef(ptr_ty_id);
- if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) {
+ if (!ptr_type_inst || (opcode(ptr_type_inst) != spv::Op::OpTypePointer)) {
Fail() << "Access chain %" << inst.result_id() << " base pointer is not of pointer type";
return {};
}
- SpvStorageClass address_space =
- static_cast<SpvStorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
+ spv::StorageClass address_space =
+ static_cast<spv::StorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
// Build up a nested expression for the access chain by walking down the type
@@ -4446,8 +4521,8 @@
<< (index - first_index) << " indices: " << inst.PrettyPrint();
return {};
}
- switch (pointee_type_inst->opcode()) {
- case SpvOpTypeVector:
+ switch (opcode(pointee_type_inst)) {
+ case spv::Op::OpTypeVector:
if (index_const) {
// Try generating a MemberAccessor expression
const auto num_elems = pointee_type_inst->GetSingleWordInOperand(1);
@@ -4473,24 +4548,24 @@
// Sink pointers to vector components.
sink_pointer = true;
break;
- case SpvOpTypeMatrix:
+ case spv::Op::OpTypeMatrix:
// Use array syntax.
next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
MakeOperand(inst, index).expr);
// All matrix components are the same type.
pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
break;
- case SpvOpTypeArray:
+ case spv::Op::OpTypeArray:
next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
MakeOperand(inst, index).expr);
pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
break;
- case SpvOpTypeRuntimeArray:
+ case spv::Op::OpTypeRuntimeArray:
next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
MakeOperand(inst, index).expr);
pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
break;
- case SpvOpTypeStruct: {
+ case spv::Op::OpTypeStruct: {
if (!index_const) {
Fail() << "Access chain %" << inst.result_id() << " index %"
<< inst.GetSingleWordInOperand(index)
@@ -4519,7 +4594,9 @@
<< ": " << pointee_type_inst->PrettyPrint();
return {};
}
- const auto pointer_type_id = type_mgr_->FindPointerToType(pointee_type_id, address_space);
+ const auto pointer_type_id = three_sided_patch_function_cc::FindPointerToType(
+ type_mgr_, &spvtools::opt::analysis::TypeManager::FindPointerToType, pointee_type_id,
+ address_space);
auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
TINT_ASSERT(Reader, type && type->Is<Reference>());
current_expr = TypedExpression{type, next_expr};
@@ -4594,11 +4671,11 @@
return {};
}
const char* operation_name = nullptr;
- switch (inst.opcode()) {
- case SpvOpCompositeExtract:
+ switch (opcode(inst)) {
+ case spv::Op::OpCompositeExtract:
operation_name = "OpCompositeExtract";
break;
- case SpvOpCompositeInsert:
+ case spv::Op::OpCompositeInsert:
operation_name = "OpCompositeInsert";
break;
default:
@@ -4606,8 +4683,8 @@
return {};
}
const ast::Expression* next_expr = nullptr;
- switch (current_type_inst->opcode()) {
- case SpvOpTypeVector: {
+ switch (opcode(current_type_inst)) {
+ case spv::Op::OpTypeVector: {
// Try generating a MemberAccessor expression. That result in something
// like "foo.z", which is more idiomatic than "foo[2]".
const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
@@ -4628,7 +4705,7 @@
current_type_id = current_type_inst->GetSingleWordInOperand(0);
break;
}
- case SpvOpTypeMatrix: {
+ case spv::Op::OpTypeMatrix: {
// Check bounds
const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
if (num_elems <= index_val) {
@@ -4648,7 +4725,7 @@
current_type_id = current_type_inst->GetSingleWordInOperand(0);
break;
}
- case SpvOpTypeArray:
+ case spv::Op::OpTypeArray:
// The array size could be a spec constant, and so it's not always
// statically checkable. Instead, rely on a runtime index clamp
// or runtime check to keep this safe.
@@ -4656,11 +4733,11 @@
make_index(index_val));
current_type_id = current_type_inst->GetSingleWordInOperand(0);
break;
- case SpvOpTypeRuntimeArray:
+ case spv::Op::OpTypeRuntimeArray:
Fail() << "can't do " << operation_name
<< " on a runtime array: " << inst.PrettyPrint();
return {};
- case SpvOpTypeStruct: {
+ case spv::Op::OpTypeStruct: {
const auto num_members = current_type_inst->NumInOperands();
if (num_members <= index_val) {
Fail() << operation_name << " %" << inst.result_id() << " index value "
@@ -4751,14 +4828,14 @@
auto& def = def_info_[id];
// Builtins are always defined outside the function.
switch (builtin) {
- case SpvBuiltInPointSize:
+ case spv::BuiltIn::PointSize:
def->skip = SkipReason::kPointSizeBuiltinPointer;
break;
- case SpvBuiltInSampleMask: {
+ case spv::BuiltIn::SampleMask: {
// Distinguish between input and output variable.
const auto storage_class =
- static_cast<SpvStorageClass>(var->GetSingleWordInOperand(0));
- if (storage_class == SpvStorageClassInput) {
+ static_cast<spv::StorageClass>(var->GetSingleWordInOperand(0));
+ if (storage_class == spv::StorageClass::Input) {
sample_mask_in_id = id;
def->skip = SkipReason::kSampleMaskInBuiltinPointer;
} else {
@@ -4767,14 +4844,14 @@
}
break;
}
- case SpvBuiltInSampleId:
- case SpvBuiltInInstanceIndex:
- case SpvBuiltInVertexIndex:
- case SpvBuiltInLocalInvocationIndex:
- case SpvBuiltInLocalInvocationId:
- case SpvBuiltInGlobalInvocationId:
- case SpvBuiltInWorkgroupId:
- case SpvBuiltInNumWorkgroups:
+ case spv::BuiltIn::SampleId:
+ case spv::BuiltIn::InstanceIndex:
+ case spv::BuiltIn::VertexIndex:
+ case spv::BuiltIn::LocalInvocationIndex:
+ case spv::BuiltIn::LocalInvocationId:
+ case spv::BuiltIn::GlobalInvocationId:
+ case spv::BuiltIn::WorkgroupId:
+ case spv::BuiltIn::NumWorkgroups:
break;
default:
return Fail() << "unrecognized special builtin: " << int(builtin);
@@ -4791,7 +4868,7 @@
const auto block_pos = block_info->pos;
for (const auto& inst : *(block_info->basic_block)) {
const auto result_id = inst.result_id();
- if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
+ if ((result_id == 0) || opcode(inst) == spv::Op::OpLabel) {
continue;
}
def_info_[result_id] = std::make_unique<DefInfo>(index, inst, block_pos);
@@ -4807,15 +4884,15 @@
// pointer definitions are SSA values, and their definitions must be
// visited before their uses.
if (type->AsPointer()) {
- switch (inst.opcode()) {
- case SpvOpUndef:
+ switch (opcode(inst)) {
+ case spv::Op::OpUndef:
return Fail() << "undef pointer is not valid: " << inst.PrettyPrint();
- case SpvOpVariable:
+ case spv::Op::OpVariable:
info->pointer = GetPointerInfo(result_id);
break;
- case SpvOpAccessChain:
- case SpvOpInBoundsAccessChain:
- case SpvOpCopyObject:
+ case spv::Op::OpAccessChain:
+ case spv::Op::OpInBoundsAccessChain:
+ case spv::Op::OpCopyObject:
// Inherit from the first operand. We need this so we can pick up
// a remapped storage buffer.
info->pointer = GetPointerInfo(inst.GetSingleWordInOperand(0));
@@ -4846,8 +4923,8 @@
[&](const spvtools::opt::Instruction& inst) -> DefInfo::Pointer {
// WGSL root identifiers (or SPIR-V "memory object declarations") are
// either variables or function parameters.
- switch (inst.opcode()) {
- case SpvOpVariable: {
+ switch (opcode(inst)) {
+ case spv::Op::OpVariable: {
if (const auto* module_var = parser_impl_.GetModuleVariable(id)) {
return DefInfo::Pointer{module_var->declared_address_space,
module_var->declared_access};
@@ -4856,7 +4933,7 @@
// access mode.
return DefInfo::Pointer{ast::AddressSpace::kFunction, ast::Access::kUndefined};
}
- case SpvOpFunctionParameter: {
+ case spv::Op::OpFunctionParameter: {
const auto* type = As<Pointer>(parser_impl_.ConvertType(inst.type_id()));
// For access mode, kUndefined is ok for now, since the
// only non-default access mode on a pointer would be for a storage
@@ -4879,7 +4956,7 @@
auto where = def_info_.find(id);
if (where != def_info_.end()) {
const auto& info = where->second;
- if (info->inst.opcode() == SpvOpVariable) {
+ if (opcode(info->inst) == spv::Op::OpVariable) {
// Ignore the cache in this case and compute it from scratch.
// That's because for a function-scope OpVariable is a
// locally-defined value. So its cache entry has been created
@@ -4925,8 +5002,8 @@
};
for (auto& id_def_info_pair : def_info_) {
const auto& inst = id_def_info_pair.second->inst;
- const auto opcode = inst.opcode();
- if ((opcode == SpvOpVectorShuffle) || (opcode == SpvOpOuterProduct)) {
+ const auto op = opcode(inst);
+ if ((op == spv::Op::OpVectorShuffle) || (op == spv::Op::OpOuterProduct)) {
// We might access the vector operands multiple times. Make sure they
// are evaluated only once.
require_named_const_def(inst, 0);
@@ -4979,7 +5056,7 @@
const auto* block_info = GetBlockInfo(block_id);
for (const auto& inst : *(block_info->basic_block)) {
// Update bookkeeping for locally-defined IDs used by this instruction.
- if (inst.opcode() == SpvOpPhi) {
+ if (opcode(inst) == spv::Op::OpPhi) {
// For an OpPhi defining value P, an incoming value V from parent block B is
// counted as being "used" at block B, not at the block containing the Phi.
// That's because we will create a variable PHI_P to hold the phi value, and
@@ -5128,7 +5205,7 @@
}
TypedExpression FunctionEmitter::MakeNumericConversion(const spvtools::opt::Instruction& inst) {
- const auto opcode = inst.opcode();
+ const auto op = opcode(inst);
auto* requested_type = parser_impl_.ConvertType(inst.type_id());
auto arg_expr = MakeOperand(inst, 0);
if (!arg_expr) {
@@ -5137,7 +5214,7 @@
arg_expr.type = arg_expr.type->UnwrapRef();
const Type* expr_type = nullptr;
- if ((opcode == SpvOpConvertSToF) || (opcode == SpvOpConvertUToF)) {
+ if ((op == spv::Op::OpConvertSToF) || (op == spv::Op::OpConvertUToF)) {
if (arg_expr.type->IsIntegerScalarOrVector()) {
expr_type = requested_type;
} else {
@@ -5145,7 +5222,7 @@
"scalar or vector: "
<< inst.PrettyPrint();
}
- } else if (inst.opcode() == SpvOpConvertFToU) {
+ } else if (op == spv::Op::OpConvertFToU) {
if (arg_expr.type->IsFloatScalarOrVector()) {
expr_type = parser_impl_.GetUnsignedIntMatchingShape(arg_expr.type);
} else {
@@ -5153,7 +5230,7 @@
"point scalar or vector: "
<< inst.PrettyPrint();
}
- } else if (inst.opcode() == SpvOpConvertFToS) {
+ } else if (op == spv::Op::OpConvertFToS) {
if (arg_expr.type->IsFloatScalarOrVector()) {
expr_type = parser_impl_.GetSignedIntMatchingShape(arg_expr.type);
} else {
@@ -5228,28 +5305,28 @@
uint32_t memory = operands[1];
uint32_t semantics = operands[2];
- if (execution != SpvScopeWorkgroup) {
+ if (execution != uint32_t(spv::Scope::Workgroup)) {
return Fail() << "unsupported control barrier execution scope: "
<< "expected Workgroup (2), got: " << execution;
}
- if (semantics & SpvMemorySemanticsAcquireReleaseMask) {
- semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsAcquireReleaseMask);
+ if (semantics & uint32_t(spv::MemorySemanticsMask::AcquireRelease)) {
+ semantics &= ~static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease);
} else {
return Fail() << "control barrier semantics requires acquire and release";
}
- if (semantics & SpvMemorySemanticsWorkgroupMemoryMask) {
- if (memory != SpvScopeWorkgroup) {
+ if (semantics & uint32_t(spv::MemorySemanticsMask::WorkgroupMemory)) {
+ if (memory != uint32_t(spv::Scope::Workgroup)) {
return Fail() << "workgroupBarrier requires workgroup memory scope";
}
AddStatement(create<ast::CallStatement>(builder_.Call("workgroupBarrier")));
- semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsWorkgroupMemoryMask);
+ semantics &= ~static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
}
- if (semantics & SpvMemorySemanticsUniformMemoryMask) {
- if (memory != SpvScopeDevice) {
+ if (semantics & uint32_t(spv::MemorySemanticsMask::UniformMemory)) {
+ if (memory != uint32_t(spv::Scope::Device)) {
return Fail() << "storageBarrier requires device memory scope";
}
AddStatement(create<ast::CallStatement>(builder_.Call("storageBarrier")));
- semantics &= ~static_cast<uint32_t>(SpvMemorySemanticsUniformMemoryMask);
+ semantics &= ~static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
}
if (semantics) {
return Fail() << "unsupported control barrier semantics: " << semantics;
@@ -5258,7 +5335,7 @@
}
TypedExpression FunctionEmitter::MakeBuiltinCall(const spvtools::opt::Instruction& inst) {
- const auto builtin = GetBuiltin(inst.opcode());
+ const auto builtin = GetBuiltin(opcode(inst));
auto* name = sem::str(builtin);
auto* ident = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
@@ -5374,7 +5451,7 @@
bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
ExpressionList args;
- const auto opcode = inst.opcode();
+ const auto op = opcode(inst);
// Form the texture operand.
const spvtools::opt::Instruction* image = GetImage(inst);
@@ -5384,7 +5461,7 @@
args.Push(GetImageExpression(inst));
// Form the sampler operand, if needed.
- if (IsSampledImageAccess(opcode)) {
+ if (IsSampledImageAccess(op)) {
// Form the sampler operand.
if (auto* sampler = GetSamplerExpression(inst)) {
args.Push(sampler);
@@ -5438,25 +5515,25 @@
bool is_dref_sample = false;
bool is_gather_or_dref_gather = false;
bool is_non_dref_sample = false;
- switch (opcode) {
- case SpvOpImageSampleImplicitLod:
- case SpvOpImageSampleExplicitLod:
- case SpvOpImageSampleProjImplicitLod:
- case SpvOpImageSampleProjExplicitLod:
+ switch (op) {
+ case spv::Op::OpImageSampleImplicitLod:
+ case spv::Op::OpImageSampleExplicitLod:
+ case spv::Op::OpImageSampleProjImplicitLod:
+ case spv::Op::OpImageSampleProjExplicitLod:
is_non_dref_sample = true;
builtin_name = "textureSample";
break;
- case SpvOpImageSampleDrefImplicitLod:
- case SpvOpImageSampleDrefExplicitLod:
- case SpvOpImageSampleProjDrefImplicitLod:
- case SpvOpImageSampleProjDrefExplicitLod:
+ case spv::Op::OpImageSampleDrefImplicitLod:
+ case spv::Op::OpImageSampleDrefExplicitLod:
+ case spv::Op::OpImageSampleProjDrefImplicitLod:
+ case spv::Op::OpImageSampleProjDrefExplicitLod:
is_dref_sample = true;
builtin_name = "textureSampleCompare";
if (!consume_dref()) {
return false;
}
break;
- case SpvOpImageGather:
+ case spv::Op::OpImageGather:
is_gather_or_dref_gather = true;
builtin_name = "textureGather";
if (!texture_type->Is<DepthTexture>()) {
@@ -5471,20 +5548,20 @@
// Skip over the component operand, even for depth textures.
arg_index++;
break;
- case SpvOpImageDrefGather:
+ case spv::Op::OpImageDrefGather:
is_gather_or_dref_gather = true;
builtin_name = "textureGatherCompare";
if (!consume_dref()) {
return false;
}
break;
- case SpvOpImageFetch:
- case SpvOpImageRead:
+ case spv::Op::OpImageFetch:
+ case spv::Op::OpImageRead:
// Read a single texel from a sampled or storage image.
builtin_name = "textureLoad";
use_level_of_detail_suffix = false;
break;
- case SpvOpImageWrite:
+ case spv::Op::OpImageWrite:
builtin_name = "textureStore";
use_level_of_detail_suffix = false;
if (arg_index < num_args) {
@@ -5511,7 +5588,7 @@
image_operands_mask = inst.GetSingleWordInOperand(arg_index);
arg_index++;
}
- if (arg_index < num_args && (image_operands_mask & SpvImageOperandsBiasMask)) {
+ if (arg_index < num_args && (image_operands_mask & uint32_t(spv::ImageOperandsMask::Bias))) {
if (is_dref_sample) {
return Fail() << "WGSL does not support depth-reference sampling with "
"level-of-detail bias: "
@@ -5524,10 +5601,10 @@
}
builtin_name += "Bias";
args.Push(MakeOperand(inst, arg_index).expr);
- image_operands_mask ^= SpvImageOperandsBiasMask;
+ image_operands_mask ^= uint32_t(spv::ImageOperandsMask::Bias);
arg_index++;
}
- if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
+ if (arg_index < num_args && (image_operands_mask & uint32_t(spv::ImageOperandsMask::Lod))) {
if (use_level_of_detail_suffix) {
builtin_name += "Level";
}
@@ -5553,15 +5630,16 @@
args.Push(lod.expr);
}
- image_operands_mask ^= SpvImageOperandsLodMask;
+ image_operands_mask ^= uint32_t(spv::ImageOperandsMask::Lod);
arg_index++;
- } else if ((opcode == SpvOpImageFetch || opcode == SpvOpImageRead) &&
+ } else if ((op == spv::Op::OpImageFetch || op == spv::Op::OpImageRead) &&
!texture_type->IsAnyOf<DepthMultisampledTexture, MultisampledTexture>()) {
// textureLoad requires an explicit level-of-detail parameter for
// non-multisampled texture types.
args.Push(parser_impl_.MakeNullValue(ty_.I32()));
}
- if (arg_index + 1 < num_args && (image_operands_mask & SpvImageOperandsGradMask)) {
+ if (arg_index + 1 < num_args &&
+ (image_operands_mask & uint32_t(spv::ImageOperandsMask::Grad))) {
if (is_dref_sample) {
return Fail() << "WGSL does not support depth-reference sampling with "
"explicit gradient: "
@@ -5575,11 +5653,12 @@
builtin_name += "Grad";
args.Push(MakeOperand(inst, arg_index).expr);
args.Push(MakeOperand(inst, arg_index + 1).expr);
- image_operands_mask ^= SpvImageOperandsGradMask;
+ image_operands_mask ^= uint32_t(spv::ImageOperandsMask::Grad);
arg_index += 2;
}
- if (arg_index < num_args && (image_operands_mask & SpvImageOperandsConstOffsetMask)) {
- if (!IsImageSamplingOrGatherOrDrefGather(opcode)) {
+ if (arg_index < num_args &&
+ (image_operands_mask & uint32_t(spv::ImageOperandsMask::ConstOffset))) {
+ if (!IsImageSamplingOrGatherOrDrefGather(op)) {
return Fail() << "ConstOffset is only permitted for sampling, gather, or "
"depth-reference gather operations: "
<< inst.PrettyPrint();
@@ -5596,13 +5675,13 @@
}
args.Push(ToSignedIfUnsigned(MakeOperand(inst, arg_index)).expr);
- image_operands_mask ^= SpvImageOperandsConstOffsetMask;
+ image_operands_mask ^= uint32_t(spv::ImageOperandsMask::ConstOffset);
arg_index++;
}
- if (arg_index < num_args && (image_operands_mask & SpvImageOperandsSampleMask)) {
+ if (arg_index < num_args && (image_operands_mask & uint32_t(spv::ImageOperandsMask::Sample))) {
// TODO(dneto): only permitted with ImageFetch
args.Push(ToI32(MakeOperand(inst, arg_index)).expr);
- image_operands_mask ^= SpvImageOperandsSampleMask;
+ image_operands_mask ^= uint32_t(spv::ImageOperandsMask::Sample);
arg_index++;
}
if (image_operands_mask) {
@@ -5642,7 +5721,7 @@
// Construct a 4-element vector with the result from the builtin in the
// first component.
if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) {
- if (is_non_dref_sample || (opcode == SpvOpImageFetch)) {
+ if (is_non_dref_sample || (op == spv::Op::OpImageFetch)) {
value = builder_.Construct(Source{},
result_type->Build(builder_), // a vec4
utils::Vector{
@@ -5658,7 +5737,7 @@
// result type. Compare the SPIR-V image's sampled component type with the
// component of the result type of the SPIR-V instruction.
auto* spirv_image_type = parser_impl_.GetSpirvTypeForHandleMemoryObjectDeclaration(*image);
- if (!spirv_image_type || (spirv_image_type->opcode() != SpvOpTypeImage)) {
+ if (!spirv_image_type || (opcode(spirv_image_type) != spv::Op::OpTypeImage)) {
return Fail() << "invalid image type for image memory object declaration "
<< image->PrettyPrint();
}
@@ -5670,7 +5749,7 @@
value =
create<ast::BitcastExpression>(Source{}, result_type->Build(builder_), call_expr);
}
- if (!expected_component_type->Is<F32>() && IsSampledImageAccess(opcode)) {
+ if (!expected_component_type->Is<F32>() && IsSampledImageAccess(op)) {
// WGSL permits sampled image access only on float textures.
// Reject this case in the SPIR-V reader, at least until SPIR-V validation
// catches up with this rule and can reject it earlier in the workflow.
@@ -5697,10 +5776,10 @@
return false;
}
- const auto opcode = inst.opcode();
- switch (opcode) {
- case SpvOpImageQuerySize:
- case SpvOpImageQuerySizeLod: {
+ const auto op = opcode(inst);
+ switch (op) {
+ case spv::Op::OpImageQuerySize:
+ case spv::Op::OpImageQuerySizeLod: {
ExpressionList exprs;
// Invoke textureDimensions.
// If the texture is arrayed, combine with the result from
@@ -5708,7 +5787,7 @@
auto* dims_ident = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register("textureDimensions"));
ExpressionList dims_args{GetImageExpression(inst)};
- if (opcode == SpvOpImageQuerySizeLod) {
+ if (op == spv::Op::OpImageQuerySizeLod) {
dims_args.Push(MakeOperand(inst, 1).expr);
}
const ast::Expression* dims_call =
@@ -5745,13 +5824,13 @@
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
- case SpvOpImageQueryLod:
+ case spv::Op::OpImageQueryLod:
return Fail() << "WGSL does not support querying the level of detail of an image: "
<< inst.PrettyPrint();
- case SpvOpImageQueryLevels:
- case SpvOpImageQuerySamples: {
+ case spv::Op::OpImageQueryLevels:
+ case spv::Op::OpImageQuerySamples: {
const auto* name =
- (opcode == SpvOpImageQueryLevels) ? "textureNumLevels" : "textureNumSamples";
+ (op == spv::Op::OpImageQueryLevels) ? "textureNumLevels" : "textureNumSamples";
auto* levels_ident =
create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
const ast::Expression* ast_expr = create<ast::CallExpression>(
@@ -5834,46 +5913,46 @@
return {};
};
- switch (inst.opcode()) {
- case SpvOpAtomicLoad:
+ switch (opcode(inst)) {
+ case spv::Op::OpAtomicLoad:
return emit_atomic(sem::BuiltinType::kAtomicLoad, {oper(/*ptr*/ 0)});
- case SpvOpAtomicStore:
+ case spv::Op::OpAtomicStore:
return emit_atomic(sem::BuiltinType::kAtomicStore,
{oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicExchange:
+ case spv::Op::OpAtomicExchange:
return emit_atomic(sem::BuiltinType::kAtomicExchange,
{oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicCompareExchange:
- case SpvOpAtomicCompareExchangeWeak:
+ case spv::Op::OpAtomicCompareExchange:
+ case spv::Op::OpAtomicCompareExchangeWeak:
return emit_atomic(sem::BuiltinType::kAtomicCompareExchangeWeak,
{oper(/*ptr*/ 0), /*value*/ oper(5), /*comparator*/ oper(4)});
- case SpvOpAtomicIIncrement:
+ case spv::Op::OpAtomicIIncrement:
return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
- case SpvOpAtomicIDecrement:
+ case spv::Op::OpAtomicIDecrement:
return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
- case SpvOpAtomicIAdd:
+ case spv::Op::OpAtomicIAdd:
return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicISub:
+ case spv::Op::OpAtomicISub:
return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicSMin:
+ case spv::Op::OpAtomicSMin:
return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicUMin:
+ case spv::Op::OpAtomicUMin:
return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicSMax:
+ case spv::Op::OpAtomicSMax:
return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicUMax:
+ case spv::Op::OpAtomicUMax:
return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicAnd:
+ case spv::Op::OpAtomicAnd:
return emit_atomic(sem::BuiltinType::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicOr:
+ case spv::Op::OpAtomicOr:
return emit_atomic(sem::BuiltinType::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicXor:
+ case spv::Op::OpAtomicXor:
return emit_atomic(sem::BuiltinType::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
- case SpvOpAtomicFlagTestAndSet:
- case SpvOpAtomicFlagClear:
- case SpvOpAtomicFMinEXT:
- case SpvOpAtomicFMaxEXT:
- case SpvOpAtomicFAddEXT:
+ case spv::Op::OpAtomicFlagTestAndSet:
+ case spv::Op::OpAtomicFlagClear:
+ case spv::Op::OpAtomicFMinEXT:
+ case spv::Op::OpAtomicFMaxEXT:
+ case spv::Op::OpAtomicFAddEXT:
return Fail() << "unsupported atomic op: " << inst.PrettyPrint();
default:
@@ -5926,11 +6005,11 @@
<< " prompted by " << inst.PrettyPrint();
}
bool is_proj = false;
- switch (inst.opcode()) {
- case SpvOpImageSampleProjImplicitLod:
- case SpvOpImageSampleProjExplicitLod:
- case SpvOpImageSampleProjDrefImplicitLod:
- case SpvOpImageSampleProjDrefExplicitLod:
+ switch (opcode(inst)) {
+ case spv::Op::OpImageSampleProjImplicitLod:
+ case spv::Op::OpImageSampleProjExplicitLod:
+ case spv::Op::OpImageSampleProjDrefImplicitLod:
+ case spv::Op::OpImageSampleProjDrefExplicitLod:
is_proj = true;
break;
default:
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index 13b4132..f055f4c 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -34,6 +34,65 @@
namespace tint::reader::spirv {
+namespace three_sided_patch {
+// This machinery is only used while SPIRV-Tools is in transition before it fully
+// uses the C++11 header spirv.hpp11
+
+/// Typedef for pointer to member function while the API call uses
+/// SpvStorageClass for its second argument.
+typedef uint32_t (
+ spvtools::opt::analysis::TypeManager::*PointerFinderSpvStorageClass)(uint32_t, SpvStorageClass);
+/// Typedef for pointer to member function while the API call uses
+/// spv::StorageClass for its second argument.
+typedef uint32_t (spvtools::opt::analysis::TypeManager::*PointerFinderSpvStorageClassCpp11)(
+ uint32_t,
+ spv::StorageClass);
+
+/// @param type_manager the SPIRV-Tools optimizer's type manager
+/// @param finder a pointer to member function in the type manager that does the
+/// actual lookup
+/// @param pointee_type_id the ID of the pointee type
+/// @param sc the storage class. SC can be SpvStorageClass or spv::StorageClass
+/// @returns the ID for a SPIR-V pointer to pointee_type_id in storage class sc
+template <typename FinderType, typename SC>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_manager,
+ FinderType finder,
+ uint32_t pointee_type_id,
+ SC sc);
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClass finder,
+ uint32_t pointee_type_id,
+ SpvStorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, sc);
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClass finder,
+ uint32_t pointee_type_id,
+ spv::StorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, static_cast<SpvStorageClass>(sc));
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClassCpp11 finder,
+ uint32_t pointee_type_id,
+ SpvStorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, static_cast<spv::StorageClass>(sc));
+}
+
+template <>
+uint32_t FindPointerToType(spvtools::opt::analysis::TypeManager* type_mgr,
+ PointerFinderSpvStorageClassCpp11 finder,
+ uint32_t pointee_type_id,
+ spv::StorageClass sc) {
+ return (type_mgr->*finder)(pointee_type_id, sc);
+}
+} // namespace three_sided_patch
+
namespace {
// Input SPIR-V needs only to conform to Vulkan 1.1 requirements.
@@ -42,6 +101,17 @@
// will satisfy SPV_ENV_WEBGPU_0 validation.
const spv_target_env kInputEnv = SPV_ENV_VULKAN_1_1;
+/// @param inst a SPIR-V instruction
+/// @returns Returns the opcode for an instruciton
+inline spv::Op opcode(const spvtools::opt::Instruction& inst) {
+ return static_cast<spv::Op>(inst.opcode());
+}
+/// @param inst a SPIR-V instruction pointer
+/// @returns Returns the opcode for an instruciton
+inline spv::Op opcode(const spvtools::opt::Instruction* inst) {
+ return static_cast<spv::Op>(inst->opcode());
+}
+
// A FunctionTraverser is used to compute an ordering of functions in the
// module such that callees precede callers.
class FunctionTraverser {
@@ -70,7 +140,7 @@
visited_.insert(&f);
for (const auto& bb : f) {
for (const auto& inst : bb) {
- if (inst.opcode() != SpvOpFunctionCall) {
+ if (opcode(inst) != spv::Op::OpFunctionCall) {
continue;
}
const auto* callee = id_to_func_[inst.GetSingleWordInOperand(0)];
@@ -89,17 +159,17 @@
};
// Returns true if the opcode operates as if its operands are signed integral.
-bool AssumesSignedOperands(SpvOp opcode) {
+bool AssumesSignedOperands(spv::Op opcode) {
switch (opcode) {
- case SpvOpSNegate:
- case SpvOpSDiv:
- case SpvOpSRem:
- case SpvOpSMod:
- case SpvOpSLessThan:
- case SpvOpSLessThanEqual:
- case SpvOpSGreaterThan:
- case SpvOpSGreaterThanEqual:
- case SpvOpConvertSToF:
+ case spv::Op::OpSNegate:
+ case spv::Op::OpSDiv:
+ case spv::Op::OpSRem:
+ case spv::Op::OpSMod:
+ case spv::Op::OpSLessThan:
+ case spv::Op::OpSLessThanEqual:
+ case spv::Op::OpSGreaterThan:
+ case spv::Op::OpSGreaterThanEqual:
+ case spv::Op::OpConvertSToF:
return true;
default:
break;
@@ -126,15 +196,15 @@
}
// Returns true if the opcode operates as if its operands are unsigned integral.
-bool AssumesUnsignedOperands(SpvOp opcode) {
+bool AssumesUnsignedOperands(spv::Op opcode) {
switch (opcode) {
- case SpvOpUDiv:
- case SpvOpUMod:
- case SpvOpULessThan:
- case SpvOpULessThanEqual:
- case SpvOpUGreaterThan:
- case SpvOpUGreaterThanEqual:
- case SpvOpConvertUToF:
+ case spv::Op::OpUDiv:
+ case spv::Op::OpUMod:
+ case spv::Op::OpULessThan:
+ case spv::Op::OpULessThanEqual:
+ case spv::Op::OpUGreaterThan:
+ case spv::Op::OpUGreaterThanEqual:
+ case spv::Op::OpConvertUToF:
return true;
default:
break;
@@ -163,18 +233,18 @@
// the signedness of the second operand to match the signedness of the
// first operand, and it's not one of the OpU* or OpS* instructions.
// (Those are handled via MakeOperand.)
-bool AssumesSecondOperandSignednessMatchesFirstOperand(SpvOp opcode) {
+bool AssumesSecondOperandSignednessMatchesFirstOperand(spv::Op opcode) {
switch (opcode) {
// All the OpI* integer binary operations.
- case SpvOpIAdd:
- case SpvOpISub:
- case SpvOpIMul:
- case SpvOpIEqual:
- case SpvOpINotEqual:
+ case spv::Op::OpIAdd:
+ case spv::Op::OpISub:
+ case spv::Op::OpIMul:
+ case spv::Op::OpIEqual:
+ case spv::Op::OpINotEqual:
// All the bitwise integer binary operations.
- case SpvOpBitwiseAnd:
- case SpvOpBitwiseOr:
- case SpvOpBitwiseXor:
+ case spv::Op::OpBitwiseAnd:
+ case spv::Op::OpBitwiseOr:
+ case spv::Op::OpBitwiseXor:
return true;
default:
break;
@@ -184,24 +254,24 @@
// Returns true if the corresponding WGSL operation requires
// the signedness of the result to match the signedness of the first operand.
-bool AssumesResultSignednessMatchesFirstOperand(SpvOp opcode) {
+bool AssumesResultSignednessMatchesFirstOperand(spv::Op opcode) {
switch (opcode) {
- case SpvOpNot:
- case SpvOpSNegate:
- case SpvOpBitCount:
- case SpvOpBitReverse:
- case SpvOpSDiv:
- case SpvOpSMod:
- case SpvOpSRem:
- case SpvOpIAdd:
- case SpvOpISub:
- case SpvOpIMul:
- case SpvOpBitwiseAnd:
- case SpvOpBitwiseOr:
- case SpvOpBitwiseXor:
- case SpvOpShiftLeftLogical:
- case SpvOpShiftRightLogical:
- case SpvOpShiftRightArithmetic:
+ case spv::Op::OpNot:
+ case spv::Op::OpSNegate:
+ case spv::Op::OpBitCount:
+ case spv::Op::OpBitReverse:
+ case spv::Op::OpSDiv:
+ case spv::Op::OpSMod:
+ case spv::Op::OpSRem:
+ case spv::Op::OpIAdd:
+ case spv::Op::OpISub:
+ case spv::Op::OpIMul:
+ case spv::Op::OpBitwiseAnd:
+ case spv::Op::OpBitwiseOr:
+ case spv::Op::OpBitwiseXor:
+ case spv::Op::OpShiftLeftLogical:
+ case spv::Op::OpShiftRightLogical:
+ case spv::Op::OpShiftRightArithmetic:
return true;
default:
break;
@@ -240,12 +310,12 @@
if (deco.size() < 1) {
return false;
}
- switch (deco[0]) {
- case SpvDecorationLocation:
- case SpvDecorationFlat:
- case SpvDecorationNoPerspective:
- case SpvDecorationCentroid:
- case SpvDecorationSample:
+ switch (static_cast<spv::Decoration>(deco[0])) {
+ case spv::Decoration::Location:
+ case spv::Decoration::Flat:
+ case spv::Decoration::NoPerspective:
+ case spv::Decoration::Centroid:
+ case spv::Decoration::Sample:
return true;
default:
break;
@@ -388,16 +458,16 @@
const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
std::unordered_set<uint32_t> visited;
for (const auto* inst : decorations) {
- if (inst->opcode() != SpvOpDecorate) {
+ if (opcode(inst) != spv::Op::OpDecorate) {
continue;
}
// Example: OpDecorate %struct_id Block
// Example: OpDecorate %array_ty ArrayStride 16
auto decoration_kind = inst->GetSingleWordInOperand(1);
- switch (decoration_kind) {
+ switch (static_cast<spv::Decoration>(decoration_kind)) {
// Restrict and RestrictPointer have no effect in graphics APIs.
- case SpvDecorationRestrict:
- case SpvDecorationRestrictPointer:
+ case spv::Decoration::Restrict:
+ case spv::Decoration::RestrictPointer:
break;
default:
if (visited.emplace(decoration_kind).second) {
@@ -418,15 +488,15 @@
std::unordered_set<uint32_t> visited;
for (const auto* inst : decorations) {
// Example: OpMemberDecorate %struct_id 1 Offset 16
- if ((inst->opcode() != SpvOpMemberDecorate) ||
+ if ((opcode(inst) != spv::Op::OpMemberDecorate) ||
(inst->GetSingleWordInOperand(1) != member_index)) {
continue;
}
auto decoration_kind = inst->GetSingleWordInOperand(2);
- switch (decoration_kind) {
+ switch (static_cast<spv::Decoration>(decoration_kind)) {
// Restrict and RestrictPointer have no effect in graphics APIs.
- case SpvDecorationRestrict:
- case SpvDecorationRestrictPointer:
+ case spv::Decoration::Restrict:
+ case spv::Decoration::RestrictPointer:
break;
default:
if (visited.emplace(decoration_kind).second) {
@@ -458,8 +528,8 @@
Fail() << "malformed SPIR-V decoration: it's empty";
return {};
}
- switch (decoration[0]) {
- case SpvDecorationOffset:
+ switch (static_cast<spv::Decoration>(decoration[0])) {
+ case spv::Decoration::Offset:
if (decoration.size() != 2) {
Fail() << "malformed Offset decoration: expected 1 literal operand, has "
<< decoration.size() - 1 << ": member " << member_index << " of "
@@ -469,24 +539,24 @@
return {
builder_.MemberOffset(Source{}, AInt(decoration[1])),
};
- case SpvDecorationNonReadable:
+ case spv::Decoration::NonReadable:
// WGSL doesn't have a member decoration for this. Silently drop it.
return {};
- case SpvDecorationNonWritable:
+ case spv::Decoration::NonWritable:
// WGSL doesn't have a member decoration for this.
return {};
- case SpvDecorationColMajor:
+ case spv::Decoration::ColMajor:
// WGSL only supports column major matrices.
return {};
- case SpvDecorationRelaxedPrecision:
+ case spv::Decoration::RelaxedPrecision:
// WGSL doesn't support relaxed precision.
return {};
- case SpvDecorationRowMajor:
+ case spv::Decoration::RowMajor:
Fail() << "WGSL does not support row-major matrices: can't "
"translate member "
<< member_index << " of " << ShowType(struct_type_id);
return {};
- case SpvDecorationMatrixStride: {
+ case spv::Decoration::MatrixStride: {
if (decoration.size() != 2) {
Fail() << "malformed MatrixStride decoration: expected 1 literal "
"operand, has "
@@ -589,15 +659,15 @@
[this, &in_op_line_scope, &op_line_source,
&instruction_number](const spvtools::opt::Instruction* inst) {
++instruction_number.line;
- switch (inst->opcode()) {
- case SpvOpLine:
+ switch (opcode(inst)) {
+ case spv::Op::OpLine:
in_op_line_scope = true;
// TODO(dneto): This ignores the File ID (operand 0), since the Tint
// Source concept doesn't represent that.
op_line_source.line = inst->GetSingleWordInOperand(1);
op_line_source.column = inst->GetSingleWordInOperand(2);
break;
- case SpvOpNoLine:
+ case spv::Op::OpNoLine:
in_op_line_scope = false;
break;
default:
@@ -670,12 +740,12 @@
}
bool ParserImpl::IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const {
- return (inst.opcode() == SpvOpExtInst) &&
+ return (opcode(inst) == spv::Op::OpExtInst) &&
(glsl_std_450_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
}
bool ParserImpl::IsIgnoredExtendedInstruction(const spvtools::opt::Instruction& inst) const {
- return (inst.opcode() == SpvOpExtInst) &&
+ return (opcode(inst) == spv::Op::OpExtInst) &&
(ignored_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
}
@@ -722,15 +792,15 @@
// Register names from OpName and OpMemberName
for (const auto& inst : module_->debugs2()) {
- switch (inst.opcode()) {
- case SpvOpName: {
+ switch (opcode(inst)) {
+ case spv::Op::OpName: {
const auto name = inst.GetInOperand(1).AsString();
if (!name.empty()) {
namer_.SuggestSanitizedName(inst.GetSingleWordInOperand(0), name);
}
break;
}
- case SpvOpMemberName: {
+ case spv::Op::OpMemberName: {
const auto name = inst.GetInOperand(2).AsString();
if (!name.empty()) {
namer_.SuggestSanitizedMemberName(inst.GetSingleWordInOperand(0),
@@ -745,7 +815,7 @@
// Fill in struct member names, and disambiguate them.
for (const auto* type_inst : module_->GetTypes()) {
- if (type_inst->opcode() == SpvOpTypeStruct) {
+ if (opcode(type_inst) == spv::Op::OpTypeStruct) {
namer_.ResolveMemberNamesForStruct(type_inst->result_id(), type_inst->NumInOperands());
}
}
@@ -779,13 +849,13 @@
bool ParserImpl::RegisterWorkgroupSizeBuiltin() {
WorkgroupSizeInfo& info = workgroup_size_builtin_;
for (const spvtools::opt::Instruction& inst : module_->annotations()) {
- if (inst.opcode() != SpvOpDecorate) {
+ if (opcode(inst) != spv::Op::OpDecorate) {
continue;
}
- if (inst.GetSingleWordInOperand(1) != SpvDecorationBuiltIn) {
+ if (inst.GetSingleWordInOperand(1) != uint32_t(spv::Decoration::BuiltIn)) {
continue;
}
- if (inst.GetSingleWordInOperand(2) != SpvBuiltInWorkgroupSize) {
+ if (inst.GetSingleWordInOperand(2) != uint32_t(spv::BuiltIn::WorkgroupSize)) {
continue;
}
info.id = inst.GetSingleWordInOperand(0);
@@ -806,8 +876,8 @@
// const-expr yet, so avoid supporting OpSpecConstantOp here.
// TODO(dneto): See https://github.com/gpuweb/gpuweb/issues/1272 for WGSL
// const_expr proposals.
- if ((composite_def->opcode() != SpvOpSpecConstantComposite &&
- composite_def->opcode() != SpvOpConstantComposite)) {
+ if ((opcode(composite_def) != spv::Op::OpSpecConstantComposite &&
+ opcode(composite_def) != spv::Op::OpConstantComposite)) {
return Fail() << "Invalid WorkgroupSize builtin. Expected 3-element "
"OpSpecConstantComposite or OpConstantComposite: "
<< composite_def->PrettyPrint();
@@ -822,7 +892,8 @@
int index) -> bool {
const auto id = composite_def->GetSingleWordInOperand(static_cast<uint32_t>(index));
const auto* def = def_use_mgr_->GetDef(id);
- if (!def || (def->opcode() != SpvOpSpecConstant && def->opcode() != SpvOpConstant) ||
+ if (!def ||
+ (opcode(def) != spv::Op::OpSpecConstant && opcode(def) != spv::Op::OpConstant) ||
(def->NumInOperands() != 1)) {
return Fail() << "invalid component " << index << " of workgroupsize "
<< (def ? def->PrettyPrint() : std::string("no definition"));
@@ -842,8 +913,8 @@
// decorations.
std::unordered_map<uint32_t, GridSize> local_size;
for (const spvtools::opt::Instruction& inst : module_->execution_modes()) {
- auto mode = static_cast<SpvExecutionMode>(inst.GetSingleWordInOperand(1));
- if (mode == SpvExecutionModeLocalSize) {
+ auto mode = static_cast<spv::ExecutionMode>(inst.GetSingleWordInOperand(1));
+ if (mode == spv::ExecutionMode::LocalSize) {
if (inst.NumInOperands() != 5) {
// This won't even get past SPIR-V binary parsing.
return Fail() << "invalid LocalSize execution mode: " << inst.PrettyPrint();
@@ -856,7 +927,7 @@
}
for (const spvtools::opt::Instruction& entry_point : module_->entry_points()) {
- const auto stage = SpvExecutionModel(entry_point.GetSingleWordInOperand(0));
+ const auto stage = spv::ExecutionModel(entry_point.GetSingleWordInOperand(0));
const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
const std::string ep_name = entry_point.GetOperand(2).AsString();
@@ -886,11 +957,11 @@
for (unsigned iarg = 3; iarg < entry_point.NumInOperands(); iarg++) {
const uint32_t var_id = entry_point.GetSingleWordInOperand(iarg);
if (const auto* var_inst = def_use_mgr_->GetDef(var_id)) {
- switch (SpvStorageClass(var_inst->GetSingleWordInOperand(0))) {
- case SpvStorageClassInput:
+ switch (spv::StorageClass(var_inst->GetSingleWordInOperand(0))) {
+ case spv::StorageClass::Input:
inputs.Add(var_id);
break;
- case SpvStorageClassOutput:
+ case spv::StorageClass::Output:
outputs.Add(var_id);
break;
default:
@@ -1036,7 +1107,7 @@
*array_stride = 0; // Implicit stride case.
const auto type_id = type_mgr_->GetId(spv_type);
for (auto& decoration : this->GetDecorationsFor(type_id)) {
- if (decoration.size() == 2 && decoration[0] == SpvDecorationArrayStride) {
+ if (decoration.size() == 2 && decoration[0] == uint32_t(spv::Decoration::ArrayStride)) {
const auto stride = decoration[1];
if (stride == 0) {
return Fail() << "invalid array type ID " << type_id << ": ArrayStride can't be 0";
@@ -1057,9 +1128,9 @@
auto struct_decorations = this->GetDecorationsFor(type_id);
if (struct_decorations.size() == 1) {
const auto decoration = struct_decorations[0][0];
- if (decoration == SpvDecorationBufferBlock) {
+ if (decoration == uint32_t(spv::Decoration::BufferBlock)) {
remap_buffer_block_type_.insert(type_id);
- } else if (decoration != SpvDecorationBlock) {
+ } else if (decoration != uint32_t(spv::Decoration::Block)) {
Fail() << "struct with ID " << type_id
<< " has unrecognized decoration: " << int(decoration);
}
@@ -1097,21 +1168,21 @@
Fail() << "malformed SPIR-V decoration: it's empty";
return nullptr;
}
- if ((decoration[0] == SpvDecorationBuiltIn) && (decoration.size() > 1)) {
- switch (decoration[1]) {
- case SpvBuiltInPosition:
+ if ((decoration[0] == uint32_t(spv::Decoration::BuiltIn)) && (decoration.size() > 1)) {
+ switch (static_cast<spv::BuiltIn>(decoration[1])) {
+ case spv::BuiltIn::Position:
// Record this built-in variable specially.
builtin_position_.struct_type_id = type_id;
builtin_position_.position_member_index = member_index;
builtin_position_.position_member_type_id = member_type_id;
create_ast_member = false; // Not part of the WGSL structure.
break;
- case SpvBuiltInPointSize: // not supported in WGSL, but ignore
+ case spv::BuiltIn::PointSize: // not supported in WGSL, but ignore
builtin_position_.pointsize_member_index = member_index;
create_ast_member = false; // Not part of the WGSL structure.
break;
- case SpvBuiltInClipDistance: // not supported in WGSL
- case SpvBuiltInCullDistance: // not supported in WGSL
+ case spv::BuiltIn::ClipDistance: // not supported in WGSL
+ case spv::BuiltIn::CullDistance: // not supported in WGSL
create_ast_member = false; // Not part of the WGSL structure.
break;
default:
@@ -1131,7 +1202,7 @@
if (IsPipelineDecoration(decoration)) {
// IO decorations are handled when emitting the entry point.
continue;
- } else if (decoration[0] == SpvDecorationNonWritable) {
+ } else if (decoration[0] == uint32_t(spv::Decoration::NonWritable)) {
// WGSL doesn't represent individual members as non-writable. Instead,
// apply the ReadOnly access control to the containing struct if all
// the members are non-writable.
@@ -1193,12 +1264,12 @@
const spvtools::opt::analysis::Pointer*) {
const auto* inst = def_use_mgr_->GetDef(type_id);
const auto pointee_type_id = inst->GetSingleWordInOperand(1);
- const auto storage_class = SpvStorageClass(inst->GetSingleWordInOperand(0));
+ const auto storage_class = spv::StorageClass(inst->GetSingleWordInOperand(0));
if (pointee_type_id == builtin_position_.struct_type_id) {
builtin_position_.pointer_type_id = type_id;
// Pipeline IO builtins map to private variables.
- builtin_position_.storage_class = SpvStorageClassPrivate;
+ builtin_position_.storage_class = spv::StorageClass::Private;
return nullptr;
}
auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr);
@@ -1244,21 +1315,21 @@
// in WGSL. In particular, exclude user-defined pipeline IO in a
// block-decorated struct.
for (const auto& type_or_value : module_->types_values()) {
- if (type_or_value.opcode() != SpvOpVariable) {
+ if (opcode(type_or_value) != spv::Op::OpVariable) {
continue;
}
const auto& var = type_or_value;
- const auto spirv_storage_class = SpvStorageClass(var.GetSingleWordInOperand(0));
- if ((spirv_storage_class != SpvStorageClassStorageBuffer) &&
- (spirv_storage_class != SpvStorageClassUniform)) {
+ const auto spirv_storage_class = spv::StorageClass(var.GetSingleWordInOperand(0));
+ if ((spirv_storage_class != spv::StorageClass::StorageBuffer) &&
+ (spirv_storage_class != spv::StorageClass::Uniform)) {
continue;
}
const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
- if (ptr_type->opcode() != SpvOpTypePointer) {
+ if (opcode(ptr_type) != spv::Op::OpTypePointer) {
return Fail() << "OpVariable type expected to be a pointer: " << var.PrettyPrint();
}
const auto* store_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
- if (store_type->opcode() == SpvOpTypeStruct) {
+ if (opcode(store_type) == spv::Op::OpTypeStruct) {
struct_types_for_buffers_.insert(store_type->result_id());
} else {
Fail() << "WGSL does not support arrays of buffers: " << var.PrettyPrint();
@@ -1276,7 +1347,8 @@
// Manufacture a type for the gl_Position variable if we have to.
if ((builtin_position_.struct_type_id != 0) &&
(builtin_position_.position_member_pointer_type_id == 0)) {
- builtin_position_.position_member_pointer_type_id = type_mgr_->FindPointerToType(
+ builtin_position_.position_member_pointer_type_id = three_sided_patch::FindPointerToType(
+ type_mgr_, &spvtools::opt::analysis::TypeManager::FindPointerToType,
builtin_position_.position_member_type_id, builtin_position_.storage_class);
ConvertType(builtin_position_.position_member_pointer_type_id);
}
@@ -1290,13 +1362,13 @@
for (auto& inst : module_->types_values()) {
if (const auto* result_type = type_mgr_->GetType(inst.type_id())) {
if (result_type->AsPointer()) {
- switch (inst.opcode()) {
- case SpvOpVariable:
+ switch (opcode(inst)) {
+ case spv::Op::OpVariable:
// This is the only valid case.
break;
- case SpvOpUndef:
+ case spv::Op::OpUndef:
return Fail() << "undef pointer is not valid: " << inst.PrettyPrint();
- case SpvOpConstantNull:
+ case spv::Op::OpConstantNull:
return Fail() << "null pointer is not valid: " << inst.PrettyPrint();
default:
return Fail()
@@ -1319,15 +1391,15 @@
const Type* ast_type = nullptr;
ast::LiteralExpression* ast_expr = nullptr;
- switch (inst.opcode()) {
- case SpvOpSpecConstantTrue:
- case SpvOpSpecConstantFalse: {
+ switch (opcode(inst)) {
+ case spv::Op::OpSpecConstantTrue:
+ case spv::Op::OpSpecConstantFalse: {
ast_type = ConvertType(inst.type_id());
ast_expr = create<ast::BoolLiteralExpression>(
- Source{}, inst.opcode() == SpvOpSpecConstantTrue);
+ Source{}, opcode(inst) == spv::Op::OpSpecConstantTrue);
break;
}
- case SpvOpSpecConstant: {
+ case spv::Op::OpSpecConstant: {
ast_type = ConvertType(inst.type_id());
const uint32_t literal_value = inst.GetSingleWordInOperand(0);
ast_expr = Switch(
@@ -1362,7 +1434,7 @@
if (ast_type && ast_expr) {
AttributeList spec_id_decos;
for (const auto& deco : GetDecorationsFor(inst.result_id())) {
- if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
+ if ((deco.size() == 2) && (deco[0] == uint32_t(spv::Decoration::SpecId))) {
const uint32_t id = deco[1];
if (id > 65535) {
return Fail() << "SpecId too large. WGSL override IDs must be "
@@ -1430,16 +1502,16 @@
return false;
}
for (const auto& type_or_value : module_->types_values()) {
- if (type_or_value.opcode() != SpvOpVariable) {
+ if (opcode(type_or_value) != spv::Op::OpVariable) {
continue;
}
const auto& var = type_or_value;
- const auto spirv_storage_class = SpvStorageClass(var.GetSingleWordInOperand(0));
+ const auto spirv_storage_class = spv::StorageClass(var.GetSingleWordInOperand(0));
uint32_t type_id = var.type_id();
if ((type_id == builtin_position_.pointer_type_id) &&
- ((spirv_storage_class == SpvStorageClassInput) ||
- (spirv_storage_class == SpvStorageClassOutput))) {
+ ((spirv_storage_class == spv::StorageClass::Input) ||
+ (spirv_storage_class == spv::StorageClass::Output))) {
// Skip emitting gl_PerVertex.
builtin_position_.per_vertex_var_id = var.result_id();
builtin_position_.per_vertex_var_init_id =
@@ -1464,7 +1536,7 @@
return false;
}
const Type* ast_type = nullptr;
- if (spirv_storage_class == SpvStorageClassUniformConstant) {
+ if (spirv_storage_class == spv::StorageClass::UniformConstant) {
// These are opaque handles: samplers or textures
ast_type = GetTypeForHandleVar(var);
if (!ast_type) {
@@ -1509,9 +1581,9 @@
if (builtin_position_.per_vertex_var_init_id) {
// The initializer is complex.
const auto* init = def_use_mgr_->GetDef(builtin_position_.per_vertex_var_init_id);
- switch (init->opcode()) {
- case SpvOpConstantComposite:
- case SpvOpSpecConstantComposite:
+ switch (opcode(init)) {
+ case spv::Op::OpConstantComposite:
+ case spv::Op::OpSpecConstantComposite:
ast_initializer =
MakeConstantExpression(
init->GetSingleWordInOperand(builtin_position_.position_member_index))
@@ -1541,15 +1613,15 @@
// @returns the IntConstant for the size of the array, or nullptr
const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(uint32_t var_id) {
auto* var = def_use_mgr_->GetDef(var_id);
- if (!var || var->opcode() != SpvOpVariable) {
+ if (!var || opcode(var) != spv::Op::OpVariable) {
return nullptr;
}
auto* ptr_type = def_use_mgr_->GetDef(var->type_id());
- if (!ptr_type || ptr_type->opcode() != SpvOpTypePointer) {
+ if (!ptr_type || opcode(ptr_type) != spv::Op::OpTypePointer) {
return nullptr;
}
auto* array_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
- if (!array_type || array_type->opcode() != SpvOpTypeArray) {
+ if (!array_type || opcode(array_type) != spv::Op::OpTypeArray) {
return nullptr;
}
auto* size = constant_mgr_->FindDeclaredConstant(array_type->GetSingleWordInOperand(1));
@@ -1632,23 +1704,23 @@
if (deco.empty()) {
return Fail() << "malformed decoration on ID " << id << ": it is empty";
}
- if (deco[0] == SpvDecorationBuiltIn) {
+ if (deco[0] == uint32_t(spv::Decoration::BuiltIn)) {
if (deco.size() == 1) {
return Fail() << "malformed BuiltIn decoration on ID " << id << ": has no operand";
}
- const auto spv_builtin = static_cast<SpvBuiltIn>(deco[1]);
+ const auto spv_builtin = static_cast<spv::BuiltIn>(deco[1]);
switch (spv_builtin) {
- case SpvBuiltInPointSize:
+ case spv::BuiltIn::PointSize:
special_builtins_[id] = spv_builtin;
return false; // This is not an error
- case SpvBuiltInSampleId:
- case SpvBuiltInVertexIndex:
- case SpvBuiltInInstanceIndex:
- case SpvBuiltInLocalInvocationId:
- case SpvBuiltInLocalInvocationIndex:
- case SpvBuiltInGlobalInvocationId:
- case SpvBuiltInWorkgroupId:
- case SpvBuiltInNumWorkgroups:
+ case spv::BuiltIn::SampleId:
+ case spv::BuiltIn::VertexIndex:
+ case spv::BuiltIn::InstanceIndex:
+ case spv::BuiltIn::LocalInvocationId:
+ case spv::BuiltIn::LocalInvocationIndex:
+ case spv::BuiltIn::GlobalInvocationId:
+ case spv::BuiltIn::WorkgroupId:
+ case spv::BuiltIn::NumWorkgroups:
// The SPIR-V variable may signed (because GLSL requires signed for
// some of these), but WGSL requires unsigned. Handle specially
// so we always perform the conversion at load and store.
@@ -1660,7 +1732,7 @@
}
}
break;
- case SpvBuiltInSampleMask: {
+ case spv::BuiltIn::SampleMask: {
// In SPIR-V this is used for both input and output variable.
// The SPIR-V variable has store type of array of integer scalar,
// either signed or unsigned.
@@ -1691,14 +1763,14 @@
if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
non_builtin_pipeline_decorations.push_back(deco);
}
- if (deco[0] == SpvDecorationDescriptorSet) {
+ if (deco[0] == uint32_t(spv::Decoration::DescriptorSet)) {
if (deco.size() == 1) {
return Fail() << "malformed DescriptorSet decoration on ID " << id
<< ": has no operand";
}
decorations->Push(builder_.Group(Source{}, AInt(deco[1])));
}
- if (deco[0] == SpvDecorationBinding) {
+ if (deco[0] == uint32_t(spv::Decoration::Binding)) {
if (deco.size() == 1) {
return Fail() << "malformed Binding decoration on ID " << id << ": has no operand";
}
@@ -1756,8 +1828,8 @@
for (const auto& deco : decorations) {
TINT_ASSERT(Reader, deco.size() > 0);
- switch (deco[0]) {
- case SpvDecorationLocation:
+ switch (static_cast<spv::Decoration>(deco[0])) {
+ case spv::Decoration::Location:
if (deco.size() != 2) {
return Fail() << "malformed Location decoration on ID requires one "
"literal operand";
@@ -1768,24 +1840,24 @@
type = ast::InterpolationType::kFlat;
}
break;
- case SpvDecorationFlat:
+ case spv::Decoration::Flat:
type = ast::InterpolationType::kFlat;
break;
- case SpvDecorationNoPerspective:
+ case spv::Decoration::NoPerspective:
if (store_type->IsIntegerScalarOrVector()) {
// This doesn't capture the array or struct case.
return Fail() << "NoPerspective is invalid on integral IO";
}
type = ast::InterpolationType::kLinear;
break;
- case SpvDecorationCentroid:
+ case spv::Decoration::Centroid:
if (store_type->IsIntegerScalarOrVector()) {
// This doesn't capture the array or struct case.
return Fail() << "Centroid interpolation sampling is invalid on integral IO";
}
sampling = ast::InterpolationSampling::kCentroid;
break;
- case SpvDecorationSample:
+ case spv::Decoration::Sample:
if (store_type->IsIntegerScalarOrVector()) {
// This doesn't capture the array or struct case.
return Fail() << "Sample interpolation sampling is invalid on integral IO";
@@ -1801,7 +1873,7 @@
!ast::HasAttribute<ast::LocationAttribute>(*attributes)) {
// WGSL requires that '@interpolate(flat)' needs to be paired with '@location', however
// SPIR-V requires all fragment shader integer Inputs are 'flat'. If the decorations do not
- // contain a SpvDecorationLocation, then make this perspective.
+ // contain a spv::Decoration::Location, then make this perspective.
type = ast::InterpolationType::kPerspective;
}
@@ -1825,7 +1897,7 @@
if (!inst) {
return false;
}
- if (inst->opcode() == SpvOpUndef) {
+ if (opcode(inst) == spv::Op::OpUndef) {
return true;
}
return nullptr != constant_mgr_->FindDeclaredConstant(id);
@@ -1880,13 +1952,13 @@
return {};
}
- switch (inst->opcode()) {
- case SpvOpUndef: // Remap undef to null.
- case SpvOpConstantNull:
+ switch (opcode(inst)) {
+ case spv::Op::OpUndef: // Remap undef to null.
+ case spv::Op::OpConstantNull:
return {original_ast_type, MakeNullValue(original_ast_type)};
- case SpvOpConstantTrue:
- case SpvOpConstantFalse:
- case SpvOpConstant: {
+ case spv::Op::OpConstantTrue:
+ case spv::Op::OpConstantFalse:
+ case spv::Op::OpConstant: {
const auto* spirv_const = constant_mgr_->FindDeclaredConstant(id);
if (spirv_const == nullptr) {
Fail() << "ID " << id << " is not a constant";
@@ -1895,7 +1967,7 @@
return MakeConstantExpressionForScalarSpirvConstant(source, original_ast_type,
spirv_const);
}
- case SpvOpConstantComposite: {
+ case spv::Op::OpConstantComposite: {
// Handle vector, matrix, array, and struct
// Generate a composite from explicit components.
@@ -2047,9 +2119,9 @@
requires_signed = AssumesSignedOperands(extended_opcode);
requires_unsigned = AssumesUnsignedOperands(extended_opcode);
} else {
- const auto opcode = inst.opcode();
- requires_signed = AssumesSignedOperands(opcode);
- requires_unsigned = AssumesUnsignedOperands(opcode);
+ const auto op = opcode(inst);
+ requires_signed = AssumesSignedOperands(op);
+ requires_unsigned = AssumesUnsignedOperands(op);
}
if (!requires_signed && !requires_unsigned) {
// No conversion is required, assuming our tables are complete.
@@ -2087,7 +2159,7 @@
TypedExpression&& second_operand_expr) {
const Type* target_type = first_operand_type->UnwrapRef();
if ((target_type != second_operand_expr.type->UnwrapRef()) &&
- AssumesSecondOperandSignednessMatchesFirstOperand(inst.opcode())) {
+ AssumesSecondOperandSignednessMatchesFirstOperand(opcode(inst))) {
// Conversion is required.
return {target_type, create<ast::BitcastExpression>(Source{}, target_type->Build(builder_),
second_operand_expr.expr)};
@@ -2099,8 +2171,8 @@
const Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
const Type* first_operand_type) {
first_operand_type = first_operand_type->UnwrapRef();
- const auto opcode = inst.opcode();
- if (AssumesResultSignednessMatchesFirstOperand(opcode)) {
+ const auto op = opcode(inst);
+ if (AssumesResultSignednessMatchesFirstOperand(op)) {
return first_operand_type;
}
if (IsGlslExtendedInstruction(inst)) {
@@ -2239,36 +2311,36 @@
if (inst == nullptr) {
return local_fail();
}
- switch (inst->opcode()) {
- case SpvOpFunctionParameter:
- case SpvOpVariable:
+ switch (opcode(inst)) {
+ case spv::Op::OpFunctionParameter:
+ case spv::Op::OpVariable:
// We found the memory object declaration.
// Remember it as the answer for the whole path.
for (auto iter : visited) {
memo_table[iter] = inst;
}
return inst;
- case SpvOpLoad:
+ case spv::Op::OpLoad:
// Follow the pointer being loaded
id = inst->GetSingleWordInOperand(0);
break;
- case SpvOpCopyObject:
+ case spv::Op::OpCopyObject:
// Follow the object being copied.
id = inst->GetSingleWordInOperand(0);
break;
- case SpvOpAccessChain:
- case SpvOpInBoundsAccessChain:
- case SpvOpPtrAccessChain:
- case SpvOpInBoundsPtrAccessChain:
+ case spv::Op::OpAccessChain:
+ case spv::Op::OpInBoundsAccessChain:
+ case spv::Op::OpPtrAccessChain:
+ case spv::Op::OpInBoundsPtrAccessChain:
// Follow the base pointer.
id = inst->GetSingleWordInOperand(0);
break;
- case SpvOpSampledImage:
+ case spv::Op::OpSampledImage:
// Follow the image or the sampler, depending on the follow_image
// parameter.
id = inst->GetSingleWordInOperand(follow_image ? 0 : 1);
break;
- case SpvOpImage:
+ case spv::Op::OpImage:
// Follow the sampled image
id = inst->GetSingleWordInOperand(0);
break;
@@ -2300,7 +2372,7 @@
// Get the SPIR-V handle type.
const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
- if (!ptr_type || (ptr_type->opcode() != SpvOpTypePointer)) {
+ if (!ptr_type || (opcode(ptr_type) != spv::Op::OpTypePointer)) {
Fail() << "Invalid type for variable or function parameter " << var.PrettyPrint();
return nullptr;
}
@@ -2309,18 +2381,18 @@
Fail() << "Invalid pointer type for variable or function parameter " << var.PrettyPrint();
return nullptr;
}
- switch (raw_handle_type->opcode()) {
- case SpvOpTypeSampler:
- case SpvOpTypeImage:
+ switch (opcode(raw_handle_type)) {
+ case spv::Op::OpTypeSampler:
+ case spv::Op::OpTypeImage:
// The expected cases.
break;
- case SpvOpTypeArray:
- case SpvOpTypeRuntimeArray:
+ case spv::Op::OpTypeArray:
+ case spv::Op::OpTypeRuntimeArray:
Fail() << "arrays of textures or samplers are not supported in WGSL; can't "
"translate variable or function parameter: "
<< var.PrettyPrint();
return nullptr;
- case SpvOpTypeSampledImage:
+ case spv::Op::OpTypeSampledImage:
Fail() << "WGSL does not support combined image-samplers: " << var.PrettyPrint();
return nullptr;
default:
@@ -2358,7 +2430,7 @@
// In SPIR-V you could statically reference a texture or sampler without
// using it in a way that gives us a clue on how to declare it. Look inside
// the store type to infer a usage.
- if (raw_handle_type->opcode() == SpvOpTypeSampler) {
+ if (opcode(raw_handle_type) == spv::Op::OpTypeSampler) {
usage.AddSampler();
} else {
// It's a texture.
@@ -2370,7 +2442,7 @@
const auto sampled_param = raw_handle_type->GetSingleWordInOperand(5);
const auto format_param = raw_handle_type->GetSingleWordInOperand(6);
// Only storage images have a format.
- if ((format_param != SpvImageFormatUnknown) ||
+ if ((format_param != uint32_t(spv::ImageFormat::Unknown)) ||
sampled_param == 2 /* without sampler */) {
// Get NonWritable and NonReadable attributes of the variable.
bool is_nonwritable = false;
@@ -2379,10 +2451,10 @@
if (deco.size() != 1) {
continue;
}
- if (deco[0] == SpvDecorationNonWritable) {
+ if (deco[0] == uint32_t(spv::Decoration::NonWritable)) {
is_nonwritable = true;
}
- if (deco[0] == SpvDecorationNonReadable) {
+ if (deco[0] == uint32_t(spv::Decoration::NonReadable)) {
is_nonreadable = true;
}
}
@@ -2429,9 +2501,9 @@
if (image_type->is_arrayed()) {
// Give a nicer error message here, where we have the offending variable
// in hand, rather than inside the enum converter.
- switch (image_type->dim()) {
- case SpvDim2D:
- case SpvDimCube:
+ switch (static_cast<spv::Dim>(image_type->dim())) {
+ case spv::Dim::Dim2D:
+ case spv::Dim::Cube:
break;
default:
Fail() << "WGSL arrayed textures must be 2d_array or cube_array: "
@@ -2450,7 +2522,7 @@
// WGSL textures are always formatted. Unformatted textures are always
// sampled.
if (usage.IsSampledTexture() || usage.IsStorageReadTexture() ||
- (image_type->format() == SpvImageFormatUnknown)) {
+ (uint32_t(image_type->format()) == uint32_t(spv::ImageFormat::Unknown))) {
// Make a sampled texture type.
auto* ast_sampled_component_type =
ConvertType(raw_handle_type->GetSingleWordInOperand(0));
@@ -2607,34 +2679,34 @@
for (const auto* f : topologically_ordered_functions_) {
for (const auto& bb : *f) {
for (const auto& inst : bb) {
- switch (inst.opcode()) {
+ switch (opcode(inst)) {
// Single texel reads and writes
- case SpvOpImageRead:
+ case spv::Op::OpImageRead:
handle_usage_[get_image(inst)].AddStorageReadTexture();
break;
- case SpvOpImageWrite:
+ case spv::Op::OpImageWrite:
handle_usage_[get_image(inst)].AddStorageWriteTexture();
break;
- case SpvOpImageFetch:
+ case spv::Op::OpImageFetch:
handle_usage_[get_image(inst)].AddSampledTexture();
break;
// Sampling and gathering from a sampled image.
- case SpvOpImageSampleImplicitLod:
- case SpvOpImageSampleExplicitLod:
- case SpvOpImageSampleProjImplicitLod:
- case SpvOpImageSampleProjExplicitLod:
- case SpvOpImageGather:
+ case spv::Op::OpImageSampleImplicitLod:
+ case spv::Op::OpImageSampleExplicitLod:
+ case spv::Op::OpImageSampleProjImplicitLod:
+ case spv::Op::OpImageSampleProjExplicitLod:
+ case spv::Op::OpImageGather:
handle_usage_[get_image(inst)].AddSampledTexture();
handle_usage_[get_sampler(inst)].AddSampler();
break;
- case SpvOpImageSampleDrefImplicitLod:
- case SpvOpImageSampleDrefExplicitLod:
- case SpvOpImageSampleProjDrefImplicitLod:
- case SpvOpImageSampleProjDrefExplicitLod:
- case SpvOpImageDrefGather:
+ case spv::Op::OpImageSampleDrefImplicitLod:
+ case spv::Op::OpImageSampleDrefExplicitLod:
+ case spv::Op::OpImageSampleProjDrefImplicitLod:
+ case spv::Op::OpImageSampleProjDrefExplicitLod:
+ case spv::Op::OpImageDrefGather:
// Depth reference access implies usage as a depth texture, which
// in turn is a sampled texture.
handle_usage_[get_image(inst)].AddDepthTexture();
@@ -2643,29 +2715,29 @@
// Image queries
- case SpvOpImageQuerySizeLod:
+ case spv::Op::OpImageQuerySizeLod:
// Vulkan requires Sampled=1 for this. SPIR-V already requires MS=0.
handle_usage_[get_image(inst)].AddSampledTexture();
break;
- case SpvOpImageQuerySize:
+ case spv::Op::OpImageQuerySize:
// Applies to either MS=1 or Sampled=0 or 2.
// So we can't force it to be multisampled, or storage image.
break;
- case SpvOpImageQueryLod:
+ case spv::Op::OpImageQueryLod:
handle_usage_[get_image(inst)].AddSampledTexture();
handle_usage_[get_sampler(inst)].AddSampler();
break;
- case SpvOpImageQueryLevels:
+ case spv::Op::OpImageQueryLevels:
// We can't tell anything more than that it's an image.
handle_usage_[get_image(inst)].AddTexture();
break;
- case SpvOpImageQuerySamples:
+ case spv::Op::OpImageQuerySamples:
handle_usage_[get_image(inst)].AddMultisampledTexture();
break;
// Function calls
- case SpvOpFunctionCall: {
+ case spv::Op::OpFunctionCall: {
// Propagate handle usages from callee function formal parameters to
// the matching caller parameters. This is where we rely on the
// fact that callees have been processed earlier in the flow.
diff --git a/src/tint/reader/spirv/parser_impl.h b/src/tint/reader/spirv/parser_impl.h
index 9965aa4..6e79ecc 100644
--- a/src/tint/reader/spirv/parser_impl.h
+++ b/src/tint/reader/spirv/parser_impl.h
@@ -66,8 +66,8 @@
/// The binary representation of a SPIR-V decoration enum followed by its
/// operands, if any.
-/// Example: { SpvDecorationBlock }
-/// Example: { SpvDecorationArrayStride, 16 }
+/// Example: { spv::Decoration::Block }
+/// Example: { spv::Decoration::ArrayStride, 16 }
using Decoration = std::vector<uint32_t>;
/// DecorationList is a list of decorations
@@ -338,13 +338,13 @@
/// Returns true when the given instruction is an extended instruction
/// for GLSL.std.450.
/// @param inst a SPIR-V instruction
- /// @returns true if its an SpvOpExtInst for GLSL.std.450
+ /// @returns true if its an spv::Op::ExtInst for GLSL.std.450
bool IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const;
/// Returns true when the given instruction is an extended instruction
/// from an ignored extended instruction set.
/// @param inst a SPIR-V instruction
- /// @returns true if its an SpvOpExtInst for an ignored extended instruction
+ /// @returns true if its an spv::Op::ExtInst for an ignored extended instruction
bool IsIgnoredExtendedInstruction(const spvtools::opt::Instruction& inst) const;
/// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
@@ -585,7 +585,7 @@
/// class class.
uint32_t pointer_type_id = 0;
/// The SPIR-V address space.
- SpvStorageClass storage_class = SpvStorageClassOutput;
+ spv::StorageClass storage_class = spv::StorageClass::Output;
/// The ID of the type of a pointer to the Position member.
uint32_t position_member_pointer_type_id = 0;
/// The ID of the gl_PerVertex variable, if it was declared.
@@ -690,7 +690,7 @@
const spvtools::opt::Instruction* GetInstructionForTest(uint32_t id) const;
/// A map of SPIR-V identifiers to builtins
- using BuiltInsMap = std::unordered_map<uint32_t, SpvBuiltIn>;
+ using BuiltInsMap = std::unordered_map<uint32_t, spv::BuiltIn>;
/// @returns a map of builtins that should be handled specially by code
/// generation. Either the builtin does not exist in WGSL, or a type
@@ -699,7 +699,7 @@
/// @param builtin the SPIR-V builtin variable kind
/// @returns the SPIR-V ID for the variable defining the given builtin, or 0
- uint32_t IdForSpecialBuiltIn(SpvBuiltIn builtin) const {
+ uint32_t IdForSpecialBuiltIn(spv::BuiltIn builtin) const {
// Do a linear search.
for (const auto& entry : special_builtins_) {
if (entry.second == builtin) {
diff --git a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
index 767b333..402cc41 100644
--- a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
+++ b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
@@ -31,7 +31,7 @@
TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithoutOperand) {
auto p = parser(std::vector<uint32_t>{});
- auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset});
+ auto result = p->ConvertMemberDecoration(12, 13, nullptr, {uint32_t(spv::Decoration::Offset)});
EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 0: member 13 of SPIR-V type 12"));
@@ -40,7 +40,8 @@
TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithTooManyOperands) {
auto p = parser(std::vector<uint32_t>{});
- auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4});
+ auto result =
+ p->ConvertMemberDecoration(12, 13, nullptr, {uint32_t(spv::Decoration::Offset), 3, 4});
EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 2: member 13 of SPIR-V type 12"));
@@ -49,7 +50,7 @@
TEST_F(SpvParserTest, ConvertMemberDecoration_Offset) {
auto p = parser(std::vector<uint32_t>{});
- auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8});
+ auto result = p->ConvertMemberDecoration(1, 1, nullptr, {uint32_t(spv::Decoration::Offset), 8});
ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
@@ -64,7 +65,8 @@
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2);
- auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 8});
EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
@@ -74,7 +76,8 @@
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2);
- auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 16});
ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
@@ -88,7 +91,8 @@
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4);
- auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 16});
EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
@@ -98,7 +102,8 @@
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4);
- auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 64});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 64});
ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
@@ -112,7 +117,8 @@
spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 3);
- auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 32});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, &matrix, {uint32_t(spv::Decoration::MatrixStride), 32});
ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>();
@@ -127,7 +133,8 @@
// relaxed precision f32.
auto p = parser(std::vector<uint32_t>{});
- auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationRelaxedPrecision});
+ auto result =
+ p->ConvertMemberDecoration(1, 1, nullptr, {uint32_t(spv::Decoration::RelaxedPrecision)});
EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty());
}
diff --git a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
index 929ab1f..cbc384f 100644
--- a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
+++ b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
@@ -52,7 +52,7 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(10);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationBlock}));
+ EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::Block)}));
EXPECT_TRUE(p->error().empty());
p->SkipDumpingPending(kSkipReason);
}
@@ -66,7 +66,7 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(10);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationBlock}));
+ EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::Block)}));
EXPECT_TRUE(p->error().empty());
p->SkipDumpingPending(kSkipReason);
}
@@ -80,8 +80,9 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
auto decorations = p->GetDecorationsFor(5);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision},
- Decoration{SpvDecorationLocation, 7}));
+ EXPECT_THAT(decorations,
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)},
+ Decoration{uint32_t(spv::Decoration::Location), 7}));
EXPECT_TRUE(p->error().empty());
p->SkipDumpingPending(kSkipReason);
}
@@ -124,7 +125,8 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
auto decorations = p->GetDecorationsForMember(10, 0);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+ EXPECT_THAT(decorations,
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)}));
EXPECT_TRUE(p->error().empty());
p->SkipDumpingPending(kSkipReason);
}
@@ -138,7 +140,8 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
auto decorations = p->GetDecorationsForMember(10, 0);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+ EXPECT_THAT(decorations,
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)}));
EXPECT_TRUE(p->error().empty());
p->SkipDumpingPending(kSkipReason);
}
@@ -154,7 +157,8 @@
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
auto decorations = p->GetDecorationsForMember(10, 1);
- EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12}));
+ EXPECT_THAT(decorations,
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::ArrayStride), 12}));
EXPECT_TRUE(p->error().empty());
}
@@ -179,11 +183,11 @@
EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
EXPECT_THAT(p->GetDecorationsForMember(50, 1),
- UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::RelaxedPrecision)}));
EXPECT_THAT(p->GetDecorationsForMember(50, 2),
- UnorderedElementsAre(Decoration{SpvDecorationColMajor},
- Decoration{SpvDecorationMatrixStride, 8},
- Decoration{SpvDecorationArrayStride, 16}));
+ UnorderedElementsAre(Decoration{uint32_t(spv::Decoration::ColMajor)},
+ Decoration{uint32_t(spv::Decoration::MatrixStride), 8},
+ Decoration{uint32_t(spv::Decoration::ArrayStride), 16}));
EXPECT_TRUE(p->error().empty());
}
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index 976706a..398c123 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -615,12 +615,11 @@
Source source;
if (match(Token::Type::kConst)) {
use = "'const' declaration";
- } else if (match(Token::Type::kLet, &source)) {
- use = "'let' declaration";
- deprecated(source, "module-scope 'let' has been replaced with 'const'");
} else if (match(Token::Type::kOverride)) {
use = "'override' declaration";
is_overridable = true;
+ } else if (match(Token::Type::kLet, &source)) {
+ return add_error(source, "module-scope 'let' is invalid, use 'const'");
} else {
return Failure::kNoMatch;
}
@@ -1613,29 +1612,6 @@
std::move(attrs.value)); // attributes
}
-// pipeline_stage
-// : VERTEX
-// | FRAGMENT
-// | COMPUTE
-//
-// TODO(crbug.com/tint/1503): Remove when deprecation period is over.
-Expect<ast::PipelineStage> ParserImpl::expect_pipeline_stage() {
- auto& t = peek();
- if (t == "vertex") {
- next(); // Consume the peek
- return {ast::PipelineStage::kVertex, t.source()};
- }
- if (t == "fragment") {
- next(); // Consume the peek
- return {ast::PipelineStage::kFragment, t.source()};
- }
- if (t == "compute") {
- next(); // Consume the peek
- return {ast::PipelineStage::kCompute, t.source()};
- }
- return add_error(peek(), "invalid value for stage attribute");
-}
-
// interpolation_sample_name
// : 'center'
// | 'centroid'
@@ -3637,34 +3613,6 @@
});
}
- // TODO(crbug.com/tint/1503): Remove when deprecation period is over.
- if (t == "stage") {
- return expect_paren_block("stage attribute", [&]() -> Result {
- auto stage = expect_pipeline_stage();
- if (stage.errored) {
- return Failure::kErrored;
- }
-
- std::string warning = "remove stage and use @";
- switch (stage.value) {
- case ast::PipelineStage::kVertex:
- warning += "vertex";
- break;
- case ast::PipelineStage::kFragment:
- warning += "fragment";
- break;
- case ast::PipelineStage::kCompute:
- warning += "compute";
- break;
- case ast::PipelineStage::kNone:
- break;
- }
- deprecated(t.source(), warning);
-
- return create<ast::StageAttribute>(t.source(), stage.value);
- });
- }
-
if (t == "vertex") {
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
}
@@ -3826,7 +3774,7 @@
next();
if (is_reserved(t)) {
- deprecated(t.source(), "'" + t.to_str() + "' is a reserved keyword");
+ return add_error(t.source(), "'" + t.to_str() + "' is a reserved keyword");
}
return {t.to_str(), t.source()};
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index fbfe6f6..6c4f14a 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -351,48 +351,6 @@
)");
}
-// TODO(crbug.com/tint/1503): Remove this when @stage is removed
-TEST_F(ParserImplErrorTest, FunctionDeclStageMissingLParen) {
- EXPECT("@stage vertex) fn f() {}",
- R"(test.wgsl:1:8 error: expected '(' for stage attribute
-@stage vertex) fn f() {}
- ^^^^^^
-)");
-}
-
-TEST_F(ParserImplErrorTest, FunctionDeclStageMissingRParen) {
- EXPECT(
- "@stage(vertex fn f() {}",
- R"(test.wgsl:1:2 warning: use of deprecated language feature: remove stage and use @vertex
-@stage(vertex fn f() {}
- ^^^^^
-
-test.wgsl:1:15 error: expected ')' for stage attribute
-@stage(vertex fn f() {}
- ^^
-)");
-}
-
-TEST_F(ParserImplErrorTest, FunctionDeclStageInvalid) {
- EXPECT("@stage(x) fn f() {}",
- R"(test.wgsl:1:8 error: invalid value for stage attribute
-@stage(x) fn f() {}
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, FunctionDeclStageTypeInvalid) {
- EXPECT("@shader(vertex) fn main() {}",
- R"(test.wgsl:1:2 error: expected attribute
-@shader(vertex) fn main() {}
- ^^^^^^
-
-test.wgsl:1:8 error: unexpected token
-@shader(vertex) fn main() {}
- ^
-)");
-}
-
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeXInvalid) {
EXPECT("@workgroup_size() fn f() {}",
R"(test.wgsl:1:17 error: expected workgroup_size x parameter
@@ -595,94 +553,11 @@
)");
}
-TEST_F(ParserImplErrorTest, GlobalDeclLetInvalidIdentifier) {
- EXPECT(
- "let ^ : i32 = 1;",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let ^ : i32 = 1;
+TEST_F(ParserImplErrorTest, GlobalDeclLet) {
+ EXPECT("let a : i32 = 1;",
+ R"(test.wgsl:1:1 error: module-scope 'let' is invalid, use 'const'
+let a : i32 = 1;
^^^
-
-test.wgsl:1:5 error: expected identifier for 'let' declaration
-let ^ : i32 = 1;
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingSemicolon) {
- EXPECT(
- "let i : i32 = 1",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : i32 = 1
-^^^
-
-test.wgsl:1:16 error: expected ';' for 'const' declaration
-let i : i32 = 1
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingLParen) {
- EXPECT(
- "let i : vec2<i32> = vec2<i32>;",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>;
-^^^
-
-test.wgsl:1:30 error: expected '(' for type initializer
-let i : vec2<i32> = vec2<i32>;
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingRParen) {
- EXPECT(
- "let i : vec2<i32> = vec2<i32>(1., 2.;",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(1., 2.;
-^^^
-
-test.wgsl:1:37 error: expected ')' for type initializer
-let i : vec2<i32> = vec2<i32>(1., 2.;
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteral) {
- EXPECT(
- "let i : vec2<i32> = vec2<i32>(!);",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(!);
-^^^
-
-test.wgsl:1:32 error: unable to parse right side of ! expression
-let i : vec2<i32> = vec2<i32>(!);
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingLParen) {
- EXPECT(
- "let i : vec2<i32> = vec2<i32> 1, 2);",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32> 1, 2);
-^^^
-
-test.wgsl:1:31 error: expected '(' for type initializer
-let i : vec2<i32> = vec2<i32> 1, 2);
- ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingRParen) {
- EXPECT(
- "let i : vec2<i32> = vec2<i32>(1, 2;",
- R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(1, 2;
-^^^
-
-test.wgsl:1:35 error: expected ')' for type initializer
-let i : vec2<i32> = vec2<i32>(1, 2;
- ^
)");
}
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
index 28b84a9..785d23c 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
@@ -18,33 +18,6 @@
namespace tint::reader::wgsl {
namespace {
-// TODO(crbug.com/tint/1503): Remove this when @stage is removed
-TEST_F(ParserImplTest, AttributeList_Parses_Stage) {
- auto p = parser("@workgroup_size(2) @stage(compute)");
- auto attrs = p->attribute_list();
- EXPECT_FALSE(p->has_error()) << p->error();
- EXPECT_FALSE(attrs.errored);
- EXPECT_TRUE(attrs.matched);
- ASSERT_EQ(attrs.value.Length(), 2u);
-
- auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
- auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
- ASSERT_NE(attr_0, nullptr);
- ASSERT_NE(attr_1, nullptr);
-
- ASSERT_TRUE(attr_0->Is<ast::WorkgroupAttribute>());
- const ast::Expression* x = attr_0->As<ast::WorkgroupAttribute>()->x;
- ASSERT_NE(x, nullptr);
- auto* x_literal = x->As<ast::LiteralExpression>();
- ASSERT_NE(x_literal, nullptr);
- ASSERT_TRUE(x_literal->Is<ast::IntLiteralExpression>());
- EXPECT_EQ(x_literal->As<ast::IntLiteralExpression>()->value, 2);
- EXPECT_EQ(x_literal->As<ast::IntLiteralExpression>()->suffix,
- ast::IntLiteralExpression::Suffix::kNone);
- ASSERT_TRUE(attr_1->Is<ast::StageAttribute>());
- EXPECT_EQ(attr_1->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
-}
-
TEST_F(ParserImplTest, AttributeList_Parses) {
auto p = parser("@workgroup_size(2) @compute");
auto attrs = p->attribute_list();
@@ -81,14 +54,5 @@
EXPECT_EQ(p->error(), "1:2: expected attribute");
}
-TEST_F(ParserImplTest, AttributeList_BadAttribute) {
- auto p = parser("@stage()");
- auto attrs = p->attribute_list();
- EXPECT_TRUE(p->has_error());
- EXPECT_TRUE(attrs.errored);
- EXPECT_FALSE(attrs.matched);
- EXPECT_EQ(p->error(), "1:8: invalid value for stage attribute");
-}
-
} // namespace
} // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
index 60e8f86..186c86a 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
@@ -397,61 +397,6 @@
EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size attribute");
}
-// TODO(crbug.com/tint/1503): Remove when @stage is removed
-TEST_F(ParserImplTest, Attribute_Stage) {
- auto p = parser("stage(compute)");
- auto attr = p->attribute();
- EXPECT_TRUE(attr.matched);
- EXPECT_FALSE(attr.errored);
- ASSERT_NE(attr.value, nullptr) << p->error();
- ASSERT_FALSE(p->has_error());
- auto* func_attr = attr.value->As<ast::Attribute>();
- ASSERT_NE(func_attr, nullptr);
- ASSERT_TRUE(func_attr->Is<ast::StageAttribute>());
- EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
-}
-
-TEST_F(ParserImplTest, Attribute_Stage_MissingValue) {
- auto p = parser("stage()");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
-}
-
-TEST_F(ParserImplTest, Attribute_Stage_MissingInvalid) {
- auto p = parser("stage(nan)");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
-}
-
-TEST_F(ParserImplTest, Attribute_Stage_MissingLeftParen) {
- auto p = parser("stage compute)");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:7: expected '(' for stage attribute");
-}
-
-TEST_F(ParserImplTest, Attribute_Stage_MissingRightParen) {
- auto p = parser("stage(compute");
- auto attr = p->attribute();
- EXPECT_FALSE(attr.matched);
- EXPECT_TRUE(attr.errored);
- EXPECT_EQ(attr.value, nullptr);
- EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), R"(1:1: use of deprecated language feature: remove stage and use @compute
-1:14: expected ')' for stage attribute)");
-}
-
TEST_F(ParserImplTest, Attribute_Compute) {
auto p = parser("compute");
auto attr = p->attribute();
diff --git a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 86e4383..c465e4b 100644
--- a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -24,79 +24,10 @@
EXPECT_FALSE(attrs.errored);
EXPECT_FALSE(attrs.matched);
auto e = p->global_constant_decl(attrs.value);
- EXPECT_FALSE(p->has_error()) << p->error();
- EXPECT_TRUE(e.matched);
- EXPECT_FALSE(e.errored);
- auto* const_ = e.value->As<ast::Const>();
- ASSERT_NE(const_, nullptr);
-
- EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
- ASSERT_NE(const_->type, nullptr);
- EXPECT_TRUE(const_->type->Is<ast::F32>());
-
- EXPECT_EQ(const_->source.range.begin.line, 1u);
- EXPECT_EQ(const_->source.range.begin.column, 5u);
- EXPECT_EQ(const_->source.range.end.line, 1u);
- EXPECT_EQ(const_->source.range.end.column, 6u);
-
- ASSERT_NE(const_->initializer, nullptr);
- EXPECT_TRUE(const_->initializer->Is<ast::LiteralExpression>());
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_Inferred) {
- auto p = parser("let a = 1.");
- auto attrs = p->attribute_list();
- EXPECT_FALSE(attrs.errored);
- EXPECT_FALSE(attrs.matched);
- auto e = p->global_constant_decl(attrs.value);
- EXPECT_FALSE(p->has_error()) << p->error();
- EXPECT_TRUE(e.matched);
- EXPECT_FALSE(e.errored);
- auto* const_ = e.value->As<ast::Const>();
- ASSERT_NE(const_, nullptr);
-
- EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
- EXPECT_EQ(const_->type, nullptr);
-
- EXPECT_EQ(const_->source.range.begin.line, 1u);
- EXPECT_EQ(const_->source.range.begin.column, 5u);
- EXPECT_EQ(const_->source.range.end.line, 1u);
- EXPECT_EQ(const_->source.range.end.column, 6u);
-
- ASSERT_NE(const_->initializer, nullptr);
- EXPECT_TRUE(const_->initializer->Is<ast::LiteralExpression>());
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_InvalidExpression) {
- auto p = parser("let a : f32 = if (a) {}");
- auto attrs = p->attribute_list();
- EXPECT_FALSE(attrs.errored);
- EXPECT_FALSE(attrs.matched);
- auto e = p->global_constant_decl(attrs.value);
EXPECT_TRUE(p->has_error());
- EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
- EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(
- p->error(),
- R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:15: missing initializer for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_MissingExpression) {
- auto p = parser("let a : f32 =");
- auto attrs = p->attribute_list();
- EXPECT_FALSE(attrs.errored);
- EXPECT_FALSE(attrs.matched);
- auto e = p->global_constant_decl(attrs.value);
- EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
- EXPECT_FALSE(e.matched);
- EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(
- p->error(),
- R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:14: missing initializer for 'let' declaration)");
+ EXPECT_EQ(p->error(), "1:1: module-scope 'let' is invalid, use 'const'");
}
TEST_F(ParserImplTest, GlobalConstDecl) {
diff --git a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index 6c943c8..2f124d5 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -58,44 +58,11 @@
TEST_F(ParserImplTest, GlobalDecl_GlobalLet) {
auto p = parser("let a : i32 = 2;");
- p->global_decl();
- ASSERT_FALSE(p->has_error()) << p->error();
-
- auto program = p->program();
- ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
-
- auto* v = program.AST().GlobalVariables()[0];
- EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingInitializer) {
- auto p = parser("let a : vec2<i32>;");
- p->global_decl();
- ASSERT_TRUE(p->has_error());
- EXPECT_EQ(
- p->error(),
- R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:18: expected '=' for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_Invalid) {
- auto p = parser("let a : vec2<i32> 1.0;");
- p->global_decl();
- ASSERT_TRUE(p->has_error());
- EXPECT_EQ(
- p->error(),
- R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:19: expected '=' for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingSemicolon) {
- auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
- p->global_decl();
- ASSERT_TRUE(p->has_error());
- EXPECT_EQ(
- p->error(),
- R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:36: expected ';' for 'const' declaration)");
+ auto e = p->global_decl();
+ EXPECT_TRUE(p->has_error());
+ EXPECT_FALSE(e.matched);
+ EXPECT_TRUE(e.errored);
+ EXPECT_EQ(p->error(), "1:1: module-scope 'let' is invalid, use 'const'");
}
TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
diff --git a/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc b/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
deleted file mode 100644
index 3c730e2..0000000
--- a/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 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/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-struct PipelineStageData {
- std::string input;
- ast::PipelineStage result;
-};
-inline std::ostream& operator<<(std::ostream& out, PipelineStageData data) {
- return out << data.input;
-}
-
-class PipelineStageTest : public ParserImplTestWithParam<PipelineStageData> {};
-
-TEST_P(PipelineStageTest, Parses) {
- auto params = GetParam();
- auto p = parser(params.input);
-
- auto stage = p->expect_pipeline_stage();
- ASSERT_FALSE(p->has_error()) << p->error();
- ASSERT_FALSE(stage.errored);
- EXPECT_EQ(stage.value, params.result);
- EXPECT_EQ(stage.source.range.begin.line, 1u);
- EXPECT_EQ(stage.source.range.begin.column, 1u);
- EXPECT_EQ(stage.source.range.end.line, 1u);
- EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size());
-
- auto& t = p->next();
- EXPECT_TRUE(t.IsEof());
-}
-INSTANTIATE_TEST_SUITE_P(
- ParserImplTest,
- PipelineStageTest,
- testing::Values(PipelineStageData{"vertex", ast::PipelineStage::kVertex},
- PipelineStageData{"fragment", ast::PipelineStage::kFragment},
- PipelineStageData{"compute", ast::PipelineStage::kCompute}));
-
-TEST_F(ParserImplTest, PipelineStage_NoMatch) {
- auto p = parser("not-a-stage");
- auto stage = p->expect_pipeline_stage();
- ASSERT_TRUE(p->has_error());
- ASSERT_TRUE(stage.errored);
- ASSERT_EQ(p->error(), "1:1: invalid value for stage attribute");
-}
-
-} // namespace
-} // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
index 0ad3cc1..8e178ab 100644
--- a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -21,74 +21,67 @@
TEST_P(ParserImplReservedKeywordTest, Function) {
auto name = GetParam();
auto p = parser("fn " + name + "() {}");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:4: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:4: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, ModuleConst) {
auto name = GetParam();
auto p = parser("const " + name + " : i32 = 1;");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:7: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:7: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, ModuleVar) {
auto name = GetParam();
auto p = parser("var " + name + " : i32 = 1;");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:5: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionLet) {
auto name = GetParam();
auto p = parser("fn f() { let " + name + " : i32 = 1; }");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:14: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionVar) {
auto name = GetParam();
auto p = parser("fn f() { var " + name + " : i32 = 1; }");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:14: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, FunctionParam) {
auto name = GetParam();
auto p = parser("fn f(" + name + " : i32) {}");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:6: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, Struct) {
auto name = GetParam();
auto p = parser("struct " + name + " {};");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:8: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), R"(1:8: ')" + name + R"(' is a reserved keyword
+1:)" + std::to_string(9 + name.length()) +
+ R"(: statement found outside of function body)");
}
TEST_P(ParserImplReservedKeywordTest, StructMember) {
auto name = GetParam();
auto p = parser("struct S { " + name + " : i32, };");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:12: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:12: '" + name + "' is a reserved keyword");
}
TEST_P(ParserImplReservedKeywordTest, Alias) {
auto name = GetParam();
auto p = parser("type " + name + " = i32;");
- EXPECT_TRUE(p->Parse());
- EXPECT_FALSE(p->has_error());
- EXPECT_EQ(p->error(),
- "1:6: use of deprecated language feature: '" + name + "' is a reserved keyword");
+ EXPECT_FALSE(p->Parse());
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
}
INSTANTIATE_TEST_SUITE_P(ParserImplReservedKeywordTest,
ParserImplReservedKeywordTest,
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index c3911fb..3d8a4db 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -748,7 +748,7 @@
EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
)");
}
@@ -761,7 +761,7 @@
EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
)");
}
@@ -775,7 +775,7 @@
R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
)");
}
@@ -790,7 +790,7 @@
R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
)");
}
@@ -806,7 +806,7 @@
R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
1 candidate function:
- cross(vec3<T>, vec3<T>) -> vec3<T> where: T is f32 or f16
+ cross(vec3<T>, vec3<T>) -> vec3<T> where: T is abstract-float, f32 or f16
)");
}
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index afb9f5d..2c012a1 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -37,6 +37,7 @@
#include "src/tint/sem/type_initializer.h"
#include "src/tint/sem/u32.h"
#include "src/tint/sem/vector.h"
+#include "src/tint/utils/bitcast.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h"
@@ -680,6 +681,33 @@
}
template <typename NumberT>
+utils::Result<NumberT> ConstEval::Sub(NumberT a, NumberT b) {
+ NumberT result;
+ if constexpr (IsAbstract<NumberT>) {
+ // Check for over/underflow for abstract values
+ if (auto r = CheckedSub(a, b)) {
+ result = r->value;
+ } else {
+ AddError(OverflowErrorMessage(a, "-", b), *current_source);
+ return utils::Failure;
+ }
+ } else {
+ using T = UnwrapNumber<NumberT>;
+ auto sub_values = [](T lhs, T rhs) {
+ if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
+ // Ensure no UB for signed overflow
+ using UT = std::make_unsigned_t<T>;
+ return static_cast<T>(static_cast<UT>(lhs) - static_cast<UT>(rhs));
+ } else {
+ return lhs - rhs;
+ }
+ };
+ result = sub_values(a.value, b.value);
+ }
+ return result;
+}
+
+template <typename NumberT>
utils::Result<NumberT> ConstEval::Mul(NumberT a, NumberT b) {
using T = UnwrapNumber<NumberT>;
NumberT result;
@@ -793,6 +821,37 @@
return r;
}
+template <typename NumberT>
+utils::Result<NumberT> ConstEval::Det2(NumberT a1, NumberT a2, NumberT b1, NumberT b2) {
+ auto r1 = Mul(a1, b2);
+ if (!r1) {
+ return utils::Failure;
+ }
+ auto r2 = Mul(b1, a2);
+ if (!r2) {
+ return utils::Failure;
+ }
+ auto r = Sub(r1.Get(), r2.Get());
+ if (!r) {
+ return utils::Failure;
+ }
+ return r;
+}
+
+template <typename NumberT>
+utils::Result<NumberT> ConstEval::Clamp(NumberT e, NumberT low, NumberT high) {
+ return NumberT{std::min(std::max(e, low), high)};
+}
+
+auto ConstEval::ClampFunc(const sem::Type* elem_ty) {
+ return [=](auto e, auto low, auto high) -> ImplResult {
+ if (auto r = Clamp(e, low, high)) {
+ return CreateElement(builder, elem_ty, r.Get());
+ }
+ return utils::Failure;
+ };
+}
+
auto ConstEval::AddFunc(const sem::Type* elem_ty) {
return [=](auto a1, auto a2) -> ImplResult {
if (auto r = Add(a1, a2)) {
@@ -802,6 +861,15 @@
};
}
+auto ConstEval::SubFunc(const sem::Type* elem_ty) {
+ return [=](auto a1, auto a2) -> ImplResult {
+ if (auto r = Sub(a1, a2)) {
+ return CreateElement(builder, elem_ty, r.Get());
+ }
+ return utils::Failure;
+ };
+}
+
auto ConstEval::MulFunc(const sem::Type* elem_ty) {
return [=](auto a1, auto a2) -> ImplResult {
if (auto r = Mul(a1, a2)) {
@@ -839,6 +907,15 @@
};
}
+auto ConstEval::Det2Func(const sem::Type* elem_ty) {
+ return [=](auto a, auto b, auto c, auto d) -> ImplResult {
+ if (auto r = Det2(a, b, c, d)) {
+ return CreateElement(builder, elem_ty, r.Get());
+ }
+ return utils::Failure;
+ };
+}
+
ConstEval::Result ConstEval::Literal(const sem::Type* ty, const ast::LiteralExpression* literal) {
return Switch(
literal,
@@ -1100,34 +1177,9 @@
ConstEval::Result ConstEval::OpMinus(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source& source) {
+ TINT_SCOPED_ASSIGNMENT(current_source, &source);
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
- auto create = [&](auto i, auto j) -> ImplResult {
- using NumberT = decltype(i);
- NumberT result;
- if constexpr (IsAbstract<NumberT>) {
- // Check for over/underflow for abstract values
- if (auto r = CheckedSub(i, j)) {
- result = r->value;
- } else {
- AddError(OverflowErrorMessage(i, "-", j), source);
- return utils::Failure;
- }
- } else {
- using T = UnwrapNumber<NumberT>;
- auto subtract_values = [](T lhs, T rhs) {
- if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
- // Ensure no UB for signed underflow
- using UT = std::make_unsigned_t<T>;
- return static_cast<T>(static_cast<UT>(lhs) - static_cast<UT>(rhs));
- } else {
- return lhs - rhs;
- }
- };
- result = subtract_values(i.value, j.value);
- }
- return CreateElement(builder, c0->Type(), result);
- };
- return Dispatch_fia_fiu32_f16(create, c0, c1);
+ return Dispatch_fia_fiu32_f16(SubFunc(c0->Type()), c0, c1);
};
return TransformBinaryElements(builder, ty, transform, args[0], args[1]);
@@ -1612,7 +1664,8 @@
auto create = [&](auto i) -> ImplResult {
using NumberT = decltype(i);
if (i < NumberT(-1.0) || i > NumberT(1.0)) {
- AddError("acos must be called with a value in the range [-1 .. 1] (inclusive)", source);
+ AddError("acos must be called with a value in the range [-1 .. 1] (inclusive)",
+ source);
return utils::Failure;
}
return CreateElement(builder, c0->Type(), NumberT(std::acos(i.value)));
@@ -1641,7 +1694,8 @@
auto create = [&](auto i) -> ImplResult {
using NumberT = decltype(i);
if (i < NumberT(-1.0) || i > NumberT(1.0)) {
- AddError("asin must be called with a value in the range [-1 .. 1] (inclusive)", source);
+ AddError("asin must be called with a value in the range [-1 .. 1] (inclusive)",
+ source);
return utils::Failure;
}
return CreateElement(builder, c0->Type(), NumberT(std::asin(i.value)));
@@ -1687,7 +1741,8 @@
auto create = [&](auto i) -> ImplResult {
using NumberT = decltype(i);
if (i <= NumberT(-1.0) || i >= NumberT(1.0)) {
- AddError("atanh must be called with a value in the range (-1 .. 1) (exclusive)", source);
+ AddError("atanh must be called with a value in the range (-1 .. 1) (exclusive)",
+ source);
return utils::Failure;
}
return CreateElement(builder, c0->Type(), NumberT(std::atanh(i.value)));
@@ -1727,11 +1782,7 @@
const Source&) {
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1,
const sem::Constant* c2) {
- auto create = [&](auto e, auto low, auto high) {
- return CreateElement(builder, c0->Type(),
- decltype(e)(std::min(std::max(e, low), high)));
- };
- return Dispatch_fia_fiu32_f16(create, c0, c1, c2);
+ return Dispatch_fia_fiu32_f16(ClampFunc(c0->Type()), c0, c1, c2);
};
return TransformElements(builder, ty, transform, args[0], args[1], args[2]);
}
@@ -1790,6 +1841,52 @@
return TransformElements(builder, ty, transform, args[0]);
}
+ConstEval::Result ConstEval::cross(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source) {
+ TINT_SCOPED_ASSIGNMENT(current_source, &source);
+ auto* u = args[0];
+ auto* v = args[1];
+ auto* elem_ty = u->Type()->As<sem::Vector>()->type();
+
+ // cross product of a v3 is the determinant of the 3x3 matrix:
+ //
+ // |i j k |
+ // |u0 u1 u2|
+ // |v0 v1 v2|
+ //
+ // |u1 u2|i - |u0 u2|j + |u0 u1|k
+ // |v1 v2| |v0 v2| |v0 v1|
+ //
+ // |u1 u2|i + |v0 v2|j + |u0 u1|k
+ // |v1 v2| |u0 u2| |v0 v1|
+
+ auto* u0 = u->Index(0);
+ auto* u1 = u->Index(1);
+ auto* u2 = u->Index(2);
+ auto* v0 = v->Index(0);
+ auto* v1 = v->Index(1);
+ auto* v2 = v->Index(2);
+
+ // auto x = Dispatch_fa_f32_f16(ab_minus_cd_func(elem_ty), u->Index(1), v->Index(2),
+ // v->Index(1), u->Index(2));
+ auto x = Dispatch_fa_f32_f16(Det2Func(elem_ty), u1, u2, v1, v2);
+ if (!x) {
+ return utils::Failure;
+ }
+ auto y = Dispatch_fa_f32_f16(Det2Func(elem_ty), v0, v2, u0, u2);
+ if (!y) {
+ return utils::Failure;
+ }
+ auto z = Dispatch_fa_f32_f16(Det2Func(elem_ty), u0, u1, v0, v1);
+ if (!z) {
+ return utils::Failure;
+ }
+
+ return CreateComposite(builder, ty,
+ utils::Vector<const sem::Constant*, 3>{x.Get(), y.Get(), z.Get()});
+}
+
ConstEval::Result ConstEval::extractBits(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source& source) {
@@ -1804,18 +1901,18 @@
NumberUT in_offset = args[1]->As<NumberUT>();
NumberUT in_count = args[2]->As<NumberUT>();
- constexpr UT w = sizeof(UT) * 8;
- if ((in_offset + in_count) > w) {
- AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
- source);
- return utils::Failure;
- }
-
// Cast all to unsigned
UT e = static_cast<UT>(in_e);
UT o = static_cast<UT>(in_offset);
UT c = static_cast<UT>(in_count);
+ constexpr UT w = sizeof(UT) * 8;
+ if (o > w || c > w || (o + c) > w) {
+ AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
+ source);
+ return utils::Failure;
+ }
+
NumberT result;
if (c == UT{0}) {
// The result is 0 if c is 0
@@ -1979,6 +2076,78 @@
return TransformElements(builder, ty, transform, args[0], args[1]);
}
+ConstEval::Result ConstEval::pack2x16snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto calc = [&](f32 val) -> u32 {
+ auto clamped = Clamp(val, f32(-1.0f), f32(1.0f)).Get();
+ return u32(utils::Bitcast<uint16_t>(
+ static_cast<int16_t>(std::floor(0.5f + (32767.0f * clamped)))));
+ };
+
+ auto* e = args[0];
+ auto e0 = calc(e->Index(0)->As<f32>());
+ auto e1 = calc(e->Index(1)->As<f32>());
+
+ u32 ret = u32((e0 & 0x0000'ffff) | (e1 << 16));
+ return CreateElement(builder, ty, ret);
+}
+
+ConstEval::Result ConstEval::pack2x16unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto calc = [&](f32 val) -> u32 {
+ auto clamped = Clamp(val, f32(0.0f), f32(1.0f)).Get();
+ return u32{std::floor(0.5f + (65535.0f * clamped))};
+ };
+
+ auto* e = args[0];
+ auto e0 = calc(e->Index(0)->As<f32>());
+ auto e1 = calc(e->Index(1)->As<f32>());
+
+ u32 ret = u32((e0 & 0x0000'ffff) | (e1 << 16));
+ return CreateElement(builder, ty, ret);
+}
+
+ConstEval::Result ConstEval::pack4x8snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto calc = [&](f32 val) -> u32 {
+ auto clamped = Clamp(val, f32(-1.0f), f32(1.0f)).Get();
+ return u32(
+ utils::Bitcast<uint8_t>(static_cast<int8_t>(std::floor(0.5f + (127.0f * clamped)))));
+ };
+
+ auto* e = args[0];
+ auto e0 = calc(e->Index(0)->As<f32>());
+ auto e1 = calc(e->Index(1)->As<f32>());
+ auto e2 = calc(e->Index(2)->As<f32>());
+ auto e3 = calc(e->Index(3)->As<f32>());
+
+ uint32_t mask = 0x0000'00ff;
+ u32 ret = u32((e0 & mask) | ((e1 & mask) << 8) | ((e2 & mask) << 16) | ((e3 & mask) << 24));
+ return CreateElement(builder, ty, ret);
+}
+
+ConstEval::Result ConstEval::pack4x8unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto calc = [&](f32 val) -> u32 {
+ auto clamped = Clamp(val, f32(0.0f), f32(1.0f)).Get();
+ return u32{std::floor(0.5f + (255.0f * clamped))};
+ };
+
+ auto* e = args[0];
+ auto e0 = calc(e->Index(0)->As<f32>());
+ auto e1 = calc(e->Index(1)->As<f32>());
+ auto e2 = calc(e->Index(2)->As<f32>());
+ auto e3 = calc(e->Index(3)->As<f32>());
+
+ uint32_t mask = 0x0000'00ff;
+ u32 ret = u32((e0 & mask) | ((e1 & mask) << 8) | ((e2 & mask) << 16) | ((e3 & mask) << 24));
+ return CreateElement(builder, ty, ret);
+}
+
ConstEval::Result ConstEval::reverseBits(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source&) {
@@ -2085,6 +2254,68 @@
return TransformElements(builder, ty, transform, args[0], args[1]);
}
+ConstEval::Result ConstEval::unpack2x16snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto* inner_ty = sem::Type::DeepestElementOf(ty);
+ auto e = args[0]->As<u32>().value;
+
+ utils::Vector<const sem::Constant*, 2> els;
+ els.Reserve(2);
+ for (size_t i = 0; i < 2; ++i) {
+ auto val = f32(
+ std::max(static_cast<float>(int16_t((e >> (16 * i)) & 0x0000'ffff)) / 32767.f, -1.f));
+ els.Push(CreateElement(builder, inner_ty, val));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::Result ConstEval::unpack2x16unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto* inner_ty = sem::Type::DeepestElementOf(ty);
+ auto e = args[0]->As<u32>().value;
+
+ utils::Vector<const sem::Constant*, 2> els;
+ els.Reserve(2);
+ for (size_t i = 0; i < 2; ++i) {
+ auto val = f32(static_cast<float>(uint16_t((e >> (16 * i)) & 0x0000'ffff)) / 65535.f);
+ els.Push(CreateElement(builder, inner_ty, val));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::Result ConstEval::unpack4x8snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto* inner_ty = sem::Type::DeepestElementOf(ty);
+ auto e = args[0]->As<u32>().value;
+
+ utils::Vector<const sem::Constant*, 4> els;
+ els.Reserve(4);
+ for (size_t i = 0; i < 4; ++i) {
+ auto val =
+ f32(std::max(static_cast<float>(int8_t((e >> (8 * i)) & 0x0000'00ff)) / 127.f, -1.f));
+ els.Push(CreateElement(builder, inner_ty, val));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
+ConstEval::Result ConstEval::unpack4x8unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source&) {
+ auto* inner_ty = sem::Type::DeepestElementOf(ty);
+ auto e = args[0]->As<u32>().value;
+
+ utils::Vector<const sem::Constant*, 4> els;
+ els.Reserve(4);
+ for (size_t i = 0; i < 4; ++i) {
+ auto val = f32(static_cast<float>(uint8_t((e >> (8 * i)) & 0x0000'00ff)) / 255.f);
+ els.Push(CreateElement(builder, inner_ty, val));
+ }
+ return CreateComposite(builder, ty, std::move(els));
+}
+
ConstEval::Result ConstEval::quantizeToF16(const sem::Type* ty,
utils::VectorRef<const sem::Constant*> args,
const Source&) {
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index f309150..9907b36 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -503,6 +503,15 @@
utils::VectorRef<const sem::Constant*> args,
const Source& source);
+ /// cross builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result cross(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
/// extractBits builtin
/// @param ty the expression type
/// @param args the input arguments
@@ -548,6 +557,42 @@
utils::VectorRef<const sem::Constant*> args,
const Source& source);
+ /// pack2x16snorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result pack2x16snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// pack2x16unorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result pack2x16unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// pack4x8snorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result pack4x8snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// pack4x8unorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result pack4x8unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
/// reverseBits builtin
/// @param ty the expression type
/// @param args the input arguments
@@ -602,6 +647,42 @@
utils::VectorRef<const sem::Constant*> args,
const Source& source);
+ /// unpack2x16snorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result unpack2x16snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// unpack2x16unorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result unpack2x16unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// unpack4x8snorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result unpack4x8snorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
+ /// unpack4x8unorm builtin
+ /// @param ty the expression type
+ /// @param args the input arguments
+ /// @param source the source location of the conversion
+ /// @return the result value, or null if the value cannot be calculated
+ Result unpack4x8unorm(const sem::Type* ty,
+ utils::VectorRef<const sem::Constant*> args,
+ const Source& source);
+
/// quantizeToF16 builtin
/// @param ty the expression type
/// @param args the input arguments
@@ -625,6 +706,13 @@
template <typename NumberT>
utils::Result<NumberT> Add(NumberT a, NumberT b);
+ /// Subtracts two Number<T>s
+ /// @param a the lhs number
+ /// @param b the rhs number
+ /// @returns the result number on success, or logs an error and returns Failure
+ template <typename NumberT>
+ utils::Result<NumberT> Sub(NumberT a, NumberT b);
+
/// Multiplies two Number<T>s
/// @param a the lhs number
/// @param b the rhs number
@@ -677,12 +765,34 @@
NumberT b3,
NumberT b4);
+ /// Returns the determinant of the 2x2 matrix [(a1, a2), (b1, b2)]
+ /// @param a1 component 1 of the first column vector
+ /// @param a2 component 2 of the first column vector
+ /// @param b1 component 1 of the second column vector
+ /// @param b2 component 2 of the second column vector
+ template <typename NumberT>
+ utils::Result<NumberT> Det2(NumberT a1, NumberT a2, NumberT b1, NumberT b2);
+
+ /// Clamps e between low and high
+ /// @param e the number to clamp
+ /// @param low the lower bound
+ /// @param high the upper bound
+ /// @returns the result number on success, or logs an error and returns Failure
+ template <typename NumberT>
+ utils::Result<NumberT> Clamp(NumberT e, NumberT low, NumberT high);
+
/// Returns a callable that calls Add, and creates a Constant with its result of type `elem_ty`
/// if successful, or returns Failure otherwise.
/// @param elem_ty the element type of the Constant to create on success
/// @returns the callable function
auto AddFunc(const sem::Type* elem_ty);
+ /// Returns a callable that calls Sub, and creates a Constant with its result of type `elem_ty`
+ /// if successful, or returns Failure otherwise.
+ /// @param elem_ty the element type of the Constant to create on success
+ /// @returns the callable function
+ auto SubFunc(const sem::Type* elem_ty);
+
/// Returns a callable that calls Mul, and creates a Constant with its result of type `elem_ty`
/// if successful, or returns Failure otherwise.
/// @param elem_ty the element type of the Constant to create on success
@@ -707,6 +817,18 @@
/// @returns the callable function
auto Dot4Func(const sem::Type* elem_ty);
+ /// Returns a callable that calls Det2, and creates a Constant with its result of type `elem_ty`
+ /// if successful, or returns Failure otherwise.
+ /// @param elem_ty the element type of the Constant to create on success
+ /// @returns the callable function
+ auto Det2Func(const sem::Type* elem_ty);
+
+ /// Returns a callable that calls Clamp, and creates a Constant with its result of type
+ /// `elem_ty` if successful, or returns Failure otherwise.
+ /// @param elem_ty the element type of the Constant to create on success
+ /// @returns the callable function
+ auto ClampFunc(const sem::Type* elem_ty);
+
ProgramBuilder& builder;
const Source* current_source = nullptr;
};
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index 3dc395b..fddca38 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -9,7 +9,7 @@
// 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
+// See the License for the empecific language governing permissions and
// limitations under the License.
#include "src/tint/resolver/const_eval_test.h"
@@ -17,6 +17,7 @@
#include "src/tint/utils/result.h"
using namespace tint::number_suffixes; // NOLINT
+using ::testing::HasSubstr;
namespace tint::resolver {
namespace {
@@ -28,8 +29,8 @@
Case(utils::VectorRef<Types> in_args, Types expected_value)
: args(std::move(in_args)), expected(Success{std::move(expected_value), false, false}) {}
- Case(utils::VectorRef<Types> in_args, const char* expected_err)
- : args(std::move(in_args)), expected(Failure{expected_err}) {}
+ Case(utils::VectorRef<Types> in_args, std::string expected_err)
+ : args(std::move(in_args)), expected(Failure{std::move(expected_err)}) {}
/// Expected value may be positive or negative
Case& PosOrNeg() {
@@ -53,7 +54,7 @@
bool float_compare = false;
};
struct Failure {
- const char* error = nullptr;
+ std::string error = nullptr;
};
utils::Vector<Types, 8> args;
@@ -94,17 +95,27 @@
}
/// Creates a Case with Values for args and expected error
-static Case E(std::initializer_list<Types> args, const char* err) {
- return Case{utils::Vector<Types, 8>{args}, err};
+static Case E(std::initializer_list<Types> args, std::string err) {
+ return Case{utils::Vector<Types, 8>{args}, std::move(err)};
}
/// Convenience overload that creates an expected-error Case with just scalars
-static Case E(std::initializer_list<ScalarTypes> sargs, const char* err) {
+static Case E(std::initializer_list<ScalarTypes> sargs, std::string err) {
utils::Vector<Types, 8> args;
for (auto& sa : sargs) {
std::visit([&](auto&& v) { return args.Push(Val(v)); }, sa);
}
- return Case{std::move(args), err};
+ return Case{std::move(args), std::move(err)};
+}
+
+/// Returns the overflow error message for binary ops
+template <typename NumberT>
+std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) {
+ std::stringstream ss;
+ ss << std::setprecision(20);
+ ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '"
+ << FriendlyName<NumberT>() << "'";
+ return ss.str();
}
using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<sem::BuiltinType, Case>>;
@@ -776,6 +787,130 @@
testing::ValuesIn(Concat(CountOneBitsCases<i32>(), //
CountOneBitsCases<u32>()))));
+template <typename T, bool finite_only>
+std::vector<Case> CrossCases() {
+ constexpr auto vec_x = [](T v) { return Vec(T(v), T(0), T(0)); };
+ constexpr auto vec_y = [](T v) { return Vec(T(0), T(v), T(0)); };
+ constexpr auto vec_z = [](T v) { return Vec(T(0), T(0), T(v)); };
+
+ const auto zero = Vec(T(0), T(0), T(0));
+ const auto unit_x = vec_x(T(1));
+ const auto unit_y = vec_y(T(1));
+ const auto unit_z = vec_z(T(1));
+ const auto neg_unit_x = vec_x(-T(1));
+ const auto neg_unit_y = vec_y(-T(1));
+ const auto neg_unit_z = vec_z(-T(1));
+ const auto highest_x = vec_x(T::Highest());
+ const auto highest_y = vec_y(T::Highest());
+ const auto highest_z = vec_z(T::Highest());
+ const auto smallest_x = vec_x(T::Smallest());
+ const auto smallest_y = vec_y(T::Smallest());
+ const auto smallest_z = vec_z(T::Smallest());
+ const auto lowest_x = vec_x(T::Lowest());
+ const auto lowest_y = vec_y(T::Lowest());
+ const auto lowest_z = vec_z(T::Lowest());
+ const auto inf_x = vec_x(T::Inf());
+ const auto inf_y = vec_y(T::Inf());
+ const auto inf_z = vec_z(T::Inf());
+ const auto neg_inf_x = vec_x(-T::Inf());
+ const auto neg_inf_y = vec_y(-T::Inf());
+ const auto neg_inf_z = vec_z(-T::Inf());
+
+ std::vector<Case> r = {
+ C({zero, zero}, zero),
+
+ C({unit_x, unit_x}, zero),
+ C({unit_y, unit_y}, zero),
+ C({unit_z, unit_z}, zero),
+
+ C({smallest_x, smallest_x}, zero),
+ C({smallest_y, smallest_y}, zero),
+ C({smallest_z, smallest_z}, zero),
+
+ C({lowest_x, lowest_x}, zero),
+ C({lowest_y, lowest_y}, zero),
+ C({lowest_z, lowest_z}, zero),
+
+ C({highest_x, highest_x}, zero),
+ C({highest_y, highest_y}, zero),
+ C({highest_z, highest_z}, zero),
+
+ C({smallest_x, highest_x}, zero),
+ C({smallest_y, highest_y}, zero),
+ C({smallest_z, highest_z}, zero),
+
+ C({unit_x, neg_unit_x}, zero).PosOrNeg(),
+ C({unit_y, neg_unit_y}, zero).PosOrNeg(),
+ C({unit_z, neg_unit_z}, zero).PosOrNeg(),
+
+ C({unit_x, unit_y}, unit_z),
+ C({unit_y, unit_x}, neg_unit_z),
+
+ C({unit_z, unit_x}, unit_y),
+ C({unit_x, unit_z}, neg_unit_y),
+
+ C({unit_y, unit_z}, unit_x),
+ C({unit_z, unit_y}, neg_unit_x),
+
+ C({vec_x(T(1)), vec_y(T(2))}, vec_z(T(2))),
+ C({vec_y(T(1)), vec_x(T(2))}, vec_z(-T(2))),
+ C({vec_x(T(2)), vec_y(T(3))}, vec_z(T(6))),
+ C({vec_y(T(2)), vec_x(T(3))}, vec_z(-T(6))),
+
+ C({Vec(T(1), T(2), T(3)), Vec(T(1), T(5), T(7))}, Vec(T(-1), T(-4), T(3))),
+ C({Vec(T(33), T(44), T(55)), Vec(T(13), T(42), T(39))}, Vec(T(-594), T(-572), T(814))),
+ C({Vec(T(3.5), T(4), T(5.5)), Vec(T(1), T(4.5), T(3.5))},
+ Vec(T(-10.75), T(-6.75), T(11.75))),
+ };
+
+ ConcatIntoIf<!finite_only>( //
+ r, std::vector<Case>{
+ C({highest_x, highest_y}, inf_z).PosOrNeg(), //
+ C({highest_y, highest_x}, inf_z).PosOrNeg(), //
+ C({highest_z, highest_x}, inf_y).PosOrNeg(), //
+ C({highest_x, highest_z}, inf_y).PosOrNeg(), //
+ C({highest_y, highest_z}, inf_x).PosOrNeg(), //
+ C({highest_z, highest_y}, inf_x).PosOrNeg(), //
+ C({lowest_x, lowest_y}, inf_z).PosOrNeg(), //
+ C({lowest_y, lowest_x}, inf_z).PosOrNeg(), //
+ C({lowest_z, lowest_x}, inf_y).PosOrNeg(), //
+ C({lowest_x, lowest_z}, inf_y).PosOrNeg(), //
+ C({lowest_y, lowest_z}, inf_x).PosOrNeg(), //
+ C({lowest_z, lowest_y}, inf_x).PosOrNeg(),
+ });
+
+ std::string pos_error_msg =
+ "12:34 error: " + OverflowErrorMessage(T::Highest(), "*", T::Highest());
+ std::string neg_error_msg =
+ "12:34 error: " + OverflowErrorMessage(T::Lowest(), "*", T::Lowest());
+
+ ConcatIntoIf<finite_only>( //
+ r, std::vector<Case>{
+ E({highest_x, highest_y}, pos_error_msg),
+ E({highest_y, highest_x}, pos_error_msg),
+ E({highest_z, highest_x}, pos_error_msg),
+ E({highest_x, highest_z}, pos_error_msg),
+ E({highest_y, highest_z}, pos_error_msg),
+ E({highest_z, highest_y}, pos_error_msg),
+ E({lowest_x, lowest_y}, neg_error_msg),
+ E({lowest_y, lowest_x}, neg_error_msg),
+ E({lowest_z, lowest_x}, neg_error_msg),
+ E({lowest_x, lowest_z}, neg_error_msg),
+ E({lowest_y, lowest_z}, neg_error_msg),
+ E({lowest_z, lowest_y}, neg_error_msg),
+ });
+
+ return r;
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Cross,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kCross),
+ testing::ValuesIn(Concat(CrossCases<AFloat, true>(), //
+ CrossCases<f32, false>(),
+ CrossCases<f32, false>(), //
+ CrossCases<f16, false>()))));
+
template <typename T>
std::vector<Case> FirstLeadingBitCases() {
using B = BitValues<T>;
@@ -1091,8 +1226,77 @@
std::make_tuple(33, 33), //
std::make_tuple(34, 34), //
std::make_tuple(1000, 1000), //
+ std::make_tuple(u32::Highest(), 1), //
+ std::make_tuple(1, u32::Highest()), //
std::make_tuple(u32::Highest(), u32::Highest())));
+std::vector<Case> Pack4x8snormCases() {
+ return {
+ C({Vec(f32(0), f32(0), f32(0), f32(0))}, Val(u32(0x0000'0000))),
+ C({Vec(f32(0), f32(0), f32(0), f32(-1))}, Val(u32(0x8100'0000))),
+ C({Vec(f32(0), f32(0), f32(0), f32(1))}, Val(u32(0x7f00'0000))),
+ C({Vec(f32(0), f32(0), f32(-1), f32(0))}, Val(u32(0x0081'0000))),
+ C({Vec(f32(0), f32(1), f32(0), f32(0))}, Val(u32(0x0000'7f00))),
+ C({Vec(f32(-1), f32(0), f32(0), f32(0))}, Val(u32(0x0000'0081))),
+ C({Vec(f32(1), f32(-1), f32(1), f32(-1))}, Val(u32(0x817f'817f))),
+ C({Vec(f32::Highest(), f32(-0.5), f32(0.5), f32::Lowest())}, Val(u32(0x8140'c17f))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Pack4x8snorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kPack4X8Snorm),
+ testing::ValuesIn(Pack4x8snormCases())));
+
+std::vector<Case> Pack4x8unormCases() {
+ return {
+ C({Vec(f32(0), f32(0), f32(0), f32(0))}, Val(u32(0x0000'0000))),
+ C({Vec(f32(0), f32(0), f32(0), f32(1))}, Val(u32(0xff00'0000))),
+ C({Vec(f32(0), f32(0), f32(1), f32(0))}, Val(u32(0x00ff'0000))),
+ C({Vec(f32(0), f32(1), f32(0), f32(0))}, Val(u32(0x0000'ff00))),
+ C({Vec(f32(1), f32(0), f32(0), f32(0))}, Val(u32(0x0000'00ff))),
+ C({Vec(f32(1), f32(0), f32(1), f32(0))}, Val(u32(0x00ff'00ff))),
+ C({Vec(f32::Highest(), f32(0), f32(0.5), f32::Lowest())}, Val(u32(0x0080'00ff))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Pack4x8unorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kPack4X8Unorm),
+ testing::ValuesIn(Pack4x8unormCases())));
+
+std::vector<Case> Pack2x16snormCases() {
+ return {
+ C({Vec(f32(0), f32(0))}, Val(u32(0x0000'0000))),
+ C({Vec(f32(0), f32(-1))}, Val(u32(0x8001'0000))),
+ C({Vec(f32(0), f32(1))}, Val(u32(0x7fff'0000))),
+ C({Vec(f32(-1), f32(0))}, Val(u32(0x0000'8001))),
+ C({Vec(f32(1), f32(0))}, Val(u32(0x0000'7fff))),
+ C({Vec(f32(1), f32(-1))}, Val(u32(0x8001'7fff))),
+ C({Vec(f32::Highest(), f32::Lowest())}, Val(u32(0x8001'7fff))),
+ C({Vec(f32(-0.5), f32(0.5))}, Val(u32(0x4000'c001))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Pack2x16snorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kPack2X16Snorm),
+ testing::ValuesIn(Pack2x16snormCases())));
+
+std::vector<Case> Pack2x16unormCases() {
+ return {
+ C({Vec(f32(0), f32(1))}, Val(u32(0xffff'0000))),
+ C({Vec(f32(1), f32(0))}, Val(u32(0x0000'ffff))),
+ C({Vec(f32(0.5), f32(0))}, Val(u32(0x0000'8000))),
+ C({Vec(f32::Highest(), f32::Lowest())}, Val(u32(0x0000'ffff))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Pack2x16unorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kPack2X16Unorm),
+ testing::ValuesIn(Pack2x16unormCases())));
+
template <typename T>
std::vector<Case> ReverseBitsCases() {
using B = BitValues<T>;
@@ -1268,6 +1472,74 @@
StepCases<f32>(),
StepCases<f16>()))));
+std::vector<Case> Unpack4x8snormCases() {
+ return {
+ C({Val(u32(0x0000'0000))}, Vec(f32(0), f32(0), f32(0), f32(0))),
+ C({Val(u32(0x8100'0000))}, Vec(f32(0), f32(0), f32(0), f32(-1))),
+ C({Val(u32(0x7f00'0000))}, Vec(f32(0), f32(0), f32(0), f32(1))),
+ C({Val(u32(0x0081'0000))}, Vec(f32(0), f32(0), f32(-1), f32(0))),
+ C({Val(u32(0x0000'7f00))}, Vec(f32(0), f32(1), f32(0), f32(0))),
+ C({Val(u32(0x0000'0081))}, Vec(f32(-1), f32(0), f32(0), f32(0))),
+ C({Val(u32(0x817f'817f))}, Vec(f32(1), f32(-1), f32(1), f32(-1))),
+ C({Val(u32(0x816d'937f))},
+ Vec(f32(1), f32(-0.8582677165354), f32(0.8582677165354), f32(-1))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Unpack4x8snorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kUnpack4X8Snorm),
+ testing::ValuesIn(Unpack4x8snormCases())));
+
+std::vector<Case> Unpack4x8unormCases() {
+ return {
+ C({Val(u32(0x0000'0000))}, Vec(f32(0), f32(0), f32(0), f32(0))),
+ C({Val(u32(0xff00'0000))}, Vec(f32(0), f32(0), f32(0), f32(1))),
+ C({Val(u32(0x00ff'0000))}, Vec(f32(0), f32(0), f32(1), f32(0))),
+ C({Val(u32(0x0000'ff00))}, Vec(f32(0), f32(1), f32(0), f32(0))),
+ C({Val(u32(0x0000'00ff))}, Vec(f32(1), f32(0), f32(0), f32(0))),
+ C({Val(u32(0x00ff'00ff))}, Vec(f32(1), f32(0), f32(1), f32(0))),
+ C({Val(u32(0x0066'00ff))}, Vec(f32(1), f32(0), f32(0.4), f32(0))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Unpack4x8unorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kUnpack4X8Unorm),
+ testing::ValuesIn(Unpack4x8unormCases())));
+
+std::vector<Case> Unpack2x16snormCases() {
+ return {
+ C({Val(u32(0x0000'0000))}, Vec(f32(0), f32(0))),
+ C({Val(u32(0x8001'0000))}, Vec(f32(0), f32(-1))),
+ C({Val(u32(0x7fff'0000))}, Vec(f32(0), f32(1))),
+ C({Val(u32(0x0000'8001))}, Vec(f32(-1), f32(0))),
+ C({Val(u32(0x0000'7fff))}, Vec(f32(1), f32(0))),
+ C({Val(u32(0x8001'7fff))}, Vec(f32(1), f32(-1))),
+ C({Val(u32(0x8001'7fff))}, Vec(f32(1), f32(-1))),
+ C({Val(u32(0x4000'999a))}, Vec(f32(-0.80001220740379), f32(0.500015259254737))).FloatComp(),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Unpack2x16snorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kUnpack2X16Snorm),
+ testing::ValuesIn(Unpack2x16snormCases())));
+
+std::vector<Case> Unpack2x16unormCases() {
+ return {
+ C({Val(u32(0xffff'0000))}, Vec(f32(0), f32(1))),
+ C({Val(u32(0x0000'ffff))}, Vec(f32(1), f32(0))),
+ C({Val(u32(0x0000'6666))}, Vec(f32(0.4), f32(0))),
+ C({Val(u32(0x0000'ffff))}, Vec(f32(1), f32(0))),
+ };
+}
+INSTANTIATE_TEST_SUITE_P( //
+ Unpack2x16unorm,
+ ResolverConstEvalBuiltinTest,
+ testing::Combine(testing::Values(sem::BuiltinType::kUnpack2X16Unorm),
+ testing::ValuesIn(Unpack2x16unormCases())));
+
std::vector<Case> QuantizeToF16Cases() {
(void)E({Vec(0_f, 0_f)}, ""); // Currently unused, but will be soon.
return {
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 5a21c55..3238c8b 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -193,8 +193,6 @@
},
[&](const ast::Function* func) {
Declare(func->symbol, func);
- TraverseAttributes(func->attributes);
- TraverseAttributes(func->return_type_attributes);
TraverseFunction(func);
},
[&](const ast::Variable* var) {
@@ -216,10 +214,13 @@
/// Traverses the function, performing symbol resolution and determining
/// global dependencies.
void TraverseFunction(const ast::Function* func) {
+ TraverseAttributes(func->attributes);
+ TraverseAttributes(func->return_type_attributes);
// Perform symbol resolution on all the parameter types before registering
// the parameters themselves. This allows the case of declaring a parameter
// with the same identifier as its type.
for (auto* param : func->params) {
+ TraverseAttributes(param->attributes);
TraverseType(param->type);
}
// Resolve the return type
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 311c9cc..272357b 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -1237,9 +1237,14 @@
})});
GlobalVar(Sym(), T, V);
GlobalConst(Sym(), T, V);
- Func(Sym(), //
- utils::Vector{Param(Sym(), T)}, //
- T, // Return type
+ Func(Sym(),
+ utils::Vector{
+ Param(Sym(), T,
+ utils::Vector{
+ Location(V), // Parameter attributes
+ }),
+ },
+ T, // Return type
utils::Vector{
Decl(Var(Sym(), T, V)), //
Decl(Let(Sym(), T, V)), //
diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl
index ddce1ba..dcba75b 100644
--- a/src/tint/resolver/intrinsic_table.inl
+++ b/src/tint/resolver/intrinsic_table.inl
@@ -13766,7 +13766,7 @@
/* parameters */ &kParameters[841],
/* return matcher indices */ &kMatcherIndices[102],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::unpack4x8unorm,
},
{
/* [453] */
@@ -13778,7 +13778,7 @@
/* parameters */ &kParameters[842],
/* return matcher indices */ &kMatcherIndices[102],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::unpack4x8snorm,
},
{
/* [454] */
@@ -13790,7 +13790,7 @@
/* parameters */ &kParameters[843],
/* return matcher indices */ &kMatcherIndices[132],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::unpack2x16unorm,
},
{
/* [455] */
@@ -13802,7 +13802,7 @@
/* parameters */ &kParameters[844],
/* return matcher indices */ &kMatcherIndices[132],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::unpack2x16snorm,
},
{
/* [456] */
@@ -13862,7 +13862,7 @@
/* parameters */ &kParameters[881],
/* return matcher indices */ &kMatcherIndices[95],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::pack4x8unorm,
},
{
/* [461] */
@@ -13874,7 +13874,7 @@
/* parameters */ &kParameters[882],
/* return matcher indices */ &kMatcherIndices[95],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::pack4x8snorm,
},
{
/* [462] */
@@ -13886,7 +13886,7 @@
/* parameters */ &kParameters[884],
/* return matcher indices */ &kMatcherIndices[95],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::pack2x16snorm,
},
{
/* [463] */
@@ -13917,12 +13917,12 @@
/* num parameters */ 2,
/* num template types */ 1,
/* num template numbers */ 0,
- /* template types */ &kTemplateTypes[22],
+ /* template types */ &kTemplateTypes[23],
/* template numbers */ &kTemplateNumbers[10],
/* parameters */ &kParameters[777],
/* return matcher indices */ &kMatcherIndices[104],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::cross,
},
{
/* [466] */
@@ -14006,7 +14006,7 @@
/* parameters */ &kParameters[883],
/* return matcher indices */ &kMatcherIndices[95],
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* const eval */ nullptr,
+ /* const eval */ &ConstEval::pack2x16unorm,
},
};
@@ -14020,8 +14020,8 @@
},
{
/* [1] */
- /* fn acos<T : fa_f32_f16>(@test_value(0.87758256189) T) -> T */
- /* fn acos<N : num, T : fa_f32_f16>(@test_value(0.87758256189) vec<N, T>) -> vec<N, T> */
+ /* fn acos<T : fa_f32_f16>(@test_value(0.96891242171) T) -> T */
+ /* fn acos<N : num, T : fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T> */
/* num overloads */ 2,
/* overloads */ &kOverloads[428],
},
@@ -14138,7 +14138,7 @@
},
{
/* [18] */
- /* fn cross<T : f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
+ /* fn cross<T : fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
/* num overloads */ 1,
/* overloads */ &kOverloads[465],
},
diff --git a/src/tint/tint_gdb.py b/src/tint/tint_gdb.py
index 2dce446..88c614d 100644
--- a/src/tint/tint_gdb.py
+++ b/src/tint/tint_gdb.py
@@ -165,11 +165,11 @@
'UtilsVector', '^tint::utils::VectorRef<.*>$', UtilsVectorRefPrinter)
-class UtilsHashsetPrinter(Printer):
- '''Printer for Hashset<T, N, HASH, EQUAL>'''
+class UtilsHashmapBasePrinter(Printer):
+ '''Base Printer for HashmapBase-derived types'''
def __init__(self, val):
- super(UtilsHashsetPrinter, self).__init__(val)
+ super(UtilsHashmapBasePrinter, self).__init__(val)
self.slice = UtilsVectorPrinter(self.val['slots_']).slice_printer()
self.try_read_std_optional_func = self.try_read_std_optional
@@ -185,26 +185,32 @@
for slot in range(0, self.slice.length()):
v = self.slice.value_at(slot)
if v['hash'] != 0:
- value = v['value']
+ entry = v['entry']
- # value is a std::optional, let's try to extract its value for display
- kvp = self.try_read_std_optional_func(slot, value)
+ # entry is a std::optional, let's try to extract its value for display
+ kvp = self.try_read_std_optional_func(slot, entry)
if kvp is None:
- # If we failed, just output the slot and value as is, which will use
+ # If we failed, just output the slot and entry as is, which will use
# the default visualizer for each.
- kvp = slot, value
+ kvp = slot, entry
yield str(kvp[0]), kvp[1]
def display_hint(self):
return 'array'
- def try_read_std_optional(self, slot, value):
+ def try_read_std_optional(self, slot, entry):
+ return None
+
+
+class UtilsHashsetPrinter(UtilsHashmapBasePrinter):
+ '''Printer for Hashset<T, N, HASH, EQUAL>'''
+
+ def try_read_std_optional(self, slot, entry):
try:
# libstdc++
- v = value['_M_payload']['_M_payload']['_M_value']
+ v = entry['_M_payload']['_M_payload']['_M_value']
return slot, v
- # return str(kvp['key']), kvp['value']
except:
return None
@@ -213,33 +219,16 @@
'UtilsHashset', '^tint::utils::Hashset<.*>$', UtilsHashsetPrinter)
-class UtilsHashmapPrinter(Printer):
+class UtilsHashmapPrinter(UtilsHashmapBasePrinter):
'''Printer for Hashmap<K, V, N, HASH, EQUAL>'''
- def __init__(self, val):
- super(UtilsHashmapPrinter, self).__init__(val)
- self.hash_set = UtilsHashsetPrinter(self.val['set_'])
- # Replace the lookup function so we can extract the key and value out of the std::optionals in the Hashset
- self.hash_set.try_read_std_optional_func = self.try_read_std_optional
-
- def to_string(self):
- return self.hash_set.to_string()
-
- def children(self):
- return self.hash_set.children()
-
- def display_hint(self):
- return 'array'
-
- def try_read_std_optional(self, slot, value):
+ def try_read_std_optional(self, slot, entry):
try:
# libstdc++
- kvp = value['_M_payload']['_M_payload']['_M_value']
+ kvp = entry['_M_payload']['_M_payload']['_M_value']
return str(kvp['key']), kvp['value']
except:
- pass
- # Failed, fall back on hash_set
- return self.hash_set.try_read_std_optional(slot, value)
+ return None
pp_set.add_printer(
diff --git a/src/tint/tint_lldb.py b/src/tint/tint_lldb.py
index 85a93ff..84e6ad3 100644
--- a/src/tint/tint_lldb.py
+++ b/src/tint/tint_lldb.py
@@ -297,8 +297,8 @@
return self.slice_printer.get_child_at_index(index)
-class UtilsHashsetPrinter(Printer):
- '''Printer for Hashset<T, N, HASH, EQUAL>'''
+class UtilsHashmapBasePrinter(Printer):
+ '''Base Printer for HashmapBase-derived types'''
def initialize(self):
self.slice = UtilsVectorPrinter(
@@ -326,26 +326,33 @@
def get_child_at_index(self, index):
slot = self.valid_slots[index]
v = self.slice.value_at(slot)
- value = member(v, 'value')
+ entry = member(v, 'entry')
- # value is a std::optional, let's try to extract its value for display
- kvp = self.try_read_std_optional_func(slot, value)
+ # entry is a std::optional, let's try to extract its value for display
+ kvp = self.try_read_std_optional_func(slot, entry)
if kvp is None:
- # If we failed, just output the slot and value as is, which will use
+ # If we failed, just output the slot and entry as is, which will use
# the default printer for std::optional.
- kvp = slot, value
+ kvp = slot, entry
return kvp[1].CreateChildAtOffset('[{}]'.format(kvp[0]), 0, kvp[1].GetType())
- def try_read_std_optional(self, slot, value):
+ def try_read_std_optional(self, slot, entry):
+ return None
+
+
+class UtilsHashsetPrinter(UtilsHashmapBasePrinter):
+ '''Printer for Hashset<T, N, HASH, EQUAL>'''
+
+ def try_read_std_optional(self, slot, entry):
try:
# libc++
- v = value.EvaluateExpression('__val_')
+ v = entry.EvaluateExpression('__val_')
if v.name is not None:
return slot, v
# libstdc++
- v = value.EvaluateExpression('_M_payload._M_payload._M_value')
+ v = entry.EvaluateExpression('_M_payload._M_payload._M_value')
if v.name is not None:
return slot, v
return None
@@ -353,45 +360,24 @@
return None
-class UtilsHashmapPrinter(Printer):
+class UtilsHashmapPrinter(UtilsHashsetPrinter):
'''Printer for Hashmap<K, V, N, HASH, EQUAL>'''
- def initialize(self):
- self.hash_set = UtilsHashsetPrinter(self.member('set_'))
- # Replace the lookup function so we can extract the key and value out of the std::optionals in the Hashset
- self.hash_set.try_read_std_optional_func = self.try_read_std_optional
-
- def update(self):
- self.hash_set.update()
-
- def get_summary(self):
- return self.hash_set.get_summary()
-
- def num_children(self):
- return self.hash_set.num_children()
-
- def has_children(self):
- return self.hash_set.has_children()
-
- def get_child_at_index(self, index):
- return self.hash_set.get_child_at_index(index)
-
- def try_read_std_optional(self, slot, value):
+ def try_read_std_optional(self, slot, entry):
try:
# libc++
- val = value.EvaluateExpression('__val_')
+ val = entry.EvaluateExpression('__val_')
k = val.EvaluateExpression('key')
v = val.EvaluateExpression('value')
if k.name is not None and v.name is not None:
return k.GetValue(), v
# libstdc++
- val = value.EvaluateExpression('_M_payload._M_payload._M_value')
+ val = entry.EvaluateExpression('_M_payload._M_payload._M_value')
k = val.EvaluateExpression('key')
v = val.EvaluateExpression('value')
if k.name is not None and v.name is not None:
return k.GetValue(), v
+ return None
except:
- pass
- # Failed, fall back on hash_set
- return self.hash_set.try_read_std_optional(slot, value)
+ return None
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index e80436d..17fcc20 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -462,6 +462,14 @@
auto name = b.Symbols().New("tint_insert_bits");
uint32_t width = WidthOf(ty);
+ // Currently in WGSL parameters of insertBits must be i32, u32, vecN<i32> or vecN<u32>
+ if (!sem::Type::DeepestElementOf(ty)->IsAnyOf<sem::I32, sem::U32>()) {
+ TINT_ICE(Transform, b.Diagnostics())
+ << "insertBits polyfill only support i32, u32, and vector of i32 or u32, got "
+ << b.FriendlyName(ty);
+ return {};
+ }
+
constexpr uint32_t W = 32u; // 32-bit
auto V = [&](auto value) -> const ast::Expression* {
@@ -481,21 +489,60 @@
return b.vec(b.ty.u32(), width, value);
};
- utils::Vector<const ast::Statement*, 8> body = {
- b.Decl(b.Let("s", b.Call("min", "offset", u32(W)))),
- b.Decl(b.Let("e", b.Call("min", u32(W), b.Add("s", "count")))),
- };
+ // Polyfill algorithm:
+ // s = min(offset, 32u);
+ // e = min(32u, (s + count));
+ // mask = (((1u << s) - 1u) ^ ((1u << e) - 1u));
+ // return (((n << s) & mask) | (v & ~(mask)));
+ // Note that the algorithm above use the left-shifting in C++ manner, but in WGSL, HLSL, MSL
+ // the rhs are modulo to bit-width of lhs (that is 32u in this case), and in GLSL the result
+ // is undefined if rhs is greater than or equal to bit-width of lhs. The results of `x << y`
+ // in C++ and HLSL are different when `y >= 32u`, and the `s` and `e` defined above can be
+ // 32u, which are cases we must handle specially. Replace all `(x << y)` to
+ // `select(Tx(), x << y, y < 32u)`, in which `Tx` is the type of x, where y can be greater
+ // than or equal to 32u.
+ // WGSL polyfill function:
+ // fn tint_insert_bits(v : T, n : T, offset : u32, count : u32) -> T {
+ // let e = offset + count;
+ // let mask = (
+ // (select(0u, 1u << offset, offset < 32u) - 1u) ^
+ // (select(0u, 1u << e, e < 32u) - 1u)
+ // );
+ // return ((select(T(), n << offset, offset < 32u) & mask) | (v & ~(mask)));
+ // }
+
+ utils::Vector<const ast::Statement*, 8> body;
switch (polyfill.insert_bits) {
case Level::kFull:
- // let mask = ((1 << s) - 1) ^ ((1 << e) - 1)
+ // let e = offset + count;
+ body.Push(b.Decl(b.Let("e", b.Add("offset", "count"))));
+
+ // let mask = (
+ // (select(0u, 1u << offset, offset < 32u) - 1u) ^
+ // (select(0u, 1u << e, e < 32u) - 1u)
+ // );
body.Push(b.Decl(b.Let(
- "mask", b.Xor(b.Sub(b.Shl(1_u, "s"), 1_u), b.Sub(b.Shl(1_u, "e"), 1_u)))));
- // return ((n << s) & mask) | (v & ~mask)
- body.Push(b.Return(b.Or(b.And(b.Shl("n", U("s")), V("mask")),
- b.And("v", V(b.Complement("mask"))))));
+ "mask",
+ b.Xor( //
+ b.Sub(
+ b.Call("select", 0_u, b.Shl(1_u, "offset"), b.LessThan("offset", 32_u)),
+ 1_u),
+ b.Sub(b.Call("select", 0_u, b.Shl(1_u, "e"), b.LessThan("e", 32_u)),
+ 1_u) //
+ ))));
+
+ // return ((select(T(), n << offset, offset < 32u) & mask) | (v & ~(mask)));
+ body.Push(
+ b.Return(b.Or(b.And(b.Call("select", b.Construct(T(ty)),
+ b.Shl("n", U("offset")), b.LessThan("offset", 32_u)),
+ V("mask")),
+ b.And("v", V(b.Complement("mask"))))));
+
break;
case Level::kClampParameters:
+ body.Push(b.Decl(b.Let("s", b.Call("min", "offset", u32(W)))));
+ body.Push(b.Decl(b.Let("e", b.Call("min", u32(W), b.Add("s", "count")))));
body.Push(b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
break;
default:
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index 3b7a42c..1e380d4 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -1722,10 +1722,9 @@
auto* expect = R"(
fn tint_insert_bits(v : i32, n : i32, offset : u32, count : u32) -> i32 {
- let s = min(offset, 32u);
- let e = min(32u, (s + count));
- let mask = (((1u << s) - 1u) ^ ((1u << e) - 1u));
- return (((n << s) & i32(mask)) | (v & i32(~(mask))));
+ let e = (offset + count);
+ let mask = ((select(0u, (1u << offset), (offset < 32u)) - 1u) ^ (select(0u, (1u << e), (e < 32u)) - 1u));
+ return ((select(i32(), (n << offset), (offset < 32u)) & i32(mask)) | (v & i32(~(mask))));
}
fn f() {
@@ -1749,10 +1748,9 @@
auto* expect = R"(
fn tint_insert_bits(v : u32, n : u32, offset : u32, count : u32) -> u32 {
- let s = min(offset, 32u);
- let e = min(32u, (s + count));
- let mask = (((1u << s) - 1u) ^ ((1u << e) - 1u));
- return (((n << s) & mask) | (v & ~(mask)));
+ let e = (offset + count);
+ let mask = ((select(0u, (1u << offset), (offset < 32u)) - 1u) ^ (select(0u, (1u << e), (e < 32u)) - 1u));
+ return ((select(u32(), (n << offset), (offset < 32u)) & mask) | (v & ~(mask)));
}
fn f() {
@@ -1776,10 +1774,9 @@
auto* expect = R"(
fn tint_insert_bits(v : vec3<i32>, n : vec3<i32>, offset : u32, count : u32) -> vec3<i32> {
- let s = min(offset, 32u);
- let e = min(32u, (s + count));
- let mask = (((1u << s) - 1u) ^ ((1u << e) - 1u));
- return (((n << vec3<u32>(s)) & vec3<i32>(i32(mask))) | (v & vec3<i32>(i32(~(mask)))));
+ let e = (offset + count);
+ let mask = ((select(0u, (1u << offset), (offset < 32u)) - 1u) ^ (select(0u, (1u << e), (e < 32u)) - 1u));
+ return ((select(vec3<i32>(), (n << vec3<u32>(offset)), (offset < 32u)) & vec3<i32>(i32(mask))) | (v & vec3<i32>(i32(~(mask)))));
}
fn f() {
@@ -1803,10 +1800,9 @@
auto* expect = R"(
fn tint_insert_bits(v : vec3<u32>, n : vec3<u32>, offset : u32, count : u32) -> vec3<u32> {
- let s = min(offset, 32u);
- let e = min(32u, (s + count));
- let mask = (((1u << s) - 1u) ^ ((1u << e) - 1u));
- return (((n << vec3<u32>(s)) & vec3<u32>(mask)) | (v & vec3<u32>(~(mask))));
+ let e = (offset + count);
+ let mask = ((select(0u, (1u << offset), (offset < 32u)) - 1u) ^ (select(0u, (1u << e), (e < 32u)) - 1u));
+ return ((select(vec3<u32>(), (n << vec3<u32>(offset)), (offset < 32u)) & vec3<u32>(mask)) | (v & vec3<u32>(~(mask))));
}
fn f() {
diff --git a/src/tint/transform/clamp_frag_depth_test.cc b/src/tint/transform/clamp_frag_depth_test.cc
index b94d5af..7c7019a 100644
--- a/src/tint/transform/clamp_frag_depth_test.cc
+++ b/src/tint/transform/clamp_frag_depth_test.cc
@@ -169,7 +169,7 @@
@fragment fn main() -> @builtin(frag_depth) f32 {
return 0.0;
}
- @fragment fn friend() -> @location(0) f32 {
+ @fragment fn other() -> @location(0) f32 {
return 0.0;
}
)";
@@ -194,7 +194,7 @@
}
@fragment
-fn friend() -> @location(0) f32 {
+fn other() -> @location(0) f32 {
return 0.0;
}
)";
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index 4416d35..8f2b014 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -580,9 +580,9 @@
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
- var signed = textureLoad(ext_tex, vec2<i32>(1));
- var unsigned = textureLoad(ext_tex, vec2<u32>(1));
- return signed + unsigned;
+ var val_signed = textureLoad(ext_tex, vec2<i32>(1));
+ var val_unsigned = textureLoad(ext_tex, vec2<u32>(1));
+ return val_signed + val_unsigned;
}
)";
@@ -652,9 +652,9 @@
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
- var signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
- var unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
- return (signed + unsigned);
+ var val_signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
+ var val_unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
+ return (val_signed + val_unsigned);
}
)";
@@ -670,9 +670,9 @@
auto* src = R"(
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
- var signed = textureLoad(ext_tex, vec2<i32>(1));
- var unsigned = textureLoad(ext_tex, vec2<u32>(1));
- return signed + unsigned;
+ var val_signed = textureLoad(ext_tex, vec2<i32>(1));
+ var val_unsigned = textureLoad(ext_tex, vec2<u32>(1));
+ return val_signed + val_unsigned;
}
@group(0) @binding(0) var ext_tex : texture_external;
@@ -742,9 +742,9 @@
@fragment
fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
- var signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
- var unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
- return (signed + unsigned);
+ var val_signed = textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1), ext_tex_params);
+ var val_unsigned = textureLoadExternal_1(ext_tex, ext_tex_plane_1, vec2<u32>(1), ext_tex_params);
+ return (val_signed + val_unsigned);
}
@group(0) @binding(0) var ext_tex : texture_2d<f32>;
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/transform/robustness_test.cc
index 990bbde..8b9a8ad 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/transform/robustness_test.cc
@@ -787,7 +787,7 @@
@group(0) @binding(0) var tex_depth_2d_arr : texture_depth_2d_array;
@group(0) @binding(0) var tex_external : texture_external;
-fn signed() {
+fn idx_signed() {
var array_idx : i32;
var level_idx : i32;
var sample_idx : i32;
@@ -802,7 +802,7 @@
textureLoad(tex_external, vec2<i32>(1, 2));
}
-fn unsigned() {
+fn idx_unsigned() {
var array_idx : u32;
var level_idx : u32;
var sample_idx : u32;
@@ -836,7 +836,7 @@
@group(0) @binding(0) var tex_external : texture_external;
-fn signed() {
+fn idx_signed() {
var array_idx : i32;
var level_idx : i32;
var sample_idx : i32;
@@ -850,7 +850,7 @@
textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
}
-fn unsigned() {
+fn idx_unsigned() {
var array_idx : u32;
var level_idx : u32;
var sample_idx : u32;
@@ -873,7 +873,7 @@
// Clamp textureLoad() coord, array_index and level values
TEST_F(RobustnessTest, TextureLoad_Clamp_OutOfOrder) {
auto* src = R"(
-fn signed() {
+fn idx_signed() {
var array_idx : i32;
var level_idx : i32;
var sample_idx : i32;
@@ -888,7 +888,7 @@
textureLoad(tex_external, vec2<i32>(1, 2));
}
-fn unsigned() {
+fn idx_unsigned() {
var array_idx : u32;
var level_idx : u32;
var sample_idx : u32;
@@ -915,7 +915,7 @@
auto* expect =
R"(
-fn signed() {
+fn idx_signed() {
var array_idx : i32;
var level_idx : i32;
var sample_idx : i32;
@@ -929,7 +929,7 @@
textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex_external)) - vec2(1)))));
}
-fn unsigned() {
+fn idx_unsigned() {
var array_idx : u32;
var level_idx : u32;
var sample_idx : u32;
@@ -976,14 +976,14 @@
@group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
-fn signed() {
+fn idx_signed() {
textureStore(tex1d, 10i, vec4<i32>());
textureStore(tex2d, vec2<i32>(10, 20), vec4<i32>());
textureStore(tex2d_arr, vec2<i32>(10, 20), 50i, vec4<i32>());
textureStore(tex3d, vec3<i32>(10, 20, 30), vec4<i32>());
}
-fn unsigned() {
+fn idx_unsigned() {
textureStore(tex1d, 10u, vec4<i32>());
textureStore(tex2d, vec2<u32>(10, 20), vec4<i32>());
textureStore(tex2d_arr, vec2<u32>(10, 20), 50u, vec4<i32>());
@@ -1000,14 +1000,14 @@
@group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
-fn signed() {
+fn idx_signed() {
textureStore(tex1d, clamp(10i, 0, i32((u32(textureDimensions(tex1d)) - 1))), vec4<i32>());
textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex2d)) - vec2(1)))), vec4<i32>());
textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex2d_arr)) - vec2(1)))), clamp(50i, 0, i32((u32(textureNumLayers(tex2d_arr)) - 1))), vec4<i32>());
textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex3d)) - vec3(1)))), vec4<i32>());
}
-fn unsigned() {
+fn idx_unsigned() {
textureStore(tex1d, min(10u, (u32(textureDimensions(tex1d)) - 1)), vec4<i32>());
textureStore(tex2d, min(vec2<u32>(10, 20), (vec2<u32>(textureDimensions(tex2d)) - vec2(1))), vec4<i32>());
textureStore(tex2d_arr, min(vec2<u32>(10, 20), (vec2<u32>(textureDimensions(tex2d_arr)) - vec2(1))), min(50u, (u32(textureNumLayers(tex2d_arr)) - 1)), vec4<i32>());
@@ -1023,14 +1023,14 @@
// Clamp textureStore() coord, array_index and level values
TEST_F(RobustnessTest, TextureStore_Clamp_OutOfOrder) {
auto* src = R"(
-fn signed() {
+fn idx_signed() {
textureStore(tex1d, 10i, vec4<i32>());
textureStore(tex2d, vec2<i32>(10, 20), vec4<i32>());
textureStore(tex2d_arr, vec2<i32>(10, 20), 50i, vec4<i32>());
textureStore(tex3d, vec3<i32>(10, 20, 30), vec4<i32>());
}
-fn unsigned() {
+fn idx_unsigned() {
textureStore(tex1d, 10u, vec4<i32>());
textureStore(tex2d, vec2<u32>(10, 20), vec4<i32>());
textureStore(tex2d_arr, vec2<u32>(10, 20), 50u, vec4<i32>());
@@ -1048,14 +1048,14 @@
)";
auto* expect = R"(
-fn signed() {
+fn idx_signed() {
textureStore(tex1d, clamp(10i, 0, i32((u32(textureDimensions(tex1d)) - 1))), vec4<i32>());
textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex2d)) - vec2(1)))), vec4<i32>());
textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2(0), vec2<i32>((vec2<u32>(textureDimensions(tex2d_arr)) - vec2(1)))), clamp(50i, 0, i32((u32(textureNumLayers(tex2d_arr)) - 1))), vec4<i32>());
textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3(0), vec3<i32>((vec3<u32>(textureDimensions(tex3d)) - vec3(1)))), vec4<i32>());
}
-fn unsigned() {
+fn idx_unsigned() {
textureStore(tex1d, min(10u, (u32(textureDimensions(tex1d)) - 1)), vec4<i32>());
textureStore(tex2d, min(vec2<u32>(10, 20), (vec2<u32>(textureDimensions(tex2d)) - vec2(1))), vec4<i32>());
textureStore(tex2d_arr, min(vec2<u32>(10, 20), (vec2<u32>(textureDimensions(tex2d_arr)) - vec2(1))), min(50u, (u32(textureNumLayers(tex2d_arr)) - 1)), vec4<i32>());
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/transform/single_entry_point_test.cc
index 7451090..e9fa68f 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/transform/single_entry_point_test.cc
@@ -240,32 +240,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(SingleEntryPointTest, WorkgroupSizeLetPreserved) {
- auto* src = R"(
-let size : i32 = 1;
-
-@compute @workgroup_size(size)
-fn main() {
-}
-)";
-
- auto* expect = R"(
-const size : i32 = 1;
-
-@compute @workgroup_size(size)
-fn main() {
-}
-)";
-
- SingleEntryPoint::Config cfg("main");
-
- DataMap data;
- data.Add<SingleEntryPoint::Config>(cfg);
- auto got = Run<SingleEntryPoint>(src, data);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(SingleEntryPointTest, WorkgroupSizeConstPreserved) {
auto* src = R"(
const size : i32 = 1;
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/transform/unshadow_test.cc
index f5a8102..c731e76 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/transform/unshadow_test.cc
@@ -384,82 +384,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(UnshadowTest, LocalShadowsGlobalLet) {
- auto* src = R"(
-let a : i32 = 1;
-
-fn X() {
- var a = (a == 123);
-}
-
-fn Y() {
- let a = (a == 321);
-}
-
-fn Z() {
- const a = 321;
-}
-)";
-
- auto* expect = R"(
-const a : i32 = 1;
-
-fn X() {
- var a_1 = (a == 123);
-}
-
-fn Y() {
- let a_2 = (a == 321);
-}
-
-fn Z() {
- const a_3 = 321;
-}
-)";
-
- auto got = Run<Unshadow>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(UnshadowTest, LocalShadowsGlobalLet_OutOfOrder) {
- auto* src = R"(
-fn X() {
- var a = (a == 123);
-}
-
-fn Y() {
- let a = (a == 321);
-}
-
-fn Z() {
- const a = 321;
-}
-
-let a : i32 = 1;
-)";
-
- auto* expect = R"(
-fn X() {
- var a_1 = (a == 123);
-}
-
-fn Y() {
- let a_2 = (a == 321);
-}
-
-fn Z() {
- const a_3 = 321;
-}
-
-const a : i32 = 1;
-)";
-
- auto got = Run<Unshadow>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(UnshadowTest, LocalShadowsGlobalConst) {
auto* src = R"(
const a : i32 = 1;
@@ -732,46 +656,6 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(UnshadowTest, ParamShadowsGlobalLet) {
- auto* src = R"(
-let a : i32 = 1;
-
-fn F(a : bool) {
-}
-)";
-
- auto* expect = R"(
-const a : i32 = 1;
-
-fn F(a_1 : bool) {
-}
-)";
-
- auto got = Run<Unshadow>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(UnshadowTest, ParamShadowsGlobalLet_OutOfOrder) {
- auto* src = R"(
-fn F(a : bool) {
-}
-
-let a : i32 = 1;
-)";
-
- auto* expect = R"(
-fn F(a_1 : bool) {
-}
-
-const a : i32 = 1;
-)";
-
- auto got = Run<Unshadow>(src);
-
- EXPECT_EQ(expect, str(got));
-}
-
TEST_F(UnshadowTest, ParamShadowsGlobalConst) {
auto* src = R"(
const a : i32 = 1;