Rename all type UnwrapXXX() methods
Give them sensible names. Make them act consistently. Remove those that were not used. Change-Id: Ib043a4093cfae9f81630643e1a0e4eae7bca2440 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50305 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: James Price <jrprice@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
fcda15ef67
commit
f14e0e1c8c
|
@ -80,41 +80,6 @@ TEST_F(AstAliasTest, FriendlyName) {
|
|||
EXPECT_EQ(at->FriendlyName(Symbols()), "Particle");
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapIfNeeded_Alias) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
EXPECT_EQ(a->symbol(), Symbol(1, ID()));
|
||||
EXPECT_EQ(a->type(), u32);
|
||||
EXPECT_EQ(a->UnwrapIfNeeded(), u32);
|
||||
EXPECT_EQ(u32->UnwrapIfNeeded(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapIfNeeded_AccessControl) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* ac = create<AccessControl>(AccessControl::kReadOnly, u32);
|
||||
EXPECT_EQ(ac->type(), u32);
|
||||
EXPECT_EQ(ac->UnwrapIfNeeded(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapIfNeeded_MultiLevel) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
auto* aa = create<Alias>(Sym("aa_type"), a);
|
||||
|
||||
EXPECT_EQ(aa->symbol(), Symbol(2, ID()));
|
||||
EXPECT_EQ(aa->type(), a);
|
||||
EXPECT_EQ(aa->UnwrapIfNeeded(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapIfNeeded_MultiLevel_AliasAccessControl) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
|
||||
auto* ac = create<AccessControl>(AccessControl::kReadWrite, a);
|
||||
EXPECT_EQ(ac->type(), a);
|
||||
EXPECT_EQ(ac->UnwrapIfNeeded(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapAll_TwiceAliasPointerTwiceAlias) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
|
@ -128,31 +93,6 @@ TEST_F(AstAliasTest, UnwrapAll_TwiceAliasPointerTwiceAlias) {
|
|||
EXPECT_EQ(aapaa->UnwrapAll(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapAll_SecondConsecutivePointerBlocksUnrapping) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
auto* aa = create<Alias>(Sym("aa_type"), a);
|
||||
|
||||
auto* paa = create<Pointer>(aa, StorageClass::kUniform);
|
||||
auto* ppaa = create<Pointer>(paa, StorageClass::kUniform);
|
||||
auto* appaa = create<Alias>(Sym("appaa_type"), ppaa);
|
||||
EXPECT_EQ(appaa->UnwrapAll(), paa);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapAll_SecondNonConsecutivePointerBlocksUnrapping) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<Alias>(Sym("a_type"), u32);
|
||||
auto* aa = create<Alias>(Sym("aa_type"), a);
|
||||
auto* paa = create<Pointer>(aa, StorageClass::kUniform);
|
||||
|
||||
auto* apaa = create<Alias>(Sym("apaa_type"), paa);
|
||||
auto* aapaa = create<Alias>(Sym("aapaa_type"), apaa);
|
||||
auto* paapaa = create<Pointer>(aapaa, StorageClass::kUniform);
|
||||
auto* apaapaa = create<Alias>(Sym("apaapaa_type"), paapaa);
|
||||
|
||||
EXPECT_EQ(apaapaa->UnwrapAll(), paa);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapAll_AccessControlPointer) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* a = create<AccessControl>(AccessControl::kReadOnly, u32);
|
||||
|
@ -170,14 +110,6 @@ TEST_F(AstAliasTest, UnwrapAll_PointerAccessControl) {
|
|||
EXPECT_EQ(a->UnwrapAll(), u32);
|
||||
}
|
||||
|
||||
TEST_F(AstAliasTest, UnwrapAliasIfNeeded) {
|
||||
auto* f32 = create<F32>();
|
||||
auto* alias1 = create<Alias>(Sym("alias1"), f32);
|
||||
auto* alias2 = create<Alias>(Sym("alias2"), alias1);
|
||||
auto* alias3 = create<Alias>(Sym("alias3"), alias2);
|
||||
EXPECT_EQ(alias3->UnwrapAliasIfNeeded(), f32);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -38,37 +38,20 @@ Type::Type(Type&&) = default;
|
|||
|
||||
Type::~Type() = default;
|
||||
|
||||
Type* Type::UnwrapPtrIfNeeded() {
|
||||
if (auto* ptr = As<Pointer>()) {
|
||||
return ptr->type();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Type* Type::UnwrapAliasIfNeeded() {
|
||||
Type* unwrapped = this;
|
||||
while (auto* ptr = unwrapped->As<Alias>()) {
|
||||
unwrapped = ptr->type();
|
||||
}
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
Type* Type::UnwrapIfNeeded() {
|
||||
auto* where = this;
|
||||
Type* Type::UnwrapAll() {
|
||||
auto* type = this;
|
||||
while (true) {
|
||||
if (auto* alias = where->As<Alias>()) {
|
||||
where = alias->type();
|
||||
} else if (auto* access = where->As<AccessControl>()) {
|
||||
where = access->type();
|
||||
if (auto* alias = type->As<Alias>()) {
|
||||
type = alias->type();
|
||||
} else if (auto* access = type->As<AccessControl>()) {
|
||||
type = access->type();
|
||||
} else if (auto* ptr = type->As<Pointer>()) {
|
||||
type = ptr->type();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
Type* Type::UnwrapAll() {
|
||||
return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
|
||||
return type;
|
||||
}
|
||||
|
||||
bool Type::is_scalar() const {
|
||||
|
|
|
@ -43,49 +43,10 @@ class Type : public Castable<Type, Node> {
|
|||
/// declared in WGSL.
|
||||
virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
|
||||
|
||||
/// @returns the pointee type if this is a pointer, `this` otherwise
|
||||
Type* UnwrapPtrIfNeeded();
|
||||
|
||||
/// @returns the most deeply nested aliased type if this is an alias, `this`
|
||||
/// otherwise
|
||||
const Type* UnwrapAliasIfNeeded() const {
|
||||
return const_cast<Type*>(this)->UnwrapAliasIfNeeded();
|
||||
}
|
||||
|
||||
/// @returns the most deeply nested aliased type if this is an alias, `this`
|
||||
/// otherwise
|
||||
Type* UnwrapAliasIfNeeded();
|
||||
|
||||
/// Removes all levels of aliasing and access control.
|
||||
/// This is just enough to assist with WGSL translation
|
||||
/// in that you want see through one level of pointer to get from an
|
||||
/// identifier-like expression as an l-value to its corresponding r-value,
|
||||
/// plus see through the wrappers on either side.
|
||||
/// @returns the completely unaliased type.
|
||||
Type* UnwrapIfNeeded();
|
||||
|
||||
/// Removes all levels of aliasing and access control.
|
||||
/// This is just enough to assist with WGSL translation
|
||||
/// in that you want see through one level of pointer to get from an
|
||||
/// identifier-like expression as an l-value to its corresponding r-value,
|
||||
/// plus see through the wrappers on either side.
|
||||
/// @returns the completely unaliased type.
|
||||
const Type* UnwrapIfNeeded() const {
|
||||
return const_cast<Type*>(this)->UnwrapIfNeeded();
|
||||
}
|
||||
|
||||
/// Returns the type found after:
|
||||
/// - removing all layers of aliasing and access control if they exist, then
|
||||
/// - removing the pointer, if it exists, then
|
||||
/// - removing all further layers of aliasing or access control, if they exist
|
||||
/// @returns the unwrapped type
|
||||
/// @returns the type with all aliasing, access control and pointers removed
|
||||
Type* UnwrapAll();
|
||||
|
||||
/// Returns the type found after:
|
||||
/// - removing all layers of aliasing and access control if they exist, then
|
||||
/// - removing the pointer, if it exists, then
|
||||
/// - removing all further layers of aliasing or access control, if they exist
|
||||
/// @returns the unwrapped type
|
||||
/// @returns the type with all aliasing, access control and pointers removed
|
||||
const Type* UnwrapAll() const { return const_cast<Type*>(this)->UnwrapAll(); }
|
||||
|
||||
/// @returns true if this type is a scalar
|
||||
|
|
|
@ -387,7 +387,7 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
|||
auto* var = ruv.first;
|
||||
auto binding_info = ruv.second;
|
||||
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* unwrapped_type = var->Type()->UnwrapAccess();
|
||||
auto* str = unwrapped_type->As<sem::Struct>();
|
||||
if (str == nullptr) {
|
||||
continue;
|
||||
|
@ -509,7 +509,7 @@ std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
|
|||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
|
||||
auto* texture_type = var->Type()->UnwrapIfNeeded()->As<sem::Texture>();
|
||||
auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
|
||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||
texture_type->dim());
|
||||
|
||||
|
@ -602,7 +602,7 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
|||
continue;
|
||||
}
|
||||
|
||||
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::Struct>();
|
||||
auto* str = var->Type()->UnwrapAccess()->As<sem::Struct>();
|
||||
if (!str) {
|
||||
continue;
|
||||
}
|
||||
|
@ -646,18 +646,15 @@ std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
|
|||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
|
||||
auto* texture_type = var->Type()->UnwrapIfNeeded()->As<sem::Texture>();
|
||||
auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
|
||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||
texture_type->dim());
|
||||
|
||||
const sem::Type* base_type = nullptr;
|
||||
if (multisampled_only) {
|
||||
base_type = texture_type->As<sem::MultisampledTexture>()
|
||||
->type()
|
||||
->UnwrapIfNeeded();
|
||||
base_type = texture_type->As<sem::MultisampledTexture>()->type();
|
||||
} else {
|
||||
base_type =
|
||||
texture_type->As<sem::SampledTexture>()->type()->UnwrapIfNeeded();
|
||||
base_type = texture_type->As<sem::SampledTexture>()->type();
|
||||
}
|
||||
entry.sampled_kind = BaseTypeToSampledKind(base_type);
|
||||
|
||||
|
@ -697,12 +694,11 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
|||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
|
||||
auto* texture_type =
|
||||
var->Type()->UnwrapIfNeeded()->As<sem::StorageTexture>();
|
||||
auto* texture_type = var->Type()->UnwrapAccess()->As<sem::StorageTexture>();
|
||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||
texture_type->dim());
|
||||
|
||||
auto* base_type = texture_type->type()->UnwrapIfNeeded();
|
||||
auto* base_type = texture_type->type();
|
||||
entry.sampled_kind = BaseTypeToSampledKind(base_type);
|
||||
entry.image_format = TypeImageFormatToResourceBindingImageFormat(
|
||||
texture_type->image_format());
|
||||
|
|
|
@ -1472,7 +1472,7 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
|||
}
|
||||
|
||||
auto source = GetSourceForInst(inst);
|
||||
auto* ast_type = original_ast_type->UnwrapIfNeeded();
|
||||
auto* ast_type = original_ast_type->UnwrapAliasAndAccess();
|
||||
|
||||
// TODO(dneto): Note: NullConstant for int, uint, float map to a regular 0.
|
||||
// So canonicalization should map that way too.
|
||||
|
@ -1548,7 +1548,7 @@ ast::Expression* ParserImpl::MakeNullValue(const Type* type) {
|
|||
}
|
||||
|
||||
auto* original_type = type;
|
||||
type = type->UnwrapIfNeeded();
|
||||
type = type->UnwrapAliasAndAccess();
|
||||
|
||||
if (type->Is<Bool>()) {
|
||||
return create<ast::ScalarConstructorExpression>(
|
||||
|
|
|
@ -305,37 +305,50 @@ struct TypeManager::State {
|
|||
storage_textures_;
|
||||
};
|
||||
|
||||
const Type* Type::UnwrapPtrIfNeeded() const {
|
||||
if (auto* ptr = As<Pointer>()) {
|
||||
return ptr->type;
|
||||
const Type* Type::UnwrapPtr() const {
|
||||
const Type* type = this;
|
||||
while (auto* ptr = type->As<Pointer>()) {
|
||||
type = ptr->type;
|
||||
}
|
||||
return this;
|
||||
return type;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapAliasIfNeeded() const {
|
||||
const Type* unwrapped = this;
|
||||
while (auto* ptr = unwrapped->As<Alias>()) {
|
||||
unwrapped = ptr->type;
|
||||
const Type* Type::UnwrapAlias() const {
|
||||
const Type* type = this;
|
||||
while (auto* alias = type->As<Alias>()) {
|
||||
type = alias->type;
|
||||
}
|
||||
return unwrapped;
|
||||
return type;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapIfNeeded() const {
|
||||
auto* where = this;
|
||||
const Type* Type::UnwrapAliasAndAccess() const {
|
||||
auto* type = this;
|
||||
while (true) {
|
||||
if (auto* alias = where->As<Alias>()) {
|
||||
where = alias->type;
|
||||
} else if (auto* access = where->As<AccessControl>()) {
|
||||
where = access->type;
|
||||
if (auto* alias = type->As<Alias>()) {
|
||||
type = alias->type;
|
||||
} else if (auto* access = type->As<AccessControl>()) {
|
||||
type = access->type;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where;
|
||||
return type;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapAll() const {
|
||||
return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
|
||||
auto* type = this;
|
||||
while (true) {
|
||||
if (auto* alias = type->As<Alias>()) {
|
||||
type = alias->type;
|
||||
} else if (auto* access = type->As<AccessControl>()) {
|
||||
type = access->type;
|
||||
} else if (auto* ptr = type->As<Pointer>()) {
|
||||
type = ptr->type;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool Type::IsFloatScalar() const {
|
||||
|
|
|
@ -45,26 +45,17 @@ class Type : public Castable<Type> {
|
|||
/// @returns the constructed ast::Type node for the given type
|
||||
virtual ast::Type* Build(ProgramBuilder& b) const = 0;
|
||||
|
||||
/// @returns the pointee type if this is a pointer, `this` otherwise
|
||||
const Type* UnwrapPtrIfNeeded() const;
|
||||
|
||||
/// @returns the most deeply nested aliased type if this is an alias, `this`
|
||||
/// @returns the inner most pointee type if this is a pointer, `this`
|
||||
/// otherwise
|
||||
const Type* UnwrapAliasIfNeeded() const;
|
||||
const Type* UnwrapPtr() const;
|
||||
|
||||
/// Removes all levels of aliasing and access control.
|
||||
/// This is just enough to assist with WGSL translation
|
||||
/// in that you want see through one level of pointer to get from an
|
||||
/// identifier-like expression as an l-value to its corresponding r-value,
|
||||
/// plus see through the wrappers on either side.
|
||||
/// @returns the completely unaliased type.
|
||||
const Type* UnwrapIfNeeded() const;
|
||||
/// @returns the inner most aliased type if this is an alias, `this` otherwise
|
||||
const Type* UnwrapAlias() const;
|
||||
|
||||
/// Returns the type found after:
|
||||
/// - removing all layers of aliasing and access control if they exist, then
|
||||
/// - removing the pointer, if it exists, then
|
||||
/// - removing all further layers of aliasing or access control, if they exist
|
||||
/// @returns the unwrapped type
|
||||
/// @returns the type with all aliasing and access control removed
|
||||
const Type* UnwrapAliasAndAccess() const;
|
||||
|
||||
/// @returns the type with all aliasing, access control and pointers removed
|
||||
const Type* UnwrapAll() const;
|
||||
|
||||
/// @returns true if this type is a float scalar
|
||||
|
|
|
@ -174,7 +174,7 @@ bool Resolver::Resolve() {
|
|||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
|
||||
bool Resolver::IsStorable(const sem::Type* type) {
|
||||
type = type->UnwrapIfNeeded();
|
||||
type = type->UnwrapAccess();
|
||||
if (type->is_scalar() || type->Is<sem::Vector>() || type->Is<sem::Matrix>()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ bool Resolver::IsStorable(const sem::Type* type) {
|
|||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
|
||||
bool Resolver::IsHostShareable(const sem::Type* type) {
|
||||
type = type->UnwrapIfNeeded();
|
||||
type = type->UnwrapAccess();
|
||||
if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -224,9 +224,9 @@ bool Resolver::IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs) {
|
|||
// This will need to be fixed after WGSL agrees the behavior of pointers /
|
||||
// references.
|
||||
// Check:
|
||||
if (lhs->UnwrapIfNeeded() != rhs->UnwrapIfNeeded()) {
|
||||
if (lhs->UnwrapAccess() != rhs->UnwrapAccess()) {
|
||||
// Try RHS dereference
|
||||
if (lhs->UnwrapIfNeeded() != rhs->UnwrapAll()) {
|
||||
if (lhs->UnwrapAccess() != rhs->UnwrapAll()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1636,7 +1636,7 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
|||
}
|
||||
|
||||
auto* res = TypeOf(expr->structure());
|
||||
auto* data_type = res->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
|
||||
auto* data_type = res->UnwrapAll();
|
||||
|
||||
sem::Type* ret = nullptr;
|
||||
std::vector<uint32_t> swizzle;
|
||||
|
@ -1926,7 +1926,7 @@ bool Resolver::Binary(ast::BinaryExpression* expr) {
|
|||
if (expr->IsAnd() || expr->IsOr() || expr->IsXor() || expr->IsShiftLeft() ||
|
||||
expr->IsShiftRight() || expr->IsAdd() || expr->IsSubtract() ||
|
||||
expr->IsDivide() || expr->IsModulo()) {
|
||||
SetType(expr, TypeOf(expr->lhs())->UnwrapPtrIfNeeded());
|
||||
SetType(expr, TypeOf(expr->lhs())->UnwrapPtr());
|
||||
return true;
|
||||
}
|
||||
// Result type is a scalar or vector of boolean type
|
||||
|
@ -1999,7 +1999,7 @@ bool Resolver::UnaryOp(ast::UnaryOpExpression* expr) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto* result_type = TypeOf(expr->expr())->UnwrapPtrIfNeeded();
|
||||
auto* result_type = TypeOf(expr->expr())->UnwrapPtr();
|
||||
SetType(expr, result_type);
|
||||
return true;
|
||||
}
|
||||
|
@ -2039,7 +2039,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
|||
// If the variable has no type, infer it from the rhs
|
||||
if (type == nullptr) {
|
||||
type_name = TypeNameOf(ctor);
|
||||
type = rhs_type->UnwrapPtrIfNeeded();
|
||||
type = rhs_type->UnwrapPtr();
|
||||
}
|
||||
|
||||
if (!IsValidAssignment(type, rhs_type)) {
|
||||
|
@ -2726,7 +2726,7 @@ bool Resolver::ValidateAssignment(const ast::AssignmentStatement* a) {
|
|||
}
|
||||
|
||||
// lhs must be a pointer or a constant
|
||||
auto* lhs_result_type = TypeOf(lhs)->UnwrapIfNeeded();
|
||||
auto* lhs_result_type = TypeOf(lhs)->UnwrapAccess();
|
||||
if (!lhs_result_type->Is<sem::Pointer>()) {
|
||||
// In case lhs is a constant identifier, output a nicer message as it's
|
||||
// likely to be a common programmer error.
|
||||
|
@ -2768,7 +2768,7 @@ bool Resolver::Assignment(ast::AssignmentStatement* a) {
|
|||
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||
sem::Type* ty,
|
||||
const Source& usage) {
|
||||
ty = const_cast<sem::Type*>(ty->UnwrapIfNeeded());
|
||||
ty = const_cast<sem::Type*>(ty->UnwrapAccess());
|
||||
|
||||
if (auto* str = ty->As<sem::Struct>()) {
|
||||
if (str->StorageClassUsage().count(sc)) {
|
||||
|
|
|
@ -521,7 +521,7 @@ TEST_P(CanonicalTest, All) {
|
|||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* got = TypeOf(expr)->UnwrapPtrIfNeeded();
|
||||
auto* got = TypeOf(expr)->UnwrapPtr();
|
||||
auto* expected = params.create_sem_type(ty);
|
||||
|
||||
EXPECT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||
|
|
|
@ -22,9 +22,7 @@ namespace sem {
|
|||
Expression::Expression(ast::Expression* declaration,
|
||||
const sem::Type* type,
|
||||
Statement* statement)
|
||||
: declaration_(declaration),
|
||||
type_(type->UnwrapIfNeeded()),
|
||||
statement_(statement) {
|
||||
: declaration_(declaration), type_(type), statement_(statement) {
|
||||
TINT_ASSERT(type_);
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ Function::VariableBindings Function::ReferencedStorageTextureVariables() const {
|
|||
VariableBindings ret;
|
||||
|
||||
for (auto* var : ReferencedModuleVariables()) {
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* unwrapped_type = var->Type()->UnwrapAccess();
|
||||
auto* storage_texture = unwrapped_type->As<sem::StorageTexture>();
|
||||
if (storage_texture == nullptr) {
|
||||
continue;
|
||||
|
@ -155,7 +155,7 @@ Function::VariableBindings Function::ReferencedDepthTextureVariables() const {
|
|||
VariableBindings ret;
|
||||
|
||||
for (auto* var : ReferencedModuleVariables()) {
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* unwrapped_type = var->Type()->UnwrapAccess();
|
||||
auto* storage_texture = unwrapped_type->As<sem::DepthTexture>();
|
||||
if (storage_texture == nullptr) {
|
||||
continue;
|
||||
|
@ -182,7 +182,7 @@ Function::VariableBindings Function::ReferencedSamplerVariablesImpl(
|
|||
VariableBindings ret;
|
||||
|
||||
for (auto* var : ReferencedModuleVariables()) {
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* unwrapped_type = var->Type()->UnwrapAccess();
|
||||
auto* sampler = unwrapped_type->As<sem::Sampler>();
|
||||
if (sampler == nullptr || sampler->kind() != kind) {
|
||||
continue;
|
||||
|
@ -200,7 +200,7 @@ Function::VariableBindings Function::ReferencedSampledTextureVariablesImpl(
|
|||
VariableBindings ret;
|
||||
|
||||
for (auto* var : ReferencedModuleVariables()) {
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* unwrapped_type = var->Type()->UnwrapAccess();
|
||||
auto* texture = unwrapped_type->As<sem::Texture>();
|
||||
if (texture == nullptr) {
|
||||
continue;
|
||||
|
|
|
@ -36,7 +36,7 @@ Type::Type(Type&&) = default;
|
|||
|
||||
Type::~Type() = default;
|
||||
|
||||
const Type* Type::UnwrapPtrIfNeeded() const {
|
||||
const Type* Type::UnwrapPtr() const {
|
||||
auto* type = this;
|
||||
while (auto* ptr = type->As<sem::Pointer>()) {
|
||||
type = ptr->type();
|
||||
|
@ -44,7 +44,7 @@ const Type* Type::UnwrapPtrIfNeeded() const {
|
|||
return type;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapIfNeeded() const {
|
||||
const Type* Type::UnwrapAccess() const {
|
||||
auto* type = this;
|
||||
while (auto* access = type->As<sem::AccessControl>()) {
|
||||
type = access->type();
|
||||
|
@ -57,14 +57,13 @@ const Type* Type::UnwrapAll() const {
|
|||
while (true) {
|
||||
if (auto* ptr = type->As<sem::Pointer>()) {
|
||||
type = ptr->type();
|
||||
continue;
|
||||
}
|
||||
if (auto* access = type->As<sem::AccessControl>()) {
|
||||
} else if (auto* access = type->As<sem::AccessControl>()) {
|
||||
type = access->type();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool Type::is_scalar() const {
|
||||
|
|
|
@ -45,19 +45,16 @@ class Type : public Castable<Type, Node> {
|
|||
/// declared in WGSL.
|
||||
virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
|
||||
|
||||
/// @returns the pointee type if this is a pointer, `this` otherwise
|
||||
const Type* UnwrapPtrIfNeeded() const;
|
||||
/// @returns the inner most pointee type if this is a pointer, `this`
|
||||
/// otherwise
|
||||
const Type* UnwrapPtr() const;
|
||||
|
||||
/// Removes all levels of access control.
|
||||
/// This is just enough to assist with WGSL translation
|
||||
/// in that you want see through one level of pointer to get from an
|
||||
/// identifier-like expression as an l-value to its corresponding r-value,
|
||||
/// plus see through the wrappers on either side.
|
||||
/// @returns the completely unaliased type.
|
||||
const Type* UnwrapIfNeeded() const;
|
||||
/// @returns the inner most type if this is an access control, `this`
|
||||
/// otherwise
|
||||
const Type* UnwrapAccess() const;
|
||||
|
||||
/// Returns the type found after removing all layers of access control and
|
||||
/// pointer.
|
||||
/// pointer
|
||||
/// @returns the unwrapped type
|
||||
const Type* UnwrapAll() const;
|
||||
|
||||
|
|
|
@ -746,7 +746,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
|||
|
||||
auto* buf = access.var->Declaration();
|
||||
auto* offset = access.offset->Build(ctx);
|
||||
auto* buf_ty = access.var->Type()->UnwrapPtrIfNeeded();
|
||||
auto* buf_ty = access.var->Type()->UnwrapPtr();
|
||||
auto* el_ty = access.type->UnwrapAll();
|
||||
auto* insert_after = ConstructedTypeOf(access.var->Type());
|
||||
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty);
|
||||
|
@ -760,7 +760,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
|||
for (auto& store : state.stores) {
|
||||
auto* buf = store.target.var->Declaration();
|
||||
auto* offset = store.target.offset->Build(ctx);
|
||||
auto* buf_ty = store.target.var->Type()->UnwrapPtrIfNeeded();
|
||||
auto* buf_ty = store.target.var->Type()->UnwrapPtr();
|
||||
auto* el_ty = store.target.type->UnwrapAll();
|
||||
auto* value = store.assignment->rhs();
|
||||
auto* insert_after = ConstructedTypeOf(store.target.var->Type());
|
||||
|
|
|
@ -41,7 +41,7 @@ ast::TypeConstructorExpression* AppendVector(ProgramBuilder* b,
|
|||
uint32_t packed_size;
|
||||
const sem::Type* packed_el_sem_ty;
|
||||
auto* vector_sem = b->Sem().Get(vector);
|
||||
auto* vector_ty = vector_sem->Type()->UnwrapPtrIfNeeded();
|
||||
auto* vector_ty = vector_sem->Type()->UnwrapPtr();
|
||||
if (auto* vec = vector_ty->As<sem::Vector>()) {
|
||||
packed_size = vec->size() + 1;
|
||||
packed_el_sem_ty = vec->type();
|
||||
|
@ -72,7 +72,7 @@ ast::TypeConstructorExpression* AppendVector(ProgramBuilder* b,
|
|||
} else {
|
||||
packed.emplace_back(vector);
|
||||
}
|
||||
if (packed_el_sem_ty != b->TypeOf(scalar)->UnwrapPtrIfNeeded()) {
|
||||
if (packed_el_sem_ty != b->TypeOf(scalar)->UnwrapPtr()) {
|
||||
// Cast scalar to the vector element type
|
||||
auto* scalar_cast = b->Construct(packed_el_ty, scalar);
|
||||
b->Sem().Add(scalar_cast, b->create<sem::Expression>(
|
||||
|
|
|
@ -1697,7 +1697,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
continue; // Global already emitted
|
||||
}
|
||||
|
||||
auto* type = var->Type()->UnwrapIfNeeded();
|
||||
auto* type = var->Type()->UnwrapAccess();
|
||||
if (auto* strct = type->As<sem::Struct>()) {
|
||||
out << "ConstantBuffer<"
|
||||
<< builder_.Symbols().NameFor(strct->Declaration()->name()) << "> "
|
||||
|
|
|
@ -627,7 +627,7 @@ bool Builder::GenerateFunctionVariable(ast::Variable* var) {
|
|||
|
||||
// TODO(dsinclair) We could detect if the constructor is fully const and emit
|
||||
// an initializer value for the variable instead of doing the OpLoad.
|
||||
auto null_id = GenerateConstantNullIfNeeded(type->UnwrapPtrIfNeeded());
|
||||
auto null_id = GenerateConstantNullIfNeeded(type->UnwrapPtr());
|
||||
if (null_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -953,7 +953,7 @@ bool Builder::GenerateMemberAccessor(ast::MemberAccessorExpression* expr,
|
|||
}
|
||||
|
||||
info->source_id = GenerateLoadIfNeeded(expr_type, extract_id);
|
||||
info->source_type = expr_type->UnwrapPtrIfNeeded();
|
||||
info->source_type = expr_type->UnwrapPtr();
|
||||
info->access_chain_indices.clear();
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1130,7 @@ uint32_t Builder::GenerateLoadIfNeeded(const sem::Type* type, uint32_t id) {
|
|||
return id;
|
||||
}
|
||||
|
||||
auto type_id = GenerateTypeIfNeeded(type->UnwrapPtrIfNeeded());
|
||||
auto type_id = GenerateTypeIfNeeded(type->UnwrapPtr());
|
||||
auto result = result_op();
|
||||
auto result_id = result.to_i();
|
||||
if (!push_function_inst(spv::Op::OpLoad,
|
||||
|
@ -1271,7 +1271,7 @@ uint32_t Builder::GenerateTypeConstructorExpression(
|
|||
|
||||
// Generate the zero initializer if there are no values provided.
|
||||
if (values.empty()) {
|
||||
return GenerateConstantNullIfNeeded(result_type->UnwrapPtrIfNeeded());
|
||||
return GenerateConstantNullIfNeeded(result_type->UnwrapPtr());
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
|
@ -1326,7 +1326,7 @@ uint32_t Builder::GenerateTypeConstructorExpression(
|
|||
return 0;
|
||||
}
|
||||
|
||||
auto* value_type = TypeOf(e)->UnwrapPtrIfNeeded();
|
||||
auto* value_type = TypeOf(e)->UnwrapPtr();
|
||||
// If the result and value types are the same we can just use the object.
|
||||
// If the result is not a vector then we should have validated that the
|
||||
// value type is a correctly sized vector so we can just use it directly.
|
||||
|
@ -1443,7 +1443,7 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
|
|||
}
|
||||
val_id = GenerateLoadIfNeeded(TypeOf(from_expr), val_id);
|
||||
|
||||
auto* from_type = TypeOf(from_expr)->UnwrapPtrIfNeeded();
|
||||
auto* from_type = TypeOf(from_expr)->UnwrapPtr();
|
||||
|
||||
spv::Op op = spv::Op::OpNop;
|
||||
if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
|
||||
|
@ -2578,8 +2578,8 @@ uint32_t Builder::GenerateBitcastExpression(ast::BitcastExpression* expr) {
|
|||
val_id = GenerateLoadIfNeeded(TypeOf(expr->expr()), val_id);
|
||||
|
||||
// Bitcast does not allow same types, just emit a CopyObject
|
||||
auto* to_type = TypeOf(expr)->UnwrapPtrIfNeeded();
|
||||
auto* from_type = TypeOf(expr->expr())->UnwrapPtrIfNeeded();
|
||||
auto* to_type = TypeOf(expr)->UnwrapPtr();
|
||||
auto* from_type = TypeOf(expr->expr())->UnwrapPtr();
|
||||
if (to_type->type_name() == from_type->type_name()) {
|
||||
if (!push_function_inst(
|
||||
spv::Op::OpCopyObject,
|
||||
|
@ -2931,7 +2931,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
}
|
||||
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
if (!ac->type()->UnwrapIfNeeded()->Is<sem::Struct>()) {
|
||||
if (!ac->type()->UnwrapAccess()->Is<sem::Struct>()) {
|
||||
return GenerateTypeIfNeeded(ac->type());
|
||||
}
|
||||
}
|
||||
|
@ -2945,7 +2945,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
auto id = result.to_i();
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
// The non-struct case was handled above.
|
||||
auto* subtype = ac->type()->UnwrapIfNeeded();
|
||||
auto* subtype = ac->UnwrapAccess();
|
||||
if (!GenerateStructType(subtype->As<sem::Struct>(), ac->access_control(),
|
||||
result)) {
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue