Work around divide-by-zero UBSAN errors in intrinsic optimization.

If the SkSL program contains intrinsics that would divide by zero when
being optimized, the fuzzer would report this as undefined behavior.
Skia insists on IEEE semantics so this isn't a concern for us. We now
use `sk_ieee_double_divide` to work around these fuzzer issues.

Also note that the optimizer will discard results that are not finite,
so these infinite/NaN values are ephemeral anyway--they won't be used
in the final output. The intrinsic in the code will be left
as-is/unoptimized.

Change-Id: I747a434898a15b34716d95f6ca3d29fe4452005d
Bug: oss-fuzz:37850, oss-fuzz:37822, oss-fuzz:37761
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/443399
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/ir/SkSLFunctionCall.cpp b/src/sksl/ir/SkSLFunctionCall.cpp
index d402a51..d9d4b78 100644
--- a/src/sksl/ir/SkSLFunctionCall.cpp
+++ b/src/sksl/ir/SkSLFunctionCall.cpp
@@ -16,6 +16,7 @@
 #include "src/sksl/ir/SkSLFunctionCall.h"
 #include "src/sksl/ir/SkSLIntLiteral.h"
 
+#include "include/private/SkFloatingPoint.h"
 #include "include/sksl/DSLCore.h"
 #include "src/core/SkMatrixInvert.h"
 
@@ -404,22 +405,26 @@
 double evaluate_exp2(double a, double, double)         { return std::exp2(a); }
 double evaluate_log2(double a, double, double)         { return std::log2(a); }
 double evaluate_sqrt(double a, double, double)         { return std::sqrt(a); }
-double evaluate_inversesqrt(double a, double, double)  { return 1.0 / std::sqrt(a); }
+double evaluate_inversesqrt(double a, double, double) {
+    return sk_ieee_double_divide(1.0, std::sqrt(a));
+}
 
 double evaluate_abs(double a, double, double)          { return std::abs(a); }
 double evaluate_sign(double a, double, double)         { return (a > 0) - (a < 0); }
 double evaluate_floor(double a, double, double)        { return std::floor(a); }
 double evaluate_ceil(double a, double, double)         { return std::ceil(a); }
 double evaluate_fract(double a, double, double)        { return a - std::floor(a); }
-double evaluate_mod(double a, double b, double)        { return a - b * std::floor(a / b); }
 double evaluate_min(double a, double b, double)        { return (a < b) ? a : b; }
 double evaluate_max(double a, double b, double)        { return (a > b) ? a : b; }
 double evaluate_clamp(double x, double l, double h)    { return (x < l) ? l : (x > h) ? h : x; }
 double evaluate_saturate(double a, double, double)     { return (a < 0) ? 0 : (a > 1) ? 1 : a; }
 double evaluate_mix(double x, double y, double a)      { return x * (1 - a) + y * a; }
 double evaluate_step(double e, double x, double)       { return (x < e) ? 0 : 1; }
+double evaluate_mod(double a, double b, double) {
+    return a - b * std::floor(sk_ieee_double_divide(a, b));
+}
 double evaluate_smoothstep(double edge0, double edge1, double x) {
-    auto t = (x - edge0) / (edge1 - edge0);
+    double t = sk_ieee_double_divide(x - edge0, edge1 - edge0);
     t = (t < 0) ? 0 : (t > 1) ? 1 : t;
     return t * t * (3.0 - 2.0 * t);
 }