From 35ce0d19937e30520de5ea195cfb273ec3321c82 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 16 Jun 2021 09:19:36 +0000 Subject: [PATCH] writer/hlsl: Implement isNormal Change-Id: I5e5aa81db686b0205ffbf157542c0e85f28b5d5d Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54323 Commit-Queue: Ben Clayton Kokoro: Kokoro Reviewed-by: David Neto --- src/writer/hlsl/generator_impl.cc | 41 ++++++++++++++++++- src/writer/hlsl/generator_impl.h | 10 +++++ .../hlsl/generator_impl_intrinsic_test.cc | 30 ++++++++++++++ .../gen/isNormal/863dcd.wgsl.expected.hlsl | 28 ++++++------- .../gen/isNormal/b00ab1.wgsl.expected.hlsl | 28 ++++++------- .../gen/isNormal/c286b7.wgsl.expected.hlsl | 28 ++++++------- .../gen/isNormal/c6e880.wgsl.expected.hlsl | 28 ++++++------- 7 files changed, 127 insertions(+), 66 deletions(-) diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index da5b6ae7ab..f159791861 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc @@ -535,8 +535,7 @@ bool GeneratorImpl::EmitCall(std::ostream& pre, if (intrinsic->Type() == sem::IntrinsicType::kFrexp) { return EmitFrexpCall(pre, out, expr, intrinsic); } else if (intrinsic->Type() == sem::IntrinsicType::kIsNormal) { - diagnostics_.add_error("is_normal not supported in HLSL backend yet"); - return false; + return EmitIsNormalCall(pre, out, expr, intrinsic); } else if (intrinsic->Type() == sem::IntrinsicType::kIgnore) { return EmitExpression(pre, out, expr->params()[0]); } else if (intrinsic->IsDataPacking()) { @@ -670,6 +669,44 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& pre, return true; } +bool GeneratorImpl::EmitIsNormalCall(std::ostream& pre, + std::ostream& out, + ast::CallExpression* expr, + const sem::Intrinsic* intrinsic) { + // HLSL doesn't have a isNormal intrinsic, we need to emulate + auto input = intrinsic->Parameters()[0]; + + std::string width; + if (auto* vec = input.type->As()) { + width = std::to_string(vec->size()); + } + + constexpr auto* kExponentMask = "0x7f80000"; + constexpr auto* kMinNormalExponent = "0x0080000"; + constexpr auto* kMaxNormalExponent = "0x7f00000"; + + auto exponent = generate_name("tint_isnormal_exponent"); + auto clamped = generate_name("tint_isnormal_clamped"); + + std::stringstream ss; + ss << "uint" << width << " " << exponent << " = asuint("; + if (!EmitExpression(pre, ss, expr->params()[0])) { + return false; + } + ss << ") & " << kExponentMask << ";"; + + make_indent(ss << std::endl); + ss << "uint" << width << " " << clamped << " = " + << "clamp(" << exponent << ", " << kMinNormalExponent << ", " + << kMaxNormalExponent << ");"; + + make_indent(ss << std::endl); + pre << ss.str(); + + out << "(" << clamped << " == " << exponent << ")"; + return true; +} + bool GeneratorImpl::EmitDataPackingCall(std::ostream& pre, std::ostream& out, ast::CallExpression* expr, diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h index e0dbdd9696..99dbbba62d 100644 --- a/src/writer/hlsl/generator_impl.h +++ b/src/writer/hlsl/generator_impl.h @@ -152,6 +152,16 @@ class GeneratorImpl : public TextGenerator { std::ostream& out, ast::CallExpression* expr, const sem::Intrinsic* intrinsic); + /// Handles generating a call to the `isNormal()` intrinsic + /// @param pre the preamble of the expression stream + /// @param out the output of the expression stream + /// @param expr the call expression + /// @param intrinsic the semantic information for the intrinsic + /// @returns true if the call expression is emitted + bool EmitIsNormalCall(std::ostream& pre, + std::ostream& out, + ast::CallExpression* expr, + const sem::Intrinsic* intrinsic); /// Handles generating a call to data packing intrinsic /// @param pre the preamble of the expression stream /// @param out the output of the expression stream diff --git a/src/writer/hlsl/generator_impl_intrinsic_test.cc b/src/writer/hlsl/generator_impl_intrinsic_test.cc index e299bbeb19..ee4a206ebe 100644 --- a/src/writer/hlsl/generator_impl_intrinsic_test.cc +++ b/src/writer/hlsl/generator_impl_intrinsic_test.cc @@ -347,6 +347,36 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Vector_i32) { )")); } +TEST_F(HlslGeneratorImplTest_Intrinsic, IsNormal_Scalar) { + auto* val = Var("val", ty.f32()); + auto* call = Call("isNormal", val); + WrapInFunction(val, call); + + GeneratorImpl& gen = SanitizeAndBuild(); + + ASSERT_TRUE(gen.Generate(out)) << gen.error(); + EXPECT_THAT(result(), HasSubstr(R"( + uint tint_isnormal_exponent = asuint(val) & 0x7f80000; + uint tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + (tint_isnormal_clamped == tint_isnormal_exponent); +)")); +} + +TEST_F(HlslGeneratorImplTest_Intrinsic, IsNormal_Vector) { + auto* val = Var("val", ty.vec3()); + auto* call = Call("isNormal", val); + WrapInFunction(val, call); + + GeneratorImpl& gen = SanitizeAndBuild(); + + ASSERT_TRUE(gen.Generate(out)) << gen.error(); + EXPECT_THAT(result(), HasSubstr(R"( + uint3 tint_isnormal_exponent = asuint(val) & 0x7f80000; + uint3 tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + (tint_isnormal_clamped == tint_isnormal_exponent); +)")); +} + TEST_F(HlslGeneratorImplTest_Intrinsic, Pack4x8Snorm) { auto* call = Call("pack4x8snorm", "p1"); Global("p1", ty.vec4(), ast::StorageClass::kPrivate); diff --git a/test/intrinsics/gen/isNormal/863dcd.wgsl.expected.hlsl b/test/intrinsics/gen/isNormal/863dcd.wgsl.expected.hlsl index 2538b808fc..ff32e3becb 100644 --- a/test/intrinsics/gen/isNormal/863dcd.wgsl.expected.hlsl +++ b/test/intrinsics/gen/isNormal/863dcd.wgsl.expected.hlsl @@ -1,30 +1,26 @@ -SKIP: FAILED - - -fn isNormal_863dcd() { - var res : vec4 = isNormal(vec4()); +void isNormal_863dcd() { + uint4 tint_isnormal_exponent = asuint(float4(0.0f, 0.0f, 0.0f, 0.0f)) & 0x7f80000; + uint4 tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + bool4 res = (tint_isnormal_clamped == tint_isnormal_exponent); } struct tint_symbol { - [[builtin(position)]] - value : vec4; + float4 value : SV_Position; }; -[[stage(vertex)]] -fn vertex_main() -> tint_symbol { +tint_symbol vertex_main() { isNormal_863dcd(); - let tint_symbol_1 : tint_symbol = tint_symbol(vec4()); + const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)}; return tint_symbol_1; } -[[stage(fragment)]] -fn fragment_main() { +void fragment_main() { isNormal_863dcd(); + return; } -[[stage(compute)]] -fn compute_main() { +[numthreads(1, 1, 1)] +void compute_main() { isNormal_863dcd(); + return; } - -Failed to generate: error: is_normal not supported in HLSL backend yet diff --git a/test/intrinsics/gen/isNormal/b00ab1.wgsl.expected.hlsl b/test/intrinsics/gen/isNormal/b00ab1.wgsl.expected.hlsl index e09dd01a68..7a5f623e9b 100644 --- a/test/intrinsics/gen/isNormal/b00ab1.wgsl.expected.hlsl +++ b/test/intrinsics/gen/isNormal/b00ab1.wgsl.expected.hlsl @@ -1,30 +1,26 @@ -SKIP: FAILED - - -fn isNormal_b00ab1() { - var res : vec2 = isNormal(vec2()); +void isNormal_b00ab1() { + uint2 tint_isnormal_exponent = asuint(float2(0.0f, 0.0f)) & 0x7f80000; + uint2 tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + bool2 res = (tint_isnormal_clamped == tint_isnormal_exponent); } struct tint_symbol { - [[builtin(position)]] - value : vec4; + float4 value : SV_Position; }; -[[stage(vertex)]] -fn vertex_main() -> tint_symbol { +tint_symbol vertex_main() { isNormal_b00ab1(); - let tint_symbol_1 : tint_symbol = tint_symbol(vec4()); + const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)}; return tint_symbol_1; } -[[stage(fragment)]] -fn fragment_main() { +void fragment_main() { isNormal_b00ab1(); + return; } -[[stage(compute)]] -fn compute_main() { +[numthreads(1, 1, 1)] +void compute_main() { isNormal_b00ab1(); + return; } - -Failed to generate: error: is_normal not supported in HLSL backend yet diff --git a/test/intrinsics/gen/isNormal/c286b7.wgsl.expected.hlsl b/test/intrinsics/gen/isNormal/c286b7.wgsl.expected.hlsl index 207ab29b32..bfc5d8b29f 100644 --- a/test/intrinsics/gen/isNormal/c286b7.wgsl.expected.hlsl +++ b/test/intrinsics/gen/isNormal/c286b7.wgsl.expected.hlsl @@ -1,30 +1,26 @@ -SKIP: FAILED - - -fn isNormal_c286b7() { - var res : vec3 = isNormal(vec3()); +void isNormal_c286b7() { + uint3 tint_isnormal_exponent = asuint(float3(0.0f, 0.0f, 0.0f)) & 0x7f80000; + uint3 tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + bool3 res = (tint_isnormal_clamped == tint_isnormal_exponent); } struct tint_symbol { - [[builtin(position)]] - value : vec4; + float4 value : SV_Position; }; -[[stage(vertex)]] -fn vertex_main() -> tint_symbol { +tint_symbol vertex_main() { isNormal_c286b7(); - let tint_symbol_1 : tint_symbol = tint_symbol(vec4()); + const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)}; return tint_symbol_1; } -[[stage(fragment)]] -fn fragment_main() { +void fragment_main() { isNormal_c286b7(); + return; } -[[stage(compute)]] -fn compute_main() { +[numthreads(1, 1, 1)] +void compute_main() { isNormal_c286b7(); + return; } - -Failed to generate: error: is_normal not supported in HLSL backend yet diff --git a/test/intrinsics/gen/isNormal/c6e880.wgsl.expected.hlsl b/test/intrinsics/gen/isNormal/c6e880.wgsl.expected.hlsl index a80ab16a34..da6faf7e8f 100644 --- a/test/intrinsics/gen/isNormal/c6e880.wgsl.expected.hlsl +++ b/test/intrinsics/gen/isNormal/c6e880.wgsl.expected.hlsl @@ -1,30 +1,26 @@ -SKIP: FAILED - - -fn isNormal_c6e880() { - var res : bool = isNormal(1.0); +void isNormal_c6e880() { + uint tint_isnormal_exponent = asuint(1.0f) & 0x7f80000; + uint tint_isnormal_clamped = clamp(tint_isnormal_exponent, 0x0080000, 0x7f00000); + bool res = (tint_isnormal_clamped == tint_isnormal_exponent); } struct tint_symbol { - [[builtin(position)]] - value : vec4; + float4 value : SV_Position; }; -[[stage(vertex)]] -fn vertex_main() -> tint_symbol { +tint_symbol vertex_main() { isNormal_c6e880(); - let tint_symbol_1 : tint_symbol = tint_symbol(vec4()); + const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)}; return tint_symbol_1; } -[[stage(fragment)]] -fn fragment_main() { +void fragment_main() { isNormal_c6e880(); + return; } -[[stage(compute)]] -fn compute_main() { +[numthreads(1, 1, 1)] +void compute_main() { isNormal_c6e880(); + return; } - -Failed to generate: error: is_normal not supported in HLSL backend yet