• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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     using InstPair = std::pair<Inst *, Inst *>;
46     using InstTriple = std::tuple<Inst *, Inst *, Inst *>;
47     using BasicBlockPair = std::pair<BasicBlock *, BasicBlock *>;
48     using FlagPair = std::pair<bool *, bool *>;
49 
Inlining(Graph * graph)50     explicit Inlining(Graph *graph) : Inlining(graph, 0, 0, nullptr) {}
Inlining(Graph * graph,bool resolveWoInline)51     Inlining(Graph *graph, bool resolveWoInline) : Inlining(graph)
52     {
53         resolveWoInline_ = resolveWoInline;
54     }
55 
56     Inlining(Graph *graph, uint32_t instructionsCount, uint32_t methodsInlined,
57              const ArenaVector<RuntimeInterface::MethodPtr> *inlinedStack);
58 
59     NO_MOVE_SEMANTIC(Inlining);
60     NO_COPY_SEMANTIC(Inlining);
61     ~Inlining() override = default;
62 
63     bool RunImpl() override;
64 
IsEnable()65     bool IsEnable() const override
66     {
67         return g_options.IsCompilerInlining();
68     }
69 
GetPassName()70     const char *GetPassName() const override
71     {
72         return "Inline";
73     }
GetCurrentDepth()74     auto GetCurrentDepth() const
75     {
76         ASSERT(!inlinedStack_.empty());
77         return inlinedStack_.size() - 1;
78     }
79 
80     void InvalidateAnalyses() override;
81 
82 protected:
83     virtual void RunOptimizations() const;
84     virtual bool IsInstSuitableForInline(Inst *inst) const;
85     virtual bool TryInline(CallInst *callInst);
86     bool TryInlineWithInlineCaches(CallInst *callInst);
87     bool TryInlineExternal(CallInst *callInst, InlineContext *ctx);
88     bool TryInlineExternalAot(CallInst *callInst, InlineContext *ctx);
89 
90     Inst *GetNewDefAndCorrectDF(Inst *callInst, Inst *oldDef);
91 
92     bool Do();
93     bool DoInline(CallInst *callInst, InlineContext *ctx);
94     bool DoInlineMethod(CallInst *callInst, InlineContext *ctx);
95     bool DoInlineIntrinsic(CallInst *callInst, InlineContext *ctx);
96     bool DoInlineIntrinsicByExpansion(CallInst *callInst, InlineContext *ctx);
97     bool DoInlineIntrinsicByEncoding(CallInst *callInst, InlineContext *ctx);
98 #include "intrinsics_inlining_expansion.inl.h"
99 
100     bool DoInlineMonomorphic(CallInst *callInst, RuntimeInterface::ClassPtr receiver);
101     bool DoInlinePolymorphic(CallInst *callInst, ArenaVector<RuntimeInterface::ClassPtr> *receivers);
102     SaveStateInst *GetOrCloneSaveState(CallInst *callInst, BasicBlock *callBb);
103     void CreateCompareClass(CallInst *callInst, Inst *getClsInst, RuntimeInterface::ClassPtr receiver,
104                             BasicBlock *callBb);
105     BasicBlockPair MakeCallBbs(InstPair insts, BasicBlockPair bbs, [[maybe_unused]] PhiInst **phiInst,
106                                [[maybe_unused]] size_t receiversSize);
107     void InlineReceiver(InstTriple insts, BasicBlockPair bbs, FlagPair flags, size_t receiversSize,
108                         InlinedGraph inlGraph);
109     bool FinalizeInlineReceiver(InstTriple insts, BasicBlockPair bbs, FlagPair flags, bool needToDeoptimize);
110     void InsertDeoptimizeInst(CallInst *callInst, BasicBlock *callBb,
111                               DeoptimizeType deoptType = DeoptimizeType::INLINE_IC);
112     void InsertCallInst(CallInst *callInst, BasicBlock *callBb, BasicBlock *retBb, Inst *phiInst);
113 
114     void UpdateDataflow(Graph *graphInl, Inst *callInst, std::variant<BasicBlock *, PhiInst *> use,
115                         Inst *newDef = nullptr);
116     void UpdateDataflowForEmptyGraph(Inst *callInst, std::variant<BasicBlock *, PhiInst *> use, BasicBlock *endBlock);
117     void UpdateParameterDataflow(Graph *graphInl, Inst *callInst);
118     void UpdateControlflow(Graph *graphInl, BasicBlock *callBb, BasicBlock *callContBb);
119     void MoveConstants(Graph *graphInl);
120 
121     template <bool CHECK_EXTERNAL, bool CHECK_INTRINSICS = false>
122     bool CheckMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx);
123     bool CheckDepthLimit(InlineContext *ctx);
124     template <bool CHECK_EXTERNAL>
125     bool CheckTooBigMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx, bool methodIsTooBig);
126     template <bool CHECK_EXTERNAL>
127     bool CheckMethodSize(const CallInst *callInst, InlineContext *ctx);
128     bool ResolveTarget(CallInst *callInst, InlineContext *ctx);
129     bool CanUseTypeInfo(ObjectTypeInfo typeInfo, RuntimeInterface::MethodPtr method);
130     void InsertChaGuard(CallInst *callInst, InlineContext *ctx);
131 
132     InlinedGraph BuildGraph(InlineContext *ctx, CallInst *callInst, CallInst *polyCallInst = nullptr);
133     bool CheckBytecode(CallInst *callInst, const InlineContext &ctx, bool *calleeCallRuntime);
134     bool TryBuildGraph(const InlineContext &ctx, Graph *graphInl, CallInst *callInst, CallInst *polyCallInst);
135     bool CheckLoops(bool *calleeCallRuntime, Graph *graphInl);
136     static void PropagateObjectInfo(Graph *graphInl, CallInst *callInst);
137 
138     void ProcessCallReturnInstructions(CallInst *callInst, BasicBlock *callContBb, bool hasRuntimeCalls,
139                                        bool needBarriers = false);
140     size_t CalculateInstructionsCount(Graph *graph);
141 
GetCha()142     IClassHierarchyAnalysis *GetCha()
143     {
144         return cha_;
145     }
146 
147     bool IsInlineCachesEnabled() const;
148 
GetLogIndent()149     std::string GetLogIndent() const
150     {
151         return std::string(GetCurrentDepth() * 2U, ' ');
152     }
153 
IsIntrinsic(const InlineContext * ctx)154     bool IsIntrinsic(const InlineContext *ctx) const
155     {
156         return ctx->intrinsicId != RuntimeInterface::IntrinsicId::INVALID;
157     }
158 
159     virtual bool SkipBlock(const BasicBlock *block) const;
160 
161 protected:
162     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
163     uint32_t methodsInlined_ {0};
164     uint32_t instructionsCount_ {0};
165     uint32_t instructionsLimit_ {0};
166     ArenaVector<BasicBlock *> returnBlocks_;
167     ArenaUnorderedSet<std::string> blacklist_;
168     ArenaVector<RuntimeInterface::MethodPtr> inlinedStack_;
169     // NOLINTEND(misc-non-private-member-variables-in-classes)
170 
171 private:
172     uint32_t vregsCount_ {0};
173     bool resolveWoInline_ {false};
174     IClassHierarchyAnalysis *cha_ {nullptr};
175 };
176 }  // namespace ark::compiler
177 
178 #endif  // COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINING_H
179