1 /* 2 * Copyright (c) 2021-2023 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 panda::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 static constexpr size_t SMALL_METHOD_MAX_SIZE = 5; 44 45 public: Inlining(Graph * graph)46 explicit Inlining(Graph *graph) : Inlining(graph, 0, 0, 0) {} 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 inlineDepth, uint32_t methodsInlined); 53 54 NO_MOVE_SEMANTIC(Inlining); 55 NO_COPY_SEMANTIC(Inlining); 56 ~Inlining() override = default; 57 58 bool RunImpl() override; 59 IsEnable()60 bool IsEnable() const override 61 { 62 return g_options.IsCompilerInlining(); 63 } 64 GetPassName()65 const char *GetPassName() const override 66 { 67 return "Inline"; 68 } 69 70 void InvalidateAnalyses() override; 71 72 protected: 73 virtual void RunOptimizations() const; 74 virtual bool IsInstSuitableForInline(Inst *inst) const; 75 virtual bool TryInline(CallInst *callInst); 76 bool TryInlineWithInlineCaches(CallInst *callInst); 77 bool TryInlineExternal(CallInst *callInst, InlineContext *ctx); 78 bool TryInlineExternalAot(CallInst *callInst, InlineContext *ctx); 79 80 Inst *GetNewDefAndCorrectDF(Inst *callInst, Inst *oldDef); 81 82 bool Do(); 83 bool DoInline(CallInst *callInst, InlineContext *ctx); 84 bool DoInlineMethod(CallInst *callInst, InlineContext *ctx); 85 bool DoInlineIntrinsic(CallInst *callInst, InlineContext *ctx); 86 bool DoInlineMonomorphic(CallInst *callInst, RuntimeInterface::ClassPtr receiver); 87 bool DoInlinePolymorphic(CallInst *callInst, ArenaVector<RuntimeInterface::ClassPtr> *receivers); 88 void CreateCompareClass(CallInst *callInst, Inst *getClsInst, RuntimeInterface::ClassPtr receiver, 89 BasicBlock *callBb); 90 void InsertDeoptimizeInst(CallInst *callInst, BasicBlock *callBb, 91 DeoptimizeType deoptType = DeoptimizeType::INLINE_IC); 92 void InsertCallInst(CallInst *callInst, BasicBlock *callBb, BasicBlock *retBb, Inst *phiInst); 93 94 void UpdateDataflow(Graph *graphInl, Inst *callInst, std::variant<BasicBlock *, PhiInst *> use, 95 Inst *newDef = nullptr); 96 void UpdateDataflowForEmptyGraph(Inst *callInst, std::variant<BasicBlock *, PhiInst *> use, BasicBlock *endBlock); 97 void UpdateParameterDataflow(Graph *graphInl, Inst *callInst); 98 void UpdateControlflow(Graph *graphInl, BasicBlock *callBb, BasicBlock *callContBb); 99 void MoveConstants(Graph *graphInl); 100 101 template <bool CHECK_EXTERNAL, bool CHECK_INTRINSICS = false> 102 bool CheckMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx); 103 template <bool CHECK_EXTERNAL> 104 bool CheckTooBigMethodCanBeInlined(const CallInst *callInst, InlineContext *ctx, bool methodIsTooBig); 105 bool ResolveTarget(CallInst *callInst, InlineContext *ctx); 106 bool CanUseTypeInfo(ObjectTypeInfo typeInfo, RuntimeInterface::MethodPtr method); 107 void InsertChaGuard(CallInst *callInst); 108 109 InlinedGraph BuildGraph(InlineContext *ctx, CallInst *callInst, CallInst *polyCallInst = nullptr); 110 bool CheckBytecode(CallInst *callInst, const InlineContext &ctx, bool *calleeCallRuntime); 111 bool CheckInstructionLimit(CallInst *callInst, InlineContext *ctx, size_t inlinedInstsCount); 112 bool TryBuildGraph(const InlineContext &ctx, Graph *graphInl, CallInst *callInst, CallInst *polyCallInst); 113 bool CheckLoops(bool *calleeCallRuntime, Graph *graphInl); 114 static void PropagateObjectInfo(Graph *graphInl, CallInst *callInst); 115 116 void ProcessCallReturnInstructions(CallInst *callInst, BasicBlock *callContBb, bool hasRuntimeCalls, 117 bool needBarriers = false); 118 size_t CalculateInstructionsCount(Graph *graph); 119 GetCha()120 IClassHierarchyAnalysis *GetCha() 121 { 122 return cha_; 123 } 124 125 bool IsInlineCachesEnabled() const; 126 GetLogIndent()127 std::string GetLogIndent() const 128 { 129 return std::string(depth_ * 2U, ' '); 130 } 131 IsIntrinsic(const InlineContext * ctx)132 bool IsIntrinsic(const InlineContext *ctx) const 133 { 134 return ctx->intrinsicId != RuntimeInterface::IntrinsicId::INVALID; 135 } 136 137 virtual bool SkipBlock(const BasicBlock *block) const; 138 139 protected: 140 // NOLINTBEGIN(misc-non-private-member-variables-in-classes) 141 uint32_t depth_ {0}; 142 uint32_t methodsInlined_ {0}; 143 uint32_t instructionsCount_ {0}; 144 uint32_t instructionsLimit_ {0}; 145 ArenaVector<BasicBlock *> returnBlocks_; 146 ArenaUnorderedSet<std::string> blacklist_; 147 // NOLINTEND(misc-non-private-member-variables-in-classes) 148 149 private: 150 uint32_t vregsCount_ {0}; 151 bool resolveWoInline_ {false}; 152 IClassHierarchyAnalysis *cha_ {nullptr}; 153 }; 154 } // namespace panda::compiler 155 156 #endif // COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINING_H 157