Remove support for the @stride attribute

We still use the StrideAttribute AST node in the SPIR-V reader for
strided arrays and matrices, which are then removed by transforms.

The WGSL parser no longer has to handle attributes on types.

Bug: tint:1381
Change-Id: Ifa39575ce207d3fdfcbef7125fe6a3686fad5f20
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/83963
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
James Price 2022-03-21 16:09:17 +00:00
parent 1a72a76e4f
commit dfc1a2c081
32 changed files with 151 additions and 1905 deletions

View File

@ -5,6 +5,7 @@
### Breaking changes ### Breaking changes
* The `@block` attribute has been removed. [tint:1324](crbug.com/tint/1324) * The `@block` attribute has been removed. [tint:1324](crbug.com/tint/1324)
* The `@stride` attribute has been removed. [tint:1381](crbug.com/tint/1381)
* Attributes using `[[attribute]]` syntax are no longer supported. [tint:1382](crbug.com/tint/1382) * Attributes using `[[attribute]]` syntax are no longer supported. [tint:1382](crbug.com/tint/1382)
## Changes for M101 ## Changes for M101

View File

@ -467,8 +467,6 @@ libtint_source_set("libtint_core_all_src") {
"transform/multiplanar_external_texture.h", "transform/multiplanar_external_texture.h",
"transform/num_workgroups_from_uniform.cc", "transform/num_workgroups_from_uniform.cc",
"transform/num_workgroups_from_uniform.h", "transform/num_workgroups_from_uniform.h",
"transform/pad_array_elements.cc",
"transform/pad_array_elements.h",
"transform/promote_initializers_to_const_var.cc", "transform/promote_initializers_to_const_var.cc",
"transform/promote_initializers_to_const_var.h", "transform/promote_initializers_to_const_var.h",
"transform/promote_side_effects_to_decl.cc", "transform/promote_side_effects_to_decl.cc",

View File

@ -345,8 +345,6 @@ set(TINT_LIB_SRCS
transform/multiplanar_external_texture.h transform/multiplanar_external_texture.h
transform/num_workgroups_from_uniform.cc transform/num_workgroups_from_uniform.cc
transform/num_workgroups_from_uniform.h transform/num_workgroups_from_uniform.h
transform/pad_array_elements.cc
transform/pad_array_elements.h
transform/promote_initializers_to_const_var.cc transform/promote_initializers_to_const_var.cc
transform/promote_initializers_to_const_var.h transform/promote_initializers_to_const_var.h
transform/promote_side_effects_to_decl.cc transform/promote_side_effects_to_decl.cc
@ -1023,7 +1021,6 @@ if(TINT_BUILD_TESTS)
transform/module_scope_var_to_entry_point_param_test.cc transform/module_scope_var_to_entry_point_param_test.cc
transform/multiplanar_external_texture_test.cc transform/multiplanar_external_texture_test.cc
transform/num_workgroups_from_uniform_test.cc transform/num_workgroups_from_uniform_test.cc
transform/pad_array_elements_test.cc
transform/promote_initializers_to_const_var_test.cc transform/promote_initializers_to_const_var_test.cc
transform/promote_side_effects_to_decl_test.cc transform/promote_side_effects_to_decl_test.cc
transform/remove_phonies_test.cc transform/remove_phonies_test.cc

View File

@ -41,7 +41,7 @@ struct S1 {
let c0 : i32 = 10; let c0 : i32 = 10;
let c1 : bool = true; let c1 : bool = true;
type t0 = @stride(16) array<vec4<f32>>; type t0 = array<vec4<f32>>;
type t1 = array<vec4<f32>>; type t1 = array<vec4<f32>>;
var<private> g0 : u32 = 20u; var<private> g0 : u32 = 20u;

View File

@ -18,11 +18,13 @@
#include <string> #include <string>
#include "src/tint/ast/attribute.h" #include "src/tint/ast/attribute.h"
#include "src/tint/ast/internal_attribute.h"
namespace tint { namespace tint {
namespace ast { namespace ast {
/// A stride attribute /// A stride attribute used by the SPIR-V reader for strided arrays and
/// matrices.
class StrideAttribute final : public Castable<StrideAttribute, Attribute> { class StrideAttribute final : public Castable<StrideAttribute, Attribute> {
public: public:
/// constructor /// constructor

View File

@ -119,7 +119,6 @@ const char kLocationAttribute[] = "location";
const char kSizeAttribute[] = "size"; const char kSizeAttribute[] = "size";
const char kAlignAttribute[] = "align"; const char kAlignAttribute[] = "align";
const char kStageAttribute[] = "stage"; const char kStageAttribute[] = "stage";
const char kStrideAttribute[] = "stride";
const char kWorkgroupSizeAttribute[] = "workgroup_size"; const char kWorkgroupSizeAttribute[] = "workgroup_size";
// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords // https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
@ -799,7 +798,7 @@ Expect<ast::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
} }
// variable_ident_decl // variable_ident_decl
// : IDENT COLON variable_attribute_list* type_decl // : IDENT COLON type_decl
Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl( Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
std::string_view use, std::string_view use,
bool allow_inferred) { bool allow_inferred) {
@ -814,20 +813,13 @@ Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
if (!expect(use, Token::Type::kColon)) if (!expect(use, Token::Type::kColon))
return Failure::kErrored; return Failure::kErrored;
auto attrs = attribute_list();
if (attrs.errored)
return Failure::kErrored;
auto t = peek(); auto t = peek();
auto type = type_decl(attrs.value); auto type = type_decl();
if (type.errored) if (type.errored)
return Failure::kErrored; return Failure::kErrored;
if (!type.matched) if (!type.matched)
return add_error(t.source(), "invalid type", use); return add_error(t.source(), "invalid type", use);
if (!expect_attributes_consumed(attrs.value))
return Failure::kErrored;
return TypedIdentifier{type.value, ident.value, ident.source}; return TypedIdentifier{type.value, ident.value, ident.source};
} }
@ -929,25 +921,6 @@ Maybe<const ast::Alias*> ParserImpl::type_alias() {
// | MAT4x4 LESS_THAN type_decl GREATER_THAN // | MAT4x4 LESS_THAN type_decl GREATER_THAN
// | texture_sampler_types // | texture_sampler_types
Maybe<const ast::Type*> ParserImpl::type_decl() { Maybe<const ast::Type*> ParserImpl::type_decl() {
auto attrs = attribute_list();
if (attrs.errored)
return Failure::kErrored;
auto type = type_decl(attrs.value);
if (type.errored) {
return Failure::kErrored;
}
if (!expect_attributes_consumed(attrs.value)) {
return Failure::kErrored;
}
if (!type.matched) {
return Failure::kNoMatch;
}
return type;
}
Maybe<const ast::Type*> ParserImpl::type_decl(ast::AttributeList& attrs) {
auto t = peek(); auto t = peek();
Source source; Source source;
if (match(Token::Type::kIdentifier, &source)) { if (match(Token::Type::kIdentifier, &source)) {
@ -981,7 +954,7 @@ Maybe<const ast::Type*> ParserImpl::type_decl(ast::AttributeList& attrs) {
} }
if (match(Token::Type::kArray, &source)) { if (match(Token::Type::kArray, &source)) {
return expect_type_decl_array(t, std::move(attrs)); return expect_type_decl_array(t);
} }
if (t.IsMatrix()) { if (t.IsMatrix()) {
@ -1080,9 +1053,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
return builder_.ty.vec(make_source_range_from(t.source()), subtype, count); return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
} }
Expect<const ast::Type*> ParserImpl::expect_type_decl_array( Expect<const ast::Type*> ParserImpl::expect_type_decl_array(Token t) {
Token t,
ast::AttributeList attrs) {
const char* use = "array declaration"; const char* use = "array declaration";
const ast::Expression* size = nullptr; const ast::Expression* size = nullptr;
@ -1111,7 +1082,7 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_array(
} }
return builder_.ty.array(make_source_range_from(t.source()), subtype.value, return builder_.ty.array(make_source_range_from(t.source()), subtype.value,
size, std::move(attrs)); size);
} }
Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) { Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
@ -1321,19 +1292,7 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
} }
return_attributes = attrs.value; return_attributes = attrs.value;
// Apply stride attributes to the type node instead of the function. auto type = type_decl();
ast::AttributeList type_attributes;
auto itr =
std::find_if(return_attributes.begin(), return_attributes.end(),
[](auto* attr) { return Is<ast::StrideAttribute>(attr); });
if (itr != return_attributes.end()) {
type_attributes.emplace_back(*itr);
return_attributes.erase(itr);
}
auto tok = peek();
auto type = type_decl(type_attributes);
if (type.errored) { if (type.errored) {
errored = true; errored = true;
} else if (!type.matched) { } else if (!type.matched) {
@ -2974,19 +2933,6 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
}); });
} }
if (t == kStrideAttribute) {
const char* use = "stride attribute";
return expect_paren_block(use, [&]() -> Result {
auto val = expect_nonzero_positive_sint(use);
if (val.errored)
return Failure::kErrored;
deprecated(t.source(),
"the @stride attribute is deprecated; use a larger type if "
"necessary");
return create<ast::StrideAttribute>(t.source(), val.value);
});
}
if (t == kSizeAttribute) { if (t == kSizeAttribute) {
const char* use = "size attribute"; const char* use = "size attribute";
return expect_paren_block(use, [&]() -> Result { return expect_paren_block(use, [&]() -> Result {

View File

@ -419,11 +419,6 @@ class ParserImpl {
/// Parses a `type_decl` grammar element /// Parses a `type_decl` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
Maybe<const ast::Type*> type_decl(); Maybe<const ast::Type*> type_decl();
/// Parses a `type_decl` grammar element with the given pre-parsed
/// attributes.
/// @param attrs the list of attributes for the type.
/// @returns the parsed Type or nullptr if none matched.
Maybe<const ast::Type*> type_decl(ast::AttributeList& attrs);
/// Parses a `storage_class` grammar element, erroring on parse failure. /// Parses a `storage_class` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised. /// @param use a description of what was being parsed if an error was raised.
/// @returns the storage class or StorageClass::kNone if none matched /// @returns the storage class or StorageClass::kNone if none matched
@ -849,8 +844,7 @@ class ParserImpl {
Expect<const ast::Type*> expect_type_decl_pointer(Token t); Expect<const ast::Type*> expect_type_decl_pointer(Token t);
Expect<const ast::Type*> expect_type_decl_atomic(Token t); Expect<const ast::Type*> expect_type_decl_atomic(Token t);
Expect<const ast::Type*> expect_type_decl_vector(Token t); Expect<const ast::Type*> expect_type_decl_vector(Token t);
Expect<const ast::Type*> expect_type_decl_array(Token t, Expect<const ast::Type*> expect_type_decl_array(Token t);
ast::AttributeList attrs);
Expect<const ast::Type*> expect_type_decl_matrix(Token t); Expect<const ast::Type*> expect_type_decl_matrix(Token t);
Expect<const ast::Type*> expect_type(std::string_view use); Expect<const ast::Type*> expect_type(std::string_view use);

View File

@ -445,9 +445,9 @@ fn f() {
TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) { TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) {
EXPECT("fn f(a:i32)->i32{return a;@size(1)}", EXPECT("fn f(a:i32)->i32{return a;@size(1)}",
R"(test.wgsl:1:28 error: unexpected attributes R"(test.wgsl:1:27 error: expected '}'
fn f(a:i32)->i32{return a;@size(1)} fn f(a:i32)->i32{return a;@size(1)}
^^^^ ^
)"); )");
} }
@ -774,31 +774,6 @@ var i : array<u32, 3;
)"); )");
} }
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayAttrNotArray) {
EXPECT("var i : @location(1) i32;",
R"(test.wgsl:1:10 error: unexpected attributes
var i : @location(1) i32;
^^^^^^^^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayStrideInvalid) {
EXPECT(
"var i : @stride(x) array<i32>;",
R"(test.wgsl:1:17 error: expected signed integer literal for stride attribute
var i : @stride(x) array<i32>;
^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayStrideNegative) {
EXPECT("var i : @stride(-1) array<i32>;",
R"(test.wgsl:1:17 error: stride attribute must be greater than 0
var i : @stride(-1) array<i32>;
^^
)");
}
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) { TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
EXPECT("var i : array<1, 3>;", EXPECT("var i : array<1, 3>;",
R"(test.wgsl:1:15 error: invalid type for array declaration R"(test.wgsl:1:15 error: invalid type for array declaration

View File

@ -75,27 +75,6 @@ TEST_F(ParserImplTest, FunctionHeader_InvariantReturnType) {
EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>()); EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
} }
TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType_WithArrayStride) {
auto p = parser("fn main() -> @location(1) @stride(16) array<f32, 4>");
auto f = p->function_header();
ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(f.matched);
EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main");
EXPECT_EQ(f->params.size(), 0u);
ASSERT_EQ(f->return_type_attributes.size(), 1u);
auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
ASSERT_TRUE(loc != nullptr);
EXPECT_EQ(loc->value, 1u);
auto* array_type = f->return_type->As<ast::Array>();
ASSERT_EQ(array_type->attributes.size(), 1u);
auto* stride = array_type->attributes[0]->As<ast::StrideAttribute>();
ASSERT_TRUE(stride != nullptr);
EXPECT_EQ(stride->stride, 16u);
}
TEST_F(ParserImplTest, FunctionHeader_MissingIdent) { TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
auto p = parser("fn ()"); auto p = parser("fn ()");
auto f = p->function_header(); auto f = p->function_header();

View File

@ -166,33 +166,6 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
EXPECT_EQ(str->members.size(), 2u); EXPECT_EQ(str->members.size(), 2u);
} }
TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
auto p = parser("struct A { data: @stride(4) array<f32>; }");
p->expect_global_decl();
ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program();
ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
auto* t = program.AST().TypeDecls()[0];
ASSERT_NE(t, nullptr);
ASSERT_TRUE(t->Is<ast::Struct>());
auto* str = t->As<ast::Struct>();
EXPECT_EQ(str->name, program.Symbols().Get("A"));
EXPECT_EQ(str->members.size(), 1u);
const auto* ty = str->members[0]->type;
ASSERT_TRUE(ty->Is<ast::Array>());
const auto* arr = ty->As<ast::Array>();
ASSERT_EQ(arr->attributes.size(), 1u);
auto* stride = arr->attributes[0];
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 4u);
}
TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) { TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
auto p = parser("A {}"); auto p = parser("A {}");
p->expect_global_decl(); p->expect_global_decl();

View File

@ -439,172 +439,6 @@ TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size"); EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
auto p = parser("@stride(16) array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t.value->Is<ast::Array>());
auto* a = t.value->As<ast::Array>();
ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
auto* size = a->count->As<ast::SintLiteralExpression>();
ASSERT_NE(size, nullptr);
EXPECT_EQ(size->ValueAsI32(), 5);
ASSERT_EQ(a->attributes.size(), 1u);
auto* stride = a->attributes[0];
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 16u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 13u}, {1u, 26u}}));
}
TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
auto p = parser("@stride(16) array<f32>");
auto t = p->type_decl();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t.value->Is<ast::Array>());
auto* a = t.value->As<ast::Array>();
ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
ASSERT_EQ(a->attributes.size(), 1u);
auto* stride = a->attributes[0];
ASSERT_TRUE(stride->Is<ast::StrideAttribute>());
ASSERT_EQ(stride->As<ast::StrideAttribute>()->stride, 16u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 13u}, {1u, 23u}}));
}
TEST_F(ParserImplTest, TypeDecl_Array_MultipleAttributes_OneBlock) {
auto p = parser("@stride(16) @stride(32) array<f32>");
auto t = p->type_decl();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t.value->Is<ast::Array>());
auto* a = t.value->As<ast::Array>();
ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
auto& attrs = a->attributes;
ASSERT_EQ(attrs.size(), 2u);
EXPECT_TRUE(attrs[0]->Is<ast::StrideAttribute>());
EXPECT_EQ(attrs[0]->As<ast::StrideAttribute>()->stride, 16u);
EXPECT_TRUE(attrs[1]->Is<ast::StrideAttribute>());
EXPECT_EQ(attrs[1]->As<ast::StrideAttribute>()->stride, 32u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 25u}, {1u, 35u}}));
}
TEST_F(ParserImplTest, TypeDecl_Array_MultipleAttributes_MultipleBlocks) {
auto p = parser("@stride(16) @stride(32) array<f32>");
auto t = p->type_decl();
EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t.value->Is<ast::Array>());
auto* a = t.value->As<ast::Array>();
ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type->Is<ast::F32>());
auto& attrs = a->attributes;
ASSERT_EQ(attrs.size(), 2u);
EXPECT_TRUE(attrs[0]->Is<ast::StrideAttribute>());
EXPECT_EQ(attrs[0]->As<ast::StrideAttribute>()->stride, 16u);
EXPECT_TRUE(attrs[1]->Is<ast::StrideAttribute>());
EXPECT_EQ(attrs[1]->As<ast::StrideAttribute>()->stride, 32u);
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 25u}, {1u, 35u}}));
}
TEST_F(ParserImplTest, TypeDecl_Array_Attribute_MissingArray) {
auto p = parser("@stride(16) f32");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(
p->error(),
R"(1:2: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
1:2: unexpected attributes)");
}
TEST_F(ParserImplTest, TypeDecl_Array_Attribute_UnknownAttribute) {
auto p = parser("@unknown(16) array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
}
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) {
auto p = parser("@stride 4) array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:9: expected '(' for stride attribute)");
}
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) {
auto p = parser("@stride(4 array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(
p->error(),
R"(1:2: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
1:11: expected ')' for stride attribute)");
}
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) {
auto p = parser("@stride() array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(),
"1:9: expected signed integer literal for stride attribute");
}
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
auto p = parser("@stride(invalid) array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(),
"1:9: expected signed integer literal for stride attribute");
}
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) {
auto p = parser("@stride(-1) array<f32, 5>");
auto t = p->type_decl();
EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: stride attribute must be greater than 0");
}
TEST_F(ParserImplTest, TypeDecl_Array_Runtime) { TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
auto p = parser("array<u32>"); auto p = parser("array<u32>");
auto t = p->type_decl(); auto t = p->type_decl();

View File

@ -75,35 +75,6 @@ TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
ASSERT_EQ(p->error(), "1:1: expected identifier for test"); ASSERT_EQ(p->error(), "1:1: expected identifier for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_NonAccessAttrFail) {
auto p = parser("my_var : @location(1) S");
auto* mem = Member("a", ty.i32(), ast::AttributeList{});
ast::StructMemberList members;
members.push_back(mem);
auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:11: unexpected attributes");
}
TEST_F(ParserImplTest, VariableIdentDecl_AttributeMissingRightParen) {
auto p = parser("my_var : @location(4 S");
auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:22: expected ')' for location attribute");
}
TEST_F(ParserImplTest, VariableIdentDecl_AttributeMissingLeftParen) {
auto p = parser("my_var : @stride 4) S");
auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:18: expected '(' for stride attribute");
}
} // namespace } // namespace
} // namespace wgsl } // namespace wgsl
} // namespace reader } // namespace reader

