Flutter Engine
The Flutter Engine
Static Public Member Functions | List of all members
SkSL::ConstantFolder Class Reference

#include <SkSLConstantFolder.h>

Static Public Member Functions

static bool GetConstantInt (const Expression &value, SKSL_INT *out)
 
static bool GetConstantValue (const Expression &value, double *out)
 
static const ExpressionGetConstantValueForVariable (const Expression &value)
 
static const ExpressionGetConstantValueOrNull (const Expression &value)
 
static bool IsConstantSplat (const Expression &expr, double value)
 
static std::unique_ptr< ExpressionMakeConstantValueForVariable (Position pos, std::unique_ptr< Expression > expr)
 
static std::unique_ptr< ExpressionSimplify (const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)
 

Detailed Description

Performs constant folding on IR expressions. This simplifies expressions containing compile-time constants, such as replacing Literal(2) + Literal(2) with Literal(4).

Definition at line 27 of file SkSLConstantFolder.h.

Member Function Documentation

◆ GetConstantInt()

bool SkSL::ConstantFolder::GetConstantInt ( const Expression value,
SKSL_INT out 
)
static

If value is an int literal or const int variable with a known value, returns true and stores the value in out. Otherwise, returns false.

Definition at line 325 of file SkSLConstantFolder.cpp.

325 {
326 const Expression* expr = GetConstantValueForVariable(value);
327 if (!expr->isIntLiteral()) {
328 return false;
329 }
330 *out = expr->as<Literal>().intValue();
331 return true;
332}
static const Expression * GetConstantValueForVariable(const Expression &value)
uint8_t value

◆ GetConstantValue()

bool SkSL::ConstantFolder::GetConstantValue ( const Expression value,
double *  out 
)
static

If value is a literal or const scalar variable with a known value, returns true and stores the value in out. Otherwise, returns false.

Definition at line 334 of file SkSLConstantFolder.cpp.

334 {
335 const Expression* expr = GetConstantValueForVariable(value);
336 if (!expr->is<Literal>()) {
337 return false;
338 }
339 *out = expr->as<Literal>().value();
340 return true;
341}

◆ GetConstantValueForVariable()

const Expression * SkSL::ConstantFolder::GetConstantValueForVariable ( const Expression value)
static

If the expression is a const variable with a known compile-time-constant value, returns that value. If not, returns the original expression as-is.

Definition at line 461 of file SkSLConstantFolder.cpp.

461 {
462 const Expression* expr = GetConstantValueOrNull(inExpr);
463 return expr ? expr : &inExpr;
464}
static const Expression * GetConstantValueOrNull(const Expression &value)

◆ GetConstantValueOrNull()

const Expression * SkSL::ConstantFolder::GetConstantValueOrNull ( const Expression value)
static

If the expression can be replaced by a compile-time-constant value, returns that value. If not, returns null.

Definition at line 440 of file SkSLConstantFolder.cpp.

440 {
441 const Expression* expr = &inExpr;
442 while (expr->is<VariableReference>()) {
443 const VariableReference& varRef = expr->as<VariableReference>();
444 if (varRef.refKind() != VariableRefKind::kRead) {
445 return nullptr;
446 }
447 const Variable& var = *varRef.variable();
448 if (!var.modifierFlags().isConst()) {
449 return nullptr;
450 }
451 expr = var.initialValue();
452 if (!expr) {
453 // Generally, const variables must have initial values. However, function parameters are
454 // an exception; they can be const but won't have an initial value.
455 return nullptr;
456 }
457 }
458 return Analysis::IsCompileTimeConstant(*expr) ? expr : nullptr;
459}
bool IsCompileTimeConstant(const Expression &expr)

◆ IsConstantSplat()

bool SkSL::ConstantFolder::IsConstantSplat ( const Expression expr,
double  value 
)
static

Returns true if the expression contains value in every slot.

Definition at line 354 of file SkSLConstantFolder.cpp.

354 {
355 int numSlots = expr.type().slotCount();
356 for (int index = 0; index < numSlots; ++index) {
357 std::optional<double> slotVal = expr.getConstantValue(index);
358 if (!slotVal.has_value() || *slotVal != value) {
359 return false;
360 }
361 }
362 return true;
363}

◆ MakeConstantValueForVariable()

std::unique_ptr< Expression > SkSL::ConstantFolder::MakeConstantValueForVariable ( Position  pos,
std::unique_ptr< Expression expr 
)
static

If the expression is a const variable with a known compile-time-constant value, returns a clone of that value. If not, returns the original expression as-is.

Definition at line 466 of file SkSLConstantFolder.cpp.

467 {
468 const Expression* expr = GetConstantValueOrNull(*inExpr);
469 return expr ? expr->clone(pos) : std::move(inExpr);
470}
SkPoint pos

◆ Simplify()

std::unique_ptr< Expression > SkSL::ConstantFolder::Simplify ( const Context context,
Position  pos,
const Expression left,
Operator  op,
const Expression right,
const Type resultType 
)
static

Simplifies the binary expression left OP right. Returns null if it can't be simplified.

