diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 2167eaf8d3..c424b5914c 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -563,6 +563,7 @@ libtint_source_set("libtint_core_all_src") { "type/array_count.h", "type/atomic.h", "type/bool.h", + "type/clone_context.h", "type/depth_multisampled_texture.h", "type/depth_texture.h", "type/external_texture.h", @@ -715,6 +716,7 @@ libtint_source_set("libtint_type_src") { "type/atomic.h", "type/bool.cc", "type/bool.h", + "type/clone_context.h", "type/depth_multisampled_texture.cc", "type/depth_multisampled_texture.h", "type/depth_texture.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index b30227a7e1..7abc023c59 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -476,6 +476,7 @@ list(APPEND TINT_LIB_SRCS type/atomic.h type/bool.cc type/bool.h + type/clone_context.h type/depth_multisampled_texture.cc type/depth_multisampled_texture.h type/depth_texture.cc @@ -951,7 +952,7 @@ if(TINT_BUILD_TESTS) traits_test.cc transform/transform_test.cc type/array_test.cc - type/atomic.cc + type/atomic_test.cc type/bool_test.cc type/depth_multisampled_texture_test.cc type/depth_texture_test.cc diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc index 517e09b58f..900613017d 100644 --- a/src/tint/ir/builder_impl.cc +++ b/src/tint/ir/builder_impl.cc @@ -83,7 +83,9 @@ bool IsConnected(const FlowNode* b) { } // namespace -BuilderImpl::BuilderImpl(const Program* program) : builder(program) {} +BuilderImpl::BuilderImpl(const Program* program) + : builder(program), + type_clone_ctx_{{&program->Symbols()}, {&builder.ir.symbols, &builder.ir.types}} {} BuilderImpl::~BuilderImpl() = default; @@ -565,61 +567,63 @@ utils::Result BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) } auto* sem = builder.ir.program->Sem().Get(expr); + auto* ty = sem->Type()->Clone(type_clone_ctx_); + Binary* instr = nullptr; switch (expr->op) { case ast::BinaryOp::kAnd: - instr = builder.And(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.And(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kOr: - instr = builder.Or(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Or(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kXor: - instr = builder.Xor(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Xor(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kLogicalAnd: - instr = builder.LogicalAnd(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.LogicalAnd(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kLogicalOr: - instr = builder.LogicalOr(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.LogicalOr(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kEqual: - instr = builder.Equal(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Equal(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kNotEqual: - instr = builder.NotEqual(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.NotEqual(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kLessThan: - instr = builder.LessThan(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.LessThan(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kGreaterThan: - instr = builder.GreaterThan(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.GreaterThan(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kLessThanEqual: - instr = builder.LessThanEqual(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.LessThanEqual(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kGreaterThanEqual: - instr = builder.GreaterThanEqual(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kShiftLeft: - instr = builder.ShiftLeft(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.ShiftLeft(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kShiftRight: - instr = builder.ShiftRight(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.ShiftRight(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kAdd: - instr = builder.Add(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Add(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kSubtract: - instr = builder.Subtract(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Subtract(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kMultiply: - instr = builder.Multiply(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Multiply(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kDivide: - instr = builder.Divide(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Divide(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kModulo: - instr = builder.Modulo(sem->Type(), lhs.Get(), rhs.Get()); + instr = builder.Modulo(ty, lhs.Get(), rhs.Get()); break; case ast::BinaryOp::kNone: TINT_ICE(IR, diagnostics_) << "missing binary operand type"; @@ -637,7 +641,8 @@ utils::Result BuilderImpl::EmitBitcast(const ast::BitcastExpression* exp } auto* sem = builder.ir.program->Sem().Get(expr); - auto* instr = builder.Bitcast(sem->Type(), val.Get()); + auto* ty = sem->Type()->Clone(type_clone_ctx_); + auto* instr = builder.Bitcast(ty, val.Get()); current_flow_block->instructions.Push(instr); return instr->Result(); diff --git a/src/tint/ir/builder_impl.h b/src/tint/ir/builder_impl.h index 5d6fbd76c0..1227b10eb7 100644 --- a/src/tint/ir/builder_impl.h +++ b/src/tint/ir/builder_impl.h @@ -212,6 +212,8 @@ class BuilderImpl { /// Map from ast nodes to flow nodes, used to retrieve the flow node for a given AST node. /// Used for testing purposes. std::unordered_map ast_to_flow_; + + type::CloneContext type_clone_ctx_; }; } // namespace tint::ir diff --git a/src/tint/ir/module.h b/src/tint/ir/module.h index 1ed9ea934e..5e7a9dde7a 100644 --- a/src/tint/ir/module.h +++ b/src/tint/ir/module.h @@ -21,6 +21,8 @@ #include "src/tint/ir/function.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/value.h" +#include "src/tint/program_id.h" +#include "src/tint/symbol_table.h" #include "src/tint/type/manager.h" #include "src/tint/utils/block_allocator.h" #include "src/tint/utils/result.h" @@ -68,6 +70,11 @@ class Module { /// (Note, this will probably turn into a utils::Result, just stubbing for now) const Program* ToProgram() const; + private: + /// Program Id required to create other components + ProgramID prog_id_; + + public: /// The flow node allocator utils::BlockAllocator flow_nodes; /// The constant allocator @@ -87,6 +94,9 @@ class Module { /// The type manager for the module type::Manager types; + + /// The symbol table for the module + SymbolTable symbols{prog_id_}; }; } // namespace tint::ir diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index 0b1a6d815c..e49be4808d 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -63,6 +63,7 @@ class Any final : public Castable { // Stub implementations for type::Type conformance. bool Equals(const type::UniqueNode&) const override { return false; } std::string FriendlyName(const SymbolTable&) const override { return ""; } + type::Type* Clone(type::CloneContext&) const override { return nullptr; } }; /// Number is an 32 bit unsigned integer, which can be in one of three states: diff --git a/src/tint/sem/array_count.cc b/src/tint/sem/array_count.cc index a324ea58e8..4fee9700ce 100644 --- a/src/tint/sem/array_count.cc +++ b/src/tint/sem/array_count.cc @@ -35,6 +35,11 @@ std::string NamedOverrideArrayCount::FriendlyName(const SymbolTable& symbols) co return symbols.NameFor(variable->Declaration()->symbol); } +type::ArrayCount* NamedOverrideArrayCount::Clone(type::CloneContext&) const { + TINT_ASSERT(Type, false && "Named override array count clone not available"); + return nullptr; +} + UnnamedOverrideArrayCount::UnnamedOverrideArrayCount(const Expression* e) : Base(static_cast(TypeInfo::Of().full_hashcode)), expr(e) {} UnnamedOverrideArrayCount::~UnnamedOverrideArrayCount() = default; @@ -50,4 +55,9 @@ std::string UnnamedOverrideArrayCount::FriendlyName(const SymbolTable&) const { return "[unnamed override-expression]"; } +type::ArrayCount* UnnamedOverrideArrayCount::Clone(type::CloneContext&) const { + TINT_ASSERT(Type, false && "Unnamed override array count clone not available"); + return nullptr; +} + } // namespace tint::sem diff --git a/src/tint/sem/array_count.h b/src/tint/sem/array_count.h index fd441e8959..2d3c27fa9f 100644 --- a/src/tint/sem/array_count.h +++ b/src/tint/sem/array_count.h @@ -44,6 +44,10 @@ class NamedOverrideArrayCount final : public CastableGet(); +} + } // namespace tint::type diff --git a/src/tint/type/abstract_float.h b/src/tint/type/abstract_float.h index 9a7d4a8bb1..8ec08823b9 100644 --- a/src/tint/type/abstract_float.h +++ b/src/tint/type/abstract_float.h @@ -38,6 +38,10 @@ class AbstractFloat final : public Castable { /// @param symbols the program's symbol table /// @returns the name for this type when printed in diagnostics. std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + AbstractFloat* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/abstract_int.cc b/src/tint/type/abstract_int.cc index 990d4e6264..806cdd3865 100644 --- a/src/tint/type/abstract_int.cc +++ b/src/tint/type/abstract_int.cc @@ -33,4 +33,8 @@ std::string AbstractInt::FriendlyName(const SymbolTable&) const { return "abstract-int"; } +AbstractInt* AbstractInt::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/abstract_int.h b/src/tint/type/abstract_int.h index 2df6328d41..7c96c8f7a1 100644 --- a/src/tint/type/abstract_int.h +++ b/src/tint/type/abstract_int.h @@ -38,6 +38,10 @@ class AbstractInt final : public Castable { /// @param symbols the program's symbol table /// @returns the name for this type when printed in diagnostics. std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + AbstractInt* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/array.cc b/src/tint/type/array.cc index 6df6cdc81f..6e1d297e66 100644 --- a/src/tint/type/array.cc +++ b/src/tint/type/array.cc @@ -19,6 +19,7 @@ #include "src/tint/ast/variable.h" #include "src/tint/debug.h" #include "src/tint/symbol_table.h" +#include "src/tint/type/manager.h" #include "src/tint/utils/hash.h" TINT_INSTANTIATE_TYPEINFO(tint::type::Array); @@ -103,4 +104,11 @@ uint32_t Array::Size() const { return size_; } +Array* Array::Clone(CloneContext& ctx) const { + auto* elem_ty = element_->Clone(ctx); + auto* count = count_->Clone(ctx); + + return ctx.dst.mgr->Get(elem_ty, count, align_, size_, stride_, implicit_stride_); +} + } // namespace tint::type diff --git a/src/tint/type/array.h b/src/tint/type/array.h index 18882a41f5..95ed164032 100644 --- a/src/tint/type/array.h +++ b/src/tint/type/array.h @@ -98,6 +98,10 @@ class Array final : public Castable { /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + Array* Clone(CloneContext& ctx) const override; + private: Type const* const element_; const ArrayCount* count_; diff --git a/src/tint/type/array_count.cc b/src/tint/type/array_count.cc index bebe8969cc..e50db29f50 100644 --- a/src/tint/type/array_count.cc +++ b/src/tint/type/array_count.cc @@ -14,6 +14,8 @@ #include "src/tint/type/array_count.h" +#include "src/tint/type/manager.h" + TINT_INSTANTIATE_TYPEINFO(tint::type::ArrayCount); TINT_INSTANTIATE_TYPEINFO(tint::type::ConstantArrayCount); TINT_INSTANTIATE_TYPEINFO(tint::type::RuntimeArrayCount); @@ -38,6 +40,10 @@ std::string ConstantArrayCount::FriendlyName(const SymbolTable&) const { return std::to_string(value); } +ConstantArrayCount* ConstantArrayCount::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(value); +} + RuntimeArrayCount::RuntimeArrayCount() : Base(static_cast(TypeInfo::Of().full_hashcode)) {} RuntimeArrayCount::~RuntimeArrayCount() = default; @@ -50,4 +56,8 @@ std::string RuntimeArrayCount::FriendlyName(const SymbolTable&) const { return ""; } +RuntimeArrayCount* RuntimeArrayCount::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/array_count.h b/src/tint/type/array_count.h index aa2c18201a..90fc253606 100644 --- a/src/tint/type/array_count.h +++ b/src/tint/type/array_count.h @@ -19,6 +19,7 @@ #include #include "src/tint/symbol_table.h" +#include "src/tint/type/clone_context.h" #include "src/tint/type/unique_node.h" namespace tint::type { @@ -32,6 +33,10 @@ class ArrayCount : public Castable { /// @returns the friendly name for this array count virtual std::string FriendlyName(const SymbolTable& symbols) const = 0; + /// @param ctx the clone context + /// @returns a clone of this type + virtual ArrayCount* Clone(CloneContext& ctx) const = 0; + protected: /// Constructor /// @param hash the unique hash of the node @@ -59,6 +64,10 @@ class ConstantArrayCount final : public Castable /// @returns the friendly name for this array count std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + ConstantArrayCount* Clone(CloneContext& ctx) const override; + /// The array count constant-expression value. uint32_t value; }; @@ -81,6 +90,10 @@ class RuntimeArrayCount final : public Castable { /// @param symbols the symbol table /// @returns the friendly name for this array count std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + RuntimeArrayCount* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/array_test.cc b/src/tint/type/array_test.cc index 089b12ebad..8f80a63638 100644 --- a/src/tint/type/array_test.cc +++ b/src/tint/type/array_test.cc @@ -164,5 +164,41 @@ TEST_F(ArrayTest, HasFixedFootprint) { EXPECT_FALSE(runtime_sized->HasFixedFootprint()); } +TEST_F(ArrayTest, CloneSizedArray) { + auto* ary = create(create(), create(2u), 4u, 8u, 32u, 16u); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* val = ary->Clone(ctx); + + ASSERT_NE(val, nullptr); + EXPECT_TRUE(val->ElemType()->Is()); + EXPECT_TRUE(val->Count()->Is()); + EXPECT_EQ(val->Count()->As()->value, 2u); + EXPECT_EQ(val->Align(), 4u); + EXPECT_EQ(val->Size(), 8u); + EXPECT_EQ(val->Stride(), 32u); + EXPECT_EQ(val->ImplicitStride(), 16u); + EXPECT_FALSE(val->IsStrideImplicit()); +} + +TEST_F(ArrayTest, CloneRuntimeArray) { + auto* ary = create(create(), create(), 4u, 8u, 32u, 32u); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* val = ary->Clone(ctx); + ASSERT_NE(val, nullptr); + EXPECT_TRUE(val->ElemType()->Is()); + EXPECT_TRUE(val->Count()->Is()); + EXPECT_EQ(val->Align(), 4u); + EXPECT_EQ(val->Size(), 8u); + EXPECT_EQ(val->Stride(), 32u); + EXPECT_EQ(val->ImplicitStride(), 32u); + EXPECT_TRUE(val->IsStrideImplicit()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/atomic.cc b/src/tint/type/atomic.cc index 91efcd4150..0daa7f51fb 100644 --- a/src/tint/type/atomic.cc +++ b/src/tint/type/atomic.cc @@ -55,4 +55,9 @@ uint32_t Atomic::Align() const { Atomic::~Atomic() = default; +Atomic* Atomic::Clone(CloneContext& ctx) const { + auto* ty = subtype_->Clone(ctx); + return ctx.dst.mgr->Get(ty); +} + } // namespace tint::type diff --git a/src/tint/type/atomic.h b/src/tint/type/atomic.h index 31d1c5bbc8..9b3d4fc451 100644 --- a/src/tint/type/atomic.h +++ b/src/tint/type/atomic.h @@ -49,6 +49,10 @@ class Atomic final : public Castable { /// @returns the alignment in bytes of the type. uint32_t Align() const override; + /// @param ctx the clone context + /// @returns a clone of this type + Atomic* Clone(CloneContext& ctx) const override; + private: type::Type const* const subtype_; }; diff --git a/src/tint/type/atomic_test.cc b/src/tint/type/atomic_test.cc index ed0bdecfa1..e7126cbd28 100644 --- a/src/tint/type/atomic_test.cc +++ b/src/tint/type/atomic_test.cc @@ -50,5 +50,15 @@ TEST_F(AtomicTest, FriendlyName) { EXPECT_EQ(a->FriendlyName(Symbols()), "atomic"); } +TEST_F(AtomicTest, Clone) { + auto* atomic = create(create()); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* val = atomic->Clone(ctx); + EXPECT_TRUE(val->Type()->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/bool.cc b/src/tint/type/bool.cc index 89c55a1835..4c3849c32f 100644 --- a/src/tint/type/bool.cc +++ b/src/tint/type/bool.cc @@ -46,4 +46,8 @@ uint32_t Bool::Align() const { return 4; } +Bool* Bool::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/bool.h b/src/tint/type/bool.h index a33a352982..d73341c80e 100644 --- a/src/tint/type/bool.h +++ b/src/tint/type/bool.h @@ -54,6 +54,10 @@ class Bool final : public Castable { /// @note: booleans are not host-sharable, but still may exist in workgroup /// storage. uint32_t Align() const override; + + /// @param ctx the clone context + /// @returns a clone of this type + Bool* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/bool_test.cc b/src/tint/type/bool_test.cc index d9b9d7a757..b061927310 100644 --- a/src/tint/type/bool_test.cc +++ b/src/tint/type/bool_test.cc @@ -44,5 +44,14 @@ TEST_F(BoolTest, FriendlyName) { EXPECT_EQ(b.FriendlyName(Symbols()), "bool"); } +TEST_F(BoolTest, Clone) { + auto* a = create(); + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/clone_context.h b/src/tint/type/clone_context.h new file mode 100644 index 0000000000..55ed44dd28 --- /dev/null +++ b/src/tint/type/clone_context.h @@ -0,0 +1,47 @@ +// Copyright 2023 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_TYPE_CLONE_CONTEXT_H_ +#define SRC_TINT_TYPE_CLONE_CONTEXT_H_ + +// Forward Declarations +namespace tint { +class SymbolTable; +} // namespace tint +namespace tint::type { +class Manager; +} // namespace tint::type + +namespace tint::type { + +/// Context information for cloning of types +struct CloneContext { + /// Source information + struct { + /// The source symbol table + const SymbolTable* st; + } src; + + /// Destination information + struct { + /// The destination symbol table + SymbolTable* st; + /// The destination type manger + Manager* mgr; + } dst; +}; + +} // namespace tint::type + +#endif // SRC_TINT_TYPE_CLONE_CONTEXT_H_ diff --git a/src/tint/type/depth_multisampled_texture.cc b/src/tint/type/depth_multisampled_texture.cc index 1313d70cff..7e80eb1bd3 100644 --- a/src/tint/type/depth_multisampled_texture.cc +++ b/src/tint/type/depth_multisampled_texture.cc @@ -48,4 +48,8 @@ std::string DepthMultisampledTexture::FriendlyName(const SymbolTable&) const { return out.str(); } +DepthMultisampledTexture* DepthMultisampledTexture::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(dim()); +} + } // namespace tint::type diff --git a/src/tint/type/depth_multisampled_texture.h b/src/tint/type/depth_multisampled_texture.h index f92a00da61..d91b4638b3 100644 --- a/src/tint/type/depth_multisampled_texture.h +++ b/src/tint/type/depth_multisampled_texture.h @@ -39,6 +39,10 @@ class DepthMultisampledTexture final : public Castable(ast::TextureDimension::k2d); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* dt = a->Clone(ctx); + EXPECT_EQ(dt->dim(), ast::TextureDimension::k2d); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/depth_texture.cc b/src/tint/type/depth_texture.cc index c5d5aaeb37..2295b39afb 100644 --- a/src/tint/type/depth_texture.cc +++ b/src/tint/type/depth_texture.cc @@ -49,4 +49,8 @@ std::string DepthTexture::FriendlyName(const SymbolTable&) const { return out.str(); } +DepthTexture* DepthTexture::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(dim()); +} + } // namespace tint::type diff --git a/src/tint/type/depth_texture.h b/src/tint/type/depth_texture.h index 0e5bef396c..21cd780d2d 100644 --- a/src/tint/type/depth_texture.h +++ b/src/tint/type/depth_texture.h @@ -39,6 +39,10 @@ class DepthTexture final : public Castable { /// @returns the name for this type that closely resembles how it would be /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + DepthTexture* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/depth_texture_test.cc b/src/tint/type/depth_texture_test.cc index eab9ba891a..18dda3d365 100644 --- a/src/tint/type/depth_texture_test.cc +++ b/src/tint/type/depth_texture_test.cc @@ -69,5 +69,15 @@ TEST_F(DepthTextureTest, FriendlyName) { EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_cube"); } +TEST_F(DepthTextureTest, Clone) { + auto* a = create(ast::TextureDimension::k2d); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* dt = a->Clone(ctx); + EXPECT_EQ(dt->dim(), ast::TextureDimension::k2d); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/external_texture.cc b/src/tint/type/external_texture.cc index 9bc319c95b..77ac5ba9bc 100644 --- a/src/tint/type/external_texture.cc +++ b/src/tint/type/external_texture.cc @@ -34,4 +34,8 @@ std::string ExternalTexture::FriendlyName(const SymbolTable&) const { return "texture_external"; } +ExternalTexture* ExternalTexture::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/external_texture.h b/src/tint/type/external_texture.h index a60eddcae7..947eb88b36 100644 --- a/src/tint/type/external_texture.h +++ b/src/tint/type/external_texture.h @@ -38,6 +38,10 @@ class ExternalTexture final : public Castable { /// @returns the name for this type that closely resembles how it would be /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + ExternalTexture* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/external_texture_test.cc b/src/tint/type/external_texture_test.cc index d04b973b5a..e9ea95dd78 100644 --- a/src/tint/type/external_texture_test.cc +++ b/src/tint/type/external_texture_test.cc @@ -66,5 +66,15 @@ TEST_F(ExternalTextureTest, FriendlyName) { EXPECT_EQ(s.FriendlyName(Symbols()), "texture_external"); } +TEST_F(ExternalTextureTest, Clone) { + auto* a = create(); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/f16.cc b/src/tint/type/f16.cc index 94849e5940..5ea9aca307 100644 --- a/src/tint/type/f16.cc +++ b/src/tint/type/f16.cc @@ -46,4 +46,8 @@ uint32_t F16::Align() const { return 2; } +F16* F16::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/f16.h b/src/tint/type/f16.h index 9cac21b86c..c35d878cab 100644 --- a/src/tint/type/f16.h +++ b/src/tint/type/f16.h @@ -44,6 +44,10 @@ class F16 final : public Castable { /// @returns the alignment in bytes of the type. uint32_t Align() const override; + + /// @param ctx the clone context + /// @returns a clone of this type + F16* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/f16_test.cc b/src/tint/type/f16_test.cc index e4863805e0..a9a2fe0c9e 100644 --- a/src/tint/type/f16_test.cc +++ b/src/tint/type/f16_test.cc @@ -44,5 +44,15 @@ TEST_F(F16Test, FriendlyName) { EXPECT_EQ(f.FriendlyName(Symbols()), "f16"); } +TEST_F(F16Test, Clone) { + auto* a = create(); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/f32.cc b/src/tint/type/f32.cc index 4ccd13a05a..91872a2366 100644 --- a/src/tint/type/f32.cc +++ b/src/tint/type/f32.cc @@ -46,4 +46,8 @@ uint32_t F32::Align() const { return 4; } +F32* F32::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/f32.h b/src/tint/type/f32.h index 7a1e864e3f..12b298f07e 100644 --- a/src/tint/type/f32.h +++ b/src/tint/type/f32.h @@ -44,6 +44,10 @@ class F32 final : public Castable { /// @returns the alignment in bytes of the type. uint32_t Align() const override; + + /// @param ctx the clone context + /// @returns a clone of this type + F32* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/f32_test.cc b/src/tint/type/f32_test.cc index 8ecbdbdcc7..43d7823a9c 100644 --- a/src/tint/type/f32_test.cc +++ b/src/tint/type/f32_test.cc @@ -44,5 +44,15 @@ TEST_F(F32Test, FriendlyName) { EXPECT_EQ(f.FriendlyName(Symbols()), "f32"); } +TEST_F(F32Test, Clone) { + auto* a = create(); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/i32.cc b/src/tint/type/i32.cc index c616d14a3e..9fe0d95a24 100644 --- a/src/tint/type/i32.cc +++ b/src/tint/type/i32.cc @@ -46,4 +46,8 @@ uint32_t I32::Align() const { return 4; } +I32* I32::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/i32.h b/src/tint/type/i32.h index 2160c3a48b..bdbf559561 100644 --- a/src/tint/type/i32.h +++ b/src/tint/type/i32.h @@ -44,6 +44,10 @@ class I32 final : public Castable { /// @returns the alignment in bytes of the type. uint32_t Align() const override; + + /// @param ctx the clone context + /// @returns a clone of this type + I32* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/i32_test.cc b/src/tint/type/i32_test.cc index bdcbf8ed69..97c90b1882 100644 --- a/src/tint/type/i32_test.cc +++ b/src/tint/type/i32_test.cc @@ -44,5 +44,15 @@ TEST_F(I32Test, FriendlyName) { EXPECT_EQ(i.FriendlyName(Symbols()), "i32"); } +TEST_F(I32Test, Clone) { + auto* a = create(); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/manager.cc b/src/tint/type/manager.cc index 2c455eb726..666a1d3c71 100644 --- a/src/tint/type/manager.cc +++ b/src/tint/type/manager.cc @@ -17,8 +17,11 @@ namespace tint::type { Manager::Manager() = default; + Manager::Manager(Manager&&) = default; + Manager& Manager::operator=(Manager&& rhs) = default; + Manager::~Manager() = default; } // namespace tint::type diff --git a/src/tint/type/matrix.cc b/src/tint/type/matrix.cc index 0d7571fe6b..600f4b04f0 100644 --- a/src/tint/type/matrix.cc +++ b/src/tint/type/matrix.cc @@ -66,4 +66,9 @@ uint32_t Matrix::ColumnStride() const { return column_type_->Align(); } +Matrix* Matrix::Clone(CloneContext& ctx) const { + auto* col_ty = column_type_->Clone(ctx); + return ctx.dst.mgr->Get(col_ty, columns_); +} + } // namespace tint::type diff --git a/src/tint/type/matrix.h b/src/tint/type/matrix.h index 70555ea699..72bb2e55fc 100644 --- a/src/tint/type/matrix.h +++ b/src/tint/type/matrix.h @@ -66,6 +66,10 @@ class Matrix final : public Castable { /// @returns the number of bytes between columns of the matrix uint32_t ColumnStride() const; + /// @param ctx the clone context + /// @returns a clone of this type + Matrix* Clone(CloneContext& ctx) const override; + private: const Type* const subtype_; const Vector* const column_type_; diff --git a/src/tint/type/matrix_test.cc b/src/tint/type/matrix_test.cc index 3a7474128b..09b46f1e51 100644 --- a/src/tint/type/matrix_test.cc +++ b/src/tint/type/matrix_test.cc @@ -65,5 +65,17 @@ TEST_F(MatrixTest, FriendlyName) { EXPECT_EQ(m.FriendlyName(Symbols()), "mat2x3"); } +TEST_F(MatrixTest, Clone) { + auto* a = create(create(create(), 3u), 4u); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* mat = a->Clone(ctx); + EXPECT_TRUE(mat->type()->Is()); + EXPECT_EQ(mat->rows(), 3u); + EXPECT_EQ(mat->columns(), 4u); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/multisampled_texture.cc b/src/tint/type/multisampled_texture.cc index 16588f4b14..47d3e210bd 100644 --- a/src/tint/type/multisampled_texture.cc +++ b/src/tint/type/multisampled_texture.cc @@ -42,4 +42,9 @@ std::string MultisampledTexture::FriendlyName(const SymbolTable& symbols) const return out.str(); } +MultisampledTexture* MultisampledTexture::Clone(CloneContext& ctx) const { + auto* ty = type_->Clone(ctx); + return ctx.dst.mgr->Get(dim(), ty); +} + } // namespace tint::type diff --git a/src/tint/type/multisampled_texture.h b/src/tint/type/multisampled_texture.h index f78d40b12f..3048590c3a 100644 --- a/src/tint/type/multisampled_texture.h +++ b/src/tint/type/multisampled_texture.h @@ -44,6 +44,10 @@ class MultisampledTexture final : public Castable /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + MultisampledTexture* Clone(CloneContext& ctx) const override; + private: const Type* const type_; }; diff --git a/src/tint/type/multisampled_texture_test.cc b/src/tint/type/multisampled_texture_test.cc index e919ccf27b..b3b671aed1 100644 --- a/src/tint/type/multisampled_texture_test.cc +++ b/src/tint/type/multisampled_texture_test.cc @@ -81,5 +81,16 @@ TEST_F(MultisampledTextureTest, FriendlyName) { EXPECT_EQ(s.FriendlyName(Symbols()), "texture_multisampled_3d"); } +TEST_F(MultisampledTextureTest, Clone) { + auto* a = create(ast::TextureDimension::k2d, create()); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* mt = a->Clone(ctx); + EXPECT_EQ(mt->dim(), ast::TextureDimension::k2d); + EXPECT_TRUE(mt->type()->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/pointer.cc b/src/tint/type/pointer.cc index 0ae8e0ad41..8716b92a57 100644 --- a/src/tint/type/pointer.cc +++ b/src/tint/type/pointer.cc @@ -53,4 +53,9 @@ std::string Pointer::FriendlyName(const SymbolTable& symbols) const { Pointer::~Pointer() = default; +Pointer* Pointer::Clone(CloneContext& ctx) const { + auto* ty = subtype_->Clone(ctx); + return ctx.dst.mgr->Get(ty, address_space_, access_); +} + } // namespace tint::type diff --git a/src/tint/type/pointer.h b/src/tint/type/pointer.h index 3f7ff0191f..083647ecef 100644 --- a/src/tint/type/pointer.h +++ b/src/tint/type/pointer.h @@ -53,6 +53,10 @@ class Pointer final : public Castable { /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + Pointer* Clone(CloneContext& ctx) const override; + private: Type const* const subtype_; ast::AddressSpace const address_space_; diff --git a/src/tint/type/pointer_test.cc b/src/tint/type/pointer_test.cc index af3587a93d..85fcab72fb 100644 --- a/src/tint/type/pointer_test.cc +++ b/src/tint/type/pointer_test.cc @@ -68,5 +68,17 @@ TEST_F(PointerTest, FriendlyNameWithAddressSpace) { EXPECT_EQ(r->FriendlyName(Symbols()), "ptr"); } +TEST_F(PointerTest, Clone) { + auto* a = create(create(), ast::AddressSpace::kStorage, ast::Access::kReadWrite); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* ptr = a->Clone(ctx); + EXPECT_TRUE(ptr->StoreType()->Is()); + EXPECT_EQ(ptr->AddressSpace(), ast::AddressSpace::kStorage); + EXPECT_EQ(ptr->Access(), ast::Access::kReadWrite); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/reference.cc b/src/tint/type/reference.cc index f811b28a1b..36915fccfe 100644 --- a/src/tint/type/reference.cc +++ b/src/tint/type/reference.cc @@ -52,4 +52,9 @@ std::string Reference::FriendlyName(const SymbolTable& symbols) const { Reference::~Reference() = default; +Reference* Reference::Clone(CloneContext& ctx) const { + auto* ty = subtype_->Clone(ctx); + return ctx.dst.mgr->Get(ty, address_space_, access_); +} + } // namespace tint::type diff --git a/src/tint/type/reference.h b/src/tint/type/reference.h index e13b3cf84a..d4235c18b9 100644 --- a/src/tint/type/reference.h +++ b/src/tint/type/reference.h @@ -53,6 +53,10 @@ class Reference final : public Castable { /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + Reference* Clone(CloneContext& ctx) const override; + private: Type const* const subtype_; ast::AddressSpace const address_space_; diff --git a/src/tint/type/reference_test.cc b/src/tint/type/reference_test.cc index e9f61289a1..93e42ad217 100644 --- a/src/tint/type/reference_test.cc +++ b/src/tint/type/reference_test.cc @@ -78,5 +78,18 @@ TEST_F(ReferenceTest, FriendlyNameWithAddressSpace) { EXPECT_EQ(r->FriendlyName(Symbols()), "ref"); } +TEST_F(ReferenceTest, Clone) { + auto* a = + create(create(), ast::AddressSpace::kStorage, ast::Access::kReadWrite); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* ref = a->Clone(ctx); + EXPECT_TRUE(ref->StoreType()->Is()); + EXPECT_EQ(ref->AddressSpace(), ast::AddressSpace::kStorage); + EXPECT_EQ(ref->Access(), ast::Access::kReadWrite); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/sampled_texture.cc b/src/tint/type/sampled_texture.cc index a8bdce6929..7651b410f6 100644 --- a/src/tint/type/sampled_texture.cc +++ b/src/tint/type/sampled_texture.cc @@ -41,4 +41,9 @@ std::string SampledTexture::FriendlyName(const SymbolTable& symbols) const { return out.str(); } +SampledTexture* SampledTexture::Clone(CloneContext& ctx) const { + auto* ty = type_->Clone(ctx); + return ctx.dst.mgr->Get(dim(), ty); +} + } // namespace tint::type diff --git a/src/tint/type/sampled_texture.h b/src/tint/type/sampled_texture.h index 527210218f..1f3779084b 100644 --- a/src/tint/type/sampled_texture.h +++ b/src/tint/type/sampled_texture.h @@ -44,6 +44,10 @@ class SampledTexture final : public Castable { /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + SampledTexture* Clone(CloneContext& ctx) const override; + private: const Type* const type_; }; diff --git a/src/tint/type/sampled_texture_test.cc b/src/tint/type/sampled_texture_test.cc index 772629f626..78ab2d3477 100644 --- a/src/tint/type/sampled_texture_test.cc +++ b/src/tint/type/sampled_texture_test.cc @@ -85,5 +85,16 @@ TEST_F(SampledTextureTest, FriendlyName) { EXPECT_EQ(s.FriendlyName(Symbols()), "texture_3d"); } +TEST_F(SampledTextureTest, Clone) { + auto* a = create(ast::TextureDimension::kCube, create()); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* mt = a->Clone(ctx); + EXPECT_EQ(mt->dim(), ast::TextureDimension::kCube); + EXPECT_TRUE(mt->type()->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/sampler.cc b/src/tint/type/sampler.cc index 9de1ea83e9..50d3f289d6 100644 --- a/src/tint/type/sampler.cc +++ b/src/tint/type/sampler.cc @@ -37,4 +37,8 @@ std::string Sampler::FriendlyName(const SymbolTable&) const { return kind_ == ast::SamplerKind::kSampler ? "sampler" : "sampler_comparison"; } +Sampler* Sampler::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(kind_); +} + } // namespace tint::type diff --git a/src/tint/type/sampler.h b/src/tint/type/sampler.h index 7778dcd7a4..ab810738b1 100644 --- a/src/tint/type/sampler.h +++ b/src/tint/type/sampler.h @@ -47,6 +47,10 @@ class Sampler final : public Castable { /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + /// @param ctx the clone context + /// @returns a clone of this type + Sampler* Clone(CloneContext& ctx) const override; + private: ast::SamplerKind const kind_; }; diff --git a/src/tint/type/sampler_test.cc b/src/tint/type/sampler_test.cc index 262dd18de5..ef0bdf5510 100644 --- a/src/tint/type/sampler_test.cc +++ b/src/tint/type/sampler_test.cc @@ -63,5 +63,15 @@ TEST_F(SamplerTest, FriendlyNameComparisonSampler) { EXPECT_EQ(s.FriendlyName(Symbols()), "sampler_comparison"); } +TEST_F(SamplerTest, Clone) { + auto* a = create(ast::SamplerKind::kSampler); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* mt = a->Clone(ctx); + EXPECT_EQ(mt->kind(), ast::SamplerKind::kSampler); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/storage_texture.cc b/src/tint/type/storage_texture.cc index ae574f19f2..d893767770 100644 --- a/src/tint/type/storage_texture.cc +++ b/src/tint/type/storage_texture.cc @@ -79,4 +79,9 @@ Type* StorageTexture::SubtypeFor(ast::TexelFormat format, Manager& type_mgr) { return nullptr; } +StorageTexture* StorageTexture::Clone(CloneContext& ctx) const { + auto* ty = subtype_->Clone(ctx); + return ctx.dst.mgr->Get(dim(), texel_format_, access_, ty); +} + } // namespace tint::type diff --git a/src/tint/type/storage_texture.h b/src/tint/type/storage_texture.h index 25b452b2a8..276e045601 100644 --- a/src/tint/type/storage_texture.h +++ b/src/tint/type/storage_texture.h @@ -67,6 +67,10 @@ class StorageTexture final : public Castable { /// @returns the storage texture subtype for the given TexelFormat static Type* SubtypeFor(ast::TexelFormat format, Manager& type_mgr); + /// @param ctx the clone context + /// @returns a clone of this type + StorageTexture* Clone(CloneContext& ctx) const override; + private: ast::TexelFormat const texel_format_; ast::Access const access_; diff --git a/src/tint/type/storage_texture_test.cc b/src/tint/type/storage_texture_test.cc index 30293ee3dd..ad8a975d8e 100644 --- a/src/tint/type/storage_texture_test.cc +++ b/src/tint/type/storage_texture_test.cc @@ -134,5 +134,18 @@ TEST_F(StorageTextureTest, I32) { EXPECT_TRUE(s->As()->type()->Is()); } +TEST_F(StorageTextureTest, Clone) { + auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, + ast::Access::kReadWrite); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* mt = a->Clone(ctx); + EXPECT_EQ(mt->dim(), ast::TextureDimension::kCube); + EXPECT_EQ(mt->texel_format(), ast::TexelFormat::kRgba32Float); + EXPECT_TRUE(mt->type()->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/struct.cc b/src/tint/type/struct.cc index f54f21f68b..c39916b605 100644 --- a/src/tint/type/struct.cc +++ b/src/tint/type/struct.cc @@ -20,6 +20,7 @@ #include #include "src/tint/symbol_table.h" +#include "src/tint/type/manager.h" #include "src/tint/utils/hash.h" TINT_INSTANTIATE_TYPEINFO(tint::type::Struct); @@ -160,6 +161,16 @@ std::string Struct::Layout(const tint::SymbolTable& symbols) const { return ss.str(); } +Struct* Struct::Clone(CloneContext& ctx) const { + auto sym = ctx.dst.st->Register(ctx.src.st->NameFor(name_)); + + utils::Vector members; + for (const auto& mem : members_) { + members.Push(mem->Clone(ctx)); + } + return ctx.dst.mgr->Get(source_, sym, members, align_, size_, size_no_padding_); +} + StructMember::StructMember(tint::Source source, Symbol name, const type::Type* type, @@ -179,4 +190,11 @@ StructMember::StructMember(tint::Source source, StructMember::~StructMember() = default; +StructMember* StructMember::Clone(CloneContext& ctx) const { + auto sym = ctx.dst.st->Register(ctx.src.st->NameFor(name_)); + auto* ty = type_->Clone(ctx); + return ctx.dst.mgr->Get(source_, sym, ty, index_, offset_, align_, size_, + location_); +} + } // namespace tint::type diff --git a/src/tint/type/struct.h b/src/tint/type/struct.h index ff23a89e2b..cd545e5798 100644 --- a/src/tint/type/struct.h +++ b/src/tint/type/struct.h @@ -149,6 +149,10 @@ class Struct : public Castable { /// @note only structures returned by builtins may be abstract (e.g. modf, frexp) utils::VectorRef ConcreteTypes() const { return concrete_types_; } + /// @param ctx the clone context + /// @returns a clone of this type + Struct* Clone(CloneContext& ctx) const override; + private: const tint::Source source_; const Symbol name_; @@ -216,6 +220,10 @@ class StructMember : public Castable { /// @returns the location, if set std::optional Location() const { return location_; } + /// @param ctx the clone context + /// @returns a clone of this struct member + StructMember* Clone(CloneContext& ctx) const; + private: const tint::Source source_; const Symbol name_; diff --git a/src/tint/type/struct_test.cc b/src/tint/type/struct_test.cc index 8bacfca9f2..ff72d0b7e6 100644 --- a/src/tint/type/struct_test.cc +++ b/src/tint/type/struct_test.cc @@ -206,5 +206,47 @@ TEST_F(TypeStructTest, HasFixedFootprint) { EXPECT_FALSE(sem_outer_with_runtime_sized_array->HasFixedFootprint()); } +TEST_F(TypeStructTest, Clone) { + auto* s = create( + Source{}, Sym("my_struct"), + utils::Vector{create(Source{}, Sym("b"), create(create(), 3u), + 0u, 0u, 16u, 12u, std::optional{2}), + create(Source{}, Sym("a"), create(), 1u, 16u, 4u, 4u, + std::optional())}, + 4u /* align */, 8u /* size */, 16u /* size_no_padding */); + + ProgramID id; + SymbolTable new_st{id}; + + type::Manager mgr; + type::CloneContext ctx{{&Symbols()}, {&new_st, &mgr}}; + + auto* st = s->Clone(ctx); + + EXPECT_TRUE(new_st.Get("my_struct").IsValid()); + EXPECT_EQ(new_st.NameFor(st->Name()), "my_struct"); + + EXPECT_EQ(st->Align(), 4u); + EXPECT_EQ(st->Size(), 8u); + EXPECT_EQ(st->SizeNoPadding(), 16u); + + auto members = st->Members(); + ASSERT_EQ(members.Length(), 2u); + + EXPECT_EQ(new_st.NameFor(members[0]->Name()), "b"); + EXPECT_TRUE(members[0]->Type()->Is()); + EXPECT_EQ(members[0]->Index(), 0u); + EXPECT_EQ(members[0]->Offset(), 0u); + EXPECT_EQ(members[0]->Align(), 16u); + EXPECT_EQ(members[0]->Size(), 12u); + + EXPECT_EQ(new_st.NameFor(members[1]->Name()), "a"); + EXPECT_TRUE(members[1]->Type()->Is()); + EXPECT_EQ(members[1]->Index(), 1u); + EXPECT_EQ(members[1]->Offset(), 16u); + EXPECT_EQ(members[1]->Align(), 4u); + EXPECT_EQ(members[1]->Size(), 4u); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/type.h b/src/tint/type/type.h index ccd0fe5b91..a02c9ac90b 100644 --- a/src/tint/type/type.h +++ b/src/tint/type/type.h @@ -18,6 +18,7 @@ #include #include +#include "src/tint/type/clone_context.h" #include "src/tint/type/unique_node.h" #include "src/tint/utils/enum_set.h" #include "src/tint/utils/vector.h" @@ -72,6 +73,10 @@ class Type : public Castable { /// @note opaque types will return a size of 0. virtual uint32_t Align() const; + /// @param ctx the clone context + /// @returns a clone of this type created in the provided context + virtual Type* Clone(CloneContext& ctx) const = 0; + /// @returns the flags on the type type::Flags Flags() { return flags_; } diff --git a/src/tint/type/u32.cc b/src/tint/type/u32.cc index 34ae02763b..a749f85349 100644 --- a/src/tint/type/u32.cc +++ b/src/tint/type/u32.cc @@ -46,4 +46,8 @@ uint32_t U32::Align() const { return 4; } +U32* U32::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/u32.h b/src/tint/type/u32.h index 222a387463..8d796423f9 100644 --- a/src/tint/type/u32.h +++ b/src/tint/type/u32.h @@ -44,6 +44,10 @@ class U32 final : public Castable { /// @returns the alignment in bytes of the type. uint32_t Align() const override; + + /// @param ctx the clone context + /// @returns a clone of this type + U32* Clone(CloneContext& ctx) const override; }; } // namespace tint::type diff --git a/src/tint/type/u32_test.cc b/src/tint/type/u32_test.cc index 5ec5502298..8f17e62bfe 100644 --- a/src/tint/type/u32_test.cc +++ b/src/tint/type/u32_test.cc @@ -44,5 +44,15 @@ TEST_F(U32Test, FriendlyName) { EXPECT_EQ(u.FriendlyName(Symbols()), "u32"); } +TEST_F(U32Test, Clone) { + auto* a = create(); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* b = a->Clone(ctx); + ASSERT_TRUE(b->Is()); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/vector.cc b/src/tint/type/vector.cc index a1f964e819..acd952c196 100644 --- a/src/tint/type/vector.cc +++ b/src/tint/type/vector.cc @@ -65,4 +65,9 @@ uint32_t Vector::Align() const { return 0; // Unreachable } +Vector* Vector::Clone(CloneContext& ctx) const { + auto* subtype = subtype_->Clone(ctx); + return ctx.dst.mgr->Get(subtype, width_); +} + } // namespace tint::type diff --git a/src/tint/type/vector.h b/src/tint/type/vector.h index 86f6f95613..acffb8c6b8 100644 --- a/src/tint/type/vector.h +++ b/src/tint/type/vector.h @@ -62,6 +62,10 @@ class Vector final : public Castable { /// @returns the alignment in bytes of a vector of the given width. static uint32_t AlignOf(uint32_t width); + /// @param ctx the clone context + /// @returns a clone of this type + Vector* Clone(CloneContext& ctx) const override; + private: Type const* const subtype_; const uint32_t width_; diff --git a/src/tint/type/vector_test.cc b/src/tint/type/vector_test.cc index 2bd144e74f..7dd5c9d592 100644 --- a/src/tint/type/vector_test.cc +++ b/src/tint/type/vector_test.cc @@ -59,5 +59,16 @@ TEST_F(VectorTest, FriendlyName) { EXPECT_EQ(v->FriendlyName(Symbols()), "vec3"); } +TEST_F(VectorTest, Clone) { + auto* a = create(create(), 2u); + + type::Manager mgr; + type::CloneContext ctx{{nullptr}, {nullptr, &mgr}}; + + auto* vec = a->Clone(ctx); + EXPECT_TRUE(vec->type()->Is()); + EXPECT_EQ(vec->Width(), 2u); +} + } // namespace } // namespace tint::type diff --git a/src/tint/type/void.cc b/src/tint/type/void.cc index 352260719e..e29def139f 100644 --- a/src/tint/type/void.cc +++ b/src/tint/type/void.cc @@ -32,4 +32,8 @@ std::string Void::FriendlyName(const SymbolTable&) const { return "void"; } +Void* Void::Clone(CloneContext& ctx) const { + return ctx.dst.mgr->Get(); +} + } // namespace tint::type diff --git a/src/tint/type/void.h b/src/tint/type/void.h index 801a671ee3..02b2eee710 100644 --- a/src/tint/type/void.h +++ b/src/tint/type/void.h @@ -38,6 +38,10 @@ class Void final : public Castable { /// @returns the name for this type that closely resembles how it would be /// declared in WGSL. std::string FriendlyName(const SymbolTable& symbols) const override; + + /// @param ctx the clone context + /// @returns a clone of this type + Void* Clone(CloneContext& ctx) const override; }; } // namespace tint::type