1 /** 2 * Copyright (c) 2023-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 PLUGINS_ETS_COMPILER_OPTIMIZER_INTEROP_JS_INTEROP_INTRINSIC_OPTIMIZATION_H_ 17 #define PLUGINS_ETS_COMPILER_OPTIMIZER_INTEROP_JS_INTEROP_INTRINSIC_OPTIMIZATION_H_ 18 19 #include "optimizer/ir/graph.h" 20 #include "optimizer/pass.h" 21 22 #include "compiler_logger.h" 23 #include "optimizer/ir/analysis.h" 24 #include "optimizer/ir/graph_visitor.h" 25 26 namespace ark::compiler { 27 // NOLINTNEXTLINE(fuchsia-multiple-inheritance) 28 class InteropIntrinsicOptimization : public Optimization, public GraphVisitor { 29 using Optimization::Optimization; 30 31 public: 32 explicit InteropIntrinsicOptimization(Graph *graph, bool trySingleScope = false) Optimization(graph)33 : Optimization(graph), 34 trySingleScope_(trySingleScope), 35 scopeObjectLimit_(g_options.GetCompilerInteropScopeObjectLimit()), 36 forbiddenLoops_(GetGraph()->GetLocalAllocator()->Adapter()), 37 blockInfo_(GetGraph()->GetVectorBlocks().size(), GetGraph()->GetLocalAllocator()->Adapter()), 38 components_(GetGraph()->GetLocalAllocator()->Adapter()), 39 currentComponentBlocks_(GetGraph()->GetLocalAllocator()->Adapter()), 40 scopeForInst_(GetGraph()->GetLocalAllocator()->Adapter()), 41 blocksToProcess_(GetGraph()->GetLocalAllocator()->Adapter()) 42 { 43 } 44 45 NO_MOVE_SEMANTIC(InteropIntrinsicOptimization); 46 NO_COPY_SEMANTIC(InteropIntrinsicOptimization); 47 ~InteropIntrinsicOptimization() override = default; 48 49 bool RunImpl() override; 50 IsEnable()51 bool IsEnable() const override 52 { 53 return g_options.IsCompilerEnableFastInterop() && g_options.IsCompilerInteropIntrinsicOptimization(); 54 } 55 GetPassName()56 const char *GetPassName() const override 57 { 58 return "InteropIntrinsicOptimization"; 59 } 60 IsApplied()61 bool IsApplied() const 62 { 63 return isApplied_; 64 } 65 GetBlocksToVisit()66 const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override 67 { 68 return GetGraph()->GetBlocksRPO(); 69 } 70 71 #include "optimizer/ir/visitor.inc" 72 73 private: 74 struct BlockInfo { 75 Inst *lastScopeStart {}; 76 int32_t dfsNumIn {DFS_NOT_VISITED}; 77 int32_t dfsNumOut {DFS_NOT_VISITED}; 78 int32_t domTreeIn {DFS_NOT_VISITED}; 79 int32_t domTreeOut {DFS_NOT_VISITED}; 80 int32_t subgraphMinNum {DFS_NOT_VISITED}; 81 int32_t subgraphMaxNum {DFS_NOT_VISITED}; 82 std::array<int32_t, 2U> blockComponent {DFS_NOT_VISITED, DFS_NOT_VISITED}; 83 int32_t maxChain {}; 84 int32_t maxDepth {}; 85 }; 86 87 struct Component { 88 int32_t parent {-1}; 89 uint32_t objectCount {}; 90 uint32_t lastUsed {}; 91 bool isForbidden {}; 92 }; 93 94 // Mechanism is similar to markers GetObjectCountIfUnused(Component & comp,uint32_t usedNumber)95 uint32_t GetObjectCountIfUnused(Component &comp, uint32_t usedNumber) 96 { 97 if (comp.lastUsed == usedNumber + 1) { 98 return 0; 99 } 100 comp.lastUsed = usedNumber + 1; 101 return comp.objectCount; 102 } 103 104 BlockInfo &GetInfo(BasicBlock *block); 105 void MergeScopesInsideBlock(BasicBlock *block); 106 bool TryCreateSingleScope(BasicBlock *bb); 107 bool TryCreateSingleScope(); 108 std::optional<uint64_t> FindForbiddenLoops(Loop *loop); 109 bool IsForbiddenLoopEntry(BasicBlock *block); 110 int32_t GetParentComponent(int32_t component); 111 void MergeComponents(int32_t first, int32_t second); 112 void UpdateStatsForMerging(Inst *inst, int32_t otherEndComponent, uint32_t *scopeSwitches, 113 uint32_t *objectsInBlockAfterMerge); 114 template <bool IS_END> 115 void IterateBlockFromBoundary(BasicBlock *block); 116 template <bool IS_END> 117 void BlockBoundaryDfs(BasicBlock *block); 118 void MergeCurrentComponentWithNeighbours(); 119 template <bool IS_END> 120 void FindComponentAndTryMerge(BasicBlock *block); 121 void MergeInterScopeRegions(); 122 123 void DfsNumbering(BasicBlock *block); 124 void CalculateReachabilityRec(BasicBlock *block); 125 template <void (InteropIntrinsicOptimization::*DFS)(BasicBlock *)> 126 void DoDfs(); 127 bool CreateScopeStartInBlock(BasicBlock *block); 128 void RemoveReachableScopeStarts(BasicBlock *block, BasicBlock *newStartBlock); 129 void HoistScopeStarts(); 130 131 void InvalidateScopesInSubgraph(BasicBlock *block); 132 void CheckGraphRec(BasicBlock *block, Inst *scopeStart); 133 void CheckGraphAndFindScopes(); 134 135 void MarkRequireRegMap(Inst *inst); 136 void TryRemoveUnwrapAndWrap(Inst *inst, Inst *input); 137 void TryRemoveUnwrapToJSValue(Inst *inst); 138 void TryRemoveIntrinsic(Inst *inst); 139 void EliminateCastPairs(); 140 141 void DomTreeDfs(BasicBlock *block); 142 void MarkPartiallyAnticipated(BasicBlock *block, BasicBlock *stopBlock); 143 void CalculateDownSafe(BasicBlock *block); 144 void ReplaceInst(Inst *inst, Inst **newInst, Inst *insertAfter); 145 bool CanHoistTo(BasicBlock *block); 146 void HoistAndEliminateRec(BasicBlock *block, const BlockInfo &startInfo, Inst **newInst, Inst *insertAfter); 147 Inst *FindEliminationCandidate(BasicBlock *block); 148 void HoistAndEliminate(BasicBlock *startBlock, Inst *boundaryInst); 149 void DoRedundancyElimination(Inst *scopeStart, InstVector &insts); 150 void SaveSiblingForElimination(Inst *sibling, ArenaMap<Inst *, InstVector> ¤tInsts, 151 RuntimeInterface::IntrinsicId id, Marker processed); 152 void RedundancyElimination(); 153 154 private: 155 static constexpr uint64_t MAX_LOOP_ITERATIONS = 10; 156 static constexpr int32_t DFS_NOT_VISITED = -1; 157 static constexpr int32_t DFS_INVALIDATED = -2; 158 159 bool trySingleScope_; 160 uint32_t scopeObjectLimit_; 161 Marker startDfs_ {}; 162 Marker canHoistTo_ {}; 163 Marker visited_ {}; 164 Marker instAnticipated_ {}; 165 Marker scopeStartInvalidated_ {}; 166 Marker eliminationCandidate_ {}; 167 Marker requireRegMap_ {}; 168 bool hasScopes_ {false}; 169 bool isApplied_ {false}; 170 int32_t dfsNum_ {}; 171 int32_t domTreeNum_ {}; 172 int32_t currentComponent_ {}; 173 uint32_t objectsInScopeAfterMerge_ {}; 174 bool canMerge_ {}; 175 bool objectLimitHit_ {false}; 176 ArenaUnorderedSet<Loop *> forbiddenLoops_; 177 ArenaVector<BlockInfo> blockInfo_; 178 ArenaVector<Component> components_; 179 ArenaVector<BasicBlock *> currentComponentBlocks_; 180 ArenaUnorderedMap<Inst *, Inst *> scopeForInst_; 181 ArenaVector<BasicBlock *> blocksToProcess_; 182 SaveStateBridgesBuilder ssb_; 183 }; 184 } // namespace ark::compiler 185 186 #endif // PLUGINS_ETS_COMPILER_OPTIMIZER_INTEROP_JS_INTEROP_INTRINSIC_OPTIMIZATION_H_ 187