Import Tint changes from Dawn
Changes:
- 51719ccc01dc4338ef579d86235c9742546d4956 tint: Fix SPIR-V validation around interpolation decorati... by Ben Clayton <bclayton@google.com>
- 66d4f6e6fb13dbcdf7d9588eb93008f9149779c3 tint/writer/spirv: Support for F16 type, constructor, and... by Zhaoming Jiang <zhaoming.jiang@intel.com>
GitOrigin-RevId: 51719ccc01dc4338ef579d86235c9742546d4956
Change-Id: Ia0fc3b3b5250f7cfc5088bd80e18930410e23fcc
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/96080
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index b34f66b..11c439d 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -1795,6 +1795,14 @@
}
}
+ if (type == ast::InterpolationType::kFlat &&
+ !ast::HasAttribute<ast::LocationAttribute>(*attributes)) {
+ // WGSL requires that '@interpolate(flat)' needs to be paired with '@location', however
+ // SPIR-V requires all fragment shader integer Inputs are 'flat'. If the decorations do not
+ // contain a SpvDecorationLocation, then make this perspective.
+ type = ast::InterpolationType::kPerspective;
+ }
+
// Apply interpolation.
if (type == ast::InterpolationType::kPerspective &&
sampling == ast::InterpolationSampling::kNone) {
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index a324bcc..6f84029 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -159,14 +159,16 @@
ast::AttributeList attributes) {
auto* ast_type = CreateASTTypeFor(ctx, type);
if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
- // Vulkan requires that integer user-defined fragment inputs are
- // always decorated with `Flat`.
- // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
- // attribute is required for integers.
- if (type->is_integer_scalar_or_vector() &&
- ast::HasAttribute<ast::LocationAttribute>(attributes) &&
+ // Vulkan requires that integer user-defined fragment inputs are always decorated with
+ // `Flat`. See:
+ // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/StandaloneSpirv.html#VUID-StandaloneSpirv-Flat-04744
+ // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is
+ // required for integers.
+ if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
+ type->is_integer_scalar_or_vector() &&
!ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
- func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
+ (ast::HasAttribute<ast::LocationAttribute>(attributes) ||
+ cfg.shader_style == ShaderStyle::kSpirv)) {
attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
ast::InterpolationSampling::kNone));
}
@@ -226,14 +228,15 @@
const sem::Type* type,
ast::AttributeList attributes,
const ast::Expression* value) {
- // Vulkan requires that integer user-defined vertex outputs are
- // always decorated with `Flat`.
- // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
- // attribute is required for integers.
- if (cfg.shader_style == ShaderStyle::kSpirv && type->is_integer_scalar_or_vector() &&
+ // Vulkan requires that integer user-defined vertex outputs are always decorated with
+ // `Flat`.
+ // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is required
+ // for integers.
+ if (cfg.shader_style == ShaderStyle::kSpirv &&
+ func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
+ type->is_integer_scalar_or_vector() &&
ast::HasAttribute<ast::LocationAttribute>(attributes) &&
- !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
- func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
+ !ast::HasAttribute<ast::InterpolateAttribute>(attributes)) {
attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
ast::InterpolationSampling::kNone));
}
@@ -262,13 +265,17 @@
/// that will be passed to the original function.
/// @param param the original function parameter
void ProcessNonStructParameter(const sem::Parameter* param) {
+ // Do not add interpolation attributes on vertex input
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
// Remove the shader IO attributes from the inner function parameter, and
// attach them to the new object instead.
ast::AttributeList attributes;
for (auto* attr : param->Declaration()->attributes) {
if (IsShaderIOAttribute(attr)) {
ctx.Remove(param->Declaration()->attributes, attr);
- attributes.push_back(ctx.Clone(attr));
+ if ((do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
+ attributes.push_back(ctx.Clone(attr));
+ }
}
}
@@ -283,6 +290,9 @@
/// the original function.
/// @param param the original function parameter
void ProcessStructParameter(const sem::Parameter* param) {
+ // Do not add interpolation attributes on vertex input
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
+
auto* str = param->Type()->As<sem::Struct>();
// Recreate struct members in the outer entry point and build an initializer
@@ -297,12 +307,6 @@
auto* member_ast = member->Declaration();
auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
- // In GLSL, do not add interpolation attributes on vertex input
- bool do_interpolate = true;
- if (cfg.shader_style == ShaderStyle::kGlsl &&
- func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
- do_interpolate = false;
- }
auto attributes = CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
auto* input_expr = AddInput(name, member->Type(), std::move(attributes));
inner_struct_values.push_back(input_expr);
@@ -319,12 +323,8 @@
/// @param inner_ret_type the original function return type
/// @param original_result the result object produced by the original function
void ProcessReturnType(const sem::Type* inner_ret_type, Symbol original_result) {
- bool do_interpolate = true;
- // In GLSL, do not add interpolation attributes on fragment output
- if (cfg.shader_style == ShaderStyle::kGlsl &&
- func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
- do_interpolate = false;
- }
+ // Do not add interpolation attributes on fragment output
+ bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
if (auto* str = inner_ret_type->As<sem::Struct>()) {
for (auto* member : str->Members()) {
if (member->Type()->Is<sem::Struct>()) {
diff --git a/src/tint/transform/canonicalize_entry_point_io_test.cc b/src/tint/transform/canonicalize_entry_point_io_test.cc
index f17c5f5..c8af902 100644
--- a/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/src/tint/transform/canonicalize_entry_point_io_test.cc
@@ -1978,13 +1978,13 @@
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
struct VertexIn {
i : i32,
@@ -2108,13 +2108,13 @@
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
-@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
-@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
+@location(1) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
-@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
+@location(2) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
-@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
+@location(3) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
fn vert_main_inner(in : VertexIn) -> VertexOut {
return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
@@ -2344,7 +2344,7 @@
}
struct tint_symbol_2 {
- @location(1) @interpolate(flat)
+ @location(1)
value : f32,
}
@@ -2397,7 +2397,7 @@
}
struct tint_symbol_2 {
- @location(1) @interpolate(flat)
+ @location(1)
value : f32,
}
@@ -3868,9 +3868,9 @@
)";
auto* expect = R"(
-@builtin(sample_index) @internal(disable_validation__ignore_storage_class) var<in> sample_index_1 : u32;
+@builtin(sample_index) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> sample_index_1 : u32;
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1u>;
+@builtin(sample_mask) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1u>;
@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> value : array<u32, 1u>;
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 833324a..b34fec3 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -379,22 +379,18 @@
}
bool Builder::GenerateExtension(ast::Extension extension) {
- /*
- For each supported extension, push corresponding capability into the builder.
- For example:
- if (kind == ast::Extension::Kind::kF16) {
- push_capability(SpvCapabilityFloat16);
- push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
- push_capability(SpvCapabilityStorageBuffer16BitAccess);
- push_capability(SpvCapabilityStorageInputOutput16);
- }
- */
switch (extension) {
case ast::Extension::kChromiumExperimentalDP4a:
push_extension("SPV_KHR_integer_dot_product");
push_capability(SpvCapabilityDotProductKHR);
push_capability(SpvCapabilityDotProductInput4x8BitPackedKHR);
break;
+ case ast::Extension::kF16:
+ push_capability(SpvCapabilityFloat16);
+ push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
+ push_capability(SpvCapabilityStorageBuffer16BitAccess);
+ push_capability(SpvCapabilityStorageInputOutput16);
+ break;
default:
return false;
}
@@ -1354,6 +1350,9 @@
if (result_type->Is<sem::F32>()) {
return GenerateConstantIfNeeded(ScalarConstant::F32(0).AsSpecOp(constant_id));
}
+ if (result_type->Is<sem::F16>()) {
+ return GenerateConstantIfNeeded(ScalarConstant::F16(0).AsSpecOp(constant_id));
+ }
if (result_type->Is<sem::Bool>()) {
return GenerateConstantIfNeeded(ScalarConstant::Bool(false).AsSpecOp(constant_id));
}
@@ -1560,22 +1559,23 @@
auto* from_type = TypeOf(from_expr)->UnwrapRef();
spv::Op op = spv::Op::OpNop;
- if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
+ if ((from_type->Is<sem::I32>() && to_type->is_float_scalar()) ||
(from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
op = spv::Op::OpConvertSToF;
- } else if ((from_type->Is<sem::U32>() && to_type->Is<sem::F32>()) ||
+ } else if ((from_type->Is<sem::U32>() && to_type->is_float_scalar()) ||
(from_type->is_unsigned_integer_vector() && to_type->is_float_vector())) {
op = spv::Op::OpConvertUToF;
- } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::I32>()) ||
+ } else if ((from_type->is_float_scalar() && to_type->Is<sem::I32>()) ||
(from_type->is_float_vector() && to_type->is_signed_integer_vector())) {
op = spv::Op::OpConvertFToS;
- } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::U32>()) ||
+ } else if ((from_type->is_float_scalar() && to_type->Is<sem::U32>()) ||
(from_type->is_float_vector() && to_type->is_unsigned_integer_vector())) {
op = spv::Op::OpConvertFToU;
} else if ((from_type->Is<sem::Bool>() && to_type->Is<sem::Bool>()) ||
(from_type->Is<sem::U32>() && to_type->Is<sem::U32>()) ||
(from_type->Is<sem::I32>() && to_type->Is<sem::I32>()) ||
(from_type->Is<sem::F32>() && to_type->Is<sem::F32>()) ||
+ (from_type->Is<sem::F16>() && to_type->Is<sem::F16>()) ||
(from_type->Is<sem::Vector>() && (from_type == to_type))) {
return val_id;
} else if ((from_type->Is<sem::I32>() && to_type->Is<sem::U32>()) ||
@@ -1608,6 +1608,9 @@
if (to_elem_type->Is<sem::F32>()) {
zero_id = GenerateConstantIfNeeded(ScalarConstant::F32(0));
one_id = GenerateConstantIfNeeded(ScalarConstant::F32(1));
+ } else if (to_elem_type->Is<sem::F16>()) {
+ zero_id = GenerateConstantIfNeeded(ScalarConstant::F16(0));
+ one_id = GenerateConstantIfNeeded(ScalarConstant::F16(1));
} else if (to_elem_type->Is<sem::U32>()) {
zero_id = GenerateConstantIfNeeded(ScalarConstant::U32(0));
one_id = GenerateConstantIfNeeded(ScalarConstant::U32(1));
@@ -1691,7 +1694,9 @@
constant.value.f32 = static_cast<float>(f->value);
return;
case ast::FloatLiteralExpression::Suffix::kH:
- error_ = "Type f16 is not completely implemented yet";
+ constant.kind = ScalarConstant::Kind::kF16;
+ constant.value.f16 = {f16(static_cast<float>(f->value)).BitsRepresentation()};
+ return;
}
},
[&](Default) { error_ = "unknown literal type"; });
@@ -1750,6 +1755,10 @@
auto val = constant->As<f32>();
return GenerateConstantIfNeeded(ScalarConstant::F32(val.value));
},
+ [&](const sem::F16*) {
+ auto val = constant->As<f16>();
+ return GenerateConstantIfNeeded(ScalarConstant::F16(val.value));
+ },
[&](const sem::I32*) {
auto val = constant->As<i32>();
return GenerateConstantIfNeeded(ScalarConstant::I32(val.value));
@@ -1788,6 +1797,10 @@
type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
break;
}
+ case ScalarConstant::Kind::kF16: {
+ type_id = GenerateTypeIfNeeded(builder_.create<sem::F16>());
+ break;
+ }
case ScalarConstant::Kind::kBool: {
type_id = GenerateTypeIfNeeded(builder_.create<sem::Bool>());
break;
@@ -1822,6 +1835,12 @@
{Operand(type_id), result, Operand(constant.value.f32)});
break;
}
+ case ScalarConstant::Kind::kF16: {
+ push_type(
+ constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
+ {Operand(type_id), result, U32Operand(constant.value.f16.bits_representation)});
+ break;
+ }
case ScalarConstant::Kind::kBool: {
if (constant.value.b) {
push_type(
@@ -3795,9 +3814,8 @@
return true;
},
[&](const sem::F16*) {
- // Should be `push_type(spv::Op::OpTypeFloat, {result, Operand(16u)});`
- error_ = "Type f16 is not completely implemented yet.";
- return false;
+ push_type(spv::Op::OpTypeFloat, {result, Operand(16u)});
+ return true;
},
[&](const sem::I32*) {
push_type(spv::Op::OpTypeInt, {result, Operand(32u), Operand(1u)});
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index d8cb809..7fc7ac6 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -212,6 +212,23 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = Construct<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 2u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Literal) {
auto* cast = vec2<bool>(true);
WrapInFunction(cast);
@@ -270,6 +287,25 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_Literal) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec2<f32>("x", "x");
@@ -295,6 +331,33 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec2<f16>("x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 9u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpCompositeConstruct %6 %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) {
auto* cast = vec2<f32>(1_f, 2_f);
WrapInFunction(cast);
@@ -313,7 +376,27 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(1_h, 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec2<f32>("x");
WrapInFunction(var, cast);
@@ -338,7 +421,34 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec2<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2_Const) {
auto* cast = vec2<f32>(vec2<f32>(1_f, 2_f));
WrapInFunction(cast);
@@ -356,6 +466,26 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(1_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec3<f32>("x", "x", "x");
@@ -382,6 +512,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec3<f16>("x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpCompositeConstruct %6 %7 %8 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) {
auto* cast = vec3<f32>(1_f, 2_f, 3_f);
WrapInFunction(cast);
@@ -401,6 +559,27 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
auto* cast = vec3<bool>("x", "x", "x");
@@ -471,6 +650,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec3<f16>("x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpCompositeConstruct %6 %7 %8 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) {
auto* cast = vec3<f32>(1_f, 2_f, 3_f);
WrapInFunction(cast);
@@ -490,6 +697,27 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
auto* cast = vec3<f32>(1_f, "x");
@@ -520,6 +748,38 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
+ auto* cast = vec3<f16>(1_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 14u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstant %2 0x1.8p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 3
+%10 = OpConstant %2 0x1p+0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%11 = OpLoad %1 %6
+%12 = OpCompositeExtract %2 %11 0
+%13 = OpCompositeExtract %2 %11 1
+%14 = OpCompositeConstruct %9 %10 %12 %13
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) {
auto* cast = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
WrapInFunction(cast);
@@ -539,6 +799,27 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec3<f32>("x", 3_f);
@@ -569,6 +850,38 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec3<f16>("x", 3_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 14u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 3
+%13 = OpConstant %2 0x1.8p+1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%14 = OpCompositeConstruct %9 %11 %12 %13
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) {
auto* cast = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
WrapInFunction(cast);
@@ -588,7 +901,28 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(1_h, 2_h), 3_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(1_f, 2_f, 3_f)));
auto* cast = vec3<f32>("x");
WrapInFunction(var, cast);
@@ -614,7 +948,35 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(1_h, 2_h, 3_h)));
+ auto* cast = vec3<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Function %1
+%9 = OpConstantNull %1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %7 %6
+%11 = OpLoad %1 %7
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3_Const) {
auto* cast = vec3<f32>(vec3<f32>(1_f, 2_f, 3_f));
WrapInFunction(cast);
@@ -633,6 +995,27 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(1_h, 2_h, 3_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
auto* cast = vec4<bool>("x");
@@ -698,6 +1081,32 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec4<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpCompositeConstruct %6 %7 %7 %7 %7
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) {
auto* cast = vec4<f32>(2_f);
WrapInFunction(cast);
@@ -715,6 +1124,25 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
auto* cast = vec4<f32>("x", "x", "x", "x");
@@ -742,6 +1170,35 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
+ auto* cast = vec4<f16>("x", "x", "x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%6 = OpTypeVector %1 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%7 = OpLoad %1 %3
+%8 = OpLoad %1 %3
+%9 = OpLoad %1 %3
+%10 = OpLoad %1 %3
+%11 = OpCompositeConstruct %6 %7 %8 %9 %10
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
auto* cast = vec4<f32>(1_f, 2_f, 3_f, 4_f);
WrapInFunction(cast);
@@ -762,6 +1219,28 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, 2_h, 3_h, 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>(1_f, 2_f, "x");
@@ -791,6 +1270,37 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>(1_h, 2_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%13 = OpCompositeConstruct %9 %3 %4 %11 %12
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) {
auto* cast = vec4<f32>(1_f, 2_f, vec2<f32>(3_f, 4_f));
WrapInFunction(cast);
@@ -811,6 +1321,28 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, 2_h, vec2<f16>(3_h, 4_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
auto* cast = vec4<f32>(1_f, "x", 4_f);
@@ -842,6 +1374,39 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
+ auto* cast = vec4<f16>(1_h, "x", 4_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 15u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstant %2 0x1.8p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+%10 = OpConstant %2 0x1p+0
+%14 = OpConstant %2 0x1p+2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%11 = OpLoad %1 %6
+%12 = OpCompositeExtract %2 %11 0
+%13 = OpCompositeExtract %2 %11 1
+%15 = OpCompositeConstruct %9 %10 %12 %13 %14
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) {
auto* cast = vec4<f32>(1_f, vec2<f32>(2_f, 3_f), 4_f);
WrapInFunction(cast);
@@ -862,6 +1427,28 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(1_h, vec2<f16>(2_h, 3_h), 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>("x", 3_f, 4_f);
@@ -893,6 +1480,39 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>("x", 3_h, 4_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 15u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+%13 = OpConstant %2 0x1.8p+1
+%14 = OpConstant %2 0x1p+2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%15 = OpCompositeConstruct %9 %11 %12 %13 %14
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) {
auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), 3_f, 4_f);
WrapInFunction(cast);
@@ -913,7 +1533,29 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), 3_h, 4_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 7u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstant %2 0x1p+2
+%7 = OpConstantComposite %1 %3 %4 %5 %6
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2) {
auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
auto* cast = vec4<f32>("x", "x");
WrapInFunction(var, cast);
@@ -945,7 +1587,41 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2_Const) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
+ auto* cast = vec4<f16>("x", "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 16u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4
+%7 = OpTypePointer Function %1
+%8 = OpConstantNull %1
+%9 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %6 %5
+%10 = OpLoad %1 %6
+%11 = OpCompositeExtract %2 %10 0
+%12 = OpCompositeExtract %2 %10 1
+%13 = OpLoad %1 %6
+%14 = OpCompositeExtract %2 %13 0
+%15 = OpCompositeExtract %2 %13 1
+%16 = OpCompositeConstruct %9 %11 %12 %14 %15
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2_Const) {
auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), vec2<f32>(1_f, 2_f));
WrapInFunction(cast);
@@ -963,6 +1639,26 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), vec2<f16>(1_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 5u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstantComposite %1 %3 %4 %3 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
auto* cast = vec4<f32>(2_f, "x");
@@ -992,6 +1688,37 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
+ auto* cast = vec4<f16>(2_h, "x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Function %1
+%7 = OpConstantNull %1
+%8 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %5 %4
+%9 = OpLoad %1 %5
+%10 = OpCompositeExtract %2 %9 0
+%11 = OpCompositeExtract %2 %9 1
+%12 = OpCompositeExtract %2 %9 2
+%13 = OpCompositeConstruct %8 %3 %10 %11 %12
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) {
auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1009,6 +1736,25 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
auto* cast = vec4<f32>("x", 2_f);
@@ -1038,6 +1784,37 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
+ auto* cast = vec4<f16>("x", 2_h);
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var));
+ EXPECT_EQ(b.GenerateExpression(cast), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Function %1
+%7 = OpConstantNull %1
+%8 = OpTypeVector %2 4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %5 %4
+%9 = OpLoad %1 %5
+%10 = OpCompositeExtract %2 %9 0
+%11 = OpCompositeExtract %2 %9 1
+%12 = OpCompositeExtract %2 %9 2
+%13 = OpCompositeConstruct %8 %10 %11 %12 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) {
auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
WrapInFunction(cast);
@@ -1055,7 +1832,26 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
-TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16_Const) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec4) {
auto* value = vec4<f32>(2_f, 2_f, 2_f, 2_f);
auto* cast = vec4<f32>(value);
WrapInFunction(cast);
@@ -1073,6 +1869,26 @@
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
}
+TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* value = vec4<f16>(2_h, 2_h, 2_h, 2_h);
+ auto* cast = vec4<f16>(value);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F32_With_F32) {
auto* ctor = Construct<f32>(2_f);
GlobalConst("g", ty.f32(), ctor);
@@ -1094,6 +1910,29 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<f16>(2_h);
+ GlobalConst("g", ty.f16(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 16
+%6 = OpConstant %5 0x1p+1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F32_With_F32) {
auto* ctor = Construct<f32>(2_f);
GlobalVar("g", ty.f32(), ast::StorageClass::kPrivate, ctor);
@@ -1111,6 +1950,25 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F16_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<f16>(2_h);
+ GlobalVar("g", ty.f16(), ast::StorageClass::kPrivate, ctor);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1p+1
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F32) {
auto* ctor = Construct<u32>(1.5_f);
GlobalConst("g", ty.u32(), ctor);
@@ -1132,6 +1990,29 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<u32>(1.5_h);
+ GlobalConst("g", ty.u32(), ctor);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeInt 32 0
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %7 %6
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F32) {
auto* ctor = Construct<u32>(1.5_f);
GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor);
@@ -1149,6 +2030,25 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* ctor = Construct<u32>(1.5_h);
+ GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstant %1 1
+%4 = OpTypePointer Private %1
+%3 = OpVariable %4 Private %2
+%6 = OpTypeVoid
+%5 = OpTypeFunction %6
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
auto* cast = vec2<f32>(2_f);
GlobalConst("g", ty.vec2<f32>(), cast);
@@ -1172,6 +2072,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ GlobalConst("g", ty.vec2<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) {
auto* cast = vec2<f32>(2_f);
auto* g = GlobalVar("g", ty.vec2<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1188,7 +2113,25 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec2<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F32_With_Vec2) {
auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
GlobalConst("g", ty.vec2<f32>(), cast);
WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
@@ -1211,7 +2154,32 @@
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec2<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 2
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F32_With_Vec2) {
auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
GlobalVar("a", ty.vec2<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1231,7 +2199,29 @@
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+ GlobalVar("a", ty.vec2<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F32_With_Vec3) {
auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
GlobalConst("g", ty.vec3<f32>(), cast);
WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
@@ -1254,7 +2244,32 @@
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F32_With_Vec3) {
auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
GlobalVar("a", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1274,7 +2289,29 @@
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+ GlobalVar("a", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec4) {
auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
GlobalConst("g", ty.vec4<f32>(), cast);
WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
@@ -1296,7 +2333,33 @@
)");
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec4) {
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec4) {
auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
GlobalVar("a", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1316,6 +2379,28 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ GlobalVar("a", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+%6 = OpTypePointer Private %1
+%5 = OpVariable %6 Private %4
+%8 = OpTypeVoid
+%7 = OpTypeFunction %8
+)");
+
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
auto* cast = vec3<f32>(2_f);
GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1339,6 +2424,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h);
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) {
auto* cast = vec3<f32>(2_f);
auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1355,6 +2465,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1378,6 +2506,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1394,6 +2547,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
GlobalConst("g", ty.vec3<f32>(), cast);
@@ -1417,6 +2588,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec3<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 3
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
auto* g = GlobalVar("g", ty.vec3<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1433,6 +2629,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec3<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
auto* cast = vec4<f32>(2_f);
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1456,6 +2670,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) {
auto* cast = vec4<f32>(2_f);
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1472,6 +2711,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1495,6 +2752,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1511,6 +2793,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1534,6 +2834,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1550,6 +2875,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1573,6 +2916,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1589,7 +2957,25 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec2_Vec2) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
GlobalConst("g", ty.vec4<f32>(), cast);
WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
@@ -1612,7 +2998,32 @@
Validate(b);
}
-TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec2_Vec2) {
auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1628,6 +3039,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1667,6 +3096,24 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
GlobalConst("g", ty.vec4<f32>(), cast);
@@ -1690,6 +3137,31 @@
Validate(b);
}
+TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ GlobalConst("g", ty.vec4<f16>(), cast);
+ WrapInFunction(Decl(Var("l", nullptr, Expr("g"))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%6 = OpTypeFloat 16
+%5 = OpTypeVector %6 4
+%7 = OpConstant %6 0x1p+1
+%8 = OpConstantComposite %5 %7 %7 %7 %7
+%10 = OpTypePointer Function %5
+%11 = OpConstantNull %5
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %9 %8
+OpReturn
+)");
+ Validate(b);
+}
+
TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
auto* g = GlobalVar("g", ty.vec4<f32>(), ast::StorageClass::kPrivate, cast);
@@ -1706,7 +3178,25 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+ auto* g = GlobalVar("g", ty.vec4<f16>(), ast::StorageClass::kPrivate, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 0x1p+1
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F32_With_Vec2_Vec2) {
auto* cast = mat2x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1724,7 +3214,27 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_With_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F32_With_Vec2_Vec2_Vec2) {
auto* cast = mat3x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1742,7 +3252,27 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat3x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F32_With_Vec2_Vec2_Vec2_Vec2) {
auto* cast = mat4x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f),
vec2<f32>(2_f, 2_f));
WrapInFunction(cast);
@@ -1761,7 +3291,28 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_With_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h),
+ vec2<f16>(2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F32_With_Vec3_Vec3) {
auto* cast = mat2x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1779,7 +3330,27 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_With_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F32_With_Vec3_Vec3_Vec3) {
auto* cast =
mat3x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1798,7 +3369,28 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast =
+ mat3x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F32_With_Vec3_Vec3_Vec3_Vec3) {
auto* cast = mat4x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f),
vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1817,7 +3409,28 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_With_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h),
+ vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F32_With_Vec4_Vec4) {
auto* cast = mat2x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1835,7 +3448,27 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_With_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat2x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 2
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F32_With_Vec4_Vec4_Vec4) {
auto* cast = mat3x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1854,7 +3487,28 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
+TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat3x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
+ vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 3
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F32_With_Vec4_Vec4_Vec4_Vec4) {
auto* cast = mat4x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
WrapInFunction(cast);
@@ -1873,6 +3527,27 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = mat4x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
+ vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 4
+%1 = OpTypeMatrix %2 4
+%4 = OpConstant %3 0x1p+1
+%5 = OpConstantComposite %2 %4 %4 %4 %4
+%6 = OpConstantComposite %1 %5 %5 %5 %5
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
auto* cast = array<f32, 5>(2_f, 2_f, 2_f, 2_f, 2_f);
WrapInFunction(cast);
@@ -1891,7 +3566,27 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) {
+TEST_F(SpvBuilderConstructorTest, Type_Array_5_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* cast = array<f16, 5>(2_h, 2_h, 2_h, 2_h, 2_h);
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(cast), 6u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 5
+%1 = OpTypeArray %2 %4
+%5 = OpConstant %2 0x1p+1
+%6 = OpConstantComposite %1 %5 %5 %5 %5 %5
+)");
+}
+
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F32) {
auto* first = vec3<f32>(1_f, 2_f, 3_f);
auto* second = vec3<f32>(1_f, 2_f, 3_f);
auto* t = Construct(ty.array(ty.vec3<f32>(), 2_u), first, second);
@@ -1913,6 +3608,30 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* first = vec3<f16>(1_h, 2_h, 3_h);
+ auto* second = vec3<f16>(1_h, 2_h, 3_h);
+ auto* t = Construct(ty.array(ty.vec3<f16>(), 2_u), first, second);
+ WrapInFunction(t);
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(t), 10u);
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%4 = OpTypeInt 32 0
+%5 = OpConstant %4 2
+%1 = OpTypeArray %2 %5
+%6 = OpConstant %3 0x1p+0
+%7 = OpConstant %3 0x1p+1
+%8 = OpConstant %3 0x1.8p+1
+%9 = OpConstantComposite %2 %6 %7 %8
+%10 = OpConstantComposite %1 %9 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
auto* v1 = vec3<f32>(2_f, 2_f, 2_f);
auto* v2 = vec3<f32>(2_f, 2_f, 2_f);
@@ -2030,6 +3749,25 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* t = Construct<f16>();
+
+ WrapInFunction(t);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstantNull %1
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_I32) {
auto* t = Construct<i32>();
@@ -2099,7 +3837,7 @@
)");
}
-TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) {
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F32) {
auto* t = mat4x2<f32>();
WrapInFunction(t);
@@ -2118,6 +3856,27 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* t = mat4x2<f16>();
+
+ WrapInFunction(t);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(t), 4u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 4
+%4 = OpConstantNull %1
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
auto* t = array<i32, 2>();
@@ -2228,6 +3987,32 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
+ auto* cast = Construct<i32>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.33p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeInt 32 1
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertFToS %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) {
auto* var = Decl(Var("x", ty.f32(), Expr(2.4_f)));
auto* cast = Construct<u32>("x");
@@ -2252,6 +4037,32 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_F16_To_U32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.f16(), Expr(2.4_h)));
+ auto* cast = Construct<u32>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.33p+1
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeInt 32 0
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertFToU %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) {
auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
auto* cast = Construct<f32>("x");
@@ -2276,6 +4087,32 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.i32(), Expr(2_i)));
+ auto* cast = Construct<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+%2 = OpConstant %1 2
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeFloat 16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertSToF %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) {
auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
auto* cast = Construct<f32>("x");
@@ -2300,6 +4137,32 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = Decl(Var("x", ty.u32(), Expr(2_u)));
+ auto* cast = Construct<f16>("x");
+ WrapInFunction(var, cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateStatement(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstant %1 2
+%4 = OpTypePointer Function %1
+%5 = OpConstantNull %1
+%7 = OpTypeFloat 16
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(OpStore %3 %2
+%8 = OpLoad %1 %3
+%6 = OpConvertUToF %7 %8
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
@@ -2352,6 +4215,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_I32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<i32>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 16
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToS %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
@@ -2404,6 +4295,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_U32) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<f16>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<u32>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 16
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToU %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
@@ -2430,6 +4349,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<f16>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 16
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertSToF %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
@@ -2456,6 +4403,34 @@
)");
}
+TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* var = GlobalVar("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+
+ auto* cast = vec3<f16>("i");
+ WrapInFunction(cast);
+
+ spirv::Builder& b = Build();
+
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+ EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 16
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertUToF %7 %9
+)");
+}
+
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithAllConstConstructors) {
// vec3<f32>(1.0, 2.0, 3.0) -> true
auto* t = vec3<f32>(1_f, 2_f, 3_f);
diff --git a/src/tint/writer/spirv/builder_entry_point_test.cc b/src/tint/writer/spirv/builder_entry_point_test.cc
index 8cbf2cc..8e9d857 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -311,9 +311,12 @@
// Make sure we generate the SampleRateShading capability.
EXPECT_EQ(DumpInstructions(b.capabilities()),
- "OpCapability Shader\n"
- "OpCapability SampleRateShading\n");
- EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
+ R"(OpCapability Shader
+OpCapability SampleRateShading
+)");
+ EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 BuiltIn SampleId
+OpDecorate %1 Flat
+)");
}
} // namespace
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index 05f6929..57b26a3 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -115,6 +115,36 @@
Validate(b);
}
+TEST_F(BuilderTest, GlobalConst_Vec_F16_Constructor) {
+ // const c = vec3<f16>(1h, 2h, 3h);
+ // var v = c;
+ Enable(ast::Extension::kF16);
+
+ auto* c = GlobalConst("c", nullptr, vec3<f16>(1_h, 2_h, 3_h));
+ GlobalVar("v", nullptr, ast::StorageClass::kPrivate, Expr(c));
+
+ spirv::Builder& b = SanitizeAndBuild();
+
+ ASSERT_TRUE(b.Build()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 16
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 0x1p+0
+%4 = OpConstant %2 0x1p+1
+%5 = OpConstant %2 0x1.8p+1
+%6 = OpConstantComposite %1 %3 %4 %5
+%8 = OpTypePointer Private %1
+%7 = OpVariable %8 Private %6
+%10 = OpTypeVoid
+%9 = OpTypeFunction %10
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+)");
+
+ Validate(b);
+}
+
TEST_F(BuilderTest, GlobalConst_Vec_AInt_Constructor) {
// const c = vec3(1, 2, 3);
// var v = c;
diff --git a/src/tint/writer/spirv/builder_literal_test.cc b/src/tint/writer/spirv/builder_literal_test.cc
index 218db86..374c80b 100644
--- a/src/tint/writer/spirv/builder_literal_test.cc
+++ b/src/tint/writer/spirv/builder_literal_test.cc
@@ -163,4 +163,39 @@
)");
}
+TEST_F(BuilderTest, Literal_F16) {
+ Enable(ast::Extension::kF16);
+
+ auto* i = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ WrapInFunction(i);
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateLiteralIfNeeded(nullptr, i);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(2u, id);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.73cp+4
+)");
+}
+
+TEST_F(BuilderTest, Literal_F16_Dedup) {
+ Enable(ast::Extension::kF16);
+
+ auto* i1 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ auto* i2 = create<ast::FloatLiteralExpression>(23.245, ast::FloatLiteralExpression::Suffix::kH);
+ WrapInFunction(i1, i2);
+
+ spirv::Builder& b = Build();
+
+ ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
+ ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 16
+%2 = OpConstant %1 0x1.73cp+4
+)");
+}
+
} // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc
index b4bff9b..b3ead65 100644
--- a/src/tint/writer/spirv/builder_type_test.cc
+++ b/src/tint/writer/spirv/builder_type_test.cc
@@ -175,6 +175,34 @@
ASSERT_FALSE(b.has_error()) << b.error();
}
+TEST_F(BuilderTest_Type, GenerateF16) {
+ auto* f16 = create<sem::F16>();
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateTypeIfNeeded(f16);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(id, 1u);
+
+ ASSERT_EQ(b.types().size(), 1u);
+ EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeFloat 16
+)");
+}
+
+TEST_F(BuilderTest_Type, ReturnsGeneratedF16) {
+ auto* f16 = create<sem::F16>();
+ auto* i32 = create<sem::I32>();
+
+ spirv::Builder& b = Build();
+
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+}
+
TEST_F(BuilderTest_Type, GenerateI32) {
auto* i32 = create<sem::I32>();
@@ -236,6 +264,39 @@
ASSERT_FALSE(b.has_error()) << b.error();
}
+TEST_F(BuilderTest_Type, GenerateF16Matrix) {
+ auto* f16 = create<sem::F16>();
+ auto* vec3 = create<sem::Vector>(f16, 3u);
+ auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+
+ spirv::Builder& b = Build();
+
+ auto id = b.GenerateTypeIfNeeded(mat2x3);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(id, 1u);
+
+ EXPECT_EQ(b.types().size(), 3u);
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 16
+%2 = OpTypeVector %3 3
+%1 = OpTypeMatrix %2 2
+)");
+}
+
+TEST_F(BuilderTest_Type, ReturnsGeneratedF16Matrix) {
+ auto* f16 = create<sem::F16>();
+ auto* col = create<sem::Vector>(f16, 4u);
+ auto* mat = create<sem::Matrix>(col, 3u);
+
+ spirv::Builder& b = Build();
+
+ EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(f16), 3u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+}
+
TEST_F(BuilderTest_Type, GeneratePtr) {
auto* i32 = create<sem::I32>();
auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput, ast::Access::kReadWrite);
diff --git a/src/tint/writer/spirv/scalar_constant.h b/src/tint/writer/spirv/scalar_constant.h
index 14bcefb..0629d0c 100644
--- a/src/tint/writer/spirv/scalar_constant.h
+++ b/src/tint/writer/spirv/scalar_constant.h
@@ -20,6 +20,7 @@
#include <cstring>
#include <functional>
+#include "src/tint/number.h"
#include "src/tint/utils/hash.h"
// Forward declarations
@@ -31,6 +32,12 @@
/// ScalarConstant represents a scalar constant value
struct ScalarConstant {
+ /// The struct type to hold the bits representation of f16 in the Value union
+ struct F16 {
+ /// The 16 bits representation of the f16, stored as uint16_t
+ uint16_t bits_representation;
+ };
+
/// The constant value
union Value {
/// The value as a bool
@@ -41,6 +48,8 @@
int32_t i32;
/// The value as a float
float f32;
+ /// The value as bits representation of a f16
+ F16 f16;
/// The value that is wide enough to encompass all other types (including
/// future 64-bit data types).
@@ -48,7 +57,7 @@
};
/// The kind of constant
- enum class Kind { kBool, kU32, kI32, kF32 };
+ enum class Kind { kBool, kU32, kI32, kF32, kF16 };
/// Constructor
inline ScalarConstant() { value.u64 = 0; }
@@ -72,7 +81,7 @@
}
/// @param value the value of the constant
- /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
+ /// @returns a new ScalarConstant with the provided value and kind Kind::kF32
static inline ScalarConstant F32(float value) {
ScalarConstant c;
c.value.f32 = value;
@@ -81,6 +90,15 @@
}
/// @param value the value of the constant
+ /// @returns a new ScalarConstant with the provided value and kind Kind::kF16
+ static inline ScalarConstant F16(f16::type value) {
+ ScalarConstant c;
+ c.value.f16 = {f16(value).BitsRepresentation()};
+ c.kind = Kind::kF16;
+ return c;
+ }
+
+ /// @param value the value of the constant
/// @returns a new ScalarConstant with the provided value and kind Kind::kBool
static inline ScalarConstant Bool(bool value) {
ScalarConstant c;
diff --git a/src/tint/writer/spirv/scalar_constant_test.cc b/src/tint/writer/spirv/scalar_constant_test.cc
index 196e600..b00f82a 100644
--- a/src/tint/writer/spirv/scalar_constant_test.cc
+++ b/src/tint/writer/spirv/scalar_constant_test.cc
@@ -52,5 +52,12 @@
EXPECT_EQ(c.kind, ScalarConstant::Kind::kU32);
}
+TEST_F(SpirvScalarConstantTest, F16) {
+ auto c = ScalarConstant::F16(123.456f);
+ // 123.456f will be quantized to f16 123.4375h, bit pattern 0x57b7
+ EXPECT_EQ(c.value.f16.bits_representation, 0x57b7u);
+ EXPECT_EQ(c.kind, ScalarConstant::Kind::kF16);
+}
+
} // namespace
} // namespace tint::writer::spirv