mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-21 18:59:21 +00:00
tint: Implement acosh, asinh, atanh
Polyfill them completely for HLSL. For the other backends, just add range checks for acosh and atanh. Fixed: tint:1465 Change-Id: I3abda99b474d9f5ba09abf400381467dc28ea0bd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94380 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Reviewed-by: Ben Clayton <bclayton@google.com> Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
6058882d4b
commit
d23f296a9a
@@ -44,6 +44,100 @@ struct BuiltinPolyfill::State {
|
||||
/// The source clone context
|
||||
const sem::Info& sem = ctx.src->Sem();
|
||||
|
||||
/// Builds the polyfill function for the `acosh` builtin
|
||||
/// @param ty the parameter and return type for the function
|
||||
/// @return the polyfill function name
|
||||
Symbol acosh(const sem::Type* ty) {
|
||||
auto name = b.Symbols().New("tint_acosh");
|
||||
uint32_t width = WidthOf(ty);
|
||||
|
||||
auto V = [&](AFloat value) -> const ast::Expression* {
|
||||
const ast::Expression* expr = b.Expr(value);
|
||||
if (width == 1) {
|
||||
return expr;
|
||||
}
|
||||
return b.Construct(T(ty), expr);
|
||||
};
|
||||
|
||||
ast::StatementList body;
|
||||
switch (polyfill.acosh) {
|
||||
case Level::kFull:
|
||||
// return log(x + sqrt(x*x - 1));
|
||||
body.emplace_back(b.Return(
|
||||
b.Call("log", b.Add("x", b.Call("sqrt", b.Sub(b.Mul("x", "x"), 1_a))))));
|
||||
break;
|
||||
case Level::kRangeCheck: {
|
||||
// return select(acosh(x), 0, x < 1);
|
||||
body.emplace_back(b.Return(
|
||||
b.Call("select", b.Call("acosh", "x"), V(0.0_a), b.LessThan("x", V(1.0_a)))));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TINT_ICE(Transform, b.Diagnostics())
|
||||
<< "unhandled polyfill level: " << static_cast<int>(polyfill.acosh);
|
||||
return {};
|
||||
}
|
||||
|
||||
b.Func(name, {b.Param("x", T(ty))}, T(ty), body);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Builds the polyfill function for the `asinh` builtin
|
||||
/// @param ty the parameter and return type for the function
|
||||
/// @return the polyfill function name
|
||||
Symbol asinh(const sem::Type* ty) {
|
||||
auto name = b.Symbols().New("tint_sinh");
|
||||
|
||||
ast::StatementList body;
|
||||
|
||||
// return log(x + sqrt(x*x + 1));
|
||||
body.emplace_back(
|
||||
b.Return(b.Call("log", b.Add("x", b.Call("sqrt", b.Add(b.Mul("x", "x"), 1_a))))));
|
||||
|
||||
b.Func(name, {b.Param("x", T(ty))}, T(ty), body);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Builds the polyfill function for the `atanh` builtin
|
||||
/// @param ty the parameter and return type for the function
|
||||
/// @return the polyfill function name
|
||||
Symbol atanh(const sem::Type* ty) {
|
||||
auto name = b.Symbols().New("tint_atanh");
|
||||
uint32_t width = WidthOf(ty);
|
||||
|
||||
auto V = [&](AFloat value) -> const ast::Expression* {
|
||||
const ast::Expression* expr = b.Expr(value);
|
||||
if (width == 1) {
|
||||
return expr;
|
||||
}
|
||||
return b.Construct(T(ty), expr);
|
||||
};
|
||||
|
||||
ast::StatementList body;
|
||||
switch (polyfill.atanh) {
|
||||
case Level::kFull:
|
||||
// return log((1+x) / (1-x)) * 0.5
|
||||
body.emplace_back(
|
||||
b.Return(b.Mul(b.Call("log", b.Div(b.Add(1_a, "x"), b.Sub(1_a, "x"))), 0.5_a)));
|
||||
break;
|
||||
case Level::kRangeCheck:
|
||||
// return select(atanh(x), 0, x >= 1);
|
||||
body.emplace_back(b.Return(b.Call("select", b.Call("atanh", "x"), V(0.0_a),
|
||||
b.GreaterThanEqual("x", V(1.0_a)))));
|
||||
break;
|
||||
default:
|
||||
TINT_ICE(Transform, b.Diagnostics())
|
||||
<< "unhandled polyfill level: " << static_cast<int>(polyfill.acosh);
|
||||
return {};
|
||||
}
|
||||
|
||||
b.Func(name, {b.Param("x", T(ty))}, T(ty), body);
|
||||
|
||||
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
|
||||
@@ -440,6 +534,21 @@ bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) con
|
||||
if (auto* call = sem.Get<sem::Call>(node)) {
|
||||
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
|
||||
switch (builtin->Type()) {
|
||||
case sem::BuiltinType::kAcosh:
|
||||
if (builtins.acosh != Level::kNone) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kAsinh:
|
||||
if (builtins.asinh) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kAtanh:
|
||||
if (builtins.atanh != Level::kNone) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kCountLeadingZeros:
|
||||
if (builtins.count_leading_zeros) {
|
||||
return true;
|
||||
@@ -496,6 +605,24 @@ void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) cons
|
||||
if (auto* builtin = call->Target()->As<sem::Builtin>()) {
|
||||
Symbol polyfill;
|
||||
switch (builtin->Type()) {
|
||||
case sem::BuiltinType::kAcosh:
|
||||
if (builtins.acosh != Level::kNone) {
|
||||
polyfill = utils::GetOrCreate(
|
||||
polyfills, builtin, [&] { return s.acosh(builtin->ReturnType()); });
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kAsinh:
|
||||
if (builtins.asinh) {
|
||||
polyfill = utils::GetOrCreate(
|
||||
polyfills, builtin, [&] { return s.asinh(builtin->ReturnType()); });
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kAtanh:
|
||||
if (builtins.atanh != Level::kNone) {
|
||||
polyfill = utils::GetOrCreate(
|
||||
polyfills, builtin, [&] { return s.atanh(builtin->ReturnType()); });
|
||||
}
|
||||
break;
|
||||
case sem::BuiltinType::kCountLeadingZeros:
|
||||
if (builtins.count_leading_zeros) {
|
||||
polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
|
||||
|
||||
@@ -33,12 +33,20 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
|
||||
kNone,
|
||||
/// Clamp the parameters to the inner implementation.
|
||||
kClampParameters,
|
||||
/// Range check the input.
|
||||
kRangeCheck,
|
||||
/// Polyfill the entire function
|
||||
kFull,
|
||||
};
|
||||
|
||||
/// Specifies the builtins that should be polyfilled by the transform.
|
||||
struct Builtins {
|
||||
/// What level should `acosh` be polyfilled?
|
||||
Level acosh = Level::kNone;
|
||||
/// Should `asinh` be polyfilled?
|
||||
bool asinh = false;
|
||||
/// What level should `atanh` be polyfilled?
|
||||
Level atanh = Level::kNone;
|
||||
/// Should `countLeadingZeros()` be polyfilled?
|
||||
bool count_leading_zeros = false;
|
||||
/// Should `countTrailingZeros()` be polyfilled?
|
||||
|
||||
@@ -41,6 +41,292 @@ TEST_F(BuiltinPolyfillTest, EmptyModule) {
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// acosh
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DataMap polyfillAcosh(Level level) {
|
||||
BuiltinPolyfill::Builtins builtins;
|
||||
builtins.acosh = level;
|
||||
DataMap data;
|
||||
data.Add<BuiltinPolyfill::Config>(builtins);
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunAcosh) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
acosh(1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kNone)));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kClampParameters)));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull)));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Acosh_Full_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : f32 = acosh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_acosh(x : f32) -> f32 {
|
||||
return log((x + sqrt(((x * x) - 1))));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : f32 = tint_acosh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Acosh_Full_vec3_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = acosh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_acosh(x : vec3<f32>) -> vec3<f32> {
|
||||
return log((x + sqrt(((x * x) - 1))));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : vec3<f32> = tint_acosh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kFull));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Acosh_Range_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : f32 = acosh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_acosh(x : f32) -> f32 {
|
||||
return select(acosh(x), 0.0, (x < 1.0));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : f32 = tint_acosh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Acosh_Range_vec3_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = acosh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_acosh(x : vec3<f32>) -> vec3<f32> {
|
||||
return select(acosh(x), vec3<f32>(0.0), (x < vec3<f32>(1.0)));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : vec3<f32> = tint_acosh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// asinh
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DataMap polyfillSinh() {
|
||||
BuiltinPolyfill::Builtins builtins;
|
||||
builtins.asinh = true;
|
||||
DataMap data;
|
||||
data.Add<BuiltinPolyfill::Config>(builtins);
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunAsinh) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
asinh(1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillSinh()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Asinh_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : f32 = asinh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_sinh(x : f32) -> f32 {
|
||||
return log((x + sqrt(((x * x) + 1))));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : f32 = tint_sinh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillSinh());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Asinh_vec3_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = asinh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_sinh(x : vec3<f32>) -> vec3<f32> {
|
||||
return log((x + sqrt(((x * x) + 1))));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : vec3<f32> = tint_sinh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillSinh());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// atanh
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DataMap polyfillAtanh(Level level) {
|
||||
BuiltinPolyfill::Builtins builtins;
|
||||
builtins.atanh = level;
|
||||
DataMap data;
|
||||
data.Add<BuiltinPolyfill::Config>(builtins);
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunAtanh) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
atanh(1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kNone)));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kClampParameters)));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull)));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Atanh_Full_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : f32 = atanh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_atanh(x : f32) -> f32 {
|
||||
return (log(((1 + x) / (1 - x))) * 0.5);
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : f32 = tint_atanh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Atanh_Full_vec3_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = atanh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_atanh(x : vec3<f32>) -> vec3<f32> {
|
||||
return (log(((1 + x) / (1 - x))) * 0.5);
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : vec3<f32> = tint_atanh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kFull));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Atanh_Range_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : f32 = atanh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn tint_atanh(x : f32) -> f32 {
|
||||
return select(atanh(x), 0.0, (x >= 1.0));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let r : f32 = tint_atanh(1234);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAtanh(Level::kRangeCheck));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, Atanh_Range_vec3_f32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = atanh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn f() {
|
||||
let r : vec3<f32> = atanh(vec3<f32>(1234));
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillAcosh(Level::kRangeCheck));
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// countLeadingZeros
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user