• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "ecmascript/compiler/scheduler.h"
17 #include <cmath>
18 #include <stack>
19 #include "ecmascript/compiler/gate_accessor.h"
20 #include "ecmascript/compiler/verifier.h"
21 
22 namespace panda::ecmascript::kungfu {
CalculateDominatorTree(const Circuit * circuit,std::vector<GateRef> & bbGatesList,std::unordered_map<GateRef,size_t> & bbGatesAddrToIdx,std::vector<size_t> & immDom)23 void Scheduler::CalculateDominatorTree(const Circuit *circuit,
24                                        std::vector<GateRef>& bbGatesList,
25                                        std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
26                                        std::vector<size_t> &immDom)
27 {
28     GateAccessor acc(const_cast<Circuit*>(circuit));
29     std::unordered_map<GateRef, size_t> dfsTimestamp;
30     std::unordered_map<GateRef, size_t> dfsFatherIdx;
31     circuit->AdvanceTime();
32     {
33         size_t timestamp = 0;
34         std::deque<GateRef> pendingList;
35         auto startGate = acc.GetStateRoot();
36         acc.SetMark(startGate, MarkCode::VISITED);
37         pendingList.push_back(startGate);
38         while (!pendingList.empty()) {
39             auto curGate = pendingList.back();
40             dfsTimestamp[curGate] = timestamp++;
41             pendingList.pop_back();
42             bbGatesList.push_back(curGate);
43             if (acc.GetOpCode(curGate) != OpCode::LOOP_BACK) {
44                 auto uses = acc.Uses(curGate);
45                 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
46                     if (useIt.GetIndex() < acc.GetStateCount(*useIt) &&
47                         acc.IsState(*useIt) && acc.GetMark(*useIt) == MarkCode::NO_MARK) {
48                         acc.SetMark(*useIt, MarkCode::VISITED);
49                         pendingList.push_back(*useIt);
50                         dfsFatherIdx[*useIt] = dfsTimestamp[curGate];
51                     }
52                 }
53             }
54         }
55         for (size_t idx = 0; idx < bbGatesList.size(); idx++) {
56             bbGatesAddrToIdx[bbGatesList[idx]] = idx;
57         }
58     }
59     immDom.resize(bbGatesList.size());
60     std::vector<size_t> semiDom(bbGatesList.size());
61     std::vector<std::vector<size_t> > semiDomTree(bbGatesList.size());
62     {
63         std::vector<size_t> parent(bbGatesList.size());
64         std::iota(parent.begin(), parent.end(), 0);
65         std::vector<size_t> minIdx(bbGatesList.size());
66         std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
67             size_t pIdx = parent[idx];
68             if (pIdx == idx) {
69                 return idx;
70             }
71             size_t unionFindSetRoot = unionFind(pIdx);
72             if (semiDom[minIdx[idx]] > semiDom[minIdx[pIdx]]) {
73                 minIdx[idx] = minIdx[pIdx];
74             }
75             return parent[idx] = unionFindSetRoot;
76         };
77         auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
78             size_t parentFatherIdx = unionFind(fatherIdx);
79             size_t parentSonIdx = unionFind(sonIdx);
80             parent[parentSonIdx] = parentFatherIdx;
81         };
82         std::iota(semiDom.begin(), semiDom.end(), 0);
83         semiDom[0] = semiDom.size();
84         for (size_t idx = bbGatesList.size() - 1; idx >= 1; idx--) {
85             std::vector<GateRef> preGates;
86             acc.GetInStates(bbGatesList[idx], preGates);
87             for (const auto &predGate : preGates) {
88                 if (bbGatesAddrToIdx.count(predGate) > 0) {
89                     size_t preGateIdx = bbGatesAddrToIdx[predGate];
90                     if (preGateIdx < idx) {
91                         semiDom[idx] = std::min(semiDom[idx], preGateIdx);
92                     } else {
93                         unionFind(preGateIdx);
94                         semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[preGateIdx]]);
95                     }
96                 }
97             }
98             for (const auto &succDomIdx : semiDomTree[idx]) {
99                 unionFind(succDomIdx);
100                 if (idx == semiDom[minIdx[succDomIdx]]) {
101                     immDom[succDomIdx] = idx;
102                 } else {
103                     immDom[succDomIdx] = minIdx[succDomIdx];
104                 }
105             }
106             minIdx[idx] = idx;
107             merge(dfsFatherIdx[bbGatesList[idx]], idx);
108             semiDomTree[semiDom[idx]].push_back(idx);
109         }
110         for (size_t idx = 1; idx < bbGatesList.size(); idx++) {
111             if (immDom[idx] != semiDom[idx]) {
112                 immDom[idx] = immDom[immDom[idx]];
113             }
114         }
115         semiDom[0] = 0;
116     }
117 }
118 
Run(const Circuit * circuit,ControlFlowGraph & result,const std::string & methodName,bool enableLog)119 void Scheduler::Run(const Circuit *circuit, ControlFlowGraph &result,
120                     [[maybe_unused]] const std::string& methodName, [[maybe_unused]] bool enableLog)
121 {
122     GateAccessor acc(const_cast<Circuit*>(circuit));
123     std::vector<GateRef> bbGatesList;
124     std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
125     std::vector<size_t> immDom;
126     Scheduler::CalculateDominatorTree(circuit, bbGatesList, bbGatesAddrToIdx, immDom);
127     ASSERT(result.size() == 0);
128     result.resize(bbGatesList.size());
129     for (size_t idx = 0; idx < bbGatesList.size(); idx++) {
130         result[idx].push_back(bbGatesList[idx]);
131     }
132     // assuming CFG is always reducible
133     std::vector<std::vector<size_t>> sonList(result.size());
134     for (size_t idx = 1; idx < immDom.size(); idx++) {
135         sonList[immDom[idx]].push_back(idx);
136     }
137     const size_t sizeLog = std::ceil(std::log2(static_cast<double>(result.size())) + 1);
138     std::vector<size_t> timeIn(result.size());
139     std::vector<size_t> timeOut(result.size());
140     std::vector<std::vector<size_t>> jumpUp;
141     jumpUp.assign(result.size(), std::vector<size_t>(sizeLog + 1));
142     {
143         size_t timestamp = 0;
144         struct DFSState {
145             size_t cur;
146             std::vector<size_t> &succList;
147             size_t idx;
148         };
149         std::stack<DFSState> dfsStack;
150         size_t root = 0;
151         dfsStack.push({root, sonList[root], 0});
152         timeIn[root] = timestamp++;
153         jumpUp[root][0] = root;
154         for (size_t stepSize = 1; stepSize <= sizeLog; stepSize++) {
155             auto jumpUpHalf = jumpUp[root][stepSize - 1];
156             jumpUp[root][stepSize] = jumpUp[jumpUpHalf][stepSize - 1];
157         }
158         while (!dfsStack.empty()) {
159             auto &curState = dfsStack.top();
160             auto &cur = curState.cur;
161             auto &succList = curState.succList;
162             auto &idx = curState.idx;
163             if (idx == succList.size()) {
164                 timeOut[cur] = timestamp++;
165                 dfsStack.pop();
166                 continue;
167             }
168             const auto &succ = succList[idx];
169             dfsStack.push({succ, sonList[succ], 0});
170             timeIn[succ] = timestamp++;
171             jumpUp[succ][0] = cur;
172             for (size_t stepSize = 1; stepSize <= sizeLog; stepSize++) {
173                 auto jumpUpHalf = jumpUp[succ][stepSize - 1];
174                 jumpUp[succ][stepSize] = jumpUp[jumpUpHalf][stepSize - 1];
175             }
176             idx++;
177         }
178     }
179     auto isAncestor = [&](size_t nodeA, size_t nodeB) -> bool {
180         return (timeIn[nodeA] <= timeIn[nodeB]) && (timeOut[nodeA] >= timeOut[nodeB]);
181     };
182     auto lowestCommonAncestor = [&](size_t nodeA, size_t nodeB) -> size_t {
183         if (isAncestor(nodeA, nodeB)) {
184             return nodeA;
185         }
186         if (isAncestor(nodeB, nodeA)) {
187             return nodeB;
188         }
189         for (size_t stepSize = sizeLog + 1; stepSize > 0; stepSize--) {
190             if (!isAncestor(jumpUp[nodeA][stepSize - 1], nodeB)) {
191                 nodeA = jumpUp[nodeA][stepSize - 1];
192             }
193         }
194         return jumpUp[nodeA][0];
195     };
196     {
197         std::vector<GateRef> order;
198         std::unordered_map<GateRef, size_t> lowerBound;
199         Scheduler::CalculateSchedulingLowerBound(circuit, bbGatesAddrToIdx, lowestCommonAncestor, lowerBound, &order);
200         for (const auto &schedulableGate : order) {
201             result[lowerBound.at(schedulableGate)].push_back(schedulableGate);
202         }
203         std::vector<GateRef> argList;
204         acc.GetOuts(acc.GetArgRoot(), argList);
205         std::sort(argList.begin(), argList.end(), [&](const GateRef &lhs, const GateRef &rhs) -> bool {
206             return acc.TryGetValue(lhs) > acc.TryGetValue(rhs);
207         });
208         for (const auto &arg : argList) {
209             result.front().push_back(arg);
210         }
211         for (const auto &bbGate : bbGatesList) {
212             auto uses = acc.Uses(bbGate);
213             for (auto i = uses.begin(); i != uses.end(); i++) {
214                 GateRef succGate = *i;
215                 if (acc.IsFixed(succGate)) {
216                     result[bbGatesAddrToIdx.at(acc.GetIn(succGate, 0))].push_back(succGate);
217                 }
218             }
219         }
220     }
221     if (enableLog) {
222         Print(&result, circuit);
223     }
224 }
225 
CalculateSchedulingUpperBound(const Circuit * circuit,const std::unordered_map<GateRef,size_t> & bbGatesAddrToIdx,const std::function<bool (size_t,size_t)> & isAncestor,const std::vector<GateRef> & schedulableGatesList,std::unordered_map<GateRef,size_t> & upperBound)226 bool Scheduler::CalculateSchedulingUpperBound(const Circuit *circuit,
227                                               const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
228                                               const std::function<bool(size_t, size_t)> &isAncestor,
229                                               const std::vector<GateRef> &schedulableGatesList,
230                                               std::unordered_map<GateRef, size_t> &upperBound)
231 {
232     GateAccessor acc(const_cast<Circuit*>(circuit));
233     struct DFSState {
234         GateRef curGate = Circuit::NullGate();
235         std::vector<GateRef> predGates;
236         size_t idx = 0;
237         size_t curUpperBound = 0;
238     };
239     DFSState emptyState = {Circuit::NullGate(), std::vector<GateRef>(0), 0, 0};
240     bool getReturn = false;
241     std::optional<size_t> returnValue = 0;
242     std::stack<DFSState> dfsStack;
243     auto CheckUnschedulable = [&](GateRef gate) -> void {
244         if (upperBound.count(gate) > 0) {
245             returnValue = upperBound[gate];
246             getReturn = true;
247         } else if (acc.IsProlog(gate) || acc.IsRoot(gate)) {
248             returnValue = 0;
249             getReturn = true;
250         } else if (acc.IsFixed(gate)) {
251             returnValue = bbGatesAddrToIdx.at(acc.GetIn(gate, 0));
252             getReturn = true;
253         } else if (acc.IsState(gate)) {
254             returnValue = bbGatesAddrToIdx.at(gate);
255             getReturn = true;
256         }
257         // then gate is schedulable
258     };
259     for (const auto &schedulableGate : schedulableGatesList) {
260         if (upperBound.count(schedulableGate) != 0) {
261             continue;
262         }
263         getReturn = false;
264         CheckUnschedulable(schedulableGate);
265         if (getReturn) {
266             continue;
267         }
268         dfsStack.push(emptyState);
269         auto &rootState = dfsStack.top();
270         auto &rootPredGates = rootState.predGates;
271         rootState.curGate = schedulableGate;
272         acc.GetIns(schedulableGate, rootPredGates);
273         while (!dfsStack.empty()) {
274             auto &curState = dfsStack.top();
275             auto &curGate = curState.curGate;
276             const auto &predGates = curState.predGates;
277             auto &idx = curState.idx;
278             auto &curUpperBound = curState.curUpperBound;
279             if (idx == predGates.size()) {
280                 upperBound[curGate] = curUpperBound;
281                 returnValue = curUpperBound;
282                 dfsStack.pop();
283                 getReturn = true;
284                 continue;
285             }
286             if (getReturn) {
287                 if (!returnValue.has_value()) {
288                     break;
289                 }
290                 auto predUpperBound = returnValue.value();
291                 if (!isAncestor(curUpperBound, predUpperBound) && !isAncestor(predUpperBound, curUpperBound)) {
292                     PrintUpperBoundError(circuit, curGate, predUpperBound, curUpperBound);
293                     returnValue = std::nullopt;
294                     break;
295                 }
296                 if (isAncestor(curUpperBound, predUpperBound)) {
297                     curUpperBound = predUpperBound;
298                 }
299                 getReturn = false;
300                 idx++;
301             } else {
302                 const auto &predGate = predGates[idx];
303                 CheckUnschedulable(predGate);
304                 if (getReturn) {
305                     continue;
306                 }
307                 dfsStack.push(emptyState);
308                 auto &newState = dfsStack.top();
309                 auto &newPredGates = newState.predGates;
310                 newState.curGate = predGate;
311                 acc.GetIns(predGate, newPredGates);
312             }
313         }
314         if (!returnValue.has_value()) {
315             return false;
316         }
317     }
318     return true;
319 }
320 
PrintUpperBoundError(const Circuit * circuit,GateRef curGate,GateRef predUpperBound,GateRef curUpperBound)321 void Scheduler::PrintUpperBoundError(const Circuit *circuit, GateRef curGate,
322                                      GateRef predUpperBound, GateRef curUpperBound)
323 {
324     GateAccessor ac(const_cast<Circuit*>(circuit));
325     LOG_COMPILER(ERROR) << "[Verifier][Error] Scheduling upper bound of gate (id="
326                         << ac.GetId(curGate)
327                         << ") does not exist, current-upper-bound = "
328                         << curUpperBound << ", pred-upper-bound = "
329                         << predUpperBound << ", there is no dominator relationship between them.";
330 }
331 
CalculateFixedGatesList(const Circuit * circuit,const std::unordered_map<GateRef,size_t> & bbGatesAddrToIdx,std::vector<GateRef> & bbAndFixedGatesList)332 void Scheduler::CalculateFixedGatesList(const Circuit *circuit,
333                                         const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
334                                         std::vector<GateRef> &bbAndFixedGatesList)
335 {
336     GateAccessor acc(const_cast<Circuit*>(circuit));
337     for (const auto &item : bbGatesAddrToIdx) {
338         bbAndFixedGatesList.push_back(item.first);
339         auto uses = acc.Uses(item.first);
340         for (auto i = uses.begin(); i != uses.end(); i++) {
341             GateRef succGate = *i;
342             if (acc.IsFixed(succGate)) {
343                 bbAndFixedGatesList.push_back(succGate);
344             }
345         }
346     }
347 }
348 
CalculateSchedulingLowerBound(const Circuit * circuit,const std::unordered_map<GateRef,size_t> & bbGatesAddrToIdx,const std::function<size_t (size_t,size_t)> & lowestCommonAncestor,std::unordered_map<GateRef,size_t> & lowerBound,std::vector<GateRef> * order)349 void Scheduler::CalculateSchedulingLowerBound(const Circuit *circuit,
350                                               const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
351                                               const std::function<size_t(size_t, size_t)> &lowestCommonAncestor,
352                                               std::unordered_map<GateRef, size_t> &lowerBound,
353                                               std::vector<GateRef> *order)
354 {
355     GateAccessor acc(const_cast<Circuit*>(circuit));
356     std::vector<GateRef> bbAndFixedGatesList;
357     CalculateFixedGatesList(circuit, bbGatesAddrToIdx, bbAndFixedGatesList);
358     std::unordered_map<GateRef, size_t> useCount;
359     struct DFSVisitState {
360         std::vector<GateRef> prevGates;
361         size_t idx = 0;
362     };
363     DFSVisitState emptyVisitState = {std::vector<GateRef>(0), 0};
364     std::stack<DFSVisitState> dfsVisitStack;
365     for (const auto &gate : bbAndFixedGatesList) {
366         dfsVisitStack.push(emptyVisitState);
367         auto &rootState = dfsVisitStack.top();
368         auto &rootPrevGates = rootState.prevGates;
369         acc.GetIns(gate, rootPrevGates);
370         while (!dfsVisitStack.empty()) {
371             auto &curState = dfsVisitStack.top();
372             auto &prevGates = curState.prevGates;
373             auto &idx = curState.idx;
374             if (idx == prevGates.size()) {
375                 dfsVisitStack.pop();
376                 continue;
377             }
378             const auto &prevGate = prevGates[idx];
379             if (!acc.IsSchedulable(prevGate)) {
380                 ++idx;
381                 continue;
382             }
383             useCount[prevGate]++;
384             if (useCount[prevGate] == 1) {
385                 dfsVisitStack.push(emptyVisitState);
386                 auto &newState = dfsVisitStack.top();
387                 auto &newPrevGates = newState.prevGates;
388                 acc.GetIns(prevGate, newPrevGates);
389             }
390             ++idx;
391         }
392     }
393     struct DFSFinishState {
394         GateRef curGate = Circuit::NullGate();
395         std::vector<GateRef> prevGates;
396         size_t idx = 0;
397     };
398     DFSFinishState emptyFinishState = {Circuit::NullGate(), std::vector<GateRef>(0), 0};
399     std::stack<DFSFinishState> dfsFinishStack;
400     for (const auto &gate : bbAndFixedGatesList) {
401         dfsFinishStack.push(emptyFinishState);
402         auto &rootState = dfsFinishStack.top();
403         auto &rootPrevGates = rootState.prevGates;
404         rootState.curGate = gate;
405         acc.GetIns(gate, rootPrevGates);
406         while (!dfsFinishStack.empty()) {
407             auto &curState = dfsFinishStack.top();
408             auto &curGate = curState.curGate;
409             auto &prevGates = curState.prevGates;
410             auto &idx = curState.idx;
411             if (idx == prevGates.size()) {
412                 dfsFinishStack.pop();
413                 continue;
414             }
415             const auto &prevGate = prevGates[idx];
416             if (!acc.IsSchedulable(prevGate)) {
417                 ++idx;
418                 continue;
419             }
420             useCount[prevGate]--;
421             size_t curLowerBound;
422             if (acc.IsState(curGate)) {  // cur_opcode would not be STATE_ENTRY
423                 curLowerBound = bbGatesAddrToIdx.at(curGate);
424             } else if (acc.IsFixed(curGate)) {
425                 ASSERT(idx > 0);
426                 curLowerBound = bbGatesAddrToIdx.at(acc.GetIn(acc.GetIn(curGate, 0), idx - 1));
427             } else {
428                 curLowerBound = lowerBound.at(curGate);
429             }
430             if (lowerBound.count(prevGate) == 0) {
431                 lowerBound[prevGate] = curLowerBound;
432             } else {
433                 lowerBound[prevGate] = lowestCommonAncestor(lowerBound[prevGate], curLowerBound);
434             }
435             if (useCount[prevGate] == 0) {
436                 if (order != nullptr) {
437                     order->push_back(prevGate);
438                 }
439                 dfsFinishStack.push(emptyFinishState);
440                 auto &newState = dfsFinishStack.top();
441                 auto &newPrevGates = newState.prevGates;
442                 newState.curGate = prevGate;
443                 acc.GetIns(prevGate, newPrevGates);
444             }
445             ++idx;
446         }
447     }
448 }
449 
Print(const std::vector<std::vector<GateRef>> * cfg,const Circuit * circuit)450 void Scheduler::Print(const std::vector<std::vector<GateRef>> *cfg, const Circuit *circuit)
451 {
452     GateAccessor acc(const_cast<Circuit*>(circuit));
453     std::vector<GateRef> bbGatesList;
454     std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
455     std::vector<size_t> immDom;
456     Scheduler::CalculateDominatorTree(circuit, bbGatesList, bbGatesAddrToIdx, immDom);
457     LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
458     for (size_t bbIdx = 0; bbIdx < cfg->size(); bbIdx++) {
459         auto opcode = acc.GetOpCode((*cfg)[bbIdx].front());
460         LOG_COMPILER(INFO) << "B" << bbIdx << "_" << opcode << ":"
461                            << "  immDom=" << immDom[bbIdx];
462         LOG_COMPILER(INFO) << "  pred=[";
463         bool isFirst = true;
464         GateRef head = cfg->at(bbIdx).front();
465         auto ins = acc.Ins(head);
466         for (auto i = ins.begin(); i != ins.end(); i++) {
467             GateRef predState = *i;
468             if (acc.IsState(predState) ||
469                 acc.GetOpCode(predState) == OpCode::STATE_ENTRY) {
470                 LOG_COMPILER(INFO) << (isFirst ? "" : " ") << bbGatesAddrToIdx.at(predState);
471                 isFirst = false;
472             }
473         }
474         LOG_COMPILER(INFO) << "]  succ=[";
475         isFirst = true;
476         GateRef h = cfg->at(bbIdx).front();
477         auto uses = acc.Uses(h);
478         for (auto i = uses.begin(); i != uses.end(); i++) {
479             GateRef succState = *i;
480             if (acc.IsState(succState) ||
481                 acc.GetOpCode(succState) == OpCode::STATE_ENTRY) {
482                 LOG_COMPILER(INFO) << (isFirst ? "" : " ") << bbGatesAddrToIdx.at(succState);
483                 isFirst = false;
484             }
485         }
486         LOG_COMPILER(INFO) << "]";
487         for (size_t instIdx = (*cfg)[bbIdx].size(); instIdx > 0; instIdx--) {
488             acc.Print((*cfg)[bbIdx][instIdx - 1]);
489         }
490     }
491     LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
492 }
493 }  // namespace panda::ecmascript::kungfu
494