tint: Add matrix identify and single-scalar ctors

Fixed: tint:1545
Change-Id: I86451223765f620861bf98861142e6d34c7e945b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90502
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-05-16 21:14:11 +00:00 committed by Dawn LUCI CQ
parent 31b379409d
commit 3b5edf1435
95 changed files with 5468 additions and 4232 deletions

View File

@ -6,6 +6,7 @@
* Produce warnings for when calling barriers, textureSample, and derivative * Produce warnings for when calling barriers, textureSample, and derivative
builtins in non-uniform control flow [tint:880](crbug.com/tint/880) builtins in non-uniform control flow [tint:880](crbug.com/tint/880)
* Matrix identity constructors and constructors for a single scalar value are now supported [tint:1545](crbug.com/tint/1545)
## Changes for M102 ## Changes for M102

View File

@ -605,6 +605,15 @@ ctor bool(bool) -> bool
ctor vec2<T: scalar>(vec2<T>) -> vec2<T> ctor vec2<T: scalar>(vec2<T>) -> vec2<T>
ctor vec3<T: scalar>(vec3<T>) -> vec3<T> ctor vec3<T: scalar>(vec3<T>) -> vec3<T>
ctor vec4<T: scalar>(vec4<T>) -> vec4<T> ctor vec4<T: scalar>(vec4<T>) -> vec4<T>
ctor mat2x2<f32>(mat2x2<f32>) -> mat2x2<f32>
ctor mat2x3<f32>(mat2x3<f32>) -> mat2x3<f32>
ctor mat2x4<f32>(mat2x4<f32>) -> mat2x4<f32>
ctor mat3x2<f32>(mat3x2<f32>) -> mat3x2<f32>
ctor mat3x3<f32>(mat3x3<f32>) -> mat3x3<f32>
ctor mat3x4<f32>(mat3x4<f32>) -> mat3x4<f32>
ctor mat4x2<f32>(mat4x2<f32>) -> mat4x2<f32>
ctor mat4x3<f32>(mat4x3<f32>) -> mat4x3<f32>
ctor mat4x4<f32>(mat4x4<f32>) -> mat4x4<f32>
// Vector constructors // Vector constructors
ctor vec2<T: scalar>(T) -> vec2<T> ctor vec2<T: scalar>(T) -> vec2<T>
@ -623,50 +632,59 @@ ctor vec4<T: scalar>(xyz: vec3<T>, w: T) -> vec4<T>
ctor vec4<T: scalar>(x: T, zyw: vec3<T>) -> vec4<T> ctor vec4<T: scalar>(x: T, zyw: vec3<T>) -> vec4<T>
// Matrix constructors // Matrix constructors
ctor mat2x2(f32, f32, ctor mat2x2<T: f32>(T) -> mat2x2<T>
f32, f32) -> mat2x2<f32> ctor mat2x2<T: f32>(T, T,
ctor mat2x2(vec2<f32>, vec2<f32>) -> mat2x2<f32> T, T) -> mat2x2<T>
ctor mat2x2<T: f32>(vec2<T>, vec2<T>) -> mat2x2<T>
ctor mat2x3(f32, f32, f32, ctor mat2x3<T: f32>(T) -> mat2x3<T>
f32, f32, f32) -> mat2x3<f32> ctor mat2x3<T: f32>(T, T, T,
ctor mat2x3(vec3<f32>, vec3<f32>) -> mat2x3<f32> T, T, T) -> mat2x3<T>
ctor mat2x3<T: f32>(vec3<T>, vec3<T>) -> mat2x3<T>
ctor mat2x4(f32, f32, f32, f32, ctor mat2x4<T: f32>(T) -> mat2x4<T>
f32, f32, f32, f32) -> mat2x4<f32> ctor mat2x4<T: f32>(T, T, T, T,
ctor mat2x4(vec4<f32>, vec4<f32>) -> mat2x4<f32> T, T, T, T) -> mat2x4<T>
ctor mat2x4<T: f32>(vec4<T>, vec4<T>) -> mat2x4<T>
ctor mat3x2(f32, f32, ctor mat3x2<T: f32>(T) -> mat3x2<T>
f32, f32, ctor mat3x2<T: f32>(T, T,
f32, f32) -> mat3x2<f32> T, T,
ctor mat3x2(vec2<f32>, vec2<f32>, vec2<f32>) -> mat3x2<f32> T, T) -> mat3x2<T>
ctor mat3x2<T: f32>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
ctor mat3x3(f32, f32, f32, ctor mat3x3<T: f32>(T) -> mat3x3<T>
f32, f32, f32, ctor mat3x3<T: f32>(T, T, T,
f32, f32, f32) -> mat3x3<f32> T, T, T,
ctor mat3x3(vec3<f32>, vec3<f32>, vec3<f32>) -> mat3x3<f32> T, T, T) -> mat3x3<T>
ctor mat3x3<T: f32>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
ctor mat3x4(f32, f32, f32, f32, ctor mat3x4<T: f32>(T) -> mat3x4<T>
f32, f32, f32, f32, ctor mat3x4<T: f32>(T, T, T, T,
f32, f32, f32, f32) -> mat3x4<f32> T, T, T, T,
ctor mat3x4(vec4<f32>, vec4<f32>, vec4<f32>) -> mat3x4<f32> T, T, T, T) -> mat3x4<T>
ctor mat3x4<T: f32>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
ctor mat4x2(f32, f32, ctor mat4x2<T: f32>(T) -> mat4x2<T>
f32, f32, ctor mat4x2<T: f32>(T, T,
f32, f32, T, T,
f32, f32) -> mat4x2<f32> T, T,
ctor mat4x2(vec2<f32>, vec2<f32>, vec2<f32>, vec2<f32>) -> mat4x2<f32> T, T) -> mat4x2<T>
ctor mat4x2<T: f32>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
ctor mat4x3(f32, f32, f32, ctor mat4x3<T: f32>(T) -> mat4x3<T>
f32, f32, f32, ctor mat4x3<T: f32>(T, T, T,
f32, f32, f32, T, T, T,
f32, f32, f32) -> mat4x3<f32> T, T, T,
ctor mat4x3(vec3<f32>, vec3<f32>, vec3<f32>, vec3<f32>) -> mat4x3<f32> T, T, T) -> mat4x3<T>
ctor mat4x3<T: f32>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
ctor mat4x4(f32, f32, f32, f32, ctor mat4x4<T: f32>(T) -> mat4x4<T>
f32, f32, f32, f32, ctor mat4x4<T: f32>(T, T, T, T,
f32, f32, f32, f32, T, T, T, T,
f32, f32, f32, f32) -> mat4x4<f32> T, T, T, T,
ctor mat4x4(vec4<f32>, vec4<f32>, vec4<f32>, vec4<f32>) -> mat4x4<f32> T, T, T, T) -> mat4x4<T>
ctor mat4x4<T: f32>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Type conversions // // Type conversions //

