mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-20 18:29:23 +00:00
tint: Rework sem::Constant to be variant-of-vector
Instead of vector-of-variant. This: • Makes it impossible to produce a mix of scalar variant types, which would make no sense. • Reduces the size of a Constant, by removing the union-tag from each element. Also clean up terminology. Rename 'Constant::Scalar' to 'Constant::Element'. Scalars are well-defined in WGSL, and with the introduction of abstract-numerics, this no longer makes sense. Bug: tint:1504 Change-Id: I599aa97ad1ea798b7db8e512a5990ba75827faad Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91304 Reviewed-by: Antonio Maiorano <amaiorano@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
ce425feef5
commit
9707e6bb38
@@ -23,29 +23,19 @@
|
||||
namespace tint::sem {
|
||||
|
||||
namespace {
|
||||
|
||||
const Type* CheckElemType(const Type* ty, size_t num_scalars) {
|
||||
diag::List diag;
|
||||
if (ty->is_abstract_or_scalar() || ty->IsAnyOf<Vector, Matrix>()) {
|
||||
uint32_t count = 0;
|
||||
auto* el_ty = Type::ElementOf(ty, &count);
|
||||
if (num_scalars != count) {
|
||||
TINT_ICE(Semantic, diag) << "sem::Constant() type <-> scalar mismatch. type: '"
|
||||
<< ty->TypeInfo().name << "' scalar: " << num_scalars;
|
||||
}
|
||||
TINT_ASSERT(Semantic, el_ty->is_abstract_or_scalar());
|
||||
return el_ty;
|
||||
}
|
||||
TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type: " << ty->TypeInfo().name;
|
||||
return nullptr;
|
||||
size_t CountElements(const Constant::Elements& elements) {
|
||||
return std::visit([](auto&& vec) { return vec.size(); }, elements);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Constant::Constant() {}
|
||||
|
||||
Constant::Constant(const sem::Type* ty, Scalars els)
|
||||
: type_(ty), elem_type_(CheckElemType(ty, els.size())), elems_(std::move(els)) {}
|
||||
Constant::Constant(const sem::Type* ty, Elements els)
|
||||
: type_(ty), elem_type_(CheckElemType(ty, CountElements(els))), elems_(std::move(els)) {}
|
||||
|
||||
Constant::Constant(const sem::Type* ty, AInts vec) : Constant(ty, Elements{std::move(vec)}) {}
|
||||
|
||||
Constant::Constant(const sem::Type* ty, AFloats vec) : Constant(ty, Elements{std::move(vec)}) {}
|
||||
|
||||
Constant::Constant(const Constant&) = default;
|
||||
|
||||
@@ -54,16 +44,31 @@ Constant::~Constant() = default;
|
||||
Constant& Constant::operator=(const Constant& rhs) = default;
|
||||
|
||||
bool Constant::AnyZero() const {
|
||||
for (auto scalar : elems_) {
|
||||
auto is_zero = [&](auto&& s) {
|
||||
using T = std::remove_reference_t<decltype(s)>;
|
||||
return s == T(0);
|
||||
};
|
||||
if (std::visit(is_zero, scalar)) {
|
||||
return true;
|
||||
return WithElements([&](auto&& vec) {
|
||||
for (auto scalar : vec) {
|
||||
using T = std::remove_reference_t<decltype(scalar)>;
|
||||
if (scalar == T(0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
const Type* Constant::CheckElemType(const sem::Type* ty, size_t num_elements) {
|
||||
diag::List diag;
|
||||
if (ty->is_abstract_or_scalar() || ty->IsAnyOf<Vector, Matrix>()) {
|
||||
uint32_t count = 0;
|
||||
auto* el_ty = Type::ElementOf(ty, &count);
|
||||
if (num_elements != count) {
|
||||
TINT_ICE(Semantic, diag) << "sem::Constant() type <-> element mismatch. type: '"
|
||||
<< ty->TypeInfo().name << "' element: " << num_elements;
|
||||
}
|
||||
TINT_ASSERT(Semantic, el_ty->is_abstract_or_scalar());
|
||||
return el_ty;
|
||||
}
|
||||
return false;
|
||||
TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type: " << ty->TypeInfo().name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace tint::sem
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
#ifndef SRC_TINT_SEM_CONSTANT_H_
|
||||
#define SRC_TINT_SEM_CONSTANT_H_
|
||||
|
||||
#include <variant>
|
||||
#include <ostream>
|
||||
// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
|
||||
#include <utility>
|
||||
#include <variant> // NOLINT(build/include_order)
|
||||
#include <vector>
|
||||
|
||||
#include "src/tint/program_builder.h"
|
||||
@@ -23,15 +26,31 @@
|
||||
|
||||
namespace tint::sem {
|
||||
|
||||
/// A Constant is compile-time known expression value, expressed as a flattened
|
||||
/// list of scalar values. Value may be of a scalar or vector type.
|
||||
/// A Constant holds a compile-time evaluated expression value, expressed as a flattened list of
|
||||
/// element values. The expression type may be of an abstract-numeric, scalar, vector or matrix
|
||||
/// type. Constant holds the element values in either a vector of abstract-integer (AInt) or
|
||||
/// abstract-float (AFloat), depending on the element type.
|
||||
class Constant {
|
||||
public:
|
||||
/// Scalar holds a single constant scalar value - one of: AInt, AFloat or bool.
|
||||
using Scalar = std::variant<AInt, AFloat, bool>;
|
||||
/// AInts is a vector of AInt, used to hold elements of the WGSL types:
|
||||
/// * abstract-integer
|
||||
/// * i32
|
||||
/// * u32
|
||||
/// * bool (0 or 1)
|
||||
using AInts = std::vector<AInt>;
|
||||
|
||||
/// Scalars is a list of scalar values
|
||||
using Scalars = std::vector<Scalar>;
|
||||
/// AFloats is a vector of AFloat, used to hold elements of the WGSL types:
|
||||
/// * abstract-float
|
||||
/// * f32
|
||||
/// * f16
|
||||
using AFloats = std::vector<AFloat>;
|
||||
|
||||
/// Elements is either a vector of AInts or AFloats
|
||||
using Elements = std::variant<AInts, AFloats>;
|
||||
|
||||
/// Helper that resolves to either AInts or AFloats based on the element type T.
|
||||
template <typename T>
|
||||
using ElementVectorFor = std::conditional_t<IsFloatingPoint<UnwrapNumber<T>>, AFloats, AInts>;
|
||||
|
||||
/// Constructs an invalid Constant
|
||||
Constant();
|
||||
@@ -39,7 +58,23 @@ class Constant {
|
||||
/// Constructs a Constant of the given type and element values
|
||||
/// @param ty the Constant type
|
||||
/// @param els the Constant element values
|
||||
Constant(const Type* ty, Scalars els);
|
||||
Constant(const sem::Type* ty, Elements els);
|
||||
|
||||
/// Constructs a Constant of the given type and element values
|
||||
/// @param ty the Constant type
|
||||
/// @param vec the Constant element values
|
||||
Constant(const sem::Type* ty, AInts vec);
|
||||
|
||||
/// Constructs a Constant of the given type and element values
|
||||
/// @param ty the Constant type
|
||||
/// @param vec the Constant element values
|
||||
Constant(const sem::Type* ty, AFloats vec);
|
||||
|
||||
/// Constructs a Constant of the given type and element values
|
||||
/// @param ty the Constant type
|
||||
/// @param els the Constant element values
|
||||
template <typename T>
|
||||
Constant(const sem::Type* ty, std::initializer_list<T> els);
|
||||
|
||||
/// Copy constructor
|
||||
Constant(const Constant&);
|
||||
@@ -61,42 +96,77 @@ class Constant {
|
||||
/// @returns the type of the Constant
|
||||
const sem::Type* Type() const { return type_; }
|
||||
|
||||
/// @returns the number of elements
|
||||
size_t ElementCount() const {
|
||||
return std::visit([](auto&& v) { return v.size(); }, elems_);
|
||||
}
|
||||
|
||||
/// @returns the element type of the Constant
|
||||
const sem::Type* ElementType() const { return elem_type_; }
|
||||
|
||||
/// @returns the constant's scalar elements
|
||||
const Scalars& Elements() const { return elems_; }
|
||||
/// @returns the constant's elements
|
||||
const Elements& GetElements() const { return elems_; }
|
||||
|
||||
/// @returns true if any scalar element is zero
|
||||
/// WithElements calls the function `f` with the vector of elements as either AFloats or AInts
|
||||
/// @param f a function-like with the signature `R(auto&&)`.
|
||||
/// @returns the result of calling `f`.
|
||||
template <typename F>
|
||||
auto WithElements(F&& f) const {
|
||||
return std::visit(std::forward<F>(f), elems_);
|
||||
}
|
||||
|
||||
/// WithElements calls the function `f` with the element vector as either AFloats or AInts
|
||||
/// @param f a function-like with the signature `R(auto&&)`.
|
||||
/// @returns the result of calling `f`.
|
||||
template <typename F>
|
||||
auto WithElements(F&& f) {
|
||||
return std::visit(std::forward<F>(f), elems_);
|
||||
}
|
||||
|
||||
/// @returns the elements as a vector of AInt
|
||||
inline const AInts& IElements() const { return std::get<AInts>(elems_); }
|
||||
|
||||
/// @returns the elements as a vector of AFloat
|
||||
inline const AFloats& FElements() const { return std::get<AFloats>(elems_); }
|
||||
|
||||
/// @returns true if any element is zero
|
||||
bool AnyZero() const;
|
||||
|
||||
/// @param index the index of the scalar value
|
||||
/// @return the value of the scalar at `index`, which must be of type `T`.
|
||||
/// @param index the index of the element
|
||||
/// @return the element at `index`, which must be of type `T`.
|
||||
template <typename T>
|
||||
T Element(size_t index) const {
|
||||
return std::get<T>(elems_[index]);
|
||||
}
|
||||
|
||||
/// @param index the index of the scalar value
|
||||
/// @return the value of the scalar `static_cast` to type T.
|
||||
template <typename T>
|
||||
T ElementAs(size_t index) const {
|
||||
return Cast<T>(elems_[index]);
|
||||
}
|
||||
|
||||
/// @param s the input scalar
|
||||
/// @returns the scalar `s` cast to the type `T`.
|
||||
template <typename T>
|
||||
static T Cast(Scalar s) {
|
||||
return std::visit([](auto v) { return static_cast<T>(v); }, s);
|
||||
}
|
||||
T Element(size_t index) const;
|
||||
|
||||
private:
|
||||
/// Checks that the provided type matches the number of expected elements.
|
||||
/// @returns the element type of `ty`.
|
||||
const sem::Type* CheckElemType(const sem::Type* ty, size_t num_elements);
|
||||
|
||||
const sem::Type* type_ = nullptr;
|
||||
const sem::Type* elem_type_ = nullptr;
|
||||
Scalars elems_;
|
||||
Elements elems_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Constant::Constant(const sem::Type* ty, std::initializer_list<T> els)
|
||||
: type_(ty), elem_type_(CheckElemType(type_, els.size())) {
|
||||
ElementVectorFor<T> elements;
|
||||
elements.reserve(els.size());
|
||||
for (auto el : els) {
|
||||
elements.emplace_back(AFloat(el));
|
||||
}
|
||||
elems_ = Elements{std::move(elements)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Constant::Element(size_t index) const {
|
||||
if constexpr (std::is_same_v<ElementVectorFor<T>, AFloats>) {
|
||||
return static_cast<T>(FElements()[index].value);
|
||||
} else {
|
||||
return static_cast<T>(IElements()[index].value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tint::sem
|
||||
|
||||
#endif // SRC_TINT_SEM_CONSTANT_H_
|
||||
|
||||
199
src/tint/sem/constant_test.cc
Normal file
199
src/tint/sem/constant_test.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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/sem/constant.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "src/tint/sem/abstract_float.h"
|
||||
#include "src/tint/sem/abstract_int.h"
|
||||
#include "src/tint/sem/test_helper.h"
|
||||
|
||||
using namespace tint::number_suffixes; // NOLINT
|
||||
|
||||
namespace tint::sem {
|
||||
namespace {
|
||||
|
||||
using ConstantTest = TestHelper;
|
||||
|
||||
TEST_F(ConstantTest, ConstructorInitializerList) {
|
||||
{
|
||||
Constant c(create<AbstractInt>(), {1_a});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<I32>(), {1_i});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<U32>(), {1_u});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<Bool>(), {false});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(0_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<Bool>(), {true});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<AbstractFloat>(), {1.0_a});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1.0_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<F32>(), {1.0_f});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1.0_a)); });
|
||||
}
|
||||
{
|
||||
Constant c(create<F16>(), {1.0_h});
|
||||
c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(1.0_a)); });
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_ai) {
|
||||
Constant c(create<AbstractInt>(), {1_a});
|
||||
EXPECT_EQ(c.Element<AInt>(0), 1_a);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_i32) {
|
||||
Constant c(create<I32>(), {1_a});
|
||||
EXPECT_EQ(c.Element<i32>(0), 1_i);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_u32) {
|
||||
Constant c(create<U32>(), {1_a});
|
||||
EXPECT_EQ(c.Element<u32>(0), 1_u);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_bool) {
|
||||
Constant c(create<Bool>(), {true});
|
||||
EXPECT_EQ(c.Element<bool>(0), true);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_af) {
|
||||
Constant c(create<AbstractFloat>(), {1.0_a});
|
||||
EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_f32) {
|
||||
Constant c(create<F32>(), {1.0_a});
|
||||
EXPECT_EQ(c.Element<f32>(0), 1.0_f);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_f16) {
|
||||
Constant c(create<F16>(), {1.0_a});
|
||||
EXPECT_EQ(c.Element<f16>(0), 1.0_h);
|
||||
EXPECT_EQ(c.ElementCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_ai) {
|
||||
Constant c(create<Vector>(create<AbstractInt>(), 3u), {1_a, 2_a, 3_a});
|
||||
EXPECT_EQ(c.Element<AInt>(0), 1_a);
|
||||
EXPECT_EQ(c.Element<AInt>(1), 2_a);
|
||||
EXPECT_EQ(c.Element<AInt>(2), 3_a);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_i32) {
|
||||
Constant c(create<Vector>(create<I32>(), 3u), {1_a, 2_a, 3_a});
|
||||
EXPECT_EQ(c.Element<i32>(0), 1_i);
|
||||
EXPECT_EQ(c.Element<i32>(1), 2_i);
|
||||
EXPECT_EQ(c.Element<i32>(2), 3_i);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_u32) {
|
||||
Constant c(create<Vector>(create<U32>(), 3u), {1_a, 2_a, 3_a});
|
||||
EXPECT_EQ(c.Element<u32>(0), 1_u);
|
||||
EXPECT_EQ(c.Element<u32>(1), 2_u);
|
||||
EXPECT_EQ(c.Element<u32>(2), 3_u);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_bool) {
|
||||
Constant c(create<Vector>(create<Bool>(), 2u), {true, false});
|
||||
EXPECT_EQ(c.Element<bool>(0), true);
|
||||
EXPECT_EQ(c.Element<bool>(1), false);
|
||||
EXPECT_EQ(c.ElementCount(), 2u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_af) {
|
||||
Constant c(create<Vector>(create<AbstractFloat>(), 3u), {1.0_a, 2.0_a, 3.0_a});
|
||||
EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(1), 2.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(2), 3.0_a);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_f32) {
|
||||
Constant c(create<Vector>(create<F32>(), 3u), {1.0_a, 2.0_a, 3.0_a});
|
||||
EXPECT_EQ(c.Element<f32>(0), 1.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(1), 2.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(2), 3.0_f);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_vec3_f16) {
|
||||
Constant c(create<Vector>(create<F16>(), 3u), {1.0_a, 2.0_a, 3.0_a});
|
||||
EXPECT_EQ(c.Element<f16>(0), 1.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(1), 2.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(2), 3.0_h);
|
||||
EXPECT_EQ(c.ElementCount(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_mat2x3_af) {
|
||||
Constant c(create<Matrix>(create<Vector>(create<AbstractFloat>(), 3u), 2u),
|
||||
{1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
|
||||
EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(1), 2.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(2), 3.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(3), 4.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(4), 5.0_a);
|
||||
EXPECT_EQ(c.Element<AFloat>(5), 6.0_a);
|
||||
EXPECT_EQ(c.ElementCount(), 6u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_mat2x3_f32) {
|
||||
Constant c(create<Matrix>(create<Vector>(create<F32>(), 3u), 2u),
|
||||
{1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
|
||||
EXPECT_EQ(c.Element<f32>(0), 1.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(1), 2.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(2), 3.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(3), 4.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(4), 5.0_f);
|
||||
EXPECT_EQ(c.Element<f32>(5), 6.0_f);
|
||||
EXPECT_EQ(c.ElementCount(), 6u);
|
||||
}
|
||||
|
||||
TEST_F(ConstantTest, Element_mat2x3_f16) {
|
||||
Constant c(create<Matrix>(create<Vector>(create<F16>(), 3u), 2u),
|
||||
{1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a});
|
||||
EXPECT_EQ(c.Element<f16>(0), 1.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(1), 2.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(2), 3.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(3), 4.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(4), 5.0_h);
|
||||
EXPECT_EQ(c.Element<f16>(5), 6.0_h);
|
||||
EXPECT_EQ(c.ElementCount(), 6u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::sem
|
||||
Reference in New Issue
Block a user