clang 22.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
18#include "llvm/Support/SaveAndRestore.h"
19
20using namespace clang;
21using namespace clang::CIRGen;
22
23const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};
24const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",
25 nullptr};
26const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",
27 nullptr};
28const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",
29 nullptr};
30const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",
31 nullptr};
33 "__gxx_personality_sj0", nullptr};
35 "__gxx_personality_seh0", nullptr};
36const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",
37 "objc_exception_throw"};
39 "__gnu_objc_personality_sj0", "objc_exception_throw"};
41 "__gnu_objc_personality_seh0", "objc_exception_throw"};
43 "__gnustep_objcxx_personality_v0", nullptr};
45 "__gnustep_objc_personality_v0", nullptr};
46const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",
47 nullptr};
49 "__C_specific_handler", nullptr};
51 "__CxxFrameHandler3", nullptr};
53 "__gxx_wasm_personality_v0", nullptr};
54const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
55 nullptr};
56const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
57 nullptr};
58
59static const EHPersonality &getCPersonality(const TargetInfo &target,
60 const CodeGenOptions &cgOpts) {
61 const llvm::Triple &triple = target.getTriple();
62 if (triple.isWindowsMSVCEnvironment())
64 if (cgOpts.hasSjLjExceptions())
66 if (cgOpts.hasDWARFExceptions())
68 if (cgOpts.hasSEHExceptions())
71}
72
73static const EHPersonality &getObjCPersonality(const TargetInfo &target,
74 const LangOptions &langOpts,
75 const CodeGenOptions &cgOpts) {
76 const llvm::Triple &triple = target.getTriple();
77 if (triple.isWindowsMSVCEnvironment())
79
80 switch (langOpts.ObjCRuntime.getKind()) {
82 return getCPersonality(target, cgOpts);
88 if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
90 [[fallthrough]];
93 if (cgOpts.hasSjLjExceptions())
95 if (cgOpts.hasSEHExceptions())
98 }
99 llvm_unreachable("bad runtime kind");
100}
101
102static const EHPersonality &getCXXPersonality(const TargetInfo &target,
103 const CodeGenOptions &cgOpts) {
104 const llvm::Triple &triple = target.getTriple();
105 if (triple.isWindowsMSVCEnvironment())
107 if (triple.isOSAIX())
109 if (cgOpts.hasSjLjExceptions())
111 if (cgOpts.hasDWARFExceptions())
113 if (cgOpts.hasSEHExceptions())
115 if (cgOpts.hasWasmExceptions())
118}
119
120/// Determines the personality function to use when both C++
121/// and Objective-C exceptions are being caught.
123 const LangOptions &langOpts,
124 const CodeGenOptions &cgOpts) {
125 if (target.getTriple().isWindowsMSVCEnvironment())
127
128 switch (langOpts.ObjCRuntime.getKind()) {
129 // In the fragile ABI, just use C++ exception handling and hope
130 // they're not doing crazy exception mixing.
132 return getCXXPersonality(target, cgOpts);
133
134 // The ObjC personality defers to the C++ personality for non-ObjC
135 // handlers. Unlike the C++ case, we use the same personality
136 // function on targets using (backend-driven) SJLJ EH.
138 case ObjCRuntime::iOS:
140 return getObjCPersonality(target, langOpts, cgOpts);
141
144
145 // The GCC runtime's personality function inherently doesn't support
146 // mixed EH. Use the ObjC personality just to avoid returning null.
147 case ObjCRuntime::GCC:
149 return getObjCPersonality(target, langOpts, cgOpts);
150 }
151 llvm_unreachable("bad runtime kind");
152}
153
154static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {
155 return triple.getArch() == llvm::Triple::x86
158}
159
161 const FunctionDecl *fd) {
162 const llvm::Triple &triple = cgm.getTarget().getTriple();
163 const LangOptions &langOpts = cgm.getLangOpts();
164 const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
165 const TargetInfo &target = cgm.getTarget();
166
167 // Functions using SEH get an SEH personality.
168 if (fd && fd->usesSEHTry())
169 return getSEHPersonalityMSVC(triple);
170
171 if (langOpts.ObjC) {
172 return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)
173 : getObjCPersonality(target, langOpts, cgOpts);
174 }
175 return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)
176 : getCPersonality(target, cgOpts);
177}
178
180 const auto *fg = cgf.curCodeDecl;
181 // For outlined finallys and filters, use the SEH personality in case they
182 // contain more SEH. This mostly only affects finallys. Filters could
183 // hypothetically use gnu statement expressions to sneak in nested SEH.
184 fg = fg ? fg : cgf.curSEHParent.getDecl();
185 return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));
186}
187
188static llvm::StringRef getPersonalityFn(CIRGenModule &cgm,
189 const EHPersonality &personality) {
190 // Create the personality function type: i32 (...)
191 mlir::Type i32Ty = cgm.getBuilder().getI32Type();
192 auto funcTy = cir::FuncType::get({}, i32Ty, /*isVarArg=*/true);
193
194 cir::FuncOp personalityFn = cgm.createRuntimeFunction(
195 funcTy, personality.personalityFn, mlir::ArrayAttr(), /*isLocal=*/true);
196
197 return personalityFn.getSymName();
198}
199
201 const llvm::Triple &triple = getTarget().getTriple();
202 if (cgm.getLangOpts().OpenMPIsTargetDevice &&
203 (triple.isNVPTX() || triple.isAMDGCN())) {
204 cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
205 return;
206 }
207
208 if (const Expr *subExpr = e->getSubExpr()) {
209 QualType throwType = subExpr->getType();
210 if (throwType->isObjCObjectPointerType()) {
211 cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
212 return;
213 }
214
215 cgm.getCXXABI().emitThrow(*this, e);
216 return;
217 }
218
219 cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
220}
221
223 // Make sure the exception object is cleaned up if there's an
224 // exception during initialization.
226
227 // __cxa_allocate_exception returns a void*; we need to cast this
228 // to the appropriate type for the object.
229 mlir::Type ty = convertTypeForMem(e->getType());
230 Address typedAddr = addr.withElementType(builder, ty);
231
232 // From LLVM's codegen:
233 // FIXME: this isn't quite right! If there's a final unelided call
234 // to a copy constructor, then according to [except.terminate]p1 we
235 // must call std::terminate() if that constructor throws, because
236 // technically that copy occurs after the exception expression is
237 // evaluated but before the exception is caught. But the best way
238 // to handle that is to teach EmitAggExpr to do the final copy
239 // differently if it can't be elided.
240 emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
241 /*isInitializer=*/true);
242
243 // Deactivate the cleanup block.
245}
246
248 cir::TryOp tryOp) {
249 const EHPersonality &personality = EHPersonality::get(*this);
250 // This can always be a call because we necessarily didn't find
251 // anything on the EH stack which needs our help.
252 const char *rethrowName = personality.catchallRethrowFn;
253 if (rethrowName != nullptr && !isCleanup) {
254 cgm.errorNYI("populateUnwindResumeBlock CatchallRethrowFn");
255 return;
256 }
257
258 unsigned regionsNum = tryOp->getNumRegions();
259 mlir::Region *unwindRegion = &tryOp->getRegion(regionsNum - 1);
260 mlir::Block *unwindResumeBlock = &unwindRegion->front();
261 if (!unwindResumeBlock->empty())
262 return;
263
264 // Emit cir.resume into the unwind region last block
265 mlir::OpBuilder::InsertionGuard guard(builder);
266 builder.setInsertionPointToStart(unwindResumeBlock);
267 cir::ResumeOp::create(builder, tryOp.getLoc());
268}
269
270mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
271 if (s.getTryBlock()->body_empty())
272 return mlir::LogicalResult::success();
273
274 mlir::Location loc = getLoc(s.getSourceRange());
275 // Create a scope to hold try local storage for catch params.
276
277 mlir::OpBuilder::InsertPoint scopeIP;
278 cir::ScopeOp::create(
279 builder, loc,
280 /*scopeBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
281 scopeIP = builder.saveInsertionPoint();
282 });
283
284 mlir::OpBuilder::InsertionGuard guard(builder);
285 builder.restoreInsertionPoint(scopeIP);
286 mlir::LogicalResult result = emitCXXTryStmtUnderScope(s);
287 cir::YieldOp::create(builder, loc);
288 return result;
289}
290
291mlir::LogicalResult
293 const llvm::Triple &t = getTarget().getTriple();
294 // If we encounter a try statement on in an OpenMP target region offloaded to
295 // a GPU, we treat it as a basic block.
296 const bool isTargetDevice =
297 (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
298 if (isTargetDevice) {
299 cgm.errorNYI(
300 "emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU");
301 return mlir::success();
302 }
303
304 unsigned numHandlers = s.getNumHandlers();
305 mlir::Location tryLoc = getLoc(s.getBeginLoc());
306 mlir::OpBuilder::InsertPoint beginInsertTryBody;
307
308 bool hasCatchAll = false;
309 for (unsigned i = 0; i != numHandlers; ++i) {
310 hasCatchAll |= s.getHandler(i)->getExceptionDecl() == nullptr;
311 if (hasCatchAll)
312 break;
313 }
314
315 // Create the scope to represent only the C/C++ `try {}` part. However,
316 // don't populate right away. Create regions for the catch handlers,
317 // but don't emit the handler bodies yet. For now, only make sure the
318 // scope returns the exception information.
319 auto tryOp = cir::TryOp::create(
320 builder, tryLoc,
321 /*tryBuilder=*/
322 [&](mlir::OpBuilder &b, mlir::Location loc) {
323 beginInsertTryBody = builder.saveInsertionPoint();
324 },
325 /*handlersBuilder=*/
326 [&](mlir::OpBuilder &b, mlir::Location loc,
327 mlir::OperationState &result) {
328 mlir::OpBuilder::InsertionGuard guard(b);
329
330 // We create an extra region for an unwind catch handler in case the
331 // catch-all handler doesn't exists
332 unsigned numRegionsToCreate =
333 hasCatchAll ? numHandlers : numHandlers + 1;
334
335 for (unsigned i = 0; i != numRegionsToCreate; ++i) {
336 mlir::Region *region = result.addRegion();
337 builder.createBlock(region);
338 }
339 });
340
341 // Finally emit the body for try/catch.
342 {
343 mlir::Location loc = tryOp.getLoc();
344 mlir::OpBuilder::InsertionGuard guard(builder);
345 builder.restoreInsertionPoint(beginInsertTryBody);
346 CIRGenFunction::LexicalScope tryScope{*this, loc,
347 builder.getInsertionBlock()};
348
349 tryScope.setAsTry(tryOp);
350
351 // Attach the basic blocks for the catch regions.
352 enterCXXTryStmt(s, tryOp);
353
354 // Emit the body for the `try {}` part.
355 {
356 mlir::OpBuilder::InsertionGuard guard(builder);
357 CIRGenFunction::LexicalScope tryBodyScope{*this, loc,
358 builder.getInsertionBlock()};
359 if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())
360 return mlir::failure();
361 }
362
363 // Emit catch clauses.
365 }
366
367 return mlir::success();
368}
369
370/// Emit the structure of the dispatch block for the given catch scope.
371/// It is an invariant that the dispatch block already exists.
373 EHCatchScope &catchScope, cir::TryOp tryOp) {
374 if (EHPersonality::get(cgf).isWasmPersonality()) {
375 cgf.cgm.errorNYI("emitCatchDispatchBlock: WasmPersonality");
376 return;
377 }
378
379 if (EHPersonality::get(cgf).usesFuncletPads()) {
380 cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
381 return;
382 }
383
384 assert(std::find_if(catchScope.begin(), catchScope.end(),
385 [](const auto &handler) {
386 return !handler.type.rtti && handler.type.flags != 0;
387 }) == catchScope.end() &&
388 "catch handler without type value or with not supported flags");
389
390 // There was no catch all handler, populate th EH regions for the
391 // enclosing scope.
392 if (!std::prev(catchScope.end())->isCatchAll())
393 cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
394}
395
396void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
397 bool isFnTryBlock) {
398 unsigned numHandlers = s.getNumHandlers();
399 EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);
400 for (unsigned i = 0; i != numHandlers; ++i) {
401 const CXXCatchStmt *catchStmt = s.getHandler(i);
402 mlir::Region *handler = &tryOp.getHandlerRegions()[i];
403 if (catchStmt->getExceptionDecl()) {
404 // FIXME: Dropping the reference type on the type into makes it
405 // impossible to correctly implement catch-by-reference
406 // semantics for pointers. Unfortunately, this is what all
407 // existing compilers do, and it's not clear that the standard
408 // personality routine is capable of doing this right. See C++ DR 388:
409 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
410 Qualifiers caughtTypeQuals;
411 QualType caughtType = cgm.getASTContext().getUnqualifiedArrayType(
412 catchStmt->getCaughtType().getNonReferenceType(), caughtTypeQuals);
413 if (caughtType->isObjCObjectPointerType()) {
414 cgm.errorNYI("enterCXXTryStmt: caughtType ObjCObjectPointerType");
415 return;
416 }
417
418 CatchTypeInfo typeInfo = cgm.getCXXABI().getAddrOfCXXCatchHandlerType(
419 getLoc(catchStmt->getSourceRange()), caughtType,
420 catchStmt->getCaughtType());
421 catchScope->setHandler(i, typeInfo, handler, catchStmt);
422 } else {
423 // No exception decl indicates '...', a catch-all.
424 catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,
425 s.getHandler(i));
426 }
427
428 // Under async exceptions, catch(...) needs to catch HW exception too
429 // Mark scope with SehTryBegin as a SEH __try scope
430 if (getLangOpts().EHAsynch) {
431 cgm.errorNYI("enterCXXTryStmt: EHAsynch");
432 return;
433 }
434 }
435}
436
437void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
438 unsigned numHandlers = s.getNumHandlers();
439 EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());
440 assert(catchScope.getNumHandlers() == numHandlers);
441 cir::TryOp tryOp = curLexScope->getTry();
442
443 // If the catch was not required, bail out now.
444 if (!catchScope.mayThrow()) {
445 catchScope.clearHandlerBlocks();
446 ehStack.popCatch();
447
448 // Drop all basic block from all catch regions.
449 SmallVector<mlir::Block *> eraseBlocks;
450 for (mlir::Region &handlerRegion : tryOp.getHandlerRegions()) {
451 if (handlerRegion.empty())
452 continue;
453
454 for (mlir::Block &b : handlerRegion.getBlocks())
455 eraseBlocks.push_back(&b);
456 }
457
458 for (mlir::Block *b : eraseBlocks)
459 b->erase();
460
461 tryOp.setHandlerTypesAttr({});
462 return;
463 }
464
465 // Emit the structure of the EH dispatch for this catch.
466 emitCatchDispatchBlock(*this, catchScope, tryOp);
467
468 // Copy the handler blocks off before we pop the EH stack. Emitting
469 // the handlers might scribble on this memory.
470 SmallVector<EHCatchScope::Handler> handlers(catchScope.begin(),
471 catchScope.begin() + numHandlers);
472
473 ehStack.popCatch();
474
475 // Determine if we need an implicit rethrow for all these catch handlers;
476 // see the comment below.
477 bool doImplicitRethrow =
479
480 // Wasm uses Windows-style EH instructions, but merges all catch clauses into
481 // one big catchpad. So we save the old funclet pad here before we traverse
482 // each catch handler.
483 if (EHPersonality::get(*this).isWasmPersonality()) {
484 cgm.errorNYI("exitCXXTryStmt: WASM personality");
485 return;
486 }
487
488 bool hasCatchAll = false;
489 for (auto &handler : llvm::reverse(handlers)) {
490 hasCatchAll |= handler.isCatchAll();
491 mlir::Region *catchRegion = handler.region;
492 const CXXCatchStmt *catchStmt = handler.stmt;
493
494 mlir::OpBuilder::InsertionGuard guard(builder);
495 builder.setInsertionPointToStart(&catchRegion->front());
496
497 // Enter a cleanup scope, including the catch variable and the
498 // end-catch.
499 RunCleanupsScope catchScope(*this);
500
501 // Initialize the catch variable and set up the cleanups.
503 cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
504
505 // Emit the PGO counter increment.
507
508 // Perform the body of the catch.
509 [[maybe_unused]] mlir::LogicalResult emitResult =
510 emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
511 assert(emitResult.succeeded() && "failed to emit catch handler block");
512
513 // [except.handle]p11:
514 // The currently handled exception is rethrown if control
515 // reaches the end of a handler of the function-try-block of a
516 // constructor or destructor.
517
518 // It is important that we only do this on fallthrough and not on
519 // return. Note that it's illegal to put a return in a
520 // constructor function-try-block's catch handler (p14), so this
521 // really only applies to destructors.
522 if (doImplicitRethrow) {
523 cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");
524 return;
525 }
526
527 // Fall out through the catch cleanups.
528 catchScope.forceCleanup();
529 }
530
531 // Because in wasm we merge all catch clauses into one big catchpad, in case
532 // none of the types in catch handlers matches after we test against each of
533 // them, we should unwind to the next EH enclosing scope. We generate a call
534 // to rethrow function here to do that.
535 if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {
536 cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");
537 }
538
540}
541
543 assert(ehStack.requiresCatchOrCleanup());
544 assert(!cgm.getLangOpts().IgnoreExceptions &&
545 "LandingPad should not be emitted when -fignore-exceptions are in "
546 "effect.");
547
548 EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());
549 switch (innermostEHScope.getKind()) {
551 cgm.errorNYI("populateCatchHandlers: terminate");
552 return;
553
554 case EHScope::Catch:
555 case EHScope::Cleanup:
556 case EHScope::Filter:
557 // CIR does not cache landing pads.
558 break;
559 }
560
561 // If there's an existing TryOp, it means we got a `cir.try` scope
562 // that leads to this "landing pad" creation site. Otherwise, exceptions
563 // are enabled but a throwing function is called anyways (common pattern
564 // with function local static initializers).
565 mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
566 if (!handlerTypesAttr || handlerTypesAttr.empty()) {
567 // Accumulate all the handlers in scope.
568 bool hasCatchAll = false;
571 for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
572 ++i) {
573 switch (i->getKind()) {
574 case EHScope::Cleanup:
575 cgm.errorNYI("emitLandingPad: Cleanup");
576 return;
577
578 case EHScope::Filter:
579 cgm.errorNYI("emitLandingPad: Filter");
580 return;
581
583 cgm.errorNYI("emitLandingPad: Terminate");
584 return;
585
586 case EHScope::Catch:
587 break;
588 } // end switch
589
590 EHCatchScope &catchScope = cast<EHCatchScope>(*i);
591 for (const EHCatchScope::Handler &handler :
592 llvm::make_range(catchScope.begin(), catchScope.end())) {
593 assert(handler.type.flags == 0 &&
594 "landingpads do not support catch handler flags");
595
596 // If this is a catch-all, register that and abort.
597 if (handler.isCatchAll()) {
598 assert(!hasCatchAll);
599 hasCatchAll = true;
600 break;
601 }
602
603 // Check whether we already have a handler for this type.
604 // If not, keep track to later add to catch op.
605 if (catchTypes.insert(handler.type.rtti).second)
606 handlerAttrs.push_back(handler.type.rtti);
607 }
608
609 if (hasCatchAll)
610 break;
611 }
612
613 if (hasCatchAll)
614 handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
615
617
618 // If there's no catch_all, attach the unwind region. This needs to be the
619 // last region in the TryOp catch list.
620 if (!hasCatchAll)
621 handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
622
623 // Add final array of clauses into TryOp.
624 tryOp.setHandlerTypesAttr(
625 mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
626 }
627
628 // In traditional LLVM codegen. this tells the backend how to generate the
629 // landing pad by generating a branch to the dispatch block. In CIR,
630 // this is used to populate blocks for later filing during
631 // cleanup handling.
632 populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);
633}
634
635// Differently from LLVM traditional codegen, there are no dispatch blocks
636// to look at given cir.try_call does not jump to blocks like invoke does.
637// However.
639 cir::TryOp tryOp) {
640 if (EHPersonality::get(*this).usesFuncletPads()) {
641 cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
642 return;
643 }
644
645 // The dispatch block for the end of the scope chain is a block that
646 // just resumes unwinding.
647 if (scope == ehStack.stable_end()) {
648 populateUnwindResumeBlock(/*isCleanup=*/true, tryOp);
649 return;
650 }
651
652 // Otherwise, we should look at the actual scope.
653 EHScope &ehScope = *ehStack.find(scope);
654 bool mayThrow = ehScope.mayThrow();
655
656 mlir::Block *originalBlock = nullptr;
657 if (mayThrow && tryOp) {
658 // If the dispatch is cached but comes from a different tryOp, make sure:
659 // - Populate current `tryOp` with a new dispatch block regardless.
660 // - Update the map to enqueue new dispatchBlock to also get a cleanup. See
661 // code at the end of the function.
662 cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");
663 return;
664 }
665
666 if (!mayThrow) {
667 switch (ehScope.getKind()) {
668 case EHScope::Catch: {
669 mayThrow = true;
670
671 // LLVM does some optimization with branches here, CIR just keep track of
672 // the corresponding calls.
673 EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
674 if (catchScope.getNumHandlers() == 1 &&
675 catchScope.getHandler(0).isCatchAll()) {
676 break;
677 }
678
679 // TODO(cir): In the incubator we create a new basic block with YieldOp
680 // inside the attached cleanup region, but this part will be redesigned
681 break;
682 }
683 case EHScope::Cleanup: {
684 cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
685 return;
686 }
687 case EHScope::Filter: {
688 cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");
689 return;
690 }
691 case EHScope::Terminate: {
692 cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");
693 return;
694 }
695 }
696 }
697
698 if (originalBlock) {
699 cgm.errorNYI("getEHDispatchBlock: originalBlock");
700 return;
701 }
702
703 ehScope.setMayThrow(mayThrow);
704}
705
706// in classic codegen this function is mapping to `isInvokeDest` previously and
707// currently it's mapping to the conditions that performs early returns in
708// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may
709// throw exception or now.
711 // If exceptions are disabled/ignored and SEH is not in use, then there is no
712 // invoke destination. SEH "works" even if exceptions are off. In practice,
713 // this means that C++ destructors and other EH cleanups don't run, which is
714 // consistent with MSVC's behavior, except in the presence of -EHa
715 const LangOptions &lo = cgm.getLangOpts();
716 if (!lo.Exceptions || lo.IgnoreExceptions) {
717 if (!lo.Borland && !lo.MicrosoftExt)
718 return false;
719 cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
720 return false;
721 }
722
723 // CUDA device code doesn't have exceptions.
724 if (lo.CUDA && lo.CUDAIsDevice)
725 return false;
726
727 return ehStack.requiresCatchOrCleanup();
728}
729
730// In classic codegen this function is equivalent to `getInvokeDestImpl`, in
731// ClangIR we don't need to return to return any landing pad, we just need to
732// populate the catch handlers if they are required
734 assert(ehStack.requiresCatchOrCleanup());
735 assert(!ehStack.empty());
736
737 const EHPersonality &personality = EHPersonality::get(*this);
738
739 // Set personality function if not already set
740 auto funcOp = mlir::cast<cir::FuncOp>(curFn);
741 if (!funcOp.getPersonality())
742 funcOp.setPersonality(getPersonalityFn(cgm, personality));
743
744 // CIR does not cache landing pads.
745 if (personality.usesFuncletPads()) {
746 cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");
747 } else {
749 }
750}
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:8333
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:8478
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:8705
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