Prevent overflow to infinity in constant-folding.
Expressions which would optimize to a non-finite value are now left
as-is.
Integer math still has problems with overflow, but that can be addressed
separately.
Change-Id: I363a2c42684989062f606186f48246b7ac5b585c
Bug: skia:12050
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/412956
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLConstantFolder.cpp b/src/sksl/SkSLConstantFolder.cpp
index 83d4ebb..9a1851a 100644
--- a/src/sksl/SkSLConstantFolder.cpp
+++ b/src/sksl/SkSLConstantFolder.cpp
@@ -318,6 +318,20 @@
return nullptr;
}
+template <typename T>
+static std::unique_ptr<Expression> fold_float_expression(int offset,
+ T result,
+ const Type* resultType) {
+ // If constant-folding this expression would generate a NaN/infinite result, leave it as-is.
+ if constexpr (std::is_floating_point<T>::value) {
+ if (!std::isfinite(result)) {
+ return nullptr;
+ }
+ }
+
+ return Literal<T>::Make(offset, result, resultType);
+}
+
std::unique_ptr<Expression> ConstantFolder::Simplify(const Context& context,
int offset,
const Expression& leftExpr,
@@ -418,10 +432,10 @@
// precision to calculate the results and hope the result makes sense.
// TODO(skia:10932): detect and handle integer overflow properly.
using SKSL_UINT = uint64_t;
- #define RESULT(t, op) t ## Literal::Make(offset, leftVal op rightVal, &resultType)
- #define URESULT(t, op) t ## Literal::Make(offset, (SKSL_UINT)(leftVal) op \
- (SKSL_UINT)(rightVal), &resultType)
if (left->is<IntLiteral>() && right->is<IntLiteral>()) {
+ #define RESULT(t, op) t ## Literal::Make(offset, leftVal op rightVal, &resultType)
+ #define URESULT(t, op) t ## Literal::Make(offset, (SKSL_UINT)(leftVal) op \
+ (SKSL_UINT)(rightVal), &resultType)
SKSL_INT leftVal = left->as<IntLiteral>().value();
SKSL_INT rightVal = right->as<IntLiteral>().value();
switch (op.kind()) {
@@ -467,25 +481,30 @@
default:
return nullptr;
}
+ #undef RESULT
+ #undef URESULT
}
// Perform constant folding on pairs of floating-point literals.
if (left->is<FloatLiteral>() && right->is<FloatLiteral>()) {
SKSL_FLOAT leftVal = left->as<FloatLiteral>().value();
SKSL_FLOAT rightVal = right->as<FloatLiteral>().value();
+
+ #define RESULT(Op) fold_float_expression(offset, leftVal Op rightVal, &resultType)
switch (op.kind()) {
- case Token::Kind::TK_PLUS: return RESULT(Float, +);
- case Token::Kind::TK_MINUS: return RESULT(Float, -);
- case Token::Kind::TK_STAR: return RESULT(Float, *);
- case Token::Kind::TK_SLASH: return RESULT(Float, /);
- case Token::Kind::TK_EQEQ: return RESULT(Bool, ==);
- case Token::Kind::TK_NEQ: return RESULT(Bool, !=);
- case Token::Kind::TK_GT: return RESULT(Bool, >);
- case Token::Kind::TK_GTEQ: return RESULT(Bool, >=);
- case Token::Kind::TK_LT: return RESULT(Bool, <);
- case Token::Kind::TK_LTEQ: return RESULT(Bool, <=);
- default: return nullptr;
+ case Token::Kind::TK_PLUS: return RESULT(+);
+ case Token::Kind::TK_MINUS: return RESULT(-);
+ case Token::Kind::TK_STAR: return RESULT(*);
+ case Token::Kind::TK_SLASH: return RESULT(/);
+ case Token::Kind::TK_EQEQ: return RESULT(==);
+ case Token::Kind::TK_NEQ: return RESULT(!=);
+ case Token::Kind::TK_GT: return RESULT(>);
+ case Token::Kind::TK_GTEQ: return RESULT(>=);
+ case Token::Kind::TK_LT: return RESULT(<);
+ case Token::Kind::TK_LTEQ: return RESULT(<=);
+ default: return nullptr;
}
+ #undef RESULT
}
// Perform constant folding on pairs of vectors.
@@ -554,8 +573,6 @@
}
// We aren't able to constant-fold.
- #undef RESULT
- #undef URESULT
return nullptr;
}