File diff suppressed because it is too large Load Diff

View File

@ -235,15 +235,18 @@ constexpr Params ParamsFor(Kind kind) {
} }
static constexpr Params valid_cases[] = { static constexpr Params valid_cases[] = {
// Direct init (non-conversions) // Identity
ParamsFor<bool, bool>(Kind::Construct), // ParamsFor<bool, bool>(Kind::Construct), //
ParamsFor<i32, i32>(Kind::Construct), // ParamsFor<i32, i32>(Kind::Construct), //
ParamsFor<u32, u32>(Kind::Construct), // ParamsFor<u32, u32>(Kind::Construct), //
ParamsFor<f32, f32>(Kind::Construct), // ParamsFor<f32, f32>(Kind::Construct), //
ParamsFor<vec3<bool>, vec3<bool>>(Kind::Construct), // ParamsFor<vec3<bool>, vec3<bool>>(Kind::Construct), //
ParamsFor<vec3<i32>, vec3<i32>>(Kind::Construct), // ParamsFor<vec3<i32>, vec3<i32>>(Kind::Construct), //
ParamsFor<vec3<u32>, vec3<u32>>(Kind::Construct), // ParamsFor<vec3<u32>, vec3<u32>>(Kind::Construct), //
ParamsFor<vec3<f32>, vec3<f32>>(Kind::Construct), // ParamsFor<vec3<f32>, vec3<f32>>(Kind::Construct), //
ParamsFor<mat3x3<f32>, mat3x3<f32>>(Kind::Construct), //
ParamsFor<mat2x3<f32>, mat2x3<f32>>(Kind::Construct), //
ParamsFor<mat3x2<f32>, mat3x2<f32>>(Kind::Construct), //
// Splat // Splat
ParamsFor<vec3<bool>, bool>(Kind::Construct), // ParamsFor<vec3<bool>, bool>(Kind::Construct), //
@ -251,6 +254,10 @@ static constexpr Params valid_cases[] = {
ParamsFor<vec3<u32>, u32>(Kind::Construct), // ParamsFor<vec3<u32>, u32>(Kind::Construct), //
ParamsFor<vec3<f32>, f32>(Kind::Construct), // ParamsFor<vec3<f32>, f32>(Kind::Construct), //
ParamsFor<mat3x3<f32>, f32>(Kind::Construct), //
ParamsFor<mat2x3<f32>, f32>(Kind::Construct), //
ParamsFor<mat3x2<f32>, f32>(Kind::Construct), //
// Conversion // Conversion
ParamsFor<bool, u32>(Kind::Conversion), // ParamsFor<bool, u32>(Kind::Conversion), //
ParamsFor<bool, i32>(Kind::Conversion), // ParamsFor<bool, i32>(Kind::Conversion), //
@ -2016,9 +2023,8 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewArguments) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) { TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
@ -2041,9 +2047,8 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) { TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
@ -2067,9 +2072,8 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) { TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
@ -2092,9 +2096,8 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType) { TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType) {
@ -2118,9 +2121,8 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType)
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType) { TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType) {
@ -2143,9 +2145,8 @@ TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType)
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArgument) { TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArgument) {
@ -2178,9 +2179,8 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArg
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorArgument) { TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorArgument) {
@ -2212,9 +2212,8 @@ TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorAr
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) { TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) {
@ -2285,9 +2284,8 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) { TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
@ -2357,9 +2355,8 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
WrapInFunction(tc); WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_THAT(r()->error(), EXPECT_THAT(r()->error(), HasSubstr("12:34 error: no matching constructor for " +
HasSubstr("12:34 error: no matching constructor for " + MatrixStr(param) + "(" + MatrixStr(param) + "(" + args_tys.str() + ")"));
args_tys.str() + ")\n\n3 candidate constructors:"));
} }
TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Success) { TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Success) {

View File

@ -14,12 +14,14 @@
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h" #include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
#include <unordered_map>
#include <utility> #include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
#include "src/tint/sem/call.h" #include "src/tint/sem/call.h"
#include "src/tint/sem/expression.h" #include "src/tint/sem/expression.h"
#include "src/tint/sem/type_constructor.h" #include "src/tint/sem/type_constructor.h"
#include "src/tint/utils/map.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::VectorizeScalarMatrixConstructors); TINT_INSTANTIATE_TYPEINFO(tint::transform::VectorizeScalarMatrixConstructors);
@ -44,6 +46,8 @@ bool VectorizeScalarMatrixConstructors::ShouldRun(const Program* program, const
} }
void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, DataMap&) const { void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
std::unordered_map<const sem::Matrix*, Symbol> scalar_ctors;
ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* { ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
auto* call = ctx.src->Sem().Get(expr); auto* call = ctx.src->Sem().Get(expr);
auto* ty_ctor = call->Target()->As<sem::TypeConstructor>(); auto* ty_ctor = call->Target()->As<sem::TypeConstructor>();
@ -64,21 +68,56 @@ void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, D
return nullptr; return nullptr;
} }
// Build a list of vector expressions for each column. // Constructs a matrix using vector columns, with the elements constructed using the
ast::ExpressionList columns; // 'element(uint32_t c, uint32_t r)' callback.
for (uint32_t c = 0; c < mat_type->columns(); c++) { auto build_mat = [&](auto&& element) {
// Build a list of scalar expressions for each value in the column. ast::ExpressionList columns(mat_type->columns());
ast::ExpressionList row_values; for (uint32_t c = 0; c < mat_type->columns(); c++) {
for (uint32_t r = 0; r < mat_type->rows(); r++) { ast::ExpressionList row_values(mat_type->rows());
row_values.push_back(ctx.Clone(args[c * mat_type->rows() + r]->Declaration())); for (uint32_t r = 0; r < mat_type->rows(); r++) {
} row_values[r] = element(c, r);
}
// Construct the column vector. // Construct the column vector.
auto* col = columns[c] = ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()), mat_type->rows(),
ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()), mat_type->rows(), row_values); row_values);
columns.push_back(col); }
return ctx.dst->Construct(CreateASTTypeFor(ctx, mat_type), columns);
};
if (args.size() == 1) {
// Generate a helper function for constructing the matrix.
// This is done to ensure that the single argument value is only evaluated once, and
// with the correct expression evaluation order.
auto fn = utils::GetOrCreate(scalar_ctors, mat_type, [&] {
auto name =
ctx.dst->Symbols().New("build_mat" + std::to_string(mat_type->columns()) + "x" +
std::to_string(mat_type->rows()));
ctx.dst->Func(name,
{
// Single scalar parameter
ctx.dst->Param("value", CreateASTTypeFor(ctx, mat_type->type())),
},
CreateASTTypeFor(ctx, mat_type),
{
ctx.dst->Return(build_mat([&](uint32_t, uint32_t) { //
return ctx.dst->Expr("value");
})),
});
return name;
});
return ctx.dst->Call(fn, ctx.Clone(args[0]->Declaration()));
} }
return ctx.dst->Construct(CreateASTTypeFor(ctx, mat_type), columns);
if (args.size() == mat_type->columns() * mat_type->rows()) {
return build_mat([&](uint32_t c, uint32_t r) {
return ctx.Clone(args[c * mat_type->rows() + r]->Declaration());
});
}
TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "matrix constructor has unexpected number of arguments";
return nullptr;
}); });
ctx.Clone(); ctx.Clone();

