tint: Refactor sem::Constant to be less memory-hungry
Change sem::Constant to be an interface to the constant data. Implement
this so that zero-initialized data doesn't need to allocate the full
size of the type.
This also makes usage a lot cleaner (no more flattened-list of
elements!), and gives us a clear path for supporting constant
structures if/when we want to support them.
Bug: chromium:1339558
Bug: chromium:1339561
Bug: chromium:1339580
Bug: chromium:1339597
Change-Id: Ifcd456f69aee18d5b84befa896d7b0189d68c2dd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94942
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index b59fa37..fb51327 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -1131,7 +1131,6 @@
"sem/atomic_test.cc",
"sem/bool_test.cc",
"sem/builtin_test.cc",
- "sem/constant_test.cc",
"sem/depth_multisampled_texture_test.cc",
"sem/depth_texture_test.cc",
"sem/expression_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 755d4a3..3e7154c 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -810,7 +810,6 @@
sem/atomic.cc
sem/bool_test.cc
sem/builtin_test.cc
- sem/constant_test.cc
sem/depth_multisampled_texture_test.cc
sem/depth_texture_test.cc
sem/expression_test.cc
diff --git a/src/tint/program.cc b/src/tint/program.cc
index 6722a09..1afbd46 100644
--- a/src/tint/program.cc
+++ b/src/tint/program.cc
@@ -38,6 +38,7 @@
types_(std::move(program.types_)),
ast_nodes_(std::move(program.ast_nodes_)),
sem_nodes_(std::move(program.sem_nodes_)),
+ constant_nodes_(std::move(program.constant_nodes_)),
ast_(std::move(program.ast_)),
sem_(std::move(program.sem_)),
symbols_(std::move(program.symbols_)),
@@ -62,6 +63,7 @@
types_ = std::move(builder.Types());
ast_nodes_ = std::move(builder.ASTNodes());
sem_nodes_ = std::move(builder.SemNodes());
+ constant_nodes_ = std::move(builder.ConstantNodes());
ast_ = &builder.AST(); // ast::Module is actually a heap allocation.
sem_ = std::move(builder.Sem());
symbols_ = std::move(builder.Symbols());
@@ -86,6 +88,7 @@
types_ = std::move(program.types_);
ast_nodes_ = std::move(program.ast_nodes_);
sem_nodes_ = std::move(program.sem_nodes_);
+ constant_nodes_ = std::move(program.constant_nodes_);
ast_ = std::move(program.ast_);
sem_ = std::move(program.sem_);
symbols_ = std::move(program.symbols_);
diff --git a/src/tint/program.h b/src/tint/program.h
index 3230e7e..5fd31dd 100644
--- a/src/tint/program.h
+++ b/src/tint/program.h
@@ -20,6 +20,7 @@
#include "src/tint/ast/function.h"
#include "src/tint/program_id.h"
+#include "src/tint/sem/constant.h"
#include "src/tint/sem/info.h"
#include "src/tint/sem/type_manager.h"
#include "src/tint/symbol_table.h"
@@ -43,6 +44,9 @@
/// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+ /// ConstantAllocator is an alias to BlockAllocator<sem::Constant>
+ using ConstantAllocator = utils::BlockAllocator<sem::Constant>;
+
/// Constructor
Program();
@@ -160,6 +164,7 @@
sem::Manager types_;
ASTNodeAllocator ast_nodes_;
SemNodeAllocator sem_nodes_;
+ ConstantAllocator constant_nodes_;
ast::Module* ast_ = nullptr;
sem::Info sem_;
SymbolTable symbols_{id_};
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 5bccb5f..e9b0a80 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -88,6 +88,7 @@
#include "src/tint/program_id.h"
#include "src/tint/sem/array.h"
#include "src/tint/sem/bool.h"
+#include "src/tint/sem/constant.h"
#include "src/tint/sem/depth_texture.h"
#include "src/tint/sem/external_texture.h"
#include "src/tint/sem/f16.h"
@@ -163,6 +164,9 @@
/// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+ /// ConstantAllocator is an alias to BlockAllocator<sem::Constant>
+ using ConstantAllocator = utils::BlockAllocator<sem::Constant>;
+
/// Constructor
ProgramBuilder();
@@ -229,6 +233,12 @@
return sem_nodes_;
}
+ /// @returns a reference to the program's semantic constant storage
+ ConstantAllocator& ConstantNodes() {
+ AssertNotMoved();
+ return constant_nodes_;
+ }
+
/// @returns a reference to the program's AST root Module
ast::Module& AST() {
AssertNotMoved();
@@ -332,9 +342,8 @@
}
/// Creates a new sem::Node owned by the ProgramBuilder.
- /// When the ProgramBuilder is destructed, the sem::Node will also be
- /// destructed.
- /// @param args the arguments to pass to the type constructor
+ /// When the ProgramBuilder is destructed, the sem::Node will also be destructed.
+ /// @param args the arguments to pass to the constructor
/// @returns the node pointer
template <typename T, typename... ARGS>
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
@@ -345,6 +354,16 @@
return sem_nodes_.Create<T>(std::forward<ARGS>(args)...);
}
+ /// Creates a new sem::Constant owned by the ProgramBuilder.
+ /// When the ProgramBuilder is destructed, the sem::Node will also be destructed.
+ /// @param args the arguments to pass to the constructor
+ /// @returns the node pointer
+ template <typename T, typename... ARGS>
+ traits::EnableIf<traits::IsTypeOrDerived<T, sem::Constant>, T>* create(ARGS&&... args) {
+ AssertNotMoved();
+ return constant_nodes_.Create<T>(std::forward<ARGS>(args)...);
+ }
+
/// Creates a new sem::Type owned by the ProgramBuilder.
/// When the ProgramBuilder is destructed, owned ProgramBuilder and the
/// returned`Type` will also be destructed.
@@ -2747,6 +2766,7 @@
sem::Manager types_;
ASTNodeAllocator ast_nodes_;
SemNodeAllocator sem_nodes_;
+ ConstantAllocator constant_nodes_;
ast::Module* ast_;
sem::Info sem_;
SymbolTable symbols_{id_};
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 89bb3da..3792e35 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -30,7 +30,9 @@
namespace tint::resolver::const_eval {
/// Typedef for a constant evaluation function
-using Function = sem::Constant(ProgramBuilder& builder, const sem::Constant* args, size_t num_args);
+using Function = const sem::Constant*(ProgramBuilder& builder,
+ sem::Constant const* const* args,
+ size_t num_args);
} // namespace tint::resolver::const_eval
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index 0ace1ca..1b935ee 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -73,12 +73,61 @@
return o << "<unknown>";
}
+template <typename CASE>
+class MaterializeTest : public resolver::ResolverTestWithParam<CASE> {
+ protected:
+ using ProgramBuilder::FriendlyName;
+
+ void CheckTypesAndValues(const sem::Expression* expr,
+ const tint::sem::Type* expected_sem_ty,
+ const std::variant<AInt, AFloat>& expected_value) {
+ std::visit([&](auto v) { CheckTypesAndValuesImpl(expr, expected_sem_ty, v); },
+ expected_value);
+ }
+
+ private:
+ template <typename T>
+ void CheckTypesAndValuesImpl(const sem::Expression* expr,
+ const tint::sem::Type* expected_sem_ty,
+ T expected_value) {
+ EXPECT_TYPE(expr->Type(), expected_sem_ty);
+
+ auto* value = expr->ConstantValue();
+ ASSERT_NE(value, nullptr);
+ EXPECT_TYPE(expr->Type(), value->Type());
+
+ tint::Switch(
+ expected_sem_ty, //
+ [&](const sem::Vector* v) {
+ for (uint32_t i = 0; i < v->Width(); i++) {
+ auto* el = value->Index(i);
+ ASSERT_NE(el, nullptr);
+ EXPECT_TYPE(el->Type(), v->type());
+ EXPECT_EQ(std::get<T>(el->Value()), expected_value);
+ }
+ },
+ [&](const sem::Matrix* m) {
+ for (uint32_t c = 0; c < m->columns(); c++) {
+ auto* column = value->Index(c);
+ ASSERT_NE(column, nullptr);
+ EXPECT_TYPE(column->Type(), m->ColumnType());
+ for (uint32_t r = 0; r < m->rows(); r++) {
+ auto* el = column->Index(r);
+ ASSERT_NE(el, nullptr);
+ EXPECT_TYPE(el->Type(), m->type());
+ EXPECT_EQ(std::get<T>(el->Value()), expected_value);
+ }
+ }
+ },
+ [&](Default) { EXPECT_EQ(std::get<T>(value->Value()), expected_value); });
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// MaterializeAbstractNumericToConcreteType
// Tests that an abstract-numeric will materialize to the expected concrete type
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace materialize_abstract_numeric_to_concrete_type {
-
// How should the materialization occur?
enum class Method {
// var a : target_type = abstract_expr;
@@ -247,7 +296,7 @@
}
using MaterializeAbstractNumericToConcreteType =
- resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
+ MaterializeTest<std::tuple<Expectation, Method, Data>>;
TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
// Once built-in and ops using f16 is properly supported, we'll need to enable this:
@@ -323,30 +372,12 @@
break;
}
- auto check_types_and_values = [&](const sem::Expression* expr) {
- auto* target_sem_ty = data.target_sem_ty(*this);
-
- EXPECT_TYPE(expr->Type(), target_sem_ty);
- EXPECT_TYPE(expr->ConstantValue().Type(), target_sem_ty);
-
- uint32_t num_elems = 0;
- const sem::Type* target_sem_el_ty = sem::Type::DeepestElementOf(target_sem_ty, &num_elems);
- EXPECT_TYPE(expr->ConstantValue().ElementType(), target_sem_el_ty);
- expr->ConstantValue().WithElements([&](auto&& vec) {
- using VEC_TY = std::decay_t<decltype(vec)>;
- using EL_TY = typename VEC_TY::value_type;
- ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
- VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
- EXPECT_EQ(vec, expected);
- });
- };
-
switch (expectation) {
case Expectation::kMaterialize: {
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* materialize = Sem().Get<sem::Materialize>(abstract_expr);
ASSERT_NE(materialize, nullptr);
- check_types_and_values(materialize);
+ CheckTypesAndValues(materialize, data.target_sem_ty(*this), data.materialized_value);
break;
}
case Expectation::kNoMaterialize: {
@@ -354,7 +385,7 @@
auto* sem = Sem().Get(abstract_expr);
ASSERT_NE(sem, nullptr);
EXPECT_FALSE(sem->Is<sem::Materialize>());
- check_types_and_values(sem);
+ CheckTypesAndValues(sem, data.target_sem_ty(*this), data.materialized_value);
break;
}
case Expectation::kInvalidConversion: {
@@ -414,8 +445,8 @@
/// Methods that do not materialize
constexpr Method kNoMaterializeMethods[] = {
Method::kPhonyAssign,
- // TODO(crbug.com/tint/1504): Enable once we have abstract overloads of builtins / binary ops:
- // Method::kBuiltinArg, Method::kBinaryOp,
+ // TODO(crbug.com/tint/1504): Enable once we have abstract overloads of builtins / binary
+ // ops: Method::kBuiltinArg, Method::kBinaryOp,
};
INSTANTIATE_TEST_SUITE_P(
MaterializeScalar,
@@ -703,7 +734,7 @@
}
using MaterializeAbstractNumericToDefaultType =
- resolver::ResolverTestWithParam<std::tuple<Expectation, Method, Data>>;
+ MaterializeTest<std::tuple<Expectation, Method, Data>>;
TEST_P(MaterializeAbstractNumericToDefaultType, Test) {
const auto& param = GetParam();
@@ -751,32 +782,14 @@
break;
}
- auto check_types_and_values = [&](const sem::Expression* expr) {
- auto* expected_sem_ty = data.expected_sem_ty(*this);
-
- EXPECT_TYPE(expr->Type(), expected_sem_ty);
- EXPECT_TYPE(expr->ConstantValue().Type(), expected_sem_ty);
-
- uint32_t num_elems = 0;
- const sem::Type* expected_sem_el_ty =
- sem::Type::DeepestElementOf(expected_sem_ty, &num_elems);
- EXPECT_TYPE(expr->ConstantValue().ElementType(), expected_sem_el_ty);
- expr->ConstantValue().WithElements([&](auto&& vec) {
- using VEC_TY = std::decay_t<decltype(vec)>;
- using EL_TY = typename VEC_TY::value_type;
- ASSERT_TRUE(std::holds_alternative<EL_TY>(data.materialized_value));
- VEC_TY expected(num_elems, std::get<EL_TY>(data.materialized_value));
- EXPECT_EQ(vec, expected);
- });
- };
-
switch (expectation) {
case Expectation::kMaterialize: {
ASSERT_TRUE(r()->Resolve()) << r()->error();
for (auto* expr : abstract_exprs) {
auto* materialize = Sem().Get<sem::Materialize>(expr);
ASSERT_NE(materialize, nullptr);
- check_types_and_values(materialize);
+ CheckTypesAndValues(materialize, data.expected_sem_ty(*this),
+ data.materialized_value);
}
break;
}
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index e6cad77..9ef9a30 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -365,13 +365,13 @@
sem::Variable* sem = nullptr;
if (is_global) {
- sem = builder_->create<sem::GlobalVariable>(v, ty, ast::StorageClass::kNone,
- ast::Access::kUndefined, sem::Constant{},
- sem::BindingPoint{});
+ sem = builder_->create<sem::GlobalVariable>(
+ v, ty, ast::StorageClass::kNone, ast::Access::kUndefined, /* constant_value */ nullptr,
+ sem::BindingPoint{});
} else {
sem = builder_->create<sem::LocalVariable>(v, ty, ast::StorageClass::kNone,
ast::Access::kUndefined, current_statement_,
- sem::Constant{});
+ /* constant_value */ nullptr);
}
sem->SetConstructor(rhs);
@@ -419,9 +419,9 @@
return nullptr;
}
- auto* sem = builder_->create<sem::GlobalVariable>(v, ty, ast::StorageClass::kNone,
- ast::Access::kUndefined, sem::Constant{},
- sem::BindingPoint{});
+ auto* sem = builder_->create<sem::GlobalVariable>(
+ v, ty, ast::StorageClass::kNone, ast::Access::kUndefined, /* constant_value */ nullptr,
+ sem::BindingPoint{});
if (auto* id = ast::GetAttribute<ast::IdAttribute>(v->attributes)) {
sem->SetConstantId(static_cast<uint16_t>(id->value));
@@ -564,11 +564,11 @@
binding_point = {bp.group->value, bp.binding->value};
}
sem = builder_->create<sem::GlobalVariable>(var, var_ty, storage_class, access,
- sem::Constant{}, binding_point);
+ /* constant_value */ nullptr, binding_point);
} else {
- sem = builder_->create<sem::LocalVariable>(var, var_ty, storage_class, access,
- current_statement_, sem::Constant{});
+ sem = builder_->create<sem::LocalVariable>(
+ var, var_ty, storage_class, access, current_statement_, /* constant_value */ nullptr);
}
sem->SetConstructor(rhs);
@@ -916,7 +916,7 @@
return false;
}
- sem::Constant value;
+ const sem::Constant* value = nullptr;
if (auto* user = args[i]->As<sem::VariableUser>()) {
// We have an variable of a module-scope constant.
@@ -950,12 +950,12 @@
continue;
}
// validator_.Validate and set the default value for this dimension.
- if (value.Element<AInt>(0).value < 1) {
+ if (value->As<AInt>() < 1) {
AddError("workgroup_size argument must be at least 1", values[i]->source);
return false;
}
- ws[i].value = value.Element<uint32_t>(0);
+ ws[i].value = value->As<uint32_t>();
}
current_function_->SetWorkgroupSize(std::move(ws));
@@ -1266,7 +1266,8 @@
[&](const ast::UnaryOpExpression* unary) -> sem::Expression* { return UnaryOp(unary); },
[&](const ast::PhonyExpression*) -> sem::Expression* {
return builder_->create<sem::Expression>(expr, builder_->create<sem::Void>(),
- current_statement_, sem::Constant{},
+ current_statement_,
+ /* constant_value */ nullptr,
/* has_side_effects */ false);
},
[&](Default) {
@@ -1309,13 +1310,14 @@
<< ") returned invalid value";
return nullptr;
}
- auto materialized_val = ConvertValue(std::move(expr_val), target_ty, decl->source);
+ auto materialized_val = ConvertValue(expr_val, target_ty, decl->source);
if (!materialized_val) {
+ // ConvertValue() has already failed and raised an diagnostic error.
return nullptr;
}
- if (!materialized_val->IsValid()) {
+ if (!materialized_val.Get()) {
TINT_ICE(Resolver, builder_->Diagnostics())
- << decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val.Type())
+ << decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val->Type())
<< " -> " << builder_->FriendlyName(target_ty) << ") returned invalid value";
return nullptr;
}
@@ -1678,9 +1680,9 @@
}
// If the builtin is @const, and all arguments have constant values, evaluate the builtin now.
- sem::Constant constant;
+ const sem::Constant* constant = nullptr;
if (builtin.const_eval_fn) {
- std::vector<sem::Constant> values(args.size());
+ std::vector<const sem::Constant*> values(args.size());
bool is_const = true; // all arguments have constant values
for (size_t i = 0; i < values.size(); i++) {
if (auto v = args[i]->ConstantValue()) {
@@ -1757,7 +1759,7 @@
// effects.
bool has_side_effects = true;
auto* call = builder_->create<sem::Call>(expr, target, std::move(args), current_statement_,
- sem::Constant{}, has_side_effects);
+ /* constant_value */ nullptr, has_side_effects);
target->AddCallSite(call);
@@ -2226,21 +2228,21 @@
return nullptr;
}
- auto count_val = count_sem->ConstantValue();
+ auto* count_val = count_sem->ConstantValue();
if (!count_val) {
AddError("array size must evaluate to a constant integer expression",
count_expr->source);
return nullptr;
}
- if (auto* ty = count_val.Type(); !ty->is_integer_scalar()) {
+ if (auto* ty = count_val->Type(); !ty->is_integer_scalar()) {
AddError("array size must evaluate to a constant integer expression, but is type '" +
builder_->FriendlyName(ty) + "'",
count_expr->source);
return nullptr;
}
- count = count_val.Element<AInt>(0).value;
+ count = count_val->As<AInt>();
if (count < 1) {
AddError("array size (" + std::to_string(count) + ") must be greater than 0",
count_expr->source);
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index aab772e..1a45bc4 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -209,22 +209,30 @@
/// These methods are called from the expression resolving methods, and so child-expression
/// nodes are guaranteed to have been already resolved and any constant values calculated.
////////////////////////////////////////////////////////////////////////////////////////////////
- sem::Constant EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
- sem::Constant EvaluateConstantValue(const ast::IdentifierExpression* ident,
- const sem::Type* type);
- sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
- const sem::Type* type);
- sem::Constant EvaluateConstantValue(const ast::CallExpression* call, const sem::Type* type);
- sem::Constant EvaluateConstantValue(const ast::IndexAccessorExpression* call,
- const sem::Type* type);
+ const sem::Constant* EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
+ const sem::Constant* EvaluateConstantValue(const ast::IdentifierExpression* ident,
+ const sem::Type* type);
+ const sem::Constant* EvaluateConstantValue(const ast::LiteralExpression* literal,
+ const sem::Type* type);
+ const sem::Constant* EvaluateConstantValue(const ast::CallExpression* call,
+ const sem::Type* type);
+ const sem::Constant* EvaluateConstantValue(const ast::IndexAccessorExpression* call,
+ const sem::Type* type);
- /// The result type of a ConstantEvaluation method. Holds the constant value and a boolean,
- /// which is true on success, false on an error.
- using ConstantResult = utils::Result<sem::Constant>;
+ /// The result type of a ConstantEvaluation method.
+ /// Can be one of three distinct values:
+ /// * A non-null sem::Constant pointer. Returned when a expression resolves to a creation time
+ /// value.
+ /// * A null sem::Constant pointer. Returned when a expression cannot resolve to a creation time
+ /// value, but is otherwise legal.
+ /// * `utils::Failure`. Returned when there was a resolver error. In this situation the method
+ /// will have already reported a diagnostic error message, and the caller should abort
+ /// resolving.
+ using ConstantResult = utils::Result<const sem::Constant*>;
/// Convert the `value` to `target_type`
/// @return the converted value
- ConstantResult ConvertValue(const sem::Constant& value,
+ ConstantResult ConvertValue(const sem::Constant* value,
const sem::Type* target_type,
const Source& source);
diff --git a/src/tint/resolver/resolver_constants.cc b/src/tint/resolver/resolver_constants.cc
index 74e4327..f6ffb28 100644
--- a/src/tint/resolver/resolver_constants.cc
+++ b/src/tint/resolver/resolver_constants.cc
@@ -14,7 +14,6 @@
#include "src/tint/resolver/resolver.h"
-#include <cmath>
#include <optional>
#include "src/tint/sem/abstract_float.h"
@@ -22,8 +21,6 @@
#include "src/tint/sem/constant.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/transform.h"
using namespace tint::number_suffixes; // NOLINT
@@ -31,127 +28,334 @@
namespace {
-/// Converts and returns all the element values of `in` to the type `T`, using the converter
-/// function `CONVERTER`.
-/// @param elements_in the vector of elements to be converted
-/// @param converter a function-like with the signature `void(TO&, FROM)`
-/// @returns the elements converted to type T.
-template <typename T, typename ELEMENTS_IN, typename CONVERTER>
-sem::Constant::Elements Transform(const ELEMENTS_IN& elements_in, CONVERTER&& converter) {
- TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
+/// TypeDispatch is a helper for calling the function `f`, passing a single zero-value argument of
+/// the C++ type that corresponds to the sem::Type `type`. For example, calling `TypeDispatch()`
+/// with a type of `sem::I32*` will call the function f with a single argument of `i32(0)`.
+/// @returns the value returned by calling `f`.
+/// @note `type` must be a scalar or abstract numeric type. Other types will not call `f`, and will
+/// return the zero-initialized value of the return type for `f`.
+template <typename F>
+auto TypeDispatch(const sem::Type* type, F&& f) {
+ return Switch(
+ type, //
+ [&](const sem::AbstractInt*) { return f(AInt(0)); }, //
+ [&](const sem::AbstractFloat*) { return f(AFloat(0)); }, //
+ [&](const sem::I32*) { return f(i32(0)); }, //
+ [&](const sem::U32*) { return f(u32(0)); }, //
+ [&](const sem::F32*) { return f(f32(0)); }, //
+ [&](const sem::F16*) { return f(f16(0)); }, //
+ [&](const sem::Bool*) { return f(static_cast<bool>(0)); });
+}
- return utils::Transform(elements_in, [&](auto value_in) {
- if constexpr (std::is_same_v<UnwrapNumber<T>, bool>) {
- return AInt(value_in != 0);
+/// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the
+/// Number.
+template <typename T>
+inline auto ValueOf(T value) {
+ if constexpr (std::is_same_v<UnwrapNumber<T>, T>) {
+ return value;
+ } else {
+ return value.value;
+ }
+}
+
+/// @returns true if `value` is a positive zero.
+template <typename T>
+inline bool IsPositiveZero(T value) {
+ using N = UnwrapNumber<T>;
+ return Number<N>(value) == Number<N>(0); // Considers sign bit
+}
+
+/// Constant inherits from sem::Constant to add an private implementation method for conversion.
+struct Constant : public sem::Constant {
+ /// Convert attempts to convert the constant value to the given type. On error, Convert()
+ /// creates a new diagnostic message and returns a Failure.
+ virtual utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const = 0;
+};
+
+// Forward declaration
+const Constant* CreateComposite(ProgramBuilder& builder,
+ const sem::Type* type,
+ std::vector<const Constant*> elements);
+
+/// Element holds a single scalar or abstract-numeric value.
+/// Element implements the Constant interface.
+template <typename T>
+struct Element : Constant {
+ Element(const sem::Type* t, T v) : type(t), value(v) {}
+ ~Element() override = default;
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override {
+ if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
+ return static_cast<AFloat>(value);
} else {
- T converted{};
- converter(converted, value_in);
- if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
- return AFloat(converted);
+ return static_cast<AInt>(value);
+ }
+ }
+ const Constant* Index(size_t) const override { return nullptr; }
+ bool AllZero() const override { return IsPositiveZero(value); }
+ bool AnyZero() const override { return IsPositiveZero(value); }
+ bool AllEqual() const override { return true; }
+ size_t Hash() const override { return utils::Hash(type, ValueOf(value)); }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
+ if (target_ty == type) {
+ // If the types are identical, then no conversion is needed.
+ return this;
+ }
+ bool failed = false;
+ auto* res = TypeDispatch(target_ty, [&](auto zero_to) -> const Constant* {
+ // `T` is the source type, `value` is the source value.
+ // `TO` is the target type.
+ using TO = std::decay_t<decltype(zero_to)>;
+ if constexpr (std::is_same_v<TO, bool>) {
+ // [x -> bool]
+ return builder.create<Element<TO>>(target_ty, !IsPositiveZero(value));
+ } else if constexpr (std::is_same_v<T, bool>) {
+ // [bool -> x]
+ return builder.create<Element<TO>>(target_ty, TO(value ? 1 : 0));
+ } else if (auto conv = CheckedConvert<TO>(value)) {
+ // Conversion success
+ return builder.create<Element<TO>>(target_ty, conv.Get());
+ // --- Below this point are the failure cases ---
+ } else if constexpr (std::is_same_v<T, AInt> || std::is_same_v<T, AFloat>) {
+ // [abstract-numeric -> x] - materialization failure
+ std::stringstream ss;
+ ss << "value " << value << " cannot be represented as ";
+ ss << "'" << builder.FriendlyName(target_ty) << "'";
+ builder.Diagnostics().add_error(tint::diag::System::Resolver, ss.str(), source);
+ failed = true;
+ } else if constexpr (IsFloatingPoint<UnwrapNumber<TO>>) {
+ // [x -> floating-point] - number not exactly representable
+ // https://www.w3.org/TR/WGSL/#floating-point-conversion
+ constexpr auto kInf = std::numeric_limits<double>::infinity();
+ switch (conv.Failure()) {
+ case ConversionFailure::kExceedsNegativeLimit:
+ return builder.create<Element<TO>>(target_ty, TO(-kInf));
+ case ConversionFailure::kExceedsPositiveLimit:
+ return builder.create<Element<TO>>(target_ty, TO(kInf));
+ }
} else {
- return AInt(converted);
+ // [x -> integer] - number not exactly representable
+ // https://www.w3.org/TR/WGSL/#floating-point-conversion
+ switch (conv.Failure()) {
+ case ConversionFailure::kExceedsNegativeLimit:
+ return builder.create<Element<TO>>(target_ty, TO(TO::kLowest));
+ case ConversionFailure::kExceedsPositiveLimit:
+ return builder.create<Element<TO>>(target_ty, TO(TO::kHighest));
+ }
}
+ return nullptr; // Expression is not constant.
+ });
+ if (failed) {
+ // A diagnostic error has been raised, and resolving should abort.
+ return utils::Failure;
}
- });
-
- TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
-}
-
-/// Converts and returns all the element values of `in` to the semantic type `el_ty`, using the
-/// converter function `CONVERTER`.
-/// @param in the constant to convert
-/// @param el_ty the target element type
-/// @param converter a function-like with the signature `void(TO&, FROM)`
-/// @returns the elements converted to `el_ty`
-template <typename CONVERTER>
-sem::Constant::Elements Transform(const sem::Constant::Elements& in,
- const sem::Type* el_ty,
- CONVERTER&& converter) {
- return std::visit(
- [&](auto&& v) {
- return Switch(
- el_ty, //
- [&](const sem::AbstractInt*) { return Transform<AInt>(v, converter); },
- [&](const sem::AbstractFloat*) { return Transform<AFloat>(v, converter); },
- [&](const sem::I32*) { return Transform<i32>(v, converter); },
- [&](const sem::U32*) { return Transform<u32>(v, converter); },
- [&](const sem::F32*) { return Transform<f32>(v, converter); },
- [&](const sem::F16*) { return Transform<f16>(v, converter); },
- [&](const sem::Bool*) { return Transform<bool>(v, converter); },
- [&](Default) -> sem::Constant::Elements {
- diag::List diags;
- TINT_UNREACHABLE(Semantic, diags)
- << "invalid element type " << el_ty->TypeInfo().name;
- return {};
- });
- },
- in);
-}
-
-/// Converts and returns all the elements in `in` to the type `el_ty`.
-/// If the value does not fit in the target type, and:
-/// * the target type is an integer type, then the resulting value will be clamped to the integer's
-/// highest or lowest value.
-/// * the target type is an float type, then the resulting value will be either positive or
-/// negative infinity, based on the sign of the input value.
-/// @param in the input elements
-/// @param el_ty the target element type
-/// @returns the elements converted to `el_ty`
-sem::Constant::Elements ConvertElements(const sem::Constant::Elements& in, const sem::Type* el_ty) {
- return Transform(in, el_ty, [](auto& el_out, auto el_in) {
- using OUT = std::decay_t<decltype(el_out)>;
- if (auto conv = CheckedConvert<OUT>(el_in)) {
- el_out = conv.Get();
- } else {
- constexpr auto kInf = std::numeric_limits<double>::infinity();
- switch (conv.Failure()) {
- case ConversionFailure::kExceedsNegativeLimit:
- el_out = IsFloatingPoint<UnwrapNumber<OUT>> ? OUT(-kInf) : OUT::kLowest;
- break;
- case ConversionFailure::kExceedsPositiveLimit:
- el_out = IsFloatingPoint<UnwrapNumber<OUT>> ? OUT(kInf) : OUT::kHighest;
- break;
- }
- }
- });
-}
-
-/// Converts and returns all the elements in `in` to the type `el_ty`, by performing a
-/// `CheckedConvert` on each element value. A single error diagnostic will be raised if an element
-/// value cannot be represented by the target type.
-/// @param in the input elements
-/// @param el_ty the target element type
-/// @returns the elements converted to `el_ty`, or a Failure if some elements could not be
-/// represented by the target type.
-utils::Result<sem::Constant::Elements> MaterializeElements(const sem::Constant::Elements& in,
- const sem::Type* el_ty,
- ProgramBuilder& builder,
- Source source) {
- std::optional<std::string> failure;
-
- auto out = Transform(in, el_ty, [&](auto& el_out, auto el_in) {
- using OUT = std::decay_t<decltype(el_out)>;
- if (auto conv = CheckedConvert<OUT>(el_in)) {
- el_out = conv.Get();
- } else if (!failure.has_value()) {
- std::stringstream ss;
- ss << "value " << el_in << " cannot be represented as ";
- ss << "'" << builder.FriendlyName(el_ty) << "'";
- failure = ss.str();
- }
- });
-
- if (failure.has_value()) {
- builder.Diagnostics().add_error(diag::System::Resolver, std::move(failure.value()), source);
- return utils::Failure;
+ return res;
+ TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
}
- return out;
+ sem::Type const* const type;
+ const T value;
+};
+
+/// Splat holds a single Constant value, duplicated as all children.
+/// Splat is used for zero-initializers, 'splat' constructors, or constructors where each element is
+/// identical. Splat may be of a vector, matrix or array type.
+/// Splat implements the Constant interface.
+struct Splat : Constant {
+ Splat(const sem::Type* t, const Constant* e, size_t n) : type(t), el(e), count(n) {}
+ ~Splat() override = default;
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const 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); }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ // Convert the single splatted element type.
+ auto conv_el = el->Convert(builder, sem::Type::ElementOf(target_ty), source);
+ if (!conv_el) {
+ return utils::Failure;
+ }
+ if (!conv_el.Get()) {
+ return nullptr;
+ }
+ return builder.create<Splat>(target_ty, conv_el.Get(), count);
+ }
+
+ sem::Type const* const type;
+ const 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.
+struct Composite : Constant {
+ Composite(const sem::Type* t, std::vector<const Constant*> 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 sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const Constant* Index(size_t i) const override {
+ return i < elements.size() ? 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; }
+
+ utils::Result<const Constant*> Convert(ProgramBuilder& builder,
+ const sem::Type* target_ty,
+ const Source& source) const override {
+ // Convert each of the composite element types.
+ auto* el_ty = sem::Type::ElementOf(target_ty);
+ std::vector<const Constant*> conv_els;
+ conv_els.reserve(elements.size());
+ for (auto* el : elements) {
+ auto conv_el = el->Convert(builder, el_ty, source);
+ if (!conv_el) {
+ return utils::Failure;
+ }
+ if (!conv_el.Get()) {
+ return nullptr;
+ }
+ conv_els.emplace_back(conv_el.Get());
+ }
+ return CreateComposite(builder, target_ty, std::move(conv_els));
+ }
+
+ size_t CalcHash() {
+ auto h = utils::Hash(type, all_zero, any_zero);
+ for (auto* el : elements) {
+ utils::HashCombine(&h, el->Hash());
+ }
+ return h;
+ }
+
+ sem::Type const* const type;
+ const std::vector<const Constant*> elements;
+ const bool all_zero;
+ const bool any_zero;
+ const size_t hash;
+};
+
+/// CreateElement constructs and returns an Element<T>.
+template <typename T>
+const Constant* CreateElement(ProgramBuilder& builder, const sem::Type* t, T v) {
+ return builder.create<Element<T>>(t, v);
+}
+
+/// ZeroValue returns a Constant for the zero-value of the type `type`.
+const Constant* ZeroValue(ProgramBuilder& builder, const sem::Type* type) {
+ return Switch(
+ type, //
+ [&](const sem::Vector* v) -> const Constant* {
+ auto* zero_el = ZeroValue(builder, v->type());
+ return builder.create<Splat>(type, zero_el, v->Width());
+ },
+ [&](const sem::Matrix* m) -> const Constant* {
+ auto* zero_el = ZeroValue(builder, m->ColumnType());
+ return builder.create<Splat>(type, zero_el, m->columns());
+ },
+ [&](const sem::Array* a) -> const Constant* {
+ if (auto* zero_el = ZeroValue(builder, a->ElemType())) {
+ return builder.create<Splat>(type, zero_el, a->Count());
+ }
+ return nullptr;
+ },
+ [&](Default) -> const Constant* {
+ return TypeDispatch(type, [&](auto zero) -> const Constant* {
+ return CreateElement(builder, type, zero);
+ });
+ });
+}
+
+/// Equal returns true if the constants `a` and `b` are of the same type and value.
+bool Equal(const sem::Constant* a, const sem::Constant* b) {
+ if (a->Hash() != b->Hash()) {
+ return false;
+ }
+ if (a->Type() != b->Type()) {
+ return false;
+ }
+ return Switch(
+ a->Type(), //
+ [&](const sem::Vector* vec) {
+ for (size_t i = 0; i < vec->Width(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](const sem::Matrix* mat) {
+ for (size_t i = 0; i < mat->columns(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](const sem::Array* arr) {
+ for (size_t i = 0; i < arr->Count(); i++) {
+ if (!Equal(a->Index(i), b->Index(i))) {
+ return false;
+ }
+ }
+ return true;
+ },
+ [&](Default) { return a->Value() == b->Value(); });
+}
+
+/// CreateComposite is used to construct a constant of a vector, matrix or array type.
+/// CreateComposite examines the element values and will return either a Composite or a Splat,
+/// depending on the element types and values.
+const Constant* CreateComposite(ProgramBuilder& builder,
+ const sem::Type* type,
+ std::vector<const Constant*> elements) {
+ if (elements.size() == 0) {
+ return nullptr;
+ }
+ bool any_zero = false;
+ bool all_zero = true;
+ bool all_equal = true;
+ auto* first = elements.front();
+ for (auto* el : elements) {
+ if (!any_zero && el->AnyZero()) {
+ any_zero = true;
+ }
+ if (all_zero && !el->AllZero()) {
+ all_zero = false;
+ }
+ if (all_equal && el != first) {
+ if (!Equal(el, first)) {
+ all_equal = false;
+ }
+ }
+ }
+ if (all_equal) {
+ return builder.create<Splat>(type, elements[0], elements.size());
+ } else {
+ return builder.create<Composite>(type, std::move(elements), all_zero, any_zero);
+ }
}
} // namespace
-sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type) {
+const sem::Constant* Resolver::EvaluateConstantValue(const ast::Expression* expr,
+ const sem::Type* type) {
return Switch(
expr, //
[&](const ast::IdentifierExpression* e) { return EvaluateConstantValue(e, type); },
@@ -160,112 +364,176 @@
[&](const ast::IndexAccessorExpression* e) { return EvaluateConstantValue(e, type); });
}
-sem::Constant Resolver::EvaluateConstantValue(const ast::IdentifierExpression* ident,
- const sem::Type*) {
+const sem::Constant* Resolver::EvaluateConstantValue(const ast::IdentifierExpression* ident,
+ const sem::Type*) {
if (auto* sem = builder_->Sem().Get(ident)) {
return sem->ConstantValue();
}
return {};
}
-sem::Constant Resolver::EvaluateConstantValue(const ast::LiteralExpression* literal,
- const sem::Type* type) {
+const sem::Constant* Resolver::EvaluateConstantValue(const ast::LiteralExpression* literal,
+ const sem::Type* type) {
return Switch(
literal,
[&](const ast::BoolLiteralExpression* lit) {
- return sem::Constant{type, {AInt(lit->value ? 1 : 0)}};
+ return CreateElement(*builder_, type, lit->value);
},
- [&](const ast::IntLiteralExpression* lit) {
- return sem::Constant{type, {AInt(lit->value)}};
+ [&](const ast::IntLiteralExpression* lit) -> const Constant* {
+ switch (lit->suffix) {
+ case ast::IntLiteralExpression::Suffix::kNone:
+ return CreateElement(*builder_, type, AInt(lit->value));
+ case ast::IntLiteralExpression::Suffix::kI:
+ return CreateElement(*builder_, type, i32(lit->value));
+ case ast::IntLiteralExpression::Suffix::kU:
+ return CreateElement(*builder_, type, u32(lit->value));
+ }
+ return nullptr;
},
- [&](const ast::FloatLiteralExpression* lit) {
- return sem::Constant{type, {AFloat(lit->value)}};
+ [&](const ast::FloatLiteralExpression* lit) -> const Constant* {
+ switch (lit->suffix) {
+ case ast::FloatLiteralExpression::Suffix::kNone:
+ return CreateElement(*builder_, type, AFloat(lit->value));
+ case ast::FloatLiteralExpression::Suffix::kF:
+ return CreateElement(*builder_, type, f32(lit->value));
+ case ast::FloatLiteralExpression::Suffix::kH:
+ return CreateElement(*builder_, type, f16(lit->value));
+ }
+ return nullptr;
});
}
-sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
- const sem::Type* ty) {
- uint32_t num_elems = 0;
- auto* el_ty = sem::Type::DeepestElementOf(ty, &num_elems);
- if (!el_ty || num_elems == 0) {
- return {};
- }
-
+const sem::Constant* Resolver::EvaluateConstantValue(const ast::CallExpression* call,
+ const sem::Type* ty) {
// Note: we are building constant values for array types. The working group as verbally agreed
// to support constant expression arrays, but this is not (yet) part of the spec.
// See: https://github.com/gpuweb/gpuweb/issues/3056
// For zero value init, return 0s
if (call->args.empty()) {
- return Switch(
- el_ty,
- [&](const sem::AbstractInt*) {
- return sem::Constant(ty, std::vector(num_elems, AInt(0)));
- },
- [&](const sem::AbstractFloat*) {
- return sem::Constant(ty, std::vector(num_elems, AFloat(0)));
- },
- [&](const sem::I32*) { return sem::Constant(ty, std::vector(num_elems, AInt(0))); },
- [&](const sem::U32*) { return sem::Constant(ty, std::vector(num_elems, AInt(0))); },
- [&](const sem::F32*) { return sem::Constant(ty, std::vector(num_elems, AFloat(0))); },
- [&](const sem::F16*) { return sem::Constant(ty, std::vector(num_elems, AFloat(0))); },
- [&](const sem::Bool*) { return sem::Constant(ty, std::vector(num_elems, AInt(0))); });
+ return ZeroValue(*builder_, ty);
}
- // Build value for type_ctor from each child value by converting to type_ctor's type.
- std::optional<sem::Constant::Elements> elements;
- for (auto* expr : call->args) {
- auto* arg = builder_->Sem().Get(expr);
+ uint32_t el_count = 0;
+ auto* el_ty = sem::Type::ElementOf(ty, &el_count);
+ if (!el_ty) {
+ return nullptr; // Target type does not support constant values
+ }
+
+ // value_of returns a `const Constant*` for the expression `expr`, or nullptr if the expression
+ // does not have a constant value.
+ auto value_of = [&](const ast::Expression* expr) {
+ return static_cast<const Constant*>(builder_->Sem().Get(expr)->ConstantValue());
+ };
+
+ if (call->args.size() == 1) {
+ // Type constructor or conversion that takes a single argument.
+ auto& src = call->args[0]->source;
+ auto* arg = value_of(call->args[0]);
if (!arg) {
- return {};
- }
- auto value = arg->ConstantValue();
- if (!value) {
- return {};
+ return nullptr; // Single argument is not constant.
}
- // Convert the elements to the desired type.
- auto converted = ConvertElements(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);
+ if (ty->is_scalar()) { // Scalar type conversion: i32(x), u32(x), bool(x), etc
+ return ConvertValue(arg, el_ty, src).Get();
}
+
+ if (arg->Type() == el_ty) {
+ // Argument type matches function type. This is a splat.
+ auto splat = [&](size_t n) { return builder_->create<Splat>(ty, arg, n); };
+ return Switch(
+ ty, //
+ [&](const sem::Vector* v) { return splat(v->Width()); },
+ [&](const sem::Matrix* m) { return splat(m->columns()); },
+ [&](const sem::Array* a) { return splat(a->Count()); });
+ }
+
+ // Argument type and function type mismatch. This is a type conversion.
+ if (auto conv = ConvertValue(arg, ty, src)) {
+ return conv.Get();
+ }
+
+ return nullptr;
}
- if (!elements) {
- return {};
- }
+ // Multiple arguments. Must be a type constructor.
- return std::visit(
- [&](auto&& v) {
- if (num_elems != v.size()) {
- if (v.size() == 1) {
- // Splat single-value initializers
- for (uint32_t i = 0; i < num_elems - 1; ++i) {
- v.emplace_back(v[0]);
+ std::vector<const Constant*> els; // The constant elements for the composite constant.
+ els.reserve(el_count);
+
+ // Helper for pushing all the argument constants to `els`.
+ auto push_all_args = [&] {
+ for (auto* expr : call->args) {
+ auto* arg = value_of(expr);
+ if (!arg) {
+ return;
+ }
+ els.emplace_back(arg);
+ }
+ };
+
+ Switch(
+ ty, // What's the target type being constructed?
+ [&](const sem::Vector*) {
+ // Vector can be constructed with a mix of scalars / abstract numerics and smaller
+ // vectors.
+ for (auto* expr : call->args) {
+ auto* arg = value_of(expr);
+ if (!arg) {
+ return;
+ }
+ auto* arg_ty = arg->Type();
+ if (auto* arg_vec = arg_ty->As<sem::Vector>()) {
+ // Extract out vector elements.
+ for (uint32_t i = 0; i < arg_vec->Width(); i++) {
+ auto* el = static_cast<const Constant*>(arg->Index(i));
+ if (!el) {
+ return;
+ }
+ els.emplace_back(el);
}
} else {
- // Provided number of arguments does not match the required number of elements.
- // Validation should error here.
- return sem::Constant{};
+ els.emplace_back(arg);
}
}
- return sem::Constant(ty, std::move(elements.value()));
},
- elements.value());
+ [&](const sem::Matrix* m) {
+ // Matrix can be constructed with a set of scalars / abstract numerics, or column
+ // vectors.
+ if (call->args.size() == m->columns() * m->rows()) {
+ // Matrix built from scalars / abstract numerics
+ for (uint32_t c = 0; c < m->columns(); c++) {
+ std::vector<const Constant*> column;
+ column.reserve(m->rows());
+ for (uint32_t r = 0; r < m->rows(); r++) {
+ auto* arg = value_of(call->args[r + c * m->rows()]);
+ if (!arg) {
+ return;
+ }
+ column.emplace_back(arg);
+ }
+ els.push_back(CreateComposite(*builder_, m->ColumnType(), std::move(column)));
+ }
+ } else if (call->args.size() == m->columns()) {
+ // Matrix built from column vectors
+ push_all_args();
+ }
+ },
+ [&](const sem::Array*) {
+ // Arrays must be constructed using a list of elements
+ push_all_args();
+ });
+
+ if (els.size() != el_count) {
+ // If the number of constant elements doesn't match the type, then something went wrong.
+ return nullptr;
+ }
+ // Construct and return either a Composite or Splat.
+ return CreateComposite(*builder_, ty, std::move(els));
}
-sem::Constant Resolver::EvaluateConstantValue(const ast::IndexAccessorExpression* accessor,
- const sem::Type* el_ty) {
+const sem::Constant* Resolver::EvaluateConstantValue(const ast::IndexAccessorExpression* accessor,
+ const sem::Type*) {
auto* obj_sem = builder_->Sem().Get(accessor->object);
if (!obj_sem) {
return {};
@@ -282,20 +550,14 @@
}
auto idx_val = idx_sem->ConstantValue();
- if (!idx_val || idx_val.ElementCount() != 1) {
+ if (!idx_val) {
return {};
}
- AInt idx = idx_val.Element<AInt>(0);
-
- // The immediate child element count.
uint32_t el_count = 0;
- sem::Type::ElementOf(obj_val.Type(), &el_count);
+ sem::Type::ElementOf(obj_val->Type(), &el_count);
- // The total number of most-nested elements per child element type.
- uint32_t step = 0;
- sem::Type::DeepestElementOf(el_ty, &step);
-
+ AInt idx = idx_val->As<AInt>();
if (idx < 0 || idx >= el_count) {
auto clamped = std::min<AInt::type>(std::max<AInt::type>(idx, 0), el_count - 1);
AddWarning("index " + std::to_string(idx) + " out of bounds [0.." +
@@ -305,32 +567,20 @@
idx = clamped;
}
- return sem::Constant{el_ty, obj_val.WithElements([&](auto&& v) {
- using VEC = std::decay_t<decltype(v)>;
- return sem::Constant::Elements(
- VEC(v.begin() + (idx * step), v.begin() + (idx + 1) * step));
- })};
+ return obj_val->Index(static_cast<size_t>(idx));
}
-utils::Result<sem::Constant> Resolver::ConvertValue(const sem::Constant& value,
- const sem::Type* ty,
- const Source& source) {
- if (value.Type() == ty) {
+utils::Result<const sem::Constant*> Resolver::ConvertValue(const sem::Constant* value,
+ const sem::Type* target_ty,
+ const Source& source) {
+ if (value->Type() == target_ty) {
return value;
}
-
- auto* el_ty = sem::Type::DeepestElementOf(ty);
- if (el_ty == nullptr) {
- return sem::Constant{};
+ auto conv = static_cast<const Constant*>(value)->Convert(*builder_, target_ty, source);
+ if (!conv) {
+ return utils::Failure;
}
- if (value.ElementType() == el_ty) {
- return sem::Constant(ty, value.GetElements());
- }
-
- if (auto res = MaterializeElements(value.GetElements(), el_ty, *builder_, source)) {
- return sem::Constant(ty, std::move(res.Get()));
- }
- return utils::Failure;
+ return conv.Get();
}
} // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_constants_test.cc b/src/tint/resolver/resolver_constants_test.cc
index 00b886d..ff8a189 100644
--- a/src/tint/resolver/resolver_constants_test.cc
+++ b/src/tint/resolver/resolver_constants_test.cc
@@ -14,10 +14,13 @@
#include "src/tint/resolver/resolver.h"
+#include <cmath>
+
#include "gtest/gtest.h"
#include "src/tint/resolver/resolver_test_helper.h"
#include "src/tint/sem/expression.h"
#include "src/tint/sem/index_accessor_expression.h"
+#include "src/tint/sem/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
@@ -39,10 +42,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AInt>(), 99);
}
TEST_F(ResolverConstantsTest, Scalar_u32) {
@@ -54,10 +58,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->Type()->Is<sem::U32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AInt>(), 99u);
}
TEST_F(ResolverConstantsTest, Scalar_f32) {
@@ -69,10 +74,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->Type()->Is<sem::F32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.9f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<AFloat>().value, 9.9f);
}
TEST_F(ResolverConstantsTest, Scalar_f16) {
@@ -85,11 +91,12 @@
auto* sem = Sem().Get(expr);
EXPECT_NE(sem, nullptr);
EXPECT_TRUE(sem->Type()->Is<sem::F16>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
// 9.9 is not exactly representable by f16, and should be quantized to 9.8984375
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.8984375f);
+ EXPECT_EQ(sem->ConstantValue()->As<AFloat>(), 9.8984375f);
}
TEST_F(ResolverConstantsTest, Scalar_bool) {
@@ -101,10 +108,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<bool>(), true);
}
TEST_F(ResolverConstantsTest, Vec3_ZeroInit_i32) {
@@ -119,12 +127,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 0);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 0);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 0);
}
TEST_F(ResolverConstantsTest, Vec3_ZeroInit_u32) {
@@ -139,12 +160,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::U32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 0u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 0u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 0u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 0u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 0u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 0u);
}
TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f32) {
@@ -159,12 +193,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 0.0);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0._a);
}
TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f16) {
@@ -180,12 +227,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 0.0);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 0._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0._a);
}
TEST_F(ResolverConstantsTest, Vec3_ZeroInit_bool) {
@@ -200,12 +260,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::Bool>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), false);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), false);
}
TEST_F(ResolverConstantsTest, Vec3_Splat_i32) {
@@ -220,12 +293,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 99);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 99);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 99);
}
TEST_F(ResolverConstantsTest, Vec3_Splat_u32) {
@@ -240,12 +326,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::U32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 99u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 99u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 99u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 99u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 99u);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 99u);
}
TEST_F(ResolverConstantsTest, Vec3_Splat_f32) {
@@ -260,12 +359,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 9.9f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 9.9f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 9.9f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 9.9f);
}
TEST_F(ResolverConstantsTest, Vec3_Splat_f16) {
@@ -281,13 +393,26 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
// 9.9 is not exactly representable by f16, and should be quantized to 9.8984375
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 9.8984375f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 9.8984375f);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 9.8984375f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 9.8984375f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 9.8984375f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 9.8984375f);
}
TEST_F(ResolverConstantsTest, Vec3_Splat_bool) {
@@ -302,12 +427,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::Bool>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
}
TEST_F(ResolverConstantsTest, Vec3_FullConstruct_i32) {
@@ -322,12 +460,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
}
TEST_F(ResolverConstantsTest, Vec3_FullConstruct_u32) {
@@ -342,12 +493,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::U32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
}
TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f32) {
@@ -362,12 +526,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 3.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
}
TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f16) {
@@ -383,12 +560,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 3.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
}
TEST_F(ResolverConstantsTest, Vec3_FullConstruct_bool) {
@@ -403,12 +593,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::Bool>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
}
TEST_F(ResolverConstantsTest, Vec3_MixConstruct_i32) {
@@ -423,12 +626,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
}
TEST_F(ResolverConstantsTest, Vec3_MixConstruct_u32) {
@@ -443,12 +659,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::U32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
}
TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32) {
@@ -463,12 +692,157 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 3.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32_all_10) {
+ auto* expr = vec3<f32>(10_f, vec2<f32>(10_f, 10_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 10_f);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32_all_positive_0) {
+ auto* expr = vec3<f32>(0_f, vec2<f32>(0_f, 0_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32_all_negative_0) {
+ auto* expr = vec3<f32>(vec2<f32>(-0_f, -0_f), -0_f);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), -0_f);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32_mixed_sign_0) {
+ auto* expr = vec3<f32>(0_f, vec2<f32>(-0_f, 0_f));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F32>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), -0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
}
TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f16) {
@@ -484,12 +858,161 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 3.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 1.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 2.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 3.f);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f16_all_10) {
+ Enable(ast::Extension::kF16);
+ auto* expr = vec3<f16>(10_h, vec2<f16>(10_h, 10_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 10_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), 10_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 10_h);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f16_all_positive_0) {
+ Enable(ast::Extension::kF16);
+ auto* expr = vec3<f16>(0_h, vec2<f16>(0_h, 0_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 0_h);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f16_all_negative_0) {
+ Enable(ast::Extension::kF16);
+ auto* expr = vec3<f16>(vec2<f16>(-0_h, -0_h), -0_h);
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), -0_h);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f16_mixed_sign_0) {
+ Enable(ast::Extension::kF16);
+ auto* expr = vec3<f16>(0_h, vec2<f16>(-0_h, 0_h));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ EXPECT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::F16>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f16>(), 0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f16>(), -0_h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f16>(), 0_h);
}
TEST_F(ResolverConstantsTest, Vec3_MixConstruct_bool) {
@@ -504,12 +1027,91 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::Bool>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(0), true);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(1), false);
- EXPECT_EQ(sem->ConstantValue().Element<bool>(2), true);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_all_true) {
+ auto* expr = vec3<bool>(true, vec2<bool>(true, true));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), true);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), true);
+}
+
+TEST_F(ResolverConstantsTest, Vec3_MixConstruct_all_false) {
+ auto* expr = vec3<bool>(false, vec2<bool>(false, false));
+ WrapInFunction(expr);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ auto* sem = Sem().Get(expr);
+ ASSERT_NE(sem, nullptr);
+ auto* vec = sem->Type()->As<sem::Vector>();
+ ASSERT_NE(vec, nullptr);
+ EXPECT_TRUE(vec->type()->Is<sem::Bool>());
+ EXPECT_EQ(vec->Width(), 3u);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<bool>(), false);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<bool>(), false);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_f32_to_i32) {
@@ -524,12 +1126,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_u32_to_f32) {
@@ -544,12 +1159,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 30.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 10.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 20.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 30.f);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_f16_to_i32) {
@@ -565,12 +1193,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, 1);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, 2);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, 3);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), 1_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), 2_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), 3_i);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_u32_to_f16) {
@@ -586,12 +1227,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 30.f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 10.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), 20.f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 30.f);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_i32) {
@@ -606,12 +1260,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::I32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, i32::kHighest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, i32::kLowest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, i32::kHighest);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), i32::kHighest);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), i32::kLowest);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), i32::kHighest);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_u32) {
@@ -626,12 +1293,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::U32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(0).value, u32::kHighest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(1).value, u32::kLowest);
- EXPECT_EQ(sem->ConstantValue().Element<AInt>(2).value, u32::kHighest);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AInt>(), u32::kHighest);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AInt>(), u32::kLowest);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AInt>(), u32::kHighest);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_f16) {
@@ -650,12 +1330,25 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, kInf);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, -kInf);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, kInf);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), kInf);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -kInf);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), kInf);
}
TEST_F(ResolverConstantsTest, Vec3_Convert_Small_f32_to_f16) {
@@ -672,12 +1365,28 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F16>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- 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>(2).value, 0.0);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<AFloat>(), 0.0);
+ EXPECT_FALSE(std::signbit(sem->ConstantValue()->Index(0)->As<AFloat>().value));
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<AFloat>(), -0.0);
+ EXPECT_TRUE(std::signbit(sem->ConstantValue()->Index(1)->As<AFloat>().value));
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<AFloat>(), 0.0);
+ EXPECT_FALSE(std::signbit(sem->ConstantValue()->Index(2)->As<AFloat>().value));
}
TEST_F(ResolverConstantsTest, Mat2x3_ZeroInit_f32) {
@@ -693,15 +1402,40 @@
EXPECT_TRUE(mat->type()->Is<sem::F32>());
EXPECT_EQ(mat->columns(), 2u);
EXPECT_EQ(mat->rows(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 0._f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 0._f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 0._f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(3).value, 0._f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(4).value, 0._f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(5).value, 0._f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0._f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0._f);
}
TEST_F(ResolverConstantsTest, Mat2x3_ZeroInit_f16) {
@@ -719,15 +1453,40 @@
EXPECT_TRUE(mat->type()->Is<sem::F16>());
EXPECT_EQ(mat->columns(), 2u);
EXPECT_EQ(mat->rows(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F16>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(0).value, 0._h);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(1).value, 0._h);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(2).value, 0._h);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(3).value, 0._h);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(4).value, 0._h);
- EXPECT_EQ(sem->ConstantValue().Element<f16>(5).value, 0._h);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f16>(), 0._h);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f16>(), 0._h);
}
TEST_F(ResolverConstantsTest, Mat3x2_Construct_Scalars_af) {
@@ -743,15 +1502,40 @@
EXPECT_TRUE(mat->type()->Is<sem::F32>());
EXPECT_EQ(mat->columns(), 3u);
EXPECT_EQ(mat->rows(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(3).value, 4._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(4).value, 5._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(5).value, 6._a);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<AFloat>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<AFloat>(), 2._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<AFloat>(), 3._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<AFloat>(), 4._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<AFloat>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<AFloat>(), 6._a);
}
TEST_F(ResolverConstantsTest, Mat3x2_Construct_Columns_af) {
@@ -770,15 +1554,40 @@
EXPECT_TRUE(mat->type()->Is<sem::F32>());
EXPECT_EQ(mat->columns(), 3u);
EXPECT_EQ(mat->rows(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(0).value, 1._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(1).value, 2._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(2).value, 3._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(3).value, 4._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(4).value, 5._a);
- EXPECT_EQ(sem->ConstantValue().Element<AFloat>(5).value, 6._a);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<AFloat>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<AFloat>(), 2._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<AFloat>(), 3._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<AFloat>(), 4._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(0)->As<AFloat>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->Index(1)->As<AFloat>(), 6._a);
}
TEST_F(ResolverConstantsTest, Array_i32_Zero) {
@@ -793,13 +1602,30 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::I32>());
EXPECT_EQ(arr->Count(), 4u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 4u);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(0).value, 0_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(1).value, 0_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(2).value, 0_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(3).value, 0_i);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<i32>(), 0_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<i32>(), 0_i);
}
TEST_F(ResolverConstantsTest, Array_f32_Zero) {
@@ -814,13 +1640,30 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::F32>());
EXPECT_EQ(arr->Count(), 4u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 4u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(3).value, 0_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f32>(), 0_f);
}
TEST_F(ResolverConstantsTest, Array_vec3_f32_Zero) {
@@ -835,15 +1678,40 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::Vector>());
EXPECT_EQ(arr->Count(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(3).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(4).value, 0_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(5).value, 0_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 0_f);
}
TEST_F(ResolverConstantsTest, Array_i32_Elements) {
@@ -858,13 +1726,30 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::I32>());
EXPECT_EQ(arr->Count(), 4u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 4u);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(0).value, 10_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(1).value, 20_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(2).value, 30_i);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(3).value, 40_i);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<i32>(), 10_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<i32>(), 20_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<i32>(), 30_i);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<i32>(), 40_i);
}
TEST_F(ResolverConstantsTest, Array_f32_Elements) {
@@ -879,13 +1764,30 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::F32>());
EXPECT_EQ(arr->Count(), 4u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 4u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 10_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 20_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 30_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(3).value, 40_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 20_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 30_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(3)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(3)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(3)->As<f32>(), 40_f);
}
TEST_F(ResolverConstantsTest, Array_vec3_f32_Elements) {
@@ -901,15 +1803,16 @@
ASSERT_NE(arr, nullptr);
EXPECT_TRUE(arr->ElemType()->Is<sem::Vector>());
EXPECT_EQ(arr->Count(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 1_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 2_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 3_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(3).value, 4_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(4).value, 5_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(5).value, 6_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(0)->As<f32>(), 4_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(1)->As<f32>(), 5_f);
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -925,10 +1828,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
ASSERT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(0).value, 3_i);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 3_i);
}
TEST_F(ResolverConstantsTest, Vec3_Index_OOB_High) {
@@ -941,10 +1845,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
ASSERT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(0).value, 3_i);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 3_i);
}
TEST_F(ResolverConstantsTest, Vec3_Index_OOB_Low) {
@@ -957,10 +1862,11 @@
auto* sem = Sem().Get(expr);
ASSERT_NE(sem, nullptr);
ASSERT_TRUE(sem->Type()->Is<sem::I32>());
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(sem->ConstantValue().Element<i32>(0).value, 1_i);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_TRUE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->As<i32>(), 1_i);
}
TEST_F(ResolverConstantsTest, Mat3x2_Index) {
@@ -975,11 +1881,17 @@
auto* vec = sem->Type()->As<sem::Vector>();
ASSERT_NE(vec, nullptr);
EXPECT_EQ(vec->Width(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 2u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 5._a);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 6._a);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 6._a);
}
TEST_F(ResolverConstantsTest, Mat3x2_Index_OOB_High) {
@@ -996,11 +1908,17 @@
auto* vec = sem->Type()->As<sem::Vector>();
ASSERT_NE(vec, nullptr);
EXPECT_EQ(vec->Width(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 2u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 5._a);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 6._a);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 5._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 6._a);
}
TEST_F(ResolverConstantsTest, Mat3x2_Index_OOB_Low) {
@@ -1017,11 +1935,17 @@
auto* vec = sem->Type()->As<sem::Vector>();
ASSERT_NE(vec, nullptr);
EXPECT_EQ(vec->Width(), 2u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 2u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 1._a);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 2._a);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1._a);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2._a);
}
TEST_F(ResolverConstantsTest, Array_vec3_f32_Index) {
@@ -1038,12 +1962,22 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 4_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 5_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 6_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 6_f);
}
TEST_F(ResolverConstantsTest, Array_vec3_f32_Index_OOB_High) {
@@ -1061,12 +1995,22 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 4_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 5_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 6_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 6_f);
}
TEST_F(ResolverConstantsTest, Array_vec3_f32_Index_OOB_Low) {
@@ -1084,19 +2028,32 @@
ASSERT_NE(vec, nullptr);
EXPECT_TRUE(vec->type()->Is<sem::F32>());
EXPECT_EQ(vec->Width(), 3u);
- EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
- EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(0).value, 1_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(1).value, 2_f);
- EXPECT_EQ(sem->ConstantValue().Element<f32>(2).value, 3_f);
+ EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
+ EXPECT_FALSE(sem->ConstantValue()->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(sem->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(sem->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(sem->ConstantValue()->Index(2)->As<f32>(), 3_f);
}
TEST_F(ResolverConstantsTest, ChainedIndex) {
auto* arr_expr = Construct(ty.array(ty.mat2x3<f32>(), 2_u), // array<mat2x3<f32>, 2u>
mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), //
vec3<f32>(4_f, 5_f, 6_f)), //
- mat2x3<f32>(vec3<f32>(7_f, 8_f, 9_f), //
+ mat2x3<f32>(vec3<f32>(7_f, 0_f, 9_f), //
vec3<f32>(10_f, 11_f, 12_f)));
auto* mat_expr = IndexAccessor(arr_expr, 1_i); // arr[1]
@@ -1114,15 +2071,40 @@
EXPECT_TRUE(ty->ColumnType()->Is<sem::Vector>());
EXPECT_EQ(ty->columns(), 2u);
EXPECT_EQ(ty->rows(), 3u);
- EXPECT_EQ(mat->ConstantValue().Type(), mat->Type());
- EXPECT_TRUE(mat->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(mat->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(0).value, 7_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(1).value, 8_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(2).value, 9_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(3).value, 10_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(4).value, 11_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(5).value, 12_f);
+ EXPECT_EQ(mat->ConstantValue()->Type(), mat->Type());
+ EXPECT_FALSE(mat->ConstantValue()->AllEqual());
+ EXPECT_TRUE(mat->ConstantValue()->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(0)->As<f32>(), 7_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(2)->As<f32>(), 9_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(0)->As<f32>(), 10_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(1)->As<f32>(), 11_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(2)->As<f32>(), 12_f);
}
{
auto* vec = Sem().Get(vec_expr);
@@ -1131,21 +2113,35 @@
ASSERT_NE(vec->Type(), nullptr);
EXPECT_TRUE(ty->type()->Is<sem::F32>());
EXPECT_EQ(ty->Width(), 3u);
- EXPECT_EQ(vec->ConstantValue().Type(), vec->Type());
- EXPECT_TRUE(vec->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(vec->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(0).value, 7_f);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(1).value, 8_f);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(2).value, 9_f);
+ EXPECT_EQ(vec->ConstantValue()->Type(), vec->Type());
+ EXPECT_FALSE(vec->ConstantValue()->AllEqual());
+ EXPECT_TRUE(vec->ConstantValue()->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(0)->As<f32>(), 7_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(1)->As<f32>(), 0_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(2)->As<f32>(), 9_f);
}
{
auto* f = Sem().Get(f32_expr);
EXPECT_NE(f, nullptr);
EXPECT_TRUE(f->Type()->Is<sem::F32>());
- EXPECT_EQ(f->ConstantValue().Type(), f->Type());
- EXPECT_TRUE(f->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(f->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(f->ConstantValue().Element<f32>(0).value, 9_f);
+ EXPECT_EQ(f->ConstantValue()->Type(), f->Type());
+ EXPECT_TRUE(f->ConstantValue()->AllEqual());
+ EXPECT_FALSE(f->ConstantValue()->AnyZero());
+ EXPECT_FALSE(f->ConstantValue()->AllZero());
+ EXPECT_EQ(f->ConstantValue()->As<f32>(), 9_f);
}
}
@@ -1174,15 +2170,40 @@
EXPECT_TRUE(ty->ColumnType()->Is<sem::Vector>());
EXPECT_EQ(ty->columns(), 2u);
EXPECT_EQ(ty->rows(), 3u);
- EXPECT_EQ(mat->ConstantValue().Type(), mat->Type());
- EXPECT_TRUE(mat->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(mat->ConstantValue().ElementCount(), 6u);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(0).value, 1_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(1).value, 2_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(2).value, 3_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(3).value, 4_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(4).value, 5_f);
- EXPECT_EQ(mat->ConstantValue().Element<f32>(5).value, 6_f);
+ EXPECT_EQ(mat->ConstantValue()->Type(), mat->Type());
+ EXPECT_FALSE(mat->ConstantValue()->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(0)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(0)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(0)->Index(2)->As<f32>(), 3_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(0)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(0)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(0)->As<f32>(), 4_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(1)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(1)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(1)->As<f32>(), 5_f);
+
+ EXPECT_TRUE(mat->ConstantValue()->Index(1)->Index(2)->AllEqual());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AnyZero());
+ EXPECT_FALSE(mat->ConstantValue()->Index(1)->Index(2)->AllZero());
+ EXPECT_EQ(mat->ConstantValue()->Index(1)->Index(2)->As<f32>(), 6_f);
}
{
auto* vec = Sem().Get(vec_expr);
@@ -1191,21 +2212,35 @@
ASSERT_NE(vec->Type(), nullptr);
EXPECT_TRUE(ty->type()->Is<sem::F32>());
EXPECT_EQ(ty->Width(), 3u);
- EXPECT_EQ(vec->ConstantValue().Type(), vec->Type());
- EXPECT_TRUE(vec->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(vec->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(0).value, 1_f);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(1).value, 2_f);
- EXPECT_EQ(vec->ConstantValue().Element<f32>(2).value, 3_f);
+ EXPECT_EQ(vec->ConstantValue()->Type(), vec->Type());
+ EXPECT_FALSE(vec->ConstantValue()->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->AllZero());
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(0)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(0)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(0)->As<f32>(), 1_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(1)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(1)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(1)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(1)->As<f32>(), 2_f);
+
+ EXPECT_TRUE(vec->ConstantValue()->Index(2)->AllEqual());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AnyZero());
+ EXPECT_FALSE(vec->ConstantValue()->Index(2)->AllZero());
+ EXPECT_EQ(vec->ConstantValue()->Index(2)->As<f32>(), 3_f);
}
{
auto* f = Sem().Get(f32_expr);
EXPECT_NE(f, nullptr);
EXPECT_TRUE(f->Type()->Is<sem::F32>());
- EXPECT_EQ(f->ConstantValue().Type(), f->Type());
- EXPECT_TRUE(f->ConstantValue().ElementType()->Is<sem::F32>());
- ASSERT_EQ(f->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(f->ConstantValue().Element<f32>(0).value, 3_f);
+ EXPECT_EQ(f->ConstantValue()->Type(), f->Type());
+ EXPECT_TRUE(f->ConstantValue()->AllEqual());
+ EXPECT_FALSE(f->ConstantValue()->AnyZero());
+ EXPECT_FALSE(f->ConstantValue()->AllZero());
+ EXPECT_EQ(f->ConstantValue()->As<f32>(), 3_f);
}
}
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 0048d74..558cb12 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -1604,16 +1604,16 @@
auto& signature = builtin->Signature();
auto check_arg_is_constexpr = [&](sem::ParameterUsage usage, int min, int max) {
- auto index = signature.IndexOf(usage);
- if (index < 0) {
+ auto signed_index = signature.IndexOf(usage);
+ if (signed_index < 0) {
return true;
}
+ auto index = static_cast<size_t>(signed_index);
std::string name = sem::str(usage);
- auto* arg = call->Arguments()[static_cast<size_t>(index)];
+ auto* arg = call->Arguments()[index];
if (auto values = arg->ConstantValue()) {
// Assert that the constant values are of the expected type.
- if (!values.Type()->IsAnyOf<sem::I32, sem::Vector>() ||
- !values.ElementType()->Is<sem::I32>()) {
+ if (!values->Type()->is_integer_scalar_or_vector()) {
TINT_ICE(Resolver, diagnostics_)
<< "failed to resolve '" + func_name + "' " << name << " parameter type";
return false;
@@ -1631,25 +1631,26 @@
return ast::TraverseAction::Stop;
});
if (is_const_expr) {
- auto vector =
- builtin->Parameters()[static_cast<size_t>(index)]->Type()->Is<sem::Vector>();
- for (size_t i = 0, n = values.ElementCount(); i < n; i++) {
- auto value = values.Element<AInt>(i).value;
- if (value < min || value > max) {
- if (vector) {
+ if (auto* vector = builtin->Parameters()[index]->Type()->As<sem::Vector>()) {
+ for (size_t i = 0; i < vector->Width(); i++) {
+ auto value = values->Index(i)->As<AInt>();
+ if (value < min || value > max) {
AddError("each component of the " + name +
" argument must be at least " + std::to_string(min) +
" and at most " + std::to_string(max) + ". " + name +
" component " + std::to_string(i) + " is " +
std::to_string(value),
arg->Declaration()->source);
- } else {
- AddError("the " + name + " argument must be at least " +
- std::to_string(min) + " and at most " +
- std::to_string(max) + ". " + name + " is " +
- std::to_string(value),
- arg->Declaration()->source);
+ return false;
}
+ }
+ } else {
+ auto value = values->As<AInt>();
+ if (value < min || value > max) {
+ AddError("the " + name + " argument must be at least " +
+ std::to_string(min) + " and at most " + std::to_string(max) +
+ ". " + name + " is " + std::to_string(value),
+ arg->Declaration()->source);
return false;
}
}
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index 2ee5979..7eb0dea 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -920,21 +920,13 @@
ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
- EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue().AllZero());
-
- EXPECT_EQ(Sem().Get(c_i32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_u32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_f32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_vi32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vu32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vf32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_mf32)->ConstantValue().ElementCount(), 9u);
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
}
TEST_F(ResolverVariableTest, LocalConst_ImplicitType_Decls) {
@@ -949,7 +941,11 @@
auto* c_vai = Const("i", nullptr, Construct(ty.vec(nullptr, 3), Expr(0_a)));
auto* c_vaf = Const("j", nullptr, Construct(ty.vec(nullptr, 3), Expr(0._a)));
auto* c_mf32 = Const("k", nullptr, mat3x3<f32>());
- auto* c_maf32 = Const("l", nullptr, Construct(ty.mat(nullptr, 3, 3), Expr(0._a)));
+ auto* c_maf32 = Const("l", nullptr,
+ Construct(ty.mat(nullptr, 3, 3), //
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a))));
WrapInFunction(c_i32, c_u32, c_f32, c_ai, c_af, c_vi32, c_vu32, c_vf32, c_vai, c_vaf, c_mf32,
c_maf32);
@@ -982,31 +978,18 @@
ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
ASSERT_TRUE(TypeOf(c_maf32)->Is<sem::Matrix>());
- EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_af)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue().AllZero());
-
- EXPECT_EQ(Sem().Get(c_i32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_u32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_f32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_ai)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_af)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_vi32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vu32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vf32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vai)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vaf)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_mf32)->ConstantValue().ElementCount(), 9u);
- EXPECT_EQ(Sem().Get(c_maf32)->ConstantValue().ElementCount(), 9u);
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_af)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue()->AllZero());
}
TEST_F(ResolverVariableTest, LocalConst_PropagateConstValue) {
@@ -1020,8 +1003,7 @@
ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
- ASSERT_EQ(Sem().Get(c)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c)->ConstantValue().Element<i32>(0), 42_i);
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 42_i);
}
// Enable when we have @const operators implemented
@@ -1034,8 +1016,7 @@
ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
- ASSERT_EQ(Sem().Get(c)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c)->ConstantValue().Element<i32>(0), 3_i);
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 3_i);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1126,21 +1107,13 @@
ASSERT_TRUE(TypeOf(c_vf32)->Is<sem::Vector>());
ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
- EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue().AllZero());
-
- EXPECT_EQ(Sem().Get(c_i32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_u32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_f32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_vi32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vu32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vf32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_mf32)->ConstantValue().ElementCount(), 9u);
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
}
TEST_F(ResolverVariableTest, GlobalConst_ImplicitType_Decls) {
@@ -1155,7 +1128,11 @@
auto* c_vai = GlobalConst("i", nullptr, Construct(ty.vec(nullptr, 3), Expr(0_a)));
auto* c_vaf = GlobalConst("j", nullptr, Construct(ty.vec(nullptr, 3), Expr(0._a)));
auto* c_mf32 = GlobalConst("k", nullptr, mat3x3<f32>());
- auto* c_maf32 = GlobalConst("l", nullptr, Construct(ty.mat(nullptr, 3, 3), Expr(0._a)));
+ auto* c_maf32 = GlobalConst("l", nullptr,
+ Construct(ty.mat(nullptr, 3, 3), //
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a)),
+ Construct(ty.vec(nullptr, 3), Expr(0._a))));
ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1185,31 +1162,18 @@
ASSERT_TRUE(TypeOf(c_mf32)->Is<sem::Matrix>());
ASSERT_TRUE(TypeOf(c_maf32)->Is<sem::Matrix>());
- EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_af)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue().AllZero());
- EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue().AllZero());
-
- EXPECT_EQ(Sem().Get(c_i32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_u32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_f32)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_ai)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_af)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c_vi32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vu32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vf32)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vai)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_vaf)->ConstantValue().ElementCount(), 3u);
- EXPECT_EQ(Sem().Get(c_mf32)->ConstantValue().ElementCount(), 9u);
- EXPECT_EQ(Sem().Get(c_maf32)->ConstantValue().ElementCount(), 9u);
+ EXPECT_TRUE(Sem().Get(c_i32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_u32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_f32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_ai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_af)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vi32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vu32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vai)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_vaf)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_mf32)->ConstantValue()->AllZero());
+ EXPECT_TRUE(Sem().Get(c_maf32)->ConstantValue()->AllZero());
}
TEST_F(ResolverVariableTest, GlobalConst_PropagateConstValue) {
@@ -1221,8 +1185,7 @@
ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
- ASSERT_EQ(Sem().Get(c)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c)->ConstantValue().Element<i32>(0), 42_i);
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 42_i);
}
// Enable when we have @const operators implemented
@@ -1233,8 +1196,7 @@
ASSERT_TRUE(TypeOf(c)->Is<sem::I32>());
- ASSERT_EQ(Sem().Get(c)->ConstantValue().ElementCount(), 1u);
- EXPECT_EQ(Sem().Get(c)->ConstantValue().Element<i32>(0), 3_i);
+ EXPECT_EQ(Sem().Get(c)->ConstantValue()->As<i32>(), 3_i);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/sem/call.cc b/src/tint/sem/call.cc
index f688cce..bfce3b1 100644
--- a/src/tint/sem/call.cc
+++ b/src/tint/sem/call.cc
@@ -25,9 +25,9 @@
const CallTarget* target,
std::vector<const sem::Expression*> arguments,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects)
- : Base(declaration, target->ReturnType(), statement, std::move(constant), has_side_effects),
+ : Base(declaration, target->ReturnType(), statement, constant, has_side_effects),
target_(target),
arguments_(std::move(arguments)) {}
diff --git a/src/tint/sem/call.h b/src/tint/sem/call.h
index e27f388..1955bf9 100644
--- a/src/tint/sem/call.h
+++ b/src/tint/sem/call.h
@@ -38,7 +38,7 @@
const CallTarget* target,
std::vector<const sem::Expression*> arguments,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects);
/// Destructor
diff --git a/src/tint/sem/constant.cc b/src/tint/sem/constant.cc
index ed38686..70bb08c 100644
--- a/src/tint/sem/constant.cc
+++ b/src/tint/sem/constant.cc
@@ -14,102 +14,10 @@
#include "src/tint/sem/constant.h"
-#include <cmath>
-#include <utility>
-
-#include "src/tint/debug.h"
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/type.h"
-
namespace tint::sem {
-namespace {
-size_t CountElements(const Constant::Elements& elements) {
- return std::visit([](auto&& vec) { return vec.size(); }, elements);
-}
-
-template <typename T>
-bool IsNegativeFloat(T value) {
- (void)value;
- if constexpr (IsFloatingPoint<T>) {
- return std::signbit(value);
- } else {
- return false;
- }
-}
-
-} // namespace
-
-Constant::Constant() {}
-
-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;
+Constant::Constant() = default;
Constant::~Constant() = default;
-Constant& Constant::operator=(const Constant& rhs) = default;
-
-bool Constant::AnyZero() const {
- return WithElements([&](auto&& vec) {
- using T = typename std::decay_t<decltype(vec)>::value_type;
- for (auto el : vec) {
- if (el == T(0) && !IsNegativeFloat(el.value)) {
- return true;
- }
- }
- return false;
- });
-}
-
-bool Constant::AllZero(size_t start, size_t end) const {
- return WithElements([&](auto&& vec) {
- using T = typename std::decay_t<decltype(vec)>::value_type;
- for (size_t i = start; i < end; i++) {
- auto el = vec[i];
- if (el != T(0) || IsNegativeFloat(el.value)) {
- return false;
- }
- }
- return true;
- });
-}
-
-bool Constant::AllEqual(size_t start, size_t end) const {
- return WithElements([&](auto&& vec) {
- if (!vec.empty()) {
- auto value = vec[start];
- bool float_sign = IsNegativeFloat(vec[start].value);
- for (size_t i = start + 1; i < end; i++) {
- if (vec[i] != value || float_sign != IsNegativeFloat(vec[i].value)) {
- return false;
- }
- }
- }
- return true;
- });
-}
-
-const Type* Constant::CheckElemType(const sem::Type* ty, size_t num_elements) {
- diag::List diag;
- uint32_t count = 0;
- auto* el_ty = Type::DeepestElementOf(ty, &count);
- if (!el_ty) {
- TINT_ICE(Semantic, diag) << "Unsupported sem::Constant type: " << ty->TypeInfo().name;
- return nullptr;
- }
- if (num_elements != count) {
- TINT_ICE(Semantic, diag) << "sem::Constant() type <-> element mismatch. type: '"
- << ty->TypeInfo().name << "' provided: " << num_elements
- << " require: " << count;
- }
- TINT_ASSERT(Semantic, el_ty->is_abstract_or_scalar());
- return el_ty;
-}
-
} // namespace tint::sem
diff --git a/src/tint/sem/constant.h b/src/tint/sem/constant.h
index cd73a79..b46127c 100644
--- a/src/tint/sem/constant.h
+++ b/src/tint/sem/constant.h
@@ -15,10 +15,7 @@
#ifndef SRC_TINT_SEM_CONSTANT_H_
#define SRC_TINT_SEM_CONSTANT_H_
-#include <ostream>
-#include <utility>
#include <variant>
-#include <vector>
#include "src/tint/number.h"
@@ -29,167 +26,53 @@
namespace tint::sem {
-/// 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.
+/// Constant is the interface to a compile-time evaluated expression value.
class Constant {
public:
- /// 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>;
-
- /// 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 AInt or AFloat based on the element type T.
- template <typename T>
- using ElementFor = std::conditional_t<IsFloatingPoint<UnwrapNumber<T>>, AFloat, AInt>;
-
- /// 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
+ /// Constructor
Constant();
- /// Constructs a Constant of the given type and element values
- /// @param ty the Constant type
- /// @param els the Constant element values
- 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&);
-
/// Destructor
- ~Constant();
+ virtual ~Constant();
- /// Copy assignment
- /// @param other the Constant to copy
- /// @returns this Constant
- Constant& operator=(const Constant& other);
+ /// @returns the type of the constant
+ virtual const sem::Type* Type() const = 0;
- /// @returns true if the Constant has been initialized
- bool IsValid() const { return type_ != nullptr; }
+ /// @returns the value of this Constant, if this constant is of a scalar value or abstract
+ /// numeric, otherwsie std::monostate.
+ virtual std::variant<std::monostate, AInt, AFloat> Value() const = 0;
- /// @return true if the Constant has been initialized
- operator bool() const { return IsValid(); }
+ /// @returns the child constant element with the given index, or nullptr if the constant has no
+ /// children, or the index is out of bounds.
+ virtual const Constant* Index(size_t) const = 0;
- /// @returns the type of the Constant
- const sem::Type* Type() const { return type_; }
+ /// @returns true if child elements of this constant are positive-zero valued.
+ virtual bool AllZero() const = 0;
- /// @returns the number of elements
- size_t ElementCount() const {
- return std::visit([](auto&& v) { return v.size(); }, elems_);
- }
+ /// @returns true if any child elements of this constant are positive-zero valued.
+ virtual bool AnyZero() const = 0;
- /// @returns the flattened element type of the Constant
- const sem::Type* ElementType() const { return elem_type_; }
+ /// @returns true if all child elements of this constant have the same value and type.
+ virtual bool AllEqual() const = 0;
- /// @returns the constant's flattened elements
- const Elements& GetElements() const { return elems_; }
+ /// @returns a hash of the constant.
+ virtual size_t Hash() const = 0;
- /// 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 positive zero
- bool AnyZero() const;
-
- /// @returns true if all elements are positive zero
- bool AllZero() const { return AllZero(0, ElementCount()); }
-
- /// @returns true if all elements are the same value, with the same sign-bit.
- bool AllEqual() const { return AllEqual(0, ElementCount()); }
-
- /// @param start the first element index
- /// @param end one past the last element index
- /// @returns true if all elements between `[start, end)` are zero
- bool AllZero(size_t start, size_t end) const;
-
- /// @param start the first element index
- /// @param end one past the last element index
- /// @returns true if all elements between `[start, end)` are the same value
- bool AllEqual(size_t start, size_t end) const;
-
- /// @param index the index of the element
- /// @return the element at `index`, which must be of type `T`.
+ /// @returns the value of the constant as the given scalar or abstract value.
template <typename T>
- 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;
- Elements elems_;
+ T As() const {
+ return std::visit(
+ [](auto v) {
+ if constexpr (std::is_same_v<decltype(v), std::monostate>) {
+ return T(0);
+ } else {
+ return static_cast<T>(v);
+ }
+ },
+ Value());
+ }
};
-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(ElementFor<T>(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_
diff --git a/src/tint/sem/constant_test.cc b/src/tint/sem/constant_test.cc
deleted file mode 100644
index e47e9a1..0000000
--- a/src/tint/sem/constant_test.cc
+++ /dev/null
@@ -1,540 +0,0 @@
-// 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 {
-
-struct ConstantTest : public TestHelper {
- const sem::Array* Array(uint32_t n, const sem::Type* el_ty) {
- return create<sem::Array>(el_ty,
- /* count */ n,
- /* align */ 16u,
- /* size */ 4u * n,
- /* stride */ 16u * n,
- /* implicit_stride */ 16u * n);
- }
-};
-
-TEST_F(ConstantTest, ConstructorInitializerList) {
- {
- auto i = AInt(AInt::kHighest);
- Constant c(create<AbstractInt>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- auto i = i32(i32::kHighest);
- Constant c(create<I32>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- auto i = u32(u32::kHighest);
- Constant c(create<U32>(), {i});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(i)); });
- }
- {
- 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)); });
- }
- {
- auto f = AFloat(AFloat::kHighest);
- Constant c(create<AbstractFloat>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
- {
- auto f = f32(f32::kHighest);
- Constant c(create<F32>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
- {
- auto f = f16(f16::kHighest);
- Constant c(create<F16>(), {f});
- c.WithElements([&](auto&& vec) { EXPECT_THAT(vec, testing::ElementsAre(f)); });
- }
-}
-
-TEST_F(ConstantTest, Element_ai) {
- auto* ty = create<AbstractInt>();
- Constant c(ty, {1_a});
- EXPECT_EQ(c.Element<AInt>(0), 1_a);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_i32) {
- auto* ty = create<I32>();
- Constant c(ty, {1_a});
- EXPECT_EQ(c.Element<i32>(0), 1_i);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_u32) {
- auto* ty = create<U32>();
- Constant c(ty, {1_a});
- EXPECT_EQ(c.Element<u32>(0), 1_u);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_bool) {
- auto* ty = create<Bool>();
- Constant c(ty, {true});
- EXPECT_EQ(c.Element<bool>(0), true);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_af) {
- auto* ty = create<AbstractFloat>();
- Constant c(ty, {1.0_a});
- EXPECT_EQ(c.Element<AFloat>(0), 1.0_a);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_f32) {
- auto* ty = create<F32>();
- Constant c(ty, {1.0_a});
- EXPECT_EQ(c.Element<f32>(0), 1.0_f);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_f16) {
- auto* ty = create<F16>();
- Constant c(ty, {1.0_a});
- EXPECT_EQ(c.Element<f16>(0), 1.0_h);
- EXPECT_EQ(c.ElementCount(), 1u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_ai) {
- auto* el_ty = create<AbstractInt>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_i32) {
- auto* el_ty = create<I32>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_u32) {
- auto* el_ty = create<U32>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_bool) {
- auto* el_ty = create<Bool>();
- auto* ty = create<Vector>(el_ty, 2u);
- Constant c(ty, {true, false});
- EXPECT_EQ(c.Element<bool>(0), true);
- EXPECT_EQ(c.Element<bool>(1), false);
- EXPECT_EQ(c.ElementCount(), 2u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_af) {
- auto* el_ty = create<AbstractFloat>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_f32) {
- auto* el_ty = create<F32>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_vec3_f16) {
- auto* el_ty = create<F16>();
- auto* ty = create<Vector>(el_ty, 3u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_af) {
- auto* el_ty = create<AbstractFloat>();
- auto* ty = create<Matrix>(create<Vector>(el_ty, 3u), 2u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_f32) {
- auto* el_ty = create<F32>();
- auto* ty = create<Matrix>(create<Vector>(el_ty, 3u), 2u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_mat2x3_f16) {
- auto* el_ty = create<F16>();
- auto* ty = create<Matrix>(create<Vector>(el_ty, 3u), 2u);
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_ai) {
- auto* el_ty = create<AbstractInt>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {1_a, 2_a, 3_a, 4_a, 5_a, 6_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.Element<AInt>(3), 4_a);
- EXPECT_EQ(c.Element<AInt>(4), 5_a);
- EXPECT_EQ(c.Element<AInt>(5), 6_a);
- EXPECT_EQ(c.ElementCount(), 6u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_i32) {
- auto* el_ty = create<I32>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {1_a, 2_a, 3_a, 4_a, 5_a, 6_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.Element<i32>(3), 4_i);
- EXPECT_EQ(c.Element<i32>(4), 5_i);
- EXPECT_EQ(c.Element<i32>(5), 6_i);
- EXPECT_EQ(c.ElementCount(), 6u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_u32) {
- auto* el_ty = create<U32>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {1_a, 2_a, 3_a, 4_a, 5_a, 6_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.Element<u32>(3), 4_u);
- EXPECT_EQ(c.Element<u32>(4), 5_u);
- EXPECT_EQ(c.Element<u32>(5), 6_u);
- EXPECT_EQ(c.ElementCount(), 6u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_bool) {
- auto* el_ty = create<Bool>();
- auto* ty = Array(2, create<Vector>(el_ty, 2u));
- Constant c(ty, {true, false, false, true});
- EXPECT_EQ(c.Element<bool>(0), true);
- EXPECT_EQ(c.Element<bool>(1), false);
- EXPECT_EQ(c.Element<bool>(2), false);
- EXPECT_EQ(c.Element<bool>(3), true);
- EXPECT_EQ(c.ElementCount(), 4u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_af) {
- auto* el_ty = create<AbstractFloat>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_f32) {
- auto* el_ty = create<F32>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_vec3_f16) {
- auto* el_ty = create<F16>();
- auto* ty = Array(2, create<Vector>(el_ty, 3u));
- Constant c(ty, {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);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, Element_arr_arr_mat2x3_f32) {
- auto* el_ty = create<F32>();
- auto* ty = Array(2, Array(2, create<Matrix>(create<Vector>(el_ty, 3u), 2u)));
- Constant c(ty, {
- 1.0_a, 2.0_a, 3.0_a, //
- 4.0_a, 5.0_a, 6.0_a, //
-
- 7.0_a, 8.0_a, 9.0_a, //
- 10.0_a, 11.0_a, 12.0_a, //
-
- 13.0_a, 14.0_a, 15.0_a, //
- 16.0_a, 17.0_a, 18.0_a, //
-
- 19.0_a, 20.0_a, 21.0_a, //
- 22.0_a, 23.0_a, 24.0_a, //
- });
- for (size_t i = 0; i < 24; i++) {
- EXPECT_EQ(c.Element<f32>(i), f32(i + 1));
- }
- EXPECT_EQ(c.ElementCount(), 24u);
- EXPECT_TYPE(c.Type(), ty);
- EXPECT_TYPE(c.ElementType(), el_ty);
-}
-
-TEST_F(ConstantTest, AnyZero) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AnyZero(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AnyZero(), true);
-
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AnyZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AnyZero(), true);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AnyZero(), false);
-}
-
-TEST_F(ConstantTest, AllZero) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllZero(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllZero(), true);
-
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllZero(), false);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllZero(), false);
-}
-
-TEST_F(ConstantTest, AllEqual) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 3_a, 3_a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {3_a, 3_a, 3_a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {3._a, 3._a, 3._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(), false);
-}
-
-TEST_F(ConstantTest, AllZeroRange) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 3_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 0_a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 0_a}).AllZero(1, 3), true);
-
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 3_a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 3_a}).AllZero(0, 2), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 2_a, 0_a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 0_a}).AllZero(0, 2), false);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 3._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 0._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 0._a}).AllZero(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 0._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, -0._a}).AllZero(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, -0._a}).AllZero(1, 3), false);
-
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 3._a}).AllZero(0, 2), true);
- EXPECT_EQ(Constant(vec3_af, {-0._a, 0._a, 1._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 1._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, 1._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 0._a}).AllZero(0, 2), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 0._a}).AllZero(0, 2), false);
-}
-
-TEST_F(ConstantTest, AllEqualRange) {
- auto* vec3_ai = create<Vector>(create<AbstractInt>(), 3u);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 3_a, 3_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 3_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 0_a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 1_a, 0_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 1_a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(1, 3), true);
-
- auto* vec3_af = create<Vector>(create<AbstractFloat>(), 3u);
- EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 3._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {0._a, 1._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 1._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -1._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 1._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(1, 3), false);
- EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, -0._a}).AllEqual(1, 3), true);
- EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllEqual(1, 3), true);
-}
-
-} // namespace
-} // namespace tint::sem
diff --git a/src/tint/sem/expression.cc b/src/tint/sem/expression.cc
index 57ec68b..4415db5 100644
--- a/src/tint/sem/expression.cc
+++ b/src/tint/sem/expression.cc
@@ -25,7 +25,7 @@
Expression::Expression(const ast::Expression* declaration,
const sem::Type* type,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
: declaration_(declaration),
diff --git a/src/tint/sem/expression.h b/src/tint/sem/expression.h
index a783851..05e5dac 100644
--- a/src/tint/sem/expression.h
+++ b/src/tint/sem/expression.h
@@ -41,7 +41,7 @@
Expression(const ast::Expression* declaration,
const sem::Type* type,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var = nullptr);
@@ -58,7 +58,7 @@
const Statement* Stmt() const { return statement_; }
/// @return the constant value of this expression
- const Constant& ConstantValue() const { return constant_; }
+ const Constant* ConstantValue() const { return constant_; }
/// Returns the variable or parameter that this expression derives from.
/// For reference and pointer expressions, this will either be the originating
@@ -88,7 +88,7 @@
private:
const sem::Type* const type_;
const Statement* const statement_;
- const Constant constant_;
+ const Constant* const constant_;
sem::Behaviors behaviors_{sem::Behavior::kNext};
const bool has_side_effects_;
};
diff --git a/src/tint/sem/expression_test.cc b/src/tint/sem/expression_test.cc
index fc1adeb..cc4bf0e 100644
--- a/src/tint/sem/expression_test.cc
+++ b/src/tint/sem/expression_test.cc
@@ -23,13 +23,30 @@
namespace tint::sem {
namespace {
+class MockConstant : public sem::Constant {
+ public:
+ explicit MockConstant(const sem::Type* ty) : type(ty) {}
+ ~MockConstant() override {}
+ const sem::Type* Type() const override { return type; }
+ std::variant<std::monostate, AInt, AFloat> Value() const override { return {}; }
+ const Constant* Index(size_t) const override { return {}; }
+ bool AllZero() const override { return {}; }
+ bool AnyZero() const override { return {}; }
+ bool AllEqual() const override { return {}; }
+ size_t Hash() const override { return 0; }
+
+ private:
+ const sem::Type* type;
+};
+
using ExpressionTest = TestHelper;
TEST_F(ExpressionTest, UnwrapMaterialize) {
+ MockConstant c(create<I32>());
auto* a = create<Expression>(/* declaration */ nullptr, create<I32>(), /* statement */ nullptr,
- Constant{},
+ /* constant_value */ nullptr,
/* has_side_effects */ false, /* source_var */ nullptr);
- auto* b = create<Materialize>(a, /* statement */ nullptr, Constant{create<I32>(), {1_a}});
+ auto* b = create<Materialize>(a, /* statement */ nullptr, &c);
EXPECT_EQ(a, a->UnwrapMaterialize());
EXPECT_EQ(a, b->UnwrapMaterialize());
diff --git a/src/tint/sem/index_accessor_expression.cc b/src/tint/sem/index_accessor_expression.cc
index 06f0990..cd74201 100644
--- a/src/tint/sem/index_accessor_expression.cc
+++ b/src/tint/sem/index_accessor_expression.cc
@@ -27,7 +27,7 @@
const Expression* object,
const Expression* index,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
: Base(declaration, type, statement, constant, has_side_effects, source_var),
diff --git a/src/tint/sem/index_accessor_expression.h b/src/tint/sem/index_accessor_expression.h
index c77f55d..233b0fa 100644
--- a/src/tint/sem/index_accessor_expression.h
+++ b/src/tint/sem/index_accessor_expression.h
@@ -43,7 +43,7 @@
const Expression* object,
const Expression* index,
const Statement* statement,
- Constant constant,
+ const Constant* constant,
bool has_side_effects,
const Variable* source_var = nullptr);
diff --git a/src/tint/sem/materialize.cc b/src/tint/sem/materialize.cc
index 76dd9d4..739b0ce 100644
--- a/src/tint/sem/materialize.cc
+++ b/src/tint/sem/materialize.cc
@@ -17,19 +17,16 @@
TINT_INSTANTIATE_TYPEINFO(tint::sem::Materialize);
namespace tint::sem {
-
-Materialize::Materialize(const Expression* expr, const Statement* statement, Constant constant)
+Materialize::Materialize(const Expression* expr,
+ const Statement* statement,
+ const Constant* constant)
: Base(/* declaration */ expr->Declaration(),
- /* type */ constant.Type(),
+ /* type */ constant->Type(),
/* statement */ statement,
/* constant */ constant,
/* has_side_effects */ false,
/* source_var */ expr->SourceVariable()),
- expr_(expr) {
- // Materialize nodes only wrap compile-time expressions, and so the Materialize expression must
- // have a constant value.
- TINT_ASSERT(Semantic, constant.IsValid());
-}
+ expr_(expr) {}
Materialize::~Materialize() = default;
diff --git a/src/tint/sem/materialize.h b/src/tint/sem/materialize.h
index a7c0e3a..0cbac29 100644
--- a/src/tint/sem/materialize.h
+++ b/src/tint/sem/materialize.h
@@ -31,7 +31,7 @@
/// @param expr the inner expression, being materialized
/// @param statement the statement that owns this expression
/// @param constant the constant value of this expression
- Materialize(const Expression* expr, const Statement* statement, Constant constant);
+ Materialize(const Expression* expr, const Statement* statement, const Constant* constant);
/// Destructor
~Materialize() override;
diff --git a/src/tint/sem/member_accessor_expression.cc b/src/tint/sem/member_accessor_expression.cc
index bd706a5..f9929c7 100644
--- a/src/tint/sem/member_accessor_expression.cc
+++ b/src/tint/sem/member_accessor_expression.cc
@@ -29,8 +29,7 @@
const Expression* object,
bool has_side_effects,
const Variable* source_var /* = nullptr */)
- : Base(declaration, type, statement, Constant{}, has_side_effects, source_var),
- object_(object) {}
+ : Base(declaration, type, statement, nullptr, has_side_effects, source_var), object_(object) {}
MemberAccessorExpression::~MemberAccessorExpression() = default;
diff --git a/src/tint/sem/variable.cc b/src/tint/sem/variable.cc
index 5439600..3849807 100644
--- a/src/tint/sem/variable.cc
+++ b/src/tint/sem/variable.cc
@@ -33,7 +33,7 @@
const sem::Type* type,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value)
+ const Constant* constant_value)
: declaration_(declaration),
type_(type),
storage_class_(storage_class),
@@ -47,9 +47,8 @@
ast::StorageClass storage_class,
ast::Access access,
const sem::Statement* statement,
- Constant constant_value)
- : Base(declaration, type, storage_class, access, std::move(constant_value)),
- statement_(statement) {}
+ const Constant* constant_value)
+ : Base(declaration, type, storage_class, access, constant_value), statement_(statement) {}
LocalVariable::~LocalVariable() = default;
@@ -57,9 +56,9 @@
const sem::Type* type,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value,
+ const Constant* constant_value,
sem::BindingPoint binding_point)
- : Base(declaration, type, storage_class, access, std::move(constant_value)),
+ : Base(declaration, type, storage_class, access, constant_value),
binding_point_(binding_point) {}
GlobalVariable::~GlobalVariable() = default;
@@ -70,7 +69,7 @@
ast::StorageClass storage_class,
ast::Access access,
const ParameterUsage usage /* = ParameterUsage::kNone */)
- : Base(declaration, type, storage_class, access, Constant{}), index_(index), usage_(usage) {}
+ : Base(declaration, type, storage_class, access, nullptr), index_(index), usage_(usage) {}
Parameter::~Parameter() = default;
diff --git a/src/tint/sem/variable.h b/src/tint/sem/variable.h
index 3b5bd0c..28e8f97 100644
--- a/src/tint/sem/variable.h
+++ b/src/tint/sem/variable.h
@@ -52,7 +52,7 @@
const sem::Type* type,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value);
+ const Constant* constant_value);
/// Destructor
~Variable() override;
@@ -70,7 +70,7 @@
ast::Access Access() const { return access_; }
/// @return the constant value of this expression
- const Constant& ConstantValue() const { return constant_value_; }
+ const Constant* ConstantValue() const { return constant_value_; }
/// @returns the variable constructor expression, or nullptr if the variable
/// does not have one.
@@ -91,7 +91,7 @@
const sem::Type* const type_;
const ast::StorageClass storage_class_;
const ast::Access access_;
- const Constant constant_value_;
+ const Constant* constant_value_;
const Expression* constructor_ = nullptr;
std::vector<const VariableUser*> users_;
};
@@ -111,7 +111,7 @@
ast::StorageClass storage_class,
ast::Access access,
const sem::Statement* statement,
- Constant constant_value);
+ const Constant* constant_value);
/// Destructor
~LocalVariable() override;
@@ -145,7 +145,7 @@
const sem::Type* type,
ast::StorageClass storage_class,
ast::Access access,
- Constant constant_value,
+ const Constant* constant_value,
sem::BindingPoint binding_point = {});
/// Destructor
diff --git a/src/tint/transform/localize_struct_array_assignment.cc b/src/tint/transform/localize_struct_array_assignment.cc
index d6cdded..7c3d695 100644
--- a/src/tint/transform/localize_struct_array_assignment.cc
+++ b/src/tint/transform/localize_struct_array_assignment.cc
@@ -46,7 +46,7 @@
expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
// Indexing using a runtime value?
auto* idx_sem = ctx.src->Sem().Get(ia->index);
- if (!idx_sem->ConstantValue().IsValid()) {
+ if (!idx_sem->ConstantValue()) {
// Indexing a member access expr?
if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
// That accesses an array?
diff --git a/src/tint/transform/promote_side_effects_to_decl.cc b/src/tint/transform/promote_side_effects_to_decl.cc
index d527a4c..7551c23 100644
--- a/src/tint/transform/promote_side_effects_to_decl.cc
+++ b/src/tint/transform/promote_side_effects_to_decl.cc
@@ -275,7 +275,7 @@
if (auto* sem_e = sem.Get(e)) {
if (auto* var_user = sem_e->As<sem::VariableUser>()) {
// Don't hoist constants.
- if (var_user->ConstantValue().IsValid()) {
+ if (var_user->ConstantValue()) {
return false;
}
// Don't hoist read-only variables as they cannot receive
diff --git a/src/tint/transform/robustness.cc b/src/tint/transform/robustness.cc
index 2e1cc40..beb1108 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/transform/robustness.cc
@@ -120,17 +120,18 @@
return nullptr;
}
- if (auto idx_constant = idx_sem->ConstantValue()) {
+ if (auto* idx_constant = idx_sem->ConstantValue()) {
// Constant value index
- if (idx_constant.Type()->Is<sem::I32>()) {
- idx.i32 = static_cast<int32_t>(idx_constant.Element<AInt>(0).value);
+ auto val = std::get<AInt>(idx_constant->Value());
+ if (idx_constant->Type()->Is<sem::I32>()) {
+ idx.i32 = static_cast<int32_t>(val);
idx.is_signed = true;
- } else if (idx_constant.Type()->Is<sem::U32>()) {
- idx.u32 = static_cast<uint32_t>(idx_constant.Element<AInt>(0).value);
+ } else if (idx_constant->Type()->Is<sem::U32>()) {
+ idx.u32 = static_cast<uint32_t>(val);
idx.is_signed = false;
} else {
TINT_ICE(Transform, b.Diagnostics()) << "unsupported constant value for accessor "
- << idx_constant.Type()->TypeInfo().name;
+ << idx_constant->Type()->TypeInfo().name;
return nullptr;
}
} else {
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index f56dc61..96395f1 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -358,8 +358,8 @@
continue;
}
auto* sem = ctx.src->Sem().Get(expr);
- if (auto c = sem->ConstantValue()) {
- workgroup_size_const *= c.Element<AInt>(0).value;
+ if (auto* c = sem->ConstantValue()) {
+ workgroup_size_const *= c->As<AInt>();
continue;
}
// Constant value could not be found. Build expression instead.
diff --git a/src/tint/writer/append_vector.cc b/src/tint/writer/append_vector.cc
index 7755ae3..c5f184d 100644
--- a/src/tint/writer/append_vector.cc
+++ b/src/tint/writer/append_vector.cc
@@ -59,7 +59,7 @@
<< "unsupported vector element type: " << ty->TypeInfo().name;
return nullptr;
}
- auto* sem = b.create<sem::Expression>(expr, ty, stmt, sem::Constant{},
+ auto* sem = b.create<sem::Expression>(expr, ty, stmt, /* constant_value */ nullptr,
/* has_side_effects */ false);
b.Sem().Add(expr, sem);
return sem;
@@ -139,7 +139,7 @@
ast::StorageClass::kNone, ast::Access::kUndefined));
auto* scalar_cast_sem = b->create<sem::Call>(
scalar_cast_ast, scalar_cast_target, std::vector<const sem::Expression*>{scalar_sem},
- statement, sem::Constant{}, /* has_side_effects */ false);
+ statement, /* constant_value */ nullptr, /* has_side_effects */ false);
b->Sem().Add(scalar_cast_ast, scalar_cast_sem);
packed.emplace_back(scalar_cast_sem);
} else {
@@ -158,7 +158,7 @@
ast::Access::kUndefined);
}));
auto* constructor_sem = b->create<sem::Call>(constructor_ast, constructor_target, packed,
- statement, sem::Constant{},
+ statement, /* constant_value */ nullptr,
/* has_side_effects */ false);
b->Sem().Add(constructor_ast, constructor_sem);
return constructor_sem;
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 022db4b..fdf4557 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -1332,7 +1332,7 @@
const ast::Expression* GeneratorImpl::CreateF32Zero(const sem::Statement* stmt) {
auto* zero = builder_.Expr(0_f);
auto* f32 = builder_.create<sem::F32>();
- auto* sem_zero = builder_.create<sem::Expression>(zero, f32, stmt, sem::Constant{},
+ auto* sem_zero = builder_.create<sem::Expression>(zero, f32, stmt, /* constant_value */ nullptr,
/* has_side_effects */ false);
builder_.Sem().Add(zero, sem_zero);
return zero;
@@ -1771,7 +1771,7 @@
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().Get(expr)) {
- if (auto constant = sem->ConstantValue()) {
+ if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
}
}
@@ -2214,31 +2214,23 @@
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- return EmitConstantRange(out, constant, constant.Type(), 0, constant.ElementCount());
-}
-
-bool GeneratorImpl::EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end) {
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
return Switch(
- range_ty, //
+ constant->Type(), //
[&](const sem::Bool*) {
- out << (constant.Element<AInt>(start) ? "true" : "false");
+ out << (constant->As<AInt>() ? "true" : "false");
return true;
},
[&](const sem::F32*) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(start)));
+ PrintF32(out, constant->As<float>());
return true;
},
[&](const sem::I32*) {
- out << constant.Element<AInt>(start).value;
+ out << constant->As<AInt>();
return true;
},
[&](const sem::U32*) {
- out << constant.Element<AInt>(start).value << "u";
+ out << constant->As<AInt>() << "u";
return true;
},
[&](const sem::Vector* v) {
@@ -2248,15 +2240,15 @@
ScopedParen sp(out);
- if (constant.AllEqual(start, end)) {
- return EmitConstantRange(out, constant, v->type(), start, start + 1);
+ if (constant->AllEqual()) {
+ return EmitConstant(out, constant->Index(0));
}
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, v->type(), i, i + 1u)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -2273,9 +2265,7 @@
if (column_idx > 0) {
out << ", ";
}
- size_t col_start = m->rows() * column_idx;
- size_t col_end = col_start + m->rows();
- if (!EmitConstantRange(out, constant, m->ColumnType(), col_start, col_end)) {
+ if (!EmitConstant(out, constant->Index(column_idx))) {
return false;
}
}
@@ -2288,15 +2278,11 @@
ScopedParen sp(out);
- auto* el_ty = a->ElemType();
-
- uint32_t step = 0;
- sem::Type::DeepestElementOf(el_ty, &step);
- for (size_t i = start; i < end; i += step) {
- if (i > start) {
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -2306,7 +2292,7 @@
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index f925bba..15b7ee1 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -346,19 +346,7 @@
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
- /// Handles emitting a sub-range of a constant value
- /// @param out the output stream
- /// @param constant the constant value to emit
- /// @param range_ty the sub-range type
- /// @param start the element index for the first element
- /// @param end the element index for one past the last element
- /// @returns true if the constant value was successfully emitted
- bool EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 3e4352b..b307c8d 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -615,8 +615,7 @@
if (auto* mat = TypeOf(lhs_sub_access->object)->UnwrapRef()->As<sem::Matrix>()) {
auto* rhs_col_idx_sem = builder_.Sem().Get(lhs_access->index);
auto* rhs_row_idx_sem = builder_.Sem().Get(lhs_sub_access->index);
- if (!rhs_col_idx_sem->ConstantValue().IsValid() ||
- !rhs_row_idx_sem->ConstantValue().IsValid()) {
+ if (!rhs_col_idx_sem->ConstantValue() || !rhs_row_idx_sem->ConstantValue()) {
return EmitDynamicMatrixScalarAssignment(stmt, mat);
}
}
@@ -626,7 +625,7 @@
const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
if (auto* mat = lhs_access_type->As<sem::Matrix>()) {
auto* lhs_index_sem = builder_.Sem().Get(lhs_access->index);
- if (!lhs_index_sem->ConstantValue().IsValid()) {
+ if (!lhs_index_sem->ConstantValue()) {
return EmitDynamicMatrixVectorAssignment(stmt, mat);
}
}
@@ -634,7 +633,7 @@
// indices
if (auto* vec = lhs_access_type->As<sem::Vector>()) {
auto* rhs_sem = builder_.Sem().Get(lhs_access->index);
- if (!rhs_sem->ConstantValue().IsValid()) {
+ if (!rhs_sem->ConstantValue()) {
return EmitDynamicVectorAssignment(stmt, vec);
}
}
@@ -654,28 +653,30 @@
bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
// For constants, replace literal 0 with 1.
- if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
- if (!val.AnyZero()) {
+ if (const auto* val = builder_.Sem().Get(expr)->ConstantValue()) {
+ if (!val->AnyZero()) {
return EmitExpression(out, expr);
}
- if (val.Type()->IsAnyOf<sem::I32, sem::U32>()) {
- return EmitValue(out, val.Type(), 1);
+ auto* ty = val->Type();
+
+ if (ty->IsAnyOf<sem::I32, sem::U32>()) {
+ return EmitValue(out, ty, 1);
}
- if (auto* vec = val.Type()->As<sem::Vector>()) {
+ if (auto* vec = ty->As<sem::Vector>()) {
auto* elem_ty = vec->type();
- if (!EmitType(out, val.Type(), ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+ if (!EmitType(out, ty, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
}
out << "(";
- for (size_t i = 0; i < val.ElementCount(); ++i) {
+ for (size_t i = 0; i < vec->Width(); ++i) {
if (i != 0) {
out << ", ";
}
- auto s = val.Element<AInt>(i).value;
+ auto s = val->Index(i)->As<AInt>();
if (!EmitValue(out, elem_ty, (s == 0) ? 1 : static_cast<int>(s))) {
return false;
}
@@ -1181,9 +1182,9 @@
// If true, use scalar_offset_value, otherwise use scalar_offset_expr
bool scalar_offset_constant = false;
- if (auto val = offset_arg->ConstantValue()) {
- TINT_ASSERT(Writer, val.Type()->Is<sem::U32>());
- scalar_offset_value = static_cast<uint32_t>(val.Element<AInt>(0).value);
+ if (auto* val = offset_arg->ConstantValue()) {
+ TINT_ASSERT(Writer, val->Type()->Is<sem::U32>());
+ scalar_offset_value = static_cast<uint32_t>(std::get<AInt>(val->Value()));
scalar_offset_value /= 4; // bytes -> scalar index
scalar_offset_constant = true;
}
@@ -2337,7 +2338,7 @@
case sem::BuiltinType::kTextureGather:
out << ".Gather";
if (builtin->Parameters()[0]->Usage() == sem::ParameterUsage::kComponent) {
- switch (call->Arguments()[0]->ConstantValue().Element<AInt>(0).value) {
+ switch (call->Arguments()[0]->ConstantValue()->As<AInt>()) {
case 0:
out << "Red";
break;
@@ -2384,8 +2385,9 @@
auto* i32 = builder_.create<sem::I32>();
auto* zero = builder_.Expr(0_i);
auto* stmt = builder_.Sem().Get(vector)->Stmt();
- builder_.Sem().Add(zero, builder_.create<sem::Expression>(zero, i32, stmt, sem::Constant{},
- /* has_side_effects */ false));
+ builder_.Sem().Add(
+ zero, builder_.create<sem::Expression>(zero, i32, stmt, /* constant_value */ nullptr,
+ /* has_side_effects */ false));
auto* packed = AppendVector(&builder_, vector, zero);
return EmitExpression(out, packed->Declaration());
};
@@ -2614,7 +2616,7 @@
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
if (auto* sem = builder_.Sem().Get(expr)) {
- if (auto constant = sem->ConstantValue()) {
+ if (auto* constant = sem->ConstantValue()) {
return EmitConstant(out, constant);
}
}
@@ -3109,43 +3111,35 @@
return true;
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- return EmitConstantRange(out, constant, constant.Type(), 0, constant.ElementCount());
-}
-
-bool GeneratorImpl::EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end) {
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
return Switch(
- range_ty, //
+ constant->Type(), //
[&](const sem::Bool*) {
- out << (constant.Element<AInt>(start) ? "true" : "false");
+ out << (constant->As<AInt>() ? "true" : "false");
return true;
},
[&](const sem::F32*) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(start)));
+ PrintF32(out, constant->As<float>());
return true;
},
[&](const sem::I32*) {
- out << constant.Element<AInt>(start).value;
+ out << constant->As<AInt>();
return true;
},
[&](const sem::U32*) {
- out << constant.Element<AInt>(start).value << "u";
+ out << constant->As<AInt>() << "u";
return true;
},
[&](const sem::Vector* v) {
- if (constant.AllEqual(start, end)) {
+ if (constant->AllEqual()) {
{
ScopedParen sp(out);
- if (!EmitConstantRange(out, constant, v->type(), start, start + 1)) {
+ if (!EmitConstant(out, constant->Index(0))) {
return false;
}
}
out << ".";
- for (size_t i = start; i < end; i++) {
+ for (size_t i = 0; i < v->Width(); i++) {
out << "x";
}
return true;
@@ -3157,11 +3151,11 @@
ScopedParen sp(out);
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, v->type(), i, i + 1u)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -3174,20 +3168,18 @@
ScopedParen sp(out);
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- if (column_idx > 0) {
+ for (size_t i = 0; i < m->columns(); i++) {
+ if (i > 0) {
out << ", ";
}
- size_t col_start = m->rows() * column_idx;
- size_t col_end = col_start + m->rows();
- if (!EmitConstantRange(out, constant, m->ColumnType(), col_start, col_end)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
return true;
},
[&](const sem::Array* a) {
- if (constant.AllZero(start, end)) {
+ if (constant->AllZero()) {
out << "(";
if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return false;
@@ -3199,15 +3191,11 @@
out << "{";
TINT_DEFER(out << "}");
- auto* el_ty = a->ElemType();
-
- uint32_t step = 0;
- sem::Type::DeepestElementOf(el_ty, &step);
- for (size_t i = start; i < end; i += step) {
- if (i > start) {
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -3217,7 +3205,7 @@
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 8960548..bf2debe 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -93,7 +93,8 @@
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitAssign(const ast::AssignmentStatement* stmt);
- /// Emits code such that if `expr` is zero, it emits one, else `expr`
+ /// Emits code such that if `expr` is zero, it emits one, else `expr`.
+ /// Used to avoid divide-by-zeros by substituting constant zeros with ones.
/// @param out the output of the expression stream
/// @param expr the expression
/// @returns true if the expression was emitted, false otherwise
@@ -342,19 +343,7 @@
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
- /// Handles emitting a sub-range of a constant value
- /// @param out the output stream
- /// @param constant the constant value to emit
- /// @param range_ty the sub-range type
- /// @param start the element index for the first element
- /// @param end the element index for one past the last element
- /// @returns true if the constant value was successfully emitted
- bool EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output stream
/// @param lit the literal to emit
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index f5ffa6c..43324bb 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -1201,7 +1201,7 @@
break; // Other texture dimensions don't have an offset
}
}
- auto c = component->ConstantValue().Element<AInt>(0);
+ auto c = component->ConstantValue()->As<AInt>();
switch (c.value) {
case 0:
out << "component::x";
@@ -1594,31 +1594,23 @@
});
}
-bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant& constant) {
- return EmitConstantRange(out, constant, constant.Type(), 0, constant.ElementCount());
-}
-
-bool GeneratorImpl::EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end) {
+bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constant) {
return Switch(
- range_ty, //
+ constant->Type(), //
[&](const sem::Bool*) {
- out << (constant.Element<AInt>(start) ? "true" : "false");
+ out << (constant->As<AInt>() ? "true" : "false");
return true;
},
[&](const sem::F32*) {
- PrintF32(out, static_cast<float>(constant.Element<AFloat>(start)));
+ PrintF32(out, constant->As<float>());
return true;
},
[&](const sem::I32*) {
- PrintI32(out, static_cast<int32_t>(constant.Element<AInt>(start).value));
+ PrintI32(out, constant->As<int32_t>());
return true;
},
[&](const sem::U32*) {
- out << constant.Element<AInt>(start).value << "u";
+ out << constant->As<AInt>() << "u";
return true;
},
[&](const sem::Vector* v) {
@@ -1628,18 +1620,18 @@
ScopedParen sp(out);
- if (constant.AllEqual(start, end)) {
- if (!EmitConstantRange(out, constant, v->type(), start, start + 1)) {
+ if (constant->AllEqual()) {
+ if (!EmitConstant(out, constant->Index(0))) {
return false;
}
return true;
}
- for (size_t i = start; i < end; i++) {
- if (i > start) {
+ for (size_t i = 0; i < v->Width(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, v->type(), i, i + 1u)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -1652,13 +1644,11 @@
ScopedParen sp(out);
- for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
- if (column_idx > 0) {
+ for (size_t i = 0; i < m->columns(); i++) {
+ if (i > 0) {
out << ", ";
}
- size_t col_start = m->rows() * column_idx;
- size_t col_end = col_start + m->rows();
- if (!EmitConstantRange(out, constant, m->ColumnType(), col_start, col_end)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -1669,7 +1659,7 @@
return false;
}
- if (constant.AllZero(start, end)) {
+ if (constant->AllZero()) {
out << "{}";
return true;
}
@@ -1677,15 +1667,11 @@
out << "{";
TINT_DEFER(out << "}");
- auto* el_ty = a->ElemType();
-
- uint32_t step = 0;
- sem::Type::DeepestElementOf(el_ty, &step);
- for (size_t i = start; i < end; i += step) {
- if (i > start) {
+ for (size_t i = 0; i < a->Count(); i++) {
+ if (i > 0) {
out << ", ";
}
- if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+ if (!EmitConstant(out, constant->Index(i))) {
return false;
}
}
@@ -1695,7 +1681,7 @@
[&](Default) {
diagnostics_.add_error(
diag::System::Writer,
- "unhandled constant type: " + builder_.FriendlyName(constant.Type()));
+ "unhandled constant type: " + builder_.FriendlyName(constant->Type()));
return false;
});
}
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index ed0c35b..f27d258 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -256,19 +256,7 @@
/// @param out the output stream
/// @param constant the constant value to emit
/// @returns true if the constant value was successfully emitted
- bool EmitConstant(std::ostream& out, const sem::Constant& constant);
- /// Handles emitting a sub-range of a constant value
- /// @param out the output stream
- /// @param constant the constant value to emit
- /// @param range_ty the sub-range type
- /// @param start the element index for the first element
- /// @param end the element index for one past the last element
- /// @returns true if the constant value was successfully emitted
- bool EmitConstantRange(std::ostream& out,
- const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end);
+ bool EmitConstant(std::ostream& out, const sem::Constant* constant);
/// Handles a literal
/// @param out the output of the expression stream
/// @param lit the literal to emit
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index fea7a14..833324a 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -959,7 +959,7 @@
Operand(result_type_id),
extract,
Operand(info->source_id),
- Operand(idx_constval.Element<uint32_t>(0)),
+ Operand(idx_constval->As<uint32_t>()),
})) {
return false;
}
@@ -1703,20 +1703,14 @@
return GenerateConstantIfNeeded(constant);
}
-uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant& constant) {
- return GenerateConstantRangeIfNeeded(constant, constant.Type(), 0, constant.ElementCount());
-}
-
-uint32_t Builder::GenerateConstantRangeIfNeeded(const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end) {
- if (constant.AllZero(start, end)) {
- return GenerateConstantNullIfNeeded(range_ty);
+uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant* constant) {
+ if (constant->AllZero()) {
+ return GenerateConstantNullIfNeeded(constant->Type());
}
+ auto* ty = constant->Type();
- auto composite = [&](const sem::Type* el_ty) -> uint32_t {
- auto type_id = GenerateTypeIfNeeded(range_ty);
+ auto composite = [&](size_t el_count) -> uint32_t {
+ auto type_id = GenerateTypeIfNeeded(ty);
if (!type_id) {
return 0;
}
@@ -1724,14 +1718,12 @@
static constexpr size_t kOpsResultIdx = 1; // operand index of the result
std::vector<Operand> ops;
- ops.reserve(end - start + 2);
+ ops.reserve(el_count + 2);
ops.emplace_back(type_id);
ops.push_back(Operand(0u)); // Placeholder for the result ID
- uint32_t step = 0;
- sem::Type::DeepestElementOf(el_ty, &step);
- for (size_t i = start; i < end; i += step) {
- auto id = GenerateConstantRangeIfNeeded(constant, el_ty, i, i + step);
+ for (size_t i = 0; i < el_count; i++) {
+ auto id = GenerateConstantIfNeeded(constant->Index(i));
if (!id) {
return 0;
}
@@ -1749,28 +1741,28 @@
};
return Switch(
- range_ty, //
+ ty, //
[&](const sem::Bool*) {
- bool val = constant.Element<AInt>(start);
+ bool val = constant->As<bool>();
return GenerateConstantIfNeeded(ScalarConstant::Bool(val));
},
[&](const sem::F32*) {
- auto val = f32(constant.Element<AFloat>(start));
+ auto val = constant->As<f32>();
return GenerateConstantIfNeeded(ScalarConstant::F32(val.value));
},
[&](const sem::I32*) {
- auto val = i32(constant.Element<AInt>(start));
+ auto val = constant->As<i32>();
return GenerateConstantIfNeeded(ScalarConstant::I32(val.value));
},
[&](const sem::U32*) {
- auto val = u32(constant.Element<AInt>(start));
+ auto val = constant->As<u32>();
return GenerateConstantIfNeeded(ScalarConstant::U32(val.value));
},
- [&](const sem::Vector* v) { return composite(v->type()); },
- [&](const sem::Matrix* m) { return composite(m->ColumnType()); },
- [&](const sem::Array* a) { return composite(a->ElemType()); },
+ [&](const sem::Vector* v) { return composite(v->Width()); },
+ [&](const sem::Matrix* m) { return composite(m->columns()); },
+ [&](const sem::Array* a) { return composite(a->Count()); },
[&](Default) {
- error_ = "unhandled constant type: " + builder_.FriendlyName(constant.Type());
+ error_ = "unhandled constant type: " + builder_.FriendlyName(ty);
return false;
});
}
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index 8465089..f6bb93f 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -554,18 +554,7 @@
/// Generates a constant value if needed
/// @param constant the constant to generate.
/// @returns the ID on success or 0 on failure
- uint32_t GenerateConstantIfNeeded(const sem::Constant& constant);
-
- /// Handles emitting a sub-range of a constant value
- /// @param constant the constant value to emit
- /// @param range_ty the sub-range type
- /// @param start the element index for the first element
- /// @param end the element index for one past the last element
- /// @returns true if the constant value was successfully emitted
- uint32_t GenerateConstantRangeIfNeeded(const sem::Constant& constant,
- const sem::Type* range_ty,
- size_t start,
- size_t end);
+ uint32_t GenerateConstantIfNeeded(const sem::Constant* constant);
/// Generates a scalar constant if needed
/// @param constant the constant to generate.