clang 23.0.0git
CIRGenException.cpp
Go to the documentation of this file.
1//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code dealing with C++ exception related code generation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenCXXABI.h"
14#include "CIRGenFunction.h"
15
17#include "llvm/Support/SaveAndRestore.h"
18
19using namespace clang;
20using namespace clang::CIRGen;
21
22const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};
23const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",
24 nullptr};
25const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",
26 nullptr};
27const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",
28 nullptr};
29const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",
30 nullptr};
32 "__gxx_personality_sj0", nullptr};
34 "__gxx_personality_seh0", nullptr};
35const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",
36 "objc_exception_throw"};
38 "__gnu_objc_personality_sj0", "objc_exception_throw"};
40 "__gnu_objc_personality_seh0", "objc_exception_throw"};
42 "__gnustep_objcxx_personality_v0", nullptr};
44 "__gnustep_objc_personality_v0", nullptr};
45const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",
46 nullptr};
48 "__C_specific_handler", nullptr};
50 "__CxxFrameHandler3", nullptr};
52 "__gxx_wasm_personality_v0", nullptr};
53const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
54 nullptr};
55const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
56 nullptr};
57
58static const EHPersonality &getCPersonality(const TargetInfo &target,
59 const CodeGenOptions &cgOpts) {
60 const llvm::Triple &triple = target.getTriple();
61 if (triple.isWindowsMSVCEnvironment())
63 if (cgOpts.hasSjLjExceptions())
65 if (cgOpts.hasDWARFExceptions())
67 if (cgOpts.hasSEHExceptions())
70}
71
72static const EHPersonality &getObjCPersonality(const TargetInfo &target,
73 const LangOptions &langOpts,
74 const CodeGenOptions &cgOpts) {
75 const llvm::Triple &triple = target.getTriple();
76 if (triple.isWindowsMSVCEnvironment())
78
79 switch (langOpts.ObjCRuntime.getKind()) {
81 return getCPersonality(target, cgOpts);
87 if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
89 [[fallthrough]];
92 if (cgOpts.hasSjLjExceptions())
94 if (cgOpts.hasSEHExceptions())
97 }
98 llvm_unreachable("bad runtime kind");
99}
100
101static const EHPersonality &getCXXPersonality(const TargetInfo &target,
102 const CodeGenOptions &cgOpts) {
103 const llvm::Triple &triple = target.getTriple();
104 if (triple.isWindowsMSVCEnvironment())
106 if (triple.isOSAIX())
108 if (cgOpts.hasSjLjExceptions())
110 if (cgOpts.hasDWARFExceptions())
112 if (cgOpts.hasSEHExceptions())
114 if (cgOpts.hasWasmExceptions())
117}
118
119/// Determines the personality function to use when both C++
120/// and Objective-C exceptions are being caught.
122 const LangOptions &langOpts,
123 const CodeGenOptions &cgOpts) {
124 if (target.getTriple().isWindowsMSVCEnvironment())
126
127 switch (langOpts.ObjCRuntime.getKind()) {
128 // In the fragile ABI, just use C++ exception handling and hope
129 // they're not doing crazy exception mixing.
131 return getCXXPersonality(target, cgOpts);
132
133 // The ObjC personality defers to the C++ personality for non-ObjC
134 // handlers. Unlike the C++ case, we use the same personality
135 // function on targets using (backend-driven) SJLJ EH.
137 case ObjCRuntime::iOS:
139 return getObjCPersonality(target, langOpts, cgOpts);
140
143
144 // The GCC runtime's personality function inherently doesn't support
145 // mixed EH. Use the ObjC personality just to avoid returning null.
146 case ObjCRuntime::GCC:
148 return getObjCPersonality(target, langOpts, cgOpts);
149 }
150 llvm_unreachable("bad runtime kind");
151}
152
153static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {
154 return triple.getArch() == llvm::Triple::x86
157}
158
160 const FunctionDecl *fd) {
161 const llvm::Triple &triple = cgm.getTarget().getTriple();
162 const LangOptions &langOpts = cgm.getLangOpts();
163 const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
164 const TargetInfo &target = cgm.getTarget();
165
166 // Functions using SEH get an SEH personality.
167 if (fd && fd->usesSEHTry())
168 return getSEHPersonalityMSVC(triple);
169
170 if (langOpts.ObjC) {
171 return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)
172 : getObjCPersonality(target, langOpts, cgOpts);
173 }
174 return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)
175 : getCPersonality(target, cgOpts);
176}
177
179 const auto *fg = cgf.curCodeDecl;
180 // For outlined finallys and filters, use the SEH personality in case they
181 // contain more SEH. This mostly only affects finallys. Filters could
182 // hypothetically use gnu statement expressions to sneak in nested SEH.
183 fg = fg ? fg : cgf.curSEHParent.getDecl();
184 return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));
185}
186
187static llvm::StringRef getPersonalityFn(CIRGenModule &cgm,
188 const EHPersonality &personality) {
189 // Create the personality function type: i32 (...)
190 mlir::Type i32Ty = cgm.getBuilder().getI32Type();
191 auto funcTy = cir::FuncType::get({}, i32Ty, /*isVarArg=*/true);
192
193 cir::FuncOp personalityFn = cgm.createRuntimeFunction(
194 funcTy, personality.personalityFn, mlir::ArrayAttr(), /*isLocal=*/true);
195
196 return personalityFn.getSymName();
197}
198
200 const llvm::Triple &triple = getTarget().getTriple();
201 if (cgm.getLangOpts().OpenMPIsTargetDevice &&
202 (triple.isNVPTX() || triple.isAMDGCN())) {
203 cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
204 return;
205 }
206
207 if (const Expr *subExpr = e->getSubExpr()) {
208 QualType throwType = subExpr->getType();
209 if (throwType->isObjCObjectPointerType()) {
210 cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
211 return;
212 }
213
214 cgm.getCXXABI().emitThrow(*this, e);
215 return;
216 }
217
218 cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
219}
220
222 // Make sure the exception object is cleaned up if there's an
223 // exception during initialization.
225
226 // __cxa_allocate_exception returns a void*; we need to cast this
227 // to the appropriate type for the object.
228 mlir::Type ty = convertTypeForMem(e->getType());
229 Address typedAddr = addr.withElementType(builder, ty);
230
231 // From LLVM's codegen:
232 // FIXME: this isn't quite right! If there's a final unelided call
233 // to a copy constructor, then according to [except.terminate]p1 we
234 // must call std::terminate() if that constructor throws, because
235 // technically that copy occurs after the exception expression is
236 // evaluated but before the exception is caught. But the best way
237 // to handle that is to teach EmitAggExpr to do the final copy
238 // differently if it can't be elided.
239 emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
240 /*isInitializer=*/true);
241
242 // Deactivate the cleanup block.
244}
245
247 cir::TryOp tryOp) {
248 const EHPersonality &personality = EHPersonality::get(*this);
249 // This can always be a call because we necessarily didn't find
250 // anything on the EH stack which needs our help.
251 const char *rethrowName = personality.catchallRethrowFn;
252 if (rethrowName != nullptr && !isCleanup) {
253 cgm.errorNYI("populateUnwindResumeBlock CatchallRethrowFn");
254 return;
255 }
256
257 unsigned regionsNum = tryOp->getNumRegions();
258 mlir::Region *unwindRegion = &tryOp->getRegion(regionsNum - 1);
259 mlir::Block *unwindResumeBlock = &unwindRegion->front();
260 if (!unwindResumeBlock->empty())
261 return;
262
263 // Emit cir.resume into the unwind region last block
264 mlir::OpBuilder::InsertionGuard guard(builder);
265 builder.setInsertionPointToStart(unwindResumeBlock);
266 cir::ResumeOp::create(builder, tryOp.getLoc());
267}
268
269mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
270 if (s.getTryBlock()->body_empty())
271 return mlir::LogicalResult::success();
272
273 mlir::Location loc = getLoc(s.getSourceRange());
274 // Create a scope to hold try local storage for catch params.
275
276 mlir::OpBuilder::InsertPoint scopeIP;
277 cir::ScopeOp::create(
278 builder, loc,
279 /*scopeBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
280 scopeIP = builder.saveInsertionPoint();
281 });
282
283 mlir::OpBuilder::InsertionGuard guard(builder);
284 builder.restoreInsertionPoint(scopeIP);
285 mlir::LogicalResult result = emitCXXTryStmtUnderScope(s);
286 cir::YieldOp::create(builder, loc);
287 return result;
288}
289
290mlir::LogicalResult
292 const llvm::Triple &t = getTarget().getTriple();
293 // If we encounter a try statement on in an OpenMP target region offloaded to
294 // a GPU, we treat it as a basic block.
295 const bool isTargetDevice =
296 (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
297 if (isTargetDevice) {
298 cgm.errorNYI(
299 "emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU");
300 return mlir::success();
301 }
302
303 unsigned numHandlers = s.getNumHandlers();
304 mlir::Location tryLoc = getLoc(s.getBeginLoc());
305 mlir::OpBuilder::InsertPoint beginInsertTryBody;
306
307 bool hasCatchAll = false;
308 for (unsigned i = 0; i != numHandlers; ++i) {
309 hasCatchAll |= s.getHandler(i)->getExceptionDecl() == nullptr;
310 if (hasCatchAll)
311 break;
312 }
313
314 // Create the scope to represent only the C/C++ `try {}` part. However,
315 // don't populate right away. Create regions for the catch handlers,
316 // but don't emit the handler bodies yet. For now, only make sure the
317 // scope returns the exception information.
318 auto tryOp = cir::TryOp::create(
319 builder, tryLoc,
320 /*tryBuilder=*/
321 [&](mlir::OpBuilder &b, mlir::Location loc) {
322 beginInsertTryBody = builder.saveInsertionPoint();
323 },
324 /*handlersBuilder=*/
325 [&](mlir::OpBuilder &b, mlir::Location loc,
326 mlir::OperationState &result) {
327 mlir::OpBuilder::InsertionGuard guard(b);
328
329 // We create an extra region for an unwind catch handler in case the
330 // catch-all handler doesn't exists
331 unsigned numRegionsToCreate =
332 hasCatchAll ? numHandlers : numHandlers + 1;
333
334 for (unsigned i = 0; i != numRegionsToCreate; ++i) {
335 mlir::Region *region = result.addRegion();
336 builder.createBlock(region);
337 }
338 });
339
340 // Finally emit the body for try/catch.
341 {
342 mlir::Location loc = tryOp.getLoc();
343 mlir::OpBuilder::InsertionGuard guard(builder);
344 builder.restoreInsertionPoint(beginInsertTryBody);
345 CIRGenFunction::LexicalScope tryScope{*this, loc,
346 builder.getInsertionBlock()};
347
348 tryScope.setAsTry(tryOp);
349
350 // Attach the basic blocks for the catch regions.
351 enterCXXTryStmt(s, tryOp);
352
353 // Emit the body for the `try {}` part.
354 {
355 mlir::OpBuilder::InsertionGuard guard(builder);
356 CIRGenFunction::LexicalScope tryBodyScope{*this, loc,
357 builder.getInsertionBlock()};
358 if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())
359 return mlir::failure();
360 }
361
362 // Emit catch clauses.
364 }
365
366 return mlir::success();
367}
368
369/// Emit the structure of the dispatch block for the given catch scope.
370/// It is an invariant that the dispatch block already exists.
372 EHCatchScope &catchScope, cir::TryOp tryOp) {
373 if (EHPersonality::get(cgf).isWasmPersonality()) {
374 cgf.cgm.errorNYI("emitCatchDispatchBlock: WasmPersonality");
375 return;
376 }
377
378 if (EHPersonality::get(cgf).usesFuncletPads()) {
379 cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
380 return;
381 }
382
383 assert(std::find_if(catchScope.begin(), catchScope.end(),
384 [](const auto &handler) {
385 return !handler.type.rtti && handler.type.flags != 0;
386 }) == catchScope.end() &&
387 "catch handler without type value or with not supported flags");
388
389 // There was no catch all handler, populate th EH regions for the
390 // enclosing scope.
391 if (!std::prev(catchScope.end())->isCatchAll())
392 cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
393}
394
395void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
396 bool isFnTryBlock) {
397 unsigned numHandlers = s.getNumHandlers();
398 EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);
399 for (unsigned i = 0; i != numHandlers; ++i) {
400 const CXXCatchStmt *catchStmt = s.getHandler(i);
401 mlir::Region *handler = &tryOp.getHandlerRegions()[i];
402 if (catchStmt->getExceptionDecl()) {
403 // FIXME: Dropping the reference type on the type into makes it
404 // impossible to correctly implement catch-by-reference
405 // semantics for pointers. Unfortunately, this is what all
406 // existing compilers do, and it's not clear that the standard
407 // personality routine is capable of doing this right. See C++ DR 388:
408 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
409 Qualifiers caughtTypeQuals;
410 QualType caughtType = cgm.getASTContext().getUnqualifiedArrayType(
411 catchStmt->getCaughtType().getNonReferenceType(), caughtTypeQuals);
412 if (caughtType->isObjCObjectPointerType()) {
413 cgm.errorNYI("enterCXXTryStmt: caughtType ObjCObjectPointerType");
414 return;
415 }
416
417 CatchTypeInfo typeInfo = cgm.getCXXABI().getAddrOfCXXCatchHandlerType(
418 getLoc(catchStmt->getSourceRange()), caughtType,
419 catchStmt->getCaughtType());
420 catchScope->setHandler(i, typeInfo, handler, catchStmt);
421 } else {
422 // No exception decl indicates '...', a catch-all.
423 catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,
424 s.getHandler(i));
425 }
426
427 // Under async exceptions, catch(...) needs to catch HW exception too
428 // Mark scope with SehTryBegin as a SEH __try scope
429 if (getLangOpts().EHAsynch) {
430 cgm.errorNYI("enterCXXTryStmt: EHAsynch");
431 return;
432 }
433 }
434}
435
436void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
437 unsigned numHandlers = s.getNumHandlers();
438 EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());
439 assert(catchScope.getNumHandlers() == numHandlers);
440 cir::TryOp tryOp = curLexScope->getTry();
441
442 // If the catch was not required, bail out now.
443 if (!catchScope.mayThrow()) {
444 catchScope.clearHandlerBlocks();
445 ehStack.popCatch();
446
447 // Drop all basic block from all catch regions.
448 SmallVector<mlir::Block *> eraseBlocks;
449 for (mlir::Region &handlerRegion : tryOp.getHandlerRegions()) {
450 if (handlerRegion.empty())
451 continue;
452
453 for (mlir::Block &b : handlerRegion.getBlocks())
454 eraseBlocks.push_back(&b);
455 }
456
457 for (mlir::Block *b : eraseBlocks)
458 b->erase();
459
460 tryOp.setHandlerTypesAttr({});
461 return;
462 }
463
464 // Emit the structure of the EH dispatch for this catch.
465 emitCatchDispatchBlock(*this, catchScope, tryOp);
466
467 // Copy the handler blocks off before we pop the EH stack. Emitting
468 // the handlers might scribble on this memory.
469 SmallVector<EHCatchScope::Handler> handlers(catchScope.begin(),
470 catchScope.begin() + numHandlers);
471
472 ehStack.popCatch();
473
474 // Determine if we need an implicit rethrow for all these catch handlers;
475 // see the comment below.
476 bool doImplicitRethrow =
478
479 // Wasm uses Windows-style EH instructions, but merges all catch clauses into
480 // one big catchpad. So we save the old funclet pad here before we traverse
481 // each catch handler.
482 if (EHPersonality::get(*this).isWasmPersonality()) {
483 cgm.errorNYI("exitCXXTryStmt: WASM personality");
484 return;
485 }
486
487 bool hasCatchAll = false;
488 for (auto &handler : llvm::reverse(handlers)) {
489 hasCatchAll |= handler.isCatchAll();
490 mlir::Region *catchRegion = handler.region;
491 const CXXCatchStmt *catchStmt = handler.stmt;
492
493 mlir::OpBuilder::InsertionGuard guard(builder);
494 builder.setInsertionPointToStart(&catchRegion->front());
495
496 // Enter a cleanup scope, including the catch variable and the
497 // end-catch.
498 RunCleanupsScope catchScope(*this);
499
500 // Initialize the catch variable and set up the cleanups.
502 cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
503
504 // Emit the PGO counter increment.
506
507 // Perform the body of the catch.
508 [[maybe_unused]] mlir::LogicalResult emitResult =
509 emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
510 assert(emitResult.succeeded() && "failed to emit catch handler block");
511
512 // [except.handle]p11:
513 // The currently handled exception is rethrown if control
514 // reaches the end of a handler of the function-try-block of a
515 // constructor or destructor.
516
517 // It is important that we only do this on fallthrough and not on
518 // return. Note that it's illegal to put a return in a
519 // constructor function-try-block's catch handler (p14), so this
520 // really only applies to destructors.
521 if (doImplicitRethrow) {
522 cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");
523 return;
524 }
525
526 // Fall out through the catch cleanups.
527 catchScope.forceCleanup();
528 }
529
530 // Because in wasm we merge all catch clauses into one big catchpad, in case
531 // none of the types in catch handlers matches after we test against each of
532 // them, we should unwind to the next EH enclosing scope. We generate a call
533 // to rethrow function here to do that.
534 if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {
535 cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");
536 }
537
539}
540
542 assert(ehStack.requiresCatchOrCleanup());
543 assert(!cgm.getLangOpts().IgnoreExceptions &&
544 "LandingPad should not be emitted when -fignore-exceptions are in "
545 "effect.");
546
547 EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());
548 switch (innermostEHScope.getKind()) {
550 cgm.errorNYI("populateCatchHandlers: terminate");
551 return;
552
553 case EHScope::Catch:
554 case EHScope::Cleanup:
555 case EHScope::Filter:
556 // CIR does not cache landing pads.
557 break;
558 }
559
560 // If there's an existing TryOp, it means we got a `cir.try` scope
561 // that leads to this "landing pad" creation site. Otherwise, exceptions
562 // are enabled but a throwing function is called anyways (common pattern
563 // with function local static initializers).
564 mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
565 if (!handlerTypesAttr || handlerTypesAttr.empty()) {
566 // Accumulate all the handlers in scope.
567 bool hasCatchAll = false;
570 for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
571 ++i) {
572 switch (i->getKind()) {
573 case EHScope::Cleanup:
574 cgm.errorNYI("emitLandingPad: Cleanup");
575 return;
576
577 case EHScope::Filter:
578 cgm.errorNYI("emitLandingPad: Filter");
579 return;
580
582 cgm.errorNYI("emitLandingPad: Terminate");
583 return;
584
585 case EHScope::Catch:
586 break;
587 } // end switch
588
589 EHCatchScope &catchScope = cast<EHCatchScope>(*i);
590 for (const EHCatchScope::Handler &handler :
591 llvm::make_range(catchScope.begin(), catchScope.end())) {
592 assert(handler.type.flags == 0 &&
593 "landingpads do not support catch handler flags");
594
595 // If this is a catch-all, register that and abort.
596 if (handler.isCatchAll()) {
597 assert(!hasCatchAll);
598 hasCatchAll = true;
599 break;
600 }
601
602 // Check whether we already have a handler for this type.
603 // If not, keep track to later add to catch op.
604 if (catchTypes.insert(handler.type.rtti).second)
605 handlerAttrs.push_back(handler.type.rtti);
606 }
607
608 if (hasCatchAll)
609 break;
610 }
611
612 if (hasCatchAll)
613 handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
614
616
617 // If there's no catch_all, attach the unwind region. This needs to be the
618 // last region in the TryOp catch list.
619 if (!hasCatchAll)
620 handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
621
622 // Add final array of clauses into TryOp.
623 tryOp.setHandlerTypesAttr(
624 mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
625 }
626
627 // In traditional LLVM codegen. this tells the backend how to generate the
628 // landing pad by generating a branch to the dispatch block. In CIR,
629 // this is used to populate blocks for later filing during
630 // cleanup handling.
631 populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);
632}
633
634// Differently from LLVM traditional codegen, there are no dispatch blocks
635// to look at given cir.try_call does not jump to blocks like invoke does.
636// However.
638 cir::TryOp tryOp) {
639 if (EHPersonality::get(*this).usesFuncletPads()) {
640 cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
641 return;
642 }
643
644 // The dispatch block for the end of the scope chain is a block that
645 // just resumes unwinding.
646 if (scope == ehStack.stable_end()) {
647 populateUnwindResumeBlock(/*isCleanup=*/true, tryOp);
648 return;
649 }
650
651 // Otherwise, we should look at the actual scope.
652 EHScope &ehScope = *ehStack.find(scope);
653 bool mayThrow = ehScope.mayThrow();
654
655 mlir::Block *originalBlock = nullptr;
656 if (mayThrow && tryOp) {
657 // If the dispatch is cached but comes from a different tryOp, make sure:
658 // - Populate current `tryOp` with a new dispatch block regardless.
659 // - Update the map to enqueue new dispatchBlock to also get a cleanup. See
660 // code at the end of the function.
661 cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");
662 return;
663 }
664
665 if (!mayThrow) {
666 switch (ehScope.getKind()) {
667 case EHScope::Catch: {
668 mayThrow = true;
669
670 // LLVM does some optimization with branches here, CIR just keep track of
671 // the corresponding calls.
672 EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
673 if (catchScope.getNumHandlers() == 1 &&
674 catchScope.getHandler(0).isCatchAll()) {
675 break;
676 }
677
678 // TODO(cir): In the incubator we create a new basic block with YieldOp
679 // inside the attached cleanup region, but this part will be redesigned
680 break;
681 }
682 case EHScope::Cleanup: {
683 cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
684 return;
685 }
686 case EHScope::Filter: {
687 cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");
688 return;
689 }
690 case EHScope::Terminate: {
691 cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");
692 return;
693 }
694 }
695 }
696
697 if (originalBlock) {
698 cgm.errorNYI("getEHDispatchBlock: originalBlock");
699 return;
700 }
701
702 ehScope.setMayThrow(mayThrow);
703}
704
705// in classic codegen this function is mapping to `isInvokeDest` previously and
706// currently it's mapping to the conditions that performs early returns in
707// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may
708// throw exception or now.
710 // If exceptions are disabled/ignored and SEH is not in use, then there is no
711 // invoke destination. SEH "works" even if exceptions are off. In practice,
712 // this means that C++ destructors and other EH cleanups don't run, which is
713 // consistent with MSVC's behavior, except in the presence of -EHa
714 const LangOptions &lo = cgm.getLangOpts();
715 if (!lo.Exceptions || lo.IgnoreExceptions) {
716 if (!lo.Borland && !lo.MicrosoftExt)
717 return false;
718 cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
719 return false;
720 }
721
722 // CUDA device code doesn't have exceptions.
723 if (lo.CUDA && lo.CUDAIsDevice)
724 return false;
725
726 return ehStack.requiresCatchOrCleanup();
727}
728
729// In classic codegen this function is equivalent to `getInvokeDestImpl`, in
730// ClangIR we don't need to return to return any landing pad, we just need to
731// populate the catch handlers if they are required
733 assert(ehStack.requiresCatchOrCleanup());
734 assert(!ehStack.empty());
735
736 const EHPersonality &personality = EHPersonality::get(*this);
737
738 // Set personality function if not already set
739 auto funcOp = mlir::cast<cir::FuncOp>(curFn);
740 if (!funcOp.getPersonality())
741 funcOp.setPersonality(getPersonalityFn(cgm, personality));
742
743 // CIR does not cache landing pads.
744 if (personality.usesFuncletPads()) {
745 cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");
746 } else {
748 }
749}
static const EHPersonality & getCXXPersonality(const TargetInfo &target, const CodeGenOptions &cgOpts)
static const EHPersonality & getCPersonality(const TargetInfo &target, const CodeGenOptions &cgOpts)
static const EHPersonality & getObjCPersonality(const TargetInfo &target, const LangOptions &langOpts, const CodeGenOptions &cgOpts)
static llvm::StringRef getPersonalityFn(CIRGenModule &cgm, const EHPersonality &personality)
static const EHPersonality & getObjCXXPersonality(const TargetInfo &target, const LangOptions &langOpts, const CodeGenOptions &cgOpts)
Determines the personality function to use when both C++ and Objective-C exceptions are being caught.
static const EHPersonality & getSEHPersonalityMSVC(const llvm::Triple &triple)
static void emitCatchDispatchBlock(CIRGenFunction &cgf, EHCatchScope &catchScope, cir::TryOp tryOp)
Emit the structure of the dispatch block for the given catch scope.
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
void forceCleanup()
Force the emission of cleanups now, instead of waiting until this object is destroyed.
const clang::LangOptions & getLangOpts() const
void enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp, bool isFnTryBlock=false)
void populateEHCatchRegions(EHScopeStack::stable_iterator scope, cir::TryOp tryOp)
void exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock=false)
const TargetInfo & getTarget() const
void emitAnyExprToExn(const Expr *e, Address addr)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
mlir::LogicalResult emitCXXTryStmtUnderScope(const clang::CXXTryStmt &s)
mlir::Operation * curFn
The current function or global initializer that is generated code for.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
void populateCatchHandlersIfRequired(cir::TryOp tryOp)
mlir::Type convertTypeForMem(QualType t)
void populateUnwindResumeBlock(bool isCleanup, cir::TryOp tryOp)
const clang::Decl * curCodeDecl
This is the inner-most code context, which includes blocks.
mlir::MLIRContext & getMLIRContext()
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s)
void emitCXXThrowExpr(const CXXThrowExpr *e)
void populateCatchHandlers(cir::TryOp tryOp)
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::ArrayAttr={}, bool isLocal=false, bool assumeConvergent=false)
CIRGenBuilderTy & getBuilder()
const clang::TargetInfo & getTarget() const
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
A scope which attempts to handle some, possibly all, types of exceptions.
const Handler & getHandler(unsigned i) const
unsigned getNumHandlers() const
void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region, const CXXCatchStmt *stmt)
A non-stable pointer into the scope stack.
A saved depth on the scope stack.
A protected scope for zero-cost EH handling.
void setMayThrow(bool mayThrow)
EHScopeStack::stable_iterator getEnclosingEHScope() const
CXXCatchStmt - This represents a C++ catch block.
Definition StmtCXX.h:28
Stmt * getHandlerBlock() const
Definition StmtCXX.h:51
VarDecl * getExceptionDecl() const
Definition StmtCXX.h:49
QualType getCaughtType() const
Definition StmtCXX.cpp:19
A C++ throw-expression (C++ [except.throw]).
Definition ExprCXX.h:1208
const Expr * getSubExpr() const
Definition ExprCXX.h:1228
CXXTryStmt - A C++ try block, including all handlers.
Definition StmtCXX.h:69
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
bool hasDWARFExceptions() const
bool hasWasmExceptions() const
bool hasSjLjExceptions() const
bool hasSEHExceptions() const
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2000
bool usesSEHTry() const
Indicates the function uses __try.
Definition Decl.h:2518
const Decl * getDecl() const
Definition GlobalDecl.h:106
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
clang::ObjCRuntime ObjCRuntime
Kind getKind() const
Definition ObjCRuntime.h:77
const VersionTuple & getVersion() const
Definition ObjCRuntime.h:78
@ MacOSX
'macosx' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the non-fragile AB...
Definition ObjCRuntime.h:35
@ FragileMacOSX
'macosx-fragile' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the fragil...
Definition ObjCRuntime.h:40
@ GNUstep
'gnustep' is the modern non-fragile GNUstep runtime.
Definition ObjCRuntime.h:56
@ ObjFW
'objfw' is the Objective-C runtime included in ObjFW
Definition ObjCRuntime.h:59
@ iOS
'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS simulator; it is always non-fragil...
Definition ObjCRuntime.h:45
@ GCC
'gcc' is the Objective-C runtime shipped with GCC, implementing a fragile Objective-C ABI
Definition ObjCRuntime.h:53
@ WatchOS
'watchos' is a variant of iOS for Apple's watchOS.
Definition ObjCRuntime.h:49
A (possibly-)qualified type.
Definition TypeBase.h:937
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8332
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8477
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
Exposes information about the current target.
Definition TargetInfo.h:226
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isObjCObjectPointerType() const
Definition TypeBase.h:8704
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool ehScopeFilter()
static bool ehCleanupScope()
static bool currentFuncletPad()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the type of a catch handler,...
The exceptions personality for a function.
bool usesFuncletPads() const
Does this personality use landingpads or the family of pad instructions designed to form funclets?
static const EHPersonality XL_CPlusPlus
static const EHPersonality GNU_ObjC_SJLJ
static const EHPersonality ZOS_CPlusPlus
static const EHPersonality GNUstep_ObjC
static const EHPersonality MSVC_CxxFrameHandler3
static const EHPersonality MSVC_C_specific_handler
static const EHPersonality GNU_CPlusPlus_SEH
static const EHPersonality GNU_ObjC
static const EHPersonality GNU_CPlusPlus_SJLJ
static const EHPersonality GNU_C_SJLJ
static const EHPersonality GNU_C
static const EHPersonality NeXT_ObjC
static const EHPersonality & get(CIRGenModule &cgm, const clang::FunctionDecl *fd)
static const EHPersonality GNU_CPlusPlus
static const EHPersonality GNU_ObjCXX
static const EHPersonality GNU_C_SEH
static const EHPersonality MSVC_except_handler
static const EHPersonality GNU_ObjC_SEH
static const EHPersonality GNU_Wasm_CPlusPlus