| 1 | #include "duckdb/optimizer/cse_optimizer.hpp" |
| 2 | |
| 3 | #include "duckdb/planner/expression/common_subexpression.hpp" |
| 4 | #include "duckdb/planner/expression_iterator.hpp" |
| 5 | #include "duckdb/planner/operator/logical_filter.hpp" |
| 6 | #include "duckdb/planner/operator/logical_projection.hpp" |
| 7 | |
| 8 | using namespace duckdb; |
| 9 | using namespace std; |
| 10 | |
| 11 | void CommonSubExpressionOptimizer::VisitOperator(LogicalOperator &op) { |
| 12 | switch (op.type) { |
| 13 | case LogicalOperatorType::FILTER: |
| 14 | case LogicalOperatorType::PROJECTION: |
| 15 | ExtractCommonSubExpresions(op); |
| 16 | break; |
| 17 | default: |
| 18 | break; |
| 19 | } |
| 20 | LogicalOperatorVisitor::VisitOperator(op); |
| 21 | } |
| 22 | |
| 23 | void CommonSubExpressionOptimizer::CountExpressions(Expression &expr, expression_map_t<CSENode> &expression_count) { |
| 24 | // we only consider expressions with children for CSE elimination |
| 25 | switch (expr.expression_class) { |
| 26 | case ExpressionClass::BOUND_COLUMN_REF: |
| 27 | case ExpressionClass::BOUND_CONSTANT: |
| 28 | case ExpressionClass::BOUND_PARAMETER: |
| 29 | case ExpressionClass::COMMON_SUBEXPRESSION: |
| 30 | return; |
| 31 | default: |
| 32 | break; |
| 33 | } |
| 34 | auto node = expression_count.find(&expr); |
| 35 | if (node == expression_count.end()) { |
| 36 | // first time we encounter this expression, insert this node with [count = 1] |
| 37 | expression_count[&expr] = CSENode(1); |
| 38 | } else { |
| 39 | // we encountered this expression before, increment the occurrence count |
| 40 | node->second.count++; |
| 41 | } |
| 42 | // recursively count the children |
| 43 | ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { CountExpressions(child, expression_count); }); |
| 44 | } |
| 45 | |
| 46 | void CommonSubExpressionOptimizer::PerformCSEReplacement(unique_ptr<Expression> *expr_ptr, |
| 47 | expression_map_t<CSENode> &expression_count) { |
| 48 | Expression &expr = **expr_ptr; |
| 49 | switch (expr.expression_class) { |
| 50 | case ExpressionClass::BOUND_COLUMN_REF: |
| 51 | case ExpressionClass::BOUND_CONSTANT: |
| 52 | case ExpressionClass::BOUND_PARAMETER: |
| 53 | case ExpressionClass::COMMON_SUBEXPRESSION: |
| 54 | return; |
| 55 | default: |
| 56 | break; |
| 57 | } |
| 58 | // check if this child is eligible for CSE elimination |
| 59 | if (expression_count.find(&expr) == expression_count.end()) { |
| 60 | // no occurrence: skip the node |
| 61 | return; |
| 62 | } |
| 63 | auto &node = expression_count[&expr]; |
| 64 | if (node.count > 1) { |
| 65 | // this expression occurs more than once! replace it with a CSE |
| 66 | // check if it has already been replaced with a CSE before |
| 67 | auto alias = expr.alias.empty() ? expr.GetName() : expr.alias; |
| 68 | if (!node.expr) { |
| 69 | // the CSE does not exist yet: create the CSE with the ownership of this node |
| 70 | node.expr = &expr; |
| 71 | *expr_ptr = make_unique<CommonSubExpression>(move(*expr_ptr), alias); |
| 72 | } else { |
| 73 | // the CSE already exists: create a CSE referring to the existing node |
| 74 | *expr_ptr = make_unique<CommonSubExpression>(node.expr, alias); |
| 75 | } |
| 76 | return; |
| 77 | } |
| 78 | // this expression only occurs once, we can't perform CSE elimination |
| 79 | // look into the children to see if we can replace them |
| 80 | ExpressionIterator::EnumerateChildren(expr, [&](unique_ptr<Expression> child) -> unique_ptr<Expression> { |
| 81 | PerformCSEReplacement(&child, expression_count); |
| 82 | return move(child); |
| 83 | }); |
| 84 | } |
| 85 | |
| 86 | void CommonSubExpressionOptimizer::(LogicalOperator &op) { |
| 87 | // first we count for each expression with children how many types it occurs |
| 88 | expression_map_t<CSENode> expression_count; |
| 89 | for (auto &expr : op.expressions) { |
| 90 | CountExpressions(*expr, expression_count); |
| 91 | } |
| 92 | // now we iterate over all the expressions and perform the actual CSE elimination |
| 93 | for (idx_t i = 0; i < op.expressions.size(); i++) { |
| 94 | PerformCSEReplacement(&op.expressions[i], expression_count); |
| 95 | } |
| 96 | } |
| 97 | |