View File

@ -31,7 +31,57 @@ TEST_F(VectorizeScalarMatrixConstructorsTest, ShouldRunEmptyModule) {
EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src)); EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
} }
TEST_P(VectorizeScalarMatrixConstructorsTest, Basic) { TEST_P(VectorizeScalarMatrixConstructorsTest, SingleScalars) {
uint32_t cols = GetParam().first;
uint32_t rows = GetParam().second;
std::string matrix_no_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows);
std::string matrix = matrix_no_type + "<f32>";
std::string vector = "vec" + std::to_string(rows) + "<f32>";
std::string values;
for (uint32_t c = 0; c < cols; c++) {
if (c > 0) {
values += ", ";
}
values += vector + "(";
for (uint32_t r = 0; r < rows; r++) {
if (r > 0) {
values += ", ";
}
values += "value";
}
values += ")";
}
std::string src = R"(
@stage(fragment)
fn main() {
let m = ${matrix}(42.0);
}
)";
std::string expect = R"(
fn build_${matrix_no_type}(value : f32) -> ${matrix} {
return ${matrix}(${values});
}
@stage(fragment)
fn main() {
let m = build_${matrix_no_type}(42.0);
}
)";
src = utils::ReplaceAll(src, "${matrix}", matrix);
expect = utils::ReplaceAll(expect, "${matrix}", matrix);
expect = utils::ReplaceAll(expect, "${matrix_no_type}", matrix_no_type);
expect = utils::ReplaceAll(expect, "${values}", values);
EXPECT_TRUE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
auto got = Run<VectorizeScalarMatrixConstructors>(src);
EXPECT_EQ(expect, str(got));
}
TEST_P(VectorizeScalarMatrixConstructorsTest, MultipleScalars) {
uint32_t cols = GetParam().first; uint32_t cols = GetParam().first;
uint32_t rows = GetParam().second; uint32_t rows = GetParam().second;
std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>"; std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";

View File

@ -66,6 +66,7 @@
#include "src/tint/transform/simplify_pointers.h" #include "src/tint/transform/simplify_pointers.h"
#include "src/tint/transform/unshadow.h" #include "src/tint/transform/unshadow.h"
#include "src/tint/transform/unwind_discard_functions.h" #include "src/tint/transform/unwind_discard_functions.h"
#include "src/tint/transform/vectorize_scalar_matrix_constructors.h"
#include "src/tint/transform/zero_init_workgroup_memory.h" #include "src/tint/transform/zero_init_workgroup_memory.h"
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
@ -198,6 +199,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
manager.Add<transform::ExpandCompoundAssignment>(); manager.Add<transform::ExpandCompoundAssignment>();
manager.Add<transform::PromoteSideEffectsToDecl>(); manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::UnwindDiscardFunctions>(); manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::VectorizeScalarMatrixConstructors>();
manager.Add<transform::SimplifyPointers>(); manager.Add<transform::SimplifyPointers>();
manager.Add<transform::RemovePhonies>(); manager.Add<transform::RemovePhonies>();
// ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as // ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as
@ -1080,6 +1082,55 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
return EmitZeroValue(out, type); return EmitZeroValue(out, type);
} }
if (auto* mat = call->Type()->As<sem::Matrix>()) {
if (ctor->Parameters().size() == 1) {
// Matrix constructor with single scalar.
auto fn = utils::GetOrCreate(matrix_scalar_ctors_, mat, [&]() -> std::string {
TextBuffer b;
TINT_DEFER(helpers_.Append(b));
auto name = UniqueIdentifier("build_mat" + std::to_string(mat->columns()) + "x" +
std::to_string(mat->rows()));
{
auto l = line(&b);
if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return "";
}
l << " " << name << "(";
if (!EmitType(l, mat->type(), ast::StorageClass::kNone, ast::Access::kUndefined,
"")) {
return "";
}
l << " value) {";
}
{
ScopedIndent si(&b);
auto l = line(&b);
l << "return ";
if (!EmitType(l, mat, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
return "";
}
l << "(";
for (uint32_t i = 0; i < mat->columns() * mat->rows(); i++) {
l << ((i > 0) ? ", value" : "value");
}
l << ");";
}
line(&b) << "}";
return name;
});
if (fn.empty()) {
return false;
}
out << fn << "(";
if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
return false;
}
out << ")";
return true;
}
}
bool brackets = type->IsAnyOf<sem::Array, sem::Struct>(); bool brackets = type->IsAnyOf<sem::Array, sem::Struct>();
// For single-value vector initializers, swizzle the scalar to the right // For single-value vector initializers, swizzle the scalar to the right

