From b5508fdcb5e6002c0937a47ecf67d5dc4c2ff7ab Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Thu, 10 Jun 2021 13:23:31 +0000 Subject: [PATCH] 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 Reviewed-by: Ben Clayton Commit-Queue: Antonio Maiorano --- src/resolver/resolver.cc | 8 +- src/resolver/validation_test.cc | 22 +- src/sem/type.cc | 4 + src/sem/type.h | 2 + src/writer/hlsl/generator_impl.cc | 14 + .../hlsl/generator_impl_constructor_test.cc | 48 +++ src/writer/spirv/builder.cc | 10 + .../builder_constructor_expression_test.cc | 144 +++++++ test/var/splat.wgsl | 91 +++++ test/var/splat.wgsl.expected.hlsl | 103 +++++ test/var/splat.wgsl.expected.msl | 106 ++++++ test/var/splat.wgsl.expected.spvasm | 353 ++++++++++++++++++ test/var/splat.wgsl.expected.wgsl | 104 ++++++ 13 files changed, 988 insertions(+), 21 deletions(-) create mode 100644 test/var/splat.wgsl create mode 100644 test/var/splat.wgsl.expected.hlsl create mode 100644 test/var/splat.wgsl.expected.msl create mode 100644 test/var/splat.wgsl.expected.spvasm create mode 100644 test/var/splat.wgsl.expected.wgsl diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index e80d11d7c0..ee2674aff6 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -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!"; diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc index 1c62b894b8..aa53bce035 100644 --- a/src/resolver/validation_test.cc +++ b/src/resolver/validation_test.cc @@ -776,18 +776,6 @@ TEST_F(ResolverValidationTest, "12:34 error: attempted to construct 'vec2' with 4 component(s)"); } -TEST_F(ResolverValidationTest, - Expr_Constructor_Vec2_Error_TooFewArgumentsScalar) { - auto* tc = vec2(create( - Source{{12, 34}}, Literal(1.0f))); - WrapInFunction(tc); - - EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ( - r()->error(), - "12:34 error: attempted to construct 'vec2' with 1 component(s)"); -} - TEST_F(ResolverValidationTest, Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) { auto* tc = vec2( @@ -1632,16 +1620,16 @@ TEST_F(ResolverValidationTest, TEST_F(ResolverValidationTest, Expr_Constructor_NestedVectorConstructors_InnerError) { - auto* tc = vec4( - vec3(1.0f, vec2(create( - Source{{12, 34}}, Literal(1.0f)))), - 1.0f); + auto* tc = vec4(vec4(1.0f, 1.0f, + vec3(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' with 1 component(s)"); + "12:34 error: attempted to construct 'vec3' with 2 component(s)"); } TEST_F(ResolverValidationTest, diff --git a/src/sem/type.cc b/src/sem/type.cc index 4d44dfe9cf..9963003d5d 100644 --- a/src/sem/type.cc +++ b/src/sem/type.cc @@ -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([](const Vector* v) { return v->type()->is_scalar(); }); +} + bool Type::is_numeric_scalar_or_vector() const { return is_numeric_scalar() || is_numeric_vector(); } diff --git a/src/sem/type.h b/src/sem/type.h index d3ee2ac64d..e63e03e09b 100644 --- a/src/sem/type.h +++ b/src/sem/type.h @@ -85,6 +85,8 @@ class Type : public Castable { 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 diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index f26515677f..5e74d5b7bf 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc @@ -1377,6 +1377,12 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre, bool brackets = type->IsAnyOf(); + // 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()->size(), 'x'); + } + out << (brackets ? "}" : ")"); return true; } diff --git a/src/writer/hlsl/generator_impl_constructor_test.cc b/src/writer/hlsl/generator_impl_constructor_test.cc index 8593fff3b1..3564389e1c 100644 --- a/src/writer/hlsl/generator_impl_constructor_test.cc +++ b/src/writer/hlsl/generator_impl_constructor_test.cc @@ -135,6 +135,54 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) { Validate(); } +TEST_F(HlslGeneratorImplTest_Constructor, + EmitConstructor_Type_Vec_SingleScalar_Float) { + WrapInFunction(vec3(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(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(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(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(vec3(1.f, 2.f, 3.f), vec3(3.f, 4.f, 5.f))); diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 6089a7d2f6..c89e06c566 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -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()->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()) { diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc index 3f7e66bdff..0a7232af2a 100644 --- a/src/writer/spirv/builder_constructor_expression_test.cc +++ b/src/writer/spirv/builder_constructor_expression_test.cc @@ -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(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(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(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(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(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(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(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(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(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(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(vec2(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(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(2.0f, vec2(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(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(2.0f, 2.0f, vec2(2.0f, 2.0f)); WrapInFunction(cast); diff --git a/test/var/splat.wgsl b/test/var/splat.wgsl new file mode 100644 index 0000000000..1ede944927 --- /dev/null +++ b/test/var/splat.wgsl @@ -0,0 +1,91 @@ +var g_v2 : vec2 = vec2(1.0); +var g_v3 : vec3 = vec3(1.0); +var g_v4 : vec4 = vec4(1.0); + +fn from_immediate_bool() { + var v2 : vec2 = vec2(true); + var v3 : vec3 = vec3(true); + var v4 : vec4 = vec4(true); +} + +fn from_immediate_f32() { + var v2 : vec2 = vec2(1.0); + var v3 : vec3 = vec3(1.0); + var v4 : vec4 = vec4(1.0); +} + +fn from_immediate_i32() { + var v2 : vec2 = vec2(1); + var v3 : vec3 = vec3(1); + var v4 : vec4 = vec4(1); +} + +fn from_immediate_u32() { + var v2 : vec2 = vec2(1u); + var v3 : vec3 = vec3(1u); + var v4 : vec4 = vec4(1u); +} + +fn from_expression_bool() { + var v2 : vec2 = vec2(true); + var v3 : vec3 = vec3(true); + var v4 : vec4 = vec4(true); +} + +fn from_expression_f32() { + var v2 : vec2 = vec2(1.0 + 2.0); + var v3 : vec3 = vec3(1.0 + 2.0); + var v4 : vec4 = vec4(1.0 + 2.0); +} + +fn from_expression_i32() { + var v2 : vec2 = vec2(1 + 2); + var v3 : vec3 = vec3(1 + 2); + var v4 : vec4 = vec4(1 + 2); +} + +fn from_expression_u32() { + var v2 : vec2 = vec2(1u + 2u); + var v3 : vec3 = vec3(1u + 2u); + var v4 : vec4 = vec4(1u + 2u); +} + +fn get_bool() -> bool { return true; } +fn get_f32() -> f32 { return 1.0; } +fn get_i32() -> i32 { return 1; } +fn get_u32() -> u32 { return 1u; } + +fn from_call_bool() { + var v2 : vec2 = vec2(get_bool()); + var v3 : vec3 = vec3(get_bool()); + var v4 : vec4 = vec4(get_bool()); +} + +fn from_call_f32() { + var v2 : vec2 = vec2(get_f32()); + var v3 : vec3 = vec3(get_f32()); + var v4 : vec4 = vec4(get_f32()); +} + +fn from_call_i32() { + var v2 : vec2 = vec2(get_i32()); + var v3 : vec3 = vec3(get_i32()); + var v4 : vec4 = vec4(get_i32()); +} + +fn from_call_u32() { + var v2 : vec2 = vec2(get_u32()); + var v3 : vec3 = vec3(get_u32()); + var v4 : vec4 = vec4(get_u32()); +} + +fn with_swizzle() { + var a = vec2(1.0).y; + var b = vec3(1.0).z; + var c = vec4(1.0).w; +} + +[[stage(fragment)]] +fn main() -> [[location(0)]] vec4 { + return vec4(0.0,0.0,0.0,0.0); +} diff --git a/test/var/splat.wgsl.expected.hlsl b/test/var/splat.wgsl.expected.hlsl new file mode 100644 index 0000000000..279743bec6 --- /dev/null +++ b/test/var/splat.wgsl.expected.hlsl @@ -0,0 +1,103 @@ +struct tint_symbol { + float4 value : SV_Target0; +}; + +void from_immediate_bool() { + bool2 v2 = bool2((true).xx); + bool3 v3 = bool3((true).xxx); + bool4 v4 = bool4((true).xxxx); +} + +void from_immediate_f32() { + float2 v2 = float2((1.0f).xx); + float3 v3 = float3((1.0f).xxx); + float4 v4 = float4((1.0f).xxxx); +} + +void from_immediate_i32() { + int2 v2 = int2((1).xx); + int3 v3 = int3((1).xxx); + int4 v4 = int4((1).xxxx); +} + +void from_immediate_u32() { + uint2 v2 = uint2((1u).xx); + uint3 v3 = uint3((1u).xxx); + uint4 v4 = uint4((1u).xxxx); +} + +void from_expression_bool() { + bool2 v2 = bool2((true).xx); + bool3 v3 = bool3((true).xxx); + bool4 v4 = bool4((true).xxxx); +} + +void from_expression_f32() { + float2 v2 = float2(((1.0f + 2.0f)).xx); + float3 v3 = float3(((1.0f + 2.0f)).xxx); + float4 v4 = float4(((1.0f + 2.0f)).xxxx); +} + +void from_expression_i32() { + int2 v2 = int2(((1 + 2)).xx); + int3 v3 = int3(((1 + 2)).xxx); + int4 v4 = int4(((1 + 2)).xxxx); +} + +void from_expression_u32() { + uint2 v2 = uint2(((1u + 2u)).xx); + uint3 v3 = uint3(((1u + 2u)).xxx); + uint4 v4 = uint4(((1u + 2u)).xxxx); +} + +bool get_bool() { + return true; +} + +float get_f32() { + return 1.0f; +} + +int get_i32() { + return 1; +} + +uint get_u32() { + return 1u; +} + +void from_call_bool() { + bool2 v2 = bool2((get_bool()).xx); + bool3 v3 = bool3((get_bool()).xxx); + bool4 v4 = bool4((get_bool()).xxxx); +} + +void from_call_f32() { + float2 v2 = float2((get_f32()).xx); + float3 v3 = float3((get_f32()).xxx); + float4 v4 = float4((get_f32()).xxxx); +} + +void from_call_i32() { + int2 v2 = int2((get_i32()).xx); + int3 v3 = int3((get_i32()).xxx); + int4 v4 = int4((get_i32()).xxxx); +} + +void from_call_u32() { + uint2 v2 = uint2((get_u32()).xx); + uint3 v3 = uint3((get_u32()).xxx); + uint4 v4 = uint4((get_u32()).xxxx); +} + +void with_swizzle() { + float a = float2((1.0f).xx).y; + float b = float3((1.0f).xxx).z; + float c = float4((1.0f).xxxx).w; +} + +tint_symbol main() { + const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)}; + return tint_symbol_1; +} + diff --git a/test/var/splat.wgsl.expected.msl b/test/var/splat.wgsl.expected.msl new file mode 100644 index 0000000000..bd8803e7a6 --- /dev/null +++ b/test/var/splat.wgsl.expected.msl @@ -0,0 +1,106 @@ +#include + +using namespace metal; +struct tint_symbol_1 { + float4 value [[color(0)]]; +}; + +void from_immediate_bool() { + bool2 v2 = bool2(true); + bool3 v3 = bool3(true); + bool4 v4 = bool4(true); +} + +void from_immediate_f32() { + float2 v2 = float2(1.0f); + float3 v3 = float3(1.0f); + float4 v4 = float4(1.0f); +} + +void from_immediate_i32() { + int2 v2 = int2(1); + int3 v3 = int3(1); + int4 v4 = int4(1); +} + +void from_immediate_u32() { + uint2 v2 = uint2(1u); + uint3 v3 = uint3(1u); + uint4 v4 = uint4(1u); +} + +void from_expression_bool() { + bool2 v2 = bool2(true); + bool3 v3 = bool3(true); + bool4 v4 = bool4(true); +} + +void from_expression_f32() { + float2 v2 = float2((1.0f + 2.0f)); + float3 v3 = float3((1.0f + 2.0f)); + float4 v4 = float4((1.0f + 2.0f)); +} + +void from_expression_i32() { + int2 v2 = int2((1 + 2)); + int3 v3 = int3((1 + 2)); + int4 v4 = int4((1 + 2)); +} + +void from_expression_u32() { + uint2 v2 = uint2((1u + 2u)); + uint3 v3 = uint3((1u + 2u)); + uint4 v4 = uint4((1u + 2u)); +} + +bool get_bool() { + return true; +} + +float get_f32() { + return 1.0f; +} + +int get_i32() { + return 1; +} + +uint get_u32() { + return 1u; +} + +void from_call_bool() { + bool2 v2 = bool2(get_bool()); + bool3 v3 = bool3(get_bool()); + bool4 v4 = bool4(get_bool()); +} + +void from_call_f32() { + float2 v2 = float2(get_f32()); + float3 v3 = float3(get_f32()); + float4 v4 = float4(get_f32()); +} + +void from_call_i32() { + int2 v2 = int2(get_i32()); + int3 v3 = int3(get_i32()); + int4 v4 = int4(get_i32()); +} + +void from_call_u32() { + uint2 v2 = uint2(get_u32()); + uint3 v3 = uint3(get_u32()); + uint4 v4 = uint4(get_u32()); +} + +void with_swizzle() { + float a = float2(1.0f).y; + float b = float3(1.0f).z; + float c = float4(1.0f).w; +} + +fragment tint_symbol_1 tint_symbol() { + tint_symbol_1 const tint_symbol_2 = {.value=float4(0.0f, 0.0f, 0.0f, 0.0f)}; + return tint_symbol_2; +} + diff --git a/test/var/splat.wgsl.expected.spvasm b/test/var/splat.wgsl.expected.spvasm new file mode 100644 index 0000000000..5ac13ce36a --- /dev/null +++ b/test/var/splat.wgsl.expected.spvasm @@ -0,0 +1,353 @@ +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 203 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %tint_symbol_1 + OpExecutionMode %main OriginUpperLeft + OpName %g_v2 "g_v2" + OpName %g_v3 "g_v3" + OpName %g_v4 "g_v4" + OpName %tint_symbol_1 "tint_symbol_1" + OpName %from_immediate_bool "from_immediate_bool" + OpName %v2 "v2" + OpName %v3 "v3" + OpName %v4 "v4" + OpName %from_immediate_f32 "from_immediate_f32" + OpName %v2_0 "v2" + OpName %v3_0 "v3" + OpName %v4_0 "v4" + OpName %from_immediate_i32 "from_immediate_i32" + OpName %v2_1 "v2" + OpName %v3_1 "v3" + OpName %v4_1 "v4" + OpName %from_immediate_u32 "from_immediate_u32" + OpName %v2_2 "v2" + OpName %v3_2 "v3" + OpName %v4_2 "v4" + OpName %from_expression_bool "from_expression_bool" + OpName %v2_3 "v2" + OpName %v3_3 "v3" + OpName %v4_3 "v4" + OpName %from_expression_f32 "from_expression_f32" + OpName %v2_4 "v2" + OpName %v3_4 "v3" + OpName %v4_4 "v4" + OpName %from_expression_i32 "from_expression_i32" + OpName %v2_5 "v2" + OpName %v3_5 "v3" + OpName %v4_5 "v4" + OpName %from_expression_u32 "from_expression_u32" + OpName %v2_6 "v2" + OpName %v3_6 "v3" + OpName %v4_6 "v4" + OpName %get_bool "get_bool" + OpName %get_f32 "get_f32" + OpName %get_i32 "get_i32" + OpName %get_u32 "get_u32" + OpName %from_call_bool "from_call_bool" + OpName %v2_7 "v2" + OpName %v3_7 "v3" + OpName %v4_7 "v4" + OpName %from_call_f32 "from_call_f32" + OpName %v2_8 "v2" + OpName %v3_8 "v3" + OpName %v4_8 "v4" + OpName %from_call_i32 "from_call_i32" + OpName %v2_9 "v2" + OpName %v3_9 "v3" + OpName %v4_9 "v4" + OpName %from_call_u32 "from_call_u32" + OpName %v2_10 "v2" + OpName %v3_10 "v3" + OpName %v4_10 "v4" + OpName %with_swizzle "with_swizzle" + OpName %a "a" + OpName %b "b" + OpName %c "c" + OpName %tint_symbol_2 "tint_symbol_2" + OpName %tint_symbol "tint_symbol" + OpName %main "main" + OpDecorate %tint_symbol_1 Location 0 + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %float_1 = OpConstant %float 1 + %4 = OpConstantComposite %v2float %float_1 %float_1 +%_ptr_Private_v2float = OpTypePointer Private %v2float + %g_v2 = OpVariable %_ptr_Private_v2float Private %4 + %v3float = OpTypeVector %float 3 + %8 = OpConstantComposite %v3float %float_1 %float_1 %float_1 +%_ptr_Private_v3float = OpTypePointer Private %v3float + %g_v3 = OpVariable %_ptr_Private_v3float Private %8 + %v4float = OpTypeVector %float 4 + %12 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Private_v4float = OpTypePointer Private %v4float + %g_v4 = OpVariable %_ptr_Private_v4float Private %12 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %17 = OpConstantNull %v4float +%tint_symbol_1 = OpVariable %_ptr_Output_v4float Output %17 + %void = OpTypeVoid + %18 = OpTypeFunction %void + %bool = OpTypeBool + %v2bool = OpTypeVector %bool 2 + %true = OpConstantTrue %bool + %25 = OpConstantComposite %v2bool %true %true +%_ptr_Function_v2bool = OpTypePointer Function %v2bool + %28 = OpConstantNull %v2bool + %v3bool = OpTypeVector %bool 3 + %30 = OpConstantComposite %v3bool %true %true %true +%_ptr_Function_v3bool = OpTypePointer Function %v3bool + %33 = OpConstantNull %v3bool + %v4bool = OpTypeVector %bool 4 + %35 = OpConstantComposite %v4bool %true %true %true %true +%_ptr_Function_v4bool = OpTypePointer Function %v4bool + %38 = OpConstantNull %v4bool +%_ptr_Function_v2float = OpTypePointer Function %v2float + %43 = OpConstantNull %v2float +%_ptr_Function_v3float = OpTypePointer Function %v3float + %46 = OpConstantNull %v3float +%_ptr_Function_v4float = OpTypePointer Function %v4float + %int = OpTypeInt 32 1 + %v2int = OpTypeVector %int 2 + %int_1 = OpConstant %int 1 + %54 = OpConstantComposite %v2int %int_1 %int_1 +%_ptr_Function_v2int = OpTypePointer Function %v2int + %57 = OpConstantNull %v2int + %v3int = OpTypeVector %int 3 + %59 = OpConstantComposite %v3int %int_1 %int_1 %int_1 +%_ptr_Function_v3int = OpTypePointer Function %v3int + %62 = OpConstantNull %v3int + %v4int = OpTypeVector %int 4 + %64 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1 +%_ptr_Function_v4int = OpTypePointer Function %v4int + %67 = OpConstantNull %v4int + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %uint_1 = OpConstant %uint 1 + %73 = OpConstantComposite %v2uint %uint_1 %uint_1 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %76 = OpConstantNull %v2uint + %v3uint = OpTypeVector %uint 3 + %78 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 +%_ptr_Function_v3uint = OpTypePointer Function %v3uint + %81 = OpConstantNull %v3uint + %v4uint = OpTypeVector %uint 4 + %83 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 +%_ptr_Function_v4uint = OpTypePointer Function %v4uint + %86 = OpConstantNull %v4uint + %float_2 = OpConstant %float 2 + %int_2 = OpConstant %int 2 + %uint_2 = OpConstant %uint 2 + %128 = OpTypeFunction %bool + %131 = OpTypeFunction %float + %134 = OpTypeFunction %int + %137 = OpTypeFunction %uint +%_ptr_Function_float = OpTypePointer Function %float + %189 = OpConstantNull %float + %194 = OpTypeFunction %void %v4float + %float_0 = OpConstant %float 0 + %202 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%from_immediate_bool = OpFunction %void None %18 + %21 = OpLabel + %v2 = OpVariable %_ptr_Function_v2bool Function %28 + %v3 = OpVariable %_ptr_Function_v3bool Function %33 + %v4 = OpVariable %_ptr_Function_v4bool Function %38 + OpStore %v2 %25 + OpStore %v3 %30 + OpStore %v4 %35 + OpReturn + OpFunctionEnd +%from_immediate_f32 = OpFunction %void None %18 + %40 = OpLabel + %v2_0 = OpVariable %_ptr_Function_v2float Function %43 + %v3_0 = OpVariable %_ptr_Function_v3float Function %46 + %v4_0 = OpVariable %_ptr_Function_v4float Function %17 + OpStore %v2_0 %4 + OpStore %v3_0 %8 + OpStore %v4_0 %12 + OpReturn + OpFunctionEnd +%from_immediate_i32 = OpFunction %void None %18 + %50 = OpLabel + %v2_1 = OpVariable %_ptr_Function_v2int Function %57 + %v3_1 = OpVariable %_ptr_Function_v3int Function %62 + %v4_1 = OpVariable %_ptr_Function_v4int Function %67 + OpStore %v2_1 %54 + OpStore %v3_1 %59 + OpStore %v4_1 %64 + OpReturn + OpFunctionEnd +%from_immediate_u32 = OpFunction %void None %18 + %69 = OpLabel + %v2_2 = OpVariable %_ptr_Function_v2uint Function %76 + %v3_2 = OpVariable %_ptr_Function_v3uint Function %81 + %v4_2 = OpVariable %_ptr_Function_v4uint Function %86 + OpStore %v2_2 %73 + OpStore %v3_2 %78 + OpStore %v4_2 %83 + OpReturn + OpFunctionEnd +%from_expression_bool = OpFunction %void None %18 + %88 = OpLabel + %v2_3 = OpVariable %_ptr_Function_v2bool Function %28 + %v3_3 = OpVariable %_ptr_Function_v3bool Function %33 + %v4_3 = OpVariable %_ptr_Function_v4bool Function %38 + OpStore %v2_3 %25 + OpStore %v3_3 %30 + OpStore %v4_3 %35 + OpReturn + OpFunctionEnd +%from_expression_f32 = OpFunction %void None %18 + %93 = OpLabel + %v2_4 = OpVariable %_ptr_Function_v2float Function %43 + %v3_4 = OpVariable %_ptr_Function_v3float Function %46 + %v4_4 = OpVariable %_ptr_Function_v4float Function %17 + %95 = OpFAdd %float %float_1 %float_2 + %96 = OpCompositeConstruct %v2float %95 %95 + OpStore %v2_4 %96 + %98 = OpFAdd %float %float_1 %float_2 + %99 = OpCompositeConstruct %v3float %98 %98 %98 + OpStore %v3_4 %99 + %101 = OpFAdd %float %float_1 %float_2 + %102 = OpCompositeConstruct %v4float %101 %101 %101 %101 + OpStore %v4_4 %102 + OpReturn + OpFunctionEnd +%from_expression_i32 = OpFunction %void None %18 + %105 = OpLabel + %v2_5 = OpVariable %_ptr_Function_v2int Function %57 + %v3_5 = OpVariable %_ptr_Function_v3int Function %62 + %v4_5 = OpVariable %_ptr_Function_v4int Function %67 + %107 = OpIAdd %int %int_1 %int_2 + %108 = OpCompositeConstruct %v2int %107 %107 + OpStore %v2_5 %108 + %110 = OpIAdd %int %int_1 %int_2 + %111 = OpCompositeConstruct %v3int %110 %110 %110 + OpStore %v3_5 %111 + %113 = OpIAdd %int %int_1 %int_2 + %114 = OpCompositeConstruct %v4int %113 %113 %113 %113 + OpStore %v4_5 %114 + OpReturn + OpFunctionEnd +%from_expression_u32 = OpFunction %void None %18 + %117 = OpLabel + %v2_6 = OpVariable %_ptr_Function_v2uint Function %76 + %v3_6 = OpVariable %_ptr_Function_v3uint Function %81 + %v4_6 = OpVariable %_ptr_Function_v4uint Function %86 + %119 = OpIAdd %uint %uint_1 %uint_2 + %120 = OpCompositeConstruct %v2uint %119 %119 + OpStore %v2_6 %120 + %122 = OpIAdd %uint %uint_1 %uint_2 + %123 = OpCompositeConstruct %v3uint %122 %122 %122 + OpStore %v3_6 %123 + %125 = OpIAdd %uint %uint_1 %uint_2 + %126 = OpCompositeConstruct %v4uint %125 %125 %125 %125 + OpStore %v4_6 %126 + OpReturn + OpFunctionEnd + %get_bool = OpFunction %bool None %128 + %130 = OpLabel + OpReturnValue %true + OpFunctionEnd + %get_f32 = OpFunction %float None %131 + %133 = OpLabel + OpReturnValue %float_1 + OpFunctionEnd + %get_i32 = OpFunction %int None %134 + %136 = OpLabel + OpReturnValue %int_1 + OpFunctionEnd + %get_u32 = OpFunction %uint None %137 + %139 = OpLabel + OpReturnValue %uint_1 + OpFunctionEnd +%from_call_bool = OpFunction %void None %18 + %141 = OpLabel + %v2_7 = OpVariable %_ptr_Function_v2bool Function %28 + %v3_7 = OpVariable %_ptr_Function_v3bool Function %33 + %v4_7 = OpVariable %_ptr_Function_v4bool Function %38 + %142 = OpFunctionCall %bool %get_bool + %143 = OpCompositeConstruct %v2bool %142 %142 + OpStore %v2_7 %143 + %145 = OpFunctionCall %bool %get_bool + %146 = OpCompositeConstruct %v3bool %145 %145 %145 + OpStore %v3_7 %146 + %148 = OpFunctionCall %bool %get_bool + %149 = OpCompositeConstruct %v4bool %148 %148 %148 %148 + OpStore %v4_7 %149 + OpReturn + OpFunctionEnd +%from_call_f32 = OpFunction %void None %18 + %152 = OpLabel + %v2_8 = OpVariable %_ptr_Function_v2float Function %43 + %v3_8 = OpVariable %_ptr_Function_v3float Function %46 + %v4_8 = OpVariable %_ptr_Function_v4float Function %17 + %153 = OpFunctionCall %float %get_f32 + %154 = OpCompositeConstruct %v2float %153 %153 + OpStore %v2_8 %154 + %156 = OpFunctionCall %float %get_f32 + %157 = OpCompositeConstruct %v3float %156 %156 %156 + OpStore %v3_8 %157 + %159 = OpFunctionCall %float %get_f32 + %160 = OpCompositeConstruct %v4float %159 %159 %159 %159 + OpStore %v4_8 %160 + OpReturn + OpFunctionEnd +%from_call_i32 = OpFunction %void None %18 + %163 = OpLabel + %v2_9 = OpVariable %_ptr_Function_v2int Function %57 + %v3_9 = OpVariable %_ptr_Function_v3int Function %62 + %v4_9 = OpVariable %_ptr_Function_v4int Function %67 + %164 = OpFunctionCall %int %get_i32 + %165 = OpCompositeConstruct %v2int %164 %164 + OpStore %v2_9 %165 + %167 = OpFunctionCall %int %get_i32 + %168 = OpCompositeConstruct %v3int %167 %167 %167 + OpStore %v3_9 %168 + %170 = OpFunctionCall %int %get_i32 + %171 = OpCompositeConstruct %v4int %170 %170 %170 %170 + OpStore %v4_9 %171 + OpReturn + OpFunctionEnd +%from_call_u32 = OpFunction %void None %18 + %174 = OpLabel + %v2_10 = OpVariable %_ptr_Function_v2uint Function %76 + %v3_10 = OpVariable %_ptr_Function_v3uint Function %81 + %v4_10 = OpVariable %_ptr_Function_v4uint Function %86 + %175 = OpFunctionCall %uint %get_u32 + %176 = OpCompositeConstruct %v2uint %175 %175 + OpStore %v2_10 %176 + %178 = OpFunctionCall %uint %get_u32 + %179 = OpCompositeConstruct %v3uint %178 %178 %178 + OpStore %v3_10 %179 + %181 = OpFunctionCall %uint %get_u32 + %182 = OpCompositeConstruct %v4uint %181 %181 %181 %181 + OpStore %v4_10 %182 + OpReturn + OpFunctionEnd +%with_swizzle = OpFunction %void None %18 + %185 = OpLabel + %a = OpVariable %_ptr_Function_float Function %189 + %b = OpVariable %_ptr_Function_float Function %189 + %c = OpVariable %_ptr_Function_float Function %189 + %186 = OpCompositeExtract %float %4 1 + OpStore %a %186 + %190 = OpCompositeExtract %float %8 2 + OpStore %b %190 + %192 = OpCompositeExtract %float %12 3 + OpStore %c %192 + OpReturn + OpFunctionEnd +%tint_symbol_2 = OpFunction %void None %194 +%tint_symbol = OpFunctionParameter %v4float + %197 = OpLabel + OpStore %tint_symbol_1 %tint_symbol + OpReturn + OpFunctionEnd + %main = OpFunction %void None %18 + %199 = OpLabel + %200 = OpFunctionCall %void %tint_symbol_2 %202 + OpReturn + OpFunctionEnd diff --git a/test/var/splat.wgsl.expected.wgsl b/test/var/splat.wgsl.expected.wgsl new file mode 100644 index 0000000000..9adddf96e6 --- /dev/null +++ b/test/var/splat.wgsl.expected.wgsl @@ -0,0 +1,104 @@ +var g_v2 : vec2 = vec2(1.0); + +var g_v3 : vec3 = vec3(1.0); + +var g_v4 : vec4 = vec4(1.0); + +fn from_immediate_bool() { + var v2 : vec2 = vec2(true); + var v3 : vec3 = vec3(true); + var v4 : vec4 = vec4(true); +} + +fn from_immediate_f32() { + var v2 : vec2 = vec2(1.0); + var v3 : vec3 = vec3(1.0); + var v4 : vec4 = vec4(1.0); +} + +fn from_immediate_i32() { + var v2 : vec2 = vec2(1); + var v3 : vec3 = vec3(1); + var v4 : vec4 = vec4(1); +} + +fn from_immediate_u32() { + var v2 : vec2 = vec2(1u); + var v3 : vec3 = vec3(1u); + var v4 : vec4 = vec4(1u); +} + +fn from_expression_bool() { + var v2 : vec2 = vec2(true); + var v3 : vec3 = vec3(true); + var v4 : vec4 = vec4(true); +} + +fn from_expression_f32() { + var v2 : vec2 = vec2((1.0 + 2.0)); + var v3 : vec3 = vec3((1.0 + 2.0)); + var v4 : vec4 = vec4((1.0 + 2.0)); +} + +fn from_expression_i32() { + var v2 : vec2 = vec2((1 + 2)); + var v3 : vec3 = vec3((1 + 2)); + var v4 : vec4 = vec4((1 + 2)); +} + +fn from_expression_u32() { + var v2 : vec2 = vec2((1u + 2u)); + var v3 : vec3 = vec3((1u + 2u)); + var v4 : vec4 = vec4((1u + 2u)); +} + +fn get_bool() -> bool { + return true; +} + +fn get_f32() -> f32 { + return 1.0; +} + +fn get_i32() -> i32 { + return 1; +} + +fn get_u32() -> u32 { + return 1u; +} + +fn from_call_bool() { + var v2 : vec2 = vec2(get_bool()); + var v3 : vec3 = vec3(get_bool()); + var v4 : vec4 = vec4(get_bool()); +} + +fn from_call_f32() { + var v2 : vec2 = vec2(get_f32()); + var v3 : vec3 = vec3(get_f32()); + var v4 : vec4 = vec4(get_f32()); +} + +fn from_call_i32() { + var v2 : vec2 = vec2(get_i32()); + var v3 : vec3 = vec3(get_i32()); + var v4 : vec4 = vec4(get_i32()); +} + +fn from_call_u32() { + var v2 : vec2 = vec2(get_u32()); + var v3 : vec3 = vec3(get_u32()); + var v4 : vec4 = vec4(get_u32()); +} + +fn with_swizzle() { + var a = vec2(1.0).y; + var b = vec3(1.0).z; + var c = vec4(1.0).w; +} + +[[stage(fragment)]] +fn main() -> [[location(0)]] vec4 { + return vec4(0.0, 0.0, 0.0, 0.0); +}