tint/intrinsics.def: Implement saturate()

Fixed: tint:1591
Change-Id: I0b1397d74abd49cd44caf326a2063e50c5cf07de
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101480
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton
2022-09-13 22:57:52 +00:00
committed by Dawn LUCI CQ
parent f3d9ea4bea
commit 751e6686aa
124 changed files with 8235 additions and 3098 deletions

View File

@@ -508,6 +508,8 @@ fn reverseBits<T: iu32>(T) -> T
fn reverseBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
fn round<T: f32_f16>(T) -> T
fn round<N: num, T: f32_f16>(vec<N, T>) -> vec<N, T>
fn saturate<T: f32_f16>(T) -> T
fn saturate<T: f32_f16, N: num>(vec<N, T>) -> vec<N, T>
fn select<T: scalar>(T, T, bool) -> T
fn select<T: scalar, N: num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T>
fn select<N: num, T: scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T>

File diff suppressed because it is too large Load Diff

View File

@@ -225,6 +225,9 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "round") {
return BuiltinType::kRound;
}
if (name == "saturate") {
return BuiltinType::kSaturate;
}
if (name == "select") {
return BuiltinType::kSelect;
}
@@ -493,6 +496,8 @@ const char* str(BuiltinType i) {
return "reverseBits";
case BuiltinType::kRound:
return "round";
case BuiltinType::kSaturate:
return "saturate";
case BuiltinType::kSelect:
return "select";
case BuiltinType::kSign:

View File

@@ -97,6 +97,7 @@ enum class BuiltinType {
kRefract,
kReverseBits,
kRound,
kSaturate,
kSelect,
kSign,
kSin,

View File

@@ -495,6 +495,23 @@ struct BuiltinPolyfill::State {
return name;
}
/// Builds the polyfill function for the `saturate` builtin
/// @param ty the parameter and return type for the function
/// @return the polyfill function name
Symbol saturate(const sem::Type* ty) {
auto name = b.Symbols().New("tint_saturate");
auto body = utils::Vector{
b.Return(b.Call("clamp", "v", b.Construct(T(ty), 0_a), b.Construct(T(ty), 1_a))),
};
b.Func(name,
utils::Vector{
b.Param("v", T(ty)),
},
T(ty), body);
return name;
}
private:
/// @returns the AST type for the given sem type
const ast::Type* T(const sem::Type* ty) const { return CreateASTTypeFor(ctx, ty); }
@@ -575,6 +592,11 @@ bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) con
return true;
}
break;
case sem::BuiltinType::kSaturate:
if (builtins.saturate) {
return true;
}
break;
default:
break;
}
@@ -661,6 +683,13 @@ void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) cons
});
}
break;
case sem::BuiltinType::kSaturate:
if (builtins.saturate) {
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
return s.saturate(builtin->ReturnType());
});
}
break;
default:
break;
}

View File

@@ -59,6 +59,8 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
bool first_trailing_bit = false;
/// Should `insertBits()` be polyfilled?
Level insert_bits = Level::kNone;
/// Should `saturate()` be polyfilled?
bool saturate = false;
};
/// Config is consumed by the BuiltinPolyfill transform.

View File

@@ -1387,5 +1387,167 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// saturate
////////////////////////////////////////////////////////////////////////////////
DataMap polyfillSaturate() {
BuiltinPolyfill::Builtins builtins;
builtins.saturate = true;
DataMap data;
data.Add<BuiltinPolyfill::Config>(builtins);
return data;
}
TEST_F(BuiltinPolyfillTest, ShouldRunSaturate) {
auto* src = R"(
fn f() {
saturate(0.5);
}
)";
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillSaturate()));
}
TEST_F(BuiltinPolyfillTest, Saturate_f32) {
auto* src = R"(
fn f() {
let r : f32 = saturate(0.5f);
}
)";
auto* expect = R"(
fn tint_saturate(v : f32) -> f32 {
return clamp(v, f32(0), f32(1));
}
fn f() {
let r : f32 = tint_saturate(0.5f);
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, Saturate_f32_from_abstract_float) {
auto* src = R"(
fn f() {
let r : f32 = saturate(0.5);
}
)";
auto* expect = R"(
fn tint_saturate(v : f32) -> f32 {
return clamp(v, f32(0), f32(1));
}
fn f() {
let r : f32 = tint_saturate(0.5);
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, Saturate_f16) {
auto* src = R"(
enable f16;
fn f() {
let r : f16 = saturate(0.5h);
}
)";
auto* expect = R"(
enable f16;
fn tint_saturate(v : f16) -> f16 {
return clamp(v, f16(0), f16(1));
}
fn f() {
let r : f16 = tint_saturate(0.5h);
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, Saturate_vec3_f32) {
auto* src = R"(
fn f() {
let r : vec3<f32> = saturate(vec3<f32>(0.5f));
}
)";
auto* expect = R"(
fn tint_saturate(v : vec3<f32>) -> vec3<f32> {
return clamp(v, vec3<f32>(0), vec3<f32>(1));
}
fn f() {
let r : vec3<f32> = tint_saturate(vec3<f32>(0.5f));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, Saturate_vec3_f32_from_abstract_float) {
auto* src = R"(
fn f() {
let r : vec3<f32> = saturate(vec3(0.5));
}
)";
auto* expect = R"(
fn tint_saturate(v : vec3<f32>) -> vec3<f32> {
return clamp(v, vec3<f32>(0), vec3<f32>(1));
}
fn f() {
let r : vec3<f32> = tint_saturate(vec3(0.5));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, Saturate_vec3_f16) {
auto* src = R"(
enable f16;
fn f() {
let r : vec3<f16> = saturate(vec3<f16>(0.5h));
}
)";
auto* expect = R"(
enable f16;
fn tint_saturate(v : vec3<f16>) -> vec3<f16> {
return clamp(v, vec3<f16>(0), vec3<f16>(1));
}
fn f() {
let r : vec3<f16> = tint_saturate(vec3<f16>(0.5h));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillSaturate());
EXPECT_EQ(expect, str(got));
}
} // namespace
} // namespace tint::transform

View File

@@ -194,6 +194,7 @@ SanitizedResult Sanitize(const Program* in,
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.saturate = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}

View File

@@ -2510,6 +2510,7 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
case sem::BuiltinType::kReflect:
case sem::BuiltinType::kRefract:
case sem::BuiltinType::kRound:
case sem::BuiltinType::kSaturate:
case sem::BuiltinType::kSign:
case sem::BuiltinType::kSin:
case sem::BuiltinType::kSinh:

View File

@@ -1400,6 +1400,7 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
case sem::BuiltinType::kPow:
case sem::BuiltinType::kReflect:
case sem::BuiltinType::kRefract:
case sem::BuiltinType::kSaturate:
case sem::BuiltinType::kSelect:
case sem::BuiltinType::kSin:
case sem::BuiltinType::kSinh:

View File

@@ -57,6 +57,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
polyfills.first_leading_bit = true;
polyfills.first_trailing_bit = true;
polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
polyfills.saturate = true;
data.Add<transform::BuiltinPolyfill::Config>(polyfills);
manager.Add<transform::BuiltinPolyfill>();
}