diff options
author | 2016-11-09 13:26:45 -0800 | |
---|---|---|
committer | 2016-11-09 13:26:45 -0800 | |
commit | 08a9211a8492a84e1f4a6899759f8f37ed5aec3e (patch) | |
tree | 8fe430d685b62467d0a59aa374ef7b98d6a3db4a /src | |
parent | f2b024db6777a904d986c68a21ba0bc41f956f6e (diff) |
added constant folding & branch elimination to skslc
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2489673002
Committed: https://skia.googlesource.com/skia/+/6136310ee8f43247548bcefcaeca6d43023c10aa
Review-Url: https://codereview.chromium.org/2489673002
Diffstat (limited to 'src')
-rw-r--r-- | src/sksl/SkSLIRGenerator.cpp | 112 | ||||
-rw-r--r-- | src/sksl/SkSLIRGenerator.h | 5 |
2 files changed, 112 insertions, 5 deletions
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index ec64fa9348..1a4c775998 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -246,6 +246,19 @@ std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) { return nullptr; } } + if (test->fKind == Expression::kBoolLiteral_Kind) { + // static boolean value, fold down to a single branch + if (((BoolLiteral&) *test).fValue) { + return ifTrue; + } else if (s.fIfFalse) { + return ifFalse; + } else { + // False & no else clause. Not an error, so don't return null! + std::vector<std::unique_ptr<Statement>> empty; + return std::unique_ptr<Statement>(new Block(s.fPosition, std::move(empty), + fSymbolTable)); + } + } return std::unique_ptr<Statement>(new IfStatement(s.fPosition, std::move(test), std::move(ifTrue), std::move(ifFalse))); } @@ -794,6 +807,78 @@ static bool determine_binary_type(const Context& context, return false; } +/** + * If both operands are compile-time constants and can be folded, returns an expression representing + * the folded value. Otherwise, returns null. Note that unlike most other functions here, null does + * not represent a compilation error. + */ +std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left, + Token::Kind op, + const Expression& right) { + // Note that we expressly do not worry about precision and overflow here -- we use the maximum + // precision to calculate the results and hope the result makes sense. The plan is to move the + // Skia caps into SkSL, so we have access to all of them including the precisions of the various + // types, which will let us be more intelligent about this. + if (left.fKind == Expression::kBoolLiteral_Kind && + right.fKind == Expression::kBoolLiteral_Kind) { + bool leftVal = ((BoolLiteral&) left).fValue; + bool rightVal = ((BoolLiteral&) right).fValue; + bool result; + switch (op) { + case Token::LOGICALAND: result = leftVal && rightVal; break; + case Token::LOGICALOR: result = leftVal || rightVal; break; + case Token::LOGICALXOR: result = leftVal ^ rightVal; break; + default: return nullptr; + } + return std::unique_ptr<Expression>(new BoolLiteral(fContext, left.fPosition, result)); + } + #define RESULT(t, op) std::unique_ptr<Expression>(new t ## Literal(fContext, left.fPosition, \ + leftVal op rightVal)) + if (left.fKind == Expression::kIntLiteral_Kind && right.fKind == Expression::kIntLiteral_Kind) { + int64_t leftVal = ((IntLiteral&) left).fValue; + int64_t rightVal = ((IntLiteral&) right).fValue; + switch (op) { + case Token::PLUS: return RESULT(Int, +); + case Token::MINUS: return RESULT(Int, -); + case Token::STAR: return RESULT(Int, *); + case Token::SLASH: return RESULT(Int, /); + case Token::PERCENT: return RESULT(Int, %); + case Token::BITWISEAND: return RESULT(Int, &); + case Token::BITWISEOR: return RESULT(Int, |); + case Token::BITWISEXOR: return RESULT(Int, ^); + case Token::SHL: return RESULT(Int, <<); + case Token::SHR: return RESULT(Int, >>); + case Token::EQEQ: return RESULT(Bool, ==); + case Token::NEQ: return RESULT(Bool, !=); + case Token::GT: return RESULT(Bool, >); + case Token::GTEQ: return RESULT(Bool, >=); + case Token::LT: return RESULT(Bool, <); + case Token::LTEQ: return RESULT(Bool, <=); + default: return nullptr; + } + } + if (left.fKind == Expression::kFloatLiteral_Kind && + right.fKind == Expression::kFloatLiteral_Kind) { + double leftVal = ((FloatLiteral&) left).fValue; + double rightVal = ((FloatLiteral&) right).fValue; + switch (op) { + case Token::PLUS: return RESULT(Float, +); + case Token::MINUS: return RESULT(Float, -); + case Token::STAR: return RESULT(Float, *); + case Token::SLASH: return RESULT(Float, /); + case Token::EQEQ: return RESULT(Bool, ==); + case Token::NEQ: return RESULT(Bool, !=); + case Token::GT: return RESULT(Bool, >); + case Token::GTEQ: return RESULT(Bool, >=); + case Token::LT: return RESULT(Bool, <); + case Token::LTEQ: return RESULT(Bool, <=); + default: return nullptr; + } + } + #undef RESULT + return nullptr; +} + std::unique_ptr<Expression> IRGenerator::convertBinaryExpression( const ASTBinaryExpression& expression) { std::unique_ptr<Expression> left = this->convertExpression(*expression.fLeft); @@ -823,11 +908,16 @@ std::unique_ptr<Expression> IRGenerator::convertBinaryExpression( if (!left || !right) { return nullptr; } - return std::unique_ptr<Expression>(new BinaryExpression(expression.fPosition, - std::move(left), - expression.fOperator, - std::move(right), - *resultType)); + std::unique_ptr<Expression> result = this->constantFold(*left.get(), expression.fOperator, + *right.get()); + if (!result) { + result = std::unique_ptr<Expression>(new BinaryExpression(expression.fPosition, + std::move(left), + expression.fOperator, + std::move(right), + *resultType)); + } + return result; } std::unique_ptr<Expression> IRGenerator::convertTernaryExpression( @@ -858,6 +948,14 @@ std::unique_ptr<Expression> IRGenerator::convertTernaryExpression( ASSERT(trueType == falseType); ifTrue = this->coerce(std::move(ifTrue), *trueType); ifFalse = this->coerce(std::move(ifFalse), *falseType); + if (test->fKind == Expression::kBoolLiteral_Kind) { + // static boolean test, just return one of the branches + if (((BoolLiteral&) *test).fValue) { + return ifTrue; + } else { + return ifFalse; + } + } return std::unique_ptr<Expression>(new TernaryExpression(expression.fPosition, std::move(test), std::move(ifTrue), @@ -1126,6 +1224,10 @@ std::unique_ptr<Expression> IRGenerator::convertPrefixExpression( "' cannot operate on '" + base->fType.description() + "'"); return nullptr; } + if (base->fKind == Expression::kBoolLiteral_Kind) { + return std::unique_ptr<Expression>(new BoolLiteral(fContext, base->fPosition, + !((BoolLiteral&) *base).fValue)); + } break; case Token::BITWISENOT: if (base->fType != *fContext.fInt_Type) { diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h index a1b86f4f54..036f24253b 100644 --- a/src/sksl/SkSLIRGenerator.h +++ b/src/sksl/SkSLIRGenerator.h @@ -89,6 +89,11 @@ private: std::unique_ptr<Statement> convertDiscard(const ASTDiscardStatement& d); std::unique_ptr<Statement> convertDo(const ASTDoStatement& d); std::unique_ptr<Expression> convertBinaryExpression(const ASTBinaryExpression& expression); + // Returns null if it cannot fold the expression. Note that unlike most other functions here, a + // null return does not represent a compilation error. + std::unique_ptr<Expression> constantFold(const Expression& left, + Token::Kind op, + const Expression& right); std::unique_ptr<Extension> convertExtension(const ASTExtension& e); std::unique_ptr<Statement> convertExpressionStatement(const ASTExpressionStatement& s); std::unique_ptr<Statement> convertFor(const ASTForStatement& f); |