View File

@ -512,6 +512,7 @@ class GeneratorImpl : public TextGenerator {
TextBuffer helpers_; // Helper functions emitted at the top of the output TextBuffer helpers_; // Helper functions emitted at the top of the output
std::function<bool()> emit_continuing_; std::function<bool()> emit_continuing_;
std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> dma_intrinsics_; std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> dma_intrinsics_;
std::unordered_map<const sem::Matrix*, std::string> matrix_scalar_ctors_;
std::unordered_map<const sem::Builtin*, std::string> builtins_; std::unordered_map<const sem::Builtin*, std::string> builtins_;
std::unordered_map<const sem::Struct*, std::string> structure_builders_; std::unordered_map<const sem::Struct*, std::string> structure_builders_;
std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_; std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f() { float3 f() {
const float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[1]; return m[1];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f(int x) { float3 f(int x) {
const float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[x]; return m[x];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f() { float3 f() {
const float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[1]; return m[1];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f(int i) { float3 f(int i) {
const float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); const float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[i]; return m[i];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f() { float3 f() {
float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[1]; return m[1];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f() { float3 f() {
float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[1]; return m[1];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f(int x) { float3 f(int x) {
float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[x]; return m[x];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f() { float3 f() {
float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[1]; return m[1];
} }

View File

@ -4,6 +4,6 @@ void unused_entry_point() {
} }
float3 f(int i) { float3 f(int i) {
float3x3 m = float3x3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f); float3x3 m = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
return m[i]; return m[i];
} }

View File

@ -0,0 +1,13 @@
fn get_f32() -> f32 { return 1.0; }
fn f() {
var m2x2 : mat2x2<f32> = mat2x2<f32>(get_f32());
var m2x3 : mat2x3<f32> = mat2x3<f32>(get_f32());
var m2x4 : mat2x4<f32> = mat2x4<f32>(get_f32());
var m3x2 : mat3x2<f32> = mat3x2<f32>(get_f32());
var m3x3 : mat3x3<f32> = mat3x3<f32>(get_f32());
var m3x4 : mat3x4<f32> = mat3x4<f32>(get_f32());
var m4x2 : mat4x2<f32> = mat4x2<f32>(get_f32());
var m4x3 : mat4x3<f32> = mat4x3<f32>(get_f32());
var m4x4 : mat4x4<f32> = mat4x4<f32>(get_f32());
}

View File

@ -0,0 +1,31 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
float get_f32() {
return 1.0f;
}
void f() {
float tint_symbol = get_f32();
mat2 m2x2 = mat2(tint_symbol);
float tint_symbol_1 = get_f32();
mat2x3 m2x3 = mat2x3(tint_symbol_1);
float tint_symbol_2 = get_f32();
mat2x4 m2x4 = mat2x4(tint_symbol_2);
float tint_symbol_3 = get_f32();
mat3x2 m3x2 = mat3x2(tint_symbol_3);
float tint_symbol_4 = get_f32();
mat3 m3x3 = mat3(tint_symbol_4);
float tint_symbol_5 = get_f32();
mat3x4 m3x4 = mat3x4(tint_symbol_5);
float tint_symbol_6 = get_f32();
mat4x2 m4x2 = mat4x2(tint_symbol_6);
float tint_symbol_7 = get_f32();
mat4x3 m4x3 = mat4x3(tint_symbol_7);
float tint_symbol_8 = get_f32();
mat4 m4x4 = mat4(tint_symbol_8);
}

View File

@ -0,0 +1,65 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
float get_f32() {
return 1.0f;
}
float2x2 build_mat2x2(float value) {
return float2x2(float2(value, value), float2(value, value));
}
float2x3 build_mat2x3(float value) {
return float2x3(float3(value, value, value), float3(value, value, value));
}
float2x4 build_mat2x4(float value) {
return float2x4(float4(value, value, value, value), float4(value, value, value, value));
}
float3x2 build_mat3x2(float value) {
return float3x2(float2(value, value), float2(value, value), float2(value, value));
}
float3x3 build_mat3x3(float value) {
return float3x3(float3(value, value, value), float3(value, value, value), float3(value, value, value));
}
float3x4 build_mat3x4(float value) {
return float3x4(float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value));
}
float4x2 build_mat4x2(float value) {
return float4x2(float2(value, value), float2(value, value), float2(value, value), float2(value, value));
}
float4x3 build_mat4x3(float value) {
return float4x3(float3(value, value, value), float3(value, value, value), float3(value, value, value), float3(value, value, value));
}
float4x4 build_mat4x4(float value) {
return float4x4(float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value));
}
void f() {
const float tint_symbol = get_f32();
float2x2 m2x2 = build_mat2x2(tint_symbol);
const float tint_symbol_1 = get_f32();
float2x3 m2x3 = build_mat2x3(tint_symbol_1);
const float tint_symbol_2 = get_f32();
float2x4 m2x4 = build_mat2x4(tint_symbol_2);
const float tint_symbol_3 = get_f32();
float3x2 m3x2 = build_mat3x2(tint_symbol_3);
const float tint_symbol_4 = get_f32();
float3x3 m3x3 = build_mat3x3(tint_symbol_4);
const float tint_symbol_5 = get_f32();
float3x4 m3x4 = build_mat3x4(tint_symbol_5);
const float tint_symbol_6 = get_f32();
float4x2 m4x2 = build_mat4x2(tint_symbol_6);
const float tint_symbol_7 = get_f32();
float4x3 m4x3 = build_mat4x3(tint_symbol_7);
const float tint_symbol_8 = get_f32();
float4x4 m4x4 = build_mat4x4(tint_symbol_8);
}

View File

@ -0,0 +1,64 @@
#include <metal_stdlib>
using namespace metal;
float get_f32() {
return 1.0f;
}
float2x2 build_mat2x2(float value) {
return float2x2(float2(value, value), float2(value, value));
}
float2x3 build_mat2x3(float value) {
return float2x3(float3(value, value, value), float3(value, value, value));
}
float2x4 build_mat2x4(float value) {
return float2x4(float4(value, value, value, value), float4(value, value, value, value));
}
float3x2 build_mat3x2(float value) {
return float3x2(float2(value, value), float2(value, value), float2(value, value));
}
float3x3 build_mat3x3(float value) {
return float3x3(float3(value, value, value), float3(value, value, value), float3(value, value, value));
}
float3x4 build_mat3x4(float value) {
return float3x4(float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value));
}
float4x2 build_mat4x2(float value) {
return float4x2(float2(value, value), float2(value, value), float2(value, value), float2(value, value));
}
float4x3 build_mat4x3(float value) {
return float4x3(float3(value, value, value), float3(value, value, value), float3(value, value, value), float3(value, value, value));
}
float4x4 build_mat4x4(float value) {
return float4x4(float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value), float4(value, value, value, value));
}
void f() {
float const tint_symbol = get_f32();
float2x2 m2x2 = build_mat2x2(tint_symbol);
float const tint_symbol_1 = get_f32();
float2x3 m2x3 = build_mat2x3(tint_symbol_1);
float const tint_symbol_2 = get_f32();
float2x4 m2x4 = build_mat2x4(tint_symbol_2);
float const tint_symbol_3 = get_f32();
float3x2 m3x2 = build_mat3x2(tint_symbol_3);
float const tint_symbol_4 = get_f32();
float3x3 m3x3 = build_mat3x3(tint_symbol_4);
float const tint_symbol_5 = get_f32();
float3x4 m3x4 = build_mat3x4(tint_symbol_5);
float const tint_symbol_6 = get_f32();
float4x2 m4x2 = build_mat4x2(tint_symbol_6);
float const tint_symbol_7 = get_f32();
float4x3 m4x3 = build_mat4x3(tint_symbol_7);
float const tint_symbol_8 = get_f32();
float4x4 m4x4 = build_mat4x4(tint_symbol_8);
}

View File

@ -0,0 +1,194 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 123
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %unused_entry_point "unused_entry_point"
OpName %get_f32 "get_f32"
OpName %build_mat2x2 "build_mat2x2"
OpName %value "value"
OpName %build_mat2x3 "build_mat2x3"
OpName %value_0 "value"
OpName %build_mat2x4 "build_mat2x4"
OpName %value_1 "value"
OpName %build_mat3x2 "build_mat3x2"
OpName %value_2 "value"
OpName %build_mat3x3 "build_mat3x3"
OpName %value_3 "value"
OpName %build_mat3x4 "build_mat3x4"
OpName %value_4 "value"
OpName %build_mat4x2 "build_mat4x2"
OpName %value_5 "value"
OpName %build_mat4x3 "build_mat4x3"
OpName %value_6 "value"
OpName %build_mat4x4 "build_mat4x4"
OpName %value_7 "value"
OpName %f "f"
OpName %m2x2 "m2x2"
OpName %m2x3 "m2x3"
OpName %m2x4 "m2x4"
OpName %m3x2 "m3x2"
OpName %m3x3 "m3x3"
OpName %m3x4 "m3x4"
OpName %m4x2 "m4x2"
OpName %m4x3 "m4x3"
OpName %m4x4 "m4x4"
%void = OpTypeVoid
%1 = OpTypeFunction %void
%float = OpTypeFloat 32
%5 = OpTypeFunction %float
%float_1 = OpConstant %float 1
%v2float = OpTypeVector %float 2
%mat2v2float = OpTypeMatrix %v2float 2
%10 = OpTypeFunction %mat2v2float %float
%v3float = OpTypeVector %float 3
%mat2v3float = OpTypeMatrix %v3float 2
%18 = OpTypeFunction %mat2v3float %float
%v4float = OpTypeVector %float 4
%mat2v4float = OpTypeMatrix %v4float 2
%26 = OpTypeFunction %mat2v4float %float
%mat3v2float = OpTypeMatrix %v2float 3
%34 = OpTypeFunction %mat3v2float %float
%mat3v3float = OpTypeMatrix %v3float 3
%41 = OpTypeFunction %mat3v3float %float
%mat3v4float = OpTypeMatrix %v4float 3
%48 = OpTypeFunction %mat3v4float %float
%mat4v2float = OpTypeMatrix %v2float 4
%55 = OpTypeFunction %mat4v2float %float
%mat4v3float = OpTypeMatrix %v3float 4
%62 = OpTypeFunction %mat4v3float %float
%mat4v4float = OpTypeMatrix %v4float 4
%69 = OpTypeFunction %mat4v4float %float
%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
%82 = OpConstantNull %mat2v2float
%_ptr_Function_mat2v3float = OpTypePointer Function %mat2v3float
%87 = OpConstantNull %mat2v3float
%_ptr_Function_mat2v4float = OpTypePointer Function %mat2v4float
%92 = OpConstantNull %mat2v4float
%_ptr_Function_mat3v2float = OpTypePointer Function %mat3v2float
%97 = OpConstantNull %mat3v2float
%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
%102 = OpConstantNull %mat3v3float
%_ptr_Function_mat3v4float = OpTypePointer Function %mat3v4float
%107 = OpConstantNull %mat3v4float
%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
%112 = OpConstantNull %mat4v2float
%_ptr_Function_mat4v3float = OpTypePointer Function %mat4v3float
%117 = OpConstantNull %mat4v3float
%_ptr_Function_mat4v4float = OpTypePointer Function %mat4v4float
%122 = OpConstantNull %mat4v4float
%unused_entry_point = OpFunction %void None %1
%4 = OpLabel
OpReturn
OpFunctionEnd
%get_f32 = OpFunction %float None %5
%8 = OpLabel
OpReturnValue %float_1
OpFunctionEnd
%build_mat2x2 = OpFunction %mat2v2float None %10
%value = OpFunctionParameter %float
%15 = OpLabel
%16 = OpCompositeConstruct %v2float %value %value
%17 = OpCompositeConstruct %mat2v2float %16 %16
OpReturnValue %17
OpFunctionEnd
%build_mat2x3 = OpFunction %mat2v3float None %18
%value_0 = OpFunctionParameter %float
%23 = OpLabel
%24 = OpCompositeConstruct %v3float %value_0 %value_0 %value_0
%25 = OpCompositeConstruct %mat2v3float %24 %24
OpReturnValue %25
OpFunctionEnd
%build_mat2x4 = OpFunction %mat2v4float None %26
%value_1 = OpFunctionParameter %float
%31 = OpLabel
%32 = OpCompositeConstruct %v4float %value_1 %value_1 %value_1 %value_1
%33 = OpCompositeConstruct %mat2v4float %32 %32
OpReturnValue %33
OpFunctionEnd
%build_mat3x2 = OpFunction %mat3v2float None %34
%value_2 = OpFunctionParameter %float
%38 = OpLabel
%39 = OpCompositeConstruct %v2float %value_2 %value_2
%40 = OpCompositeConstruct %mat3v2float %39 %39 %39
OpReturnValue %40
OpFunctionEnd
%build_mat3x3 = OpFunction %mat3v3float None %41
%value_3 = OpFunctionParameter %float
%45 = OpLabel
%46 = OpCompositeConstruct %v3float %value_3 %value_3 %value_3
%47 = OpCompositeConstruct %mat3v3float %46 %46 %46
OpReturnValue %47
OpFunctionEnd
%build_mat3x4 = OpFunction %mat3v4float None %48
%value_4 = OpFunctionParameter %float
%52 = OpLabel
%53 = OpCompositeConstruct %v4float %value_4 %value_4 %value_4 %value_4
%54 = OpCompositeConstruct %mat3v4float %53 %53 %53
OpReturnValue %54
OpFunctionEnd
%build_mat4x2 = OpFunction %mat4v2float None %55
%value_5 = OpFunctionParameter %float
%59 = OpLabel
%60 = OpCompositeConstruct %v2float %value_5 %value_5
%61 = OpCompositeConstruct %mat4v2float %60 %60 %60 %60
OpReturnValue %61
OpFunctionEnd
%build_mat4x3 = OpFunction %mat4v3float None %62
%value_6 = OpFunctionParameter %float
%66 = OpLabel
%67 = OpCompositeConstruct %v3float %value_6 %value_6 %value_6
%68 = OpCompositeConstruct %mat4v3float %67 %67 %67 %67
OpReturnValue %68
OpFunctionEnd
%build_mat4x4 = OpFunction %mat4v4float None %69
%value_7 = OpFunctionParameter %float
%73 = OpLabel
%74 = OpCompositeConstruct %v4float %value_7 %value_7 %value_7 %value_7
%75 = OpCompositeConstruct %mat4v4float %74 %74 %74 %74
OpReturnValue %75
OpFunctionEnd
%f = OpFunction %void None %1
%77 = OpLabel
%m2x2 = OpVariable %_ptr_Function_mat2v2float Function %82
%m2x3 = OpVariable %_ptr_Function_mat2v3float Function %87
%m2x4 = OpVariable %_ptr_Function_mat2v4float Function %92
%m3x2 = OpVariable %_ptr_Function_mat3v2float Function %97
%m3x3 = OpVariable %_ptr_Function_mat3v3float Function %102
%m3x4 = OpVariable %_ptr_Function_mat3v4float Function %107
%m4x2 = OpVariable %_ptr_Function_mat4v2float Function %112
%m4x3 = OpVariable %_ptr_Function_mat4v3float Function %117
%m4x4 = OpVariable %_ptr_Function_mat4v4float Function %122
%78 = OpFunctionCall %float %get_f32
%79 = OpFunctionCall %mat2v2float %build_mat2x2 %78
OpStore %m2x2 %79
%83 = OpFunctionCall %float %get_f32
%84 = OpFunctionCall %mat2v3float %build_mat2x3 %83
OpStore %m2x3 %84
%88 = OpFunctionCall %float %get_f32
%89 = OpFunctionCall %mat2v4float %build_mat2x4 %88
OpStore %m2x4 %89
%93 = OpFunctionCall %float %get_f32
%94 = OpFunctionCall %mat3v2float %build_mat3x2 %93
OpStore %m3x2 %94
%98 = OpFunctionCall %float %get_f32
%99 = OpFunctionCall %mat3v3float %build_mat3x3 %98
OpStore %m3x3 %99
%103 = OpFunctionCall %float %get_f32
%104 = OpFunctionCall %mat3v4float %build_mat3x4 %103
OpStore %m3x4 %104
%108 = OpFunctionCall %float %get_f32
%109 = OpFunctionCall %mat4v2float %build_mat4x2 %108
OpStore %m4x2 %109
%113 = OpFunctionCall %float %get_f32
%114 = OpFunctionCall %mat4v3float %build_mat4x3 %113
OpStore %m4x3 %114
%118 = OpFunctionCall %float %get_f32
%119 = OpFunctionCall %mat4v4float %build_mat4x4 %118
OpStore %m4x4 %119
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,15 @@
fn get_f32() -> f32 {
return 1.0;
}
fn f() {
var m2x2 : mat2x2<f32> = mat2x2<f32>(get_f32());
var m2x3 : mat2x3<f32> = mat2x3<f32>(get_f32());
var m2x4 : mat2x4<f32> = mat2x4<f32>(get_f32());
var m3x2 : mat3x2<f32> = mat3x2<f32>(get_f32());
var m3x3 : mat3x3<f32> = mat3x3<f32>(get_f32());
var m3x4 : mat3x4<f32> = mat3x4<f32>(get_f32());
var m4x2 : mat4x2<f32> = mat4x2<f32>(get_f32());
var m4x3 : mat4x3<f32> = mat4x3<f32>(get_f32());
var m4x4 : mat4x4<f32> = mat4x4<f32>(get_f32());
}

View File

@ -0,0 +1 @@
let m = mat2x2<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat2 m = mat2(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float2x2 m = float2x2(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float2x2 m = float2x2();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%mat2v2float = OpTypeMatrix %v2float 2
%m = OpConstantNull %mat2v2float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat2x2<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x2 m = float2x2(0.0f, 1.0f, 2.0f, 3.0f); static const float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x2 m = float2x2(0.0f, 1.0f, 2.0f, 3.0f); static const float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x3 m = float2x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f); static const float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));

View File

@ -0,0 +1 @@
let m = mat2x3<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat2x3 m = mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float2x3 m = float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float2x3 m = float2x3();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%mat2v3float = OpTypeMatrix %v3float 2
%m = OpConstantNull %mat2v3float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat2x3<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x3 m = float2x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f); static const float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x4 m = float2x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f); static const float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));

View File

@ -0,0 +1 @@
let m = mat2x4<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat2x4 m = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float2x4 m = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float2x4 m = float2x4();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%mat2v4float = OpTypeMatrix %v4float 2
%m = OpConstantNull %mat2v4float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat2x4<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float2x4 m = float2x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f); static const float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x2 m = float3x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f); static const float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));

