diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 5ac2ea9efe..af37a52a95 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -366,8 +366,11 @@ libtint_source_set("libtint_core_all_src") { "castable.h", "clone_context.cc", "clone_context.h", + "constant/composite.h", "constant/constant.h", "constant/node.h", + "constant/scalar.h", + "constant/splat.h", "debug.cc", "debug.h", "demangler.cc", @@ -762,10 +765,16 @@ libtint_source_set("libtint_type_src") { libtint_source_set("libtint_constant_src") { sources = [ + "constant/composite.cc", + "constant/composite.h", "constant/constant.cc", "constant/constant.h", "constant/node.cc", "constant/node.h", + "constant/scalar.cc", + "constant/scalar.h", + "constant/splat.cc", + "constant/splat.h", ] public_deps = [ ":libtint_core_all_src" ] } diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index d2f2a19872..e0248b75e2 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -254,8 +254,14 @@ list(APPEND TINT_LIB_SRCS castable.h clone_context.cc clone_context.h + constant/composite.cc + constant/composite.h constant/constant.cc constant/constant.h + constant/scalar.cc + constant/scalar.h + constant/splat.cc + constant/splat.h constant/node.cc constant/node.h demangler.cc diff --git a/src/tint/constant/composite.cc b/src/tint/constant/composite.cc new file mode 100644 index 0000000000..40bcc3c60c --- /dev/null +++ b/src/tint/constant/composite.cc @@ -0,0 +1,31 @@ +// Copyright 2022 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 + +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Composite); + +namespace tint::resolver { + +Composite::Composite(const type::Type* t, + utils::VectorRef els, + bool all_0, + bool any_0) + : type(t), elements(std::move(els)), all_zero(all_0), any_zero(any_0), hash(CalcHash()) {} + +Composite::~Composite() = default; + +} // namespace tint::resolver diff --git a/src/tint/constant/composite.h b/src/tint/constant/composite.h new file mode 100644 index 0000000000..5facc56c58 --- /dev/null +++ b/src/tint/constant/composite.h @@ -0,0 +1,80 @@ +// Copyright 2022 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_COMPOSITE_H_ +#define SRC_TINT_CONSTANT_COMPOSITE_H_ + +#include "src/tint/castable.h" +#include "src/tint/constant/constant.h" +#include "src/tint/number.h" +#include "src/tint/type/type.h" +#include "src/tint/utils/hash.h" +#include "src/tint/utils/vector.h" + +namespace tint::resolver { + +/// Composite holds a number of mixed child Constant values. +/// Composite may be of a vector, matrix or array type. +/// If each element is the same type and value, then a Splat would be a more efficient constant +/// implementation. Use CreateComposite() to create the appropriate Constant type. +/// Composite implements the Constant interface. +class Composite : public Castable { + public: + /// Constructor + /// @param t the compsite type + /// @param els the composite elements + /// @param all_0 true if all elements are 0 + /// @param any_0 true if any element is 0 + Composite(const type::Type* t, + utils::VectorRef els, + bool all_0, + bool any_0); + ~Composite() override; + + const type::Type* Type() const override { return type; } + + std::variant Value() const override { return {}; } + const constant::Constant* Index(size_t i) const override { + return i < elements.Length() ? elements[i] : nullptr; + } + + bool AllZero() const override { return all_zero; } + bool AnyZero() const override { return any_zero; } + bool AllEqual() const override { return false; } + size_t Hash() const override { return hash; } + + /// The composite type + type::Type const* const type; + /// The composite elements + const utils::Vector elements; + /// True if all elements are zero + const bool all_zero; + /// True if any element is zero + const bool any_zero; + /// The hash of the composite + const size_t hash; + + private: + size_t CalcHash() { + auto h = utils::Hash(type, all_zero, any_zero); + for (auto* el : elements) { + h = utils::HashCombine(h, el->Hash()); + } + return h; + } +}; + +} // namespace tint::resolver + +#endif // SRC_TINT_CONSTANT_COMPOSITE_H_ diff --git a/src/tint/constant/scalar.cc b/src/tint/constant/scalar.cc new file mode 100644 index 0000000000..2f7de7fc62 --- /dev/null +++ b/src/tint/constant/scalar.cc @@ -0,0 +1,23 @@ +// Copyright 2022 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" + +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); diff --git a/src/tint/constant/scalar.h b/src/tint/constant/scalar.h new file mode 100644 index 0000000000..b159563465 --- /dev/null +++ b/src/tint/constant/scalar.h @@ -0,0 +1,84 @@ +// Copyright 2022 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_SCALAR_H_ +#define SRC_TINT_CONSTANT_SCALAR_H_ + +#include "src/tint/castable.h" +#include "src/tint/constant/constant.h" +#include "src/tint/number.h" +#include "src/tint/type/type.h" +#include "src/tint/utils/hash.h" + +namespace tint::resolver { + +/// Scalar holds a single scalar or abstract-numeric value. +/// Scalar implements the Constant interface. +template +class Scalar : public Castable, constant::Constant> { + public: + static_assert(!std::is_same_v, T> || std::is_same_v, + "T must be a Number or bool"); + + /// Constructor + /// @param t the scalar type + /// @param v the scalar value + Scalar(const type::Type* t, T v) : type(t), value(v) { + if constexpr (IsFloatingPoint) { + TINT_ASSERT(Resolver, std::isfinite(v.value)); + } + } + ~Scalar() override = default; + + const type::Type* Type() const override { return type; } + + std::variant Value() const override { + if constexpr (IsFloatingPoint>) { + return static_cast(value); + } else { + return static_cast(value); + } + } + const constant::Constant* Index(size_t) const override { return nullptr; } + + bool AllZero() const override { return IsPositiveZero(); } + bool AnyZero() const override { return IsPositiveZero(); } + bool AllEqual() const override { return true; } + size_t Hash() const override { return utils::Hash(type, ValueOf()); } + + /// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the + /// Number. + inline auto ValueOf() const { + if constexpr (std::is_same_v, T>) { + return value; + } else { + return value.value; + } + } + + /// @returns true if `value` is a positive zero. + inline bool IsPositiveZero() const { + using N = UnwrapNumber; + return Number(value) == Number(0); // Considers sign bit + } + + /// The scalar type + type::Type const* const type; + /// The scalar value + const T value; +}; + +} // namespace tint::resolver + +#endif // SRC_TINT_CONSTANT_SCALAR_H_ diff --git a/src/tint/constant/splat.cc b/src/tint/constant/splat.cc new file mode 100644 index 0000000000..04ae2495db --- /dev/null +++ b/src/tint/constant/splat.cc @@ -0,0 +1,26 @@ +// Copyright 2022 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" + +TINT_INSTANTIATE_TYPEINFO(tint::resolver::Splat); + +namespace tint::resolver { + +Splat::Splat(const type::Type* t, const constant::Constant* e, size_t n) + : type(t), el(e), count(n) {} + +Splat::~Splat() = default; + +} // namespace tint::resolver diff --git a/src/tint/constant/splat.h b/src/tint/constant/splat.h new file mode 100644 index 0000000000..1b7c9993d5 --- /dev/null +++ b/src/tint/constant/splat.h @@ -0,0 +1,69 @@ +// Copyright 2022 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_SPLAT_H_ +#define SRC_TINT_CONSTANT_SPLAT_H_ + +#include "src/tint/castable.h" +#include "src/tint/constant/composite.h" +#include "src/tint/type/type.h" +#include "src/tint/utils/vector.h" + +namespace tint::resolver { + +/// Splat holds a single Constant value, duplicated as all children. +/// Splat is used for zero-initializers, 'splat' initializers, or initializers where each element is +/// identical. Splat may be of a vector, matrix or array type. +/// Splat implements the Constant interface. +class Splat : public Castable { + public: + /// Constructor + /// @param t the splat type + /// @param e the splat element + /// @param n the number of items in the splat + Splat(const type::Type* t, const constant::Constant* e, size_t n); + ~Splat() override; + + /// @returns the type of the splat + const type::Type* Type() const override { return type; } + + /// @returns a monostate variant. + std::variant Value() const override { return {}; } + + /// Retrieve item at index @p i + /// @param i the index to retrieve + /// @returns the element, or nullptr if out of bounds + const constant::Constant* Index(size_t i) const override { return i < count ? el : nullptr; } + + /// @returns true if the element is zero + bool AllZero() const override { return el->AllZero(); } + /// @returns true if the element is zero + bool AnyZero() const override { return el->AnyZero(); } + /// @returns true + bool AllEqual() const override { return true; } + + /// @returns the hash for the splat + size_t Hash() const override { return utils::Hash(type, el->Hash(), count); } + + /// The type of the splat element + type::Type const* const type; + /// The element stored in the splat + const constant::Constant* el; + /// The number of items in the splat + const size_t count; +}; + +} // namespace tint::resolver + +#endif // SRC_TINT_CONSTANT_SPLAT_H_ diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc index a035849928..295b00ae18 100644 --- a/src/tint/resolver/const_eval.cc +++ b/src/tint/resolver/const_eval.cc @@ -22,7 +22,10 @@ #include #include +#include "src/tint/constant/composite.h" #include "src/tint/constant/constant.h" +#include "src/tint/constant/scalar.h" +#include "src/tint/constant/splat.h" #include "src/tint/number.h" #include "src/tint/program_builder.h" #include "src/tint/sem/member_accessor_expression.h" @@ -237,115 +240,6 @@ const constant::Constant* CreateComposite(ProgramBuilder& builder, const type::Type* type, utils::VectorRef elements); -/// Scalar holds a single scalar or abstract-numeric value. -/// Scalar implements the Constant interface. -template -class Scalar : public Castable, constant::Constant> { - public: - static_assert(!std::is_same_v, T> || std::is_same_v, - "T must be a Number or bool"); - - Scalar(const type::Type* t, T v) : type(t), value(v) { - if constexpr (IsFloatingPoint) { - TINT_ASSERT(Resolver, std::isfinite(v.value)); - } - } - ~Scalar() override = default; - const type::Type* Type() const override { return type; } - std::variant Value() const override { - if constexpr (IsFloatingPoint>) { - return static_cast(value); - } else { - return static_cast(value); - } - } - const constant::Constant* Index(size_t) const override { return nullptr; } - - bool AllZero() const override { return IsPositiveZero(); } - bool AnyZero() const override { return IsPositiveZero(); } - - bool AllEqual() const override { return true; } - size_t Hash() const override { return utils::Hash(type, ValueOf()); } - - /// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the - /// Number. - inline auto ValueOf() const { - if constexpr (std::is_same_v, T>) { - return value; - } else { - return value.value; - } - } - - /// @returns true if `value` is a positive zero. - inline bool IsPositiveZero() const { - using N = UnwrapNumber; - return Number(value) == Number(0); // Considers sign bit - } - - type::Type const* const type; - const T value; -}; - -/// Splat holds a single Constant value, duplicated as all children. -/// Splat is used for zero-initializers, 'splat' initializers, or initializers where each element is -/// identical. Splat may be of a vector, matrix or array type. -/// Splat implements the Constant interface. -class Splat : public Castable { - public: - Splat(const type::Type* t, const constant::Constant* e, size_t n) : type(t), el(e), count(n) {} - ~Splat() override = default; - const type::Type* Type() const override { return type; } - std::variant Value() const override { return {}; } - const constant::Constant* Index(size_t i) const override { return i < count ? el : nullptr; } - bool AllZero() const override { return el->AllZero(); } - bool AnyZero() const override { return el->AnyZero(); } - bool AllEqual() const override { return true; } - size_t Hash() const override { return utils::Hash(type, el->Hash(), count); } - - type::Type const* const type; - const constant::Constant* el; - const size_t count; -}; - -/// Composite holds a number of mixed child Constant values. -/// Composite may be of a vector, matrix or array type. -/// If each element is the same type and value, then a Splat would be a more efficient constant -/// implementation. Use CreateComposite() to create the appropriate Constant type. -/// Composite implements the Constant interface. -class Composite : public Castable { - public: - Composite(const type::Type* t, - utils::VectorRef els, - bool all_0, - bool any_0) - : type(t), elements(std::move(els)), all_zero(all_0), any_zero(any_0), hash(CalcHash()) {} - ~Composite() override = default; - const type::Type* Type() const override { return type; } - std::variant Value() const override { return {}; } - const constant::Constant* Index(size_t i) const override { - return i < elements.Length() ? elements[i] : nullptr; - } - bool AllZero() const override { return all_zero; } - bool AnyZero() const override { return any_zero; } - bool AllEqual() const override { return false; /* otherwise this should be a Splat */ } - size_t Hash() const override { return hash; } - - size_t CalcHash() { - auto h = utils::Hash(type, all_zero, any_zero); - for (auto* el : elements) { - h = utils::HashCombine(h, el->Hash()); - } - return h; - } - - type::Type const* const type; - const utils::Vector elements; - const bool all_zero; - const bool any_zero; - const size_t hash; -}; - template ImplResult ScalarConvert(const Scalar* scalar, ProgramBuilder& builder, @@ -488,22 +382,6 @@ ImplResult ConvertInternal(const constant::Constant* c, [&](const Composite* val) { return CompositeConvert(val, builder, target_ty, source); }); } -} // namespace -} // namespace tint::resolver - -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Scalar); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Splat); -TINT_INSTANTIATE_TYPEINFO(tint::resolver::Composite); - -namespace tint::resolver { -namespace { - /// CreateScalar constructs and returns an Scalar. template ImplResult CreateScalar(ProgramBuilder& builder, const Source& source, const type::Type* t, T v) {