1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef COMPILER_OPTIMIZER_PASS_MANAGER_H
17#define COMPILER_OPTIMIZER_PASS_MANAGER_H
18
19#include <tuple>
20#include "compiler_options.h"
21#include "pass.h"
22#include "utils/bit_field.h"
23#include "utils/arena_containers.h"
24#include "pass_manager_statistics.h"
25
26namespace panda::compiler {
27class Graph;
28class Pass;
29class Analysis;
30class LivenessAnalyzer;
31class LoopAnalyzer;
32class DominatorsTree;
33class Rpo;
34class LinearOrder;
35// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
36
37namespace details {
38template <typename... Types>
39class PassTypeList {
40public:
41    using IdentifierType = size_t;
42    using TupleType = std::tuple<std::decay_t<Types>...>;
43
44    template <typename T>
45    static constexpr bool HasType()
46    {
47        return std::disjunction_v<std::is_same<T, Types>...>;
48    }
49
50    template <typename T, typename... Args>
51    static ArenaVector<T> Instantiate(ArenaAllocator *allocator, Args &&... args)
52    {
53        ArenaVector<T> vec(allocator->Adapter());
54        vec.reserve(sizeof...(Types));
55        ((vec.push_back(allocator->New<Types>((std::forward<Args>(args))...))), ...);
56        return vec;
57    }
58
59    template <typename Type, std::size_t... Indexes>
60    static constexpr size_t GetIndex(std::index_sequence<Indexes... /* unused */>)
61    {
62        static_assert(HasType<Type>());
63        return (0 + ... +
64                (std::is_same_v<Type, std::tuple_element_t<Indexes, TupleType>> ? size_t(Indexes) : size_t {}));
65    }
66
67    template <typename Type>
68    static constexpr IdentifierType ID = GetIndex<std::decay_t<Type>>(std::index_sequence_for<Types...> {});
69    static constexpr size_t SIZE = sizeof...(Types);
70};
71
72using PredefinedAnalyses =
73    PassTypeList<LivenessAnalyzer, LoopAnalyzer, DominatorsTree, Rpo, LinearOrder>;
74}  // namespace details
75
76class PassManager {
77public:
78    PassManager(Graph *graph, PassManager *parent_pm);
79
80    ArenaAllocator *GetAllocator();
81    ArenaAllocator *GetLocalAllocator();
82
83    bool RunPass(Pass *pass, size_t local_mem_size_before_pass);
84
85    template <typename T, typename... Args>
86    bool RunPass(Args... args)
87    {
88        auto local_mem_size_before = GetLocalAllocator()->GetAllocatedSize();
89        bool res = false;
90        // NOLINTNEXTLINE(readability-braces-around-statements)
91        if constexpr (details::PredefinedAnalyses::HasType<T>()) {
92            static_assert(sizeof...(Args) == 0);
93            res = RunPass(ANALYSES[details::PredefinedAnalyses::ID<T>], local_mem_size_before);
94            // NOLINTNEXTLINE(readability-misleading-indentation)
95        } else {
96            T pass(graph_, std::forward<Args>(args)...);
97            res = RunPass(&pass, local_mem_size_before);
98        }
99        if (!IsCheckMode()) {
100            if (options.IsCompilerResetLocalAllocator()) {
101                ASSERT(GetLocalAllocator() != GetAllocator());
102                GetLocalAllocator()->Resize(local_mem_size_before);
103            }
104        }
105        return res;
106    }
107
108    template <typename T>
109    T &GetAnalysis()
110    {
111        static_assert(std::is_base_of_v<Analysis, std::decay_t<T>>);
112        return *static_cast<T *>(ANALYSES[details::PredefinedAnalyses::ID<T>]);
113    }
114    std::string GetFileName(const char *pass_name = nullptr, const std::string &suffix = ".cfg");
115    void DumpGraph(const char *pass_name);
116    void DumpLifeIntervals(const char *pass_name);
117
118    Graph *GetGraph()
119    {
120        return graph_;
121    }
122
123    void Finalize() const;
124
125    PassManagerStatistics *GetStatistics()
126    {
127        return stats_;
128    }
129
130    void SetCheckMode(bool v)
131    {
132        check_mode_ = v;
133    }
134
135    bool IsCheckMode() const
136    {
137        return check_mode_;
138    }
139
140    // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
141    size_t GetExecutionCounter() const
142    {
143        return execution_counter;
144    }
145
146    // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
147    void StartExecution()
148    {
149        execution_counter++;
150    }
151
152private:
153    Graph *graph_ {nullptr};
154    ArenaVector<Optimization *> optimizations_;
155    const ArenaVector<Analysis *> ANALYSES;
156
157    PassManagerStatistics *stats_ {nullptr};
158    inline static size_t execution_counter {0};
159
160    // Whether passes are run by checker.
161    bool check_mode_ {false};
162
163    bool first_execution_ {true};
164};
165}  // namespace panda::compiler
166
167#endif  // COMPILER_OPTIMIZER_PASS_MANAGER_H
168