From ee665a4240d657b53510fbc6398a0b03044e164e Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Tue, 14 Feb 2023 16:12:59 +0000 Subject: [PATCH] tint: add precise float mod polyfill and enable it for HLSL HLSL's % operator results in less precise results than expected. Bug: tint:1799 Change-Id: I1a9572288a0e536f0fc9c0748a25dcf58551e57b Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119760 Kokoro: Kokoro Kokoro: Ben Clayton Reviewed-by: Ben Clayton Commit-Queue: Antonio Maiorano --- src/tint/transform/builtin_polyfill.cc | 71 +++++- src/tint/transform/builtin_polyfill.h | 2 + src/tint/transform/builtin_polyfill_test.cc | 226 ++++++++++++++++++ src/tint/writer/hlsl/generator_impl.cc | 1 + test/tint/bug/tint/948.wgsl.expected.dxc.hlsl | 6 +- test/tint/bug/tint/948.wgsl.expected.fxc.hlsl | 6 +- .../scalar-scalar/f16.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.fxc.hlsl | 6 +- .../scalar-vec3/f16.wgsl.expected.dxc.hlsl | 7 +- .../scalar-vec3/f32.wgsl.expected.dxc.hlsl | 7 +- .../scalar-vec3/f32.wgsl.expected.fxc.hlsl | 7 +- .../vec3-scalar/f16.wgsl.expected.dxc.hlsl | 7 +- .../vec3-scalar/f32.wgsl.expected.dxc.hlsl | 7 +- .../vec3-scalar/f32.wgsl.expected.fxc.hlsl | 7 +- .../mod/vec3-vec3/f16.wgsl.expected.dxc.hlsl | 6 +- .../mod/vec3-vec3/f32.wgsl.expected.dxc.hlsl | 6 +- .../mod/vec3-vec3/f32.wgsl.expected.fxc.hlsl | 6 +- .../scalar-scalar/f16.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.fxc.hlsl | 6 +- .../vec3-vec3/f16.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.fxc.hlsl | 6 +- .../scalar-scalar/f16.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.fxc.hlsl | 6 +- .../vec3-vec3/f16.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.fxc.hlsl | 6 +- .../scalar-scalar/f16.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.dxc.hlsl | 6 +- .../scalar-scalar/f32.wgsl.expected.fxc.hlsl | 6 +- .../vec3-vec3/f16.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.dxc.hlsl | 6 +- .../vec3-vec3/f32.wgsl.expected.fxc.hlsl | 6 +- .../divide_by_zero.wgsl.expected.dxc.hlsl | 8 +- .../divide_by_zero.wgsl.expected.fxc.hlsl | 8 +- 38 files changed, 477 insertions(+), 37 deletions(-) diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc index 5baef8a7b4..e140fb34c7 100644 --- a/src/tint/transform/builtin_polyfill.cc +++ b/src/tint/transform/builtin_polyfill.cc @@ -808,6 +808,58 @@ struct BuiltinPolyfill::State { return b.Call(fn, lhs, rhs); } + /// Builds the polyfill inline expression for a precise float modulo, as defined in the spec. + /// @param bin_op the original BinaryExpression + /// @return the polyfill divide or modulo + const ast::Expression* PreciseFloatMod(const ast::BinaryExpression* bin_op) { + auto* lhs_ty = ctx.src->TypeOf(bin_op->lhs)->UnwrapRef(); + auto* rhs_ty = ctx.src->TypeOf(bin_op->rhs)->UnwrapRef(); + BinaryOpSignature sig{bin_op->op, lhs_ty, rhs_ty}; + auto fn = binary_op_polyfills.GetOrCreate(sig, [&] { + uint32_t lhs_width = 1; + uint32_t rhs_width = 1; + const auto* lhs_el_ty = type::Type::ElementOf(lhs_ty, &lhs_width); + const auto* rhs_el_ty = type::Type::ElementOf(rhs_ty, &rhs_width); + + const uint32_t width = std::max(lhs_width, rhs_width); + + const char* lhs = "lhs"; + const char* rhs = "rhs"; + + utils::Vector body; + + if (lhs_width < width) { + // lhs is scalar, rhs is vector. Convert lhs to vector. + body.Push(b.Decl(b.Let("l", b.vec(T(lhs_el_ty), width, b.Expr(lhs))))); + lhs = "l"; + } + if (rhs_width < width) { + // lhs is vector, rhs is scalar. Convert rhs to vector. + body.Push(b.Decl(b.Let("r", b.vec(T(rhs_el_ty), width, b.Expr(rhs))))); + rhs = "r"; + } + + auto name = b.Symbols().New("tint_float_mod"); + + // lhs - trunc(lhs / rhs) * rhs + auto* precise_mod = b.Sub(lhs, b.Mul(b.Call("trunc", b.Div(lhs, rhs)), rhs)); + body.Push(b.Return(precise_mod)); + + b.Func(name, + utils::Vector{ + b.Param("lhs", T(lhs_ty)), + b.Param("rhs", T(rhs_ty)), + }, + width == 1 ? T(lhs_ty) : b.ty.vec(T(lhs_el_ty), width), // return type + std::move(body)); + + return name; + }); + auto* lhs = ctx.Clone(bin_op->lhs); + auto* rhs = ctx.Clone(bin_op->rhs); + return b.Call(fn, lhs, rhs); + } + private: /// The clone context CloneContext& ctx; @@ -1052,7 +1104,16 @@ Transform::ApplyResult BuiltinPolyfill::Apply(const Program* src, } break; } - case ast::BinaryOp::kDivide: + case ast::BinaryOp::kDivide: { + if (polyfill.int_div_mod) { + auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef(); + if (lhs_ty->is_integer_scalar_or_vector()) { + ctx.Replace(bin_op, [bin_op, &s] { return s.IntDivMod(bin_op); }); + made_changes = true; + } + } + break; + } case ast::BinaryOp::kModulo: { if (polyfill.int_div_mod) { auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef(); @@ -1061,6 +1122,14 @@ Transform::ApplyResult BuiltinPolyfill::Apply(const Program* src, made_changes = true; } } + if (polyfill.precise_float_mod) { + auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef(); + if (lhs_ty->is_float_scalar_or_vector()) { + ctx.Replace(bin_op, + [bin_op, &s] { return s.PreciseFloatMod(bin_op); }); + made_changes = true; + } + } break; } default: diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/transform/builtin_polyfill.h index ae5f588465..521940c644 100644 --- a/src/tint/transform/builtin_polyfill.h +++ b/src/tint/transform/builtin_polyfill.h @@ -68,6 +68,8 @@ class BuiltinPolyfill final : public Castable { /// Should integer scalar / vector divides and modulos be polyfilled to avoid DBZ and /// integer overflows? bool int_div_mod = false; + /// Should float modulos be polyfilled to emit a precise modulo operation as per the spec? + bool precise_float_mod = false; /// Should `saturate()` be polyfilled? bool saturate = false; /// Should `sign()` be polyfilled for integer types? diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc index 65365bbb77..688d95e5bf 100644 --- a/src/tint/transform/builtin_polyfill_test.cc +++ b/src/tint/transform/builtin_polyfill_test.cc @@ -2004,6 +2004,232 @@ fn f() { EXPECT_EQ(expect, str(got)); } +//////////////////////////////////////////////////////////////////////////////// +// precise_float_mod +//////////////////////////////////////////////////////////////////////////////// +DataMap polyfillPreciseFloatMod() { + BuiltinPolyfill::Builtins builtins; + builtins.precise_float_mod = true; + DataMap data; + data.Add(builtins); + return data; +} + +TEST_F(BuiltinPolyfillTest, ShouldRunPreciseFloatMod) { + auto* src = R"( +fn f() { + let v = 10f; + let x = 20f % v; +} +)"; + + EXPECT_FALSE(ShouldRun(src)); + EXPECT_TRUE(ShouldRun(src, polyfillPreciseFloatMod())); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_af_f32) { + auto* src = R"( +fn f() { + let v = 10f; + let x = 20.0 % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : f32, rhs : f32) -> f32 { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(20.0, v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_f32_af) { + auto* src = R"( +fn f() { + let v = 10.0; + let x = 20f % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : f32, rhs : f32) -> f32 { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + +fn f() { + let v = 10.0; + let x = tint_float_mod(20.0f, v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_f32_f32) { + auto* src = R"( +fn f() { + let v = 10f; + let x = 20f % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : f32, rhs : f32) -> f32 { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(20.0f, v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_Overloads) { + auto* src = R"( +fn f() { + let v = 10f; + let x = 20f % v; + let w = 10i; + let y = 20i % w; + let u = 10u; + let z = 20u % u; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : f32, rhs : f32) -> f32 { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(20.0f, v); + let w = 10i; + let y = (20i % w); + let u = 10u; + let z = (20u % u); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_vec3_af_f32) { + auto* src = R"( +fn f() { + let v = 10f; + let x = vec3(20.0) % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : vec3, rhs : f32) -> vec3 { + let r = vec3(rhs); + return (lhs - (trunc((lhs / r)) * r)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(vec3(20.0), v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_vec3_f32_af) { + auto* src = R"( +fn f() { + let v = 10.0; + let x = vec3(20f) % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : vec3, rhs : f32) -> vec3 { + let r = vec3(rhs); + return (lhs - (trunc((lhs / r)) * r)); +} + +fn f() { + let v = 10.0; + let x = tint_float_mod(vec3(20.0f), v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_vec3_f32_f32) { + auto* src = R"( +fn f() { + let v = 10f; + let x = vec3(20f) % v; +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : vec3, rhs : f32) -> vec3 { + let r = vec3(rhs); + return (lhs - (trunc((lhs / r)) * r)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(vec3(20.0f), v); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + +TEST_F(BuiltinPolyfillTest, PreciseFloatMod_vec3_f32_vec3_f32) { + auto* src = R"( +fn f() { + let v = 10f; + let x = vec3(20f) % vec3(v); +} +)"; + + auto* expect = R"( +fn tint_float_mod(lhs : vec3, rhs : vec3) -> vec3 { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + +fn f() { + let v = 10.0f; + let x = tint_float_mod(vec3(20.0f), vec3(v)); +} +)"; + + auto got = Run(src, polyfillPreciseFloatMod()); + + EXPECT_EQ(expect, str(got)); +} + //////////////////////////////////////////////////////////////////////////////// // int_div_mod //////////////////////////////////////////////////////////////////////////////// diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc index 0f8fdb1665..4e37faa879 100644 --- a/src/tint/writer/hlsl/generator_impl.cc +++ b/src/tint/writer/hlsl/generator_impl.cc @@ -180,6 +180,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) { polyfills.first_trailing_bit = true; polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull; polyfills.int_div_mod = true; + polyfills.precise_float_mod = true; polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true; polyfills.workgroup_uniform_load = true; data.Add(polyfills); diff --git a/test/tint/bug/tint/948.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/948.wgsl.expected.dxc.hlsl index c926578814..306658ca8e 100644 --- a/test/tint/bug/tint/948.wgsl.expected.dxc.hlsl +++ b/test/tint/bug/tint/948.wgsl.expected.dxc.hlsl @@ -33,6 +33,10 @@ float4x4 getFrameData_f1_(inout float frameID) { return float4x4(float4(x_40.x, x_40.y, x_40.z, x_40.w), float4(x_47.x, x_47.y, x_47.z, x_47.w), float4(x_54.x, x_54.y, x_54.z, x_54.w), (0.0f).xxxx); } +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + void main_1() { float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f); float2 tileUV = float2(0.0f, 0.0f); @@ -100,7 +104,7 @@ void main_1() { if ((x_174 > 0.0f)) { const float x_181 = asfloat(x_20[0].x); const float x_184 = animationData.z; - mt = ((x_181 * x_184) % 1.0f); + mt = tint_float_mod((x_181 * x_184), 1.0f); f = 0.0f; while (true) { const float x_193 = f; diff --git a/test/tint/bug/tint/948.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/948.wgsl.expected.fxc.hlsl index c926578814..306658ca8e 100644 --- a/test/tint/bug/tint/948.wgsl.expected.fxc.hlsl +++ b/test/tint/bug/tint/948.wgsl.expected.fxc.hlsl @@ -33,6 +33,10 @@ float4x4 getFrameData_f1_(inout float frameID) { return float4x4(float4(x_40.x, x_40.y, x_40.z, x_40.w), float4(x_47.x, x_47.y, x_47.z, x_47.w), float4(x_54.x, x_54.y, x_54.z, x_54.w), (0.0f).xxxx); } +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + void main_1() { float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f); float2 tileUV = float2(0.0f, 0.0f); @@ -100,7 +104,7 @@ void main_1() { if ((x_174 > 0.0f)) { const float x_181 = asfloat(x_20[0].x); const float x_184 = animationData.z; - mt = ((x_181 * x_184) % 1.0f); + mt = tint_float_mod((x_181 * x_184), 1.0f); f = 0.0f; while (true) { const float x_193 = f; diff --git a/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.dxc.hlsl index 9ce6ac82a8..ad0a42199e 100644 --- a/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float16_t tint_float_mod(float16_t lhs, float16_t rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float16_t a = float16_t(1.0h); const float16_t b = float16_t(2.0h); - const float16_t r = (a % b); + const float16_t r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.dxc.hlsl index 7e166b705d..0c9eb2e075 100644 --- a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 1.0f; const float b = 2.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.fxc.hlsl index 7e166b705d..0c9eb2e075 100644 --- a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 1.0f; const float b = 2.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.dxc.hlsl index 5b7fdbe997..99ffb584bb 100644 --- a/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,12 @@ +vector tint_float_mod(float16_t lhs, vector rhs) { + const vector l = vector((lhs).xxx); + return (l - (trunc((l / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float16_t a = float16_t(4.0h); const vector b = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); - const vector r = (a % b); + const vector r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.dxc.hlsl index b2653df18a..c864275a6a 100644 --- a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,12 @@ +float3 tint_float_mod(float lhs, float3 rhs) { + const float3 l = float3((lhs).xxx); + return (l - (trunc((l / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 4.0f; const float3 b = float3(1.0f, 2.0f, 3.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.fxc.hlsl index b2653df18a..c864275a6a 100644 --- a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,12 @@ +float3 tint_float_mod(float lhs, float3 rhs) { + const float3 l = float3((lhs).xxx); + return (l - (trunc((l / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 4.0f; const float3 b = float3(1.0f, 2.0f, 3.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.dxc.hlsl index 4c5452253c..a8976e907f 100644 --- a/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,12 @@ +vector tint_float_mod(vector lhs, float16_t rhs) { + const vector r = vector((rhs).xxx); + return (lhs - (trunc((lhs / r)) * r)); +} + [numthreads(1, 1, 1)] void f() { const vector a = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); const float16_t b = float16_t(4.0h); - const vector r = (a % b); + const vector r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.dxc.hlsl index 147b45c54f..c61e266e8d 100644 --- a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,12 @@ +float3 tint_float_mod(float3 lhs, float rhs) { + const float3 r = float3((rhs).xxx); + return (lhs - (trunc((lhs / r)) * r)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float b = 4.0f; - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.fxc.hlsl index 147b45c54f..c61e266e8d 100644 --- a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,12 @@ +float3 tint_float_mod(float3 lhs, float rhs) { + const float3 r = float3((rhs).xxx); + return (lhs - (trunc((lhs / r)) * r)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float b = 4.0f; - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.dxc.hlsl index 69def7917c..69ff97a56e 100644 --- a/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +vector tint_float_mod(vector lhs, vector rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const vector a = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); const vector b = vector(float16_t(4.0h), float16_t(5.0h), float16_t(6.0h)); - const vector r = (a % b); + const vector r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.dxc.hlsl index 87e4dd4a72..b03e6c8bb7 100644 --- a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float3 b = float3(4.0f, 5.0f, 6.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.fxc.hlsl index 87e4dd4a72..b03e6c8bb7 100644 --- a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float3 b = float3(4.0f, 5.0f, 6.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.dxc.hlsl index 87f2c8f455..45c8ee1ef6 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float16_t tint_float_mod(float16_t lhs, float16_t rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float16_t a = float16_t(1.0h); const float16_t b = float16_t(0.0h); - const float16_t r = (a % b); + const float16_t r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.dxc.hlsl index 80448b1e38..515bcfb4cf 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 1.0f; const float b = 0.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.fxc.hlsl index 80448b1e38..515bcfb4cf 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float a = 1.0f; const float b = 0.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.dxc.hlsl index 8c6cb4ca24..8e4d644520 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +vector tint_float_mod(vector lhs, vector rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const vector a = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); const vector b = vector(float16_t(0.0h), float16_t(5.0h), float16_t(0.0h)); - const vector r = (a % b); + const vector r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.dxc.hlsl index 5ea2fbd98f..0cd0191b63 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.fxc.hlsl index 5ea2fbd98f..0cd0191b63 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { const float3 a = float3(1.0f, 2.0f, 3.0f); const float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.dxc.hlsl index 9dd48b3282..649bbd27ca 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float16_t tint_float_mod(float16_t lhs, float16_t rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float16_t a = float16_t(1.0h); float16_t b = float16_t(0.0h); - const float16_t r = (a % (b + b)); + const float16_t r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.dxc.hlsl index 468c33d586..6af8624597 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float a = 1.0f; float b = 0.0f; - const float r = (a % (b + b)); + const float r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.fxc.hlsl index 468c33d586..6af8624597 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float a = 1.0f; float b = 0.0f; - const float r = (a % (b + b)); + const float r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.dxc.hlsl index 2f75bb382c..dfe3a63dc3 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +vector tint_float_mod(vector lhs, vector rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { vector a = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); vector b = vector(float16_t(0.0h), float16_t(5.0h), float16_t(0.0h)); - const vector r = (a % (b + b)); + const vector r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.dxc.hlsl index 8d2155076d..ff6fdd424b 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float3 a = float3(1.0f, 2.0f, 3.0f); float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % (b + b)); + const float3 r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.fxc.hlsl index 8d2155076d..ff6fdd424b 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float3 a = float3(1.0f, 2.0f, 3.0f); float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % (b + b)); + const float3 r = tint_float_mod(a, (b + b)); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.dxc.hlsl index 18770f0087..7ee2e0b994 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float16_t tint_float_mod(float16_t lhs, float16_t rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float16_t a = float16_t(1.0h); float16_t b = float16_t(0.0h); - const float16_t r = (a % b); + const float16_t r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.dxc.hlsl index 3d43aff25b..0fc0aef110 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float a = 1.0f; float b = 0.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.fxc.hlsl index 3d43aff25b..0fc0aef110 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float a = 1.0f; float b = 0.0f; - const float r = (a % b); + const float r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.dxc.hlsl index d79d88c455..4c47f3bd27 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +vector tint_float_mod(vector lhs, vector rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { vector a = vector(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h)); vector b = vector(float16_t(0.0h), float16_t(5.0h), float16_t(0.0h)); - const vector r = (a % b); + const vector r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.dxc.hlsl index 636719b6d6..f6fdd4c136 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.dxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.dxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float3 a = float3(1.0f, 2.0f, 3.0f); float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.fxc.hlsl index 636719b6d6..f6fdd4c136 100644 --- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.fxc.hlsl +++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.fxc.hlsl @@ -1,7 +1,11 @@ +float3 tint_float_mod(float3 lhs, float3 rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + [numthreads(1, 1, 1)] void f() { float3 a = float3(1.0f, 2.0f, 3.0f); float3 b = float3(0.0f, 5.0f, 0.0f); - const float3 r = (a % b); + const float3 r = tint_float_mod(a, b); return; } diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl index ab7448db45..314a630db0 100644 --- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl +++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl @@ -19,13 +19,17 @@ int tint_mod(int lhs, int rhs) { } } +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + void foo(int maybe_zero) { a = tint_div(a, 0); a = tint_mod(a, 0); a = tint_div(a, maybe_zero); a = tint_mod(a, maybe_zero); b = (b / 0.0f); - b = (b % 0.0f); + b = tint_float_mod(b, 0.0f); b = (b / float(maybe_zero)); - b = (b % float(maybe_zero)); + b = tint_float_mod(b, float(maybe_zero)); } diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl index ab7448db45..314a630db0 100644 --- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl +++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl @@ -19,13 +19,17 @@ int tint_mod(int lhs, int rhs) { } } +float tint_float_mod(float lhs, float rhs) { + return (lhs - (trunc((lhs / rhs)) * rhs)); +} + void foo(int maybe_zero) { a = tint_div(a, 0); a = tint_mod(a, 0); a = tint_div(a, maybe_zero); a = tint_mod(a, maybe_zero); b = (b / 0.0f); - b = (b % 0.0f); + b = tint_float_mod(b, 0.0f); b = (b / float(maybe_zero)); - b = (b % float(maybe_zero)); + b = tint_float_mod(b, float(maybe_zero)); }