View File

@ -0,0 +1 @@
let m = mat3x2<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat3x2 m = mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float3x2 m = float3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float3x2 m = float3x2();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%mat3v2float = OpTypeMatrix %v2float 3
%m = OpConstantNull %mat3v2float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat3x2<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x2 m = float3x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f); static const float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x3 m = float3x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f); static const float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));

View File

@ -0,0 +1 @@
let m = mat3x3<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat3 m = mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float3x3 m = float3x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float3x3 m = float3x3();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%mat3v3float = OpTypeMatrix %v3float 3
%m = OpConstantNull %mat3v3float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat3x3<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x3 m = float3x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f); static const float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x4 m = float3x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f); static const float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));

View File

@ -0,0 +1 @@
let m = mat3x4<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat3x4 m = mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float3x4 m = float3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float3x4 m = float3x4();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%mat3v4float = OpTypeMatrix %v4float 3
%m = OpConstantNull %mat3v4float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat3x4<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float3x4 m = float3x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f); static const float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x2 m = float4x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f); static const float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));

View File

@ -0,0 +1 @@
let m = mat4x2<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat4x2 m = mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float4x2 m = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float4x2 m = float4x2();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%mat4v2float = OpTypeMatrix %v2float 4
%m = OpConstantNull %mat4v2float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat4x2<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x2 m = float4x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f); static const float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x3 m = float4x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f); static const float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));

View File

@ -0,0 +1 @@
let m = mat4x3<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat4x3 m = mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float4x3 m = float4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float4x3 m = float4x3();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%mat4v3float = OpTypeMatrix %v3float 4
%m = OpConstantNull %mat4v3float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat4x3<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x3 m = float4x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f); static const float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x4 m = float4x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f); static const float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));

View File

@ -0,0 +1 @@
let m = mat4x4<f32>();

View File

@ -0,0 +1,7 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
const mat4 m = mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,6 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
static const float4x4 m = float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -0,0 +1,5 @@
#include <metal_stdlib>
using namespace metal;
constant float4x4 m = float4x4();

View File

@ -0,0 +1,21 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 9
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %m "m"
OpName %unused_entry_point "unused_entry_point"
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%mat4v4float = OpTypeMatrix %v4float 4
%m = OpConstantNull %mat4v4float
%void = OpTypeVoid
%5 = OpTypeFunction %void
%unused_entry_point = OpFunction %void None %5
%8 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1 @@
let m = mat4x4<f32>();

View File

@ -3,4 +3,4 @@ void unused_entry_point() {
return; return;
} }
static const float4x4 m = float4x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f); static const float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));