tint/resolver: Validate @size only on creation-fixed footprint member types.
Fixed: tint:1623 Change-Id: Id553dfe57effb4084a16fd6e6b02ad0cef85f836 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106224 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
bd5bd247f0
commit
5af4d88753
|
@ -809,11 +809,25 @@ TEST_F(StructMemberAttributeTest, Size_Attribute_Var) {
|
||||||
TEST_F(StructMemberAttributeTest, Size_Attribute_Override) {
|
TEST_F(StructMemberAttributeTest, Size_Attribute_Override) {
|
||||||
Override("val", ty.f32(), Expr(1.23_f));
|
Override("val", ty.f32(), Expr(1.23_f));
|
||||||
|
|
||||||
Structure("mystruct", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize("val")})});
|
Structure("mystruct",
|
||||||
|
utils::Vector{
|
||||||
|
Member("a", ty.f32(), utils::Vector{MemberSize(Expr(Source{{12, 34}}, "val"))}),
|
||||||
|
});
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
r()->error(),
|
r()->error(),
|
||||||
R"(error: @size requires a const-expression, but expression is an override-expression)");
|
R"(12:34 error: @size requires a const-expression, but expression is an override-expression)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Size_On_RuntimeSizedArray) {
|
||||||
|
Structure("mystruct",
|
||||||
|
utils::Vector{
|
||||||
|
Member("a", ty.array<i32>(), utils::Vector{MemberSize(Source{{12, 34}}, 8_a)}),
|
||||||
|
});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(12:34 error: @size can only be applied to members where the member's type size can be fully determined at shader creation time)");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace StructAndStructMemberTests
|
} // namespace StructAndStructMemberTests
|
||||||
|
|
|
@ -2186,33 +2186,22 @@ bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) cons
|
||||||
const ast::InvariantAttribute* invariant_attribute = nullptr;
|
const ast::InvariantAttribute* invariant_attribute = nullptr;
|
||||||
const ast::InterpolateAttribute* interpolate_attribute = nullptr;
|
const ast::InterpolateAttribute* interpolate_attribute = nullptr;
|
||||||
for (auto* attr : member->Declaration()->attributes) {
|
for (auto* attr : member->Declaration()->attributes) {
|
||||||
if (!attr->IsAnyOf<ast::BuiltinAttribute, //
|
bool ok = Switch(
|
||||||
ast::InternalAttribute, //
|
attr, //
|
||||||
ast::InterpolateAttribute, //
|
[&](const ast::InvariantAttribute* invariant) {
|
||||||
ast::InvariantAttribute, //
|
|
||||||
ast::LocationAttribute, //
|
|
||||||
ast::StructMemberOffsetAttribute, //
|
|
||||||
ast::StructMemberSizeAttribute, //
|
|
||||||
ast::StructMemberAlignAttribute>()) {
|
|
||||||
if (attr->Is<ast::StrideAttribute>() &&
|
|
||||||
IsValidationDisabled(member->Declaration()->attributes,
|
|
||||||
ast::DisabledValidation::kIgnoreStrideAttribute)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
AddError("attribute is not valid for structure members", attr->source);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto* invariant = attr->As<ast::InvariantAttribute>()) {
|
|
||||||
invariant_attribute = invariant;
|
invariant_attribute = invariant;
|
||||||
} else if (auto* location = attr->As<ast::LocationAttribute>()) {
|
return true;
|
||||||
|
},
|
||||||
|
[&](const ast::LocationAttribute* location) {
|
||||||
has_location = true;
|
has_location = true;
|
||||||
TINT_ASSERT(Resolver, member->Location().has_value());
|
TINT_ASSERT(Resolver, member->Location().has_value());
|
||||||
if (!LocationAttribute(location, member->Location().value(), member->Type(),
|
if (!LocationAttribute(location, member->Location().value(), member->Type(),
|
||||||
locations, stage, member->Declaration()->source)) {
|
locations, stage, member->Declaration()->source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
|
return true;
|
||||||
|
},
|
||||||
|
[&](const ast::BuiltinAttribute* builtin) {
|
||||||
if (!BuiltinAttribute(builtin, member->Type(), stage,
|
if (!BuiltinAttribute(builtin, member->Type(), stage,
|
||||||
/* is_input */ false)) {
|
/* is_input */ false)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2220,11 +2209,45 @@ bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) cons
|
||||||
if (builtin->builtin == ast::BuiltinValue::kPosition) {
|
if (builtin->builtin == ast::BuiltinValue::kPosition) {
|
||||||
has_position = true;
|
has_position = true;
|
||||||
}
|
}
|
||||||
} else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
|
return true;
|
||||||
|
},
|
||||||
|
[&](const ast::InterpolateAttribute* interpolate) {
|
||||||
interpolate_attribute = interpolate;
|
interpolate_attribute = interpolate;
|
||||||
if (!InterpolateAttribute(interpolate, member->Type())) {
|
if (!InterpolateAttribute(interpolate, member->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[&](const ast::StructMemberSizeAttribute*) {
|
||||||
|
if (!member->Type()->HasCreationFixedFootprint()) {
|
||||||
|
AddError(
|
||||||
|
"@size can only be applied to members where the member's type size "
|
||||||
|
"can be fully determined at shader creation time",
|
||||||
|
attr->source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[&](Default) {
|
||||||
|
if (!attr->IsAnyOf<ast::BuiltinAttribute, //
|
||||||
|
ast::InternalAttribute, //
|
||||||
|
ast::InterpolateAttribute, //
|
||||||
|
ast::InvariantAttribute, //
|
||||||
|
ast::LocationAttribute, //
|
||||||
|
ast::StructMemberOffsetAttribute, //
|
||||||
|
ast::StructMemberAlignAttribute>()) {
|
||||||
|
if (attr->Is<ast::StrideAttribute>() &&
|
||||||
|
IsValidationDisabled(member->Declaration()->attributes,
|
||||||
|
ast::DisabledValidation::kIgnoreStrideAttribute)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
AddError("attribute is not valid for structure members", attr->source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::AbstractNumeric);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
AbstractNumeric::AbstractNumeric() : Base(TypeFlags{Flag::kConstructable}) {}
|
AbstractNumeric::AbstractNumeric()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
AbstractNumeric::AbstractNumeric(AbstractNumeric&&) = default;
|
AbstractNumeric::AbstractNumeric(AbstractNumeric&&) = default;
|
||||||
AbstractNumeric::~AbstractNumeric() = default;
|
AbstractNumeric::~AbstractNumeric() = default;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,15 @@ TypeFlags FlagsFrom(const Type* element, ArrayCount count) {
|
||||||
if (element->IsConstructible()) {
|
if (element->IsConstructible()) {
|
||||||
flags.Add(TypeFlag::kConstructable);
|
flags.Add(TypeFlag::kConstructable);
|
||||||
}
|
}
|
||||||
|
if (element->HasCreationFixedFootprint()) {
|
||||||
|
flags.Add(TypeFlag::kCreationFixedFootprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ConstantArrayCount>(count) ||
|
||||||
|
std::holds_alternative<OverrideArrayCount>(count)) {
|
||||||
|
if (element->HasFixedFootprint()) {
|
||||||
|
flags.Add(TypeFlag::kFixedFootprint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,5 +135,25 @@ TEST_F(ArrayTest, IsConstructable) {
|
||||||
EXPECT_FALSE(runtime_sized->IsConstructible());
|
EXPECT_FALSE(runtime_sized->IsConstructible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ArrayTest, HasCreationFixedFootprint) {
|
||||||
|
auto* fixed_sized = create<Array>(create<U32>(), ConstantArrayCount{2u}, 4u, 8u, 32u, 16u);
|
||||||
|
auto* override_sized = create<Array>(create<U32>(), OverrideArrayCount{}, 4u, 8u, 32u, 16u);
|
||||||
|
auto* runtime_sized = create<Array>(create<U32>(), RuntimeArrayCount{}, 4u, 8u, 32u, 16u);
|
||||||
|
|
||||||
|
EXPECT_TRUE(fixed_sized->HasCreationFixedFootprint());
|
||||||
|
EXPECT_FALSE(override_sized->HasCreationFixedFootprint());
|
||||||
|
EXPECT_FALSE(runtime_sized->HasCreationFixedFootprint());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ArrayTest, HasFixedFootprint) {
|
||||||
|
auto* fixed_sized = create<Array>(create<U32>(), ConstantArrayCount{2u}, 4u, 8u, 32u, 16u);
|
||||||
|
auto* override_sized = create<Array>(create<U32>(), OverrideArrayCount{}, 4u, 8u, 32u, 16u);
|
||||||
|
auto* runtime_sized = create<Array>(create<U32>(), RuntimeArrayCount{}, 4u, 8u, 32u, 16u);
|
||||||
|
|
||||||
|
EXPECT_TRUE(fixed_sized->HasFixedFootprint());
|
||||||
|
EXPECT_TRUE(override_sized->HasFixedFootprint());
|
||||||
|
EXPECT_FALSE(runtime_sized->HasFixedFootprint());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
|
@ -22,7 +22,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Atomic);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
Atomic::Atomic(const sem::Type* subtype) : Base(TypeFlags{}), subtype_(subtype) {
|
Atomic::Atomic(const sem::Type* subtype)
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}),
|
||||||
|
subtype_(subtype) {
|
||||||
TINT_ASSERT(AST, !subtype->Is<Reference>());
|
TINT_ASSERT(AST, !subtype->Is<Reference>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Bool);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
Bool::Bool() : Base(TypeFlags{Flag::kConstructable}) {}
|
Bool::Bool()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
|
|
||||||
Bool::Bool(Bool&&) = default;
|
Bool::Bool(Bool&&) = default;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::F16);
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace sem {
|
namespace sem {
|
||||||
|
|
||||||
F16::F16() : Base(TypeFlags{Flag::kConstructable}) {}
|
F16::F16()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
|
|
||||||
F16::F16(F16&&) = default;
|
F16::F16(F16&&) = default;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::F32);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
F32::F32() : Base(TypeFlags{Flag::kConstructable}) {}
|
F32::F32()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
|
|
||||||
F32::F32(F32&&) = default;
|
F32::F32(F32&&) = default;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::I32);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
I32::I32() : Base(TypeFlags{Flag::kConstructable}) {}
|
I32::I32()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
|
|
||||||
I32::I32(I32&&) = default;
|
I32::I32(I32&&) = default;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Matrix);
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
Matrix::Matrix(const Vector* column_type, uint32_t columns)
|
Matrix::Matrix(const Vector* column_type, uint32_t columns)
|
||||||
: Base(TypeFlags{Flag::kConstructable}),
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}),
|
||||||
subtype_(column_type->type()),
|
subtype_(column_type->type()),
|
||||||
column_type_(column_type),
|
column_type_(column_type),
|
||||||
rows_(column_type->Width()),
|
rows_(column_type->Width()),
|
||||||
|
|
|
@ -30,11 +30,20 @@ namespace tint::sem {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
TypeFlags FlagsFrom(const StructMemberList& members) {
|
TypeFlags FlagsFrom(const StructMemberList& members) {
|
||||||
TypeFlags flags{TypeFlag::kConstructable};
|
TypeFlags flags{
|
||||||
|
TypeFlag::kConstructable,
|
||||||
|
TypeFlag::kCreationFixedFootprint,
|
||||||
|
TypeFlag::kFixedFootprint,
|
||||||
|
};
|
||||||
for (auto* member : members) {
|
for (auto* member : members) {
|
||||||
if (!member->Type()->IsConstructible()) {
|
if (!member->Type()->IsConstructible()) {
|
||||||
flags.Remove(TypeFlag::kConstructable);
|
flags.Remove(TypeFlag::kConstructable);
|
||||||
break;
|
}
|
||||||
|
if (!member->Type()->HasFixedFootprint()) {
|
||||||
|
flags.Remove(TypeFlag::kFixedFootprint);
|
||||||
|
}
|
||||||
|
if (!member->Type()->HasCreationFixedFootprint()) {
|
||||||
|
flags.Remove(TypeFlag::kCreationFixedFootprint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
|
|
|
@ -157,5 +157,71 @@ TEST_F(StructTest, IsConstructable) {
|
||||||
EXPECT_FALSE(sem_outer_runtime_sized_array->IsConstructible());
|
EXPECT_FALSE(sem_outer_runtime_sized_array->IsConstructible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StructTest, HasCreationFixedFootprint) {
|
||||||
|
auto* inner = //
|
||||||
|
Structure("Inner", utils::Vector{
|
||||||
|
Member("a", ty.i32()),
|
||||||
|
Member("b", ty.u32()),
|
||||||
|
Member("c", ty.f32()),
|
||||||
|
Member("d", ty.vec3<f32>()),
|
||||||
|
Member("e", ty.mat4x2<f32>()),
|
||||||
|
Member("f", ty.array<f32, 32>()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* outer = Structure("Outer", utils::Vector{
|
||||||
|
Member("inner", ty.type_name("Inner")),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* outer_with_runtime_sized_array =
|
||||||
|
Structure("OuterRuntimeSizedArray", utils::Vector{
|
||||||
|
Member("inner", ty.type_name("Inner")),
|
||||||
|
Member("runtime_sized_array", ty.array<i32>()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto p = Build();
|
||||||
|
ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
|
||||||
|
|
||||||
|
auto* sem_inner = p.Sem().Get(inner);
|
||||||
|
auto* sem_outer = p.Sem().Get(outer);
|
||||||
|
auto* sem_outer_with_runtime_sized_array = p.Sem().Get(outer_with_runtime_sized_array);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sem_inner->HasCreationFixedFootprint());
|
||||||
|
EXPECT_TRUE(sem_outer->HasCreationFixedFootprint());
|
||||||
|
EXPECT_FALSE(sem_outer_with_runtime_sized_array->HasCreationFixedFootprint());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructTest, HasFixedFootprint) {
|
||||||
|
auto* inner = //
|
||||||
|
Structure("Inner", utils::Vector{
|
||||||
|
Member("a", ty.i32()),
|
||||||
|
Member("b", ty.u32()),
|
||||||
|
Member("c", ty.f32()),
|
||||||
|
Member("d", ty.vec3<f32>()),
|
||||||
|
Member("e", ty.mat4x2<f32>()),
|
||||||
|
Member("f", ty.array<f32, 32>()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* outer = Structure("Outer", utils::Vector{
|
||||||
|
Member("inner", ty.type_name("Inner")),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* outer_with_runtime_sized_array =
|
||||||
|
Structure("OuterRuntimeSizedArray", utils::Vector{
|
||||||
|
Member("inner", ty.type_name("Inner")),
|
||||||
|
Member("runtime_sized_array", ty.array<i32>()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto p = Build();
|
||||||
|
ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
|
||||||
|
|
||||||
|
auto* sem_inner = p.Sem().Get(inner);
|
||||||
|
auto* sem_outer = p.Sem().Get(outer);
|
||||||
|
auto* sem_outer_with_runtime_sized_array = p.Sem().Get(outer_with_runtime_sized_array);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sem_inner->HasFixedFootprint());
|
||||||
|
EXPECT_TRUE(sem_outer->HasFixedFootprint());
|
||||||
|
EXPECT_FALSE(sem_outer_with_runtime_sized_array->HasFixedFootprint());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
|
@ -34,7 +34,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Type);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
Type::Type(TypeFlags flags) : flags_(flags) {}
|
Type::Type(TypeFlags flags) : flags_(flags) {
|
||||||
|
if (IsConstructible()) {
|
||||||
|
TINT_ASSERT(Semantic, HasCreationFixedFootprint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type::Type(Type&&) = default;
|
Type::Type(Type&&) = default;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,12 @@ enum TypeFlag {
|
||||||
/// Type is constructable.
|
/// Type is constructable.
|
||||||
/// @see https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
/// @see https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
||||||
kConstructable,
|
kConstructable,
|
||||||
|
/// Type has a creation-fixed footprint.
|
||||||
|
/// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
|
||||||
|
kCreationFixedFootprint,
|
||||||
|
/// Type has a fixed footprint.
|
||||||
|
/// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
|
||||||
|
kFixedFootprint,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An alias to utils::EnumSet<TypeFlag>
|
/// An alias to utils::EnumSet<TypeFlag>
|
||||||
|
@ -83,6 +89,16 @@ class Type : public Castable<Type, Node> {
|
||||||
/// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
/// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
||||||
inline bool IsConstructible() const { return flags_.Contains(Flag::kConstructable); }
|
inline bool IsConstructible() const { return flags_.Contains(Flag::kConstructable); }
|
||||||
|
|
||||||
|
/// @returns true has a creation-fixed footprint.
|
||||||
|
/// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
|
||||||
|
inline bool HasCreationFixedFootprint() const {
|
||||||
|
return flags_.Contains(Flag::kCreationFixedFootprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns true has a fixed footprint.
|
||||||
|
/// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
|
||||||
|
inline bool HasFixedFootprint() const { return flags_.Contains(Flag::kFixedFootprint); }
|
||||||
|
|
||||||
/// @returns true if this type is a scalar
|
/// @returns true if this type is a scalar
|
||||||
bool is_scalar() const;
|
bool is_scalar() const;
|
||||||
/// @returns true if this type is a numeric scalar
|
/// @returns true if this type is a numeric scalar
|
||||||
|
|
|
@ -20,7 +20,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::U32);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
U32::U32() : Base(TypeFlags{Flag::kConstructable}) {}
|
U32::U32()
|
||||||
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}) {}
|
||||||
|
|
||||||
U32::~U32() = default;
|
U32::~U32() = default;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::Vector);
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
Vector::Vector(Type const* subtype, uint32_t width)
|
Vector::Vector(Type const* subtype, uint32_t width)
|
||||||
: Base(TypeFlags{Flag::kConstructable}), subtype_(subtype), width_(width) {
|
: Base(TypeFlags{
|
||||||
|
Flag::kConstructable,
|
||||||
|
Flag::kCreationFixedFootprint,
|
||||||
|
Flag::kFixedFootprint,
|
||||||
|
}),
|
||||||
|
subtype_(subtype),
|
||||||
|
width_(width) {
|
||||||
TINT_ASSERT(Semantic, width_ > 1);
|
TINT_ASSERT(Semantic, width_ > 1);
|
||||||
TINT_ASSERT(Semantic, width_ < 5);
|
TINT_ASSERT(Semantic, width_ < 5);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue