• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "cgfunc.h"
17 #include "loop.h"
18 #include "cg_ssa_pre.h"
19 
20 namespace maplebe {
21 
22 // ================ Step 6: Code Motion ================
CodeMotion()23 void SSAPre::CodeMotion()
24 {
25     // pass 1 only doing insertion
26     for (Occ *occ : allOccs) {
27         if (occ->occTy != kAOccPhiOpnd) {
28             continue;
29         }
30         PhiOpndOcc *phiOpndOcc = static_cast<PhiOpndOcc *>(occ);
31         if (phiOpndOcc->insertHere) {
32             DEBUG_ASSERT(loop->GetBBLoopParent(phiOpndOcc->cgbb->GetId()) == nullptr,
33                          "cg_ssapre: save inserted inside loop");
34             workCand->saveAtEntryBBs.insert(phiOpndOcc->cgbb->GetId());
35         }
36     }
37     // pass 2 only doing deletion
38     for (Occ *occ : realOccs) {
39         if (occ->occTy != kAOccReal) {
40             continue;
41         }
42         RealOcc *realOcc = static_cast<RealOcc *>(occ);
43         if (!realOcc->redundant) {
44             DEBUG_ASSERT(loop->GetBBLoopParent(realOcc->cgbb->GetId()) == nullptr,
45                          "cg_ssapre: save in place inside loop");
46             workCand->saveAtEntryBBs.insert(realOcc->cgbb->GetId());
47         }
48     }
49     if (enabledDebug) {
50         LogInfo::MapleLogger() << " _______ output _______" << '\n';
51         LogInfo::MapleLogger() << " saveAtEntryBBs: [";
52         for (uint32 id : workCand->saveAtEntryBBs) {
53             LogInfo::MapleLogger() << id << " ";
54         }
55         LogInfo::MapleLogger() << "]\n\n";
56     }
57 }
58 
59 // ================ Step 5: Finalize ================
60 // for setting RealOcc's redundant flag and PhiOpndOcc's insertHere flag
Finalize()61 void SSAPre::Finalize()
62 {
63     std::vector<Occ *> availDefVec(classCount + 1, nullptr);
64     // preorder traversal of dominator tree
65     for (Occ *occ : allOccs) {
66         size_t classId = static_cast<size_t>(occ->classId);
67         switch (occ->occTy) {
68             case kAOccPhi: {
69                 PhiOcc *phiOcc = static_cast<PhiOcc *>(occ);
70                 if (phiOcc->WillBeAvail()) {
71                     availDefVec[classId] = phiOcc;
72                 }
73                 break;
74             }
75             case kAOccReal: {
76                 RealOcc *realOcc = static_cast<RealOcc *>(occ);
77                 if (availDefVec[classId] == nullptr || !availDefVec[classId]->IsDominate(dom, occ)) {
78                     realOcc->redundant = false;
79                     availDefVec[classId] = realOcc;
80                 } else {
81                     realOcc->redundant = true;
82                 }
83                 break;
84             }
85             case kAOccPhiOpnd: {
86                 PhiOpndOcc *phiOpndOcc = static_cast<PhiOpndOcc *>(occ);
87                 const PhiOcc *phiOcc = phiOpndOcc->defPhiOcc;
88                 if (phiOcc->WillBeAvail()) {
89                     if (phiOpndOcc->def == nullptr || (!phiOpndOcc->hasRealUse && phiOpndOcc->def->occTy == kAOccPhi &&
90                                                        !static_cast<PhiOcc *>(phiOpndOcc->def)->WillBeAvail())) {
91                         // insert a store
92                         if (phiOpndOcc->cgbb->GetSuccs().size() != 1) {  // critical edge
93                             workCand->saveAtProlog = true;
94                             break;
95                         }
96                         phiOpndOcc->insertHere = true;
97                     } else {
98                         phiOpndOcc->def = availDefVec[classId];
99                     }
100                 }
101                 break;
102             }
103             case kAOccExit:
104                 break;
105             default:
106                 DEBUG_ASSERT(false, "Finalize: unexpected occ type");
107                 break;
108         }
109         if (workCand->saveAtProlog) {
110             break;
111         }
112     }
113     if (enabledDebug) {
114         LogInfo::MapleLogger() << " _______ after finalize _______" << '\n';
115         if (workCand->saveAtProlog) {
116             LogInfo::MapleLogger() << "Giving up because of insertion at critical edge" << '\n';
117             return;
118         }
119         for (Occ *occ : allOccs) {
120             if (occ->occTy == kAOccReal) {
121                 RealOcc *realOcc = static_cast<RealOcc *>(occ);
122                 if (!realOcc->redundant) {
123                     occ->Dump();
124                     LogInfo::MapleLogger() << " non-redundant" << '\n';
125                 }
126             } else if (occ->occTy == kAOccPhiOpnd) {
127                 PhiOpndOcc *phiOpndOcc = static_cast<PhiOpndOcc *>(occ);
128                 if (phiOpndOcc->insertHere) {
129                     occ->Dump();
130                     LogInfo::MapleLogger() << " insertHere" << '\n';
131                 }
132             }
133         }
134     }
135 }
136 
137 // ================ Step 4: WillBeAvail Computation ================
138 
ResetCanBeAvail(PhiOcc * phi) const139 void SSAPre::ResetCanBeAvail(PhiOcc *phi) const
140 {
141     phi->isCanBeAvail = false;
142     // the following loop finds phi's uses and reset them
143     for (PhiOcc *phiOcc : phiOccs) {
144         for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
145             if (phiOpndOcc->def != nullptr && phiOpndOcc->def == phi) {
146                 if (!phiOpndOcc->hasRealUse && !phiOcc->isDownsafe && phiOcc->isCanBeAvail) {
147                     ResetCanBeAvail(phiOcc);
148                 }
149             }
150         }
151     }
152 }
153 
ComputeCanBeAvail() const154 void SSAPre::ComputeCanBeAvail() const
155 {
156     for (PhiOcc *phiOcc : phiOccs) {
157         if (!phiOcc->isDownsafe && phiOcc->isCanBeAvail) {
158             bool existNullUse = false;
159             for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
160                 if (phiOpndOcc->def == nullptr) {
161                     existNullUse = true;
162                     break;
163                 }
164             }
165             if (existNullUse) {
166                 ResetCanBeAvail(phiOcc);
167             }
168         }
169     }
170 }
171 
ResetLater(PhiOcc * phi) const172 void SSAPre::ResetLater(PhiOcc *phi) const
173 {
174     phi->isLater = false;
175     // the following loop finds phi's uses and reset them
176     for (PhiOcc *phiOcc : phiOccs) {
177         for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
178             if (phiOpndOcc->def != nullptr && phiOpndOcc->def == phi) {
179                 if (phiOcc->isLater) {
180                     ResetLater(phiOcc);
181                 }
182             }
183         }
184     }
185 }
186 
ComputeLater() const187 void SSAPre::ComputeLater() const
188 {
189     for (PhiOcc *phiOcc : phiOccs) {
190         phiOcc->isLater = phiOcc->isCanBeAvail;
191     }
192     for (PhiOcc *phiOcc : phiOccs) {
193         if (phiOcc->isLater) {
194             bool existNonNullUse = false;
195             for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
196                 if (phiOpndOcc->def != nullptr && phiOpndOcc->hasRealUse) {
197                     existNonNullUse = true;
198                     break;
199                 }
200             }
201             if (existNonNullUse || phiOcc->speculativeDownsafe) {
202                 ResetLater(phiOcc);
203             }
204         }
205     }
206     if (enabledDebug) {
207         LogInfo::MapleLogger() << " _______ after later computation _______" << '\n';
208         for (PhiOcc *phiOcc : phiOccs) {
209             phiOcc->Dump();
210             if (phiOcc->isCanBeAvail) {
211                 LogInfo::MapleLogger() << " canbeAvail";
212             }
213             if (phiOcc->isLater) {
214                 LogInfo::MapleLogger() << " later";
215             }
216             if (phiOcc->isCanBeAvail && !phiOcc->isLater) {
217                 LogInfo::MapleLogger() << " will be Avail";
218             }
219             LogInfo::MapleLogger() << '\n';
220         }
221     }
222 }
223 
224 // ================ Step 3: Downsafe Computation ================
ResetDownsafe(const PhiOpndOcc * phiOpnd) const225 void SSAPre::ResetDownsafe(const PhiOpndOcc *phiOpnd) const
226 {
227     if (phiOpnd->hasRealUse) {
228         return;
229     }
230     Occ *defOcc = phiOpnd->def;
231     if (defOcc == nullptr || defOcc->occTy != kAOccPhi) {
232         return;
233     }
234     PhiOcc *defPhiOcc = static_cast<PhiOcc *>(defOcc);
235     if (defPhiOcc->speculativeDownsafe) {
236         return;
237     }
238     if (!defPhiOcc->isDownsafe) {
239         return;
240     }
241     defPhiOcc->isDownsafe = false;
242     for (PhiOpndOcc *phiOpndOcc : defPhiOcc->phiOpnds) {
243         ResetDownsafe(phiOpndOcc);
244     }
245 }
246 
ComputeDownsafe() const247 void SSAPre::ComputeDownsafe() const
248 {
249     for (PhiOcc *phiOcc : phiOccs) {
250         if (!phiOcc->isDownsafe) {
251             // propagate not-Downsafe backward along use-def edges
252             for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
253                 ResetDownsafe(phiOpndOcc);
254             }
255         }
256     }
257     if (enabledDebug) {
258         LogInfo::MapleLogger() << " _______ after downsafe computation _______" << '\n';
259         for (PhiOcc *phiOcc : phiOccs) {
260             phiOcc->Dump();
261             if (phiOcc->speculativeDownsafe) {
262                 LogInfo::MapleLogger() << " spec_downsafe /";
263             }
264             if (phiOcc->isDownsafe) {
265                 LogInfo::MapleLogger() << " downsafe";
266             }
267             LogInfo::MapleLogger() << '\n';
268         }
269     }
270 }
271 
272 // ================ Step 2: rename ================
PropagateSpeculativeDownsafe(const LoopAnalysis & loop,PhiOcc * phiOcc)273 static void PropagateSpeculativeDownsafe(const LoopAnalysis &loop, PhiOcc *phiOcc)
274 {
275     if (phiOcc->speculativeDownsafe) {
276         return;
277     }
278     phiOcc->isDownsafe = true;
279     phiOcc->speculativeDownsafe = true;
280     for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
281         if (phiOpndOcc->def != nullptr && phiOpndOcc->def->occTy == kAOccPhi) {
282             PhiOcc *nextPhiOcc = static_cast<PhiOcc *>(phiOpndOcc->def);
283             if (loop.GetBBLoopParent(nextPhiOcc->cgbb->GetId()) != nullptr) {
284                 PropagateSpeculativeDownsafe(loop, nextPhiOcc);
285             }
286         }
287     }
288 }
289 
Rename()290 void SSAPre::Rename()
291 {
292     std::stack<Occ *> occStack;
293     classCount = 0;
294     // iterate thru the occurrences in order of preorder traversal of dominator
295     // tree
296     for (Occ *occ : allOccs) {
297         while (!occStack.empty() && !occStack.top()->IsDominate(dom, occ)) {
298             occStack.pop();
299         }
300         switch (occ->occTy) {
301             case kAOccExit:
302                 if (!occStack.empty()) {
303                     Occ *topOcc = occStack.top();
304                     if (topOcc->occTy == kAOccPhi) {
305                         PhiOcc *phiTopOcc = static_cast<PhiOcc *>(topOcc);
306                         if (!phiTopOcc->speculativeDownsafe) {
307                             phiTopOcc->isDownsafe = false;
308                         }
309                     }
310                 }
311                 break;
312             case kAOccPhi:
313                 // assign new class
314                 occ->classId = ++classCount;
315                 occStack.push(occ);
316                 break;
317             case kAOccReal: {
318                 if (occStack.empty()) {
319                     // assign new class
320                     occ->classId = ++classCount;
321                     occStack.push(occ);
322                     break;
323                 }
324                 Occ *topOcc = occStack.top();
325                 occ->classId = topOcc->classId;
326                 if (topOcc->occTy == kAOccPhi) {
327                     occStack.push(occ);
328                     if (loop->GetBBLoopParent(occ->cgbb->GetId()) != nullptr) {
329                         static_cast<PhiOcc *>(topOcc)->isDownsafe = true;
330                         static_cast<PhiOcc *>(topOcc)->speculativeDownsafe = true;
331                     }
332                 }
333                 break;
334             }
335             case kAOccPhiOpnd: {
336                 if (occStack.empty()) {
337                     // leave classId as 0
338                     break;
339                 }
340                 Occ *topOcc = occStack.top();
341                 occ->def = topOcc;
342                 occ->classId = topOcc->classId;
343                 if (topOcc->occTy == kAOccReal) {
344                     static_cast<PhiOpndOcc *>(occ)->hasRealUse = true;
345                 }
346                 break;
347             }
348             default:
349                 DEBUG_ASSERT(false, "Rename: unexpected type of occurrence");
350                 break;
351         }
352     }
353     // loop thru phiOccs to propagate speculativeDownsafe
354     for (PhiOcc *phiOcc : phiOccs) {
355         if (phiOcc->speculativeDownsafe) {
356             for (PhiOpndOcc *phiOpndOcc : phiOcc->phiOpnds) {
357                 if (phiOpndOcc->def != nullptr && phiOpndOcc->def->occTy == kAOccPhi) {
358                     PhiOcc *nextPhiOcc = static_cast<PhiOcc *>(phiOpndOcc->def);
359                     if (loop->GetBBLoopParent(nextPhiOcc->cgbb->GetId()) != nullptr) {
360                         PropagateSpeculativeDownsafe(*loop, nextPhiOcc);
361                     }
362                 }
363             }
364         }
365     }
366     if (enabledDebug) {
367         LogInfo::MapleLogger() << " _______ after rename _______" << '\n';
368         for (Occ *occ : allOccs) {
369             occ->Dump();
370             if (occ->occTy == kAOccPhi) {
371                 PhiOcc *phiOcc = static_cast<PhiOcc *>(occ);
372                 if (phiOcc->speculativeDownsafe) {
373                     LogInfo::MapleLogger() << " spec_downsafe /";
374                 }
375             }
376             LogInfo::MapleLogger() << '\n';
377         }
378     }
379 }
380 
381 // ================ Step 1: insert phis ================
382 
383 // form pih occ based on the real occ in workCand->realOccs; result is
384 // stored in phiDfns
FormPhis()385 void SSAPre::FormPhis()
386 {
387     for (Occ *occ : realOccs) {
388         GetIterDomFrontier(occ->cgbb, &phiDfns);
389     }
390 }
391 
392 // form allOccs inclusive of real, phi, phiOpnd, exit occurrences;
393 // form phiOccs containing only the phis
CreateSortedOccs()394 void SSAPre::CreateSortedOccs()
395 {
396     // form phiOpnd occs based on the preds of the phi occs; result is
397     // stored in phiOpndDfns
398     std::multiset<uint32> phiOpndDfns;
399     for (uint32 dfn : phiDfns) {
400         const BBId bbId = dom->GetDtPreOrderItem(dfn);
401         BB *cgbb = cgFunc->GetAllBBs()[bbId];
402         for (BB *pred : cgbb->GetPreds()) {
403             (void)phiOpndDfns.insert(dom->GetDtDfnItem(pred->GetId()));
404         }
405     }
406     std::unordered_map<BBId, std::forward_list<PhiOpndOcc *>> bb2PhiOpndMap;
407     MapleVector<Occ *>::iterator realOccIt = realOccs.begin();
408     MapleVector<ExitOcc *>::iterator exitOccIt = exitOccs.begin();
409     MapleSet<uint32>::iterator phiDfnIt = phiDfns.begin();
410     MapleSet<uint32>::iterator phiOpndDfnIt = phiOpndDfns.begin();
411     Occ *nextRealOcc = nullptr;
412     if (realOccIt != realOccs.end()) {
413         nextRealOcc = *realOccIt;
414     }
415     ExitOcc *nextExitOcc = nullptr;
416     if (exitOccIt != exitOccs.end()) {
417         nextExitOcc = *exitOccIt;
418     }
419     PhiOcc *nextPhiOcc = nullptr;
420     if (phiDfnIt != phiDfns.end()) {
421         nextPhiOcc = preMp->New<PhiOcc>(cgFunc->GetAllBBs().at(dom->GetDtPreOrderItem(*phiDfnIt)), preAllocator);
422     }
423     PhiOpndOcc *nextPhiOpndOcc = nullptr;
424     if (phiOpndDfnIt != phiOpndDfns.end()) {
425         nextPhiOpndOcc = preMp->New<PhiOpndOcc>(cgFunc->GetAllBBs().at(dom->GetDtPreOrderItem(*phiOpndDfnIt)));
426         auto it = bb2PhiOpndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt));
427         if (it == bb2PhiOpndMap.end()) {
428             std::forward_list<PhiOpndOcc *> newlist = {nextPhiOpndOcc};
429             bb2PhiOpndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newlist;
430         } else {
431             it->second.push_front(nextPhiOpndOcc);
432         }
433     }
434     Occ *pickedOcc = nullptr;  // the next picked occ in order of preorder traversal of dominator tree
435     do {
436         pickedOcc = nullptr;
437         if (nextPhiOcc != nullptr) {
438             pickedOcc = nextPhiOcc;
439         }
440         if (nextRealOcc != nullptr && (pickedOcc == nullptr || dom->GetDtDfnItem(nextRealOcc->cgbb->GetId()) <
441                                                                    dom->GetDtDfnItem(pickedOcc->cgbb->GetId()))) {
442             pickedOcc = nextRealOcc;
443         }
444         if (nextPhiOpndOcc != nullptr &&
445             (pickedOcc == nullptr || *phiOpndDfnIt < dom->GetDtDfnItem(pickedOcc->cgbb->GetId()))) {
446             pickedOcc = nextPhiOpndOcc;
447         }
448         if (nextExitOcc != nullptr && (pickedOcc == nullptr || dom->GetDtDfnItem(nextExitOcc->cgbb->GetId()) <
449                                                                    dom->GetDtDfnItem(pickedOcc->cgbb->GetId()))) {
450             pickedOcc = nextExitOcc;
451         }
452         if (pickedOcc != nullptr) {
453             allOccs.push_back(pickedOcc);
454             switch (pickedOcc->occTy) {
455                 case kAOccReal: {
456                     // get the next real occ
457                     CHECK_FATAL(realOccIt != realOccs.end(), "iterator check");
458                     ++realOccIt;
459                     if (realOccIt != realOccs.end()) {
460                         nextRealOcc = *realOccIt;
461                     } else {
462                         nextRealOcc = nullptr;
463                     }
464                     break;
465                 }
466                 case kAOccExit: {
467                     CHECK_FATAL(exitOccIt != exitOccs.end(), "iterator check");
468                     ++exitOccIt;
469                     if (exitOccIt != exitOccs.end()) {
470                         nextExitOcc = *exitOccIt;
471                     } else {
472                         nextExitOcc = nullptr;
473                     }
474                     break;
475                 }
476                 case kAOccPhi: {
477                     phiOccs.push_back(static_cast<PhiOcc *>(pickedOcc));
478                     CHECK_FATAL(phiDfnIt != phiDfns.end(), "iterator check");
479                     ++phiDfnIt;
480                     if (phiDfnIt != phiDfns.end()) {
481                         nextPhiOcc =
482                             preMp->New<PhiOcc>(cgFunc->GetAllBBs().at(dom->GetDtPreOrderItem(*phiDfnIt)), preAllocator);
483                     } else {
484                         nextPhiOcc = nullptr;
485                     }
486                     break;
487                 }
488                 case kAOccPhiOpnd: {
489                     CHECK_FATAL(phiOpndDfnIt != phiOpndDfns.end(), "iterator check");
490                     ++phiOpndDfnIt;
491                     if (phiOpndDfnIt != phiOpndDfns.end()) {
492                         nextPhiOpndOcc =
493                             preMp->New<PhiOpndOcc>(cgFunc->GetAllBBs().at(dom->GetDtPreOrderItem(*phiOpndDfnIt)));
494                         auto it = bb2PhiOpndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt));
495                         if (it == bb2PhiOpndMap.end()) {
496                             std::forward_list<PhiOpndOcc *> newlist = {nextPhiOpndOcc};
497                             bb2PhiOpndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newlist;
498                         } else {
499                             it->second.push_front(nextPhiOpndOcc);
500                         }
501                     } else {
502                         nextPhiOpndOcc = nullptr;
503                     }
504                     break;
505                 }
506                 default:
507                     DEBUG_ASSERT(false, "CreateSortedOccs: unexpected occTy");
508                     break;
509             }
510         }
511     } while (pickedOcc != nullptr);
512     // initialize phiOpnd vector in each PhiOcc node and defPhiOcc in each PhiOpndOcc
513     for (PhiOcc *phiOcc : phiOccs) {
514         for (BB *pred : phiOcc->cgbb->GetPreds()) {
515             PhiOpndOcc *phiOpndOcc = bb2PhiOpndMap[pred->GetId()].front();
516             phiOcc->phiOpnds.push_back(phiOpndOcc);
517             phiOpndOcc->defPhiOcc = phiOcc;
518             bb2PhiOpndMap[pred->GetId()].pop_front();
519         }
520     }
521     if (enabledDebug) {
522         LogInfo::MapleLogger() << " _______ after phi insertion _______" << '\n';
523         for (Occ *occ : allOccs) {
524             occ->Dump();
525             LogInfo::MapleLogger() << '\n';
526         }
527     }
528 }
529 
530 // ================ Step 0: Preparations ================
531 
PropagateNotAnt(BB * bb,std::set<BB *,BBIdCmp> * visitedBBs)532 void SSAPre::PropagateNotAnt(BB *bb, std::set<BB *, BBIdCmp> *visitedBBs)
533 {
534     if (visitedBBs->count(bb) != 0) {
535         return;
536     }
537     visitedBBs->insert(bb);
538     if (workCand->occBBs.count(bb->GetId()) != 0) {
539         return;
540     }
541     fullyAntBBs[bb->GetId()] = false;
542     for (BB *predbb : bb->GetPreds()) {
543         PropagateNotAnt(predbb, visitedBBs);
544     }
545 }
546 
FormRealsNExits()547 void SSAPre::FormRealsNExits()
548 {
549     std::set<BB *, BBIdCmp> visitedBBs;
550     if (asEarlyAsPossible) {
551         for (BB *cgbb : cgFunc->GetExitBBsVec()) {
552             if (!cgbb->IsUnreachable()) {
553                 PropagateNotAnt(cgbb, &visitedBBs);
554             }
555         }
556     }
557 
558     for (uint32 i = 0; i < dom->GetDtPreOrderSize(); i++) {
559         BBId bbid = dom->GetDtPreOrderItem(i);
560         BB *cgbb = cgFunc->GetAllBBs()[bbid];
561         if (asEarlyAsPossible) {
562             if (fullyAntBBs[cgbb->GetId()]) {
563                 RealOcc *realOcc = preMp->New<RealOcc>(cgbb);
564                 realOccs.push_back(realOcc);
565             }
566         } else {
567             if (workCand->occBBs.count(cgbb->GetId()) != 0) {
568                 RealOcc *realOcc = preMp->New<RealOcc>(cgbb);
569                 realOccs.push_back(realOcc);
570             }
571         }
572         if (!cgbb->IsUnreachable() && (cgbb->NumSuccs() == 0 || cgbb->GetKind() == BB::kBBReturn)) {
573             ExitOcc *exitOcc = preMp->New<ExitOcc>(cgbb);
574             exitOccs.push_back(exitOcc);
575         }
576     }
577     if (enabledDebug) {
578         LogInfo::MapleLogger() << "Placement Optimization for callee-save saves" << '\n';
579         LogInfo::MapleLogger() << "-----------------------------------------------" << '\n';
580         LogInfo::MapleLogger() << " _______ input _______" << '\n';
581         LogInfo::MapleLogger() << " occBBs: [";
582         for (uint32 id : workCand->occBBs) {
583             LogInfo::MapleLogger() << id << " ";
584         }
585         LogInfo::MapleLogger() << "]\n";
586     }
587 }
588 
ApplySSAPre()589 void SSAPre::ApplySSAPre()
590 {
591     FormRealsNExits();
592     // #1 insert phis; results in allOccs and phiOccs
593     FormPhis();  // result put in the set phi_bbs
594     CreateSortedOccs();
595     // #2 rename
596     Rename();
597     if (!phiOccs.empty()) {
598         // #3 DownSafety
599         ComputeDownsafe();
600         // #4 CanBeAvail
601         ComputeCanBeAvail();
602         ComputeLater();
603     }
604     // #5 Finalize
605     Finalize();
606     if (!workCand->saveAtProlog) {
607         // #6 Code Motion
608         CodeMotion();
609     }
610 }
611 
DoSavePlacementOpt(CGFunc * f,DomAnalysis * dom,LoopAnalysis * loop,SsaPreWorkCand * workCand)612 void DoSavePlacementOpt(CGFunc *f, DomAnalysis *dom, LoopAnalysis *loop, SsaPreWorkCand *workCand)
613 {
614     MemPool *tempMP = memPoolCtrler.NewMemPool("cg_ssa_pre", true);
615     SSAPre cgssapre(f, dom, loop, tempMP, workCand, false /*asEarlyAsPossible*/, false /*enabledDebug*/);
616 
617     cgssapre.ApplySSAPre();
618 
619     memPoolCtrler.DeleteMemPool(tempMP);
620 }
621 
622 }  // namespace maplebe
623