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