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 */