mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-09 21:47:47 +00:00
tint/writers: Polyfill integer clamp()
...to `min(max(e, low), high)` as defined by the WGSL spec. Fixed: tint:1479 Fixed: tint:1539 Change-Id: I39406d5256a155a781e44bd9d6081ce7a9bf5a68 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/107640 Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
be83128031
commit
6dbb463f1d
@@ -137,6 +137,27 @@ struct BuiltinPolyfill::State {
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Builds the polyfill function for the `clamp` builtin when called with integer arguments
|
||||
/// (scalar or vector)
|
||||
/// @param ty the parameter and return type for the function
|
||||
/// @return the polyfill function name
|
||||
Symbol clampInteger(const sem::Type* ty) {
|
||||
auto name = b.Symbols().New("tint_clamp");
|
||||
|
||||
b.Func(name,
|
||||
utils::Vector{
|
||||
b.Param("e", T(ty)),
|
||||
b.Param("low", T(ty)),
|
||||
b.Param("high", T(ty)),
|
||||
},
|
||||
T(ty),
|
||||
utils::Vector{
|
||||
// return min(max(e, low), high);
|
||||
b.Return(b.Call("min", b.Call("max", "e", "low"), "high")),
|
||||
});
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Builds the polyfill function for the `countLeadingZeros` builtin
|
||||
/// @param ty the parameter and return type for the function
|
||||
/// @return the polyfill function name
|
||||
@@ -588,6 +609,12 @@ bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) con
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kClamp:
|
||||
if (builtins.clamp_int) {
|
||||
auto& sig = builtin->Signature();
|
||||
return sig.parameters[0]->Type()->is_integer_scalar_or_vector();
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kCountLeadingZeros:
|
||||
if (builtins.count_leading_zeros) {
|
||||
return true;
|
||||
@@ -679,6 +706,16 @@ void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) cons
|
||||
polyfills, builtin, [&] { return s.atanh(builtin->ReturnType()); });
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kClamp:
|
||||
if (builtins.clamp_int) {
|
||||
auto& sig = builtin->Signature();
|
||||
if (sig.parameters[0]->Type()->is_integer_scalar_or_vector()) {
|
||||
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
|
||||
return s.clampInteger(builtin->ReturnType());
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kCountLeadingZeros:
|
||||
if (builtins.count_leading_zeros) {
|
||||
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
|
||||
|
||||
@@ -47,6 +47,8 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
|
||||
bool asinh = false;
|
||||
/// What level should `atanh` be polyfilled?
|
||||
Level atanh = Level::kNone;
|
||||
/// Should `clamp()` be polyfilled for integer values (scalar or vector)?
|
||||
bool clamp_int = false;
|
||||
/// Should `countLeadingZeros()` be polyfilled?
|
||||
bool count_leading_zeros = false;
|
||||
/// Should `countTrailingZeros()` be polyfilled?
|
||||
|
||||
@@ -398,6 +398,173 @@ fn f() {
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// clampInteger
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DataMap polyfillClampInteger() {
|
||||
BuiltinPolyfill::Builtins builtins;
|
||||
builtins.clamp_int = true;
|
||||
DataMap data;
|
||||
data.Add<BuiltinPolyfill::Config>(builtins);
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunClampInteger_i32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1i;
|
||||
clamp(v, 2i, 3i);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillClampInteger()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunClampInteger_u32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1u;
|
||||
clamp(v, 2u, 3u);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillClampInteger()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunClampInteger_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1f;
|
||||
clamp(v, 2f, 3f);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillClampInteger()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunClampInteger_f16) {
|
||||
auto* src = R"(
|
||||
enable f16;
|
||||
|
||||
fn f() {
|
||||
let v = 1h;
|
||||
clamp(v, 2h, 3h);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillClampInteger()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ClampInteger_ConstantExpression) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : i32 = clamp(1i, 2i, 3i);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = src;
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillClampInteger());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ClampInteger_i32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1i;
|
||||
let r : i32 = clamp(v, 2i, 3i);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_clamp(e : i32, low : i32, high : i32) -> i32 {
|
||||
return min(max(e, low), high);
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let v = 1i;
|
||||
let r : i32 = tint_clamp(v, 2i, 3i);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillClampInteger());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ClampInteger_vec3_i32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1i;
|
||||
let r : vec3<i32> = clamp(vec3(v), vec3(2i), vec3(3i));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect =
|
||||
R"(
|
||||
fn tint_clamp(e : vec3<i32>, low : vec3<i32>, high : vec3<i32>) -> vec3<i32> {
|
||||
return min(max(e, low), high);
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let v = 1i;
|
||||
let r : vec3<i32> = tint_clamp(vec3(v), vec3(2i), vec3(3i));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillClampInteger());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ClampInteger_u32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : u32 = clamp(1u, 2u, 3u);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn f() {
|
||||
let r : u32 = clamp(1u, 2u, 3u);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillClampInteger());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ClampInteger_vec3_u32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let v = 1u;
|
||||
let r : vec3<u32> = clamp(vec3(v), vec3(2u), vec3(3u));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect =
|
||||
R"(
|
||||
fn tint_clamp(e : vec3<u32>, low : vec3<u32>, high : vec3<u32>) -> vec3<u32> {
|
||||
return min(max(e, low), high);
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let v = 1u;
|
||||
let r : vec3<u32> = tint_clamp(vec3(v), vec3(2u), vec3(3u));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillClampInteger());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// countLeadingZeros
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -162,6 +162,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
polyfills.acosh = transform::BuiltinPolyfill::Level::kFull;
|
||||
polyfills.asinh = true;
|
||||
polyfills.atanh = transform::BuiltinPolyfill::Level::kFull;
|
||||
polyfills.clamp_int = true;
|
||||
// TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
|
||||
// and `firstbithigh`.
|
||||
polyfills.count_leading_zeros = true;
|
||||
|
||||
@@ -171,6 +171,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
transform::BuiltinPolyfill::Builtins polyfills;
|
||||
polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.clamp_int = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
|
||||
polyfills.first_leading_bit = true;
|
||||
polyfills.first_trailing_bit = true;
|
||||
|
||||
@@ -52,6 +52,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
transform::BuiltinPolyfill::Builtins polyfills;
|
||||
polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.clamp_int = true;
|
||||
polyfills.count_leading_zeros = true;
|
||||
polyfills.count_trailing_zeros = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
|
||||
|
||||
Reference in New Issue
Block a user