mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-15 11:51:22 +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:
parent
ce425feef5
commit
9707e6bb38
@ -529,6 +529,8 @@ libtint_source_set("libtint_core_all_src") {
|
|||||||
"transform/zero_init_workgroup_memory.h",
|
"transform/zero_init_workgroup_memory.h",
|
||||||
"utils/bitcast.h",
|
"utils/bitcast.h",
|
||||||
"utils/block_allocator.h",
|
"utils/block_allocator.h",
|
||||||
|
"utils/compiler_macros.h",
|
||||||
|
"utils/concat.h",
|
||||||
"utils/crc32.h",
|
"utils/crc32.h",
|
||||||
"utils/debugger.cc",
|
"utils/debugger.cc",
|
||||||
"utils/debugger.h",
|
"utils/debugger.h",
|
||||||
|
@ -456,6 +456,8 @@ set(TINT_LIB_SRCS
|
|||||||
transform/zero_init_workgroup_memory.h
|
transform/zero_init_workgroup_memory.h
|
||||||
utils/bitcast.h
|
utils/bitcast.h
|
||||||
utils/block_allocator.h
|
utils/block_allocator.h
|
||||||
|
utils/compiler_macros.h
|
||||||
|
utils/concat.h
|
||||||
utils/crc32.h
|
utils/crc32.h
|
||||||
utils/enum_set.h
|
utils/enum_set.h
|
||||||
utils/hash.h
|
utils/hash.h
|
||||||
@ -801,6 +803,7 @@ if(TINT_BUILD_TESTS)
|
|||||||
sem/atomic.cc
|
sem/atomic.cc
|
||||||
sem/bool_test.cc
|
sem/bool_test.cc
|
||||||
sem/builtin_test.cc
|
sem/builtin_test.cc
|
||||||
|
sem/constant_test.cc
|
||||||
sem/depth_multisampled_texture_test.cc
|
sem/depth_multisampled_texture_test.cc
|
||||||
sem/depth_texture_test.cc
|
sem/depth_texture_test.cc
|
||||||
sem/expression_test.cc
|
sem/expression_test.cc
|
||||||
|
@ -252,11 +252,13 @@ TEST_P(MaterializeAbstractNumeric, Test) {
|
|||||||
uint32_t num_elems = 0;
|
uint32_t num_elems = 0;
|
||||||
const sem::Type* target_sem_el_ty = sem::Type::ElementOf(target_sem_ty, &num_elems);
|
const sem::Type* target_sem_el_ty = sem::Type::ElementOf(target_sem_ty, &num_elems);
|
||||||
EXPECT_TYPE(expr->ConstantValue().ElementType(), target_sem_el_ty);
|
EXPECT_TYPE(expr->ConstantValue().ElementType(), target_sem_el_ty);
|
||||||
std::visit(
|
expr->ConstantValue().WithElements([&](auto&& vec) {
|
||||||
[&](auto&& v) {
|
using VEC_TY = std::decay_t<decltype(vec)>;
|
||||||
EXPECT_EQ(expr->ConstantValue().Elements(), sem::Constant::Scalars(num_elems, {v}));
|
using EL_TY = typename VEC_TY::value_type;
|
||||||
},
|
ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
|
||||||
data.materialized_value);
|
VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
|
||||||
|
EXPECT_EQ(vec, expected);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (expectation) {
|
switch (expectation) {
|
||||||
|
@ -806,7 +806,7 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws[i].value = static_cast<uint32_t>(value.Element<AInt>(0).value);
|
ws[i].value = value.Element<uint32_t>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_function_->SetWorkgroupSize(std::move(ws));
|
current_function_->SetWorkgroupSize(std::move(ws));
|
||||||
@ -1119,7 +1119,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
|
|||||||
<< (expr->Type() ? expr->Type()->FriendlyName(builder_->Symbols()) : "<null>");
|
<< (expr->Type() ? expr->Type()->FriendlyName(builder_->Symbols()) : "<null>");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto materialized_val = ConstantCast(expr_val, target_ty);
|
auto materialized_val = ConvertValue(expr_val, target_ty);
|
||||||
auto* m = builder_->create<sem::Materialize>(expr, current_statement_, materialized_val);
|
auto* m = builder_->create<sem::Materialize>(expr, current_statement_, materialized_val);
|
||||||
m->Behaviors() = expr->Behaviors();
|
m->Behaviors() = expr->Behaviors();
|
||||||
builder_->Sem().Replace(expr->Declaration(), m);
|
builder_->Sem().Replace(expr->Declaration(), m);
|
||||||
@ -2022,7 +2022,7 @@ sem::Array* Resolver::Array(const ast::Array* arr) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = static_cast<uint32_t>(count_val.Element<AInt>(0).value);
|
count = count_val.Element<uint32_t>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size = std::max<uint64_t>(count, 1) * stride;
|
auto size = std::max<uint64_t>(count, 1) * stride;
|
||||||
|
@ -354,11 +354,10 @@ class Resolver {
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// Constant value evaluation methods
|
/// Constant value evaluation methods
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// Cast `Value` to `target_type`
|
|
||||||
/// @return the casted value
|
/// Convert the `value` to `target_type`
|
||||||
sem::Constant ConstantCast(const sem::Constant& value,
|
/// @return the converted value
|
||||||
const sem::Type* target_type,
|
sem::Constant ConvertValue(const sem::Constant& value, const sem::Type* target_type);
|
||||||
const sem::Type* target_element_type = nullptr);
|
|
||||||
|
|
||||||
sem::Constant EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
|
sem::Constant EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
|
||||||
sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
|
sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
|
||||||
|
@ -14,39 +14,70 @@
|
|||||||
|
|
||||||
#include "src/tint/resolver/resolver.h"
|
#include "src/tint/resolver/resolver.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "src/tint/sem/abstract_float.h"
|
#include "src/tint/sem/abstract_float.h"
|
||||||
#include "src/tint/sem/abstract_int.h"
|
#include "src/tint/sem/abstract_int.h"
|
||||||
#include "src/tint/sem/constant.h"
|
#include "src/tint/sem/constant.h"
|
||||||
#include "src/tint/sem/type_constructor.h"
|
#include "src/tint/sem/type_constructor.h"
|
||||||
|
#include "src/tint/utils/compiler_macros.h"
|
||||||
#include "src/tint/utils/map.h"
|
#include "src/tint/utils/map.h"
|
||||||
|
#include "src/tint/utils/transform.h"
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
using namespace tint::number_suffixes; // NOLINT
|
||||||
|
|
||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
sem::Constant::Scalars CastScalars(sem::Constant::Scalars in, const sem::Type* target_type) {
|
/// Converts all the element values of `in` to the type `T`.
|
||||||
sem::Constant::Scalars out;
|
/// @param elements_in the vector of elements to be converted
|
||||||
out.reserve(in.size());
|
/// @returns the elements converted to type T.
|
||||||
for (auto v : in) {
|
template <typename T, typename ELEMENTS_IN>
|
||||||
// TODO(crbug.com/tint/1504): Check that value fits in new type
|
sem::Constant::Elements Convert(const ELEMENTS_IN& elements_in) {
|
||||||
out.emplace_back(Switch<sem::Constant::Scalar>(
|
TINT_BEGIN_DISABLE_WARNING_UNREACHABLE_CODE();
|
||||||
target_type, //
|
|
||||||
[&](const sem::AbstractInt*) { return sem::Constant::Cast<AInt>(v); },
|
using E = UnwrapNumber<T>;
|
||||||
[&](const sem::AbstractFloat*) { return sem::Constant::Cast<AFloat>(v); },
|
return utils::Transform(elements_in, [&](auto value_in) {
|
||||||
[&](const sem::I32*) { return sem::Constant::Cast<AInt>(v); },
|
if constexpr (std::is_same_v<E, bool>) {
|
||||||
[&](const sem::U32*) { return sem::Constant::Cast<AInt>(v); },
|
return AInt(value_in != 0);
|
||||||
[&](const sem::F32*) { return sem::Constant::Cast<AFloat>(v); },
|
}
|
||||||
[&](const sem::F16*) { return sem::Constant::Cast<AFloat>(v); },
|
|
||||||
[&](const sem::Bool*) { return sem::Constant::Cast<bool>(v); },
|
E converted = static_cast<E>(value_in);
|
||||||
[&](Default) {
|
if constexpr (IsFloatingPoint<E>) {
|
||||||
|
return AFloat(converted);
|
||||||
|
} else {
|
||||||
|
return AInt(converted);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TINT_END_DISABLE_WARNING_UNREACHABLE_CODE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts and returns all the element values of `in` to the semantic type `el_ty`.
|
||||||
|
/// @param in the constant to convert
|
||||||
|
/// @param el_ty the target element type
|
||||||
|
/// @returns the elements converted to `type`
|
||||||
|
sem::Constant::Elements Convert(const sem::Constant::Elements& in, const sem::Type* el_ty) {
|
||||||
|
return std::visit(
|
||||||
|
[&](auto&& v) {
|
||||||
|
return Switch(
|
||||||
|
el_ty, //
|
||||||
|
[&](const sem::AbstractInt*) { return Convert<AInt>(v); },
|
||||||
|
[&](const sem::AbstractFloat*) { return Convert<AFloat>(v); },
|
||||||
|
[&](const sem::I32*) { return Convert<i32>(v); },
|
||||||
|
[&](const sem::U32*) { return Convert<u32>(v); },
|
||||||
|
[&](const sem::F32*) { return Convert<f32>(v); },
|
||||||
|
[&](const sem::F16*) { return Convert<f16>(v); },
|
||||||
|
[&](const sem::Bool*) { return Convert<bool>(v); },
|
||||||
|
[&](Default) -> sem::Constant::Elements {
|
||||||
diag::List diags;
|
diag::List diags;
|
||||||
TINT_UNREACHABLE(Semantic, diags)
|
TINT_UNREACHABLE(Semantic, diags)
|
||||||
<< "invalid element type " << target_type->TypeInfo().name;
|
<< "invalid element type " << el_ty->TypeInfo().name;
|
||||||
return sem::Constant::Scalar(false);
|
return {};
|
||||||
}));
|
});
|
||||||
}
|
},
|
||||||
return out;
|
in);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -72,43 +103,42 @@ sem::Constant Resolver::EvaluateConstantValue(const ast::LiteralExpression* lite
|
|||||||
return sem::Constant{type, {AFloat(lit->value)}};
|
return sem::Constant{type, {AFloat(lit->value)}};
|
||||||
},
|
},
|
||||||
[&](const ast::BoolLiteralExpression* lit) {
|
[&](const ast::BoolLiteralExpression* lit) {
|
||||||
return sem::Constant{type, {lit->value}};
|
return sem::Constant{type, {AInt(lit->value ? 1 : 0)}};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
|
sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
|
||||||
const sem::Type* type) {
|
const sem::Type* ty) {
|
||||||
uint32_t result_size = 0;
|
uint32_t result_size = 0;
|
||||||
auto* el_ty = sem::Type::ElementOf(type, &result_size);
|
auto* el_ty = sem::Type::ElementOf(ty, &result_size);
|
||||||
if (!el_ty) {
|
if (!el_ty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ElementOf() will also return the element type of array, which we do not support.
|
// ElementOf() will also return the element type of array, which we do not support.
|
||||||
if (type->Is<sem::Array>()) {
|
if (ty->Is<sem::Array>()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// For zero value init, return 0s
|
// For zero value init, return 0s
|
||||||
if (call->args.empty()) {
|
if (call->args.empty()) {
|
||||||
using Scalars = sem::Constant::Scalars;
|
|
||||||
return Switch(
|
return Switch(
|
||||||
el_ty,
|
el_ty,
|
||||||
[&](const sem::AbstractInt*) {
|
[&](const sem::AbstractInt*) {
|
||||||
return sem::Constant(type, Scalars(result_size, AInt(0)));
|
return sem::Constant(ty, std::vector(result_size, AInt(0)));
|
||||||
},
|
},
|
||||||
[&](const sem::AbstractFloat*) {
|
[&](const sem::AbstractFloat*) {
|
||||||
return sem::Constant(type, Scalars(result_size, AFloat(0)));
|
return sem::Constant(ty, std::vector(result_size, AFloat(0)));
|
||||||
},
|
},
|
||||||
[&](const sem::I32*) { return sem::Constant(type, Scalars(result_size, AInt(0))); },
|
[&](const sem::I32*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); },
|
||||||
[&](const sem::U32*) { return sem::Constant(type, Scalars(result_size, AInt(0))); },
|
[&](const sem::U32*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); },
|
||||||
[&](const sem::F32*) { return sem::Constant(type, Scalars(result_size, AFloat(0))); },
|
[&](const sem::F32*) { return sem::Constant(ty, std::vector(result_size, AFloat(0))); },
|
||||||
[&](const sem::F16*) { return sem::Constant(type, Scalars(result_size, AFloat(0))); },
|
[&](const sem::F16*) { return sem::Constant(ty, std::vector(result_size, AFloat(0))); },
|
||||||
[&](const sem::Bool*) { return sem::Constant(type, Scalars(result_size, false)); });
|
[&](const sem::Bool*) { return sem::Constant(ty, std::vector(result_size, AInt(0))); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build value for type_ctor from each child value by casting to type_ctor's type.
|
// Build value for type_ctor from each child value by converting to type_ctor's type.
|
||||||
sem::Constant::Scalars elems;
|
std::optional<sem::Constant::Elements> elements;
|
||||||
for (auto* expr : call->args) {
|
for (auto* expr : call->args) {
|
||||||
auto* arg = builder_->Sem().Get(expr);
|
auto* arg = builder_->Sem().Get(expr);
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
@ -118,42 +148,52 @@ sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
|
|||||||
if (!value) {
|
if (!value) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
elems.insert(elems.end(), value.Elements().begin(), value.Elements().end());
|
|
||||||
|
// Convert the elements to the desired type.
|
||||||
|
auto converted = Convert(value.GetElements(), el_ty);
|
||||||
|
|
||||||
|
if (elements.has_value()) {
|
||||||
|
// Append the converted vector to elements
|
||||||
|
std::visit(
|
||||||
|
[&](auto&& dst) {
|
||||||
|
using VEC_TY = std::decay_t<decltype(dst)>;
|
||||||
|
const auto& src = std::get<VEC_TY>(converted);
|
||||||
|
dst.insert(dst.end(), src.begin(), src.end());
|
||||||
|
},
|
||||||
|
elements.value());
|
||||||
|
} else {
|
||||||
|
elements = std::move(converted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splat single-value initializers
|
// Splat single-value initializers
|
||||||
if (elems.size() == 1) {
|
std::visit(
|
||||||
|
[&](auto&& v) {
|
||||||
|
if (v.size() == 1) {
|
||||||
for (uint32_t i = 0; i < result_size - 1; ++i) {
|
for (uint32_t i = 0; i < result_size - 1; ++i) {
|
||||||
elems.emplace_back(elems[0]);
|
v.emplace_back(v[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
elements.value());
|
||||||
|
|
||||||
// Finally cast the elements to the desired type.
|
return sem::Constant(ty, std::move(elements.value()));
|
||||||
auto cast = CastScalars(elems, el_ty);
|
|
||||||
|
|
||||||
return sem::Constant(type, std::move(cast));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Constant Resolver::ConstantCast(const sem::Constant& value,
|
sem::Constant Resolver::ConvertValue(const sem::Constant& value, const sem::Type* ty) {
|
||||||
const sem::Type* target_type,
|
if (value.Type() == ty) {
|
||||||
const sem::Type* target_element_type /* = nullptr */) {
|
|
||||||
if (value.Type() == target_type) {
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_element_type == nullptr) {
|
auto* el_ty = sem::Type::ElementOf(ty);
|
||||||
target_element_type = sem::Type::ElementOf(target_type);
|
if (el_ty == nullptr) {
|
||||||
}
|
|
||||||
if (target_element_type == nullptr) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (value.ElementType() == target_element_type) {
|
if (value.ElementType() == el_ty) {
|
||||||
return sem::Constant(target_type, value.Elements());
|
return sem::Constant(ty, value.GetElements());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto elems = CastScalars(value.Elements(), target_element_type);
|
return sem::Constant(ty, Convert(value.GetElements(), el_ty));
|
||||||
|
|
||||||
return sem::Constant(target_type, elems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
@ -23,8 +23,6 @@ using namespace tint::number_suffixes; // NOLINT
|
|||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using Scalar = sem::Constant::Scalar;
|
|
||||||
|
|
||||||
using ResolverConstantsTest = ResolverTest;
|
using ResolverConstantsTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverConstantsTest, Scalar_i32) {
|
TEST_F(ResolverConstantsTest, Scalar_i32) {
|
||||||
@ -38,7 +36,7 @@ TEST_F(ResolverConstantsTest, Scalar_i32) {
|
|||||||
EXPECT_TRUE(sem->Type()->Is<sem::I32>());
|
EXPECT_TRUE(sem->Type()->Is<sem::I32>());
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ TEST_F(ResolverConstantsTest, Scalar_u32) {
|
|||||||
EXPECT_TRUE(sem->Type()->Is<sem::U32>());
|
EXPECT_TRUE(sem->Type()->Is<sem::U32>());
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +66,7 @@ TEST_F(ResolverConstantsTest, Scalar_f32) {
|
|||||||
EXPECT_TRUE(sem->Type()->Is<sem::F32>());
|
EXPECT_TRUE(sem->Type()->Is<sem::F32>());
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +81,7 @@ TEST_F(ResolverConstantsTest, Scalar_bool) {
|
|||||||
EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
|
EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +98,7 @@ TEST_F(ResolverConstantsTest, Vec3_ZeroInit_i32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0);
|
||||||
@ -119,7 +117,7 @@ TEST_F(ResolverConstantsTest, Vec3_ZeroInit_u32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0u);
|
||||||
@ -138,7 +136,7 @@ TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 0.0);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 0.0);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 0.0);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 0.0);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 0.0);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 0.0);
|
||||||
@ -157,7 +155,7 @@ TEST_F(ResolverConstantsTest, Vec3_ZeroInit_bool) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), false);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), false);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), false);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), false);
|
||||||
@ -176,7 +174,7 @@ TEST_F(ResolverConstantsTest, Vec3_Splat_i32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99);
|
||||||
@ -195,7 +193,7 @@ TEST_F(ResolverConstantsTest, Vec3_Splat_u32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99u);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99u);
|
||||||
@ -214,7 +212,7 @@ TEST_F(ResolverConstantsTest, Vec3_Splat_f32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 9.9f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 9.9f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 9.9f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 9.9f);
|
||||||
@ -233,7 +231,7 @@ TEST_F(ResolverConstantsTest, Vec3_Splat_bool) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), true);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
||||||
@ -252,7 +250,7 @@ TEST_F(ResolverConstantsTest, Vec3_FullConstruct_i32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
||||||
@ -271,7 +269,7 @@ TEST_F(ResolverConstantsTest, Vec3_FullConstruct_u32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
||||||
@ -290,7 +288,7 @@ TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
|
||||||
@ -309,7 +307,7 @@ TEST_F(ResolverConstantsTest, Vec3_FullConstruct_bool) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
||||||
@ -328,7 +326,7 @@ TEST_F(ResolverConstantsTest, Vec3_MixConstruct_i32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
||||||
@ -347,7 +345,7 @@ TEST_F(ResolverConstantsTest, Vec3_MixConstruct_u32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
||||||
@ -366,7 +364,7 @@ TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3.f);
|
||||||
@ -385,13 +383,13 @@ TEST_F(ResolverConstantsTest, Vec3_MixConstruct_bool) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverConstantsTest, Vec3_Cast_f32_to_32) {
|
TEST_F(ResolverConstantsTest, Vec3_Cast_f32_to_i32) {
|
||||||
auto* expr = vec3<i32>(vec3<f32>(1.1_f, 2.2_f, 3.3_f));
|
auto* expr = vec3<i32>(vec3<f32>(1.1_f, 2.2_f, 3.3_f));
|
||||||
WrapInFunction(expr);
|
WrapInFunction(expr);
|
||||||
|
|
||||||
@ -404,7 +402,7 @@ TEST_F(ResolverConstantsTest, Vec3_Cast_f32_to_32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
|
||||||
@ -423,7 +421,7 @@ TEST_F(ResolverConstantsTest, Vec3_Cast_u32_to_f32) {
|
|||||||
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
|
||||||
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
|
ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 10.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 10.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 20.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 20.f);
|
||||||
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 30.f);
|
EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 30.f);
|
||||||
|
@ -1535,7 +1535,7 @@ bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
|
|||||||
});
|
});
|
||||||
if (is_const_expr) {
|
if (is_const_expr) {
|
||||||
auto vector = builtin->Parameters()[index]->Type()->Is<sem::Vector>();
|
auto vector = builtin->Parameters()[index]->Type()->Is<sem::Vector>();
|
||||||
for (size_t i = 0; i < values.Elements().size(); i++) {
|
for (size_t i = 0, n = values.ElementCount(); i < n; i++) {
|
||||||
auto value = values.Element<AInt>(i).value;
|
auto value = values.Element<AInt>(i).value;
|
||||||
if (value < min || value > max) {
|
if (value < min || value > max) {
|
||||||
if (vector) {
|
if (vector) {
|
||||||
|
@ -23,29 +23,19 @@
|
|||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
size_t CountElements(const Constant::Elements& elements) {
|
||||||
const Type* CheckElemType(const Type* ty, size_t num_scalars) {
|
return std::visit([](auto&& vec) { return vec.size(); }, 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_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Constant::Constant() {}
|
Constant::Constant() {}
|
||||||
|
|
||||||
Constant::Constant(const sem::Type* ty, Scalars els)
|
Constant::Constant(const sem::Type* ty, Elements els)
|
||||||
: type_(ty), elem_type_(CheckElemType(ty, els.size())), elems_(std::move(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;
|
Constant::Constant(const Constant&) = default;
|
||||||
|
|
||||||
@ -54,16 +44,31 @@ Constant::~Constant() = default;
|
|||||||
Constant& Constant::operator=(const Constant& rhs) = default;
|
Constant& Constant::operator=(const Constant& rhs) = default;
|
||||||
|
|
||||||
bool Constant::AnyZero() const {
|
bool Constant::AnyZero() const {
|
||||||
for (auto scalar : elems_) {
|
return WithElements([&](auto&& vec) {
|
||||||
auto is_zero = [&](auto&& s) {
|
for (auto scalar : vec) {
|
||||||
using T = std::remove_reference_t<decltype(s)>;
|
using T = std::remove_reference_t<decltype(scalar)>;
|
||||||
return s == T(0);
|
if (scalar == T(0)) {
|
||||||
};
|
|
||||||
if (std::visit(is_zero, scalar)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type: " << ty->TypeInfo().name;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
@ -15,7 +15,10 @@
|
|||||||
#ifndef SRC_TINT_SEM_CONSTANT_H_
|
#ifndef SRC_TINT_SEM_CONSTANT_H_
|
||||||
#define 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 <vector>
|
||||||
|
|
||||||
#include "src/tint/program_builder.h"
|
#include "src/tint/program_builder.h"
|
||||||
@ -23,15 +26,31 @@
|
|||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
/// A Constant is compile-time known expression value, expressed as a flattened
|
/// A Constant holds a compile-time evaluated expression value, expressed as a flattened list of
|
||||||
/// list of scalar values. Value may be of a scalar or vector type.
|
/// 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 {
|
class Constant {
|
||||||
public:
|
public:
|
||||||
/// Scalar holds a single constant scalar value - one of: AInt, AFloat or bool.
|
/// AInts is a vector of AInt, used to hold elements of the WGSL types:
|
||||||
using Scalar = std::variant<AInt, AFloat, bool>;
|
/// * abstract-integer
|
||||||
|
/// * i32
|
||||||
|
/// * u32
|
||||||
|
/// * bool (0 or 1)
|
||||||
|
using AInts = std::vector<AInt>;
|
||||||
|
|
||||||
/// Scalars is a list of scalar values
|
/// AFloats is a vector of AFloat, used to hold elements of the WGSL types:
|
||||||
using Scalars = std::vector<Scalar>;
|
/// * 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
|
/// Constructs an invalid Constant
|
||||||
Constant();
|
Constant();
|
||||||
@ -39,7 +58,23 @@ class Constant {
|
|||||||
/// Constructs a Constant of the given type and element values
|
/// Constructs a Constant of the given type and element values
|
||||||
/// @param ty the Constant type
|
/// @param ty the Constant type
|
||||||
/// @param els the Constant element values
|
/// @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
|
/// Copy constructor
|
||||||
Constant(const Constant&);
|
Constant(const Constant&);
|
||||||
@ -61,42 +96,77 @@ class Constant {
|
|||||||
/// @returns the type of the Constant
|
/// @returns the type of the Constant
|
||||||
const sem::Type* Type() const { return type_; }
|
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
|
/// @returns the element type of the Constant
|
||||||
const sem::Type* ElementType() const { return elem_type_; }
|
const sem::Type* ElementType() const { return elem_type_; }
|
||||||
|
|
||||||
/// @returns the constant's scalar elements
|
/// @returns the constant's elements
|
||||||
const Scalars& Elements() const { return elems_; }
|
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;
|
bool AnyZero() const;
|
||||||
|
|
||||||
/// @param index the index of the scalar value
|
/// @param index the index of the element
|
||||||
/// @return the value of the scalar at `index`, which must be of type `T`.
|
/// @return the element at `index`, which must be of type `T`.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Element(size_t index) const {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
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* type_ = nullptr;
|
||||||
const sem::Type* elem_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
|
} // namespace tint::sem
|
||||||
|
|
||||||
#endif // SRC_TINT_SEM_CONSTANT_H_
|
#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
|
@ -23,6 +23,7 @@
|
|||||||
#include "src/tint/sem/expression.h"
|
#include "src/tint/sem/expression.h"
|
||||||
#include "src/tint/sem/type_constructor.h"
|
#include "src/tint/sem/type_constructor.h"
|
||||||
#include "src/tint/sem/type_conversion.h"
|
#include "src/tint/sem/type_conversion.h"
|
||||||
|
#include "src/tint/utils/transform.h"
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::transform::FoldConstants);
|
TINT_INSTANTIATE_TYPEINFO(tint::transform::FoldConstants);
|
||||||
|
|
||||||
@ -50,24 +51,40 @@ void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If original ctor expression had no init values, don't replace the
|
// If original ctor expression had no init values, don't replace the expression
|
||||||
// expression
|
|
||||||
if (call->Arguments().empty()) {
|
if (call->Arguments().empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto build_scalar = [&](sem::Constant::Scalar s) {
|
auto build_elements = [&](size_t limit) {
|
||||||
return Switch(
|
return Switch(
|
||||||
value.ElementType(), //
|
value.ElementType(), //
|
||||||
[&](const sem::I32*) { return ctx.dst->Expr(i32(std::get<AInt>(s).value)); },
|
[&](const sem::Bool*) {
|
||||||
[&](const sem::U32*) { return ctx.dst->Expr(u32(std::get<AInt>(s).value)); },
|
return utils::TransformN(value.IElements(), limit, [&](AInt i) {
|
||||||
[&](const sem::F32*) { return ctx.dst->Expr(f32(std::get<AFloat>(s).value)); },
|
return static_cast<const ast::Expression*>(
|
||||||
[&](const sem::Bool*) { return ctx.dst->Expr(std::get<bool>(s)); },
|
ctx.dst->Expr(static_cast<bool>(i.value)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[&](const sem::I32*) {
|
||||||
|
return utils::TransformN(value.IElements(), limit, [&](AInt i) {
|
||||||
|
return static_cast<const ast::Expression*>(ctx.dst->Expr(i32(i.value)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[&](const sem::U32*) {
|
||||||
|
return utils::TransformN(value.IElements(), limit, [&](AInt i) {
|
||||||
|
return static_cast<const ast::Expression*>(ctx.dst->Expr(u32(i.value)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[&](const sem::F32*) {
|
||||||
|
return utils::TransformN(value.FElements(), limit, [&](AFloat f) {
|
||||||
|
return static_cast<const ast::Expression*>(ctx.dst->Expr(f32(f.value)));
|
||||||
|
});
|
||||||
|
},
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
TINT_ICE(Transform, ctx.dst->Diagnostics())
|
TINT_ICE(Transform, ctx.dst->Diagnostics())
|
||||||
<< "unhandled Constant::Scalar type: "
|
<< "unhandled Constant::Scalar type: "
|
||||||
<< value.ElementType()->FriendlyName(ctx.src->Symbols());
|
<< value.ElementType()->FriendlyName(ctx.src->Symbols());
|
||||||
return nullptr;
|
return ast::ExpressionList{};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,17 +95,17 @@ void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
|
|||||||
// constructor args that the original node had, but after folding
|
// constructor args that the original node had, but after folding
|
||||||
// constants, cases like the following are problematic:
|
// constants, cases like the following are problematic:
|
||||||
//
|
//
|
||||||
// vec3<f32> = vec3<f32>(vec2<f32>, 1.0) // vec_size=3, ctor_size=2
|
// vec3<f32> = vec3<f32>(vec2<f32>(), 1.0) // vec_size=3, ctor_size=2
|
||||||
//
|
//
|
||||||
// In this case, creating a vec3 with 2 args is invalid, so we should
|
// In this case, creating a vec3 with 2 args is invalid, so we should
|
||||||
// create it with 3. So what we do is construct with vec_size args,
|
// create it with 3. So what we do is construct with vec_size args,
|
||||||
// except if the original vector was single-value initialized, in
|
// except if the original vector was single-value initialized, in
|
||||||
// which case, we only construct with one arg again.
|
// which case, we only construct with one arg again.
|
||||||
uint32_t ctor_size = (call->Arguments().size() == 1) ? 1 : vec_size;
|
|
||||||
|
|
||||||
ast::ExpressionList ctors;
|
ast::ExpressionList ctors;
|
||||||
for (uint32_t i = 0; i < ctor_size; ++i) {
|
if (call->Arguments().size() == 1) {
|
||||||
ctors.emplace_back(build_scalar(value.Elements()[i]));
|
ctors = build_elements(1);
|
||||||
|
} else {
|
||||||
|
ctors = build_elements(value.ElementCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* el_ty = CreateASTTypeFor(ctx, vec->type());
|
auto* el_ty = CreateASTTypeFor(ctx, vec->type());
|
||||||
@ -96,7 +113,7 @@ void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ty->is_scalar()) {
|
if (ty->is_scalar()) {
|
||||||
return build_scalar(value.Elements()[0]);
|
return build_elements(1)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
39
src/tint/utils/compiler_macros.h
Normal file
39
src/tint/utils/compiler_macros.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// 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_UTILS_COMPILER_MACROS_H_
|
||||||
|
#define SRC_TINT_UTILS_COMPILER_MACROS_H_
|
||||||
|
|
||||||
|
#define TINT_REQUIRE_SEMICOLON \
|
||||||
|
do { \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// clang-format off
|
||||||
|
#define TINT_BEGIN_DISABLE_WARNING_UNREACHABLE_CODE() \
|
||||||
|
__pragma(warning(push)) \
|
||||||
|
__pragma(warning(disable:4702)) \
|
||||||
|
TINT_REQUIRE_SEMICOLON
|
||||||
|
#define TINT_END_DISABLE_WARNING_UNREACHABLE_CODE() \
|
||||||
|
__pragma(warning(pop)) \
|
||||||
|
TINT_REQUIRE_SEMICOLON
|
||||||
|
// clang-format on
|
||||||
|
#else
|
||||||
|
// clang-format off
|
||||||
|
#define TINT_BEGIN_DISABLE_WARNING_UNREACHABLE_CODE() TINT_REQUIRE_SEMICOLON
|
||||||
|
#define TINT_END_DISABLE_WARNING_UNREACHABLE_CODE() TINT_REQUIRE_SEMICOLON
|
||||||
|
// clang-format on
|
||||||
|
#endif // defined(_MSC_VER)
|
||||||
|
|
||||||
|
#endif // SRC_TINT_UTILS_COMPILER_MACROS_H_
|
@ -639,7 +639,6 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
|
|||||||
|
|
||||||
bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
|
bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
|
||||||
// For constants, replace literal 0 with 1.
|
// For constants, replace literal 0 with 1.
|
||||||
sem::Constant::Scalars elems;
|
|
||||||
if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
|
if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
|
||||||
if (!val.AnyZero()) {
|
if (!val.AnyZero()) {
|
||||||
return EmitExpression(out, expr);
|
return EmitExpression(out, expr);
|
||||||
@ -657,7 +656,7 @@ bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expr
|
|||||||
}
|
}
|
||||||
|
|
||||||
out << "(";
|
out << "(";
|
||||||
for (size_t i = 0; i < val.Elements().size(); ++i) {
|
for (size_t i = 0; i < val.ElementCount(); ++i) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
|
@ -924,7 +924,7 @@ bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, Ac
|
|||||||
Operand(result_type_id),
|
Operand(result_type_id),
|
||||||
extract,
|
extract,
|
||||||
Operand(info->source_id),
|
Operand(info->source_id),
|
||||||
Operand(idx_constval.ElementAs<uint32_t>(0)),
|
Operand(idx_constval.Element<uint32_t>(0)),
|
||||||
})) {
|
})) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -289,6 +289,7 @@ tint_unittests_source_set("tint_unittests_sem_src") {
|
|||||||
"../../src/tint/sem/atomic_test.cc",
|
"../../src/tint/sem/atomic_test.cc",
|
||||||
"../../src/tint/sem/bool_test.cc",
|
"../../src/tint/sem/bool_test.cc",
|
||||||
"../../src/tint/sem/builtin_test.cc",
|
"../../src/tint/sem/builtin_test.cc",
|
||||||
|
"../../src/tint/sem/constant_test.cc",
|
||||||
"../../src/tint/sem/depth_multisampled_texture_test.cc",
|
"../../src/tint/sem/depth_multisampled_texture_test.cc",
|
||||||
"../../src/tint/sem/depth_texture_test.cc",
|
"../../src/tint/sem/depth_texture_test.cc",
|
||||||
"../../src/tint/sem/expression_test.cc",
|
"../../src/tint/sem/expression_test.cc",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user