aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/core/common_opt/yql_co.h
blob: 027fb26f0a2d93d51e4fd1306e49668e62a17a8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#pragma once

#include <yql/essentials/core/yql_type_annotation.h>
#include <yql/essentials/core/expr_nodes/yql_expr_nodes.h>

#include <string_view>

namespace NYql {

struct TOptimizeContext {
    TTypeAnnotationContext* Types = nullptr;
    TParentsMap* ParentsMap = nullptr;

    const TExprNode* GetParentIfSingle(const TExprNode& node) const {
        YQL_ENSURE(ParentsMap);

        const auto it = ParentsMap->find(&node);
        YQL_ENSURE(it != ParentsMap->cend());

        auto& parents = it->second;
        YQL_ENSURE(!parents.empty());
        if (parents.size() > 1) {
            return nullptr;
        }

        size_t usageCount = 0;
        for (const auto& child : (*parents.cbegin())->ChildrenList()) {
            if (child.Get() == &node && ++usageCount > 1) {
                return nullptr;
            }
        }

        YQL_ENSURE(usageCount == 1);
        return *parents.cbegin();
    }

    bool IsSingleUsage(const TExprNode& node) const {
        return bool(GetParentIfSingle(node));
    }

    bool IsSingleUsage(const NNodes::TExprBase& node) const {
        return IsSingleUsage(node.Ref());
    }

    bool HasParent(const TExprNode& node) const {
        YQL_ENSURE(ParentsMap);
        return ParentsMap->contains(&node);
    }

    bool IsPersistentNode(const TExprNode& node) const {
        if (Types) {
            for (auto& source: Types->DataSources) {
                if (source->IsPersistent(node)) {
                    return true;
                }
            }

            for (auto& sink: Types->DataSinks) {
                if (sink->IsPersistent(node)) {
                    return true;
                }
            }
        }

        return false;
    }

    bool IsPersistentNode(const NNodes::TExprBase& node) const {
        return IsPersistentNode(node.Ref());
    }
};

using TCallableOptimizerExt = std::function<TExprNode::TPtr (const TExprNode::TPtr&, TExprContext&, TOptimizeContext&)>;
using TCallableOptimizerMap = std::unordered_map<std::string_view, TCallableOptimizerExt>;
using TFinalizingOptimizerExt = std::function<bool (const TExprNode::TPtr&, TNodeOnNodeOwnedMap&, TExprContext&, TOptimizeContext&)>;
using TFinalizingOptimizerMap = std::unordered_map<std::string_view, TFinalizingOptimizerExt>;

struct TCoCallableRules {
    enum {
        SIMPLE_STEP_1,
        SIMPLE_STEP_2,
        SIMPLE_STEP_3,
        SIMPLE_STEPS
    };

    enum {
        FLOW_STEP_1,
        FLOW_STEP_2,
        FLOW_STEPS
    };

    // rules that don't make a flow fork - e.g. False || x -> x
    TCallableOptimizerMap SimpleCallables[SIMPLE_STEPS];
    // rules that make a flow fork - Join pushdown if Join has multiple usage
    TCallableOptimizerMap FlowCallables[FLOW_STEPS];

    TFinalizingOptimizerMap Finalizers;

    // rules to be applied before execution
    TCallableOptimizerMap FinalCallables;

    TCoCallableRules();
    static const TCoCallableRules& Instance();
};

void RegisterCoSimpleCallables1(TCallableOptimizerMap& map);
void RegisterCoSimpleCallables2(TCallableOptimizerMap& map);
void RegisterCoSimpleCallables3(TCallableOptimizerMap& map);
void RegisterCoFlowCallables1(TCallableOptimizerMap& map);
void RegisterCoFlowCallables2(TCallableOptimizerMap& map);
void RegisterCoFinalizers(TFinalizingOptimizerMap& map);
void RegisterCoFinalCallables(TCallableOptimizerMap& map);

}