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 "eh_func.h"
17 #include "cgfunc.h"
18 #include "cg.h"
19 #include "mir_builder.h"
20 #include "switch_lowerer.h"
21
22 namespace maplebe {
23 using namespace maple;
24
DumpEHTry(const MIRModule & mirModule)25 void EHTry::DumpEHTry(const MIRModule &mirModule)
26 {
27 if (tryNode != nullptr) {
28 tryNode->Dump();
29 }
30
31 if (endTryNode != nullptr) {
32 endTryNode->Dump();
33 }
34
35 for (const auto *currCatch : catchVec) {
36 if (currCatch == nullptr) {
37 continue;
38 }
39 currCatch->Dump();
40 }
41 }
42
ConvertThrowToRuntime(CGFunc & cgFunc,BaseNode & arg)43 void EHThrow::ConvertThrowToRuntime(CGFunc &cgFunc, BaseNode &arg)
44 {
45 MIRFunction &mirFunc = cgFunc.GetFunction();
46 MIRModule *mirModule = mirFunc.GetModule();
47 MIRFunction *calleeFunc =
48 mirModule->GetMIRBuilder()->GetOrCreateFunction("MCC_ThrowException", static_cast<TyIdx>(PTY_void));
49 cgFunc.GetBecommon().UpdateTypeTable(*calleeFunc->GetMIRFuncType());
50 calleeFunc->SetNoReturn();
51 MapleVector<BaseNode *> args(mirModule->GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());
52 args.emplace_back(&arg);
53 CallNode *callAssign = mirModule->GetMIRBuilder()->CreateStmtCall(calleeFunc->GetPuidx(), args);
54 mirFunc.GetBody()->ReplaceStmt1WithStmt2(rethrow, callAssign);
55 }
56
ConvertThrowToRethrow(CGFunc & cgFunc)57 void EHThrow::ConvertThrowToRethrow(CGFunc &cgFunc)
58 {
59 MIRFunction &mirFunc = cgFunc.GetFunction();
60 MIRModule *mirModule = mirFunc.GetModule();
61 MIRBuilder *mirBuilder = mirModule->GetMIRBuilder();
62 MIRFunction *unFunc = mirBuilder->GetOrCreateFunction("MCC_RethrowException", static_cast<TyIdx>(PTY_void));
63 cgFunc.GetBecommon().UpdateTypeTable(*unFunc->GetMIRFuncType());
64 unFunc->SetNoReturn();
65 MapleVector<BaseNode *> args(mirBuilder->GetCurrentFuncCodeMpAllocator()->Adapter());
66 args.emplace_back(rethrow->Opnd(0));
67 CallNode *callNode = mirBuilder->CreateStmtCall(unFunc->GetPuidx(), args);
68 mirFunc.GetBody()->ReplaceStmt1WithStmt2(rethrow, callNode);
69 }
70
EHFunc(CGFunc & func)71 EHFunc::EHFunc(CGFunc &func)
72 : cgFunc(&func),
73 tryVec(func.GetFuncScopeAllocator()->Adapter()),
74 ehTyTable(func.GetFuncScopeAllocator()->Adapter()),
75 ty2IndexTable(std::less<TyIdx>(), func.GetFuncScopeAllocator()->Adapter()),
76 rethrowVec(func.GetFuncScopeAllocator()->Adapter())
77 {
78 }
79
BuildEHFunc()80 EHFunc *CGFunc::BuildEHFunc()
81 {
82 EHFunc *newEHFunc = GetMemoryPool()->New<EHFunc>(*this);
83 SetEHFunc(*newEHFunc);
84 std::vector<std::pair<LabelIdx, CatchNode *>> catchVec;
85 newEHFunc->MergeCatchToTry(catchVec);
86 newEHFunc->BuildEHTypeTable(catchVec);
87 newEHFunc->InsertEHSwitchTable();
88 newEHFunc->GenerateCleanupLabel();
89
90 GetBecommon().BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetVoid());
91 if (newEHFunc->NeedFullLSDA()) {
92 newEHFunc->CreateLSDA();
93 }
94 if (GetCG()->GetCGOptions().GenerateExceptionHandlingCode()) {
95 newEHFunc->CreateTypeInfoSt();
96 }
97
98 return newEHFunc;
99 }
100
NeedFullLSDA() const101 bool EHFunc::NeedFullLSDA() const
102 {
103 return false;
104 }
105
NeedFastLSDA() const106 bool EHFunc::NeedFastLSDA() const
107 {
108 return false;
109 }
110
HasTry() const111 bool EHFunc::HasTry() const
112 {
113 return !tryVec.empty();
114 }
115
CreateTypeInfoSt()116 void EHFunc::CreateTypeInfoSt()
117 {
118 MIRFunction &mirFunc = cgFunc->GetFunction();
119 bool ctorDefined = false;
120 if (mirFunc.GetAttr(FUNCATTR_constructor) && !mirFunc.GetAttr(FUNCATTR_static) && (mirFunc.GetBody() != nullptr)) {
121 ctorDefined = true;
122 }
123
124 if (!ctorDefined) {
125 return;
126 }
127
128 const auto *classType = static_cast<const MIRClassType *>(mirFunc.GetClassType());
129 if (cgFunc->GetMirModule().IsCModule() && classType == nullptr) {
130 return;
131 }
132 DEBUG_ASSERT(classType != nullptr, "");
133 if (classType->GetMethods().empty() && (classType->GetFieldsSize() == 0)) {
134 return;
135 }
136 }
137
138 /*
139 * merge catch to try
140 */
MergeCatchToTry(const std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)141 void EHFunc::MergeCatchToTry(const std::vector<std::pair<LabelIdx, CatchNode *>> &catchVec)
142 {
143 size_t tryOffsetCount;
144 for (auto *ehTry : tryVec) {
145 tryOffsetCount = ehTry->GetTryNode()->GetOffsetsCount();
146 for (size_t i = 0; i < tryOffsetCount; i++) {
147 auto o = ehTry->GetTryNode()->GetOffset(i);
148 for (const auto &catchVecPair : catchVec) {
149 LabelIdx lbIdx = catchVecPair.first;
150 if (lbIdx == o) {
151 ehTry->PushBackCatchVec(*catchVecPair.second);
152 break;
153 }
154 }
155 }
156 CHECK_FATAL(ehTry->GetCatchVecSize() == tryOffsetCount,
157 "EHTry instance offset does not equal catch node amount.");
158 }
159 }
160
161 /* catchvec is going to be released by the caller */
BuildEHTypeTable(const std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)162 void EHFunc::BuildEHTypeTable(const std::vector<std::pair<LabelIdx, CatchNode *>> &catchVec)
163 {
164 if (!catchVec.empty()) {
165 /* the first one assume to be <*void> */
166 TyIdx voidTyIdx(PTY_void);
167 ehTyTable.emplace_back(voidTyIdx);
168 ty2IndexTable[voidTyIdx] = 0;
169 /* create void pointer and update becommon's size table */
170 cgFunc->GetBecommon().UpdateTypeTable(*GlobalTables::GetTypeTable().GetVoidPtr());
171 }
172
173 /* create the type table for this function, just iterate each catch */
174 CatchNode *jCatchNode = nullptr;
175 size_t catchNodeSize;
176 for (const auto &catchVecPair : catchVec) {
177 jCatchNode = catchVecPair.second;
178 catchNodeSize = jCatchNode->Size();
179 for (size_t i = 0; i < catchNodeSize; i++) {
180 MIRType *mirTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(jCatchNode->GetExceptionTyIdxVecElement(i));
181 DEBUG_ASSERT(mirTy->GetKind() == kTypePointer, "mirTy is not pointer type");
182 TyIdx ehTyIdx = static_cast<MIRPtrType *>(mirTy)->GetPointedTyIdx();
183 if (ty2IndexTable.find(ehTyIdx) != ty2IndexTable.end()) {
184 continue;
185 }
186
187 ty2IndexTable[ehTyIdx] = ehTyTable.size();
188 ehTyTable.emplace_back(ehTyIdx);
189 }
190 }
191 }
192
DumpEHFunc() const193 void EHFunc::DumpEHFunc() const
194 {
195 MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
196 for (uint32 i = 0; i < this->tryVec.size(); i++) {
197 LogInfo::MapleLogger() << "\n========== start " << i << " th eh:\n";
198 EHTry *ehTry = tryVec[i];
199 ehTry->DumpEHTry(mirModule);
200 LogInfo::MapleLogger() << "========== end " << i << " th eh =========\n";
201 }
202
203 LogInfo::MapleLogger() << "\n========== start LSDA type table ========\n";
204 for (uint32 i = 0; i < this->ehTyTable.size(); i++) {
205 LogInfo::MapleLogger() << i << " vector to ";
206 GlobalTables::GetTypeTable().GetTypeFromTyIdx(ehTyTable[i])->Dump(0);
207 LogInfo::MapleLogger() << "\n";
208 }
209 LogInfo::MapleLogger() << "========== end LSDA type table ========\n";
210
211 LogInfo::MapleLogger() << "\n========== start type-index map ========\n";
212 for (const auto &ty2indexTablePair : ty2IndexTable) {
213 GlobalTables::GetTypeTable().GetTypeFromTyIdx(ty2indexTablePair.first)->Dump(0);
214 LogInfo::MapleLogger() << " map to ";
215 LogInfo::MapleLogger() << ty2indexTablePair.second << "\n";
216 }
217 LogInfo::MapleLogger() << "========== end type-index map ========\n";
218 }
219
220 /*
221 * cleanup_label is an LabelNode, and placed just before endLabel.
222 * cleanup_label is the first statement of cleanupbb.
223 * the layout of clean up code is:
224 * //return bb
225 * ...
226 * //cleanup bb = lastbb->prev; cleanupbb->PrependBB(retbb)
227 * cleanup_label:
228 * ...
229 * //lastbb
230 * endLabel:
231 * .cfi_endproc
232 * .Label.xx.end:
233 * .size
234 */
GenerateCleanupLabel()235 void EHFunc::GenerateCleanupLabel()
236 {
237 MIRModule *mirModule = cgFunc->GetFunction().GetModule();
238 cgFunc->SetCleanupLabel(*mirModule->GetMIRBuilder()->CreateStmtLabel(CreateLabel(".LCLEANUP")));
239 BlockNode *blockNode = cgFunc->GetFunction().GetBody();
240 blockNode->InsertBefore(cgFunc->GetEndLabel(), cgFunc->GetCleanupLabel());
241 }
242
InsertDefaultLabelAndAbortFunc(BlockNode & blkNode,SwitchNode & switchNode,const StmtNode & beforeEndLabel)243 void EHFunc::InsertDefaultLabelAndAbortFunc(BlockNode &blkNode, SwitchNode &switchNode, const StmtNode &beforeEndLabel)
244 {
245 MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
246 LabelIdx dfLabIdx = cgFunc->GetFunction().GetLabelTab()->CreateLabel();
247 cgFunc->GetFunction().GetLabelTab()->AddToStringLabelMap(dfLabIdx);
248 StmtNode *dfLabStmt = mirModule.GetMIRBuilder()->CreateStmtLabel(dfLabIdx);
249 blkNode.InsertAfter(&beforeEndLabel, dfLabStmt);
250 MIRFunction *calleeFunc = mirModule.GetMIRBuilder()->GetOrCreateFunction("abort", static_cast<TyIdx>(PTY_void));
251 cgFunc->GetBecommon().UpdateTypeTable(*calleeFunc->GetMIRFuncType());
252 MapleVector<BaseNode *> args(mirModule.GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());
253 CallNode *callExit = mirModule.GetMIRBuilder()->CreateStmtCall(calleeFunc->GetPuidx(), args);
254 blkNode.InsertAfter(dfLabStmt, callExit);
255 switchNode.SetDefaultLabel(dfLabIdx);
256 }
257
FillSwitchTable(SwitchNode & switchNode,const EHTry & ehTry)258 void EHFunc::FillSwitchTable(SwitchNode &switchNode, const EHTry &ehTry)
259 {
260 CatchNode *catchNode = nullptr;
261 MIRType *exceptionType = nullptr;
262 MIRPtrType *ptType = nullptr;
263 size_t catchVecSize = ehTry.GetCatchVecSize();
264 /* update switch node's cases */
265 for (size_t i = 0; i < catchVecSize; i++) {
266 catchNode = ehTry.GetCatchNodeAt(i);
267 for (size_t j = 0; j < catchNode->Size(); j++) {
268 exceptionType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(catchNode->GetExceptionTyIdxVecElement(j));
269 ptType = static_cast<MIRPtrType *>(exceptionType);
270 MapleMap<TyIdx, uint32>::iterator ty2IdxIt = ty2IndexTable.find(ptType->GetPointedTyIdx());
271 DEBUG_ASSERT(ty2IdxIt != ty2IndexTable.end(), "find tyIdx failed!");
272 uint32 tableIdx = ty2IdxIt->second;
273 LabelNode *catchLabelNode = static_cast<LabelNode *>(catchNode->GetPrev());
274 CasePair p(tableIdx, catchLabelNode->GetLabelIdx());
275 bool inserted = false;
276 for (auto x : switchNode.GetSwitchTable()) {
277 if (x == p) {
278 inserted = true;
279 break;
280 }
281 }
282 if (!inserted) {
283 switchNode.InsertCasePair(p);
284 }
285 }
286 }
287 }
288
289 /* this is also the landing pad code. */
InsertEHSwitchTable()290 void EHFunc::InsertEHSwitchTable()
291 {
292 MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
293 BlockNode *blockNode = cgFunc->GetFunction().GetBody();
294 CHECK_FATAL(blockNode != nullptr, "get function body failed in EHThrow::InsertEHSwitchTable");
295 StmtNode *endLabelPrevNode = nullptr;
296 SwitchNode *switchNode = nullptr;
297 for (auto *ehTry : tryVec) {
298 endLabelPrevNode = cgFunc->GetEndLabel()->GetPrev();
299 /*
300 * get the next statement of the trynode. when no throw happend in try block, jump to the statement directly
301 * create a switch statement and insert after tryend;
302 */
303 switchNode = mirModule.CurFuncCodeMemPool()->New<SwitchNode>(mirModule);
304 /* create a new label as default, and if program excute here, error it */
305 InsertDefaultLabelAndAbortFunc(*blockNode, *switchNode, *endLabelPrevNode);
306 /* create s special symbol that use the second return of __builtin_eh_return() */
307 MIRSymbol *mirSymbol = mirModule.GetMIRBuilder()->CreateSymbol(TyIdx(PTY_i32), "__eh_index__", kStVar, kScAuto,
308 &cgFunc->GetFunction(), kScopeLocal);
309 switchNode->SetSwitchOpnd(mirModule.GetMIRBuilder()->CreateExprDread(*mirSymbol));
310 FillSwitchTable(*switchNode, *ehTry);
311 SwitchLowerer switchLower(mirModule, *switchNode, *cgFunc->GetFuncScopeAllocator());
312 blockNode->InsertBlockAfter(*switchLower.LowerSwitch(), endLabelPrevNode);
313 ehTry->SetFallthruGoto(endLabelPrevNode->GetNext());
314 }
315 if (!CGOptions::IsQuiet()) {
316 cgFunc->GetFunction().Dump();
317 }
318 }
319
CreateLabel(const std::string & cstr)320 LabelIdx EHFunc::CreateLabel(const std::string &cstr)
321 {
322 MIRSymbol *mirSymbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(cgFunc->GetFunction().GetStIdx().Idx());
323 CHECK_FATAL(mirSymbol != nullptr, "get function symbol failed in EHFunc::CreateLabel");
324 std::string funcName = mirSymbol->GetName();
325 std::string labStr = funcName.append(cstr).append(std::to_string(labelIdx++));
326 return cgFunc->GetFunction().GetOrCreateLableIdxFromName(labStr);
327 }
328
CreateLSDAHeader()329 void EHFunc::CreateLSDAHeader()
330 {
331 constexpr uint8 startEncoding = 0xff;
332 constexpr uint8 typeEncoding = 0x9b;
333 constexpr uint8 callSiteEncoding = 0x1;
334 MIRBuilder *mirBuilder = cgFunc->GetFunction().GetModule()->GetMIRBuilder();
335
336 LSDAHeader *lsdaHeaders = cgFunc->GetMemoryPool()->New<LSDAHeader>();
337 LabelIdx lsdaHdLblIdx = CreateLabel("LSDAHD"); /* LSDA head */
338 LabelNode *lsdaHdLblNode = mirBuilder->CreateStmtLabel(lsdaHdLblIdx);
339 lsdaHeaders->SetLSDALabel(*lsdaHdLblNode);
340
341 LabelIdx lsdaTTStartIdx = CreateLabel("LSDAALLS"); /* LSDA all start; */
342 LabelNode *lsdaTTLblNode = mirBuilder->CreateStmtLabel(lsdaTTStartIdx);
343 LabelIdx lsdaTTEndIdx = CreateLabel("LSDAALLE"); /* LSDA all end; */
344 LabelNode *lsdaCSTELblNode = mirBuilder->CreateStmtLabel(lsdaTTEndIdx);
345 lsdaHeaders->SetTTypeOffset(lsdaTTLblNode, lsdaCSTELblNode);
346
347 lsdaHeaders->SetLPStartEncoding(startEncoding);
348 lsdaHeaders->SetTTypeEncoding(typeEncoding);
349 lsdaHeaders->SetCallSiteEncoding(callSiteEncoding);
350 lsdaHeader = lsdaHeaders;
351 }
352
FillLSDACallSiteTable()353 void EHFunc::FillLSDACallSiteTable()
354 {
355 constexpr uint8 callSiteFirstAction = 0x1;
356 MIRBuilder *mirBuilder = cgFunc->GetFunction().GetModule()->GetMIRBuilder();
357 BlockNode *bodyNode = cgFunc->GetFunction().GetBody();
358
359 lsdaCallSiteTable = cgFunc->GetMemoryPool()->New<LSDACallSiteTable>(*cgFunc->GetFuncScopeAllocator());
360 LabelIdx lsdaCSTStartIdx = CreateLabel("LSDACSTS"); /* LSDA callsite table start; */
361 LabelNode *lsdaCSTStartLabel = mirBuilder->CreateStmtLabel(lsdaCSTStartIdx);
362 LabelIdx lsdaCSTEndIdx = CreateLabel("LSDACSTE"); /* LSDA callsite table end; */
363 LabelNode *lsdaCSTEndLabel = mirBuilder->CreateStmtLabel(lsdaCSTEndIdx);
364 lsdaCallSiteTable->SetCSTable(lsdaCSTStartLabel, lsdaCSTEndLabel);
365
366 /* create LDSACallSite for each EHTry instance */
367 for (auto *ehTry : tryVec) {
368 DEBUG_ASSERT(ehTry != nullptr, "null ptr check");
369 /* replace try with a label which is the callsite_start */
370 LabelIdx csStartLblIdx = CreateLabel("LSDACS");
371 LabelNode *csLblNode = mirBuilder->CreateStmtLabel(csStartLblIdx);
372 LabelIdx csEndLblIdx = CreateLabel("LSDACE");
373 LabelNode *ceLblNode = mirBuilder->CreateStmtLabel(csEndLblIdx);
374 TryNode *tryNode = ehTry->GetTryNode();
375 bodyNode->ReplaceStmt1WithStmt2(tryNode, csLblNode);
376 StmtNode *endTryNode = ehTry->GetEndtryNode();
377 bodyNode->ReplaceStmt1WithStmt2(endTryNode, ceLblNode);
378
379 LabelNode *ladpadEndLabel = nullptr;
380 if (ehTry->GetFallthruGoto()) {
381 ladpadEndLabel = mirBuilder->CreateStmtLabel(CreateLabel("LSDALPE"));
382 bodyNode->InsertBefore(ehTry->GetFallthruGoto(), ladpadEndLabel);
383 } else {
384 ladpadEndLabel = ceLblNode;
385 }
386 /* When there is only one catch, the exception table is optimized. */
387 if (ehTry->GetCatchVecSize() == 1) {
388 ladpadEndLabel = static_cast<LabelNode *>(ehTry->GetCatchNodeAt(0)->GetPrev());
389 }
390
391 LSDACallSite *lsdaCallSite = cgFunc->GetMemoryPool()->New<LSDACallSite>();
392 LabelPair csStart(cgFunc->GetStartLabel(), csLblNode);
393 LabelPair csLength(csLblNode, ceLblNode);
394 LabelPair csLandingPad(cgFunc->GetStartLabel(), ladpadEndLabel);
395 lsdaCallSite->Init(csStart, csLength, csLandingPad, callSiteFirstAction);
396 ehTry->SetLSDACallSite(*lsdaCallSite);
397 lsdaCallSiteTable->PushBack(*lsdaCallSite);
398 }
399 }
400
CreateLSDA()401 void EHFunc::CreateLSDA()
402 {
403 constexpr uint8 callSiteCleanUpAction = 0x0;
404 /* create header */
405 CreateLSDAHeader();
406 /* create and fill callsite table */
407 FillLSDACallSiteTable();
408
409 for (auto *rethrow : rethrowVec) {
410 DEBUG_ASSERT(rethrow != nullptr, "null ptr check");
411 if (rethrow->HasLSDA()) {
412 LSDACallSite *lsdaCallSite = cgFunc->GetMemoryPool()->New<LSDACallSite>();
413 LabelPair csStart(cgFunc->GetStartLabel(), rethrow->GetStartLabel());
414 LabelPair csLength(rethrow->GetStartLabel(), rethrow->GetEndLabel());
415 LabelPair csLandingPad(nullptr, nullptr);
416 lsdaCallSite->Init(csStart, csLength, csLandingPad, callSiteCleanUpAction);
417 lsdaCallSiteTable->PushBack(*lsdaCallSite);
418 }
419 }
420
421 /* LSDAAction table */
422 CreateLSDAAction();
423 }
424
CreateLSDAAction()425 void EHFunc::CreateLSDAAction()
426 {
427 constexpr uint8 actionTableNextEncoding = 0x7d;
428 /* iterate each try and its corresponding catch */
429 LSDAActionTable *actionTable = cgFunc->GetMemoryPool()->New<LSDAActionTable>(*cgFunc->GetFuncScopeAllocator());
430 lsdaActionTable = actionTable;
431
432 for (auto *ehTry : tryVec) {
433 LSDAAction *lastAction = nullptr;
434 for (int32 j = static_cast<int32>(ehTry->GetCatchVecSize()) - 1; j >= 0; --j) {
435 CatchNode *catchNode = ehTry->GetCatchNodeAt(j);
436 DEBUG_ASSERT(catchNode != nullptr, "null ptr check");
437 for (uint32 idx = 0; idx < catchNode->Size(); ++idx) {
438 MIRPtrType *ptType = static_cast<MIRPtrType *>(
439 GlobalTables::GetTypeTable().GetTypeFromTyIdx(catchNode->GetExceptionTyIdxVecElement(idx)));
440 uint32 tyIndex = ty2IndexTable[ptType->GetPointedTyIdx()]; /* get the index of ptType of ehTyTable; */
441 DEBUG_ASSERT(tyIndex != 0, "exception type index not allow equal zero");
442 LSDAAction *lsdaAction = cgFunc->GetMemoryPool()->New<LSDAAction>(
443 tyIndex, lastAction == nullptr ? 0 : actionTableNextEncoding);
444 lastAction = lsdaAction;
445 actionTable->PushBack(*lsdaAction);
446 }
447 }
448
449 CHECK_FATAL(actionTable->Size(), "must not be zero");
450 /* record actionTable group offset, per LSDAAction object in actionTable occupy 2 bytes */
451 ehTry->SetCSAction((actionTable->Size() - 1) * 2 + 1);
452 }
453 }
454
PhaseRun(maplebe::CGFunc & f)455 bool CgBuildEHFunc::PhaseRun(maplebe::CGFunc &f)
456 {
457 f.BuildEHFunc();
458 return false;
459 }
460 MAPLE_TRANSFORM_PHASE_REGISTER(CgBuildEHFunc, buildehfunc)
461 } /* namespace maplebe */
462