View File

@ -177,94 +177,6 @@ fn main() {
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices); got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
} }
TEST_F(ArrayLengthFromUniformTest, WithStride) {
auto* src = R"(
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = arrayLength(&sb);
}
)";
auto* expect = R"(
struct tint_symbol {
buffer_size : array<vec4<u32>, 1u>;
}
@group(0) @binding(30) var<uniform> tint_symbol_1 : tint_symbol;
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = (tint_symbol_1.buffer_size[0u][0u] / 64u);
}
)";
ArrayLengthFromUniform::Config cfg({0, 30u});
cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
DataMap data;
data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
EXPECT_EQ(expect, str(got));
EXPECT_EQ(std::unordered_set<uint32_t>({0}),
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
}
TEST_F(ArrayLengthFromUniformTest, WithStride_InStruct) {
auto* src = R"(
struct SB {
x : i32;
y : f32;
arr : @stride(64) array<i32>;
};
@group(0) @binding(0) var<storage, read> sb : SB;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = arrayLength(&sb.arr);
}
)";
auto* expect = R"(
struct tint_symbol {
buffer_size : array<vec4<u32>, 1u>;
}
@group(0) @binding(30) var<uniform> tint_symbol_1 : tint_symbol;
struct SB {
x : i32;
y : f32;
arr : @stride(64) array<i32>;
}
@group(0) @binding(0) var<storage, read> sb : SB;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = ((tint_symbol_1.buffer_size[0u][0u] - 8u) / 64u);
}
)";
ArrayLengthFromUniform::Config cfg({0, 30u});
cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
DataMap data;
data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
EXPECT_EQ(expect, str(got));
EXPECT_EQ(std::unordered_set<uint32_t>({0}),
got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
}
TEST_F(ArrayLengthFromUniformTest, MultipleStorageBuffers) { TEST_F(ArrayLengthFromUniformTest, MultipleStorageBuffers) {
auto* src = R"( auto* src = R"(
struct SB1 { struct SB1 {

View File

@ -287,78 +287,6 @@ fn main() {
EXPECT_EQ(expect, str(got)); EXPECT_EQ(expect, str(got));
} }
TEST_F(CalculateArrayLengthTest, WithStride) {
auto* src = R"(
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = arrayLength(&sb);
}
)";
auto* expect = R"(
@internal(intrinsic_buffer_size)
fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : @stride(64) array<i32>, result : ptr<function, u32>)
@group(0) @binding(0) var<storage, read> sb : @stride(64) array<i32>;
@stage(compute) @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
tint_symbol(sb, &(tint_symbol_1));
let tint_symbol_2 : u32 = (tint_symbol_1 / 64u);
var len : u32 = tint_symbol_2;
}
)";
auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(CalculateArrayLengthTest, WithStride_InStruct) {
auto* src = R"(
struct SB {
x : i32;
y : f32;
arr : @stride(64) array<i32>;
};
@group(0) @binding(0) var<storage, read> sb : SB;
@stage(compute) @workgroup_size(1)
fn main() {
var len : u32 = arrayLength(&sb.arr);
}
)";
auto* expect = R"(
@internal(intrinsic_buffer_size)
fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
struct SB {
x : i32;
y : f32;
arr : @stride(64) array<i32>;
}
@group(0) @binding(0) var<storage, read> sb : SB;
@stage(compute) @workgroup_size(1)
fn main() {
var tint_symbol_1 : u32 = 0u;
tint_symbol(sb, &(tint_symbol_1));
let tint_symbol_2 : u32 = ((tint_symbol_1 - 8u) / 64u);
var len : u32 = tint_symbol_2;
}
)";
auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(CalculateArrayLengthTest, Nested) { TEST_F(CalculateArrayLengthTest, Nested) {
auto* src = R"( auto* src = R"(
struct SB { struct SB {

View File

@ -1970,22 +1970,26 @@ struct SB {
TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) { TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) {
auto* src = R"( auto* src = R"(
// sizeof(S1) == 32
// alignof(S1) == 16
struct S1 { struct S1 {
a : i32; a : i32;
b : vec3<f32>; b : vec3<f32>;
c : i32; c : i32;
}; };
// sizeof(S2) == 116
// alignof(S2) == 16
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
}; };
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
}; };
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -1999,9 +2003,9 @@ fn main() {
// sb.b[4].b[1].b.z // sb.b[4].b[1].b.z
// ^ ^ ^ ^ ^ ^ // ^ ^ ^ ^ ^ ^
// | | | | | | // | | | | | |
// 128 | |1200| 1224 // 128 | |688 | 712
// | | | // | | |
// 1152 1168 1216 // 640 656 704
auto* expect = R"( auto* expect = R"(
struct S1 { struct S1 {
@ -2012,14 +2016,14 @@ struct S1 {
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
} }
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
} }
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2029,7 +2033,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
@stage(compute) @workgroup_size(1) @stage(compute) @workgroup_size(1)
fn main() { fn main() {
var x : f32 = tint_symbol(sb, 1224u); var x : f32 = tint_symbol(sb, 712u);
} }
)"; )";
@ -2050,12 +2054,12 @@ fn main() {
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
}; };
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
}; };
@ -2069,9 +2073,9 @@ struct S1 {
// sb.b[4].b[1].b.z // sb.b[4].b[1].b.z
// ^ ^ ^ ^ ^ ^ // ^ ^ ^ ^ ^ ^
// | | | | | | // | | | | | |
// 128 | |1200| 1224 // 128 | |688 | 712
// | | | // | | |
// 1152 1168 1216 // 640 656 704
auto* expect = R"( auto* expect = R"(
@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body) @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
@ -2079,7 +2083,7 @@ fn tint_symbol(@internal(disable_validation__ignore_constructible_function_param
@stage(compute) @workgroup_size(1) @stage(compute) @workgroup_size(1)
fn main() { fn main() {
var x : f32 = tint_symbol(sb, 1224u); var x : f32 = tint_symbol(sb, 712u);
} }
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2087,12 +2091,12 @@ fn main() {
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
} }
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
} }
@ -2118,14 +2122,14 @@ struct S1 {
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
}; };
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
}; };
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2148,14 +2152,14 @@ struct S1 {
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
} }
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
} }
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2168,7 +2172,7 @@ fn main() {
var i : i32 = 4; var i : i32 = 4;
var j : u32 = 1u; var j : u32 = 1u;
var k : i32 = 2; var k : i32 = 2;
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k)))); var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
} }
)"; )";
@ -2192,12 +2196,12 @@ fn main() {
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b :array<S2>;
}; };
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
}; };
@ -2217,7 +2221,7 @@ fn main() {
var i : i32 = 4; var i : i32 = 4;
var j : u32 = 1u; var j : u32 = 1u;
var k : i32 = 2; var k : i32 = 2;
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k)))); var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
} }
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2225,12 +2229,12 @@ fn main() {
struct SB { struct SB {
@size(128) @size(128)
a : i32; a : i32;
b : @stride(256) array<S2>; b : array<S2>;
} }
struct S2 { struct S2 {
a : i32; a : i32;
b : @stride(32) array<S1, 3>; b : array<S1, 3>;
c : i32; c : i32;
} }
@ -2256,7 +2260,7 @@ struct S1 {
type A1 = S1; type A1 = S1;
type A1_Array = @stride(32) array<S1, 3>; type A1_Array = array<S1, 3>;
struct S2 { struct S2 {
a : i32; a : i32;
@ -2266,7 +2270,7 @@ struct S2 {
type A2 = S2; type A2 = S2;
type A2_Array = @stride(256) array<S2>; type A2_Array = array<S2>;
struct SB { struct SB {
@size(128) @size(128)
@ -2294,7 +2298,7 @@ struct S1 {
type A1 = S1; type A1 = S1;
type A1_Array = @stride(32) array<S1, 3>; type A1_Array = array<S1, 3>;
struct S2 { struct S2 {
a : i32; a : i32;
@ -2304,7 +2308,7 @@ struct S2 {
type A2 = S2; type A2 = S2;
type A2_Array = @stride(256) array<S2>; type A2_Array = array<S2>;
struct SB { struct SB {
@size(128) @size(128)
@ -2322,7 +2326,7 @@ fn main() {
var i : i32 = 4; var i : i32 = 4;
var j : u32 = 1u; var j : u32 = 1u;
var k : i32 = 2; var k : i32 = 2;
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k)))); var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
} }
)"; )";
@ -2350,7 +2354,7 @@ struct SB {
b : A2_Array; b : A2_Array;
}; };
type A2_Array = @stride(256) array<S2>; type A2_Array = array<S2>;
type A2 = S2; type A2 = S2;
@ -2362,7 +2366,7 @@ struct S2 {
type A1 = S1; type A1 = S1;
type A1_Array = @stride(32) array<S1, 3>; type A1_Array = array<S1, 3>;
struct S1 { struct S1 {
a : i32; a : i32;
@ -2380,7 +2384,7 @@ fn main() {
var i : i32 = 4; var i : i32 = 4;
var j : u32 = 1u; var j : u32 = 1u;
var k : i32 = 2; var k : i32 = 2;
var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k)))); var x : f32 = tint_symbol(sb, (((((128u + (128u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
} }
@group(0) @binding(0) var<storage, read_write> sb : SB; @group(0) @binding(0) var<storage, read_write> sb : SB;
@ -2391,7 +2395,7 @@ struct SB {
b : A2_Array; b : A2_Array;
} }
type A2_Array = @stride(256) array<S2>; type A2_Array = array<S2>;
type A2 = S2; type A2 = S2;
@ -2403,7 +2407,7 @@ struct S2 {
type A1 = S1; type A1 = S1;
type A1_Array = @stride(32) array<S1, 3>; type A1_Array = array<S1, 3>;
struct S1 { struct S1 {
a : i32; a : i32;

View File

@ -27,7 +27,6 @@
#include "src/tint/transform/fold_trivial_single_use_lets.h" #include "src/tint/transform/fold_trivial_single_use_lets.h"
#include "src/tint/transform/loop_to_for_loop.h" #include "src/tint/transform/loop_to_for_loop.h"
#include "src/tint/transform/manager.h" #include "src/tint/transform/manager.h"
#include "src/tint/transform/pad_array_elements.h"
#include "src/tint/transform/promote_initializers_to_const_var.h" #include "src/tint/transform/promote_initializers_to_const_var.h"
#include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h" #include "src/tint/transform/remove_phonies.h"
@ -105,7 +104,6 @@ Output Glsl::Run(const Program* in, const DataMap& inputs) const {
} }
manager.Add<PromoteInitializersToConstVar>(); manager.Add<PromoteInitializersToConstVar>();
manager.Add<PadArrayElements>();
manager.Add<AddEmptyEntryPoint>(); manager.Add<AddEmptyEntryPoint>();
manager.Add<AddSpirvBlockAttribute>(); manager.Add<AddSpirvBlockAttribute>();

View File

@ -1,177 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/transform/pad_array_elements.h"
#include <unordered_map>
#include <utility>
#include "src/tint/program_builder.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/expression.h"
#include "src/tint/sem/type_constructor.h"
#include "src/tint/utils/map.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::PadArrayElements);
namespace tint {
namespace transform {
namespace {
using ArrayBuilder = std::function<const ast::Array*()>;
/// PadArray returns a function that constructs a new array in `ctx.dst` with
/// the element type padded to account for the explicit stride. PadArray will
/// recursively pad arrays-of-arrays. The new array element type will be added
/// to module-scope type declarations of `ctx.dst`.
/// @param ctx the CloneContext
/// @param create_ast_type_for Transform::CreateASTTypeFor()
/// @param padded_arrays a map of src array type to the new array name
/// @param array the array type
/// @return the new AST array
template <typename CREATE_AST_TYPE_FOR>
ArrayBuilder PadArray(
CloneContext& ctx,
CREATE_AST_TYPE_FOR&& create_ast_type_for,
std::unordered_map<const sem::Array*, ArrayBuilder>& padded_arrays,
const sem::Array* array) {
if (array->IsStrideImplicit()) {
// We don't want to wrap arrays that have an implicit stride
return nullptr;
}
return utils::GetOrCreate(padded_arrays, array, [&] {
// Generate a unique name for the array element type
auto name = ctx.dst->Symbols().New("tint_padded_array_element");
// Examine the element type. Is it also an array?
const ast::Type* el_ty = nullptr;
if (auto* el_array = array->ElemType()->As<sem::Array>()) {
// Array of array - call PadArray() on the element type
if (auto p =
PadArray(ctx, create_ast_type_for, padded_arrays, el_array)) {
el_ty = p();
}
}
// If the element wasn't a padded array, just create the typical AST type
// for it
if (el_ty == nullptr) {
el_ty = create_ast_type_for(ctx, array->ElemType());
}
// Structure() will create and append the ast::Struct to the
// global declarations of `ctx.dst`. As we haven't finished building the
// current module-scope statement or function, this will be placed
// immediately before the usage.
ctx.dst->Structure(
name,
{ctx.dst->Member("el", el_ty, {ctx.dst->MemberSize(array->Stride())})});
auto* dst = ctx.dst;
return [=] {
if (array->IsRuntimeSized()) {
return dst->ty.array(dst->create<ast::TypeName>(name));
} else {
return dst->ty.array(dst->create<ast::TypeName>(name), array->Count());
}
};
});
}
} // namespace
PadArrayElements::PadArrayElements() = default;
PadArrayElements::~PadArrayElements() = default;
bool PadArrayElements::ShouldRun(const Program* program, const DataMap&) const {
for (auto* node : program->ASTNodes().Objects()) {
if (auto* var = node->As<ast::Type>()) {
if (auto* arr = program->Sem().Get<sem::Array>(var)) {
if (!arr->IsStrideImplicit()) {
return true;
}
}
}
}
return false;
}
void PadArrayElements::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
auto& sem = ctx.src->Sem();
std::unordered_map<const sem::Array*, ArrayBuilder> padded_arrays;
auto pad = [&](const sem::Array* array) {
return PadArray(ctx, CreateASTTypeFor, padded_arrays, array);
};
// Replace all array types with their corresponding padded array type
ctx.ReplaceAll([&](const ast::Type* ast_type) -> const ast::Type* {
auto* type = ctx.src->TypeOf(ast_type);
if (auto* array = type->UnwrapRef()->As<sem::Array>()) {
if (auto p = pad(array)) {
return p();
}
}
return nullptr;
});
// Fix up index accessors so `a[1]` becomes `a[1].el`
ctx.ReplaceAll([&](const ast::IndexAccessorExpression* accessor)
-> const ast::Expression* {
if (auto* array = tint::As<sem::Array>(
sem.Get(accessor->object)->Type()->UnwrapRef())) {
if (pad(array)) {
// Array element is wrapped in a structure. Emit a member accessor
// to get to the actual array element.
auto* idx = ctx.CloneWithoutTransform(accessor);
return ctx.dst->MemberAccessor(idx, "el");
}
}
return nullptr;
});
// Fix up array constructors so `A(1,2)` becomes
// `A(padded(1), padded(2))`
ctx.ReplaceAll(
[&](const ast::CallExpression* expr) -> const ast::Expression* {
auto* call = sem.Get(expr);
if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
if (auto* array = ctor->ReturnType()->As<sem::Array>()) {
if (auto p = pad(array)) {
auto* arr_ty = p();
auto el_typename = arr_ty->type->As<ast::TypeName>()->name;
ast::ExpressionList args;
args.reserve(call->Arguments().size());
for (auto* arg : call->Arguments()) {
auto* val = ctx.Clone(arg->Declaration());
args.emplace_back(ctx.dst->Construct(
ctx.dst->create<ast::TypeName>(el_typename), val));
}
return ctx.dst->Construct(arr_ty, args);
}
}
}
return nullptr;
});
ctx.Clone();
}
} // namespace transform
} // namespace tint

View File

@ -1,62 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_
#define SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_
#include "src/tint/transform/transform.h"
namespace tint {
namespace transform {
/// PadArrayElements is a transform that replaces array types with an explicit
/// stride that is larger than the implicit stride, with an array of a new
/// structure type. This structure holds with a single field of the element
/// type, decorated with a `@size` attribute to pad the structure to the
/// required array stride. The new array types have no explicit stride,
/// structure size is equal to the desired stride.
/// Array index expressions and constructors are also adjusted to deal with this
/// structure element type.
/// This transform helps with backends that cannot directly return arrays or use
/// them as parameters.
class PadArrayElements : public Castable<PadArrayElements, Transform> {
public:
/// Constructor
PadArrayElements();
/// Destructor
~PadArrayElements() override;
/// @param program the program to inspect
/// @param data optional extra transform-specific input data
/// @returns true if this transform should be run for the given program
bool ShouldRun(const Program* program,
const DataMap& data = {}) const override;
protected:
/// Runs the transform using the CloneContext built for transforming a
/// program. Run() is responsible for calling Clone() on the CloneContext.
/// @param ctx the CloneContext primed with the input program and
/// ProgramBuilder
/// @param inputs optional extra transform-specific input data
/// @param outputs optional extra transform-specific output data
void Run(CloneContext& ctx,
const DataMap& inputs,
DataMap& outputs) const override;
};
} // namespace transform
} // namespace tint
#endif // SRC_TINT_TRANSFORM_PAD_ARRAY_ELEMENTS_H_

View File

@ -1,518 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/transform/pad_array_elements.h"
#include <utility>
#include "src/tint/transform/test_helper.h"
namespace tint {
namespace transform {
namespace {
using PadArrayElementsTest = TransformTest;
TEST_F(PadArrayElementsTest, ShouldRunEmptyModule) {
auto* src = R"()";
EXPECT_FALSE(ShouldRun<PadArrayElements>(src));
}
TEST_F(PadArrayElementsTest, ShouldRunHasImplicitArrayStride) {
auto* src = R"(
var<private> arr : array<i32, 4>;
)";
EXPECT_FALSE(ShouldRun<PadArrayElements>(src));
}
TEST_F(PadArrayElementsTest, ShouldRunHasExplicitArrayStride) {
auto* src = R"(
var<private> arr : @stride(8) array<i32, 4>;
)";
EXPECT_TRUE(ShouldRun<PadArrayElements>(src));
}
TEST_F(PadArrayElementsTest, EmptyModule) {
auto* src = "";
auto* expect = "";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ImplicitArrayStride) {
auto* src = R"(
var<private> arr : array<i32, 4>;
)";
auto* expect = src;
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArrayAsGlobal) {
auto* src = R"(
var<private> arr : @stride(8) array<i32, 4>;
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(8)
el : i32;
}
var<private> arr : array<tint_padded_array_element, 4u>;
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, RuntimeArray) {
auto* src = R"(
struct S {
rta : @stride(8) array<i32>;
};
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(8)
el : i32;
}
struct S {
rta : array<tint_padded_array_element>;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArrayFunctionVar) {
auto* src = R"(
fn f() {
var arr : @stride(16) array<i32, 4>;
arr = @stride(16) array<i32, 4>();
arr = @stride(16) array<i32, 4>(1, 2, 3, 4);
let x = arr[3];
}
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(16)
el : i32;
}
fn f() {
var arr : array<tint_padded_array_element, 4u>;
arr = array<tint_padded_array_element, 4u>();
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
let x = arr[3].el;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArrayAsParam) {
auto* src = R"(
fn f(a : @stride(12) array<i32, 4>) -> i32 {
return a[2];
}
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(12)
el : i32;
}
fn f(a : array<tint_padded_array_element, 4u>) -> i32 {
return a[2].el;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
// TODO(crbug.com/tint/781): Cannot parse the stride on the return array type.
TEST_F(PadArrayElementsTest, DISABLED_ArrayAsReturn) {
auto* src = R"(
fn f() -> @stride(8) array<i32, 4> {
return array<i32, 4>(1, 2, 3, 4);
}
)";
auto* expect = R"(
struct tint_padded_array_element {
el : i32;
@size(4)
padding : u32;
};
fn f() -> array<tint_padded_array_element, 4> {
return array<tint_padded_array_element, 4>(tint_padded_array_element(1, 0u), tint_padded_array_element(2, 0u), tint_padded_array_element(3, 0u), tint_padded_array_element(4, 0u));
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArrayAlias) {
auto* src = R"(
type Array = @stride(16) array<i32, 4>;
fn f() {
var arr : Array;
arr = Array();
arr = Array(1, 2, 3, 4);
let vals : Array = Array(1, 2, 3, 4);
arr = vals;
let x = arr[3];
}
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(16)
el : i32;
}
type Array = array<tint_padded_array_element, 4u>;
fn f() {
var arr : array<tint_padded_array_element, 4u>;
arr = array<tint_padded_array_element, 4u>();
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
arr = vals;
let x = arr[3].el;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArrayAlias_OutOfOrder) {
auto* src = R"(
fn f() {
var arr : Array;
arr = Array();
arr = Array(1, 2, 3, 4);
let vals : Array = Array(1, 2, 3, 4);
arr = vals;
let x = arr[3];
}
type Array = @stride(16) array<i32, 4>;
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(16)
el : i32;
}
fn f() {
var arr : array<tint_padded_array_element, 4u>;
arr = array<tint_padded_array_element, 4u>();
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
arr = vals;
let x = arr[3].el;
}
type Array = array<tint_padded_array_element, 4u>;
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArraysInStruct) {
auto* src = R"(
struct S {
a : @stride(8) array<i32, 4>;
b : @stride(8) array<i32, 8>;
c : @stride(8) array<i32, 4>;
d : @stride(12) array<i32, 8>;
};
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(8)
el : i32;
}
struct tint_padded_array_element_1 {
@size(8)
el : i32;
}
struct tint_padded_array_element_2 {
@size(12)
el : i32;
}
struct S {
a : array<tint_padded_array_element, 4u>;
b : array<tint_padded_array_element_1, 8u>;
c : array<tint_padded_array_element, 4u>;
d : array<tint_padded_array_element_2, 8u>;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, ArraysOfArraysInStruct) {
auto* src = R"(
struct S {
a : @stride(512) array<i32, 4>;
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
};
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(512)
el : i32;
}
struct tint_padded_array_element_2 {
@size(32)
el : i32;
}
struct tint_padded_array_element_1 {
@size(512)
el : array<tint_padded_array_element_2, 4u>;
}
struct tint_padded_array_element_5 {
@size(8)
el : i32;
}
struct tint_padded_array_element_4 {
@size(64)
el : array<tint_padded_array_element_5, 4u>;
}
struct tint_padded_array_element_3 {
@size(512)
el : array<tint_padded_array_element_4, 4u>;
}
struct S {
a : array<tint_padded_array_element, 4u>;
b : array<tint_padded_array_element_1, 4u>;
c : array<tint_padded_array_element_3, 4u>;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, AccessArraysOfArraysInStruct) {
auto* src = R"(
struct S {
a : @stride(512) array<i32, 4>;
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
};
fn f(s : S) -> i32 {
return s.a[2] + s.b[1][2] + s.c[3][1][2];
}
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(512)
el : i32;
}
struct tint_padded_array_element_2 {
@size(32)
el : i32;
}
struct tint_padded_array_element_1 {
@size(512)
el : array<tint_padded_array_element_2, 4u>;
}
struct tint_padded_array_element_5 {
@size(8)
el : i32;
}
struct tint_padded_array_element_4 {
@size(64)
el : array<tint_padded_array_element_5, 4u>;
}
struct tint_padded_array_element_3 {
@size(512)
el : array<tint_padded_array_element_4, 4u>;
}
struct S {
a : array<tint_padded_array_element, 4u>;
b : array<tint_padded_array_element_1, 4u>;
c : array<tint_padded_array_element_3, 4u>;
}
fn f(s : S) -> i32 {
return ((s.a[2].el + s.b[1].el[2].el) + s.c[3].el[1].el[2].el);
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, AccessArraysOfArraysInStruct_OutOfOrder) {
auto* src = R"(
fn f(s : S) -> i32 {
return s.a[2] + s.b[1][2] + s.c[3][1][2];
}
struct S {
a : @stride(512) array<i32, 4>;
b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
};
)";
auto* expect = R"(
struct tint_padded_array_element {
@size(512)
el : i32;
}
struct tint_padded_array_element_1 {
@size(32)
el : i32;
}
struct tint_padded_array_element_2 {
@size(512)
el : array<tint_padded_array_element_1, 4u>;
}
struct tint_padded_array_element_3 {
@size(8)
el : i32;
}
struct tint_padded_array_element_4 {
@size(64)
el : array<tint_padded_array_element_3, 4u>;
}
struct tint_padded_array_element_5 {
@size(512)
el : array<tint_padded_array_element_4, 4u>;
}
fn f(s : S) -> i32 {
return ((s.a[2].el + s.b[1].el[2].el) + s.c[3].el[1].el[2].el);
}
struct S {
a : array<tint_padded_array_element, 4u>;
b : array<tint_padded_array_element_2, 4u>;
c : array<tint_padded_array_element_5, 4u>;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(PadArrayElementsTest, DeclarationOrder) {
auto* src = R"(
type T0 = i32;
type T1 = @stride(8) array<i32, 1>;
type T2 = i32;
fn f1(a : @stride(8) array<i32, 2>) {
}
type T3 = i32;
fn f2() {
var v : @stride(8) array<i32, 3>;
}
)";
auto* expect = R"(
type T0 = i32;
struct tint_padded_array_element {
@size(8)
el : i32;
}
type T1 = array<tint_padded_array_element, 1u>;
type T2 = i32;
struct tint_padded_array_element_1 {
@size(8)
el : i32;
}
fn f1(a : array<tint_padded_array_element_1, 2u>) {
}
type T3 = i32;
struct tint_padded_array_element_2 {
@size(8)
el : i32;
}
fn f2() {
var v : array<tint_padded_array_element_2, 3u>;
}
)";
auto got = Run<PadArrayElements>(src);
EXPECT_EQ(expect, str(got));
}
} // namespace
} // namespace transform
} // namespace tint

View File

@ -1431,7 +1431,7 @@ struct S {
}; };
@group(0) @binding(0) var<storage, read> s : S; @group(0) @binding(0) var<storage, read> s : S;
type UArr = @stride(16) array<f32, 4>; type UArr = array<vec4<f32>, 4>;
struct U { struct U {
a : UArr; a : UArr;
}; };
@ -1451,11 +1451,11 @@ fn f() {
var i32_sb4 : f32 = s.b[-1]; var i32_sb4 : f32 = s.b[-1];
var i32_sb5 : f32 = s.b[-4]; var i32_sb5 : f32 = s.b[-4];
var i32_ua1 : f32 = u.a[4]; var i32_ua1 : f32 = u.a[4].x;
var i32_ua2 : f32 = u.a[1]; var i32_ua2 : f32 = u.a[1].x;
var i32_ua3 : f32 = u.a[0]; var i32_ua3 : f32 = u.a[0].x;
var i32_ua4 : f32 = u.a[-1]; var i32_ua4 : f32 = u.a[-1].x;
var i32_ua5 : f32 = u.a[-4]; var i32_ua5 : f32 = u.a[-4].x;
// Unsigned // Unsigned
var u32_sa1 : f32 = s.a[0u]; var u32_sa1 : f32 = s.a[0u];
@ -1472,12 +1472,12 @@ fn f() {
var u32_sb5 : f32 = s.b[10u]; var u32_sb5 : f32 = s.b[10u];
var u32_sb6 : f32 = s.b[100u]; var u32_sb6 : f32 = s.b[100u];
var u32_ua1 : f32 = u.a[0u]; var u32_ua1 : f32 = u.a[0u].x;
var u32_ua2 : f32 = u.a[1u]; var u32_ua2 : f32 = u.a[1u].x;
var u32_ua3 : f32 = u.a[3u]; var u32_ua3 : f32 = u.a[3u].x;
var u32_ua4 : f32 = u.a[4u]; var u32_ua4 : f32 = u.a[4u].x;
var u32_ua5 : f32 = u.a[10u]; var u32_ua5 : f32 = u.a[10u].x;
var u32_ua6 : f32 = u.a[100u]; var u32_ua6 : f32 = u.a[100u].x;
} }
)"; )";
@ -1490,7 +1490,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S; @group(0) @binding(0) var<storage, read> s : S;
type UArr = @stride(16) array<f32, 4>; type UArr = array<vec4<f32>, 4>;
struct U { struct U {
a : UArr; a : UArr;
@ -1509,11 +1509,11 @@ fn f() {
var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_ua1 : f32 = u.a[3]; var i32_ua1 : f32 = u.a[3].x;
var i32_ua2 : f32 = u.a[1]; var i32_ua2 : f32 = u.a[1].x;
var i32_ua3 : f32 = u.a[0]; var i32_ua3 : f32 = u.a[0].x;
var i32_ua4 : f32 = u.a[0]; var i32_ua4 : f32 = u.a[0].x;
var i32_ua5 : f32 = u.a[0]; var i32_ua5 : f32 = u.a[0].x;
var u32_sa1 : f32 = s.a[0u]; var u32_sa1 : f32 = s.a[0u];
var u32_sa2 : f32 = s.a[1u]; var u32_sa2 : f32 = s.a[1u];
var u32_sa3 : f32 = s.a[3u]; var u32_sa3 : f32 = s.a[3u];
@ -1526,12 +1526,12 @@ fn f() {
var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))]; var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))]; var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))]; var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
var u32_ua1 : f32 = u.a[0u]; var u32_ua1 : f32 = u.a[0u].x;
var u32_ua2 : f32 = u.a[1u]; var u32_ua2 : f32 = u.a[1u].x;
var u32_ua3 : f32 = u.a[3u]; var u32_ua3 : f32 = u.a[3u].x;
var u32_ua4 : f32 = u.a[3u]; var u32_ua4 : f32 = u.a[3u].x;
var u32_ua5 : f32 = u.a[3u]; var u32_ua5 : f32 = u.a[3u].x;
var u32_ua6 : f32 = u.a[3u]; var u32_ua6 : f32 = u.a[3u].x;
} }
)"; )";
@ -1553,7 +1553,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S; @group(0) @binding(0) var<storage, read> s : S;
type UArr = @stride(16) array<f32, 4>; type UArr = array<vec4<f32>, 4>;
struct U { struct U {
a : UArr; a : UArr;
@ -1572,11 +1572,11 @@ fn f() {
var i32_sb3 : f32 = s.b[0]; var i32_sb3 : f32 = s.b[0];
var i32_sb4 : f32 = s.b[-1]; var i32_sb4 : f32 = s.b[-1];
var i32_sb5 : f32 = s.b[-4]; var i32_sb5 : f32 = s.b[-4];
var i32_ua1 : f32 = u.a[3]; var i32_ua1 : f32 = u.a[3].x;
var i32_ua2 : f32 = u.a[1]; var i32_ua2 : f32 = u.a[1].x;
var i32_ua3 : f32 = u.a[0]; var i32_ua3 : f32 = u.a[0].x;
var i32_ua4 : f32 = u.a[0]; var i32_ua4 : f32 = u.a[0].x;
var i32_ua5 : f32 = u.a[0]; var i32_ua5 : f32 = u.a[0].x;
var u32_sa1 : f32 = s.a[0u]; var u32_sa1 : f32 = s.a[0u];
var u32_sa2 : f32 = s.a[1u]; var u32_sa2 : f32 = s.a[1u];
var u32_sa3 : f32 = s.a[3u]; var u32_sa3 : f32 = s.a[3u];
@ -1589,12 +1589,12 @@ fn f() {
var u32_sb4 : f32 = s.b[4u]; var u32_sb4 : f32 = s.b[4u];
var u32_sb5 : f32 = s.b[10u]; var u32_sb5 : f32 = s.b[10u];
var u32_sb6 : f32 = s.b[100u]; var u32_sb6 : f32 = s.b[100u];
var u32_ua1 : f32 = u.a[0u]; var u32_ua1 : f32 = u.a[0u].x;
var u32_ua2 : f32 = u.a[1u]; var u32_ua2 : f32 = u.a[1u].x;
var u32_ua3 : f32 = u.a[3u]; var u32_ua3 : f32 = u.a[3u].x;
var u32_ua4 : f32 = u.a[3u]; var u32_ua4 : f32 = u.a[3u].x;
var u32_ua5 : f32 = u.a[3u]; var u32_ua5 : f32 = u.a[3u].x;
var u32_ua6 : f32 = u.a[3u]; var u32_ua6 : f32 = u.a[3u].x;
} }
)"; )";
@ -1618,7 +1618,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S; @group(0) @binding(0) var<storage, read> s : S;
type UArr = @stride(16) array<f32, 4>; type UArr = array<vec4<f32>, 4>;
struct U { struct U {
a : UArr; a : UArr;
@ -1637,11 +1637,11 @@ fn f() {
var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))]; var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
var i32_ua1 : f32 = u.a[4]; var i32_ua1 : f32 = u.a[4].x;
var i32_ua2 : f32 = u.a[1]; var i32_ua2 : f32 = u.a[1].x;
var i32_ua3 : f32 = u.a[0]; var i32_ua3 : f32 = u.a[0].x;
var i32_ua4 : f32 = u.a[-1]; var i32_ua4 : f32 = u.a[-1].x;
var i32_ua5 : f32 = u.a[-4]; var i32_ua5 : f32 = u.a[-4].x;
var u32_sa1 : f32 = s.a[0u]; var u32_sa1 : f32 = s.a[0u];
var u32_sa2 : f32 = s.a[1u]; var u32_sa2 : f32 = s.a[1u];
var u32_sa3 : f32 = s.a[3u]; var u32_sa3 : f32 = s.a[3u];
@ -1654,12 +1654,12 @@ fn f() {
var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))]; var u32_sb4 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))]; var u32_sb5 : f32 = s.b[min(10u, (arrayLength(&(s.b)) - 1u))];
var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))]; var u32_sb6 : f32 = s.b[min(100u, (arrayLength(&(s.b)) - 1u))];
var u32_ua1 : f32 = u.a[0u]; var u32_ua1 : f32 = u.a[0u].x;
var u32_ua2 : f32 = u.a[1u]; var u32_ua2 : f32 = u.a[1u].x;
var u32_ua3 : f32 = u.a[3u]; var u32_ua3 : f32 = u.a[3u].x;
var u32_ua4 : f32 = u.a[4u]; var u32_ua4 : f32 = u.a[4u].x;
var u32_ua5 : f32 = u.a[10u]; var u32_ua5 : f32 = u.a[10u].x;
var u32_ua6 : f32 = u.a[100u]; var u32_ua6 : f32 = u.a[100u].x;
} }
)"; )";
@ -1683,7 +1683,7 @@ struct S {
@group(0) @binding(0) var<storage, read> s : S; @group(0) @binding(0) var<storage, read> s : S;
type UArr = @stride(16) array<f32, 4>; type UArr = array<vec4<f32>, 4>;
struct U { struct U {
a : UArr; a : UArr;
@ -1702,11 +1702,11 @@ fn f() {
var i32_sb3 : f32 = s.b[0]; var i32_sb3 : f32 = s.b[0];
var i32_sb4 : f32 = s.b[-1]; var i32_sb4 : f32 = s.b[-1];
var i32_sb5 : f32 = s.b[-4]; var i32_sb5 : f32 = s.b[-4];
var i32_ua1 : f32 = u.a[4]; var i32_ua1 : f32 = u.a[4].x;
var i32_ua2 : f32 = u.a[1]; var i32_ua2 : f32 = u.a[1].x;
var i32_ua3 : f32 = u.a[0]; var i32_ua3 : f32 = u.a[0].x;
var i32_ua4 : f32 = u.a[-1]; var i32_ua4 : f32 = u.a[-1].x;
var i32_ua5 : f32 = u.a[-4]; var i32_ua5 : f32 = u.a[-4].x;
var u32_sa1 : f32 = s.a[0u]; var u32_sa1 : f32 = s.a[0u];
var u32_sa2 : f32 = s.a[1u]; var u32_sa2 : f32 = s.a[1u];
var u32_sa3 : f32 = s.a[3u]; var u32_sa3 : f32 = s.a[3u];
@ -1719,12 +1719,12 @@ fn f() {
var u32_sb4 : f32 = s.b[4u]; var u32_sb4 : f32 = s.b[4u];
var u32_sb5 : f32 = s.b[10u]; var u32_sb5 : f32 = s.b[10u];
var u32_sb6 : f32 = s.b[100u]; var u32_sb6 : f32 = s.b[100u];
var u32_ua1 : f32 = u.a[0u]; var u32_ua1 : f32 = u.a[0u].x;
var u32_ua2 : f32 = u.a[1u]; var u32_ua2 : f32 = u.a[1u].x;
var u32_ua3 : f32 = u.a[3u]; var u32_ua3 : f32 = u.a[3u].x;
var u32_ua4 : f32 = u.a[4u]; var u32_ua4 : f32 = u.a[4u].x;
var u32_ua5 : f32 = u.a[10u]; var u32_ua5 : f32 = u.a[10u].x;
var u32_ua6 : f32 = u.a[100u]; var u32_ua6 : f32 = u.a[100u].x;
} }
)"; )";

View File

@ -258,7 +258,7 @@ struct State {
ctx.dst->Symbols().New(kStructName), ctx.dst->Symbols().New(kStructName),
{ {
ctx.dst->Member(GetStructBufferName(), ctx.dst->Member(GetStructBufferName(),
ctx.dst->ty.array<ProgramBuilder::u32>(4)), ctx.dst->ty.array<ProgramBuilder::u32>()),
}); });
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) { for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
// The decorated variable with struct type // The decorated variable with struct type

View File

@ -108,7 +108,7 @@ fn main() -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@stage(vertex) @stage(vertex)
@ -137,7 +137,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -175,7 +175,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -213,7 +213,7 @@ fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(5) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(5) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -256,7 +256,7 @@ fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -304,7 +304,7 @@ fn main(@location(0) var_a : f32,
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -364,7 +364,7 @@ fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -444,7 +444,7 @@ struct Inputs {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -526,7 +526,7 @@ fn main(inputs : Inputs, indices : Indices) -> @builtin(position) vec4<f32> {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -603,7 +603,7 @@ struct Indices {
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -670,7 +670,7 @@ fn main(@location(0) var_a : f32,
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -715,7 +715,7 @@ fn main(@location(0) var_a : vec2<f32>,
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -771,7 +771,7 @@ fn main(@location(0) var_a : f32,
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data_1 : @stride(4) array<u32>; tint_vertex_data_1 : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0_1 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0_1 : TintVertexData;
@ -848,7 +848,7 @@ fn main(
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -1008,7 +1008,7 @@ fn main(
auto* expect = auto* expect =
R"( R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
@ -1167,7 +1167,7 @@ fn main(
auto* expect = R"( auto* expect = R"(
struct TintVertexData { struct TintVertexData {
tint_vertex_data : @stride(4) array<u32>; tint_vertex_data : array<u32>;
} }
@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData; @binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;

View File

@ -363,7 +363,7 @@ void main() {
TEST_F(GlslGeneratorImplTest_MemberAccessor, TEST_F(GlslGeneratorImplTest_MemberAccessor,
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) { EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[2]; // data.a[2];
@ -409,7 +409,7 @@ void main() {
TEST_F(GlslGeneratorImplTest_MemberAccessor, TEST_F(GlslGeneratorImplTest_MemberAccessor,
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) { EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[(2 + 4) - 3]; // data.a[(2 + 4) - 3];
@ -455,7 +455,7 @@ void main() {
TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) { TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[2] = 2; // data.a[2] = 2;
@ -503,7 +503,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -562,7 +562,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -623,7 +623,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -684,7 +684,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -744,7 +744,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -802,7 +802,7 @@ TEST_F(GlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;

View File

@ -57,7 +57,6 @@
#include "src/tint/transform/loop_to_for_loop.h" #include "src/tint/transform/loop_to_for_loop.h"
#include "src/tint/transform/manager.h" #include "src/tint/transform/manager.h"
#include "src/tint/transform/num_workgroups_from_uniform.h" #include "src/tint/transform/num_workgroups_from_uniform.h"
#include "src/tint/transform/pad_array_elements.h"
#include "src/tint/transform/promote_initializers_to_const_var.h" #include "src/tint/transform/promote_initializers_to_const_var.h"
#include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h" #include "src/tint/transform/remove_phonies.h"
@ -209,7 +208,6 @@ SanitizedResult Sanitize(
manager.Add<transform::CalculateArrayLength>(); manager.Add<transform::CalculateArrayLength>();
manager.Add<transform::PromoteInitializersToConstVar>(); manager.Add<transform::PromoteInitializersToConstVar>();
manager.Add<transform::PadArrayElements>();
manager.Add<transform::AddEmptyEntryPoint>(); manager.Add<transform::AddEmptyEntryPoint>();
data.Add<transform::CanonicalizeEntryPointIO::Config>( data.Add<transform::CanonicalizeEntryPointIO::Config>(

View File

@ -391,7 +391,7 @@ void main() {
TEST_F(HlslGeneratorImplTest_MemberAccessor, TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) { EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[2]; // data.a[2];
@ -423,7 +423,7 @@ void main() {
TEST_F(HlslGeneratorImplTest_MemberAccessor, TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) { EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[(2 + 4) - 3]; // data.a[(2 + 4) - 3];
@ -455,7 +455,7 @@ void main() {
TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) { TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
// struct Data { // struct Data {
// a : @stride(4) array<i32, 5>; // a : array<i32, 5>;
// }; // };
// var<storage> data : Data; // var<storage> data : Data;
// data.a[2] = 2; // data.a[2] = 2;
@ -489,7 +489,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -531,7 +531,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -575,7 +575,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -619,7 +619,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -662,7 +662,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;
@ -703,7 +703,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// b : vec3<f32>; // b : vec3<f32>;
// }; // };
// struct Data { // struct Data {
// var c : @stride(32) array<Inner, 4>; // var c : array<Inner, 4>;
// }; // };
// //
// var<storage> data : Pre; // var<storage> data : Pre;

View File

@ -63,7 +63,6 @@
#include "src/tint/transform/canonicalize_entry_point_io.h" #include "src/tint/transform/canonicalize_entry_point_io.h"
#include "src/tint/transform/manager.h" #include "src/tint/transform/manager.h"
#include "src/tint/transform/module_scope_var_to_entry_point_param.h" #include "src/tint/transform/module_scope_var_to_entry_point_param.h"
#include "src/tint/transform/pad_array_elements.h"
#include "src/tint/transform/promote_initializers_to_const_var.h" #include "src/tint/transform/promote_initializers_to_const_var.h"
#include "src/tint/transform/promote_side_effects_to_decl.h" #include "src/tint/transform/promote_side_effects_to_decl.h"
#include "src/tint/transform/remove_phonies.h" #include "src/tint/transform/remove_phonies.h"
@ -179,7 +178,6 @@ SanitizedResult Sanitize(
manager.Add<transform::VectorizeScalarMatrixConstructors>(); manager.Add<transform::VectorizeScalarMatrixConstructors>();
manager.Add<transform::WrapArraysInStructs>(); manager.Add<transform::WrapArraysInStructs>();
manager.Add<transform::PadArrayElements>();
manager.Add<transform::RemovePhonies>(); manager.Add<transform::RemovePhonies>();
manager.Add<transform::SimplifyPointers>(); manager.Add<transform::SimplifyPointers>();
// ArrayLengthFromUniform must come after SimplifyPointers, as // ArrayLengthFromUniform must come after SimplifyPointers, as
@ -2945,9 +2943,8 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
[&](const sem::Array* arr) { [&](const sem::Array* arr) {
if (!arr->IsStrideImplicit()) { if (!arr->IsStrideImplicit()) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_) << "arrays with explicit strides not "
<< "arrays with explicit strides should have " "exist past the SPIR-V reader";
"removed with the PadArrayElements transform";
return SizeAndAlign{}; return SizeAndAlign{};
} }
auto num_els = std::max<uint32_t>(arr->Count(), 1); auto num_els = std::max<uint32_t>(arr->Count(), 1);

View File

@ -119,30 +119,6 @@ TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) {
EXPECT_EQ(out.str(), "bool ary[1]"); EXPECT_EQ(out.str(), "bool ary[1]");
} }
TEST_F(MslGeneratorImplTest, EmitType_ArrayWithStride) {
auto* s = Structure("s", {Member("arr", ty.array<f32, 4>(64))});
auto* ubo = Global("ubo", ty.Of(s), ast::StorageClass::kUniform,
ast::AttributeList{
create<ast::GroupAttribute>(0),
create<ast::BindingAttribute>(1),
});
WrapInFunction(MemberAccessor(ubo, "arr"));
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_THAT(gen.result(), HasSubstr(R"(struct tint_padded_array_element {
/* 0x0000 */ float el;
/* 0x0004 */ int8_t tint_pad[60];
};)"));
EXPECT_THAT(gen.result(), HasSubstr(R"(struct tint_array_wrapper {
/* 0x0000 */ tint_padded_array_element arr[4];
};)"));
EXPECT_THAT(gen.result(), HasSubstr(R"(struct s {
/* 0x0000 */ tint_array_wrapper arr;
};)"));
}
TEST_F(MslGeneratorImplTest, EmitType_Bool) { TEST_F(MslGeneratorImplTest, EmitType_Bool) {
auto* bool_ = create<sem::Bool>(); auto* bool_ = create<sem::Bool>();

View File

@ -1622,7 +1622,7 @@ OpReturn
TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) { TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
// struct my_struct { // struct my_struct {
// a : @stride(4) array<f32>; // a : array<f32>;
// }; // };
// @binding(1) @group(2) var<storage, read> b : my_struct; // @binding(1) @group(2) var<storage, read> b : my_struct;
// //

View File

@ -327,7 +327,6 @@ tint_unittests_source_set("tint_unittests_transform_src") {
"../../src/tint/transform/module_scope_var_to_entry_point_param_test.cc", "../../src/tint/transform/module_scope_var_to_entry_point_param_test.cc",
"../../src/tint/transform/multiplanar_external_texture_test.cc", "../../src/tint/transform/multiplanar_external_texture_test.cc",
"../../src/tint/transform/num_workgroups_from_uniform_test.cc", "../../src/tint/transform/num_workgroups_from_uniform_test.cc",
"../../src/tint/transform/pad_array_elements_test.cc",
"../../src/tint/transform/promote_initializers_to_const_var_test.cc", "../../src/tint/transform/promote_initializers_to_const_var_test.cc",
"../../src/tint/transform/promote_side_effects_to_decl_test.cc", "../../src/tint/transform/promote_side_effects_to_decl_test.cc",
"../../src/tint/transform/remove_phonies_test.cc", "../../src/tint/transform/remove_phonies_test.cc",

View File

@ -1,98 +0,0 @@
#version 310 es
float tint_float_modulo(float lhs, float rhs) {
return (lhs - rhs * trunc(lhs / rhs));
}
layout(location = 0) in vec4 position_1;
layout(location = 1) in vec4 color_1;
layout(location = 0) out vec4 v_color_1;
struct Time {
float value;
};
struct Uniforms {
float scale;
float offsetX;
float offsetY;
float scalar;
float scalarOffset;
};
layout(binding = 0) uniform Time_1 {
float value;
} time;
layout(binding = 1) uniform Uniforms_1 {
float scale;
float offsetX;
float offsetY;
float scalar;
float scalarOffset;
} uniforms;
struct VertexOutput {
vec4 Position;
vec4 v_color;
};
VertexOutput vert_main(vec4 position, vec4 color) {
float fade = tint_float_modulo((uniforms.scalarOffset + ((time.value * uniforms.scalar) / 10.0f)), 1.0f);
if ((fade < 0.5f)) {
fade = (fade * 2.0f);
} else {
fade = ((1.0f - fade) * 2.0f);
}
float xpos = (position.x * uniforms.scale);
float ypos = (position.y * uniforms.scale);
float angle = ((3.141590118f * 2.0f) * fade);
float xrot = ((xpos * cos(angle)) - (ypos * sin(angle)));
float yrot = ((xpos * sin(angle)) + (ypos * cos(angle)));
xpos = (xrot + uniforms.offsetX);
ypos = (yrot + uniforms.offsetY);
VertexOutput tint_symbol = VertexOutput(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f));
tint_symbol.v_color = (vec4(fade, (1.0f - fade), 0.0f, 1.0f) + color);
tint_symbol.Position = vec4(xpos, ypos, 0.0f, 1.0f);
return tint_symbol;
}
void main() {
VertexOutput inner_result = vert_main(position_1, color_1);
gl_Position = inner_result.Position;
v_color_1 = inner_result.v_color;
gl_Position.y = -(gl_Position.y);
gl_Position.z = ((2.0f * gl_Position.z) - gl_Position.w);
return;
}
#version 310 es
precision mediump float;
layout(location = 0) in vec4 v_color_1;
layout(location = 0) out vec4 value_1;
struct Time {
float value;
};
struct Uniforms {
float scale;
float offsetX;
float offsetY;
float scalar;
float scalarOffset;
};
struct VertexOutput {
vec4 Position;
vec4 v_color;
};
vec4 frag_main(vec4 v_color) {
return v_color;
}
void main() {
vec4 inner_result = frag_main(v_color_1);
value_1 = inner_result;
return;
}

View File

@ -48,7 +48,7 @@ struct GlobalLights {
dirIntensity : f32; dirIntensity : f32;
dirDirection : vec3<f32>; dirDirection : vec3<f32>;
lightCount : u32; lightCount : u32;
lights : @stride(32) array<Light>; lights : array<Light>;
} }
@binding(2) @group(0) var<storage, read> globalLights : GlobalLights; @binding(2) @group(0) var<storage, read> globalLights : GlobalLights;

View File

@ -1,381 +0,0 @@
benchmark/skinned-shadowed-pbr-fragment.wgsl:51:13 warning: use of deprecated language feature: the @stride attribute is deprecated; use a larger type if necessary
lights : @stride(32) array<Light>;
^^^^^^
#version 310 es
precision mediump float;
layout(location = 0) in vec3 worldPos_1;
layout(location = 1) in vec3 view_1;
layout(location = 2) in vec2 texcoord_1;
layout(location = 3) in vec2 texcoord2_1;
layout(location = 4) in vec4 color_1;
layout(location = 5) in vec4 instanceColor_1;
layout(location = 6) in vec3 normal_1;
layout(location = 7) in vec3 tangent_1;
layout(location = 8) in vec3 bitangent_1;
layout(location = 0) out vec4 color_2;
layout(location = 1) out vec4 emissive_1;
const float GAMMA = 2.200000048f;
vec3 linearTosRGB(vec3 linear) {
float INV_GAMMA = (1.0f / GAMMA);
return pow(linear, vec3(INV_GAMMA));
}
struct Camera {
mat4 projection;
mat4 inverseProjection;
mat4 view;
vec3 position;
float time;
vec2 outputSize;
float zNear;
float zFar;
};
layout(binding = 0) uniform Camera_1 {
mat4 projection;
mat4 inverseProjection;
mat4 view;
vec3 position;
float time;
vec2 outputSize;
float zNear;
float zFar;
} camera;
struct ClusterLights {
uint offset;
uint count;
};
struct ClusterLightGroup {
uint offset;
ClusterLights lights[27648];
uint indices[1769472];
};
layout(binding = 1, std430) buffer ClusterLightGroup_1 {
uint offset;
ClusterLights lights[27648];
uint indices[1769472];
} clusterLights;
struct Light {
vec3 position;
float range;
vec3 color;
float intensity;
};
layout(binding = 2, std430) buffer GlobalLights_1 {
vec3 ambient;
vec3 dirColor;
float dirIntensity;
vec3 dirDirection;
uint lightCount;
Light lights[];
} globalLights;
const uvec3 tileCount = uvec3(32u, 18u, 48u);
float linearDepth(float depthSample) {
return ((camera.zFar * camera.zNear) / ((depthSample) * ((camera.zNear - camera.zFar)) + (camera.zFar)));
}
uvec3 getTile(vec4 fragCoord) {
float sliceScale = (float(tileCount.z) / log2((camera.zFar / camera.zNear)));
float sliceBias = -(((float(tileCount.z) * log2(camera.zNear)) / log2((camera.zFar / camera.zNear))));
float tint_symbol_3 = linearDepth(fragCoord.z);
float tint_symbol_4 = log2(tint_symbol_3);
float tint_symbol_5 = max(((tint_symbol_4 * sliceScale) + sliceBias), 0.0f);
uint zTile = uint(tint_symbol_5);
return uvec3(uint((fragCoord.x / (camera.outputSize.x / float(tileCount.x)))), uint((fragCoord.y / (camera.outputSize.y / float(tileCount.y)))), zTile);
}
uint getClusterIndex(vec4 fragCoord) {
uvec3 tile = getTile(fragCoord);
return ((tile.x + (tile.y * tileCount.x)) + ((tile.z * tileCount.x) * tileCount.y));
}
layout(binding = 6, std430) buffer LightShadowTable_1 {
int light[];
} lightShadowTable;
vec2 shadowSampleOffsets[16] = vec2[16](vec2(-1.5f, -1.5f), vec2(-1.5f, -0.5f), vec2(-1.5f, 0.5f), vec2(-1.5f, 1.5f), vec2(-0.5f, -1.5f), vec2(-0.5f, -0.5f), vec2(-0.5f, 0.5f), vec2(-0.5f, 1.5f), vec2(0.5f, -1.5f), vec2(0.5f, -0.5f), vec2(0.5f, 0.5f), vec2(0.5f, 1.5f), vec2(1.5f, -1.5f), vec2(1.5f, -0.5f), vec2(1.5f, 0.5f), vec2(1.5f, 1.5f));
const uint shadowSampleCount = 16u;
struct ShadowProperties {
vec4 viewport;
mat4 viewProj;
};
layout(binding = 7, std430) buffer LightShadows_1 {
ShadowProperties properties[];
} shadow;
uniform highp sampler2D shadowTexture_1;
uniform highp sampler2DShadow shadowTexture_shadowSampler;
float dirLightVisibility(vec3 worldPos) {
int shadowIndex = lightShadowTable.light[0u];
if ((shadowIndex == -1)) {
return 1.0f;
}
vec4 viewport = shadow.properties[shadowIndex].viewport;
vec4 lightPos = (shadow.properties[shadowIndex].viewProj * vec4(worldPos, 1.0f));
vec3 shadowPos = vec3((((lightPos.xy / lightPos.w) * vec2(0.5f, -0.5f)) + vec2(0.5f, 0.5f)), (lightPos.z / lightPos.w));
vec2 viewportPos = vec2((viewport.xy + (shadowPos.xy * viewport.zw)));
vec2 texelSize = (1.0f / vec2(textureSize(shadowTexture_1, 0)));
vec4 clampRect = vec4((viewport.xy - texelSize), ((viewport.xy + viewport.zw) + texelSize));
float visibility = 0.0f;
{
for(uint i = 0u; (i < shadowSampleCount); i = (i + 1u)) {
visibility = (visibility + texture(shadowTexture_shadowSampler, vec3(clamp((viewportPos + (shadowSampleOffsets[i] * texelSize)), clampRect.xy, clampRect.zw), (shadowPos.z - 0.003f))));
}
}
return (visibility / float(shadowSampleCount));
}
int getCubeFace(vec3 v) {
vec3 vAbs = abs(v);
bool tint_tmp = (vAbs.z >= vAbs.x);
if (tint_tmp) {
tint_tmp = (vAbs.z >= vAbs.y);
}
if ((tint_tmp)) {
if ((v.z < 0.0f)) {
return 5;
}
return 4;
}
if ((vAbs.y >= vAbs.x)) {
if ((v.y < 0.0f)) {
return 3;
}
return 2;
}
if ((v.x < 0.0f)) {
return 1;
}
return 0;
}
float pointLightVisibility(uint lightIndex, vec3 worldPos, vec3 pointToLight) {
int shadowIndex = lightShadowTable.light[(lightIndex + 1u)];
if ((shadowIndex == -1)) {
return 1.0f;
}
int tint_symbol_6 = shadowIndex;
int tint_symbol_7 = getCubeFace((pointToLight * -1.0f));
shadowIndex = (tint_symbol_6 + tint_symbol_7);
vec4 viewport = shadow.properties[shadowIndex].viewport;
vec4 lightPos = (shadow.properties[shadowIndex].viewProj * vec4(worldPos, 1.0f));
vec3 shadowPos = vec3((((lightPos.xy / lightPos.w) * vec2(0.5f, -0.5f)) + vec2(0.5f, 0.5f)), (lightPos.z / lightPos.w));
vec2 viewportPos = vec2((viewport.xy + (shadowPos.xy * viewport.zw)));
vec2 texelSize = (1.0f / vec2(textureSize(shadowTexture_1, 0)));
vec4 clampRect = vec4(viewport.xy, (viewport.xy + viewport.zw));
float visibility = 0.0f;
{
for(uint i = 0u; (i < shadowSampleCount); i = (i + 1u)) {
visibility = (visibility + texture(shadowTexture_shadowSampler, vec3(clamp((viewportPos + (shadowSampleOffsets[i] * texelSize)), clampRect.xy, clampRect.zw), (shadowPos.z - 0.01f))));
}
}
return (visibility / float(shadowSampleCount));
}
struct VertexOutput {
vec4 position;
vec3 worldPos;
vec3 view;
vec2 texcoord;
vec2 texcoord2;
vec4 color;
vec4 instanceColor;
vec3 normal;
vec3 tangent;
vec3 bitangent;
};
struct Material {
vec4 baseColorFactor;
vec3 emissiveFactor;
float occlusionStrength;
vec2 metallicRoughnessFactor;
float alphaCutoff;
};
layout(binding = 8) uniform Material_1 {
vec4 baseColorFactor;
vec3 emissiveFactor;
float occlusionStrength;
vec2 metallicRoughnessFactor;
float alphaCutoff;
} material;
struct SurfaceInfo {
vec4 baseColor;
vec3 albedo;
float metallic;
float roughness;
vec3 normal;
vec3 f0;
float ao;
vec3 emissive;
vec3 v;
};
uniform highp sampler2D normalTexture_normalSampler;
uniform highp sampler2D baseColorTexture_baseColorSampler;
uniform highp sampler2D metallicRoughnessTexture_metallicRoughnessSampler;
uniform highp sampler2D occlusionTexture_occlusionSampler;
uniform highp sampler2D emissiveTexture_emissiveSampler;
SurfaceInfo GetSurfaceInfo(VertexOutput tint_symbol) {
SurfaceInfo surface = SurfaceInfo(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), 0.0f, 0.0f, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f));
surface.v = normalize(tint_symbol.view);
mat3 tbn = mat3(tint_symbol.tangent, tint_symbol.bitangent, tint_symbol.normal);
vec3 normalMap = texture(normalTexture_normalSampler, tint_symbol.texcoord).rgb;
surface.normal = normalize((tbn * ((2.0f * normalMap) - vec3(1.0f))));
vec4 baseColorMap = texture(baseColorTexture_baseColorSampler, tint_symbol.texcoord);
surface.baseColor = ((tint_symbol.color * material.baseColorFactor) * baseColorMap);
if ((surface.baseColor.a < material.alphaCutoff)) {
discard;
}
surface.albedo = surface.baseColor.rgb;
vec4 metallicRoughnessMap = texture(metallicRoughnessTexture_metallicRoughnessSampler, tint_symbol.texcoord);
surface.metallic = (material.metallicRoughnessFactor.x * metallicRoughnessMap.b);
surface.roughness = (material.metallicRoughnessFactor.y * metallicRoughnessMap.g);
vec3 dielectricSpec = vec3(0.039999999f);
surface.f0 = mix(dielectricSpec, surface.albedo, vec3(surface.metallic));
vec4 occlusionMap = texture(occlusionTexture_occlusionSampler, tint_symbol.texcoord);
surface.ao = (material.occlusionStrength * occlusionMap.r);
vec4 emissiveMap = texture(emissiveTexture_emissiveSampler, tint_symbol.texcoord);
surface.emissive = (material.emissiveFactor * emissiveMap.rgb);
if ((tint_symbol.instanceColor.a == 0.0f)) {
surface.albedo = (surface.albedo + tint_symbol.instanceColor.rgb);
} else {
surface.albedo = (surface.albedo * tint_symbol.instanceColor.rgb);
}
return surface;
}
const float PI = 3.141592741f;
const uint LightType_Point = 0u;
const uint LightType_Directional = 2u;
struct PuctualLight {
uint lightType;
vec3 pointToLight;
float range;
vec3 color;
float intensity;
};
vec3 FresnelSchlick(float cosTheta, vec3 F0) {
return (F0 + ((vec3(1.0f) - F0) * pow((1.0f - cosTheta), 5.0f)));
}
float DistributionGGX(vec3 N, vec3 H, float roughness) {
float a_1 = (roughness * roughness);
float a2 = (a_1 * a_1);
float NdotH = max(dot(N, H), 0.0f);
float NdotH2 = (NdotH * NdotH);
float num = a2;
float denom = ((NdotH2 * (a2 - 1.0f)) + 1.0f);
return (num / ((PI * denom) * denom));
}
float GeometrySchlickGGX(float NdotV, float roughness) {
float r_1 = (roughness + 1.0f);
float k = ((r_1 * r_1) / 8.0f);
float num = NdotV;
float denom = ((NdotV * (1.0f - k)) + k);
return (num / denom);
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0f);
float NdotL = max(dot(N, L), 0.0f);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return (ggx1 * ggx2);
}
float lightAttenuation(PuctualLight light) {
if ((light.lightType == LightType_Directional)) {
return 1.0f;
}
float tint_symbol_1 = length(light.pointToLight);
if ((light.range <= 0.0f)) {
return (1.0f / pow(tint_symbol_1, 2.0f));
}
return (clamp((1.0f - pow((tint_symbol_1 / light.range), 4.0f)), 0.0f, 1.0f) / pow(tint_symbol_1, 2.0f));
}
vec3 lightRadiance(PuctualLight light, SurfaceInfo surface) {
vec3 L = normalize(light.pointToLight);
vec3 H = normalize((surface.v + L));
float NDF = DistributionGGX(surface.normal, H, surface.roughness);
float G = GeometrySmith(surface.normal, surface.v, L, surface.roughness);
vec3 F = FresnelSchlick(max(dot(H, surface.v), 0.0f), surface.f0);
vec3 kD = ((vec3(1.0f) - F) * (1.0f - surface.metallic));
float NdotL = max(dot(surface.normal, L), 0.0f);
vec3 numerator = ((NDF * G) * F);
float denominator = max(((4.0f * max(dot(surface.normal, surface.v), 0.0f)) * NdotL), 0.001f);
vec3 specular = (numerator / vec3(denominator));
vec3 tint_symbol_8 = (light.color * light.intensity);
float tint_symbol_9 = lightAttenuation(light);
vec3 radiance = (tint_symbol_8 * tint_symbol_9);
return (((((kD * surface.albedo) / vec3(PI)) + specular) * radiance) * NdotL);
}
struct FragmentOutput {
vec4 color;
vec4 emissive;
};
uniform highp sampler2D ssaoTexture_1;
uniform highp sampler2D ssaoTexture_defaultSampler;
FragmentOutput fragmentMain(VertexOutput tint_symbol) {
SurfaceInfo surface = GetSurfaceInfo(tint_symbol);
vec3 Lo = vec3(0.0f, 0.0f, 0.0f);
if ((globalLights.dirIntensity > 0.0f)) {
PuctualLight light = PuctualLight(0u, vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), 0.0f);
light.lightType = LightType_Directional;
light.pointToLight = globalLights.dirDirection;
light.color = globalLights.dirColor;
light.intensity = globalLights.dirIntensity;
float lightVis = dirLightVisibility(tint_symbol.worldPos);
vec3 tint_symbol_10 = Lo;
vec3 tint_symbol_11 = lightRadiance(light, surface);
Lo = (tint_symbol_10 + (tint_symbol_11 * lightVis));
}
uint clusterIndex = getClusterIndex(tint_symbol.position);
uint lightOffset = clusterLights.lights[clusterIndex].offset;
uint lightCount = clusterLights.lights[clusterIndex].count;
{
for(uint lightIndex = 0u; (lightIndex < lightCount); lightIndex = (lightIndex + 1u)) {
uint i = clusterLights.indices[(lightOffset + lightIndex)];
PuctualLight light = PuctualLight(0u, vec3(0.0f, 0.0f, 0.0f), 0.0f, vec3(0.0f, 0.0f, 0.0f), 0.0f);
light.lightType = LightType_Point;
light.pointToLight = (globalLights.lights[i].position.xyz - tint_symbol.worldPos);
light.range = globalLights.lights[i].range;
light.color = globalLights.lights[i].color;
light.intensity = globalLights.lights[i].intensity;
float lightVis = pointLightVisibility(i, tint_symbol.worldPos, light.pointToLight);
vec3 tint_symbol_12 = Lo;
vec3 tint_symbol_13 = lightRadiance(light, surface);
Lo = (tint_symbol_12 + (tint_symbol_13 * lightVis));
}
}
vec2 ssaoCoord = (tint_symbol.position.xy / vec2(textureSize(ssaoTexture_1, 0).xy));
float ssaoFactor = texture(ssaoTexture_defaultSampler, ssaoCoord).r;
vec3 ambient = (((globalLights.ambient * surface.albedo) * surface.ao) * ssaoFactor);
vec3 color = linearTosRGB(((Lo + ambient) + surface.emissive));
FragmentOutput tint_symbol_2 = FragmentOutput(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f));
tint_symbol_2.color = vec4(color, surface.baseColor.a);
tint_symbol_2.emissive = vec4(surface.emissive, surface.baseColor.a);
return tint_symbol_2;
}
void main() {
VertexOutput tint_symbol_14 = VertexOutput(gl_FragCoord, worldPos_1, view_1, texcoord_1, texcoord2_1, color_1, instanceColor_1, normal_1, tangent_1, bitangent_1);
FragmentOutput inner_result = fragmentMain(tint_symbol_14);
color_2 = inner_result.color;
emissive_1 = inner_result.emissive;
return;
}