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