mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-09 06:35:54 +00:00
tint/writer/wgsl: Support for F16 type, constructor, and convertor
This patch make WGSL writer support emitting f16 types, f16 literals, f16 constructor and convertor. Unittests are also implemented. Bug: tint:1473, tint:1502 Change-Id: Id2a5eec54b95add330366cf141b36999e604a63b Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/95990 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ryan Harrison <rharrison@chromium.org>
This commit is contained in:
parent
b108fb391e
commit
9a32a720ac
@ -258,6 +258,10 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
|
||||
return true;
|
||||
},
|
||||
[&](const ast::FloatLiteralExpression* l) { //
|
||||
// f16 literals are also emitted as float value with suffix "h".
|
||||
// Note that all normal and subnormal f16 values are normal f32 values, and since NaN
|
||||
// and Inf are not allowed to be spelled in literal, it should be fine to emit f16
|
||||
// literals in this way.
|
||||
out << FloatToBitPreservingString(static_cast<float>(l->value)) << l->suffix;
|
||||
return true;
|
||||
},
|
||||
@ -402,9 +406,8 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
|
||||
return true;
|
||||
},
|
||||
[&](const ast::F16*) {
|
||||
diagnostics_.add_error(diag::System::Writer,
|
||||
"Type f16 is not completely implemented yet.");
|
||||
return false;
|
||||
out << "f16";
|
||||
return true;
|
||||
},
|
||||
[&](const ast::I32*) {
|
||||
out << "i32";
|
||||
|
@ -21,7 +21,7 @@ namespace {
|
||||
|
||||
using WgslGeneratorImplTest = TestHelper;
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar_F32_From_I32) {
|
||||
auto* cast = Construct<f32>(1_i);
|
||||
WrapInFunction(cast);
|
||||
|
||||
@ -32,7 +32,20 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
|
||||
EXPECT_EQ(out.str(), "f32(1i)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar_F16_From_I32) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* cast = Construct<f16>(1_i);
|
||||
WrapInFunction(cast);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
|
||||
EXPECT_EQ(out.str(), "f16(1i)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F32_From_I32) {
|
||||
auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
|
||||
WrapInFunction(cast);
|
||||
|
||||
@ -43,5 +56,18 @@ TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
|
||||
EXPECT_EQ(out.str(), "vec3<f32>(vec3<i32>(1i, 2i, 3i))");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F16_From_I32) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* cast = vec3<f16>(vec3<i32>(1_i, 2_i, 3_i));
|
||||
WrapInFunction(cast);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
|
||||
EXPECT_EQ(out.str(), "vec3<f16>(vec3<i32>(1i, 2i, 3i))");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::writer::wgsl
|
||||
|
@ -51,7 +51,7 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_UInt) {
|
||||
EXPECT_THAT(gen.result(), HasSubstr("56779u"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_F32) {
|
||||
// Use a number close to 1<<30 but whose decimal representation ends in 0.
|
||||
WrapInFunction(Expr(f32((1 << 30) - 4)));
|
||||
|
||||
@ -61,7 +61,19 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
|
||||
EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
// Use a number close to 1<<16 but whose decimal representation ends in 0.
|
||||
WrapInFunction(Expr(f16((1 << 15) - 8)));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
EXPECT_THAT(gen.result(), HasSubstr("32752.0h"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_F32) {
|
||||
WrapInFunction(Construct<f32>(Expr(-1.2e-5_f)));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
@ -70,6 +82,17 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
|
||||
EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012f)"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
WrapInFunction(Construct<f16>(Expr(-1.2e-5_h)));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
EXPECT_THAT(gen.result(), HasSubstr("f16(-1.19805336e-05h)"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Bool) {
|
||||
WrapInFunction(Construct<bool>(true));
|
||||
|
||||
@ -97,7 +120,7 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Uint) {
|
||||
EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec_F32) {
|
||||
WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
@ -106,7 +129,18 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
|
||||
EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0f, 2.0f, 3.0f)"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
EXPECT_THAT(gen.result(), HasSubstr("vec3<f16>(1.0h, 2.0h, 3.0h)"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat_F32) {
|
||||
WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
@ -116,6 +150,18 @@ TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
|
||||
"vec3<f32>(3.0f, 4.0f, 5.0f))"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
EXPECT_THAT(gen.result(), HasSubstr("mat2x3<f16>(vec3<f16>(1.0h, 2.0h, 3.0h), "
|
||||
"vec3<f16>(3.0h, 4.0h, 5.0h))"));
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Array) {
|
||||
WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
|
||||
vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
|
||||
|
@ -25,7 +25,7 @@ namespace {
|
||||
// - 0 sign if sign is 0, 1 otherwise
|
||||
// - 'exponent_bits' is placed in the exponent space.
|
||||
// So, the exponent bias must already be included.
|
||||
f32 MakeFloat(uint32_t sign, uint32_t biased_exponent, uint32_t mantissa) {
|
||||
f32 MakeF32(uint32_t sign, uint32_t biased_exponent, uint32_t mantissa) {
|
||||
const uint32_t sign_bit = sign ? 0x80000000u : 0u;
|
||||
// The binary32 exponent is 8 bits, just below the sign.
|
||||
const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
|
||||
@ -40,18 +40,75 @@ f32 MakeFloat(uint32_t sign, uint32_t biased_exponent, uint32_t mantissa) {
|
||||
return f32(result);
|
||||
}
|
||||
|
||||
struct FloatData {
|
||||
// Get the representation of an IEEE 754 binary16 floating point number with
|
||||
// - 0 sign if sign is 0, 1 otherwise
|
||||
// - 'exponent_bits' is placed in the exponent space.
|
||||
// - the exponent bias (15) already be included.
|
||||
f16 MakeF16(uint32_t sign, uint32_t f16_biased_exponent, uint16_t f16_mantissa) {
|
||||
assert((f16_biased_exponent & 0xffffffe0u) == 0);
|
||||
assert((f16_mantissa & 0xfc00u) == 0);
|
||||
|
||||
const uint32_t sign_bit = sign ? 0x80000000u : 0u;
|
||||
|
||||
// F16 has a exponent bias of 15, and f32 bias 127. Adding 127-15=112 to the f16-biased exponent
|
||||
// to get f32-biased exponent.
|
||||
uint32_t f32_biased_exponent = (f16_biased_exponent & 0x1fu) + 112;
|
||||
assert((f32_biased_exponent & 0xffffff00u) == 0);
|
||||
|
||||
if (f16_biased_exponent == 0) {
|
||||
// +/- zero, or subnormal
|
||||
if (f16_mantissa == 0) {
|
||||
// +/- zero
|
||||
return sign ? f16(-0.0f) : f16(0.0f);
|
||||
}
|
||||
// Subnormal f16, calc the corresponding exponent and mantissa of normal f32.
|
||||
f32_biased_exponent += 1;
|
||||
// There must be at least one of the 10 mantissa bits being 1, left-shift the mantissa bits
|
||||
// until the most significant 1 bit is left-shifted to 10th bit (count from zero), which
|
||||
// will be omitted in the resulting f32 mantissa part.
|
||||
assert(f16_mantissa & 0x03ffu);
|
||||
while ((f16_mantissa & 0x0400u) == 0) {
|
||||
f16_mantissa = static_cast<uint16_t>(f16_mantissa << 1);
|
||||
f32_biased_exponent--;
|
||||
}
|
||||
}
|
||||
|
||||
// The binary32 exponent is 8 bits, just below the sign.
|
||||
const uint32_t f32_exponent_bits = (f32_biased_exponent & 0xffu) << 23;
|
||||
// The mantissa is the bottom 23 bits.
|
||||
const uint32_t f32_mantissa_bits = (f16_mantissa & 0x03ffu) << 13;
|
||||
|
||||
uint32_t bits = sign_bit | f32_exponent_bits | f32_mantissa_bits;
|
||||
float result = 0.0f;
|
||||
static_assert(sizeof(result) == sizeof(bits),
|
||||
"expected float and uint32_t to be the same size");
|
||||
std::memcpy(&result, &bits, sizeof(bits));
|
||||
return f16(result);
|
||||
}
|
||||
|
||||
struct F32Data {
|
||||
f32 value;
|
||||
std::string expected;
|
||||
};
|
||||
inline std::ostream& operator<<(std::ostream& out, FloatData data) {
|
||||
|
||||
struct F16Data {
|
||||
f16 value;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, F32Data data) {
|
||||
out << "{" << data.value << "," << data.expected << "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
using WgslGenerator_FloatLiteralTest = TestParamHelper<FloatData>;
|
||||
inline std::ostream& operator<<(std::ostream& out, F16Data data) {
|
||||
out << "{" << data.value << "," << data.expected << "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
TEST_P(WgslGenerator_FloatLiteralTest, Emit) {
|
||||
using WgslGenerator_F32LiteralTest = TestParamHelper<F32Data>;
|
||||
|
||||
TEST_P(WgslGenerator_F32LiteralTest, Emit) {
|
||||
auto* v = Expr(GetParam().value);
|
||||
|
||||
SetResolveOnBuild(false);
|
||||
@ -63,38 +120,37 @@ TEST_P(WgslGenerator_FloatLiteralTest, Emit) {
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Zero,
|
||||
WgslGenerator_FloatLiteralTest,
|
||||
::testing::ValuesIn(std::vector<FloatData>{
|
||||
{0_f, "0.0f"},
|
||||
{MakeFloat(0, 0, 0), "0.0f"},
|
||||
{MakeFloat(1, 0, 0), "-0.0f"}}));
|
||||
WgslGenerator_F32LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F32Data>{{0_f, "0.0f"},
|
||||
{MakeF32(0, 0, 0), "0.0f"},
|
||||
{MakeF32(1, 0, 0), "-0.0f"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Normal,
|
||||
WgslGenerator_FloatLiteralTest,
|
||||
::testing::ValuesIn(std::vector<FloatData>{{1_f, "1.0f"},
|
||||
{-1_f, "-1.0f"},
|
||||
{101.375_f, "101.375f"}}));
|
||||
WgslGenerator_F32LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F32Data>{{1_f, "1.0f"},
|
||||
{-1_f, "-1.0f"},
|
||||
{101.375_f, "101.375f"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Subnormal,
|
||||
WgslGenerator_FloatLiteralTest,
|
||||
::testing::ValuesIn(std::vector<FloatData>{
|
||||
{MakeFloat(0, 0, 1), "0x1p-149f"}, // Smallest
|
||||
{MakeFloat(1, 0, 1), "-0x1p-149f"},
|
||||
{MakeFloat(0, 0, 2), "0x1p-148f"},
|
||||
{MakeFloat(1, 0, 2), "-0x1p-148f"},
|
||||
{MakeFloat(0, 0, 0x7fffff), "0x1.fffffcp-127f"}, // Largest
|
||||
{MakeFloat(1, 0, 0x7fffff), "-0x1.fffffcp-127f"}, // Largest
|
||||
{MakeFloat(0, 0, 0xcafebe), "0x1.2bfaf8p-127f"}, // Scattered bits
|
||||
{MakeFloat(1, 0, 0xcafebe), "-0x1.2bfaf8p-127f"}, // Scattered bits
|
||||
{MakeFloat(0, 0, 0xaaaaa), "0x1.55554p-130f"}, // Scattered bits
|
||||
{MakeFloat(1, 0, 0xaaaaa), "-0x1.55554p-130f"}, // Scattered bits
|
||||
WgslGenerator_F32LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F32Data>{
|
||||
{MakeF32(0, 0, 1), "0x1p-149f"}, // Smallest
|
||||
{MakeF32(1, 0, 1), "-0x1p-149f"},
|
||||
{MakeF32(0, 0, 2), "0x1p-148f"},
|
||||
{MakeF32(1, 0, 2), "-0x1p-148f"},
|
||||
{MakeF32(0, 0, 0x7fffff), "0x1.fffffcp-127f"}, // Largest
|
||||
{MakeF32(1, 0, 0x7fffff), "-0x1.fffffcp-127f"}, // Largest
|
||||
{MakeF32(0, 0, 0xcafebe), "0x1.2bfaf8p-127f"}, // Scattered bits
|
||||
{MakeF32(1, 0, 0xcafebe), "-0x1.2bfaf8p-127f"}, // Scattered bits
|
||||
{MakeF32(0, 0, 0xaaaaa), "0x1.55554p-130f"}, // Scattered bits
|
||||
{MakeF32(1, 0, 0xaaaaa), "-0x1.55554p-130f"}, // Scattered bits
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Infinity,
|
||||
WgslGenerator_FloatLiteralTest,
|
||||
::testing::ValuesIn(std::vector<FloatData>{
|
||||
{MakeFloat(0, 255, 0), "0x1p+128f"},
|
||||
{MakeFloat(1, 255, 0), "-0x1p+128f"}}));
|
||||
WgslGenerator_F32LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F32Data>{
|
||||
{MakeF32(0, 255, 0), "0x1p+128f"},
|
||||
{MakeF32(1, 255, 0), "-0x1p+128f"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
// TODO(dneto): It's unclear how Infinity and NaN should be handled.
|
||||
@ -106,23 +162,95 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
// whether the NaN is signalling or quiet, but no agreement between
|
||||
// different machine architectures on whether 1 means signalling or
|
||||
// if 1 means quiet.
|
||||
WgslGenerator_FloatLiteralTest,
|
||||
::testing::ValuesIn(std::vector<FloatData>{
|
||||
WgslGenerator_F32LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F32Data>{
|
||||
// LSB only. Smallest mantissa.
|
||||
{MakeFloat(0, 255, 1), "0x1.000002p+128f"}, // Smallest mantissa
|
||||
{MakeFloat(1, 255, 1), "-0x1.000002p+128f"},
|
||||
{MakeF32(0, 255, 1), "0x1.000002p+128f"}, // Smallest mantissa
|
||||
{MakeF32(1, 255, 1), "-0x1.000002p+128f"},
|
||||
// MSB only.
|
||||
{MakeFloat(0, 255, 0x400000), "0x1.8p+128f"},
|
||||
{MakeFloat(1, 255, 0x400000), "-0x1.8p+128f"},
|
||||
{MakeF32(0, 255, 0x400000), "0x1.8p+128f"},
|
||||
{MakeF32(1, 255, 0x400000), "-0x1.8p+128f"},
|
||||
// All 1s in the mantissa.
|
||||
{MakeFloat(0, 255, 0x7fffff), "0x1.fffffep+128f"},
|
||||
{MakeFloat(1, 255, 0x7fffff), "-0x1.fffffep+128f"},
|
||||
{MakeF32(0, 255, 0x7fffff), "0x1.fffffep+128f"},
|
||||
{MakeF32(1, 255, 0x7fffff), "-0x1.fffffep+128f"},
|
||||
// Scattered bits, with 0 in top mantissa bit.
|
||||
{MakeFloat(0, 255, 0x20101f), "0x1.40203ep+128f"},
|
||||
{MakeFloat(1, 255, 0x20101f), "-0x1.40203ep+128f"},
|
||||
{MakeF32(0, 255, 0x20101f), "0x1.40203ep+128f"},
|
||||
{MakeF32(1, 255, 0x20101f), "-0x1.40203ep+128f"},
|
||||
// Scattered bits, with 1 in top mantissa bit.
|
||||
{MakeFloat(0, 255, 0x40101f), "0x1.80203ep+128f"},
|
||||
{MakeFloat(1, 255, 0x40101f), "-0x1.80203ep+128f"}}));
|
||||
{MakeF32(0, 255, 0x40101f), "0x1.80203ep+128f"},
|
||||
{MakeF32(1, 255, 0x40101f), "-0x1.80203ep+128f"}}));
|
||||
|
||||
using WgslGenerator_F16LiteralTest = TestParamHelper<F16Data>;
|
||||
|
||||
TEST_P(WgslGenerator_F16LiteralTest, Emit) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* v = Expr(GetParam().value);
|
||||
|
||||
SetResolveOnBuild(false);
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
|
||||
EXPECT_EQ(out.str(), GetParam().expected);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Zero,
|
||||
WgslGenerator_F16LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F16Data>{{0_h, "0.0h"},
|
||||
{MakeF16(0, 0, 0), "0.0h"},
|
||||
{MakeF16(1, 0, 0), "-0.0h"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Normal,
|
||||
WgslGenerator_F16LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F16Data>{{1_h, "1.0h"},
|
||||
{-1_h, "-1.0h"},
|
||||
{101.375_h, "101.375h"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Subnormal,
|
||||
WgslGenerator_F16LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F16Data>{
|
||||
{MakeF16(0, 0, 1), "5.96046448e-08h"}, // Smallest
|
||||
{MakeF16(1, 0, 1), "-5.96046448e-08h"},
|
||||
{MakeF16(0, 0, 2), "1.1920929e-07h"},
|
||||
{MakeF16(1, 0, 2), "-1.1920929e-07h"},
|
||||
{MakeF16(0, 0, 0x3ffu), "6.09755516e-05h"}, // Largest
|
||||
{MakeF16(1, 0, 0x3ffu), "-6.09755516e-05h"}, // Largest
|
||||
{MakeF16(0, 0, 0x3afu), "5.620718e-05h"}, // Scattered bits
|
||||
{MakeF16(1, 0, 0x3afu), "-5.620718e-05h"}, // Scattered bits
|
||||
{MakeF16(0, 0, 0x2c7u), "4.23789024e-05h"}, // Scattered bits
|
||||
{MakeF16(1, 0, 0x2c7u), "-4.23789024e-05h"}, // Scattered bits
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
// Currently Inf is impossible to be spelled out in literal.
|
||||
// https://github.com/gpuweb/gpuweb/issues/1769
|
||||
DISABLED_Infinity,
|
||||
WgslGenerator_F16LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F16Data>{{MakeF16(0, 31, 0), "0x1p+128h"},
|
||||
{MakeF16(1, 31, 0), "-0x1p+128h"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
// Currently NaN is impossible to be spelled out in literal.
|
||||
// https://github.com/gpuweb/gpuweb/issues/1769
|
||||
DISABLED_NaN,
|
||||
WgslGenerator_F16LiteralTest,
|
||||
::testing::ValuesIn(std::vector<F16Data>{
|
||||
// LSB only. Smallest mantissa.
|
||||
{MakeF16(0, 31, 1), "0x1.004p+128h"}, // Smallest mantissa
|
||||
{MakeF16(1, 31, 1), "-0x1.004p+128h"},
|
||||
// MSB only.
|
||||
{MakeF16(0, 31, 0x200u), "0x1.8p+128h"},
|
||||
{MakeF16(1, 31, 0x200u), "-0x1.8p+128h"},
|
||||
// All 1s in the mantissa.
|
||||
{MakeF16(0, 31, 0x3ffu), "0x1.ffcp+128h"},
|
||||
{MakeF16(1, 31, 0x3ffu), "-0x1.ffcp+128h"},
|
||||
// Scattered bits, with 0 in top mantissa bit.
|
||||
{MakeF16(0, 31, 0x11fu), "0x1.47cp+128h"},
|
||||
{MakeF16(1, 31, 0x11fu), "-0x1.47cp+128h"},
|
||||
// Scattered bits, with 1 in top mantissa bit.
|
||||
{MakeF16(0, 31, 0x23fu), "0x1.8fcp+128h"},
|
||||
{MakeF16(1, 31, 0x23fu), "-0x1.8fcp+128h"}}));
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::writer::wgsl
|
||||
|
@ -91,6 +91,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_F32) {
|
||||
EXPECT_EQ(out.str(), "f32");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* f16 = ty.f16();
|
||||
Alias("make_type_reachable", f16);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitType(out, f16)) << gen.error();
|
||||
EXPECT_EQ(out.str(), "f16");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_I32) {
|
||||
auto* i32 = ty.i32();
|
||||
Alias("make_type_reachable", i32);
|
||||
@ -102,7 +115,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_I32) {
|
||||
EXPECT_EQ(out.str(), "i32");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Matrix_F32) {
|
||||
auto* mat2x3 = ty.mat2x3<f32>();
|
||||
Alias("make_type_reachable", mat2x3);
|
||||
|
||||
@ -113,6 +126,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
|
||||
EXPECT_EQ(out.str(), "mat2x3<f32>");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Matrix_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* mat2x3 = ty.mat2x3<f16>();
|
||||
Alias("make_type_reachable", mat2x3);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitType(out, mat2x3)) << gen.error();
|
||||
EXPECT_EQ(out.str(), "mat2x3<f16>");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
|
||||
auto* p = ty.pointer<f32>(ast::StorageClass::kWorkgroup);
|
||||
Alias("make_type_reachable", p);
|
||||
@ -271,7 +297,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_U32) {
|
||||
EXPECT_EQ(out.str(), "u32");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Vector_F32) {
|
||||
auto* vec3 = ty.vec3<f32>();
|
||||
Alias("make_type_reachable", vec3);
|
||||
|
||||
@ -282,6 +308,19 @@ TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
|
||||
EXPECT_EQ(out.str(), "vec3<f32>");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Vector_F16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* vec3 = ty.vec3<f16>();
|
||||
Alias("make_type_reachable", vec3);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(gen.EmitType(out, vec3)) << gen.error();
|
||||
EXPECT_EQ(out.str(), "vec3<f16>");
|
||||
}
|
||||
|
||||
struct TextureData {
|
||||
ast::TextureDimension dim;
|
||||
const char* name;
|
||||
|
@ -125,6 +125,25 @@ TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f32) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_f16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* C = Const("C", nullptr, Expr(1_h));
|
||||
Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
|
||||
EXPECT_EQ(gen.result(), R"(enable f16;
|
||||
|
||||
fn f() {
|
||||
const C = 1.0h;
|
||||
let l = C;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
|
||||
auto* C = Const("C", nullptr, Construct(ty.vec3(nullptr), 1_a, 2_a, 3_a));
|
||||
Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
|
||||
@ -170,6 +189,25 @@ TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* C = Const("C", nullptr, vec3<f16>(1_h, 2_h, 3_h));
|
||||
Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
|
||||
EXPECT_EQ(gen.result(), R"(enable f16;
|
||||
|
||||
fn f() {
|
||||
const C = vec3<f16>(1.0h, 2.0h, 3.0h);
|
||||
let l = C;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
|
||||
auto* C =
|
||||
Const("C", nullptr, Construct(ty.mat(nullptr, 2, 3), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
|
||||
@ -201,6 +239,25 @@ TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
auto* C = Const("C", nullptr, mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
|
||||
Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.Generate()) << gen.error();
|
||||
|
||||
EXPECT_EQ(gen.result(), R"(enable f16;
|
||||
|
||||
fn f() {
|
||||
const C = mat2x3<f16>(1.0h, 2.0h, 3.0h, 4.0h, 5.0h, 6.0h);
|
||||
let l = C;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
|
||||
auto* C = Const("C", nullptr, Construct(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
|
||||
Func("f", {}, ty.void_(), {Decl(C), Decl(Let("l", nullptr, Expr(C)))});
|
||||
|
Loading…
x
Reference in New Issue
Block a user