From 66d4f6e6fb13dbcdf7d9588eb93008f9149779c3 Mon Sep 17 00:00:00 2001 From: Zhaoming Jiang Date: Tue, 12 Jul 2022 12:35:09 +0000 Subject: [PATCH] tint/writer/spirv: Support for F16 type, constructor, and convertor This patch make SPIRV writer support emitting f16 types, f16 literals, f16 constructor and convertor. Unittests are also implemented. Currently SPIRV writer will require 4 capabilities in generated SPIRV: `Float16`, `UniformAndStorageBuffer16BitAccess`, `StorageBuffer16BitAccess`, and `storageInputOutput16`. Bug: tint:1473, tint:1502 Change-Id: Ia1af04f1f4a02bf1b1c2599a5d89791854eabc16 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/95920 Kokoro: Kokoro Reviewed-by: Ben Clayton Commit-Queue: Zhaoming Jiang --- src/tint/writer/spirv/builder.cc | 54 +- .../builder_constructor_expression_test.cc | 2027 ++++++++++++++++- .../spirv/builder_global_variable_test.cc | 30 + src/tint/writer/spirv/builder_literal_test.cc | 35 + src/tint/writer/spirv/builder_type_test.cc | 61 + src/tint/writer/spirv/scalar_constant.h | 22 +- src/tint/writer/spirv/scalar_constant_test.cc | 7 + .../parsing/basic.wgsl.expected.spvasm | 4 + ...duplicated_extensions.wgsl.expected.spvasm | 4 + 9 files changed, 2198 insertions(+), 46 deletions(-) diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc index 833324a338..b34fec3b09 100644 --- a/src/tint/writer/spirv/builder.cc +++ b/src/tint/writer/spirv/builder.cc @@ -379,22 +379,18 @@ void Builder::push_extension(const char* extension) { } 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 @@ uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call, if (result_type->Is()) { return GenerateConstantIfNeeded(ScalarConstant::F32(0).AsSpecOp(constant_id)); } + if (result_type->Is()) { + return GenerateConstantIfNeeded(ScalarConstant::F16(0).AsSpecOp(constant_id)); + } if (result_type->Is()) { return GenerateConstantIfNeeded(ScalarConstant::Bool(false).AsSpecOp(constant_id)); } @@ -1560,22 +1559,23 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type, auto* from_type = TypeOf(from_expr)->UnwrapRef(); spv::Op op = spv::Op::OpNop; - if ((from_type->Is() && to_type->Is()) || + if ((from_type->Is() && 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() && to_type->Is()) || + } else if ((from_type->Is() && 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() && to_type->Is()) || + } else if ((from_type->is_float_scalar() && to_type->Is()) || (from_type->is_float_vector() && to_type->is_signed_integer_vector())) { op = spv::Op::OpConvertFToS; - } else if ((from_type->Is() && to_type->Is()) || + } else if ((from_type->is_float_scalar() && to_type->Is()) || (from_type->is_float_vector() && to_type->is_unsigned_integer_vector())) { op = spv::Op::OpConvertFToU; } else if ((from_type->Is() && to_type->Is()) || (from_type->Is() && to_type->Is()) || (from_type->Is() && to_type->Is()) || (from_type->Is() && to_type->Is()) || + (from_type->Is() && to_type->Is()) || (from_type->Is() && (from_type == to_type))) { return val_id; } else if ((from_type->Is() && to_type->Is()) || @@ -1608,6 +1608,9 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type, if (to_elem_type->Is()) { zero_id = GenerateConstantIfNeeded(ScalarConstant::F32(0)); one_id = GenerateConstantIfNeeded(ScalarConstant::F32(1)); + } else if (to_elem_type->Is()) { + zero_id = GenerateConstantIfNeeded(ScalarConstant::F16(0)); + one_id = GenerateConstantIfNeeded(ScalarConstant::F16(1)); } else if (to_elem_type->Is()) { zero_id = GenerateConstantIfNeeded(ScalarConstant::U32(0)); one_id = GenerateConstantIfNeeded(ScalarConstant::U32(1)); @@ -1691,7 +1694,9 @@ uint32_t Builder::GenerateLiteralIfNeeded(const ast::Variable* var, constant.value.f32 = static_cast(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(f->value)).BitsRepresentation()}; + return; } }, [&](Default) { error_ = "unknown literal type"; }); @@ -1750,6 +1755,10 @@ uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant* constant) { auto val = constant->As(); return GenerateConstantIfNeeded(ScalarConstant::F32(val.value)); }, + [&](const sem::F16*) { + auto val = constant->As(); + return GenerateConstantIfNeeded(ScalarConstant::F16(val.value)); + }, [&](const sem::I32*) { auto val = constant->As(); return GenerateConstantIfNeeded(ScalarConstant::I32(val.value)); @@ -1788,6 +1797,10 @@ uint32_t Builder::GenerateConstantIfNeeded(const ScalarConstant& constant) { type_id = GenerateTypeIfNeeded(builder_.create()); break; } + case ScalarConstant::Kind::kF16: { + type_id = GenerateTypeIfNeeded(builder_.create()); + break; + } case ScalarConstant::Kind::kBool: { type_id = GenerateTypeIfNeeded(builder_.create()); break; @@ -1822,6 +1835,12 @@ uint32_t Builder::GenerateConstantIfNeeded(const ScalarConstant& constant) { {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 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) { 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 d8cb8094c7..7fc7ac635f 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 @@ TEST_F(SpvBuilderConstructorTest, Type_F32_With_F32) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_F16_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = Construct(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(true); WrapInFunction(cast); @@ -270,6 +287,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Literal) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_Literal) { + Enable(ast::Extension::kF16); + + auto* cast = vec2(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("x", "x"); @@ -295,6 +331,33 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) { )"); } +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("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(1_f, 2_f); WrapInFunction(cast); @@ -313,7 +376,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) { 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(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(), vec2(1_f, 2_f))); auto* cast = vec2("x"); WrapInFunction(var, cast); @@ -338,7 +421,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) { )"); } -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(), vec2(1_h, 2_h))); + auto* cast = vec2("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(vec2(1_f, 2_f)); WrapInFunction(cast); @@ -356,6 +466,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec2(vec2(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("x", "x", "x"); @@ -382,6 +512,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.f16(), Expr(2_h))); + auto* cast = vec3("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(1_f, 2_f, 3_f); WrapInFunction(cast); @@ -401,6 +559,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(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("x", "x", "x"); @@ -471,6 +650,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) { )"); } +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("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(1_f, 2_f, 3_f); WrapInFunction(cast); @@ -490,6 +697,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) { 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(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(), vec2(2_f, 3_f))); auto* cast = vec3(1_f, "x"); @@ -520,6 +748,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec2(), vec2(2_h, 3_h))); + auto* cast = vec3(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(1_f, vec2(2_f, 3_f)); WrapInFunction(cast); @@ -539,6 +799,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(1_h, vec2(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(), vec2(1_f, 2_f))); auto* cast = vec3("x", 3_f); @@ -569,6 +850,38 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec2(), vec2(1_h, 2_h))); + auto* cast = vec3("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(vec2(1_f, 2_f), 3_f); WrapInFunction(cast); @@ -588,7 +901,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) { 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(vec2(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(), vec3(1_f, 2_f, 3_f))); auto* cast = vec3("x"); WrapInFunction(var, cast); @@ -614,7 +948,35 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) { )"); } -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(), vec3(1_h, 2_h, 3_h))); + auto* cast = vec3("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(vec3(1_f, 2_f, 3_f)); WrapInFunction(cast); @@ -633,6 +995,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(vec3(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("x"); @@ -698,6 +1081,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.f16(), Expr(2_h))); + auto* cast = vec4("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(2_f); WrapInFunction(cast); @@ -715,6 +1124,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(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("x", "x", "x", "x"); @@ -742,6 +1170,35 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) { )"); } +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("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(1_f, 2_f, 3_f, 4_f); WrapInFunction(cast); @@ -762,6 +1219,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) { 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(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(), vec2(1_f, 2_f))); auto* cast = vec4(1_f, 2_f, "x"); @@ -791,6 +1270,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec2(), vec2(1_h, 2_h))); + auto* cast = vec4(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(1_f, 2_f, vec2(3_f, 4_f)); WrapInFunction(cast); @@ -811,6 +1321,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) { 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(1_h, 2_h, vec2(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(), vec2(2_f, 3_f))); auto* cast = vec4(1_f, "x", 4_f); @@ -842,6 +1374,39 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec2(), vec2(2_h, 3_h))); + auto* cast = vec4(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(1_f, vec2(2_f, 3_f), 4_f); WrapInFunction(cast); @@ -862,6 +1427,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) { 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(1_h, vec2(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(), vec2(1_f, 2_f))); auto* cast = vec4("x", 3_f, 4_f); @@ -893,6 +1480,39 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec2(), vec2(1_h, 2_h))); + auto* cast = vec4("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(vec2(1_f, 2_f), 3_f, 4_f); WrapInFunction(cast); @@ -913,7 +1533,29 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) { 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(vec2(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(), vec2(1_f, 2_f))); auto* cast = vec4("x", "x"); WrapInFunction(var, cast); @@ -945,7 +1587,41 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2) { )"); } -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(), vec2(1_h, 2_h))); + auto* cast = vec4("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(vec2(1_f, 2_f), vec2(1_f, 2_f)); WrapInFunction(cast); @@ -963,6 +1639,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2_Const) { 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(vec2(1_h, 2_h), vec2(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(), vec3(2_f, 2_f, 2_f))); auto* cast = vec4(2_f, "x"); @@ -992,6 +1688,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec3(), vec3(2_h, 2_h, 2_h))); + auto* cast = vec4(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(2_f, vec3(2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1009,6 +1736,25 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3_Const) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, vec3(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(), vec3(2_f, 2_f, 2_f))); auto* cast = vec4("x", 2_f); @@ -1038,6 +1784,37 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16) { + Enable(ast::Extension::kF16); + + auto* var = Decl(Var("x", ty.vec3(), vec3(2_h, 2_h, 2_h))); + auto* cast = vec4("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(vec3(2_f, 2_f, 2_f), 2_f); WrapInFunction(cast); @@ -1055,7 +1832,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) { 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(vec3(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(2_f, 2_f, 2_f, 2_f); auto* cast = vec4(value); WrapInFunction(cast); @@ -1073,6 +1869,26 @@ TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()"); } +TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec4) { + Enable(ast::Extension::kF16); + + auto* value = vec4(2_h, 2_h, 2_h, 2_h); + auto* cast = vec4(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(2_f); GlobalConst("g", ty.f32(), ctor); @@ -1094,6 +1910,29 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_F16_With_F16) { + Enable(ast::Extension::kF16); + + auto* ctor = Construct(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(2_f); GlobalVar("g", ty.f32(), ast::StorageClass::kPrivate, ctor); @@ -1111,6 +1950,25 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F32_With_F32) { Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_F16_With_F16) { + Enable(ast::Extension::kF16); + + auto* ctor = Construct(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(1.5_f); GlobalConst("g", ty.u32(), ctor); @@ -1132,6 +1990,29 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_U32_With_F16) { + Enable(ast::Extension::kF16); + + auto* ctor = Construct(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(1.5_f); GlobalVar("g", ty.u32(), ast::StorageClass::kPrivate, ctor); @@ -1149,6 +2030,25 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F32) { Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_U32_With_F16) { + Enable(ast::Extension::kF16); + + auto* ctor = Construct(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(2_f); GlobalConst("g", ty.vec2(), cast); @@ -1172,6 +2072,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec2(2_h); + GlobalConst("g", ty.vec2(), 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(2_f); auto* g = GlobalVar("g", ty.vec2(), ast::StorageClass::kPrivate, cast); @@ -1188,7 +2113,25 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) { )"); } -TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_Vec2) { +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec2(2_h); + auto* g = GlobalVar("g", ty.vec2(), 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(vec2(2_f, 2_f)); GlobalConst("g", ty.vec2(), cast); WrapInFunction(Decl(Var("l", nullptr, Expr("g")))); @@ -1211,7 +2154,32 @@ OpReturn 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(vec2(2_h, 2_h)); + GlobalConst("g", ty.vec2(), 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(vec2(2_f, 2_f)); GlobalVar("a", ty.vec2(), ast::StorageClass::kPrivate, cast); @@ -1231,7 +2199,29 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_Vec2) { 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(vec2(2_h, 2_h)); + GlobalVar("a", ty.vec2(), 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(vec3(2_f, 2_f, 2_f)); GlobalConst("g", ty.vec3(), cast); WrapInFunction(Decl(Var("l", nullptr, Expr("g")))); @@ -1254,7 +2244,32 @@ OpReturn 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(vec3(2_h, 2_h, 2_h)); + GlobalConst("g", ty.vec3(), 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(vec3(2_f, 2_f, 2_f)); GlobalVar("a", ty.vec3(), ast::StorageClass::kPrivate, cast); @@ -1274,7 +2289,29 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec3) { 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(vec3(2_h, 2_h, 2_h)); + GlobalVar("a", ty.vec3(), 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(vec4(2_f, 2_f, 2_f, 2_f)); GlobalConst("g", ty.vec4(), cast); WrapInFunction(Decl(Var("l", nullptr, Expr("g")))); @@ -1296,7 +2333,33 @@ OpReturn )"); 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(vec4(2_h, 2_h, 2_h, 2_h)); + GlobalConst("g", ty.vec4(), 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(vec4(2_f, 2_f, 2_f, 2_f)); GlobalVar("a", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1316,6 +2379,28 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec4) { Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec4) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(vec4(2_h, 2_h, 2_h, 2_h)); + GlobalVar("a", ty.vec4(), 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(2_f); GlobalConst("g", ty.vec3(), cast); @@ -1339,6 +2424,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(2_h); + GlobalConst("g", ty.vec3(), 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(2_f); auto* g = GlobalVar("g", ty.vec3(), ast::StorageClass::kPrivate, cast); @@ -1355,6 +2465,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(2_h); + auto* g = GlobalVar("g", ty.vec3(), 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(2_f, vec2(2_f, 2_f)); GlobalConst("g", ty.vec3(), cast); @@ -1378,6 +2506,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(2_h, vec2(2_h, 2_h)); + GlobalConst("g", ty.vec3(), 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(2_f, vec2(2_f, 2_f)); auto* g = GlobalVar("g", ty.vec3(), ast::StorageClass::kPrivate, cast); @@ -1394,6 +2547,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(2_h, vec2(2_h, 2_h)); + auto* g = GlobalVar("g", ty.vec3(), 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(vec2(2_f, 2_f), 2_f); GlobalConst("g", ty.vec3(), cast); @@ -1417,6 +2588,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(vec2(2_h, 2_h), 2_h); + GlobalConst("g", ty.vec3(), 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(vec2(2_f, 2_f), 2_f); auto* g = GlobalVar("g", ty.vec3(), ast::StorageClass::kPrivate, cast); @@ -1433,6 +2629,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec3(vec2(2_h, 2_h), 2_h); + auto* g = GlobalVar("g", ty.vec3(), 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(2_f); GlobalConst("g", ty.vec4(), cast); @@ -1456,6 +2670,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h); + GlobalConst("g", ty.vec4(), 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(2_f); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1472,6 +2711,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h); + auto* g = GlobalVar("g", ty.vec4(), 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(2_f, 2_f, vec2(2_f, 2_f)); GlobalConst("g", ty.vec4(), cast); @@ -1495,6 +2752,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, 2_h, vec2(2_h, 2_h)); + GlobalConst("g", ty.vec4(), 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(2_f, 2_f, vec2(2_f, 2_f)); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1511,6 +2793,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, 2_h, vec2(2_h, 2_h)); + auto* g = GlobalVar("g", ty.vec4(), 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(2_f, vec2(2_f, 2_f), 2_f); GlobalConst("g", ty.vec4(), cast); @@ -1534,6 +2834,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, vec2(2_h, 2_h), 2_h); + GlobalConst("g", ty.vec4(), 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(2_f, vec2(2_f, 2_f), 2_f); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1550,6 +2875,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, vec2(2_h, 2_h), 2_h); + auto* g = GlobalVar("g", ty.vec4(), 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(vec2(2_f, 2_f), 2_f, 2_f); GlobalConst("g", ty.vec4(), cast); @@ -1573,6 +2916,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(vec2(2_h, 2_h), 2_h, 2_h); + GlobalConst("g", ty.vec4(), 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(vec2(2_f, 2_f), 2_f, 2_f); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1589,7 +2957,25 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) { )"); } -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(vec2(2_h, 2_h), 2_h, 2_h); + auto* g = GlobalVar("g", ty.vec4(), 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(vec2(2_f, 2_f), vec2(2_f, 2_f)); GlobalConst("g", ty.vec4(), cast); WrapInFunction(Decl(Var("l", nullptr, Expr("g")))); @@ -1612,7 +2998,32 @@ OpReturn 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(vec2(2_h, 2_h), vec2(2_h, 2_h)); + GlobalConst("g", ty.vec4(), 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(vec2(2_f, 2_f), vec2(2_f, 2_f)); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1628,6 +3039,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_Vec2) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(vec2(2_h, 2_h), vec2(2_h, 2_h)); + auto* g = GlobalVar("g", ty.vec4(), 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(2_f, vec3(2_f, 2_f, 2_f)); GlobalConst("g", ty.vec4(), cast); @@ -1667,6 +3096,24 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec3) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec3) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(2_h, vec3(2_h, 2_h, 2_h)); + auto* g = GlobalVar("g", ty.vec4(), 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(vec3(2_f, 2_f, 2_f), 2_f); GlobalConst("g", ty.vec4(), cast); @@ -1690,6 +3137,31 @@ OpReturn Validate(b); } +TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(vec3(2_h, 2_h, 2_h), 2_h); + GlobalConst("g", ty.vec4(), 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(vec3(2_f, 2_f, 2_f), 2_f); auto* g = GlobalVar("g", ty.vec4(), ast::StorageClass::kPrivate, cast); @@ -1706,7 +3178,25 @@ TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) { )"); } -TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) { +TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F16) { + Enable(ast::Extension::kF16); + + auto* cast = vec4(vec3(2_h, 2_h, 2_h), 2_h); + auto* g = GlobalVar("g", ty.vec4(), 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(vec2(2_f, 2_f), vec2(2_f, 2_f)); WrapInFunction(cast); @@ -1724,7 +3214,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) { )"); } -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(vec2(2_h, 2_h), vec2(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(vec2(2_f, 2_f), vec2(2_f, 2_f), vec2(2_f, 2_f)); WrapInFunction(cast); @@ -1742,7 +3252,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_With_Vec2_Vec2_Vec2) { )"); } -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(vec2(2_h, 2_h), vec2(2_h, 2_h), vec2(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(vec2(2_f, 2_f), vec2(2_f, 2_f), vec2(2_f, 2_f), vec2(2_f, 2_f)); WrapInFunction(cast); @@ -1761,7 +3291,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) { )"); } -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(vec2(2_h, 2_h), vec2(2_h, 2_h), vec2(2_h, 2_h), + vec2(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(vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1779,7 +3330,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_With_Vec3_Vec3) { )"); } -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(vec3(2_h, 2_h, 2_h), vec3(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(vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1798,7 +3369,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_With_Vec3_Vec3_Vec3) { )"); } -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(vec3(2_h, 2_h, 2_h), vec3(2_h, 2_h, 2_h), vec3(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(vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f), vec3(2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1817,7 +3409,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) { )"); } -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(vec3(2_h, 2_h, 2_h), vec3(2_h, 2_h, 2_h), + vec3(2_h, 2_h, 2_h), vec3(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(vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1835,7 +3448,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_With_Vec4_Vec4) { )"); } -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(vec4(2_h, 2_h, 2_h, 2_h), vec4(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(vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1854,7 +3487,28 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_With_Vec4_Vec4_Vec4) { )"); } -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(vec4(2_h, 2_h, 2_h, 2_h), vec4(2_h, 2_h, 2_h, 2_h), + vec4(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(vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f), vec4(2_f, 2_f, 2_f, 2_f)); WrapInFunction(cast); @@ -1873,6 +3527,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) { + Enable(ast::Extension::kF16); + + auto* cast = mat4x4(vec4(2_h, 2_h, 2_h, 2_h), vec4(2_h, 2_h, 2_h, 2_h), + vec4(2_h, 2_h, 2_h, 2_h), vec4(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(2_f, 2_f, 2_f, 2_f, 2_f); WrapInFunction(cast); @@ -1891,7 +3566,27 @@ TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) { )"); } -TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) { +TEST_F(SpvBuilderConstructorTest, Type_Array_5_F16) { + Enable(ast::Extension::kF16); + + auto* cast = array(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(1_f, 2_f, 3_f); auto* second = vec3(1_f, 2_f, 3_f); auto* t = Construct(ty.array(ty.vec3(), 2_u), first, second); @@ -1913,6 +3608,30 @@ TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F16) { + Enable(ast::Extension::kF16); + + auto* first = vec3(1_h, 2_h, 3_h); + auto* second = vec3(1_h, 2_h, 3_h); + auto* t = Construct(ty.array(ty.vec3(), 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(2_f, 2_f, 2_f); auto* v2 = vec3(2_f, 2_f, 2_f); @@ -2030,6 +3749,25 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F16) { + Enable(ast::Extension::kF16); + + auto* t = Construct(); + + 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(); @@ -2099,7 +3837,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Vector) { )"); } -TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) { +TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F32) { auto* t = mat4x2(); WrapInFunction(t); @@ -2118,6 +3856,27 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F16) { + Enable(ast::Extension::kF16); + + auto* t = mat4x2(); + + 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(); @@ -2228,6 +3987,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_I32) { )"); } +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("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("x"); @@ -2252,6 +4037,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) { )"); } +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("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("x"); @@ -2276,6 +4087,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) { )"); } +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("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("x"); @@ -2300,6 +4137,32 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) { )"); } +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("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(), ast::StorageClass::kPrivate); @@ -2352,6 +4215,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_I32) { + Enable(ast::Extension::kF16); + + auto* var = GlobalVar("i", ty.vec3(), ast::StorageClass::kPrivate); + + auto* cast = vec3("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(), ast::StorageClass::kPrivate); @@ -2404,6 +4295,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F16_to_U32) { + Enable(ast::Extension::kF16); + + auto* var = GlobalVar("i", ty.vec3(), ast::StorageClass::kPrivate); + + auto* cast = vec3("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(), ast::StorageClass::kPrivate); @@ -2430,6 +4349,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F16) { + Enable(ast::Extension::kF16); + + auto* var = GlobalVar("i", ty.vec3(), ast::StorageClass::kPrivate); + + auto* cast = vec3("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(), ast::StorageClass::kPrivate); @@ -2456,6 +4403,34 @@ TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) { )"); } +TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F16) { + Enable(ast::Extension::kF16); + + auto* var = GlobalVar("i", ty.vec3(), ast::StorageClass::kPrivate); + + auto* cast = vec3("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(1.0, 2.0, 3.0) -> true auto* t = vec3(1_f, 2_f, 3_f); diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc index 05f6929e13..57b26a3feb 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 @@ TEST_F(BuilderTest, GlobalConst_Vec_Constructor) { Validate(b); } +TEST_F(BuilderTest, GlobalConst_Vec_F16_Constructor) { + // const c = vec3(1h, 2h, 3h); + // var v = c; + Enable(ast::Extension::kF16); + + auto* c = GlobalConst("c", nullptr, vec3(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 218db86919..374c80be12 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_F32_Dedup) { )"); } +TEST_F(BuilderTest, Literal_F16) { + Enable(ast::Extension::kF16); + + auto* i = create(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(23.245, ast::FloatLiteralExpression::Suffix::kH); + auto* i2 = create(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 b4bff9ba16..b3ead651b2 100644 --- a/src/tint/writer/spirv/builder_type_test.cc +++ b/src/tint/writer/spirv/builder_type_test.cc @@ -175,6 +175,34 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedF32) { ASSERT_FALSE(b.has_error()) << b.error(); } +TEST_F(BuilderTest_Type, GenerateF16) { + auto* f16 = create(); + + 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(); + auto* i32 = create(); + + 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(); @@ -236,6 +264,39 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) { ASSERT_FALSE(b.has_error()) << b.error(); } +TEST_F(BuilderTest_Type, GenerateF16Matrix) { + auto* f16 = create(); + auto* vec3 = create(f16, 3u); + auto* mat2x3 = create(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(); + auto* col = create(f16, 4u); + auto* mat = create(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(); auto* ptr = create(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 14bcefbc17..0629d0cdc4 100644 --- a/src/tint/writer/spirv/scalar_constant.h +++ b/src/tint/writer/spirv/scalar_constant.h @@ -20,6 +20,7 @@ #include #include +#include "src/tint/number.h" #include "src/tint/utils/hash.h" // Forward declarations @@ -31,6 +32,12 @@ namespace tint::writer::spirv { /// 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 @@ struct ScalarConstant { 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 @@ struct ScalarConstant { }; /// 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 @@ struct ScalarConstant { } /// @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; @@ -80,6 +89,15 @@ struct ScalarConstant { return c; } + /// @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) { diff --git a/src/tint/writer/spirv/scalar_constant_test.cc b/src/tint/writer/spirv/scalar_constant_test.cc index 196e600e14..b00f82ab0b 100644 --- a/src/tint/writer/spirv/scalar_constant_test.cc +++ b/src/tint/writer/spirv/scalar_constant_test.cc @@ -52,5 +52,12 @@ TEST_F(SpirvScalarConstantTest, U32) { 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 diff --git a/test/tint/extensions/parsing/basic.wgsl.expected.spvasm b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm index 225da82e55..3b3eac5cae 100644 --- a/test/tint/extensions/parsing/basic.wgsl.expected.spvasm +++ b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm @@ -4,6 +4,10 @@ ; Bound: 19 ; Schema: 0 OpCapability Shader + OpCapability Float16 + OpCapability UniformAndStorageBuffer16BitAccess + OpCapability StorageBuffer16BitAccess + OpCapability StorageInputOutput16 OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %value OpExecutionMode %main OriginUpperLeft diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm index 225da82e55..3b3eac5cae 100644 --- a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm +++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm @@ -4,6 +4,10 @@ ; Bound: 19 ; Schema: 0 OpCapability Shader + OpCapability Float16 + OpCapability UniformAndStorageBuffer16BitAccess + OpCapability StorageBuffer16BitAccess + OpCapability StorageInputOutput16 OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %value OpExecutionMode %main OriginUpperLeft