mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-12 14:46:08 +00:00
Implement vector initialization from single scalar (aka "splat")
Updated spir-v and HSLS backends to emit valid constructors. Bug: tint:656 Change-Id: I53356945563b633239b12c0f4e207f160dbc23d8 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53780 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@chromium.org> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
committed by
Tint LUCI CQ
parent
5b2f49b5df
commit
b5508fdcb5
@@ -1895,10 +1895,10 @@ bool Resolver::ValidateVectorConstructor(
|
||||
}
|
||||
}
|
||||
|
||||
// A correct vector constructor must either be a zero-value expression
|
||||
// or the number of components of all constructor arguments must add up
|
||||
// to the vector cardinality.
|
||||
if (value_cardinality_sum > 0 && value_cardinality_sum != vec_type->size()) {
|
||||
// A correct vector constructor must either be a zero-value expression,
|
||||
// a single-value initializer (splat) expression, or the number of components
|
||||
// of all constructor arguments must add up to the vector cardinality.
|
||||
if (value_cardinality_sum > 1 && value_cardinality_sum != vec_type->size()) {
|
||||
if (values.empty()) {
|
||||
TINT_ICE(diagnostics_)
|
||||
<< "constructor arguments expected to be non-empty!";
|
||||
|
||||
@@ -776,18 +776,6 @@ TEST_F(ResolverValidationTest,
|
||||
"12:34 error: attempted to construct 'vec2<f32>' with 4 component(s)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverValidationTest,
|
||||
Expr_Constructor_Vec2_Error_TooFewArgumentsScalar) {
|
||||
auto* tc = vec2<f32>(create<ast::ScalarConstructorExpression>(
|
||||
Source{{12, 34}}, Literal(1.0f)));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
r()->error(),
|
||||
"12:34 error: attempted to construct 'vec2<f32>' with 1 component(s)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverValidationTest,
|
||||
Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) {
|
||||
auto* tc = vec2<f32>(
|
||||
@@ -1632,16 +1620,16 @@ TEST_F(ResolverValidationTest,
|
||||
|
||||
TEST_F(ResolverValidationTest,
|
||||
Expr_Constructor_NestedVectorConstructors_InnerError) {
|
||||
auto* tc = vec4<f32>(
|
||||
vec3<f32>(1.0f, vec2<f32>(create<ast::ScalarConstructorExpression>(
|
||||
Source{{12, 34}}, Literal(1.0f)))),
|
||||
1.0f);
|
||||
auto* tc = vec4<f32>(vec4<f32>(1.0f, 1.0f,
|
||||
vec3<f32>(Expr(Source{{12, 34}}, 1.0f),
|
||||
Expr(Source{{12, 34}}, 1.0f))),
|
||||
1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
r()->error(),
|
||||
"12:34 error: attempted to construct 'vec2<f32>' with 1 component(s)");
|
||||
"12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverValidationTest,
|
||||
|
||||
@@ -119,6 +119,10 @@ bool Type::is_numeric_vector() const {
|
||||
[](const Vector* v) { return v->type()->is_numeric_scalar(); });
|
||||
}
|
||||
|
||||
bool Type::is_scalar_vector() const {
|
||||
return Is<Vector>([](const Vector* v) { return v->type()->is_scalar(); });
|
||||
}
|
||||
|
||||
bool Type::is_numeric_scalar_or_vector() const {
|
||||
return is_numeric_scalar() || is_numeric_vector();
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ class Type : public Castable<Type, Node> {
|
||||
bool is_bool_scalar_or_vector() const;
|
||||
/// @returns true if this type is a numeric vector
|
||||
bool is_numeric_vector() const;
|
||||
/// @returns true if this type is a vector of scalar type
|
||||
bool is_scalar_vector() const;
|
||||
/// @returns true if this type is a numeric scale or vector
|
||||
bool is_numeric_scalar_or_vector() const;
|
||||
/// @returns true if this type is a handle type
|
||||
|
||||
@@ -1377,6 +1377,12 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
||||
|
||||
bool brackets = type->IsAnyOf<sem::Array, sem::Struct>();
|
||||
|
||||
// For single-value vector initializers, swizzle the scalar to the right
|
||||
// vector dimension using .x
|
||||
const bool is_single_value_vector_init =
|
||||
type->is_scalar_vector() && expr->values().size() == 1 &&
|
||||
TypeOf(expr->values()[0])->is_scalar();
|
||||
|
||||
if (brackets) {
|
||||
out << "{";
|
||||
} else {
|
||||
@@ -1387,6 +1393,10 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
||||
out << "(";
|
||||
}
|
||||
|
||||
if (is_single_value_vector_init) {
|
||||
out << "(";
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
for (auto* e : expr->values()) {
|
||||
if (!first) {
|
||||
@@ -1399,6 +1409,10 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
||||
}
|
||||
}
|
||||
|
||||
if (is_single_value_vector_init) {
|
||||
out << ")." << std::string(type->As<sem::Vector>()->size(), 'x');
|
||||
}
|
||||
|
||||
out << (brackets ? "}" : ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,54 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
|
||||
Validate();
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor,
|
||||
EmitConstructor_Type_Vec_SingleScalar_Float) {
|
||||
WrapInFunction(vec3<f32>(2.0f));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||
EXPECT_THAT(result(), HasSubstr("float3((2.0f).xxx)"));
|
||||
|
||||
Validate();
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor,
|
||||
EmitConstructor_Type_Vec_SingleScalar_Bool) {
|
||||
WrapInFunction(vec3<bool>(true));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||
EXPECT_THAT(result(), HasSubstr("bool3((true).xxx)"));
|
||||
|
||||
Validate();
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor,
|
||||
EmitConstructor_Type_Vec_SingleScalar_Int) {
|
||||
WrapInFunction(vec3<i32>(2));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||
EXPECT_THAT(result(), HasSubstr("int3((2).xxx)"));
|
||||
|
||||
Validate();
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor,
|
||||
EmitConstructor_Type_Vec_SingleScalar_UInt) {
|
||||
WrapInFunction(vec3<u32>(2u));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||
EXPECT_THAT(result(), HasSubstr("uint3((2u).xxx)"));
|
||||
|
||||
Validate();
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
|
||||
WrapInFunction(
|
||||
mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
|
||||
|
||||
@@ -1430,6 +1430,16 @@ uint32_t Builder::GenerateTypeConstructorExpression(
|
||||
}
|
||||
}
|
||||
|
||||
// For a single-value vector initializer, splat the initializer value.
|
||||
auto* const init_result_type = TypeOf(init)->UnwrapRef();
|
||||
if (values.size() == 1 && init_result_type->is_scalar_vector() &&
|
||||
TypeOf(values[0])->is_scalar()) {
|
||||
size_t vec_size = init_result_type->As<sem::Vector>()->size();
|
||||
for (size_t i = 0; i < (vec_size - 1); ++i) {
|
||||
ops.push_back(ops[0]);
|
||||
}
|
||||
}
|
||||
|
||||
auto str = out.str();
|
||||
auto val = type_constructor_to_id_.find(str);
|
||||
if (val != type_constructor_to_id_.end()) {
|
||||
|
||||
@@ -241,6 +241,38 @@ TEST_F(SpvBuilderConstructorTest, Type_F32_With_F32) {
|
||||
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool) {
|
||||
auto* cast = vec2<bool>(true);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
|
||||
%1 = OpTypeVector %2 2
|
||||
%3 = OpConstantTrue %2
|
||||
%4 = OpConstantComposite %1 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32) {
|
||||
auto* cast = vec2<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 2
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
|
||||
auto* cast = vec2<f32>(2.0f, 2.0f);
|
||||
WrapInFunction(cast);
|
||||
@@ -275,6 +307,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) {
|
||||
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
|
||||
auto* cast = vec3<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 3
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
|
||||
auto* cast = vec3<bool>(true);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
|
||||
%1 = OpTypeVector %2 3
|
||||
%3 = OpConstantTrue %2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) {
|
||||
auto* cast = vec3<f32>(2.0f, 2.0f, 2.0f);
|
||||
WrapInFunction(cast);
|
||||
@@ -353,6 +417,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) {
|
||||
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
|
||||
auto* cast = vec4<bool>(true);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
|
||||
%1 = OpTypeVector %2 4
|
||||
%3 = OpConstantTrue %2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) {
|
||||
auto* cast = vec4<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateExpression(cast), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 4
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
|
||||
auto* cast = vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f);
|
||||
WrapInFunction(cast);
|
||||
@@ -523,6 +619,22 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) {
|
||||
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_F32) {
|
||||
auto* cast = vec2<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateConstructorExpression(nullptr, cast, true), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 2
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_Vec2) {
|
||||
auto* cast = vec2<f32>(vec2<f32>(2.0f, 2.0f));
|
||||
WrapInFunction(cast);
|
||||
@@ -571,6 +683,22 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec4) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32) {
|
||||
auto* cast = vec3<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateConstructorExpression(nullptr, cast, true), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 3
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32_Vec2) {
|
||||
auto* cast = vec3<f32>(2.0f, vec2<f32>(2.0f, 2.0f));
|
||||
WrapInFunction(cast);
|
||||
@@ -617,6 +745,22 @@ TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec2_F32) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32) {
|
||||
auto* cast = vec4<f32>(2.0f);
|
||||
WrapInFunction(cast);
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
b.push_function(Function{});
|
||||
EXPECT_EQ(b.GenerateConstructorExpression(nullptr, cast, true), 4u);
|
||||
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
|
||||
%1 = OpTypeVector %2 4
|
||||
%3 = OpConstant %2 2
|
||||
%4 = OpConstantComposite %1 %3 %3 %3 %3
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_F32_Vec2) {
|
||||
auto* cast = vec4<f32>(2.0f, 2.0f, vec2<f32>(2.0f, 2.0f));
|
||||
WrapInFunction(cast);
|
||||
|
||||
Reference in New Issue
Block a user