• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &currentInsts,
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