clang 24.0.0git
CIRGenStmt.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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// Emit Stmt nodes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenBuilder.h"
14#include "CIRGenFunction.h"
15
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/Location.h"
18#include "mlir/Support/LLVM.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/Stmt.h"
23#include "clang/AST/StmtSYCL.h"
25#include "llvm/Support/SaveAndRestore.h"
26
27using namespace clang;
28using namespace clang::CIRGen;
29using namespace cir;
30
31static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf,
32 const Stmt *exprResult,
33 AggValueSlot slot,
34 Address *lastValue) {
35 // We have to special case labels here. They are statements, but when put
36 // at the end of a statement expression, they yield the value of their
37 // subexpression. Handle this by walking through all labels we encounter,
38 // emitting them before we evaluate the subexpr.
39 // Similar issues arise for attributed statements.
40 while (!isa<Expr>(exprResult)) {
41 if (const auto *ls = dyn_cast<LabelStmt>(exprResult)) {
42 if (cgf.emitLabel(*ls->getDecl()).failed())
43 return mlir::failure();
44 exprResult = ls->getSubStmt();
45 } else if (const auto *as = dyn_cast<AttributedStmt>(exprResult)) {
46 // FIXME: Update this if we ever have attributes that affect the
47 // semantics of an expression.
48 exprResult = as->getSubStmt();
49 } else {
50 llvm_unreachable("Unknown value statement");
51 }
52 }
53
54 const Expr *e = cast<Expr>(exprResult);
55 QualType exprTy = e->getType();
56 if (cgf.hasAggregateEvaluationKind(exprTy)) {
57 cgf.emitAggExpr(e, slot);
58 } else {
59 // We can't return an RValue here because there might be cleanups at
60 // the end of the StmtExpr. Because of that, we have to emit the result
61 // here into a temporary alloca.
62 cgf.emitAnyExprToMem(e, *lastValue, Qualifiers(),
63 /*IsInit*/ false);
64 }
65
66 return mlir::success();
67}
68
70 const CompoundStmt &s, Address *lastValue, AggValueSlot slot) {
71 mlir::LogicalResult result = mlir::success();
72 const Stmt *exprResult = s.body_back();
73 assert((!lastValue || (lastValue && exprResult)) &&
74 "If lastValue is not null then the CompoundStmt must have a "
75 "StmtExprResult");
76
77 for (const Stmt *curStmt : s.body()) {
78 const bool saveResult = lastValue && exprResult == curStmt;
79 if (saveResult) {
80 if (emitStmtWithResult(*this, exprResult, slot, lastValue).failed())
81 result = mlir::failure();
82 } else {
83 if (emitStmt(curStmt, /*useCurrentScope=*/false).failed())
84 result = mlir::failure();
85 }
86 }
87 return result;
88}
89
90mlir::LogicalResult
92
93 bool noinline = inNoInlineAttributedStmt;
94 bool alwaysinline = inAlwaysInlineAttributedStmt;
95 const CallExpr *musttail = mustTailCall;
96
97 for (const Attr *attr : s.getAttrs()) {
98 switch (attr->getKind()) {
99 default:
100 break;
101 case attr::NoMerge:
102 case attr::NoConvergent:
103 case attr::Atomic:
104 case attr::AMDGPUAvailableVisible:
105 case attr::HLSLControlFlowHint:
106 cgm.errorNYI(s.getSourceRange(),
107 "Unimplemented statement attribute: ", attr->getKind());
108 break;
109 case attr::NoInline:
110 noinline = true;
111 alwaysinline = false;
112 break;
113 case attr::AlwaysInline:
114 alwaysinline = true;
115 noinline = false;
116 break;
117 case attr::MustTail: {
118 const Stmt *sub = s.getSubStmt();
119 const ReturnStmt *ret = cast<ReturnStmt>(sub);
120 musttail = cast<CallExpr>(ret->getRetValue()->IgnoreParens());
121 break;
122 }
123 case attr::CXXAssume: {
124 const Expr *assumptionExpr = cast<CXXAssumeAttr>(attr)->getAssumption();
125 if (getLangOpts().CXXAssumptions && builder.getInsertionBlock() &&
126 !assumptionExpr->HasSideEffects(getContext())) {
127 mlir::Value assumptionValue = emitCheckedArgForAssume(assumptionExpr);
128 cir::AssumeOp::create(builder, getLoc(s.getSourceRange()),
129 assumptionValue, cir::AssumeBundleKind::None,
130 mlir::ValueRange{});
131 }
132 } break;
133 }
134 }
135
136 assert(!(alwaysinline && noinline) &&
137 "alwaysinline and noinline are mutually exclusive");
138
139 SaveAndRestore save_noinline(inNoInlineAttributedStmt, noinline);
140 SaveAndRestore save_alwaysinline(inAlwaysInlineAttributedStmt, alwaysinline);
141
142 SaveAndRestore save_musttail(mustTailCall, musttail);
143
144 return emitStmt(s.getSubStmt(), /*useCurrentScope=*/true, s.getAttrs());
145}
146
148 Address *lastValue,
149 AggValueSlot slot) {
150 // Add local scope to track new declared variables.
152 mlir::Location scopeLoc = getLoc(s.getSourceRange());
153 mlir::OpBuilder::InsertPoint scopeInsPt;
154 cir::ScopeOp::create(
155 builder, scopeLoc,
156 [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
157 scopeInsPt = b.saveInsertionPoint();
158 });
159 mlir::OpBuilder::InsertionGuard guard(builder);
160 builder.restoreInsertionPoint(scopeInsPt);
161 LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
162 return emitCompoundStmtWithoutScope(s, lastValue, slot);
163}
164
168
169// Build CIR for a statement. useCurrentScope should be true if no new scopes
170// need to be created when finding a compound statement.
171mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
172 bool useCurrentScope,
174 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
175 return mlir::success();
176
177 switch (s->getStmtClass()) {
179 case Stmt::CXXCatchStmtClass:
180 case Stmt::SEHExceptStmtClass:
181 case Stmt::SEHFinallyStmtClass:
182 case Stmt::MSDependentExistsStmtClass:
183 case Stmt::UnresolvedSYCLKernelCallStmtClass:
184 llvm_unreachable("invalid statement class to emit generically");
185 case Stmt::BreakStmtClass:
186 case Stmt::NullStmtClass:
187 case Stmt::CompoundStmtClass:
188 case Stmt::ContinueStmtClass:
189 case Stmt::DeclStmtClass:
190 case Stmt::ReturnStmtClass:
191 llvm_unreachable("should have emitted these statements as simple");
192
193#define STMT(Type, Base)
194#define ABSTRACT_STMT(Op)
195#define EXPR(Type, Base) case Stmt::Type##Class:
196#include "clang/AST/StmtNodes.inc"
197 {
198 assert(builder.getInsertionBlock() &&
199 "expression emission must have an insertion point");
200
202
203 // Classic codegen has a check here to see if the emitter created a new
204 // block that isn't used (comparing the incoming and outgoing insertion
205 // points) and deletes the outgoing block if it's not used. In CIR, we
206 // will handle that during the cir.canonicalize pass.
207 return mlir::success();
208 }
209 case Stmt::IfStmtClass:
210 return emitIfStmt(cast<IfStmt>(*s));
211 case Stmt::SwitchStmtClass:
213 case Stmt::ForStmtClass:
214 return emitForStmt(cast<ForStmt>(*s));
215 case Stmt::WhileStmtClass:
216 return emitWhileStmt(cast<WhileStmt>(*s));
217 case Stmt::DoStmtClass:
218 return emitDoStmt(cast<DoStmt>(*s));
219 case Stmt::CXXTryStmtClass:
221 case Stmt::CXXForRangeStmtClass:
223 case Stmt::CoroutineBodyStmtClass:
225 case Stmt::IndirectGotoStmtClass:
227 case Stmt::CoreturnStmtClass:
229 case Stmt::SYCLKernelCallStmtClass:
231 case Stmt::OpenACCComputeConstructClass:
233 case Stmt::OpenACCLoopConstructClass:
235 case Stmt::OpenACCCombinedConstructClass:
237 case Stmt::OpenACCDataConstructClass:
239 case Stmt::OpenACCEnterDataConstructClass:
241 case Stmt::OpenACCExitDataConstructClass:
243 case Stmt::OpenACCHostDataConstructClass:
245 case Stmt::OpenACCWaitConstructClass:
247 case Stmt::OpenACCInitConstructClass:
249 case Stmt::OpenACCShutdownConstructClass:
251 case Stmt::OpenACCSetConstructClass:
253 case Stmt::OpenACCUpdateConstructClass:
255 case Stmt::OpenACCCacheConstructClass:
257 case Stmt::OpenACCAtomicConstructClass:
259 case Stmt::GCCAsmStmtClass:
260 case Stmt::MSAsmStmtClass:
261 return emitAsmStmt(cast<AsmStmt>(*s));
262 case Stmt::OMPScopeDirectiveClass:
264 case Stmt::OMPErrorDirectiveClass:
266 case Stmt::OMPParallelDirectiveClass:
268 case Stmt::OMPTaskwaitDirectiveClass:
270 case Stmt::OMPTaskyieldDirectiveClass:
272 case Stmt::OMPBarrierDirectiveClass:
274 case Stmt::OMPMetaDirectiveClass:
276 case Stmt::OMPCanonicalLoopClass:
278 case Stmt::OMPSimdDirectiveClass:
280 case Stmt::OMPTileDirectiveClass:
282 case Stmt::OMPUnrollDirectiveClass:
284 case Stmt::OMPFuseDirectiveClass:
286 case Stmt::OMPForDirectiveClass:
288 case Stmt::OMPForSimdDirectiveClass:
290 case Stmt::OMPSectionsDirectiveClass:
292 case Stmt::OMPSectionDirectiveClass:
294 case Stmt::OMPSingleDirectiveClass:
296 case Stmt::OMPMasterDirectiveClass:
298 case Stmt::OMPCriticalDirectiveClass:
300 case Stmt::OMPParallelForDirectiveClass:
302 case Stmt::OMPParallelForSimdDirectiveClass:
305 case Stmt::OMPParallelMasterDirectiveClass:
307 case Stmt::OMPParallelSectionsDirectiveClass:
310 case Stmt::OMPTaskDirectiveClass:
312 case Stmt::OMPTaskgroupDirectiveClass:
314 case Stmt::OMPFlushDirectiveClass:
316 case Stmt::OMPDepobjDirectiveClass:
318 case Stmt::OMPScanDirectiveClass:
320 case Stmt::OMPOrderedStandaloneDirectiveClass:
323 case Stmt::OMPOrderedBlockAssocDirectiveClass:
326 case Stmt::OMPAtomicDirectiveClass:
328 case Stmt::OMPTargetDirectiveClass:
330 case Stmt::OMPTeamsDirectiveClass:
332 case Stmt::OMPCancellationPointDirectiveClass:
335 case Stmt::OMPCancelDirectiveClass:
337 case Stmt::OMPTargetDataDirectiveClass:
339 case Stmt::OMPTargetEnterDataDirectiveClass:
342 case Stmt::OMPTargetExitDataDirectiveClass:
344 case Stmt::OMPTargetParallelDirectiveClass:
346 case Stmt::OMPTargetParallelForDirectiveClass:
349 case Stmt::OMPTaskLoopDirectiveClass:
351 case Stmt::OMPTaskLoopSimdDirectiveClass:
353 case Stmt::OMPMaskedTaskLoopDirectiveClass:
355 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
358 case Stmt::OMPMasterTaskLoopDirectiveClass:
360 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
363 case Stmt::OMPParallelGenericLoopDirectiveClass:
366 case Stmt::OMPParallelMaskedDirectiveClass:
368 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
371 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
374 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
377 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
380 case Stmt::OMPDistributeDirectiveClass:
382 case Stmt::OMPDistributeParallelForDirectiveClass:
385 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
388 case Stmt::OMPDistributeSimdDirectiveClass:
390 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
393 case Stmt::OMPTargetParallelForSimdDirectiveClass:
396 case Stmt::OMPTargetSimdDirectiveClass:
398 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
401 case Stmt::OMPTargetUpdateDirectiveClass:
403 case Stmt::OMPTeamsDistributeDirectiveClass:
406 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
409 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
412 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
415 case Stmt::OMPTeamsGenericLoopDirectiveClass:
418 case Stmt::OMPTargetTeamsDirectiveClass:
420 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
423 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
426 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
429 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
432 case Stmt::OMPInteropDirectiveClass:
434 case Stmt::OMPDispatchDirectiveClass:
436 case Stmt::OMPGenericLoopDirectiveClass:
438 case Stmt::OMPReverseDirectiveClass:
440 case Stmt::OMPSplitDirectiveClass:
442 case Stmt::OMPInterchangeDirectiveClass:
444 case Stmt::OMPAssumeDirectiveClass:
446 case Stmt::OMPMaskedDirectiveClass:
448 case Stmt::OMPStripeDirectiveClass:
450 case Stmt::LabelStmtClass:
451 case Stmt::AttributedStmtClass:
452 case Stmt::GotoStmtClass:
453 case Stmt::DefaultStmtClass:
454 case Stmt::CaseStmtClass:
455 case Stmt::SEHLeaveStmtClass:
456 case Stmt::ObjCAtTryStmtClass:
457 case Stmt::ObjCAtThrowStmtClass:
458 case Stmt::ObjCAtSynchronizedStmtClass:
459 case Stmt::ObjCForCollectionStmtClass:
460 case Stmt::ObjCAutoreleasePoolStmtClass:
461 case Stmt::SEHTryStmtClass:
462 case Stmt::ObjCAtCatchStmtClass:
463 case Stmt::ObjCAtFinallyStmtClass:
464 case Stmt::DeferStmtClass:
465 case Stmt::CXXExpansionStmtPatternClass:
466 case Stmt::CXXExpansionStmtInstantiationClass:
467 cgm.errorNYI(s->getSourceRange(),
468 std::string("emitStmt: ") + s->getStmtClassName());
469 return mlir::failure();
470 case Stmt::CapturedStmtClass:
471 llvm_unreachable("CapturedStmt must be handled by the parent directive");
472 }
473
474 llvm_unreachable("Unexpected statement class");
475}
476
477mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
478 bool useCurrentScope) {
479 switch (s->getStmtClass()) {
480 default:
481 return mlir::failure();
482 case Stmt::DeclStmtClass:
483 return emitDeclStmt(cast<DeclStmt>(*s));
484 case Stmt::CompoundStmtClass:
485 if (useCurrentScope)
488 case Stmt::GotoStmtClass:
489 return emitGotoStmt(cast<GotoStmt>(*s));
490 case Stmt::ContinueStmtClass:
492
493 // NullStmt doesn't need any handling, but we need to say we handled it.
494 case Stmt::NullStmtClass:
495 break;
496
497 case Stmt::LabelStmtClass:
498 return emitLabelStmt(cast<LabelStmt>(*s));
499 case Stmt::CaseStmtClass:
500 case Stmt::DefaultStmtClass:
501 // If we reached here, we must not handling a switch case in the top level.
503 /*buildingTopLevelCase=*/false);
504 break;
505
506 case Stmt::BreakStmtClass:
507 return emitBreakStmt(cast<BreakStmt>(*s));
508 case Stmt::ReturnStmtClass:
510 case Stmt::AttributedStmtClass:
512 }
513
514 return mlir::success();
515}
516
517mlir::LogicalResult CIRGenFunction::emitLabelStmt(const clang::LabelStmt &s) {
518
519 if (emitLabel(*s.getDecl()).failed())
520 return mlir::failure();
521
522 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())
523 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");
524
525 return emitStmt(s.getSubStmt(), /*useCurrentScope*/ true);
526}
527
528// Add a terminating yield on a body region if no other terminators are used.
530 mlir::Location loc) {
531 if (r.empty())
532 return;
533
535 unsigned numBlocks = r.getBlocks().size();
536 for (auto &block : r.getBlocks()) {
537 // Already cleanup after return operations, which might create
538 // empty blocks if emitted as last stmt.
539 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
540 block.hasNoSuccessors())
541 eraseBlocks.push_back(&block);
542
543 if (block.empty() ||
544 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
545 mlir::OpBuilder::InsertionGuard guardCase(builder);
546 builder.setInsertionPointToEnd(&block);
547 builder.createYield(loc);
548 }
549 }
550
551 for (auto *b : eraseBlocks)
552 b->erase();
553}
554
555mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
556 mlir::LogicalResult res = mlir::success();
557 // The else branch of a consteval if statement is always the only branch
558 // that can be runtime evaluated.
559 const Stmt *constevalExecuted;
560 if (s.isConsteval()) {
561 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
562 if (!constevalExecuted) {
563 // No runtime code execution required
564 return res;
565 }
566 }
567
568 // C99 6.8.4.1: The first substatement is executed if the expression
569 // compares unequal to 0. The condition must be a scalar type.
570 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
571 if (s.isConsteval())
572 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
573
574 if (s.getInit())
575 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
576 return mlir::failure();
577
578 if (s.getConditionVariable())
580
581 // If the condition folds to a constant and this is an 'if constexpr',
582 // we simplify it early in CIRGen to avoid emitting the full 'if'.
583 bool condConstant;
584 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
585 if (s.isConstexpr()) {
586 // Handle "if constexpr" explicitly here to avoid generating some
587 // ill-formed code since in CIR the "if" is no longer simplified
588 // in this lambda like in Clang but postponed to other MLIR
589 // passes.
590 if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())
591 return emitStmt(executed, /*useCurrentScope=*/true);
592 // There is nothing to execute at runtime.
593 // TODO(cir): there is still an empty cir.scope generated by the caller.
594 return mlir::success();
595 }
596 }
597
600 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
601 };
602
603 // TODO: Add a new scoped symbol table.
604 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
605 // The if scope contains the full source range for IfStmt.
606 mlir::Location scopeLoc = getLoc(s.getSourceRange());
607 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
608 [&](mlir::OpBuilder &b, mlir::Location loc) {
609 LexicalScope lexScope{*this, scopeLoc,
610 builder.getInsertionBlock()};
611 res = ifStmtBuilder();
612 });
613
614 return res;
615}
616
617mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
618 assert(builder.getInsertionBlock() && "expected valid insertion point");
619
620 for (const Decl *i : s.decls())
621 emitDecl(*i, /*evaluateConditionDecl=*/true);
622
623 return mlir::success();
624}
625
626mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
627 mlir::Location loc = getLoc(s.getSourceRange());
628 const Expr *rv = s.getRetValue();
629
630 RunCleanupsScope cleanupScope(*this);
631 bool createNewScope = false;
632 if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) {
633 rv = ewc->getSubExpr();
634 createNewScope = true;
635 }
636
637 auto handleReturnVal = [&]() {
638 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
641 // Apply the named return value optimization for this return statement,
642 // which means doing nothing: the appropriate result has already been
643 // constructed into the NRVO variable.
644
645 // If there is an NRVO flag for this variable, set it to 1 into indicate
646 // that the cleanup code should not destroy the variable.
647 if (auto nrvoFlag = nrvoFlags[s.getNRVOCandidate()])
648 builder.createFlagStore(loc, true, nrvoFlag);
649 } else if (!rv) {
650 // No return expression. Do nothing.
651 } else if (rv->getType()->isVoidType()) {
652 // Make sure not to return anything, but evaluate the expression
653 // for side effects.
654 if (rv) {
655 emitAnyExpr(rv);
656 }
657 } else if (cast<FunctionDecl>(curGD.getDecl())
658 ->getReturnType()
659 ->isReferenceType()) {
660 // If this function returns a reference, take the address of the
661 // expression rather than the value.
663 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(),
664 *fnRetAlloca);
665 } else {
666 mlir::Value value = nullptr;
668 case cir::TEK_Scalar:
669 value = emitScalarExpr(rv);
670 if (value) { // Change this to an assert once emitScalarExpr is complete
671 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
672 }
673 break;
674 case cir::TEK_Complex:
677 /*isInit=*/true);
678 break;
685 break;
686 }
687 }
688 };
689
690 if (!createNewScope) {
691 handleReturnVal();
692 } else {
693 FullExprCleanupScope fullExprScope(*this, rv);
694 handleReturnVal();
695 }
696
697 cleanupScope.forceCleanup();
698
699 // Classic codegen emits a branch through any cleanups before continuing to
700 // a shared return block. Because CIR handles branching through cleanups
701 // during the CFG flattening phase, we can just emit the return statement
702 // directly.
703 // TODO(cir): Eliminate this redundant load and the store above when we can.
704 if (fnRetAlloca) {
705 // Load the value from `__retval` and return it via the `cir.return` op.
706 cir::AllocaOp retAlloca =
707 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
708 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
709 *fnRetAlloca);
710
711 cir::ReturnOp::create(builder, loc, {value});
712 } else {
713 cir::ReturnOp::create(builder, loc);
714 }
715
716 // Insert the new block to continue codegen after the return statement.
717 // This will get deleted if we don't populate it. This handles the case of
718 // unreachable statements below a return.
719 builder.createBlock(builder.getBlock()->getParent());
720 return mlir::success();
721}
722
723mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
724 // FIXME: LLVM codegen inserts emit a stop point here for debug info
725 // sake when the insertion point is available, but doesn't do
726 // anything special when there isn't. We haven't implemented debug
727 // info support just yet, look at this again once we have it.
729
730 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),
731 s.getLabel()->getName());
732
733 // A goto marks the end of a block, create a new one for codegen after
734 // emitGotoStmt can resume building in that block.
735 // Insert the new block to continue codegen after goto.
736 builder.createBlock(builder.getBlock()->getParent());
737
738 return mlir::success();
739}
740
741mlir::LogicalResult
743 // An indirect goto with an active cleanup may leave its scope. Determining
744 // whether its dynamic destination requires cleanup is not implemented.
745 if (ehStack.stable_begin() != prologueCleanupDepth) {
746 cgm.errorNYI(s.getSourceRange(), "indirect goto with active cleanup");
747 return mlir::success();
748 }
749
750 mlir::Value val = emitScalarExpr(s.getTarget());
751 // Emit a symbolic indirect goto. GotoSolver resolves it into the shared
752 // indirect-branch block after FlattenCFG merges regions, so this stays valid
753 // even when the goto sits inside a nested scope.
754 cir::IndirectGotoOp::create(builder, getLoc(s.getSourceRange()), val);
755
756 // The indirect goto ends the block; open a fresh one so codegen can resume.
757 builder.createBlock(builder.getBlock()->getParent());
758 return mlir::success();
759}
760
761mlir::LogicalResult
763 builder.createContinue(getLoc(s.getKwLoc()));
764
765 // Insert the new block to continue codegen after the continue statement.
766 builder.createBlock(builder.getBlock()->getParent());
767
768 return mlir::success();
769}
770
771mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
772 // Create a new block to tag with a label and add a branch from
773 // the current one to it. If the block is empty just call attach it
774 // to this label.
775 mlir::Block *currBlock = builder.getBlock();
776 mlir::Block *labelBlock = currBlock;
777
778 if (!currBlock->empty() || currBlock->isEntryBlock()) {
779 {
780 mlir::OpBuilder::InsertionGuard guard(builder);
781 labelBlock = builder.createBlock(builder.getBlock()->getParent());
782 }
783 cir::BrOp::create(builder, getLoc(d.getSourceRange()), labelBlock);
784 }
785
786 builder.setInsertionPointToEnd(labelBlock);
787 cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
788 // FIXME: emit debug info for labels, incrementProfileCounter
791 return mlir::success();
792}
793
794mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
795 builder.createBreak(getLoc(s.getKwLoc()));
796
797 // Insert the new block to continue codegen after the break statement.
798 builder.createBlock(builder.getBlock()->getParent());
799
800 return mlir::success();
801}
802
803template <typename T>
804mlir::LogicalResult
806 mlir::ArrayAttr value, CaseOpKind kind,
807 bool buildingTopLevelCase) {
808
810 "only case or default stmt go here");
811
812 mlir::LogicalResult result = mlir::success();
813
814 mlir::Location loc = getLoc(stmt->getBeginLoc());
815
816 enum class SubStmtKind { Case, Default, Other };
817 SubStmtKind subStmtKind = SubStmtKind::Other;
818 const Stmt *sub = stmt->getSubStmt();
819
820 mlir::OpBuilder::InsertPoint insertPoint;
821 CaseOp::create(builder, loc, value, kind, insertPoint);
822
823 {
824 mlir::OpBuilder::InsertionGuard guardSwitch(builder);
825 builder.restoreInsertionPoint(insertPoint);
826
827 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
828 subStmtKind = SubStmtKind::Default;
829 builder.createYield(loc);
830 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
831 subStmtKind = SubStmtKind::Case;
832 builder.createYield(loc);
833 } else {
834 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
835 }
836
837 insertPoint = builder.saveInsertionPoint();
838 }
839
840 // If the substmt is default stmt or case stmt, try to handle the special case
841 // to make it into the simple form. e.g.
842 //
843 // switch () {
844 // case 1:
845 // default:
846 // ...
847 // }
848 //
849 // we prefer generating
850 //
851 // cir.switch() {
852 // cir.case(equal, 1) {
853 // cir.yield
854 // }
855 // cir.case(default) {
856 // ...
857 // }
858 // }
859 //
860 // than
861 //
862 // cir.switch() {
863 // cir.case(equal, 1) {
864 // cir.case(default) {
865 // ...
866 // }
867 // }
868 // }
869 //
870 // We don't need to revert this if we find the current switch can't be in
871 // simple form later since the conversion itself should be harmless.
872 if (subStmtKind == SubStmtKind::Case) {
873 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
874 } else if (subStmtKind == SubStmtKind::Default) {
875 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
876 buildingTopLevelCase);
877 } else if (buildingTopLevelCase) {
878 // If we're building a top level case, try to restore the insert point to
879 // the case we're building, then we can attach more random stmts to the
880 // case to make generating `cir.switch` operation to be a simple form.
881 builder.restoreInsertionPoint(insertPoint);
882 }
883
884 return result;
885}
886
887mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
888 mlir::Type condType,
889 bool buildingTopLevelCase) {
890 cir::CaseOpKind kind;
891 mlir::ArrayAttr value;
892 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
893
894 // Coerce a bool to an i1 for a switch, so we can just treat all its elements
895 // as an int later on.
896 if (isa<cir::BoolType>(condType))
897 condType = builder.getUIntNTy(1);
898
899 // If the case statement has an RHS value, it is representing a GNU
900 // case range statement, where LHS is the beginning of the range
901 // and RHS is the end of the range.
902 if (const Expr *rhs = s.getRHS()) {
903 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
904 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
905 cir::IntAttr::get(condType, endVal)});
906 kind = cir::CaseOpKind::Range;
907 } else {
908 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
909 kind = cir::CaseOpKind::Equal;
910 }
911
912 return emitCaseDefaultCascade(&s, condType, value, kind,
913 buildingTopLevelCase);
914}
915
917 mlir::Type condType,
918 bool buildingTopLevelCase) {
919 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
920 cir::CaseOpKind::Default, buildingTopLevelCase);
921}
922
923mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
924 bool buildingTopLevelCase) {
925 assert(!condTypeStack.empty() &&
926 "build switch case without specifying the type of the condition");
927
928 if (s.getStmtClass() == Stmt::CaseStmtClass)
929 return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
930 buildingTopLevelCase);
931
932 if (s.getStmtClass() == Stmt::DefaultStmtClass)
934 buildingTopLevelCase);
935
936 llvm_unreachable("expect case or default stmt");
937}
938
939mlir::LogicalResult
941 ArrayRef<const Attr *> forAttrs) {
942 cir::ForOp forOp;
943
944 // TODO(cir): pass in array of attributes.
945 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
946 mlir::LogicalResult loopRes = mlir::success();
947 // Evaluate the first pieces before the loop.
948 if (s.getInit())
949 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
950 return mlir::failure();
951 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
952 return mlir::failure();
953 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
954 return mlir::failure();
955 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
956 return mlir::failure();
957
959
960 forOp = builder.createFor(
962 /*condBuilder=*/
963 [&](mlir::OpBuilder &b, mlir::Location loc) {
964 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
965 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
966 mlir::Value condVal = evaluateExprAsBool(s.getCond());
967 builder.createCondition(condVal);
968 },
969 /*bodyBuilder=*/
970 [&](mlir::OpBuilder &b, mlir::Location loc) {
971 // https://en.cppreference.com/w/cpp/language/for
972 // In C++ the scope of the init-statement and the scope of
973 // statement are one and the same.
974 RunCleanupsScope bodyScope(*this);
975 bool useCurrentScope = true;
976 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
977 loopRes = mlir::failure();
978 if (emitStmt(s.getBody(), useCurrentScope).failed())
979 loopRes = mlir::failure();
980 emitStopPoint(&s);
981 },
982 /*stepBuilder=*/
983 [&](mlir::OpBuilder &b, mlir::Location loc) {
984 if (s.getInc())
985 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
986 loopRes = mlir::failure();
987 builder.createYield(loc);
988 });
989 return loopRes;
990 };
991
992 mlir::LogicalResult res = mlir::success();
993 mlir::Location scopeLoc = getLoc(s.getSourceRange());
994 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
995 [&](mlir::OpBuilder &b, mlir::Location loc) {
996 // Create a cleanup scope for the condition
997 // variable cleanups. Logical equivalent from
998 // LLVM codegn for LexicalScope
999 // ConditionScope(*this, S.getSourceRange())...
1000 LexicalScope lexScope{*this, loc,
1001 builder.getInsertionBlock()};
1002 res = forStmtBuilder();
1003 });
1004
1005 if (res.failed())
1006 return res;
1007
1008 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1009 return mlir::success();
1010}
1011
1012mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
1013 cir::ForOp forOp;
1014
1015 // TODO: pass in an array of attributes.
1016 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
1017 mlir::LogicalResult loopRes = mlir::success();
1018 // Evaluate the first part before the loop.
1019 if (s.getInit())
1020 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1021 return mlir::failure();
1023
1024 // If the condition variable has a non-trivial destructor, its lifetime is
1025 // a single iteration, so capture its cleanup and emit it into the loop's
1026 // per-iteration cleanup region. This scope is constructed after the
1027 // init-statement so its cleanups are not captured.
1028 const VarDecl *condVar = s.getConditionVariable();
1029 bool needsCondCleanup =
1030 condVar && condVar->needsDestruction(getContext()) != QualType::DK_none;
1031 // We will also need cleanup if lifetime markers are enabled.
1033 DeferredLoopConditionCleanup loopCondScope(*this, needsCondCleanup);
1034
1035 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1038 mlir::Value condVal;
1039 if (s.getCond()) {
1040 // If the for statement declares a condition variable, emit that here.
1041 if (condVar)
1042 emitLoopConditionVariable(*condVar, loopCondScope);
1043 // C99 6.8.5p2/p4: The first substatement is executed if the
1044 // expression compares unequal to 0. The condition must be a
1045 // scalar type.
1046 condVal = evaluateExprAsBool(s.getCond());
1047 } else {
1048 condVal = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
1049 }
1050 builder.createCondition(condVal);
1051 };
1052 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1053 // The scope of the for loop body is nested within the scope of the
1054 // for loop's init-statement and condition.
1055 RunCleanupsScope bodyScope(*this);
1056 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1057 loopRes = mlir::failure();
1058 emitStopPoint(&s);
1059 };
1060 auto stepBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1061 if (s.getInc())
1062 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
1063 loopRes = mlir::failure();
1064 builder.createYield(loc);
1065 };
1066
1067 if (needsCondCleanup) {
1068 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1069 ? cir::CleanupKind::All
1070 : cir::CleanupKind::Normal;
1071 forOp = builder.createFor(
1072 getLoc(s.getSourceRange()), condBuilder, bodyBuilder, stepBuilder,
1073 /*cleanupBuilder=*/
1074 [&](mlir::OpBuilder &b, mlir::Location loc) {
1075 loopCondScope.emitIntoLoopCleanupRegion(loc);
1076 builder.createYield(loc);
1077 },
1078 cleanupKind);
1079 } else {
1080 forOp = builder.createFor(getLoc(s.getSourceRange()), condBuilder,
1081 bodyBuilder, stepBuilder);
1082 }
1083 return loopRes;
1084 };
1085
1086 auto res = mlir::success();
1087 auto scopeLoc = getLoc(s.getSourceRange());
1088 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1089 [&](mlir::OpBuilder &b, mlir::Location loc) {
1090 LexicalScope lexScope{*this, loc,
1091 builder.getInsertionBlock()};
1092 res = forStmtBuilder();
1093 });
1094
1095 if (res.failed())
1096 return res;
1097
1098 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1099 return mlir::success();
1100}
1101
1102mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
1103 cir::DoWhileOp doWhileOp;
1104
1105 // TODO: pass in array of attributes.
1106 auto doStmtBuilder = [&]() -> mlir::LogicalResult {
1107 mlir::LogicalResult loopRes = mlir::success();
1109
1110 doWhileOp = builder.createDoWhile(
1112 /*condBuilder=*/
1113 [&](mlir::OpBuilder &b, mlir::Location loc) {
1114 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
1115 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
1116 // C99 6.8.5p2/p4: The first substatement is executed if the
1117 // expression compares unequal to 0. The condition must be a
1118 // scalar type.
1119 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1120 builder.createCondition(condVal);
1121 },
1122 /*bodyBuilder=*/
1123 [&](mlir::OpBuilder &b, mlir::Location loc) {
1124 // The scope of the do-while loop body is a nested scope.
1125 RunCleanupsScope bodyScope(*this);
1126 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1127 loopRes = mlir::failure();
1128 emitStopPoint(&s);
1129 });
1130 return loopRes;
1131 };
1132
1133 mlir::LogicalResult res = mlir::success();
1134 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1135 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1136 [&](mlir::OpBuilder &b, mlir::Location loc) {
1137 LexicalScope lexScope{*this, loc,
1138 builder.getInsertionBlock()};
1139 res = doStmtBuilder();
1140 });
1141
1142 if (res.failed())
1143 return res;
1144
1145 terminateStructuredRegionBody(doWhileOp.getBody(), getLoc(s.getEndLoc()));
1146 return mlir::success();
1147}
1148
1149mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
1150 cir::WhileOp whileOp;
1151
1152 // TODO: pass in array of attributes.
1153 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
1154 mlir::LogicalResult loopRes = mlir::success();
1156
1157 // If the condition variable has a non-trivial destructor, its lifetime is
1158 // a single iteration, so capture its cleanup and emit it into the loop's
1159 // per-iteration cleanup region.
1160 const VarDecl *condVar = s.getConditionVariable();
1161 bool needsCondCleanup =
1162 condVar && condVar->needsDestruction(getContext()) != QualType::DK_none;
1163 // We will also need cleanup if lifetime markers are enabled.
1165 DeferredLoopConditionCleanup loopCondScope(*this, needsCondCleanup);
1166
1167 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1170 // If the while statement declares a condition variable, emit that here.
1171 if (condVar)
1172 emitLoopConditionVariable(*condVar, loopCondScope);
1173 // C99 6.8.5p2/p4: The first substatement is executed if the
1174 // expression compares unequal to 0. The condition must be a
1175 // scalar type.
1176 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1177 builder.createCondition(condVal);
1178 };
1179 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1180 // The scope of the while loop body is a nested scope.
1181 RunCleanupsScope bodyScope(*this);
1182 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1183 loopRes = mlir::failure();
1184 emitStopPoint(&s);
1185 };
1186
1187 if (needsCondCleanup) {
1188 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1189 ? cir::CleanupKind::All
1190 : cir::CleanupKind::Normal;
1191 whileOp = builder.createWhile(
1192 getLoc(s.getSourceRange()), condBuilder, bodyBuilder,
1193 /*cleanupBuilder=*/
1194 [&](mlir::OpBuilder &b, mlir::Location loc) {
1195 loopCondScope.emitIntoLoopCleanupRegion(loc);
1196 builder.createYield(loc);
1197 },
1198 cleanupKind);
1199 } else {
1200 whileOp = builder.createWhile(getLoc(s.getSourceRange()), condBuilder,
1201 bodyBuilder);
1202 }
1203 return loopRes;
1204 };
1205
1206 mlir::LogicalResult res = mlir::success();
1207 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1208 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1209 [&](mlir::OpBuilder &b, mlir::Location loc) {
1210 LexicalScope lexScope{*this, loc,
1211 builder.getInsertionBlock()};
1212 res = whileStmtBuilder();
1213 });
1214
1215 if (res.failed())
1216 return res;
1217
1218 terminateStructuredRegionBody(whileOp.getBody(), getLoc(s.getEndLoc()));
1219 return mlir::success();
1220}
1221
1222mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
1223 // It is rare but legal if the switch body is not a compound stmt. e.g.,
1224 //
1225 // switch(a)
1226 // while(...) {
1227 // case1
1228 // ...
1229 // case2
1230 // ...
1231 // }
1232 if (!isa<CompoundStmt>(s))
1233 return emitStmt(s, /*useCurrentScope=*/true);
1234
1236
1237 ArrayRef<Stmt *> body{compoundStmt->body_begin(), compoundStmt->body_end()};
1238
1239 mlir::Block *switchBlock = builder.getBlock();
1240
1241 // Any statements appearing before the first case statement are 'unassociated'
1242 // with anything. So we have to create them FIRST in their own block. After
1243 // that, the 'case' regions will take care of future ones.
1244 if (!body.empty() && !isa<SwitchCase>(body.front())) {
1245 builder.setInsertionPointToEnd(switchBlock);
1246 {
1247 // This is needed to handle cleanups in a compound statement before the
1248 // first case statement.
1249 RunCleanupsScope preCaseScope(*this);
1250 while (!body.empty() && !isa<SwitchCase>(body.front())) {
1251
1252 auto *c = body.front();
1253 if (mlir::failed(
1254 emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1255 return mlir::failure();
1256
1257 body = body.drop_front();
1258 }
1259 }
1260
1261 // Now that we've emitted ALL of the statements, we can create a new block
1262 // for the actual case statements/etc to appear.
1263 mlir::Block *lastBlock = builder.getBlock();
1264 switchBlock = builder.createBlock(switchBlock->getParent());
1265 builder.setInsertionPointToEnd(lastBlock);
1266 cir::BrOp::create(builder, getLoc(s->getSourceRange()), switchBlock);
1267 }
1268
1269 for (auto *c : body) {
1270 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
1271 builder.setInsertionPointToEnd(switchBlock);
1272 // Reset insert point automatically, so that we can attach following
1273 // random stmt to the region of previous built case op to try to make
1274 // the being generated `cir.switch` to be in simple form.
1275 if (mlir::failed(
1276 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
1277 return mlir::failure();
1278
1279 continue;
1280 }
1281
1282 // Otherwise, just build the statements in the nearest case region.
1283 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1284 return mlir::failure();
1285 }
1286
1287 return mlir::success();
1288}
1289
1291 // TODO: LLVM codegen does some early optimization to fold the condition and
1292 // only emit live cases. CIR should use MLIR to achieve similar things,
1293 // nothing to be done here.
1294 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
1296
1297 SwitchOp swop;
1298 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
1299 if (s.getInit())
1300 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1301 return mlir::failure();
1302
1303 if (s.getConditionVariable())
1304 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
1305
1306 mlir::Value condV = emitScalarExpr(s.getCond());
1307
1308 // Coerce bool values to an i1. There is no real sensible reason we need to
1309 // represent a 'switch' of scoped-enum-with-bool-backing-type specially
1310 // here. It is a rarely used thing, and would result in a lot of work to
1311 // properly handle this everywhere.
1312 if (isa<cir::BoolType>(condV.getType()))
1313 condV = builder.createBoolToInt(condV, builder.getUIntNTy(1));
1314
1315 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
1318 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
1320
1321 mlir::LogicalResult res = mlir::success();
1322 swop = SwitchOp::create(
1323 builder, getLoc(s.getBeginLoc()), condV,
1324 /*switchBuilder=*/
1325 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
1326 curLexScope->setAsSwitch();
1327
1328 condTypeStack.push_back(condV.getType());
1329
1330 res = emitSwitchBody(s.getBody());
1331
1332 condTypeStack.pop_back();
1333 });
1334
1335 return res;
1336 };
1337
1338 // The switch scope contains the full source range for SwitchStmt.
1339 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1340 mlir::LogicalResult res = mlir::success();
1341 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1342 [&](mlir::OpBuilder &b, mlir::Location loc) {
1343 LexicalScope lexScope{*this, loc,
1344 builder.getInsertionBlock()};
1345 res = switchStmtBuilder();
1346 });
1347
1349 swop.collectCases(cases);
1350 for (auto caseOp : cases)
1351 terminateStructuredRegionBody(caseOp.getCaseRegion(), caseOp.getLoc());
1352 terminateStructuredRegionBody(swop.getBody(), swop.getLoc());
1353
1354 swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered());
1355
1356 return res;
1357}
1358
1359void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv,
1360 QualType ty) {
1361 if (rv.isScalar()) {
1362 builder.createStore(loc, rv.getValue(), returnValue);
1363 } else if (rv.isAggregate()) {
1364 Address rvAddr = rv.getAggregateAddress();
1365 // If the aggregate is already in the return slot (e.g. a callee was
1366 // invoked through a ReturnValueSlot bound to returnValue), the copy is
1367 // a no-op. Calling emitAggregateCopy here would also incorrectly
1368 // require the type to have a trivial copy/move.
1369 if (rvAddr.getPointer() != returnValue.getPointer()) {
1370 LValue dest = makeAddrLValue(returnValue, ty);
1371 LValue src = makeAddrLValue(rvAddr, ty);
1373 }
1374 } else {
1375 assert(rv.isComplex() && "Unknown rvalue kind?");
1376 builder.createStore(loc, rv.getComplexValue(), returnValue);
1377 }
1378
1379 // Classic codegen emits a branch through any cleanups before continuing to
1380 // a shared return block. Because CIR handles branching through cleanups
1381 // during the CFG flattening phase, we can just emit the return statement
1382 // directly.
1383 // TODO(cir): Eliminate this redundant load and the store above when we can.
1384 // Load the value from `__retval` and return it via the `cir.return` op.
1385 cir::AllocaOp retAlloca =
1386 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
1387 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
1388 *fnRetAlloca);
1389
1390 cir::ReturnOp::create(builder, loc, {value});
1391}
static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, const Stmt *exprResult, AggValueSlot slot, Address *lastValue)
Defines the clang::Expr interface and subclasses for C++ expressions.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
This file defines OpenACC AST classes for statement-level contructs.
This file defines OpenMP AST classes for executable directives and clauses.
This file defines SYCL AST classes used to represent calls to SYCL kernels.
Attr - This represents one attribute.
Definition Attr.h:46
Represents an attribute applied to a statement.
Definition Stmt.h:2212
Stmt * getSubStmt()
Definition Stmt.h:2248
ArrayRef< const Attr * > getAttrs() const
Definition Stmt.h:2244
BreakStmt - This represents a break.
Definition Stmt.h:3144
mlir::Value getPointer() const
Definition Address.h:98
An aggregate value slot.
static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
Captures the destructor cleanup for a loop's condition variable so that it can be emitted into the lo...
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
void forceCleanup(ArrayRef< mlir::Value * > valuesToReload={})
Force the emission of cleanups now, instead of waiting until this object is destroyed.
mlir::LogicalResult emitOMPTargetParallelForDirective(const OMPTargetParallelForDirective &s)
mlir::LogicalResult emitOMPParallelMasterTaskLoopSimdDirective(const OMPParallelMasterTaskLoopSimdDirective &s)
mlir::LogicalResult emitOMPSimdDirective(const OMPSimdDirective &s)
mlir::Value emitCheckedArgForAssume(const Expr *e)
Emits an argument for a call to a __builtin_assume.
mlir::LogicalResult emitDoStmt(const clang::DoStmt &s)
mlir::LogicalResult emitOMPCriticalDirective(const OMPCriticalDirective &s)
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
mlir::LogicalResult emitCoreturnStmt(const CoreturnStmt &s)
mlir::LogicalResult emitOpenACCDataConstruct(const OpenACCDataConstruct &s)
EHScopeStack::stable_iterator prologueCleanupDepth
The cleanup depth enclosing all the cleanups associated with the parameters.
mlir::LogicalResult emitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &s)
mlir::LogicalResult emitOMPParallelMasterDirective(const OMPParallelMasterDirective &s)
mlir::LogicalResult emitOpenACCWaitConstruct(const OpenACCWaitConstruct &s)
mlir::LogicalResult emitOMPCancellationPointDirective(const OMPCancellationPointDirective &s)
mlir::LogicalResult emitOMPParallelMaskedTaskLoopDirective(const OMPParallelMaskedTaskLoopDirective &s)
mlir::LogicalResult emitOMPReverseDirective(const OMPReverseDirective &s)
const clang::LangOptions & getLangOpts() const
mlir::LogicalResult emitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &s)
mlir::LogicalResult emitOMPTileDirective(const OMPTileDirective &s)
mlir::LogicalResult emitIfOnBoolExpr(const clang::Expr *cond, const clang::Stmt *thenS, const clang::Stmt *elseS)
Emit an if on a boolean condition to the specified blocks.
mlir::LogicalResult emitOMPTargetTeamsDirective(const OMPTargetTeamsDirective &s)
mlir::LogicalResult emitOMPTeamsDistributeParallelForDirective(const OMPTeamsDistributeParallelForDirective &s)
mlir::LogicalResult emitOMPBarrierDirective(const OMPBarrierDirective &s)
mlir::LogicalResult emitOMPTargetParallelDirective(const OMPTargetParallelDirective &s)
mlir::LogicalResult emitOpenACCCacheConstruct(const OpenACCCacheConstruct &s)
mlir::LogicalResult emitOMPTargetDirective(const OMPTargetDirective &s)
mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s, llvm::ArrayRef< const Attr * > attrs)
mlir::Value evaluateExprAsBool(const clang::Expr *e)
Perform the usual unary conversions on the specified expression and compare the result against zero,...
void emitAggregateCopy(LValue dest, LValue src, QualType eltTy, AggValueSlot::Overlap_t mayOverlap, bool isVolatile=false)
Emit an aggregate copy.
mlir::LogicalResult emitOMPScopeDirective(const OMPScopeDirective &s)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::LogicalResult emitOMPDepobjDirective(const OMPDepobjDirective &s)
bool constantFoldsToBool(const clang::Expr *cond, bool &resultBool, bool allowLabels=false)
If the specified expression does not fold to a constant, or if it does but contains a label,...
void emitLoopConditionVariable(const clang::VarDecl &d, DeferredLoopConditionCleanup &condCleanup)
Emit a loop's condition-variable declaration.
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s)
mlir::LogicalResult emitOpenACCInitConstruct(const OpenACCInitConstruct &s)
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 emitOMPDistributeParallelForSimdDirective(const OMPDistributeParallelForSimdDirective &s)
mlir::LogicalResult emitOMPUnrollDirective(const OMPUnrollDirective &s)
mlir::LogicalResult emitOMPTaskDirective(const OMPTaskDirective &s)
mlir::LogicalResult emitOpenACCSetConstruct(const OpenACCSetConstruct &s)
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
mlir::LogicalResult emitOMPTeamsGenericLoopDirective(const OMPTeamsGenericLoopDirective &s)
mlir::LogicalResult emitOMPCanonicalLoop(const OMPCanonicalLoop &s)
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s)
mlir::LogicalResult emitOMPTeamsDirective(const OMPTeamsDirective &s)
mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s, mlir::Type condType, bool buildingTopLevelCase)
llvm::ScopedHashTableScope< const clang::Decl *, mlir::Value > SymTableScopeTy
mlir::LogicalResult emitOMPMaskedTaskLoopDirective(const OMPMaskedTaskLoopDirective &s)
mlir::LogicalResult emitOMPFuseDirective(const OMPFuseDirective &s)
mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s, bool useCurrentScope)
mlir::LogicalResult emitOMPSectionDirective(const OMPSectionDirective &s)
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s)
mlir::LogicalResult emitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &s)
mlir::LogicalResult emitOMPDistributeParallelForDirective(const OMPDistributeParallelForDirective &s)
mlir::LogicalResult emitOMPOrderedStandaloneDirective(const OMPOrderedStandaloneDirective &s)
mlir::LogicalResult emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s)
mlir::LogicalResult emitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective &s)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
mlir::LogicalResult emitSwitchBody(const clang::Stmt *s)
mlir::LogicalResult emitForStmt(const clang::ForStmt &s)
mlir::LogicalResult emitOMPTaskwaitDirective(const OMPTaskwaitDirective &s)
mlir::LogicalResult emitOMPFlushDirective(const OMPFlushDirective &s)
mlir::LogicalResult emitOMPGenericLoopDirective(const OMPGenericLoopDirective &s)
mlir::LogicalResult emitOMPTargetUpdateDirective(const OMPTargetUpdateDirective &s)
std::optional< mlir::Value > fnRetAlloca
The compiler-generated variable that holds the return value.
mlir::LogicalResult emitOMPTargetParallelForSimdDirective(const OMPTargetParallelForSimdDirective &s)
mlir::LogicalResult emitOMPInterchangeDirective(const OMPInterchangeDirective &s)
mlir::LogicalResult emitOMPDispatchDirective(const OMPDispatchDirective &s)
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback)
mlir::LogicalResult emitOMPParallelDirective(const OMPParallelDirective &s)
mlir::LogicalResult emitAttributedStmt(const AttributedStmt &s)
mlir::LogicalResult emitOMPForSimdDirective(const OMPForSimdDirective &s)
mlir::LogicalResult emitOMPTaskLoopDirective(const OMPTaskLoopDirective &s)
Address returnValue
The temporary alloca to hold the return value.
mlir::LogicalResult emitOMPTargetDataDirective(const OMPTargetDataDirective &s)
mlir::LogicalResult emitLabel(const clang::LabelDecl &d)
mlir::LogicalResult emitOMPTargetParallelGenericLoopDirective(const OMPTargetParallelGenericLoopDirective &s)
static bool hasAggregateEvaluationKind(clang::QualType type)
mlir::LogicalResult emitOMPParallelMaskedDirective(const OMPParallelMaskedDirective &s)
mlir::LogicalResult emitOMPMaskedTaskLoopSimdDirective(const OMPMaskedTaskLoopSimdDirective &s)
mlir::LogicalResult emitOMPAtomicDirective(const OMPAtomicDirective &s)
mlir::LogicalResult emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s)
mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s)
mlir::LogicalResult emitIndirectGotoStmt(const IndirectGotoStmt &s)
mlir::LogicalResult emitOMPTeamsDistributeParallelForSimdDirective(const OMPTeamsDistributeParallelForSimdDirective &s)
mlir::LogicalResult emitOMPTaskgroupDirective(const OMPTaskgroupDirective &s)
mlir::LogicalResult emitOMPParallelMaskedTaskLoopSimdDirective(const OMPParallelMaskedTaskLoopSimdDirective &s)
mlir::LogicalResult emitOMPTeamsDistributeDirective(const OMPTeamsDistributeDirective &s)
void emitReturnOfRValue(mlir::Location loc, RValue rv, QualType ty)
mlir::LogicalResult emitOMPInteropDirective(const OMPInteropDirective &s)
mlir::LogicalResult emitOMPErrorDirective(const OMPErrorDirective &s)
mlir::LogicalResult emitOMPSingleDirective(const OMPSingleDirective &s)
mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s)
mlir::LogicalResult emitOMPTaskyieldDirective(const OMPTaskyieldDirective &s)
mlir::LogicalResult emitOMPTargetTeamsDistributeSimdDirective(const OMPTargetTeamsDistributeSimdDirective &s)
mlir::LogicalResult emitOMPScanDirective(const OMPScanDirective &s)
llvm::SmallVector< mlir::Type, 2 > condTypeStack
The type of the condition for the emitting switch statement.
mlir::LogicalResult emitOMPTargetEnterDataDirective(const OMPTargetEnterDataDirective &s)
void emitStopPoint(const Stmt *s)
Build a debug stoppoint if we are emitting debug info.
mlir::LogicalResult emitOMPMasterTaskLoopDirective(const OMPMasterTaskLoopDirective &s)
mlir::LogicalResult emitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &s)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
mlir::LogicalResult emitIfStmt(const clang::IfStmt &s)
mlir::LogicalResult emitOMPForDirective(const OMPForDirective &s)
mlir::LogicalResult emitOMPMasterDirective(const OMPMasterDirective &s)
AggValueSlot::Overlap_t getOverlapForReturnValue()
Determine whether a return value slot may overlap some other object.
mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s, bool buildingTopLevelCase)
mlir::LogicalResult emitOMPMetaDirective(const OMPMetaDirective &s)
mlir::LogicalResult emitOMPDistributeSimdDirective(const OMPDistributeSimdDirective &s)
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl=false)
mlir::LogicalResult emitOMPParallelGenericLoopDirective(const OMPParallelGenericLoopDirective &s)
mlir::LogicalResult emitOMPMaskedDirective(const OMPMaskedDirective &s)
mlir::LogicalResult emitOMPSplitDirective(const OMPSplitDirective &s)
llvm::DenseMap< const VarDecl *, mlir::Value > nrvoFlags
A mapping from NRVO variables to the flags used to indicate when the NRVO has been applied to this va...
mlir::LogicalResult emitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &s)
mlir::LogicalResult emitOMPTargetExitDataDirective(const OMPTargetExitDataDirective &s)
mlir::LogicalResult emitOMPOrderedBlockAssocDirective(const OMPOrderedBlockAssocDirective &s)
mlir::LogicalResult emitOMPTargetTeamsDistributeParallelForDirective(const OMPTargetTeamsDistributeParallelForDirective &s)
void emitComplexExprIntoLValue(const Expr *e, LValue dest, bool isInit)
mlir::LogicalResult emitOMPParallelForDirective(const OMPParallelForDirective &s)
mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType, mlir::ArrayAttr value, cir::CaseOpKind kind, bool buildingTopLevelCase)
mlir::LogicalResult emitOMPSectionsDirective(const OMPSectionsDirective &s)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
mlir::LogicalResult emitOMPDistributeDirective(const OMPDistributeDirective &s)
RValue emitAnyExpr(const clang::Expr *e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
Emit code to compute the specified expression which can have any type.
mlir::LogicalResult emitOMPTargetTeamsDistributeParallelForSimdDirective(const OMPTargetTeamsDistributeParallelForSimdDirective &s)
mlir::LogicalResult emitOMPTargetTeamsGenericLoopDirective(const OMPTargetTeamsGenericLoopDirective &s)
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s)
mlir::LogicalResult emitOMPTeamsDistributeSimdDirective(const OMPTeamsDistributeSimdDirective &s)
mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s, mlir::Type condType, bool buildingTopLevelCase)
mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s)
mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s)
mlir::LogicalResult emitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &s)
void terminateStructuredRegionBody(mlir::Region &r, mlir::Location loc)
clang::ASTContext & getContext() const
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s)
mlir::LogicalResult emitCompoundStmt(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
mlir::LogicalResult emitGotoStmt(const clang::GotoStmt &s)
bool inAlwaysInlineAttributedStmt
True if the current statement has always_inline attribute.
bool inNoInlineAttributedStmt
True if the current statement has noinline attribute.
mlir::LogicalResult emitOMPParallelMasterTaskLoopDirective(const OMPParallelMasterTaskLoopDirective &s)
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
mlir::LogicalResult emitOMPCancelDirective(const OMPCancelDirective &s)
mlir::LogicalResult emitOMPStripeDirective(const OMPStripeDirective &s)
mlir::LogicalResult emitOMPTargetTeamsDistributeDirective(const OMPTargetTeamsDistributeDirective &s)
mlir::LogicalResult emitCompoundStmtWithoutScope(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
mlir::LogicalResult emitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &s)
mlir::LogicalResult emitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &s)
mlir::LogicalResult emitSYCLKernelCallStmt(const SYCLKernelCallStmt &s)
void emitIgnoredExpr(const clang::Expr *e)
Emit code to compute the specified expression, ignoring the result.
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
mlir::LogicalResult emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s)
mlir::LogicalResult emitOMPTargetSimdDirective(const OMPTargetSimdDirective &s)
mlir::LogicalResult emitOMPAssumeDirective(const OMPAssumeDirective &s)
mlir::LogicalResult emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
Address getAggregateAddress() const
Return the value of the address of the aggregate.
Definition CIRGenValue.h:69
bool isAggregate() const
Definition CIRGenValue.h:51
bool isComplex() const
Definition CIRGenValue.h:50
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
bool isScalar() const
Definition CIRGenValue.h:49
mlir::Value getComplexValue() const
Return the value of this complex value.
Definition CIRGenValue.h:63
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Definition StmtCXX.h:136
DeclStmt * getBeginStmt()
Definition StmtCXX.h:164
DeclStmt * getEndStmt()
Definition StmtCXX.h:167
DeclStmt * getRangeStmt()
Definition StmtCXX.h:163
SourceLocation getEndLoc() const LLVM_READONLY
Definition StmtCXX.h:209
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2954
CaseStmt - Represent a case statement.
Definition Stmt.h:1929
Expr * getLHS()
Definition Stmt.h:2012
Expr * getRHS()
Definition Stmt.h:2024
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1749
body_range body()
Definition Stmt.h:1812
Stmt * body_back()
Definition Stmt.h:1817
ContinueStmt - This represents a continue.
Definition Stmt.h:3128
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1640
decl_range decls()
Definition Stmt.h:1688
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2841
SourceLocation getEndLoc() const
Definition Stmt.h:2878
This represents one expression.
Definition Expr.h:112
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3097
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition Expr.cpp:3700
QualType getType() const
Definition Expr.h:144
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition Stmt.h:2897
Stmt * getInit()
Definition Stmt.h:2912
VarDecl * getConditionVariable() const
Retrieve the variable declared in this "for" statement, if any.
Definition Stmt.cpp:1120
SourceLocation getEndLoc() const
Definition Stmt.h:2961
Stmt * getBody()
Definition Stmt.h:2941
Expr * getInc()
Definition Stmt.h:2940
Expr * getCond()
Definition Stmt.h:2939
GotoStmt - This represents a direct goto.
Definition Stmt.h:2978
LabelDecl * getLabel() const
Definition Stmt.h:2991
IfStmt - This represents an if/then/else.
Definition Stmt.h:2268
Stmt * getThen()
Definition Stmt.h:2357
Stmt * getInit()
Definition Stmt.h:2418
Expr * getCond()
Definition Stmt.h:2345
bool isConstexpr() const
Definition Stmt.h:2461
bool isNegatedConsteval() const
Definition Stmt.h:2457
Stmt * getElse()
Definition Stmt.h:2366
bool isConsteval() const
Definition Stmt.h:2448
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
Definition Stmt.cpp:1068
IndirectGotoStmt - This represents an indirect goto.
Definition Stmt.h:3017
Represents the declaration of a label.
Definition Decl.h:524
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.h:554
LabelStmt - Represents a label, which has a substatement.
Definition Stmt.h:2155
LabelDecl * getDecl() const
Definition Stmt.h:2173
bool isSideEntry() const
Definition Stmt.h:2202
Stmt * getSubStmt()
Definition Stmt.h:2177
SourceLocation getKwLoc() const
Definition Stmt.h:3091
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
A (possibly-)qualified type.
Definition TypeBase.h:938
The collection of all-type qualifiers we support.
Definition TypeBase.h:332
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3169
const VarDecl * getNRVOCandidate() const
Retrieve the variable that might be used for the named return value optimization.
Definition Stmt.h:3205
Expr * getRetValue()
Definition Stmt.h:3196
Stmt - This represents one statement.
Definition Stmt.h:85
@ NoStmtClass
Definition Stmt.h:88
StmtClass getStmtClass() const
Definition Stmt.h:1502
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
const char * getStmtClassName() const
Definition Stmt.cpp:86
SwitchStmt - This represents a 'switch' stmt.
Definition Stmt.h:2518
bool isAllEnumCasesCovered() const
Returns true if the SwitchStmt is a switch of an enum value and all cases have been explicitly covere...
Definition Stmt.h:2678
Expr * getCond()
Definition Stmt.h:2581
VarDecl * getConditionVariable()
Retrieve the variable declared in this "switch" statement, if any.
Definition Stmt.cpp:1186
Stmt * getInit()
Definition Stmt.h:2598
SourceLocation getBeginLoc() const
Definition Stmt.h:2682
bool isVoidType() const
Definition TypeBase.h:9113
Represents a variable declaration or definition.
Definition Decl.h:932
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1536
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2822
WhileStmt - This represents a 'while' stmt.
Definition Stmt.h:2706
Expr * getCond()
Definition Stmt.h:2758
VarDecl * getConditionVariable()
Retrieve the variable declared in this "while" statement, if any.
Definition Stmt.cpp:1247
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.h:2820
Stmt * getBody()
Definition Stmt.h:2770
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicDynCastAllOfMatcher< Stmt, CompoundStmt > compoundStmt
Matches compound statements.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, SwitchCase > switchCase
Matches case and default statements inside switch statements.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Default
Set to the current date and time.
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1774
static bool emitLifetimeMarkers()
static bool aggValueSlotGC()
static bool createProfileWeightsForLoop()
static bool loopInfoStack()
static bool emitCondLikelihoodViaExpectIntrinsic()
static bool constantFoldSwitchStatement()
static bool insertBuiltinUnpredictable()
static bool generateDebugInfo()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...