Add clone into constant/

This Cl adds the ability to clone a constant into a context provided.
This allows the IR to clone the constants out of the Program and into
the IR.

Bug: tint:1718
Change-Id: I78170cdc66b5824a1ab81000976a747b5bffee79
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116363
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
dan sinclair 2023-01-06 02:57:36 +00:00 committed by Dawn LUCI CQ
parent 128980f218
commit 529c3fd385
16 changed files with 624 additions and 5 deletions

View File

@ -366,6 +366,7 @@ libtint_source_set("libtint_core_all_src") {
"castable.h", "castable.h",
"clone_context.cc", "clone_context.cc",
"clone_context.h", "clone_context.h",
"constant/clone_context.h",
"constant/composite.h", "constant/composite.h",
"constant/node.h", "constant/node.h",
"constant/scalar.h", "constant/scalar.h",
@ -770,6 +771,7 @@ libtint_source_set("libtint_type_src") {
libtint_source_set("libtint_constant_src") { libtint_source_set("libtint_constant_src") {
sources = [ sources = [
"constant/clone_context.h",
"constant/composite.cc", "constant/composite.cc",
"constant/composite.h", "constant/composite.h",
"constant/node.cc", "constant/node.cc",
@ -1242,6 +1244,14 @@ if (tint_build_unittests) {
] ]
} }
tint_unittests_source_set("tint_unittests_constant_src") {
sources = [
"constant/composite_test.cc",
"constant/scalar_test.cc",
"constant/splat_test.cc",
]
}
tint_unittests_source_set("tint_unittests_type_src") { tint_unittests_source_set("tint_unittests_type_src") {
sources = [ sources = [
"type/array_test.cc", "type/array_test.cc",
@ -1738,6 +1748,7 @@ if (tint_build_unittests) {
":libtint_wgsl_reader_src", ":libtint_wgsl_reader_src",
":libtint_wgsl_writer_src", ":libtint_wgsl_writer_src",
":tint_unittests_ast_src", ":tint_unittests_ast_src",
":tint_unittests_constant_src",
":tint_unittests_core_src", ":tint_unittests_core_src",
":tint_unittests_diagnostic_src", ":tint_unittests_diagnostic_src",
":tint_unittests_inspector_src", ":tint_unittests_inspector_src",

View File

@ -254,6 +254,7 @@ list(APPEND TINT_LIB_SRCS
castable.h castable.h
clone_context.cc clone_context.cc
clone_context.h clone_context.h
constant/clone_context.h
constant/composite.cc constant/composite.cc
constant/composite.h constant/composite.h
constant/scalar.cc constant/scalar.cc
@ -873,6 +874,9 @@ if(TINT_BUILD_TESTS)
ast/workgroup_attribute_test.cc ast/workgroup_attribute_test.cc
castable_test.cc castable_test.cc
clone_context_test.cc clone_context_test.cc
constant/composite_test.cc
constant/scalar_test.cc
constant/splat_test.cc
debug_test.cc debug_test.cc
demangler_test.cc demangler_test.cc
diagnostic/diagnostic_test.cc diagnostic/diagnostic_test.cc

View File

@ -0,0 +1,42 @@
// 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_CONSTANT_CLONE_CONTEXT_H_
#define SRC_TINT_CONSTANT_CLONE_CONTEXT_H_
#include "src/tint/type/clone_context.h"
#include "src/tint/utils/block_allocator.h"
// Forward Declarations
namespace tint::constant {
class Value;
} // namespace tint::constant
namespace tint::constant {
/// Context information for cloning of constants
struct CloneContext {
/// The context for cloning type information
type::CloneContext type_ctx;
/// Destination information
struct {
/// The constant allocator
utils::BlockAllocator<constant::Value>* constants;
} dst;
};
} // namespace tint::constant
#endif // SRC_TINT_CONSTANT_CLONE_CONTEXT_H_

View File

@ -28,4 +28,13 @@ Composite::Composite(const type::Type* t,
Composite::~Composite() = default; Composite::~Composite() = default;
Composite* Composite::Clone(CloneContext& ctx) const {
auto* ty = type->Clone(ctx.type_ctx);
utils::Vector<const constant::Value*, 4> els;
for (const auto* el : elements) {
els.Push(el->Clone(ctx));
}
return ctx.dst.constants->Create<Composite>(ty, els, all_zero, any_zero);
}
} // namespace tint::constant } // namespace tint::constant

View File

@ -52,6 +52,11 @@ class Composite : public Castable<Composite, constant::Value> {
bool AllEqual() const override { return false; } bool AllEqual() const override { return false; }
size_t Hash() const override { return hash; } size_t Hash() const override { return hash; }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
Composite* Clone(CloneContext& ctx) const override;
/// The composite type /// The composite type
type::Type const* const type; type::Type const* const type;
/// The composite elements /// The composite elements

View File

@ -0,0 +1,112 @@
// 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.
#include "src/tint/constant/composite.h"
#include "src/tint/constant/scalar.h"
#include "src/tint/constant/test_helper.h"
namespace tint::constant {
namespace {
using namespace tint::number_suffixes; // NOLINT
using ConstantTest_Composite = TestHelper;
TEST_F(ConstantTest_Composite, AllZero) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* compositeAll = create<Composite>(f32, utils::Vector{fPos0, fPos0});
auto* compositeAny = create<Composite>(f32, utils::Vector{fNeg0, fPos1, fPos0});
auto* compositeNone = create<Composite>(f32, utils::Vector{fNeg0, fNeg0});
EXPECT_TRUE(compositeAll->AllZero());
EXPECT_FALSE(compositeAny->AllZero());
EXPECT_FALSE(compositeNone->AllZero());
}
TEST_F(ConstantTest_Composite, AnyZero) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* compositeAll = create<Composite>(f32, utils::Vector{fPos0, fPos0});
auto* compositeAny = create<Composite>(f32, utils::Vector{fNeg0, fPos1, fPos0});
auto* compositeNone = create<Composite>(f32, utils::Vector{fNeg0, fNeg0});
EXPECT_TRUE(compositeAll->AnyZero());
EXPECT_TRUE(compositeAny->AnyZero());
EXPECT_FALSE(compositeNone->AnyZero());
}
TEST_F(ConstantTest_Composite, AllEqual) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* compositeEq = create<Composite>(f32, utils::Vector{fPos0, fPos0});
auto* compositeNe = create<Composite>(f32, utils::Vector{fNeg0, fPos1, fPos0});
EXPECT_TRUE(compositeEq->AllEqual());
EXPECT_FALSE(compositeNe->AllZero());
}
TEST_F(ConstantTest_Composite, Index) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* composite = create<Composite>(f32, utils::Vector{fPos1, fPos0});
ASSERT_NE(composite->Index(0), nullptr);
ASSERT_NE(composite->Index(1), nullptr);
ASSERT_EQ(composite->Index(2), nullptr);
EXPECT_TRUE(composite->Index(0)->Is<Scalar<tint::f32>>());
EXPECT_EQ(composite->Index(0)->As<Scalar<tint::f32>>()->ValueOf(), 1.0);
EXPECT_TRUE(composite->Index(1)->Is<Scalar<tint::f32>>());
EXPECT_EQ(composite->Index(1)->As<Scalar<tint::f32>>()->ValueOf(), 0.0);
}
TEST_F(ConstantTest_Composite, Clone) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* composite = create<Composite>(f32, utils::Vector{fPos1, fPos0});
type::Manager mgr;
utils::BlockAllocator<constant::Value> consts;
constant::CloneContext ctx{type::CloneContext{{nullptr}, {nullptr, &mgr}}, {&consts}};
auto* r = composite->As<Composite>()->Clone(ctx);
ASSERT_NE(r, nullptr);
EXPECT_TRUE(r->type->Is<type::F32>());
EXPECT_FALSE(r->all_zero);
EXPECT_TRUE(r->any_zero);
ASSERT_EQ(r->elements.Length(), 2u);
}
} // namespace
} // namespace tint::constant

View File

@ -49,6 +49,14 @@ class Scalar : public Castable<Scalar<T>, constant::Value> {
bool AllEqual() const override { return true; } bool AllEqual() const override { return true; }
size_t Hash() const override { return utils::Hash(type, ValueOf()); } size_t Hash() const override { return utils::Hash(type, ValueOf()); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
Scalar* Clone(CloneContext& ctx) const override {
auto* ty = type->Clone(ctx.type_ctx);
return ctx.dst.constants->Create<Scalar<T>>(ty, value);
}
/// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the /// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the
/// Number. /// Number.
inline auto ValueOf() const { inline auto ValueOf() const {

View File

@ -0,0 +1,265 @@
// 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.
#include "src/tint/constant/scalar.h"
#include "src/tint/constant/test_helper.h"
namespace tint::constant {
namespace {
using namespace tint::number_suffixes; // NOLINT
using ConstantTest_Scalar = TestHelper;
TEST_F(ConstantTest_Scalar, AllZero) {
auto* i32 = create<type::I32>();
auto* u32 = create<type::U32>();
auto* f16 = create<type::F16>();
auto* f32 = create<type::F32>();
auto* bool_ = create<type::Bool>();
auto* i0 = create<Scalar<tint::i32>>(i32, 0_i);
auto* iPos1 = create<Scalar<tint::i32>>(i32, 1_i);
auto* iNeg1 = create<Scalar<tint::i32>>(i32, -1_i);
auto* u0 = create<Scalar<tint::u32>>(u32, 0_u);
auto* u1 = create<Scalar<tint::u32>>(u32, 1_u);
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* fNeg1 = create<Scalar<tint::f32>>(f32, -1_f);
auto* f16Pos0 = create<Scalar<tint::f16>>(f16, 0_h);
auto* f16Neg0 = create<Scalar<tint::f16>>(f16, -0_h);
auto* f16Pos1 = create<Scalar<tint::f16>>(f16, 1_h);
auto* f16Neg1 = create<Scalar<tint::f16>>(f16, -1_h);
auto* bf = create<Scalar<bool>>(bool_, false);
auto* bt = create<Scalar<bool>>(bool_, true);
auto* afPos0 = create<Scalar<tint::AFloat>>(f32, 0.0_a);
auto* afNeg0 = create<Scalar<tint::AFloat>>(f32, -0.0_a);
auto* afPos1 = create<Scalar<tint::AFloat>>(f32, 1.0_a);
auto* afNeg1 = create<Scalar<tint::AFloat>>(f32, -1.0_a);
auto* ai0 = create<Scalar<tint::AInt>>(i32, 0_a);
auto* aiPos1 = create<Scalar<tint::AInt>>(i32, 1_a);
auto* aiNeg1 = create<Scalar<tint::AInt>>(i32, -1_a);
EXPECT_TRUE(i0->AllZero());
EXPECT_FALSE(iPos1->AllZero());
EXPECT_FALSE(iNeg1->AllZero());
EXPECT_TRUE(u0->AllZero());
EXPECT_FALSE(u1->AllZero());
EXPECT_TRUE(fPos0->AllZero());
EXPECT_FALSE(fNeg0->AllZero());
EXPECT_FALSE(fPos1->AllZero());
EXPECT_FALSE(fNeg1->AllZero());
EXPECT_TRUE(f16Pos0->AllZero());
EXPECT_FALSE(f16Neg0->AllZero());
EXPECT_FALSE(f16Pos1->AllZero());
EXPECT_FALSE(f16Neg1->AllZero());
EXPECT_TRUE(bf->AllZero());
EXPECT_FALSE(bt->AllZero());
EXPECT_TRUE(afPos0->AllZero());
EXPECT_FALSE(afNeg0->AllZero());
EXPECT_FALSE(afPos1->AllZero());
EXPECT_FALSE(afNeg1->AllZero());
EXPECT_TRUE(ai0->AllZero());
EXPECT_FALSE(aiPos1->AllZero());
EXPECT_FALSE(aiNeg1->AllZero());
}
TEST_F(ConstantTest_Scalar, AnyZero) {
auto* i32 = create<type::I32>();
auto* u32 = create<type::U32>();
auto* f16 = create<type::F16>();
auto* f32 = create<type::F32>();
auto* bool_ = create<type::Bool>();
auto* i0 = create<Scalar<tint::i32>>(i32, 0_i);
auto* iPos1 = create<Scalar<tint::i32>>(i32, 1_i);
auto* iNeg1 = create<Scalar<tint::i32>>(i32, -1_i);
auto* u0 = create<Scalar<tint::u32>>(u32, 0_u);
auto* u1 = create<Scalar<tint::u32>>(u32, 1_u);
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* fNeg1 = create<Scalar<tint::f32>>(f32, -1_f);
auto* f16Pos0 = create<Scalar<tint::f16>>(f16, 0_h);
auto* f16Neg0 = create<Scalar<tint::f16>>(f16, -0_h);
auto* f16Pos1 = create<Scalar<tint::f16>>(f16, 1_h);
auto* f16Neg1 = create<Scalar<tint::f16>>(f16, -1_h);
auto* bf = create<Scalar<bool>>(bool_, false);
auto* bt = create<Scalar<bool>>(bool_, true);
auto* afPos0 = create<Scalar<tint::AFloat>>(f32, 0.0_a);
auto* afNeg0 = create<Scalar<tint::AFloat>>(f32, -0.0_a);
auto* afPos1 = create<Scalar<tint::AFloat>>(f32, 1.0_a);
auto* afNeg1 = create<Scalar<tint::AFloat>>(f32, -1.0_a);
auto* ai0 = create<Scalar<tint::AInt>>(i32, 0_a);
auto* aiPos1 = create<Scalar<tint::AInt>>(i32, 1_a);
auto* aiNeg1 = create<Scalar<tint::AInt>>(i32, -1_a);
EXPECT_TRUE(i0->AnyZero());
EXPECT_FALSE(iPos1->AnyZero());
EXPECT_FALSE(iNeg1->AnyZero());
EXPECT_TRUE(u0->AnyZero());
EXPECT_FALSE(u1->AnyZero());
EXPECT_TRUE(fPos0->AnyZero());
EXPECT_FALSE(fNeg0->AnyZero());
EXPECT_FALSE(fPos1->AnyZero());
EXPECT_FALSE(fNeg1->AnyZero());
EXPECT_TRUE(f16Pos0->AnyZero());
EXPECT_FALSE(f16Neg0->AnyZero());
EXPECT_FALSE(f16Pos1->AnyZero());
EXPECT_FALSE(f16Neg1->AnyZero());
EXPECT_TRUE(bf->AnyZero());
EXPECT_FALSE(bt->AnyZero());
EXPECT_TRUE(afPos0->AnyZero());
EXPECT_FALSE(afNeg0->AnyZero());
EXPECT_FALSE(afPos1->AnyZero());
EXPECT_FALSE(afNeg1->AnyZero());
EXPECT_TRUE(ai0->AnyZero());
EXPECT_FALSE(aiPos1->AnyZero());
EXPECT_FALSE(aiNeg1->AnyZero());
}
TEST_F(ConstantTest_Scalar, AllEqual) {
auto* i32 = create<type::I32>();
auto* u32 = create<type::U32>();
auto* f16 = create<type::F16>();
auto* f32 = create<type::F32>();
auto* bool_ = create<type::Bool>();
auto* i0 = create<Scalar<tint::i32>>(i32, 0_i);
auto* iPos1 = create<Scalar<tint::i32>>(i32, 1_i);
auto* iNeg1 = create<Scalar<tint::i32>>(i32, -1_i);
auto* u0 = create<Scalar<tint::u32>>(u32, 0_u);
auto* u1 = create<Scalar<tint::u32>>(u32, 1_u);
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* fNeg1 = create<Scalar<tint::f32>>(f32, -1_f);
auto* f16Pos0 = create<Scalar<tint::f16>>(f16, 0_h);
auto* f16Neg0 = create<Scalar<tint::f16>>(f16, -0_h);
auto* f16Pos1 = create<Scalar<tint::f16>>(f16, 1_h);
auto* f16Neg1 = create<Scalar<tint::f16>>(f16, -1_h);
auto* bf = create<Scalar<bool>>(bool_, false);
auto* bt = create<Scalar<bool>>(bool_, true);
auto* afPos0 = create<Scalar<tint::AFloat>>(f32, 0.0_a);
auto* afNeg0 = create<Scalar<tint::AFloat>>(f32, -0.0_a);
auto* afPos1 = create<Scalar<tint::AFloat>>(f32, 1.0_a);
auto* afNeg1 = create<Scalar<tint::AFloat>>(f32, -1.0_a);
auto* ai0 = create<Scalar<tint::AInt>>(i32, 0_a);
auto* aiPos1 = create<Scalar<tint::AInt>>(i32, 1_a);
auto* aiNeg1 = create<Scalar<tint::AInt>>(i32, -1_a);
EXPECT_TRUE(i0->AllEqual());
EXPECT_TRUE(iPos1->AllEqual());
EXPECT_TRUE(iNeg1->AllEqual());
EXPECT_TRUE(u0->AllEqual());
EXPECT_TRUE(u1->AllEqual());
EXPECT_TRUE(fPos0->AllEqual());
EXPECT_TRUE(fNeg0->AllEqual());
EXPECT_TRUE(fPos1->AllEqual());
EXPECT_TRUE(fNeg1->AllEqual());
EXPECT_TRUE(f16Pos0->AllEqual());
EXPECT_TRUE(f16Neg0->AllEqual());
EXPECT_TRUE(f16Pos1->AllEqual());
EXPECT_TRUE(f16Neg1->AllEqual());
EXPECT_TRUE(bf->AllEqual());
EXPECT_TRUE(bt->AllEqual());
EXPECT_TRUE(afPos0->AllEqual());
EXPECT_TRUE(afNeg0->AllEqual());
EXPECT_TRUE(afPos1->AllEqual());
EXPECT_TRUE(afNeg1->AllEqual());
EXPECT_TRUE(ai0->AllEqual());
EXPECT_TRUE(aiPos1->AllEqual());
EXPECT_TRUE(aiNeg1->AllEqual());
}
TEST_F(ConstantTest_Scalar, ValueOf) {
auto* i32 = create<type::I32>();
auto* u32 = create<type::U32>();
auto* f16 = create<type::F16>();
auto* f32 = create<type::F32>();
auto* bool_ = create<type::Bool>();
auto* i1 = create<Scalar<tint::i32>>(i32, 1_i);
auto* u1 = create<Scalar<tint::u32>>(u32, 1_u);
auto* f1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* f16Pos1 = create<Scalar<tint::f16>>(f16, 1_h);
auto* bf = create<Scalar<bool>>(bool_, false);
auto* bt = create<Scalar<bool>>(bool_, true);
auto* af1 = create<Scalar<tint::AFloat>>(f32, 1.0_a);
auto* ai1 = create<Scalar<tint::AInt>>(i32, 1_a);
EXPECT_EQ(i1->ValueOf(), 1);
EXPECT_EQ(u1->ValueOf(), 1u);
EXPECT_EQ(f1->ValueOf(), 1.f);
EXPECT_EQ(f16Pos1->ValueOf(), 1.f);
EXPECT_FALSE(bf->ValueOf());
EXPECT_TRUE(bt->ValueOf());
EXPECT_EQ(af1->ValueOf(), 1.0);
EXPECT_EQ(ai1->ValueOf(), 1l);
}
TEST_F(ConstantTest_Scalar, Clone) {
auto* i32 = create<type::I32>();
auto* val = create<Scalar<tint::i32>>(i32, 12_i);
type::Manager mgr;
utils::BlockAllocator<constant::Value> consts;
constant::CloneContext ctx{type::CloneContext{{nullptr}, {nullptr, &mgr}}, {&consts}};
auto* r = val->Clone(ctx);
ASSERT_NE(r, nullptr);
EXPECT_TRUE(r->type->Is<type::I32>());
EXPECT_EQ(r->value, 12);
}
} // namespace
} // namespace tint::constant

View File

@ -22,4 +22,10 @@ Splat::Splat(const type::Type* t, const constant::Value* e, size_t n) : type(t),
Splat::~Splat() = default; Splat::~Splat() = default;
Splat* Splat::Clone(CloneContext& ctx) const {
auto* ty = type->Clone(ctx.type_ctx);
auto* element = el->Clone(ctx);
return ctx.dst.constants->Create<Splat>(ty, element, count);
}
} // namespace tint::constant } // namespace tint::constant

View File

@ -53,6 +53,11 @@ class Splat : public Castable<Splat, constant::Value> {
/// @returns the hash for the splat /// @returns the hash for the splat
size_t Hash() const override { return utils::Hash(type, el->Hash(), count); } size_t Hash() const override { return utils::Hash(type, el->Hash(), count); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
Splat* Clone(CloneContext& ctx) const override;
/// The type of the splat element /// The type of the splat element
type::Type const* const type; type::Type const* const type;
/// The element stored in the splat /// The element stored in the splat

View File

@ -0,0 +1,106 @@
// 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.
#include "src/tint/constant/splat.h"
#include "src/tint/constant/scalar.h"
#include "src/tint/constant/test_helper.h"
namespace tint::constant {
namespace {
using namespace tint::number_suffixes; // NOLINT
using ConstantTest_Splat = TestHelper;
TEST_F(ConstantTest_Splat, AllZero) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* SpfPos0 = create<Splat>(f32, fPos0, 2);
auto* SpfNeg0 = create<Splat>(f32, fNeg0, 2);
auto* SpfPos1 = create<Splat>(f32, fPos1, 2);
EXPECT_TRUE(SpfPos0->AllZero());
EXPECT_FALSE(SpfNeg0->AllZero());
EXPECT_FALSE(SpfPos1->AllZero());
}
TEST_F(ConstantTest_Splat, AnyZero) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* SpfPos0 = create<Splat>(f32, fPos0, 2);
auto* SpfNeg0 = create<Splat>(f32, fNeg0, 2);
auto* SpfPos1 = create<Splat>(f32, fPos1, 2);
EXPECT_TRUE(SpfPos0->AnyZero());
EXPECT_FALSE(SpfNeg0->AnyZero());
EXPECT_FALSE(SpfPos1->AnyZero());
}
TEST_F(ConstantTest_Splat, AllEqual) {
auto* f32 = create<type::F32>();
auto* fPos0 = create<Scalar<tint::f32>>(f32, 0_f);
auto* fNeg0 = create<Scalar<tint::f32>>(f32, -0_f);
auto* fPos1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* SpfPos0 = create<Splat>(f32, fPos0, 2);
auto* SpfNeg0 = create<Splat>(f32, fNeg0, 2);
auto* SpfPos1 = create<Splat>(f32, fPos1, 2);
EXPECT_TRUE(SpfPos0->AllEqual());
EXPECT_TRUE(SpfNeg0->AllEqual());
EXPECT_TRUE(SpfPos1->AllEqual());
}
TEST_F(ConstantTest_Splat, Index) {
auto* f32 = create<type::F32>();
auto* f1 = create<Scalar<tint::f32>>(f32, 1_f);
auto* sp = create<Splat>(f32, f1, 2);
ASSERT_NE(sp->Index(0), nullptr);
ASSERT_NE(sp->Index(1), nullptr);
ASSERT_EQ(sp->Index(2), nullptr);
EXPECT_EQ(sp->Index(0)->As<Scalar<tint::f32>>()->ValueOf(), 1.f);
EXPECT_EQ(sp->Index(1)->As<Scalar<tint::f32>>()->ValueOf(), 1.f);
}
TEST_F(ConstantTest_Splat, Clone) {
auto* i32 = create<type::I32>();
auto* val = create<Scalar<tint::i32>>(i32, 12_i);
auto* sp = create<Splat>(i32, val, 2);
type::Manager mgr;
utils::BlockAllocator<constant::Value> consts;
constant::CloneContext ctx{type::CloneContext{{nullptr}, {nullptr, &mgr}}, {&consts}};
auto* r = sp->Clone(ctx);
ASSERT_NE(r, nullptr);
EXPECT_TRUE(r->type->Is<type::I32>());
EXPECT_TRUE(r->el->Is<Scalar<tint::i32>>());
EXPECT_EQ(r->count, 2u);
}
} // namespace
} // namespace tint::constant

View File

@ -0,0 +1,36 @@
// 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_CONSTANT_TEST_HELPER_H_
#define SRC_TINT_CONSTANT_TEST_HELPER_H_
#include "gtest/gtest.h"
#include "src/tint/program_builder.h"
namespace tint::constant {
/// Helper base class for testing
template <typename BASE>
class TestHelperBase : public BASE, public ProgramBuilder {};
/// Helper class for testing that derives from testing::Test.
using TestHelper = TestHelperBase<testing::Test>;
/// Helper class for testing that derives from `T`.
template <typename T>
using TestParamHelper = TestHelperBase<testing::TestWithParam<T>>;
} // namespace tint::constant
#endif // SRC_TINT_CONSTANT_TEST_HELPER_H_

View File

@ -18,6 +18,7 @@
#include <variant> #include <variant>
#include "src/tint/castable.h" #include "src/tint/castable.h"
#include "src/tint/constant/clone_context.h"
#include "src/tint/constant/node.h" #include "src/tint/constant/node.h"
#include "src/tint/number.h" #include "src/tint/number.h"
#include "src/tint/type/type.h" #include "src/tint/type/type.h"
@ -75,6 +76,11 @@ class Value : public Castable<Value, Node> {
/// @returns true if this value is equal to @p b /// @returns true if this value is equal to @p b
bool Equal(const constant::Value* b) const; bool Equal(const constant::Value* b) const;
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
virtual Value* Clone(CloneContext& ctx) const = 0;
protected: protected:
/// @returns the value, if this is of a scalar value or abstract numeric, otherwise /// @returns the value, if this is of a scalar value or abstract numeric, otherwise
/// std::monostate. /// std::monostate.

View File

@ -85,7 +85,9 @@ bool IsConnected(const FlowNode* b) {
BuilderImpl::BuilderImpl(const Program* program) BuilderImpl::BuilderImpl(const Program* program)
: builder(program), : builder(program),
type_clone_ctx_{{&program->Symbols()}, {&builder.ir.symbols, &builder.ir.types}} {} clone_ctx_{
type::CloneContext{{&program->Symbols()}, {&builder.ir.symbols, &builder.ir.types}},
{&builder.ir.constants}} {}
BuilderImpl::~BuilderImpl() = default; BuilderImpl::~BuilderImpl() = default;
@ -567,7 +569,7 @@ utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr)
} }
auto* sem = builder.ir.program->Sem().Get(expr); auto* sem = builder.ir.program->Sem().Get(expr);
auto* ty = sem->Type()->Clone(type_clone_ctx_); auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
Binary* instr = nullptr; Binary* instr = nullptr;
switch (expr->op) { switch (expr->op) {
@ -641,7 +643,7 @@ utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* exp
} }
auto* sem = builder.ir.program->Sem().Get(expr); auto* sem = builder.ir.program->Sem().Get(expr);
auto* ty = sem->Type()->Clone(type_clone_ctx_); auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
auto* instr = builder.Bitcast(ty, val.Get()); auto* instr = builder.Bitcast(ty, val.Get());
current_flow_block->instructions.Push(instr); current_flow_block->instructions.Push(instr);
@ -658,7 +660,7 @@ utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit
return utils::Failure; return utils::Failure;
} }
auto* cv = sem->ConstantValue(); auto* cv = sem->ConstantValue()->Clone(clone_ctx_);
if (!cv) { if (!cv) {
diagnostics_.add_error( diagnostics_.add_error(
tint::diag::System::IR, tint::diag::System::IR,

View File

@ -19,6 +19,7 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "src/tint/constant/clone_context.h"
#include "src/tint/diagnostic/diagnostic.h" #include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/ir/builder.h" #include "src/tint/ir/builder.h"
#include "src/tint/ir/flow_node.h" #include "src/tint/ir/flow_node.h"
@ -213,7 +214,7 @@ class BuilderImpl {
/// Used for testing purposes. /// Used for testing purposes.
std::unordered_map<const ast::Node*, const FlowNode*> ast_to_flow_; std::unordered_map<const ast::Node*, const FlowNode*> ast_to_flow_;
type::CloneContext type_clone_ctx_; constant::CloneContext clone_ctx_;
}; };
} // namespace tint::ir } // namespace tint::ir

View File

@ -33,6 +33,7 @@ class MockConstant : public constant::Value {
bool AnyZero() const override { return {}; } bool AnyZero() const override { return {}; }
bool AllEqual() const override { return {}; } bool AllEqual() const override { return {}; }
size_t Hash() const override { return 0; } size_t Hash() const override { return 0; }
MockConstant* Clone(constant::CloneContext&) const override { return nullptr; }
protected: protected:
std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; } std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }