spirv-reader: convert coordinate type when unsigned
In SPIR-V, coordinates for ImageRead, ImageFetch, ImageWrite are
integral. When they are unsigned, they must be converted to signed.
Fix tests for image sampling and dref sampling that used integer
coordinates. SPIR-V requires them to be floating point.
Bug: tint:109
Fixed: tint:346
Change-Id: If33c8970b9d8f7d934d3e582194fe6ed83eff7e8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35560
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: David Neto <dneto@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 9f24f00..ce8deec 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3868,11 +3868,6 @@
arg_index++;
// Push the coordinates operands.
- // TODO(dneto): For explicit-Lod variations, we may have to convert from
- // integral coordinates to floating point coordinates.
- // In WGSL, integer (unnormalized) coordinates are only used for texture
- // fetch (textureLoad on sampled image) or textureLoad or textureStore
- // on storage images.
auto coords = MakeCoordinateOperandsForImageAccess(inst);
if (coords.empty()) {
return false;
@@ -3951,15 +3946,13 @@
}
if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
builtin_name += "Level";
- auto* lod_operand = MakeOperand(inst, arg_index).expr;
- // When sampling from a depth texture, the Lod operand must be an unsigned
- // integer.
+ TypedExpression lod = MakeOperand(inst, arg_index);
+ // When sampling from a depth texture, the Lod operand must be an I32.
if (texture_type->Is<ast::type::DepthTexture>()) {
// Convert it to a signed integer type.
- lod_operand = create<ast::TypeConstructorExpression>(
- Source{}, create<ast::type::I32>(), ast::ExpressionList{lod_operand});
+ lod = ToI32(lod);
}
- params.push_back(lod_operand);
+ params.push_back(lod.expr);
image_operands_mask ^= SpvImageOperandsLodMask;
arg_index++;
}
@@ -4053,6 +4046,17 @@
return {};
}
+ // In SPIR-V for Shader, coordinates are:
+ // - floating point for sampling, dref sampling, gather, dref gather
+ // - integral for fetch, read, write
+ // In WGSL:
+ // - floating point for sampling, dref sampling, gather, dref gather
+ // - signed integral for textureLoad, textureStore
+ //
+ // The only conversions we have to do for WGSL are:
+ // - When the coordinates are unsigned integral, convert them to signed.
+ // - Array index is always i32
+
// The coordinates parameter is always in position 1.
TypedExpression raw_coords(MakeOperand(inst, 1));
if (!raw_coords.type) {
@@ -4107,11 +4111,13 @@
assert(num_axes <= 3);
const auto num_coords_required = num_axes + (is_arrayed ? 1 : 0);
uint32_t num_coords_supplied = 0;
- if (raw_coords.type->is_float_scalar() ||
- raw_coords.type->is_integer_scalar()) {
+ auto* component_type = raw_coords.type;
+ if (component_type->is_float_scalar() ||
+ component_type->is_integer_scalar()) {
num_coords_supplied = 1;
- } else if (auto* vec_ty = raw_coords.type->As<ast::type::Vector>()) {
- num_coords_supplied = vec_ty->size();
+ } else if (auto* vec_type = raw_coords.type->As<ast::type::Vector>()) {
+ component_type = vec_type->type();
+ num_coords_supplied = vec_type->size();
}
if (num_coords_supplied == 0) {
Fail() << "bad or unsupported coordinate type for image access: "
@@ -4127,29 +4133,41 @@
ast::ExpressionList result;
- // TODO(dneto): Convert coordinate component type if needed.
+ // Generates the expression for the WGSL coordinates, when it is a prefix
+ // swizzle with num_axes. If the result would be unsigned, also converts
+ // it to a signed value of the same shape (scalar or vector).
+ // Use a lambda to make it easy to only generate the expressions when we
+ // will actually use them.
+ auto prefix_swizzle_expr = [this, num_axes, component_type,
+ raw_coords]() -> ast::Expression* {
+ auto* swizzle_type =
+ (num_axes == 1) ? component_type
+ : create<ast::type::Vector>(component_type, num_axes);
+ auto* swizzle = create<ast::MemberAccessorExpression>(
+ Source{}, raw_coords.expr, PrefixSwizzle(num_axes));
+ return ToSignedIfUnsigned({swizzle_type, swizzle}).expr;
+ };
+
if (is_arrayed) {
- // The source must be a vector, because it has enough components and has an
- // array component. Use a vector swizzle to get the first `num_axes`
- // components.
- result.push_back(create<ast::MemberAccessorExpression>(
- Source{}, raw_coords.expr, PrefixSwizzle(num_axes)));
+ // The source must be a vector. It has at least one coordinate component
+ // and it must have an array component. Use a vector swizzle to get the
+ // first `num_axes` components.
+ result.push_back(prefix_swizzle_expr());
// Now get the array index.
ast::Expression* array_index = create<ast::MemberAccessorExpression>(
Source{}, raw_coords.expr, Swizzle(num_axes));
- // Convert it to a signed integer type.
- result.push_back(create<ast::TypeConstructorExpression>(
- Source{}, create<ast::type::I32>(), ast::ExpressionList{array_index}));
+ // Convert it to a signed integer type, if needed
+ result.push_back(ToI32({component_type, array_index}).expr);
} else {
if (num_coords_supplied == num_coords_required) {
- // Pass the value through.
- result.push_back(std::move(raw_coords.expr));
+ // Pass the value through, with possible unsigned->signed conversion.
+ result.push_back(ToSignedIfUnsigned(raw_coords).expr);
} else {
- // There are more coordinates supplied than needed. So the source type is
- // a vector. Use a vector swizzle to get the first `num_axes` components.
- result.push_back(create<ast::MemberAccessorExpression>(
- Source{}, raw_coords.expr, PrefixSwizzle(num_axes)));
+ // There are more coordinates supplied than needed. So the source type
+ // is a vector. Use a vector swizzle to get the first `num_axes`
+ // components.
+ result.push_back(prefix_swizzle_expr());
}
}
return result;
@@ -4249,6 +4267,18 @@
Source{}, i32_, ast::ExpressionList{value.expr})};
}
+TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
+ if (!value.type || !value.type->is_unsigned_scalar_or_vector()) {
+ return value;
+ }
+ if (auto* vec_type = value.type->As<ast::type::Vector>()) {
+ auto* new_type = create<ast::type::Vector>(i32_, vec_type->size());
+ return {new_type, create<ast::TypeConstructorExpression>(
+ Source{}, new_type, ast::ExpressionList{value.expr})};
+ }
+ return ToI32(value);
+}
+
FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default;
FunctionEmitter::FunctionDeclaration::~FunctionDeclaration() = default;
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 4b234fb..5d24318 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -701,6 +701,14 @@
/// @returns the value as an I32 value.
TypedExpression ToI32(TypedExpression value);
+ /// Returns the given value as a signed integer type of the same shape
+ /// if the value is unsigned scalar or vector, by wrapping the value
+ /// with a TypeConstructor expression. Returns the value itself if the
+ /// value otherwise.
+ /// @param value the value to pass through or convert
+ /// @returns the value itself, or converted to signed integral
+ TypedExpression ToSignedIfUnsigned(TypedExpression value);
+
private:
/// FunctionDeclaration contains the parsed information for a function header.
struct FunctionDeclaration {
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index bed8be6..e170a28 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -2389,7 +2389,7 @@
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageWrite with no extra params
- {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
+ {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@@ -2404,13 +2404,13 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vf1234}
)
})"},
// OpImageWrite with ConstOffset
{"%float 2D 0 0 0 2 Rgba32f",
- "OpImageWrite %im %vu12 %vf1234 ConstOffset %offsets2d",
+ "OpImageWrite %im %vi12 %vf1234 ConstOffset %offsets2d",
R"(
Variable{
Decorations{
@@ -2425,7 +2425,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vf1234}
Identifier[not set]{offsets2d}
)
@@ -2439,7 +2439,7 @@
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// Source 1 component, dest 1 component
- {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %f1",
+ {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %f1",
R"(
Variable{
Decorations{
@@ -2454,12 +2454,12 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{f1}
)
})"},
// Source 2 component, dest 1 component
- {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf12",
+ {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf12",
R"(
Variable{
Decorations{
@@ -2474,7 +2474,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf12}
Identifier[not set]{x}
@@ -2482,7 +2482,7 @@
)
})"},
// Source 3 component, dest 1 component
- {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf123",
+ {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf123",
R"(
Variable{
Decorations{
@@ -2497,7 +2497,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{x}
@@ -2505,7 +2505,7 @@
)
})"},
// Source 4 component, dest 1 component
- {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf1234",
+ {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@@ -2520,7 +2520,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf1234}
Identifier[not set]{x}
@@ -2528,7 +2528,7 @@
)
})"},
// Source 2 component, dest 2 component
- {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf12",
+ {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf12",
R"(
Variable{
Decorations{
@@ -2543,12 +2543,12 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vf12}
)
})"},
// Source 3 component, dest 2 component
- {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf123",
+ {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf123",
R"(
Variable{
Decorations{
@@ -2563,7 +2563,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
@@ -2571,7 +2571,7 @@
)
})"},
// Source 4 component, dest 2 component
- {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf1234",
+ {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@@ -2586,7 +2586,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf1234}
Identifier[not set]{xy}
@@ -2595,7 +2595,7 @@
})"},
// WGSL does not support 3-component storage textures.
// Source 4 component, dest 4 component
- {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
+ {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@@ -2610,7 +2610,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vf1234}
)
})"}}));
@@ -2761,7 +2761,7 @@
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// Sampled type is unsigned int, texel is unsigned int
- {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vu1234",
+ {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vi12 %vu1234",
R"(
Variable{
Decorations{
@@ -2776,12 +2776,12 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vu1234}
)
})"},
// Sampled type is unsigned int, texel is signed int
- {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vi1234",
+ {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vi12 %vi1234",
R"(
Variable{
Decorations{
@@ -2796,14 +2796,14 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Bitcast[not set]<__vec_4__u32>{
Identifier[not set]{vi1234}
}
)
})"},
// Sampled type is signed int, texel is unsigned int
- {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vu1234",
+ {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vu1234",
R"(
Variable{
Decorations{
@@ -2818,14 +2818,14 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Bitcast[not set]<__vec_4__i32>{
Identifier[not set]{vu1234}
}
)
})"},
// Sampled type is signed int, texel is signed int
- {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vi1234",
+ {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vi1234",
R"(
Variable{
Decorations{
@@ -2840,7 +2840,7 @@
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{vi1234}
)
})"}}));
@@ -2850,7 +2850,7 @@
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageRead with no extra params
- {"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
+ {"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -2870,7 +2870,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -2878,7 +2878,7 @@
})"},
// OpImageRead with ConstOffset
{"%float 2D 0 0 0 2 Rgba32f",
- "%99 = OpImageRead %v4float %im %vu12 ConstOffset %offsets2d",
+ "%99 = OpImageRead %v4float %im %vi12 ConstOffset %offsets2d",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -2898,7 +2898,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{offsets2d}
)
}
@@ -2911,7 +2911,7 @@
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageFetch with no extra params
- {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
+ {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -2931,7 +2931,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -2940,7 +2940,7 @@
// OpImageFetch with ConstOffset
// TODO(dneto): Seems this is not valid in WGSL.
{"%float 2D 0 0 0 1 Unknown",
- "%99 = OpImageFetch %v4float %im %vu12 ConstOffset %offsets2d",
+ "%99 = OpImageFetch %v4float %im %vi12 ConstOffset %offsets2d",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -2960,7 +2960,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
Identifier[not set]{offsets2d}
)
}
@@ -3030,12 +3030,9 @@
Identifier[not set]{vi123}
Identifier[not set]{xy}
}
- TypeConstructor[not set]{
- __i32
- MemberAccessor[not set]{
- Identifier[not set]{vi123}
- Identifier[not set]{z}
- }
+ MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{z}
}
Identifier[not set]{i1}
)
@@ -3099,7 +3096,7 @@
//
// OpImageFetch requires no conversion, float -> v4float
- {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
+ {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3119,14 +3116,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires no conversion, uint -> v4uint
- {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
+ {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3146,14 +3143,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires conversion, uint -> v4int
- {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
+ {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3174,7 +3171,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -3182,7 +3179,7 @@
}
})"},
// OpImageFetch requires no conversion, int -> v4int
- {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
+ {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3202,14 +3199,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires conversion, int -> v4uint
- {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
+ {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3230,7 +3227,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -3243,7 +3240,7 @@
//
// OpImageRead requires no conversion, float -> v4float
- {"%float 2D 0 0 0 1 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
+ {"%float 2D 0 0 0 1 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3263,14 +3260,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires no conversion, uint -> v4uint
- {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4uint %im %vu12",
+ {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3290,14 +3287,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires conversion, uint -> v4int
- {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4int %im %vu12",
+ {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3318,7 +3315,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -3326,7 +3323,7 @@
}
})"},
// OpImageRead requires no conversion, int -> v4int
- {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4int %im %vu12",
+ {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3346,14 +3343,14 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires conversion, int -> v4uint
- {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4uint %im %vu12",
+ {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3374,7 +3371,7 @@
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
- Identifier[not set]{vu12}
+ Identifier[not set]{vi12}
)
}
}
@@ -3388,7 +3385,7 @@
// OpImageSampleImplicitLod requires no conversion, float -> v4float
{"%float 2D 0 0 0 1 Unknown",
- "%99 = OpImageSampleImplicitLod %v4float %sampled_image %vu12",
+ "%99 = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
R"(
Variable{
Decorations{
@@ -3419,7 +3416,7 @@
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
- Identifier[not set]{vu12}
+ Identifier[not set]{vf12}
)
}
}
@@ -3427,7 +3424,7 @@
})"},
// OpImageSampleImplicitLod requires no conversion, uint -> v4uint
{"%uint 2D 0 0 0 1 Unknown",
- "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
+ "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
R"(
Variable{
Decorations{
@@ -3458,7 +3455,7 @@
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
- Identifier[not set]{vu12}
+ Identifier[not set]{vf12}
)
}
}
@@ -3466,7 +3463,7 @@
})"},
// OpImageSampleImplicitLod requires conversion, uint -> v4int
{"%uint 2D 0 0 0 1 Unknown",
- "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
+ "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
R"(
Variable{
Decorations{
@@ -3498,7 +3495,7 @@
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
- Identifier[not set]{vu12}
+ Identifier[not set]{vf12}
)
}
}
@@ -3507,7 +3504,7 @@
})"},
// OpImageSampleImplicitLod requires no conversion, int -> v4int
{"%int 2D 0 0 0 1 Unknown",
- "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
+ "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
R"(
Variable{
Decorations{
@@ -3538,7 +3535,7 @@
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
- Identifier[not set]{vu12}
+ Identifier[not set]{vf12}
)
}
}
@@ -3546,7 +3543,7 @@
})"},
// OpImageSampleImplicitLod requires conversion, int -> v4uint
{"%int 2D 0 0 0 1 Unknown",
- "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
+ "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
R"(Variable{
Decorations{
SetDecoration{2}
@@ -3568,7 +3565,7 @@
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
- Identifier[not set]{vu12}
+ Identifier[not set]{vf12}
)
}
}
@@ -3604,6 +3601,14 @@
OpExecutionMode %100 OriginUpperLeft
OpName %float_var "float_var"
OpName %ptr_float "ptr_float"
+ OpName %i1 "i1"
+ OpName %vi12 "vi12"
+ OpName %vi123 "vi123"
+ OpName %vi1234 "vi1234"
+ OpName %u1 "u1"
+ OpName %vu12 "vu12"
+ OpName %vu123 "vu123"
+ OpName %vu1234 "vu1234"
OpName %f1 "f1"
OpName %vf12 "vf12"
OpName %vf123 "vf123"
@@ -3635,6 +3640,16 @@
%float_var = OpVariable %ptr_float Function
+ %i1 = OpCopyObject %int %int_1
+ %vi12 = OpCopyObject %v2int %the_vi12
+ %vi123 = OpCopyObject %v3int %the_vi123
+ %vi1234 = OpCopyObject %v4int %the_vi1234
+
+ %u1 = OpCopyObject %uint %uint_1
+ %vu12 = OpCopyObject %v2uint %the_vu12
+ %vu123 = OpCopyObject %v3uint %the_vu123
+ %vu1234 = OpCopyObject %v4uint %the_vu1234
+
%f1 = OpCopyObject %float %float_1
%vf12 = OpCopyObject %v2float %the_vf12
%vf123 = OpCopyObject %v3float %the_vf123
@@ -3913,6 +3928,333 @@
)"}}}));
INSTANTIATE_TEST_SUITE_P(
+ PreserveFloatCoords_NonArrayed,
+ // In SPIR-V, sampling and dref sampling operations use floating point
+ // coordinates. Prove that we preserve floating point-ness.
+ // Test across all such instructions.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ // Scalar cases
+ {"%float 1D 0 0 0 1 Unknown",
+ "%result = OpImageSampleImplicitLod %v4float %sampled_image %f1",
+ "",
+ {"Identifier[not set]{f1}\n"}},
+ {"%float 1D 0 0 0 1 Unknown",
+ "%result = OpImageSampleExplicitLod %v4float %sampled_image %f1 Lod "
+ "%f1",
+ "",
+ {"Identifier[not set]{f1}\n"}},
+ // WGSL does not support depth textures with 1D coordinates
+ // Vector cases
+ {"%float 2D 0 0 0 1 Unknown",
+ "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
+ "",
+ {"Identifier[not set]{vf12}\n"}},
+ {"%float 2D 0 0 0 1 Unknown",
+ "%result = OpImageSampleExplicitLod %v4float %sampled_image %vf12 Lod "
+ "%f1",
+ "",
+ {"Identifier[not set]{vf12}\n"}},
+ {"%float 2D 1 0 0 1 Unknown",
+ "%result = OpImageSampleDrefImplicitLod %v4float %sampled_image %vf12 "
+ "%depth",
+ "",
+ {"Identifier[not set]{vf12}\n"}},
+ {"%float 2D 1 0 0 1 Unknown",
+ "%result = OpImageSampleDrefExplicitLod %v4float %sampled_image %vf12 "
+ "%depth Lod %f1",
+ "",
+ {"Identifier[not set]{vf12}\n"}},
+ }));
+
+INSTANTIATE_TEST_SUITE_P(
+ PreserveFloatCoords_Arrayed,
+ // In SPIR-V, sampling and dref sampling operations use floating point
+ // coordinates. Prove that we preserve floating point-ness of the
+ // coordinate part, but convert the array index to signed integer. Test
+ // across all such instructions.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ {"%float 2D 0 1 0 1 Unknown",
+ "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf123",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{z}
+ }
+}
+)"}},
+
+ {"%float 2D 0 1 0 1 Unknown",
+ "%result = OpImageSampleExplicitLod %v4float %sampled_image %vf123 "
+ "Lod %f1",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{z}
+ }
+}
+)"}},
+ {"%float 2D 1 1 0 1 Unknown",
+ "%result = OpImageSampleDrefImplicitLod %v4float %sampled_image "
+ "%vf123 %depth",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{z}
+ }
+}
+)"}},
+ {"%float 2D 1 1 0 1 Unknown",
+ "%result = OpImageSampleDrefExplicitLod %v4float %sampled_image "
+ "%vf123 %depth Lod %f1",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vf123}
+ Identifier[not set]{z}
+ }
+}
+)"}}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ PreserveIntCoords_NonArrayed,
+ // In SPIR-V, image read, fetch, and write use integer coordinates.
+ // Prove that we preserve signed integer coordinates.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ // Scalar cases
+ {"%float 1D 0 0 0 1 Unknown",
+ "%result = OpImageFetch %float %im %i1",
+ "",
+ {"Identifier[not set]{i1}\n"}},
+ {"%float 1D 0 0 0 2 R32f",
+ "%result = OpImageRead %float %im %i1",
+ "",
+ {"Identifier[not set]{i1}\n"}},
+ {"%float 1D 0 0 0 2 R32f",
+ "OpImageWrite %im %i1 %float_1",
+ "",
+ {"Identifier[not set]{i1}\n"}},
+ // Vector cases
+ {"%float 2D 0 0 0 1 Unknown",
+ "%result = OpImageFetch %float %im %vi12",
+ "",
+ {"Identifier[not set]{vi12}\n"}},
+ {"%float 2D 0 0 0 2 R32f",
+ "%result = OpImageRead %float %im %vi12",
+ "",
+ {"Identifier[not set]{vi12}\n"}},
+ {"%float 2D 0 0 0 2 R32f",
+ "OpImageWrite %im %vi12 %float_1",
+ "",
+ {"Identifier[not set]{vi12}\n"}}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ PreserveIntCoords_Arrayed,
+ // In SPIR-V, image read, fetch, and write use integer coordinates.
+ // Prove that we preserve signed integer coordinates.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ {"%float 2D 0 1 0 1 Unknown",
+ "%result = OpImageFetch %float %im %vi123",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{z}
+}
+)"}},
+ {"%float 2D 0 1 0 2 R32f",
+ "%result = OpImageRead %float %im %vi123",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{z}
+}
+)"}},
+ {"%float 2D 0 1 0 2 R32f",
+ "OpImageWrite %im %vi123 %float_1",
+ "",
+ {
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{xy}
+}
+)",
+ R"(MemberAccessor[not set]{
+ Identifier[not set]{vi123}
+ Identifier[not set]{z}
+}
+)"}}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ ConvertUintCoords_NonArrayed,
+ // In SPIR-V, image read, fetch, and write use integer coordinates.
+ // Prove that we convert unsigned integer coordinates to signed.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ // Scalar cases
+ {"%float 1D 0 0 0 1 Unknown",
+ "%result = OpImageFetch %float %im %u1",
+ "",
+ {R"(TypeConstructor[not set]{
+ __i32
+ Identifier[not set]{u1}
+}
+)"}},
+ {"%float 1D 0 0 0 2 R32f",
+ "%result = OpImageRead %float %im %u1",
+ "",
+ {R"(TypeConstructor[not set]{
+ __i32
+ Identifier[not set]{u1}
+}
+)"}},
+ {"%float 1D 0 0 0 2 R32f",
+ "OpImageWrite %im %u1 %float_1",
+ "",
+ {R"(TypeConstructor[not set]{
+ __i32
+ Identifier[not set]{u1}
+}
+)"}},
+ // Vector cases
+ {"%float 2D 0 0 0 1 Unknown",
+ "%result = OpImageFetch %float %im %vu12",
+ "",
+ {R"(TypeConstructor[not set]{
+ __vec_2__i32
+ Identifier[not set]{vu12}
+}
+)"}},
+ {"%float 2D 0 0 0 2 R32f",
+ "%result = OpImageRead %float %im %vu12",
+ "",
+ {R"(TypeConstructor[not set]{
+ __vec_2__i32
+ Identifier[not set]{vu12}
+}
+)"}},
+ {"%float 2D 0 0 0 2 R32f",
+ "OpImageWrite %im %vu12 %float_1",
+ "",
+ {R"(TypeConstructor[not set]{
+ __vec_2__i32
+ Identifier[not set]{vu12}
+}
+)"}}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ ConvertUintCoords_Arrayed,
+ // In SPIR-V, image read, fetch, and write use integer coordinates.
+ // Prove that we convert unsigned integer coordinates to signed.
+ SpvParserTest_ImageCoordsTest,
+ ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+ {"%float 2D 0 1 0 1 Unknown",
+ "%result = OpImageFetch %float %im %vu123",
+ "",
+ {
+ R"(TypeConstructor[not set]{
+ __vec_2__i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{xy}
+ }
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{z}
+ }
+}
+)"}},
+ {"%float 2D 0 1 0 2 R32f",
+ "%result = OpImageRead %float %im %vu123",
+ "",
+ {
+ R"(TypeConstructor[not set]{
+ __vec_2__i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{xy}
+ }
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{z}
+ }
+}
+)"}},
+ {"%float 2D 0 1 0 2 R32f",
+ "OpImageWrite %im %vu123 %float_1",
+ "",
+ {
+ R"(TypeConstructor[not set]{
+ __vec_2__i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{xy}
+ }
+}
+)",
+ R"(TypeConstructor[not set]{
+ __i32
+ MemberAccessor[not set]{
+ Identifier[not set]{vu123}
+ Identifier[not set]{z}
+ }
+}
+)"}}}));
+
+INSTANTIATE_TEST_SUITE_P(
BadInstructions,
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
@@ -3924,7 +4266,7 @@
{"%float 1D 0 0 0 1 Unknown",
"%50 = OpCopyObject %float %float_1",
"internal error: couldn't find image for "
- "%50 = OpCopyObject %9 %36",
+ "%50 = OpCopyObject %18 %44",
{}},
{"%float 1D 0 0 0 1 Unknown",
"OpStore %float_var %float_1",
@@ -3939,40 +4281,40 @@
Bad_Coordinate,
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
- {"%float 2D 0 0 0 1 Unknown",
+ {"%float 1D 0 0 0 1 Unknown",
"%result = OpImageSampleImplicitLod "
// bad type for coordinate: not a number
"%v4float %sampled_image %float_var",
- "bad or unsupported coordinate type for image access: %63 = "
- "OpImageSampleImplicitLod %34 %62 %1",
+ "bad or unsupported coordinate type for image access: %71 = "
+ "OpImageSampleImplicitLod %42 %70 %1",
{}},
{"%float 1D 0 1 0 1 Unknown", // 1DArray
"%result = OpImageSampleImplicitLod "
// 1 component, but need 2
"%v4float %sampled_image %f1",
"image access required 2 coordinate components, but only 1 provided, "
- "in: %63 = OpImageSampleImplicitLod %34 %62 %3",
+ "in: %71 = OpImageSampleImplicitLod %42 %70 %12",
{}},
{"%float 2D 0 0 0 1 Unknown", // 2D
"%result = OpImageSampleImplicitLod "
// 1 component, but need 2
"%v4float %sampled_image %f1",
"image access required 2 coordinate components, but only 1 provided, "
- "in: %63 = OpImageSampleImplicitLod %34 %62 %3",
+ "in: %71 = OpImageSampleImplicitLod %42 %70 %12",
{}},
{"%float 2D 0 1 0 1 Unknown", // 2DArray
"%result = OpImageSampleImplicitLod "
// 2 component, but need 3
"%v4float %sampled_image %vf12",
"image access required 3 coordinate components, but only 2 provided, "
- "in: %63 = OpImageSampleImplicitLod %34 %62 %4",
+ "in: %71 = OpImageSampleImplicitLod %42 %70 %13",
{}},
{"%float 3D 0 0 0 1 Unknown", // 3D
"%result = OpImageSampleImplicitLod "
// 2 components, but need 3
"%v4float %sampled_image %vf12",
"image access required 3 coordinate components, but only 2 provided, "
- "in: %63 = OpImageSampleImplicitLod %34 %62 %4",
+ "in: %71 = OpImageSampleImplicitLod %42 %70 %13",
{}},
}));