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:
parent
128980f218
commit
529c3fd385
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {}; }
|
||||||
|
|
Loading…
Reference in New Issue