• 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 "try_catch.h"
17 namespace maplebe {
CreateNewBB(StmtNode * first,StmtNode * last)18 BBT *TryCatchBlocksLower::CreateNewBB(StmtNode *first, StmtNode *last)
19 {
20     BBT *newBB = memPool.New<BBT>(first, last, &memPool);
21     bbList.emplace_back(newBB);
22     return newBB;
23 }
24 
FindTargetBBlock(LabelIdx idx,const std::vector<BBT * > & bbs)25 BBT *TryCatchBlocksLower::FindTargetBBlock(LabelIdx idx, const std::vector<BBT *> &bbs)
26 {
27     for (auto &target : bbs) {
28         if (target->GetLabelIdx() == idx) {
29             return target;
30         }
31     }
32     return nullptr;
33 }
34 
35 /* returns the first statement that is moved in into the try block. If none is moved in, nullptr is returned */
MoveCondGotoIntoTry(BBT & jtBB,BBT & condbrBB,const MapleVector<BBT * > & labeledBBsInTry)36 StmtNode *TryCatchBlocksLower::MoveCondGotoIntoTry(BBT &jtBB, BBT &condbrBB, const MapleVector<BBT *> &labeledBBsInTry)
37 {
38     StmtNode *firstStmtMovedIn = nullptr;
39     const MapleVector<BBT *> &bbs = labeledBBsInTry;
40     StmtNode *jtStmt = jtBB.GetKeyStmt();
41 #if DEBUG
42     StmtNode *js = jtBB.GetFirstStmt();
43     while (js->GetOpCode() != OP_try) {
44         js = js->GetNext();
45     }
46     CHECK_FATAL(js == jtStmt, "make sure js equal jtStmt");
47 #endif
48     StmtNode *ts = jtBB.GetFirstStmt()->GetPrev();
49     while ((ts != nullptr) && (ts->GetOpCode() == OP_comment)) {
50         ts = ts->GetPrev();
51     }
52 
53     if (ts != nullptr && ts->IsCondBr()) {
54         CHECK_FATAL(ts->GetNext() == jtBB.GetFirstStmt(), "make sure ts's next equal jtBB's firstStmt");
55         StmtNode *firstStmtNode = jtBB.GetFirstStmt();
56         /* [ jtbb_b..jtstmt ]; either jtbb_b is a comment or jtbb_b == jtstmt */
57         LabelIdx id = static_cast<CondGotoNode *>(ts)->GetOffset();
58         for (auto &lbb : bbs) {
59             if (lbb->GetLabelIdx() == id) {
60                 /*
61                  * this cond goto jumps into the try block; let the try block enclose it
62                  * first find the preceding comment statements if any
63                  */
64                 StmtNode *brS = ts;
65                 while ((ts->GetPrev() != nullptr) && (ts->GetPrev()->GetOpCode() == OP_comment)) {
66                     ts = ts->GetPrev();
67                 }
68                 StmtNode *secondStmtNode = ts; /* beginning statement of branch block */
69                 /* [ brbb_b..br_s ]; either brbb_b is a comment or brbb_b == br_s */
70                 firstStmtNode->SetPrev(secondStmtNode->GetPrev());
71                 if (secondStmtNode->GetPrev()) {
72                     secondStmtNode->GetPrev()->SetNext(firstStmtNode);
73                 }
74                 jtStmt->GetNext()->SetPrev(brS);
75                 brS->SetNext(jtStmt->GetNext());
76                 secondStmtNode->SetPrev(jtStmt);
77                 jtStmt->SetNext(secondStmtNode);
78                 condbrBB.SetLastStmt(*firstStmtNode->GetPrev());
79                 CHECK_FATAL(condbrBB.GetFallthruBranch() == &jtBB, "make sure condbrBB's fallthruBranch equal &jtBB");
80                 condbrBB.SetFallthruBranch(&jtBB);
81                 condbrBB.SetCondJumpBranch(nullptr);
82                 firstStmtMovedIn = secondStmtNode;
83                 break;
84             }
85         }
86     }
87     return firstStmtMovedIn;
88 }
89 
90 /* collect catchbb->fallthru(0-n) into currBBThread, when encounter a new catch, return it, else return nullptr */
CollectCatchAndFallthruUntilNextCatchBB(BBT * & lowerBB,uint32 & nextEnclosedIdx,std::vector<BBT * > & currBBThread)91 BBT *TryCatchBlocksLower::CollectCatchAndFallthruUntilNextCatchBB(BBT *&lowerBB, uint32 &nextEnclosedIdx,
92                                                                   std::vector<BBT *> &currBBThread)
93 {
94     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
95     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
96 
97     BBT *nextBBThreadHead = nullptr;
98     while (lowerBB->GetFallthruBranch() != nullptr) {
99         lowerBB = lowerBB->GetFallthruBranch();
100         ++nextEnclosedIdx;
101         if (lowerBB->IsEndTry()) {
102             CHECK_FATAL(lowerBB == endTryBB, "lowerBB should equal endTryBB");
103             break;
104         }
105 
106         for (uint32 j = 0; j < enclosedBBs.size(); ++j) {
107             if (enclosedBBs[j] == lowerBB) {
108                 enclosedBBs[j] = nullptr;
109                 break;
110             }
111         }
112         if (lowerBB->IsCatch()) {
113             nextBBThreadHead = lowerBB;
114             break;
115         }
116         currBBThread.emplace_back(lowerBB);
117     }
118 
119     if (nextBBThreadHead == nullptr && lowerBB->GetFallthruBranch() == nullptr && lowerBB != endTryBB &&
120         nextEnclosedIdx < enclosedBBs.size() && enclosedBBs[nextEnclosedIdx]) {
121         /*
122          * Using a loop to find the next_bb_thread_head when it's a catch_BB or a normal_BB which
123          * is after a catch_BB. Other condition, push_back into the curr_bb_thread.
124          */
125         do {
126             lowerBB = enclosedBBs[nextEnclosedIdx];
127             enclosedBBs[nextEnclosedIdx++] = nullptr;
128             BBT *head = currBBThread.front();
129             if (head->IsCatch() || lowerBB->IsCatch()) {
130                 nextBBThreadHead = lowerBB;
131                 break;
132             }
133             currBBThread.emplace_back(lowerBB);
134         } while (nextEnclosedIdx < enclosedBBs.size());
135     }
136 
137     return nextBBThreadHead;
138 }
139 
ProcessThreadTail(BBT & threadTail,BBT * const & nextBBThreadHead,bool hasMoveEndTry)140 void TryCatchBlocksLower::ProcessThreadTail(BBT &threadTail, BBT *const &nextBBThreadHead, bool hasMoveEndTry)
141 {
142     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
143     StmtNode *newEndTry = endTryBB->GetKeyStmt()->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
144     newEndTry->SetPrev(threadTail.GetLastStmt());
145     newEndTry->SetNext(threadTail.GetLastStmt()->GetNext());
146     if (bodyEndWithEndTry && hasMoveEndTry) {
147         if (threadTail.GetLastStmt()->GetNext()) {
148             threadTail.GetLastStmt()->GetNext()->SetPrev(newEndTry);
149         }
150     } else {
151         CHECK_FATAL(threadTail.GetLastStmt()->GetNext() != nullptr,
152                     "the next of threadTail's lastStmt should not be nullptr");
153         threadTail.GetLastStmt()->GetNext()->SetPrev(newEndTry);
154     }
155     threadTail.GetLastStmt()->SetNext(newEndTry);
156 
157     threadTail.SetLastStmt(*newEndTry);
158     if (hasMoveEndTry && nextBBThreadHead == nullptr) {
159         body.SetLast(threadTail.GetLastStmt());
160     }
161 }
162 
163 /* Wrap this catch block with try-endtry block */
WrapCatchWithTryEndTryBlock(std::vector<BBT * > & currBBThread,BBT * & nextBBThreadHead,uint32 & nextEnclosedIdx,bool hasMoveEndTry)164 void TryCatchBlocksLower::WrapCatchWithTryEndTryBlock(std::vector<BBT *> &currBBThread, BBT *&nextBBThreadHead,
165                                                       uint32 &nextEnclosedIdx, bool hasMoveEndTry)
166 {
167     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
168     StmtNode *tryStmt = tryEndTryBlock.GetTryStmtNode();
169     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
170     for (auto &e : currBBThread) {
171         CHECK_FATAL(!e->IsTry(), "expect e is not try");
172     }
173     BBT *threadHead = currBBThread.front();
174     if (threadHead->IsCatch()) {
175         StmtNode *jcStmt = threadHead->GetKeyStmt();
176         CHECK_FATAL(jcStmt->GetNext() != nullptr, "jcStmt's next should not be nullptr");
177         TryNode *jtCopy = static_cast<TryNode *>(tryStmt)->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
178         jtCopy->SetNext(jcStmt->GetNext());
179         jtCopy->SetPrev(jcStmt);
180         jcStmt->GetNext()->SetPrev(jtCopy);
181         jcStmt->SetNext(jtCopy);
182 
183         BBT *threadTail = currBBThread.back();
184 
185         /* for this endtry stmt, we don't need to create a basic block */
186         ProcessThreadTail(*threadTail, static_cast<BBT *const &>(nextBBThreadHead), hasMoveEndTry);
187     } else {
188         /* For cases try->catch->normal_bb->normal_bb->endtry, Combine normal bb first. */
189         while (nextEnclosedIdx < enclosedBBs.size()) {
190             if (nextBBThreadHead != nullptr) {
191                 if (nextBBThreadHead->IsCatch()) {
192                     break;
193                 }
194             }
195             BBT *ebbSecond = enclosedBBs[nextEnclosedIdx];
196             enclosedBBs[nextEnclosedIdx++] = nullptr;
197             CHECK_FATAL(ebbSecond != endTryBB, "ebbSecond should not equal endTryBB");
198             if (ebbSecond->IsCatch()) {
199                 nextBBThreadHead = ebbSecond;
200                 break;
201             }
202             currBBThread.emplace_back(ebbSecond);
203         }
204         /* normal bb. */
205         StmtNode *stmt = threadHead->GetFirstStmt();
206 
207         TryNode *jtCopy = static_cast<TryNode *>(tryStmt)->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
208         jtCopy->SetNext(stmt);
209         jtCopy->SetPrev(stmt->GetPrev());
210         stmt->GetPrev()->SetNext(jtCopy);
211         stmt->SetPrev(jtCopy);
212         threadHead->SetFirstStmt(*jtCopy);
213 
214         BBT *threadTail = currBBThread.back();
215 
216         /* for this endtry stmt, we don't need to create a basic block */
217         ProcessThreadTail(*threadTail, static_cast<BBT *const &>(nextBBThreadHead), hasMoveEndTry);
218     }
219 }
220 
221 /*
222  * We have the following case.
223  * bb_head -> bb_1 -> .. bb_n -> endtry_bb -> succ
224  * For this particular case, we swap EndTry bb and curr_bb_thread, because the bblock that contains the endtry
225  * statement does not contain any other statements!!
226  */
SwapEndTryBBAndCurrBBThread(const std::vector<BBT * > & currBBThread,bool & hasMoveEndTry,const BBT * nextBBThreadHead)227 void TryCatchBlocksLower::SwapEndTryBBAndCurrBBThread(const std::vector<BBT *> &currBBThread, bool &hasMoveEndTry,
228                                                       const BBT *nextBBThreadHead)
229 {
230     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
231     CHECK_FATAL(endTryBB->GetFirstStmt()->GetOpCode() == OP_comment ||
232                     endTryBB->GetFirstStmt()->GetOpCode() == OP_endtry,
233                 "the opcode of endTryBB's firstStmt should be OP_comment or OP_endtry");
234     CHECK_FATAL(endTryBB->GetLastStmt()->GetOpCode() == OP_endtry,
235                 "the opcode of endTryBB's lastStmt should be OP_endtry");
236 
237     /* we move endtry_bb before bb_head */
238     BBT *threadHead = currBBThread.front();
239     CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev() != nullptr,
240                 "the prev of threadHead's firstStmt should not nullptr");
241     CHECK_FATAL(threadHead->GetFirstStmt()->GetOpCode() == OP_comment ||
242                     threadHead->GetFirstStmt()->GetOpCode() == OP_label,
243                 "the opcode of threadHead's firstStmt should be OP_comment or OP_label");
244     CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev()->GetNext() == threadHead->GetFirstStmt(),
245                 "the next of the prev of threadHead's firstStmt should equal threadHead's firstStmt");
246 
247     endTryBB->GetFirstStmt()->GetPrev()->SetNext(endTryBB->GetLastStmt()->GetNext());
248     if (endTryBB->GetLastStmt()->GetNext() != nullptr) {
249         endTryBB->GetLastStmt()->GetNext()->SetPrev(endTryBB->GetFirstStmt()->GetPrev());
250     }
251 
252     threadHead->GetFirstStmt()->GetPrev()->SetNext(endTryBB->GetFirstStmt());
253     endTryBB->GetFirstStmt()->SetPrev(threadHead->GetFirstStmt()->GetPrev());
254 
255     endTryBB->GetLastStmt()->SetNext(threadHead->GetFirstStmt());
256     threadHead->GetFirstStmt()->SetPrev(endTryBB->GetLastStmt());
257 
258     CHECK_FATAL(endTryBB->GetCondJumpBranch() == nullptr, "endTryBB's condJumpBranch must be nullptr");
259     endTryBB->SetFallthruBranch(nullptr);
260     if (bodyEndWithEndTry) {
261         hasMoveEndTry = true;
262         if (nextBBThreadHead == nullptr) {
263             body.SetLast(currBBThread.back()->GetLastStmt());
264         }
265     }
266 }
267 
ProcessEnclosedBBBetweenTryEndTry()268 void TryCatchBlocksLower::ProcessEnclosedBBBetweenTryEndTry()
269 {
270     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
271     MapleVector<BBT *> &labeledBBsInTry = tryEndTryBlock.GetLabeledBBsInTry();
272 
273     for (uint32 i = 0; i < enclosedBBs.size(); ++i) {
274         BBT *lowerBB = enclosedBBs[i];
275         if (lowerBB == nullptr) {
276             continue; /* we may have removed the element */
277         }
278         if (!lowerBB->IsLabeled()) {
279             continue;
280         }
281         labeledBBsInTry.emplace_back(lowerBB);
282     }
283 }
284 
ConnectRemainBB()285 void TryCatchBlocksLower::ConnectRemainBB()
286 {
287     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
288     BBT *startTryBB = tryEndTryBlock.GetStartTryBB();
289     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
290     size_t nEnclosedBBs = enclosedBBs.size();
291     size_t k = 0;
292     while ((k < nEnclosedBBs) && (enclosedBBs[k] == nullptr)) {
293         ++k;
294     }
295 
296     if (k < nEnclosedBBs) {
297         BBT *prevBB = enclosedBBs[k];
298 
299         startTryBB->GetLastStmt()->SetNext(prevBB->GetFirstStmt());
300         prevBB->GetFirstStmt()->SetPrev(startTryBB->GetLastStmt());
301 
302         for (++k; k < nEnclosedBBs; ++k) {
303             BBT *lowerBB = enclosedBBs[k];
304             if (lowerBB == nullptr) {
305                 continue;
306             }
307             prevBB->GetLastStmt()->SetNext(lowerBB->GetFirstStmt());
308             lowerBB->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
309             prevBB = lowerBB;
310         }
311 
312         prevBB->GetLastStmt()->SetNext(endTryBB->GetFirstStmt());
313         endTryBB->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
314     } else {
315         startTryBB->GetLastStmt()->SetNext(endTryBB->GetFirstStmt());
316         endTryBB->GetFirstStmt()->SetPrev(startTryBB->GetLastStmt());
317     }
318 }
319 
FindInsertAfterBB()320 BBT *TryCatchBlocksLower::FindInsertAfterBB()
321 {
322     BBT *insertAfter = tryEndTryBlock.GetEndTryBB();
323     CHECK_FATAL(tryEndTryBlock.GetEndTryBB()->GetLastStmt()->GetOpCode() == OP_endtry, "LowerBB type check");
324     BBT *iaOpenTry = nullptr;
325     while (insertAfter->GetFallthruBranch() != nullptr || iaOpenTry != nullptr) {
326         if (insertAfter->GetFallthruBranch() != nullptr) {
327             insertAfter = insertAfter->GetFallthruBranch();
328         } else {
329             CHECK_FATAL(iaOpenTry != nullptr, "iaOpenTry should not be nullptr");
330             insertAfter = firstStmtToBBMap[insertAfter->GetLastStmt()->GetNext()];
331             CHECK_FATAL(!insertAfter->IsTry(), "insertAfter should not be try");
332         }
333 
334         if (insertAfter->IsTry()) {
335             iaOpenTry = insertAfter;
336         } else if (insertAfter->IsEndTry()) {
337             iaOpenTry = nullptr;
338         }
339     }
340     return insertAfter;
341 }
342 
PlaceRelocatedBB(BBT & insertAfter)343 void TryCatchBlocksLower::PlaceRelocatedBB(BBT &insertAfter)
344 {
345     StmtNode *iaLast = insertAfter.GetLastStmt();
346     CHECK_FATAL(iaLast != nullptr, "iaLast should not nullptr");
347 
348     StmtNode *iaNext = iaLast->GetNext();
349     if (iaNext == nullptr) {
350         CHECK_FATAL(body.GetLast() == iaLast, "body's last should equal iaLast");
351     }
352     BBT *prevBB = &insertAfter;
353     MapleVector<BBT *> &bbsToRelocate = tryEndTryBlock.GetBBsToRelocate();
354     for (auto &rbb : bbsToRelocate) {
355         prevBB->GetLastStmt()->SetNext(rbb->GetFirstStmt());
356         rbb->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
357         prevBB = rbb;
358     }
359     prevBB->GetLastStmt()->SetNext(iaNext);
360     if (iaNext != nullptr) {
361         iaNext->SetPrev(prevBB->GetLastStmt());
362     } else {
363         /* !ia_next means we started with insert_after that was the last bblock Refer to the above CHECK_FATAL. */
364         body.SetLast(prevBB->GetLastStmt());
365         body.GetLast()->SetNext(nullptr);
366     }
367 }
368 
CheckTryCatchPattern() const369 void TryCatchBlocksLower::CheckTryCatchPattern() const
370 {
371     StmtNode *openJt = nullptr;
372     for (StmtNode *stmt = body.GetFirst(); stmt; stmt = stmt->GetNext()) {
373         switch (stmt->GetOpCode()) {
374             case OP_try:
375                 openJt = stmt;
376                 break;
377             case OP_endtry:
378                 openJt = nullptr;
379                 break;
380             case OP_catch:
381                 if (openJt != nullptr) {
382                     CatchNode *jcn = static_cast<CatchNode *>(stmt);
383                     for (uint32 i = 0; i < jcn->Size(); ++i) {
384                         MIRType *type =
385                             GlobalTables::GetTypeTable().GetTypeFromTyIdx(jcn->GetExceptionTyIdxVecElement(i));
386                         MIRPtrType *ptr = static_cast<MIRPtrType *>(type);
387                         type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr->GetPointedTyIdx());
388                         CHECK_FATAL(type->GetPrimType() == PTY_void, "type's primType should be PTY_void");
389                     }
390                 }
391                 break;
392             default:
393                 break;
394         }
395     }
396 }
397 } /* namespace maplebe */