• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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_OPTIMIZATIONS_INLINING_H
17 #define COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINING_H
18 
19 #include <string>
20 #include "optimizer/pass.h"
21 #include "optimizer/ir/inst.h"
22 #include "optimizer/ir/runtime_interface.h"
23 #include "compiler_options.h"
24 #include "utils/arena_containers.h"
25 
26 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage,-warnings-as-errors)
27 #define LOG_INLINING(level) COMPILER_LOG(level, INLINING) << GetLogIndent()
28 
29 namespace ark::compiler {
30 struct InlineContext {
31     RuntimeInterface::MethodPtr method {};
32     bool chaDevirtualize {false};
33     bool replaceToStatic {false};
34     RuntimeInterface::IntrinsicId intrinsicId {RuntimeInterface::IntrinsicId::INVALID};
35 };
36 
37 struct InlinedGraph {
38     Graph *graph {nullptr};
39     bool hasRuntimeCalls {false};
40 };
41 
42 class Inlining : public Optimization {
43 public:
44     static constexpr auto MAX_CALL_DEPTH = 20U;
45 
Inlining(Graph * graph)46     explicit Inlining(Graph *graph) : Inlining(graph, 0, 0, nullptr) {}
Inlining(Graph * graph,bool resolveWoInline)47     Inlining(Graph *graph, bool resolveWoInline) : Inlining(graph)
48     {
49         resolveWoInline_ = resolveWoInline;
50     }
51 
52     Inlining(Graph *graph, uint32_t instructionsCount, uint32_t methodsInlined,
53              const ArenaVector<RuntimeInterface::MethodPtr> *inlinedStack);
54 
55     NO_MOVE_SEMANTIC(Inlining);
56     NO_COPY_SEMANTIC(Inlining);
57     ~Inlining() override = default;
58 
59     bool RunImpl() override;
60 
IsEnable()61     bool IsEnable() const override
62     {
63         return g_options.IsCompilerInlining();
64     }
65 
GetPassName()66     const char *GetPassName() const override
67     {
68         return "Inline";
69     }
GetCurrentDepth()70     auto GetCurrentDepth() const
71     {
72         ASSERT(!inlinedStack_.empty());
73         return inlinedStack_.size() - 1;
74     }
75 
76     void InvalidateAnalyses() override;
77 
78 protected:
79     virtual void RunOptimizations() const;
80     virtual bool IsInstSuitableForInline(Inst *inst) const;
81     virtual bool TryInline(CallInst *callInst);
82     bool TryInlineWithInlineCaches(CallInst *callInst);
83     bool TryInlineExternal(CallInst *callInst, InlineContext *ctx);
84     bool TryInlineExternalAot(CallInst *callInst, InlineContext *ctx);
85 
86     Inst *GetNewDefAndCorrectDF(Inst *callInst, Inst *oldDef);
87 
88     bool Do();
89     bool DoInline(CallInst *callInst, InlineContext *ctx);
90     bool DoInlineMethod(CallInst *callInst, InlineContext *ctx);
91     bool DoInlineIntrinsic(CallInst *callInst, InlineContext *ctx);
92     bool DoInlineMonomorphic(CallInst *callInst, RuntimeInterface::ClassPtr receiver);
93     bool DoInlinePolymorphic(CallInst *callInst, ArenaVector<RuntimeInterface::ClassPtr> *receivers);
94     void CreateCompareClass(CallInst *callInst, Inst *getClsInst, RuntimeInterface::ClassPtr receiver,
95                             BasicBlock *callBb);
96     void InsertDeoptimizeInst(CallInst *callInst, BasicBlock *callBb,
97                               DeoptimizeType deoptType = DeoptimizeType::INLINE_IC);
98     void InsertCallInst(CallInst *callInst, BasicBlock *callBb, BasicBlock *retBb, Inst *phiInst);
99 
100     void UpdateDataflow(Graph *graphInl, Inst *callInst, std::variant<BasicBlock *, PhiInst *> use,
101                         Inst *newDef = nullptr);
102     void UpdateDataflowForEmptyGraph(Inst *callInst, std::variant<BasicBlock *, PhiInst *> use, BasicBlock *endBlock);
103     void UpdateParameterDataflow(Graph *graphInl, Inst *callInst);
104     void UpdateControlflow(Graph *graphInl, BasicBlock *callBb, BasicBlock *callContBb);
105     void MoveConstants(Graph *graphInl);
106 
107     template <bool CHECK_EXTERNAL, bool CHECK_INTRINSICS = false>
108     bool CheckMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx);
109     bool CheckDepthLimit(InlineContext *ctx);
110     template <bool CHECK_EXTERNAL>
111     bool CheckTooBigMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx, bool methodIsTooBig);
112     template <bool CHECK_EXTERNAL>
113     bool CheckMethodSize(const CallInst *callInst, InlineContext *ctx);
114     bool ResolveTarget(CallInst *callInst, InlineContext *ctx);
115     bool CanUseTypeInfo(ObjectTypeInfo typeInfo, RuntimeInterface::MethodPtr method);
116     void InsertChaGuard(CallInst *callInst);
117 
118     InlinedGraph BuildGraph(InlineContext *ctx, CallInst *callInst, CallInst *polyCallInst = nullptr);
119     bool CheckBytecode(CallInst *callInst, const InlineContext &ctx, bool *calleeCallRuntime);
120     bool TryBuildGraph(const InlineContext &ctx, Graph *graphInl, CallInst *callInst, CallInst *polyCallInst);
121     bool CheckLoops(bool *calleeCallRuntime, Graph *graphInl);
122     static void PropagateObjectInfo(Graph *graphInl, CallInst *callInst);
123 
124     void ProcessCallReturnInstructions(CallInst *callInst, BasicBlock *callContBb, bool hasRuntimeCalls,
125                                        bool needBarriers = false);
126     size_t CalculateInstructionsCount(Graph *graph);
127 
GetCha()128     IClassHierarchyAnalysis *GetCha()
129     {
130         return cha_;
131     }
132 
133     bool IsInlineCachesEnabled() const;
134 
GetLogIndent()135     std::string GetLogIndent() const
136     {
137         return std::string(GetCurrentDepth() * 2U, ' ');
138     }
139 
IsIntrinsic(const InlineContext * ctx)140     bool IsIntrinsic(const InlineContext *ctx) const
141     {
142         return ctx->intrinsicId != RuntimeInterface::IntrinsicId::INVALID;
143     }
144 
145     virtual bool SkipBlock(const BasicBlock *block) const;
146 
147 protected:
148     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
149     uint32_t methodsInlined_ {0};
150     uint32_t instructionsCount_ {0};
151     uint32_t instructionsLimit_ {0};
152     ArenaVector<BasicBlock *> returnBlocks_;
153     ArenaUnorderedSet<std::string> blacklist_;
154     ArenaVector<RuntimeInterface::MethodPtr> inlinedStack_;
155     // NOLINTEND(misc-non-private-member-variables-in-classes)
156 
157 private:
158     uint32_t vregsCount_ {0};
159     bool resolveWoInline_ {false};
160     IClassHierarchyAnalysis *cha_ {nullptr};
161 };
162 }  // namespace ark::compiler
163 
164 #endif  // COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINING_H
165