Definition at line 810 of file SkSLConstantFolder.cpp.

815 {
816 // Replace constant variables with their literal values.
817 const Expression* left = GetConstantValueForVariable(leftExpr);
818 const Expression* right = GetConstantValueForVariable(rightExpr);
819
820 // If this is the assignment operator, and both sides are the same trivial expression, this is
821 // self-assignment (i.e., `var = var`) and can be reduced to just a variable reference (`var`).
822 // This can happen when other parts of the assignment are optimized away.
823 if (op.kind() == Operator::Kind::EQ && Analysis::IsSameExpressionTree(*left, *right)) {
824 return right->clone(pos);
825 }
826
827 // Simplify the expression when both sides are constant Boolean literals.
828 if (left->isBoolLiteral() && right->isBoolLiteral()) {
829 bool leftVal = left->as<Literal>().boolValue();
830 bool rightVal = right->as<Literal>().boolValue();
831 bool result;
832 switch (op.kind()) {
833 case Operator::Kind::LOGICALAND: result = leftVal && rightVal; break;
834 case Operator::Kind::LOGICALOR: result = leftVal || rightVal; break;
835 case Operator::Kind::LOGICALXOR: result = leftVal ^ rightVal; break;
836 case Operator::Kind::EQEQ: result = leftVal == rightVal; break;
837 case Operator::Kind::NEQ: result = leftVal != rightVal; break;
838 default: return nullptr;
839 }
840 return Literal::MakeBool(context, pos, result);
841 }
842
843 // If the left side is a Boolean literal, apply short-circuit optimizations.
844 if (left->isBoolLiteral()) {
845 return short_circuit_boolean(pos, *left, op, *right);
846 }
847
848 // If the right side is a Boolean literal...
849 if (right->isBoolLiteral()) {
850 // ... and the left side has no side effects...
851 if (!Analysis::HasSideEffects(*left)) {
852 // We can reverse the expressions and short-circuit optimizations are still valid.
853 return short_circuit_boolean(pos, *right, op, *left);
854 }
855
856 // We can't use short-circuiting, but we can still optimize away no-op Boolean expressions.
857 return eliminate_no_op_boolean(pos, *left, op, *right);
858 }
859
860 if (op.kind() == Operator::Kind::EQEQ && Analysis::IsSameExpressionTree(*left, *right)) {
861 // With == comparison, if both sides are the same trivial expression, this is self-
862 // comparison and is always true. (We are not concerned with NaN.)
863 return Literal::MakeBool(context, pos, /*value=*/true);
864 }
865
866 if (op.kind() == Operator::Kind::NEQ && Analysis::IsSameExpressionTree(*left, *right)) {
867 // With != comparison, if both sides are the same trivial expression, this is self-
868 // comparison and is always false. (We are not concerned with NaN.)
869 return Literal::MakeBool(context, pos, /*value=*/false);
870 }
871
872 if (error_on_divide_by_zero(context, pos, op, *right)) {
873 return nullptr;
874 }
875
876 // Perform full constant folding when both sides are compile-time constants.
877 bool leftSideIsConstant = Analysis::IsCompileTimeConstant(*left);
878 bool rightSideIsConstant = Analysis::IsCompileTimeConstant(*right);
879 if (leftSideIsConstant && rightSideIsConstant) {
880 return fold_two_constants(context, pos, left, op, right, resultType);
881 }
882
883 if (context.fConfig->fSettings.fOptimize) {
884 // If just one side is constant, we might still be able to simplify arithmetic expressions
885 // like `x * 1`, `x *= 1`, `x + 0`, `x * 0`, `0 / x`, etc.
886 if (leftSideIsConstant || rightSideIsConstant) {
887 if (std::unique_ptr<Expression> expr = simplify_arithmetic(context, pos, *left, op,
888 *right, resultType)) {
889 return expr;
890 }
891 }
892
893 // We can simplify some forms of matrix division even when neither side is constant.
894 if (std::unique_ptr<Expression> expr = simplify_matrix_division(context, pos, *left, op,
895 *right, resultType)) {
896 return expr;
897 }
898 }
899
900 // We aren't able to constant-fold.
901 return nullptr;
902}
static std::unique_ptr< Literal > MakeBool(const Context &context, Position pos, bool value)
Definition: SkSLLiteral.h:69
GAsyncResult * result
bool IsSameExpressionTree(const Expression &left, const Expression &right)
bool HasSideEffects(const Expression &expr)
static std::unique_ptr< Expression > simplify_matrix_division(const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)
static bool error_on_divide_by_zero(const Context &context, Position pos, Operator op, const Expression &right)
static std::unique_ptr< Expression > eliminate_no_op_boolean(Position pos, const Expression &left, Operator op, const Expression &right)
static std::unique_ptr< Expression > short_circuit_boolean(Position pos, const Expression &left, Operator op, const Expression &right)
static std::unique_ptr< Expression > fold_two_constants(const Context &context, Position pos, const Expression *left, Operator op, const Expression *right, const Type &resultType)
static std::unique_ptr< Expression > simplify_arithmetic(const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)

The documentation for this class was generated from the following files: