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"
26#include "llvm/Support/SaveAndRestore.h"
27
28using namespace clang;
29using namespace clang::CIRGen;
30using namespace cir;
31
32/// Compute the atomic options that apply for the extent of a clang::atomic
33/// attributed statement, starting from the enclosing options adjustments on top
34/// of them.
36 const AtomicAttr *aa) {
37 if (!aa)
38 return ao;
39 for (auto option : aa->atomicOptions()) {
40 switch (option) {
41 case AtomicAttr::remote_memory:
42 ao.remote_memory = true;
43 break;
44 case AtomicAttr::no_remote_memory:
45 ao.remote_memory = false;
46 break;
47 case AtomicAttr::fine_grained_memory:
48 ao.fine_grained_memory = true;
49 break;
50 case AtomicAttr::no_fine_grained_memory:
51 ao.fine_grained_memory = false;
52 break;
53 case AtomicAttr::ignore_denormal_mode:
54 ao.ignore_denormal_mode = true;
55 break;
56 case AtomicAttr::no_ignore_denormal_mode:
57 ao.ignore_denormal_mode = false;
58 break;
59 }
60 }
61 return ao;
62}
63
64static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf,
65 const Stmt *exprResult,
66 AggValueSlot slot,
67 Address *lastValue) {
68 // We have to special case labels here. They are statements, but when put
69 // at the end of a statement expression, they yield the value of their
70 // subexpression. Handle this by walking through all labels we encounter,
71 // emitting them before we evaluate the subexpr.
72 // Similar issues arise for attributed statements.
73 while (!isa<Expr>(exprResult)) {
74 if (const auto *ls = dyn_cast<LabelStmt>(exprResult)) {
75 if (cgf.emitLabel(*ls->getDecl()).failed())
76 return mlir::failure();
77 exprResult = ls->getSubStmt();
78 } else if (const auto *as = dyn_cast<AttributedStmt>(exprResult)) {
79 // FIXME: Update this if we ever have attributes that affect the
80 // semantics of an expression.
81 exprResult = as->getSubStmt();
82 } else {
83 llvm_unreachable("Unknown value statement");
84 }
85 }
86
87 const Expr *e = cast<Expr>(exprResult);
88 QualType exprTy = e->getType();
89 if (cgf.hasAggregateEvaluationKind(exprTy)) {
90 cgf.emitAggExpr(e, slot);
91 } else {
92 // We can't return an RValue here because there might be cleanups at
93 // the end of the StmtExpr. Because of that, we have to emit the result
94 // here into a temporary alloca.
95 cgf.emitAnyExprToMem(e, *lastValue, Qualifiers(),
96 /*IsInit*/ false);
97 }
98
99 return mlir::success();
100}
101
103 const CompoundStmt &s, Address *lastValue, AggValueSlot slot) {
104 mlir::LogicalResult result = mlir::success();
105 const Stmt *exprResult = s.body_back();
106 assert((!lastValue || (lastValue && exprResult)) &&
107 "If lastValue is not null then the CompoundStmt must have a "
108 "StmtExprResult");
109
110 for (const Stmt *curStmt : s.body()) {
111 const bool saveResult = lastValue && exprResult == curStmt;
112 if (saveResult) {
113 if (emitStmtWithResult(*this, exprResult, slot, lastValue).failed())
114 result = mlir::failure();
115 } else {
116 if (emitStmt(curStmt, /*useCurrentScope=*/false).failed())
117 result = mlir::failure();
118 }
119 }
120 return result;
121}
122
123mlir::LogicalResult
125
126 bool noinline = inNoInlineAttributedStmt;
127 bool alwaysinline = inAlwaysInlineAttributedStmt;
128 const CallExpr *musttail = mustTailCall;
129 const AtomicAttr *atomicAttr = nullptr;
130
131 for (const Attr *attr : s.getAttrs()) {
132 switch (attr->getKind()) {
133 default:
134 break;
135 case attr::Atomic:
136 atomicAttr = cast<AtomicAttr>(attr);
137 break;
138 case attr::NoMerge:
139 case attr::NoConvergent:
140 case attr::AMDGPUAvailableVisible:
141 case attr::HLSLControlFlowHint:
142 cgm.errorNYI(s.getSourceRange(),
143 "Unimplemented statement attribute: ", attr->getKind());
144 break;
145 case attr::NoInline:
146 noinline = true;
147 alwaysinline = false;
148 break;
149 case attr::AlwaysInline:
150 alwaysinline = true;
151 noinline = false;
152 break;
153 case attr::MustTail: {
154 const Stmt *sub = s.getSubStmt();
155 const ReturnStmt *ret = cast<ReturnStmt>(sub);
156 musttail = cast<CallExpr>(ret->getRetValue()->IgnoreParens());
157 break;
158 }
159 case attr::CXXAssume: {
160 const Expr *assumptionExpr = cast<CXXAssumeAttr>(attr)->getAssumption();
161 if (getLangOpts().CXXAssumptions && builder.getInsertionBlock() &&
162 !assumptionExpr->HasSideEffects(getContext())) {
163 mlir::Value assumptionValue = emitCheckedArgForAssume(assumptionExpr);
164 cir::AssumeOp::create(builder, getLoc(s.getSourceRange()),
165 assumptionValue, cir::AssumeBundleKind::None,
166 mlir::ValueRange{});
167 }
168 } break;
169 }
170 }
171
172 assert(!(alwaysinline && noinline) &&
173 "alwaysinline and noinline are mutually exclusive");
174
175 SaveAndRestore save_noinline(inNoInlineAttributedStmt, noinline);
176 SaveAndRestore save_alwaysinline(inAlwaysInlineAttributedStmt, alwaysinline);
177
178 SaveAndRestore save_musttail(mustTailCall, musttail);
179
180 // clang::atomic adjusts the atomic options for the extent of the statement it
181 // is attached to, so they are saved and restored around it.
182 clang::AtomicOptions savedAtomicOpts = cgm.getAtomicOpts();
183 cgm.setAtomicOpts(getAdjustedAtomicOptions(savedAtomicOpts, atomicAttr));
184
185 mlir::LogicalResult result =
186 emitStmt(s.getSubStmt(), /*useCurrentScope=*/false, s.getAttrs());
187
188 cgm.setAtomicOpts(savedAtomicOpts);
189 return result;
190}
191
193 Address *lastValue,
194 AggValueSlot slot) {
195 // Add local scope to track new declared variables.
197 mlir::Location scopeLoc = getLoc(s.getSourceRange());
198 mlir::OpBuilder::InsertPoint scopeInsPt;
199 cir::ScopeOp::create(
200 builder, scopeLoc,
201 [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
202 scopeInsPt = b.saveInsertionPoint();
203 });
204 mlir::OpBuilder::InsertionGuard guard(builder);
205 builder.restoreInsertionPoint(scopeInsPt);
206 LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
207 return emitCompoundStmtWithoutScope(s, lastValue, slot);
208}
209
213
214// Build CIR for a statement. useCurrentScope should be true if no new scopes
215// need to be created when finding a compound statement.
216mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
217 bool useCurrentScope,
219 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
220 return mlir::success();
221
222 switch (s->getStmtClass()) {
224 case Stmt::CXXCatchStmtClass:
225 case Stmt::SEHExceptStmtClass:
226 case Stmt::SEHFinallyStmtClass:
227 case Stmt::MSDependentExistsStmtClass:
228 case Stmt::UnresolvedSYCLKernelCallStmtClass:
229 llvm_unreachable("invalid statement class to emit generically");
230 case Stmt::BreakStmtClass:
231 case Stmt::NullStmtClass:
232 case Stmt::CompoundStmtClass:
233 case Stmt::ContinueStmtClass:
234 case Stmt::DeclStmtClass:
235 case Stmt::ReturnStmtClass:
236 llvm_unreachable("should have emitted these statements as simple");
237
238#define STMT(Type, Base)
239#define ABSTRACT_STMT(Op)
240#define EXPR(Type, Base) case Stmt::Type##Class:
241#include "clang/AST/StmtNodes.inc"
242 {
243 assert(builder.getInsertionBlock() &&
244 "expression emission must have an insertion point");
245
247
248 // Classic codegen has a check here to see if the emitter created a new
249 // block that isn't used (comparing the incoming and outgoing insertion
250 // points) and deletes the outgoing block if it's not used. In CIR, we
251 // will handle that during the cir.canonicalize pass.
252 return mlir::success();
253 }
254 case Stmt::IfStmtClass:
255 return emitIfStmt(cast<IfStmt>(*s));
256 case Stmt::SwitchStmtClass:
258 case Stmt::ForStmtClass:
259 return emitForStmt(cast<ForStmt>(*s));
260 case Stmt::WhileStmtClass:
261 return emitWhileStmt(cast<WhileStmt>(*s));
262 case Stmt::DoStmtClass:
263 return emitDoStmt(cast<DoStmt>(*s));
264 case Stmt::CXXTryStmtClass:
266 case Stmt::CXXForRangeStmtClass:
268 case Stmt::CoroutineBodyStmtClass:
270 case Stmt::IndirectGotoStmtClass:
272 case Stmt::CoreturnStmtClass:
274 case Stmt::SYCLKernelCallStmtClass:
276 case Stmt::OpenACCComputeConstructClass:
278 case Stmt::OpenACCLoopConstructClass:
280 case Stmt::OpenACCCombinedConstructClass:
282 case Stmt::OpenACCDataConstructClass:
284 case Stmt::OpenACCEnterDataConstructClass:
286 case Stmt::OpenACCExitDataConstructClass:
288 case Stmt::OpenACCHostDataConstructClass:
290 case Stmt::OpenACCWaitConstructClass:
292 case Stmt::OpenACCInitConstructClass:
294 case Stmt::OpenACCShutdownConstructClass:
296 case Stmt::OpenACCSetConstructClass:
298 case Stmt::OpenACCUpdateConstructClass:
300 case Stmt::OpenACCCacheConstructClass:
302 case Stmt::OpenACCAtomicConstructClass:
304 case Stmt::GCCAsmStmtClass:
305 case Stmt::MSAsmStmtClass:
306 return emitAsmStmt(cast<AsmStmt>(*s));
307 case Stmt::OMPScopeDirectiveClass:
309 case Stmt::OMPErrorDirectiveClass:
311 case Stmt::OMPParallelDirectiveClass:
313 case Stmt::OMPTaskwaitDirectiveClass:
315 case Stmt::OMPTaskyieldDirectiveClass:
317 case Stmt::OMPBarrierDirectiveClass:
319 case Stmt::OMPMetaDirectiveClass:
321 case Stmt::OMPCanonicalLoopClass:
323 case Stmt::OMPSimdDirectiveClass:
325 case Stmt::OMPTileDirectiveClass:
327 case Stmt::OMPUnrollDirectiveClass:
329 case Stmt::OMPFuseDirectiveClass:
331 case Stmt::OMPForDirectiveClass:
333 case Stmt::OMPForSimdDirectiveClass:
335 case Stmt::OMPSectionsDirectiveClass:
337 case Stmt::OMPSectionDirectiveClass:
339 case Stmt::OMPSingleDirectiveClass:
341 case Stmt::OMPMasterDirectiveClass:
343 case Stmt::OMPCriticalDirectiveClass:
345 case Stmt::OMPParallelForDirectiveClass:
347 case Stmt::OMPParallelForSimdDirectiveClass:
350 case Stmt::OMPParallelMasterDirectiveClass:
352 case Stmt::OMPParallelSectionsDirectiveClass:
355 case Stmt::OMPTaskDirectiveClass:
357 case Stmt::OMPTaskgroupDirectiveClass:
359 case Stmt::OMPFlushDirectiveClass:
361 case Stmt::OMPDepobjDirectiveClass:
363 case Stmt::OMPScanDirectiveClass:
365 case Stmt::OMPOrderedStandaloneDirectiveClass:
368 case Stmt::OMPOrderedBlockAssocDirectiveClass:
371 case Stmt::OMPAtomicDirectiveClass:
373 case Stmt::OMPTargetDirectiveClass:
375 case Stmt::OMPTeamsDirectiveClass:
377 case Stmt::OMPCancellationPointDirectiveClass:
380 case Stmt::OMPCancelDirectiveClass:
382 case Stmt::OMPTargetDataDirectiveClass:
384 case Stmt::OMPTargetEnterDataDirectiveClass:
387 case Stmt::OMPTargetExitDataDirectiveClass:
389 case Stmt::OMPTargetParallelDirectiveClass:
391 case Stmt::OMPTargetParallelForDirectiveClass:
394 case Stmt::OMPTaskLoopDirectiveClass:
396 case Stmt::OMPTaskLoopSimdDirectiveClass:
398 case Stmt::OMPMaskedTaskLoopDirectiveClass:
400 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
403 case Stmt::OMPMasterTaskLoopDirectiveClass:
405 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
408 case Stmt::OMPParallelGenericLoopDirectiveClass:
411 case Stmt::OMPParallelMaskedDirectiveClass:
413 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
416 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
419 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
422 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
425 case Stmt::OMPDistributeDirectiveClass:
427 case Stmt::OMPDistributeParallelForDirectiveClass:
430 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
433 case Stmt::OMPDistributeSimdDirectiveClass:
435 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
438 case Stmt::OMPTargetParallelForSimdDirectiveClass:
441 case Stmt::OMPTargetSimdDirectiveClass:
443 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
446 case Stmt::OMPTargetUpdateDirectiveClass:
448 case Stmt::OMPTeamsDistributeDirectiveClass:
451 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
454 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
457 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
460 case Stmt::OMPTeamsGenericLoopDirectiveClass:
463 case Stmt::OMPTargetTeamsDirectiveClass:
465 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
468 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
471 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
474 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
477 case Stmt::OMPInteropDirectiveClass:
479 case Stmt::OMPDispatchDirectiveClass:
481 case Stmt::OMPGenericLoopDirectiveClass:
483 case Stmt::OMPReverseDirectiveClass:
485 case Stmt::OMPSplitDirectiveClass:
487 case Stmt::OMPInterchangeDirectiveClass:
489 case Stmt::OMPFlattenDirectiveClass:
491 case Stmt::OMPAssumeDirectiveClass:
493 case Stmt::OMPMaskedDirectiveClass:
495 case Stmt::OMPStripeDirectiveClass:
497 case Stmt::LabelStmtClass:
498 case Stmt::AttributedStmtClass:
499 case Stmt::GotoStmtClass:
500 case Stmt::DefaultStmtClass:
501 case Stmt::CaseStmtClass:
502 case Stmt::SEHLeaveStmtClass:
503 case Stmt::ObjCAtTryStmtClass:
504 case Stmt::ObjCAtThrowStmtClass:
505 case Stmt::ObjCAtSynchronizedStmtClass:
506 case Stmt::ObjCForCollectionStmtClass:
507 case Stmt::ObjCAutoreleasePoolStmtClass:
508 case Stmt::SEHTryStmtClass:
509 case Stmt::ObjCAtCatchStmtClass:
510 case Stmt::ObjCAtFinallyStmtClass:
511 case Stmt::DeferStmtClass:
512 case Stmt::CXXExpansionStmtPatternClass:
513 case Stmt::CXXExpansionStmtInstantiationClass:
514 cgm.errorNYI(s->getSourceRange(),
515 std::string("emitStmt: ") + s->getStmtClassName());
516 return mlir::failure();
517 case Stmt::CapturedStmtClass:
518 llvm_unreachable("CapturedStmt must be handled by the parent directive");
519 }
520
521 llvm_unreachable("Unexpected statement class");
522}
523
524mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
525 bool useCurrentScope) {
526 switch (s->getStmtClass()) {
527 default:
528 return mlir::failure();
529 case Stmt::DeclStmtClass:
530 return emitDeclStmt(cast<DeclStmt>(*s));
531 case Stmt::CompoundStmtClass:
532 if (useCurrentScope)
535 case Stmt::GotoStmtClass:
536 return emitGotoStmt(cast<GotoStmt>(*s));
537 case Stmt::ContinueStmtClass:
539
540 // NullStmt doesn't need any handling, but we need to say we handled it.
541 case Stmt::NullStmtClass:
542 break;
543
544 case Stmt::LabelStmtClass:
545 return emitLabelStmt(cast<LabelStmt>(*s));
546 case Stmt::CaseStmtClass:
547 case Stmt::DefaultStmtClass:
548 // If we reached here, we must not handling a switch case in the top level.
550 /*buildingTopLevelCase=*/false);
551 break;
552
553 case Stmt::BreakStmtClass:
554 return emitBreakStmt(cast<BreakStmt>(*s));
555 case Stmt::ReturnStmtClass:
557 case Stmt::AttributedStmtClass:
559 }
560
561 return mlir::success();
562}
563
564mlir::LogicalResult CIRGenFunction::emitLabelStmt(const clang::LabelStmt &s) {
565
566 if (emitLabel(*s.getDecl()).failed())
567 return mlir::failure();
568
569 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())
570 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");
571
572 return emitStmt(s.getSubStmt(), /*useCurrentScope=*/false);
573}
574
575// Add a terminating yield on a body region if no other terminators are used.
577 mlir::Location loc) {
578 if (r.empty())
579 return;
580
582 unsigned numBlocks = r.getBlocks().size();
583 for (auto &block : r.getBlocks()) {
584 // Already cleanup after return operations, which might create
585 // empty blocks if emitted as last stmt.
586 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
587 block.hasNoSuccessors())
588 eraseBlocks.push_back(&block);
589
590 if (block.empty() ||
591 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
592 mlir::OpBuilder::InsertionGuard guardCase(builder);
593 builder.setInsertionPointToEnd(&block);
594 builder.createYield(loc);
595 }
596 }
597
598 for (auto *b : eraseBlocks)
599 b->erase();
600}
601
602mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
603 mlir::LogicalResult res = mlir::success();
604 // The else branch of a consteval if statement is always the only branch
605 // that can be runtime evaluated.
606 const Stmt *constevalExecuted;
607 if (s.isConsteval()) {
608 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
609 if (!constevalExecuted) {
610 // No runtime code execution required
611 return res;
612 }
613 }
614
615 // C99 6.8.4.1: The first substatement is executed if the expression
616 // compares unequal to 0. The condition must be a scalar type.
617 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
618 if (s.isConsteval())
619 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
620
621 if (s.getInit())
622 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
623 return mlir::failure();
624
625 if (s.getConditionVariable())
627
628 // If the condition constant folds and can be elided, try to avoid
629 // emitting the condition and the dead arm of the if/else.
630 bool condConstant;
631 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
632 // Figure out which block (then or else) is executed.
633 const Stmt *executed = s.getThen();
634 const Stmt *skipped = s.getElse();
635 if (!condConstant) // Condition false?
636 std::swap(executed, skipped);
637
638 // If the skipped block has no labels in it, just emit the executed block.
639 // This avoids emitting dead code and simplifies the CFG substantially.
640 if (s.isConstexpr() || !containsLabel(skipped)) {
641 if (executed)
642 return emitStmt(executed, /*useCurrentScope=*/true);
643 // There is nothing to execute at runtime.
644 // TODO(cir): there is still an empty cir.scope generated by the caller.
645 return mlir::success();
646 }
647 }
648
651 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
652 };
653
654 // TODO: Add a new scoped symbol table.
655 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
656 // The if scope contains the full source range for IfStmt.
657 mlir::Location scopeLoc = getLoc(s.getSourceRange());
658 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
659 [&](mlir::OpBuilder &b, mlir::Location loc) {
660 LexicalScope lexScope{*this, scopeLoc,
661 builder.getInsertionBlock()};
662 res = ifStmtBuilder();
663 });
664
665 return res;
666}
667
668mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
669 assert(builder.getInsertionBlock() && "expected valid insertion point");
670
671 for (const Decl *i : s.decls())
672 emitDecl(*i, /*evaluateConditionDecl=*/true);
673
674 return mlir::success();
675}
676
677mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
678 mlir::Location loc = getLoc(s.getSourceRange());
679 const Expr *rv = s.getRetValue();
680
681 RunCleanupsScope cleanupScope(*this);
682 bool createNewScope = false;
683 if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) {
684 rv = ewc->getSubExpr();
685 createNewScope = true;
686 }
687
688 auto handleReturnVal = [&]() {
689 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
692 // Apply the named return value optimization for this return statement,
693 // which means doing nothing: the appropriate result has already been
694 // constructed into the NRVO variable.
695
696 // If there is an NRVO flag for this variable, set it to 1 into indicate
697 // that the cleanup code should not destroy the variable.
698 if (auto nrvoFlag = nrvoFlags[s.getNRVOCandidate()])
699 builder.createFlagStore(loc, true, nrvoFlag);
700 } else if (!rv) {
701 // No return expression. Do nothing.
702 } else if (rv->getType()->isVoidType()) {
703 // Make sure not to return anything, but evaluate the expression
704 // for side effects.
705 if (rv) {
706 emitAnyExpr(rv);
707 }
708 } else if (cast<FunctionDecl>(curGD.getDecl())
709 ->getReturnType()
710 ->isReferenceType()) {
711 // If this function returns a reference, take the address of the
712 // expression rather than the value.
714 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(),
715 *fnRetAlloca);
716 } else {
717 mlir::Value value = nullptr;
719 case cir::TEK_Scalar:
720 value = emitScalarExpr(rv);
721 if (value) { // Change this to an assert once emitScalarExpr is complete
722 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
723 }
724 break;
725 case cir::TEK_Complex:
728 /*isInit=*/true);
729 break;
736 break;
737 }
738 }
739 };
740
741 if (!createNewScope) {
742 handleReturnVal();
743 } else {
744 FullExprCleanupScope fullExprScope(*this, rv);
745 handleReturnVal();
746 }
747
748 cleanupScope.forceCleanup();
749
750 // Classic codegen emits a branch through any cleanups before continuing to
751 // a shared return block. Because CIR handles branching through cleanups
752 // during the CFG flattening phase, we can just emit the return statement
753 // directly.
754 // TODO(cir): Eliminate this redundant load and the store above when we can.
755 if (fnRetAlloca) {
756 // Load the value from `__retval` and return it via the `cir.return` op.
757 cir::AllocaOp retAlloca =
758 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
759 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
760 *fnRetAlloca);
761
762 cir::ReturnOp::create(builder, loc, {value});
763 } else {
764 cir::ReturnOp::create(builder, loc);
765 }
766
767 // Insert the new block to continue codegen after the return statement.
768 // This will get deleted if we don't populate it. This handles the case of
769 // unreachable statements below a return.
770 builder.createBlock(builder.getBlock()->getParent());
771 return mlir::success();
772}
773
774mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
775 // FIXME: LLVM codegen inserts emit a stop point here for debug info
776 // sake when the insertion point is available, but doesn't do
777 // anything special when there isn't. We haven't implemented debug
778 // info support just yet, look at this again once we have it.
780
781 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),
782 s.getLabel()->getName());
783
784 // A goto marks the end of a block, create a new one for codegen after
785 // emitGotoStmt can resume building in that block.
786 // Insert the new block to continue codegen after goto.
787 builder.createBlock(builder.getBlock()->getParent());
788
789 return mlir::success();
790}
791
792mlir::LogicalResult
794 // An indirect goto with an active cleanup may leave its scope. Determining
795 // whether its dynamic destination requires cleanup is not implemented.
796 if (ehStack.stable_begin() != prologueCleanupDepth) {
797 cgm.errorNYI(s.getSourceRange(), "indirect goto with active cleanup");
798 return mlir::success();
799 }
800
801 mlir::Value val = emitScalarExpr(s.getTarget());
802 // Emit a symbolic indirect goto. GotoSolver resolves it into the shared
803 // indirect-branch block after FlattenCFG merges regions, so this stays valid
804 // even when the goto sits inside a nested scope.
805 cir::IndirectGotoOp::create(builder, getLoc(s.getSourceRange()), val);
806
807 // The indirect goto ends the block; open a fresh one so codegen can resume.
808 builder.createBlock(builder.getBlock()->getParent());
809 return mlir::success();
810}
811
812mlir::LogicalResult
814 builder.createContinue(getLoc(s.getKwLoc()));
815
816 // Insert the new block to continue codegen after the continue statement.
817 builder.createBlock(builder.getBlock()->getParent());
818
819 return mlir::success();
820}
821
822mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
823 // Create a new block to tag with a label and add a branch from
824 // the current one to it. If the block is empty just call attach it
825 // to this label.
826 mlir::Block *currBlock = builder.getBlock();
827 mlir::Block *labelBlock = currBlock;
828
829 if (!currBlock->empty() || currBlock->isEntryBlock()) {
830 {
831 mlir::OpBuilder::InsertionGuard guard(builder);
832 labelBlock = builder.createBlock(builder.getBlock()->getParent());
833 }
834 cir::BrOp::create(builder, getLoc(d.getSourceRange()), labelBlock);
835 }
836
837 builder.setInsertionPointToEnd(labelBlock);
838 cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
839 // In a coroutine, the label makes the end of the body reachable again even
840 // after a co_return, so the implicit `co_return;` must not be left out.
841 if (curLexScope)
842 curLexScope->clearCoreturnInEnclosingScopes();
843 // FIXME: emit debug info for labels, incrementProfileCounter
846 return mlir::success();
847}
848
849mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
850 builder.createBreak(getLoc(s.getKwLoc()));
851
852 // Insert the new block to continue codegen after the break statement.
853 builder.createBlock(builder.getBlock()->getParent());
854
855 return mlir::success();
856}
857
858template <typename T>
859mlir::LogicalResult
861 mlir::ArrayAttr value, CaseOpKind kind,
862 bool buildingTopLevelCase) {
863
865 "only case or default stmt go here");
866
867 mlir::LogicalResult result = mlir::success();
868
869 mlir::Location loc = getLoc(stmt->getBeginLoc());
870
871 enum class SubStmtKind { Case, Default, Other };
872 SubStmtKind subStmtKind = SubStmtKind::Other;
873 const Stmt *sub = stmt->getSubStmt();
874
875 mlir::OpBuilder::InsertPoint insertPoint;
876 CaseOp::create(builder, loc, value, kind, insertPoint);
877
878 {
879 mlir::OpBuilder::InsertionGuard guardSwitch(builder);
880 builder.restoreInsertionPoint(insertPoint);
881
882 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
883 subStmtKind = SubStmtKind::Default;
884 builder.createYield(loc);
885 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
886 subStmtKind = SubStmtKind::Case;
887 builder.createYield(loc);
888 } else {
889 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
890 }
891
892 insertPoint = builder.saveInsertionPoint();
893 }
894
895 // If the substmt is default stmt or case stmt, try to handle the special case
896 // to make it into the simple form. e.g.
897 //
898 // switch () {
899 // case 1:
900 // default:
901 // ...
902 // }
903 //
904 // we prefer generating
905 //
906 // cir.switch() {
907 // cir.case(equal, 1) {
908 // cir.yield
909 // }
910 // cir.case(default) {
911 // ...
912 // }
913 // }
914 //
915 // than
916 //
917 // cir.switch() {
918 // cir.case(equal, 1) {
919 // cir.case(default) {
920 // ...
921 // }
922 // }
923 // }
924 //
925 // We don't need to revert this if we find the current switch can't be in
926 // simple form later since the conversion itself should be harmless.
927 if (subStmtKind == SubStmtKind::Case) {
928 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
929 } else if (subStmtKind == SubStmtKind::Default) {
930 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
931 buildingTopLevelCase);
932 } else if (buildingTopLevelCase) {
933 // If we're building a top level case, try to restore the insert point to
934 // the case we're building, then we can attach more random stmts to the
935 // case to make generating `cir.switch` operation to be a simple form.
936 builder.restoreInsertionPoint(insertPoint);
937 }
938
939 return result;
940}
941
942mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
943 mlir::Type condType,
944 bool buildingTopLevelCase) {
945 cir::CaseOpKind kind;
946 mlir::ArrayAttr value;
947 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
948
949 // Coerce a bool to an i1 for a switch, so we can just treat all its elements
950 // as an int later on.
951 if (isa<cir::BoolType>(condType))
952 condType = builder.getUIntNTy(1);
953
954 // If the case statement has an RHS value, it is representing a GNU
955 // case range statement, where LHS is the beginning of the range
956 // and RHS is the end of the range.
957 if (const Expr *rhs = s.getRHS()) {
958 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
959 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
960 cir::IntAttr::get(condType, endVal)});
961 kind = cir::CaseOpKind::Range;
962 } else {
963 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
964 kind = cir::CaseOpKind::Equal;
965 }
966
967 return emitCaseDefaultCascade(&s, condType, value, kind,
968 buildingTopLevelCase);
969}
970
972 mlir::Type condType,
973 bool buildingTopLevelCase) {
974 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
975 cir::CaseOpKind::Default, buildingTopLevelCase);
976}
977
978mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
979 bool buildingTopLevelCase) {
980 assert(!condTypeStack.empty() &&
981 "build switch case without specifying the type of the condition");
982
983 if (s.getStmtClass() == Stmt::CaseStmtClass)
984 return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
985 buildingTopLevelCase);
986
987 if (s.getStmtClass() == Stmt::DefaultStmtClass)
989 buildingTopLevelCase);
990
991 llvm_unreachable("expect case or default stmt");
992}
993
994mlir::LogicalResult
996 ArrayRef<const Attr *> forAttrs) {
997 cir::ForOp forOp;
998
999 // TODO(cir): pass in array of attributes.
1000 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
1001 mlir::LogicalResult loopRes = mlir::success();
1002 // Evaluate the first pieces before the loop.
1003 if (s.getInit())
1004 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1005 return mlir::failure();
1006 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
1007 return mlir::failure();
1008 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
1009 return mlir::failure();
1010 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
1011 return mlir::failure();
1012
1014
1015 forOp = builder.createFor(
1017 /*condBuilder=*/
1018 [&](mlir::OpBuilder &b, mlir::Location loc) {
1019 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
1020 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
1021 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1022 builder.createCondition(condVal);
1023 },
1024 /*bodyBuilder=*/
1025 [&](mlir::OpBuilder &b, mlir::Location loc) {
1026 // https://en.cppreference.com/w/cpp/language/for
1027 // In C++ the scope of the init-statement and the scope of
1028 // statement are one and the same.
1029 RunCleanupsScope bodyScope(*this);
1030 bool useCurrentScope = true;
1031 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
1032 loopRes = mlir::failure();
1033 if (emitStmt(s.getBody(), useCurrentScope).failed())
1034 loopRes = mlir::failure();
1035 emitStopPoint(&s);
1036 },
1037 /*stepBuilder=*/
1038 [&](mlir::OpBuilder &b, mlir::Location loc) {
1039 if (s.getInc())
1040 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
1041 loopRes = mlir::failure();
1042 builder.createYield(loc);
1043 });
1044 return loopRes;
1045 };
1046
1047 mlir::LogicalResult res = mlir::success();
1048 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1049 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1050 [&](mlir::OpBuilder &b, mlir::Location loc) {
1051 // Create a cleanup scope for the condition
1052 // variable cleanups. Logical equivalent from
1053 // LLVM codegn for LexicalScope
1054 // ConditionScope(*this, S.getSourceRange())...
1055 LexicalScope lexScope{*this, loc,
1056 builder.getInsertionBlock()};
1057 res = forStmtBuilder();
1058 });
1059
1060 if (res.failed())
1061 return res;
1062
1063 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1064 return mlir::success();
1065}
1066
1067mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
1068 cir::ForOp forOp;
1069
1070 // TODO: pass in an array of attributes.
1071 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
1072 mlir::LogicalResult loopRes = mlir::success();
1073 // Evaluate the first part before the loop.
1074 if (s.getInit())
1075 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1076 return mlir::failure();
1079
1080 // A condition variable's lifetime is a single iteration, so capture its
1081 // destructor and lifetime-end cleanups, and those of the temporaries that
1082 // its initializer lifetime-extends, and emit them into the loop's
1083 // per-iteration cleanup region. This scope is constructed after the
1084 // init-statement so the init-statement's cleanups are not captured.
1085 const VarDecl *condVar = s.getConditionVariable();
1086 SmallVector<QualType, 2> condVarExtendedTemporaries;
1087 if (condVar)
1088 condVarExtendedTemporaries =
1090 bool needsCondCleanup =
1091 condVar &&
1093 shouldEmitLifetimeMarkersForAutoVar() ||
1094 !condVarExtendedTemporaries.empty());
1095 CapturedCleanups loopCondScope(*this, needsCondCleanup);
1096
1097 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1100 mlir::Value condVal;
1101 if (s.getCond()) {
1102 // If the for statement declares a condition variable, emit that here.
1103 if (condVar)
1104 emitLoopConditionVariable(*condVar, loopCondScope,
1105 condVarExtendedTemporaries);
1106 // C99 6.8.5p2/p4: The first substatement is executed if the
1107 // expression compares unequal to 0. The condition must be a
1108 // scalar type.
1109 condVal = evaluateExprAsBool(s.getCond());
1110 } else {
1111 condVal = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
1112 }
1113 builder.createCondition(condVal);
1114 };
1115 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1116 // The scope of the for loop body is nested within the scope of the
1117 // for loop's init-statement and condition.
1118 RunCleanupsScope bodyScope(*this);
1119 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1120 loopRes = mlir::failure();
1121 emitStopPoint(&s);
1122 };
1123 auto stepBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1124 if (s.getInc())
1125 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
1126 loopRes = mlir::failure();
1127 builder.createYield(loc);
1128 };
1129
1130 if (needsCondCleanup) {
1131 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1132 ? cir::CleanupKind::All
1133 : cir::CleanupKind::Normal;
1134 forOp = builder.createFor(
1135 getLoc(s.getSourceRange()), condBuilder, bodyBuilder, stepBuilder,
1136 /*cleanupBuilder=*/
1137 [&](mlir::OpBuilder &b, mlir::Location loc) {
1138 loopCondScope.emitIntoCleanupRegion(loc);
1139 builder.createYield(loc);
1140 },
1141 cleanupKind);
1142 } else {
1143 forOp = builder.createFor(getLoc(s.getSourceRange()), condBuilder,
1144 bodyBuilder, stepBuilder);
1145 }
1146 return loopRes;
1147 };
1148
1149 auto res = mlir::success();
1150 auto scopeLoc = getLoc(s.getSourceRange());
1151 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1152 [&](mlir::OpBuilder &b, mlir::Location loc) {
1153 LexicalScope lexScope{*this, loc,
1154 builder.getInsertionBlock()};
1155 res = forStmtBuilder();
1156 });
1157
1158 if (res.failed())
1159 return res;
1160
1161 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1162 return mlir::success();
1163}
1164
1165mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
1166 cir::DoWhileOp doWhileOp;
1167
1168 // TODO: pass in array of attributes.
1169 auto doStmtBuilder = [&]() -> mlir::LogicalResult {
1170 mlir::LogicalResult loopRes = mlir::success();
1173
1174 doWhileOp = builder.createDoWhile(
1176 /*condBuilder=*/
1177 [&](mlir::OpBuilder &b, mlir::Location loc) {
1178 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
1179 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
1180 // C99 6.8.5p2/p4: The first substatement is executed if the
1181 // expression compares unequal to 0. The condition must be a
1182 // scalar type.
1183 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1184 builder.createCondition(condVal);
1185 },
1186 /*bodyBuilder=*/
1187 [&](mlir::OpBuilder &b, mlir::Location loc) {
1188 // The scope of the do-while loop body is a nested scope.
1189 RunCleanupsScope bodyScope(*this);
1190 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1191 loopRes = mlir::failure();
1192 emitStopPoint(&s);
1193 });
1194 return loopRes;
1195 };
1196
1197 mlir::LogicalResult res = mlir::success();
1198 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1199 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1200 [&](mlir::OpBuilder &b, mlir::Location loc) {
1201 LexicalScope lexScope{*this, loc,
1202 builder.getInsertionBlock()};
1203 res = doStmtBuilder();
1204 });
1205
1206 if (res.failed())
1207 return res;
1208
1209 terminateStructuredRegionBody(doWhileOp.getBody(), getLoc(s.getEndLoc()));
1210 return mlir::success();
1211}
1212
1213mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
1214 cir::WhileOp whileOp;
1215
1216 // TODO: pass in array of attributes.
1217 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
1218 mlir::LogicalResult loopRes = mlir::success();
1221
1222 // A condition variable's lifetime is a single iteration, so capture its
1223 // destructor and lifetime-end cleanups, and those of the temporaries that
1224 // its initializer lifetime-extends, and emit them into the loop's
1225 // per-iteration cleanup region.
1226 const VarDecl *condVar = s.getConditionVariable();
1227 SmallVector<QualType, 2> condVarExtendedTemporaries;
1228 if (condVar)
1229 condVarExtendedTemporaries =
1231 bool needsCondCleanup =
1232 condVar &&
1234 shouldEmitLifetimeMarkersForAutoVar() ||
1235 !condVarExtendedTemporaries.empty());
1236 CapturedCleanups loopCondScope(*this, needsCondCleanup);
1237
1238 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1241 // If the while statement declares a condition variable, emit that here.
1242 if (condVar)
1243 emitLoopConditionVariable(*condVar, loopCondScope,
1244 condVarExtendedTemporaries);
1245 // C99 6.8.5p2/p4: The first substatement is executed if the
1246 // expression compares unequal to 0. The condition must be a
1247 // scalar type.
1248 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1249 builder.createCondition(condVal);
1250 };
1251 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1252 // The scope of the while loop body is a nested scope.
1253 RunCleanupsScope bodyScope(*this);
1254 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1255 loopRes = mlir::failure();
1256 emitStopPoint(&s);
1257 };
1258
1259 if (needsCondCleanup) {
1260 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1261 ? cir::CleanupKind::All
1262 : cir::CleanupKind::Normal;
1263 whileOp = builder.createWhile(
1264 getLoc(s.getSourceRange()), condBuilder, bodyBuilder,
1265 /*cleanupBuilder=*/
1266 [&](mlir::OpBuilder &b, mlir::Location loc) {
1267 loopCondScope.emitIntoCleanupRegion(loc);
1268 builder.createYield(loc);
1269 },
1270 cleanupKind);
1271 } else {
1272 whileOp = builder.createWhile(getLoc(s.getSourceRange()), condBuilder,
1273 bodyBuilder);
1274 }
1275 return loopRes;
1276 };
1277
1278 mlir::LogicalResult res = mlir::success();
1279 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1280 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1281 [&](mlir::OpBuilder &b, mlir::Location loc) {
1282 LexicalScope lexScope{*this, loc,
1283 builder.getInsertionBlock()};
1284 res = whileStmtBuilder();
1285 });
1286
1287 if (res.failed())
1288 return res;
1289
1290 terminateStructuredRegionBody(whileOp.getBody(), getLoc(s.getEndLoc()));
1291 return mlir::success();
1292}
1293
1294mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
1295 // It is rare but legal if the switch body is not a compound stmt. e.g.,
1296 //
1297 // switch(a)
1298 // while(...) {
1299 // case1
1300 // ...
1301 // case2
1302 // ...
1303 // }
1304 if (!isa<CompoundStmt>(s))
1305 return emitStmt(s, /*useCurrentScope=*/true);
1306
1308
1309 ArrayRef<Stmt *> body{compoundStmt->body_begin(), compoundStmt->body_end()};
1310
1311 mlir::Block *switchBlock = builder.getBlock();
1312
1313 // Any statements appearing before the first case statement are 'unassociated'
1314 // with anything. So we have to create them FIRST in their own block. After
1315 // that, the 'case' regions will take care of future ones.
1316 if (!body.empty() && !isa<SwitchCase>(body.front())) {
1317 builder.setInsertionPointToEnd(switchBlock);
1318 {
1319 // This is needed to handle cleanups in a compound statement before the
1320 // first case statement.
1321 RunCleanupsScope preCaseScope(*this);
1322 while (!body.empty() && !isa<SwitchCase>(body.front())) {
1323
1324 auto *c = body.front();
1325 if (mlir::failed(
1326 emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1327 return mlir::failure();
1328
1329 body = body.drop_front();
1330 }
1331 }
1332
1333 // Now that we've emitted ALL of the statements, we can create a new block
1334 // for the actual case statements/etc to appear.
1335 mlir::Block *lastBlock = builder.getBlock();
1336 switchBlock = builder.createBlock(switchBlock->getParent());
1337 builder.setInsertionPointToEnd(lastBlock);
1338 cir::BrOp::create(builder, getLoc(s->getSourceRange()), switchBlock);
1339 }
1340
1341 for (auto *c : body) {
1342 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
1343 builder.setInsertionPointToEnd(switchBlock);
1344 // Reset insert point automatically, so that we can attach following
1345 // random stmt to the region of previous built case op to try to make
1346 // the being generated `cir.switch` to be in simple form.
1347 if (mlir::failed(
1348 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
1349 return mlir::failure();
1350
1351 continue;
1352 }
1353
1354 // Otherwise, just build the statements in the nearest case region.
1355 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1356 return mlir::failure();
1357 }
1358
1359 return mlir::success();
1360}
1361
1363 // TODO: LLVM codegen does some early optimization to fold the condition and
1364 // only emit live cases. CIR should use MLIR to achieve similar things,
1365 // nothing to be done here.
1366 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
1368
1369 SwitchOp swop;
1370 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
1371 if (s.getInit())
1372 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1373 return mlir::failure();
1374
1375 if (s.getConditionVariable())
1376 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
1377
1378 mlir::Value condV = emitScalarExpr(s.getCond());
1379
1380 // Coerce bool values to an i1. There is no real sensible reason we need to
1381 // represent a 'switch' of scoped-enum-with-bool-backing-type specially
1382 // here. It is a rarely used thing, and would result in a lot of work to
1383 // properly handle this everywhere.
1384 if (isa<cir::BoolType>(condV.getType()))
1385 condV = builder.createBoolToInt(condV, builder.getUIntNTy(1));
1386
1387 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
1390 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
1392
1393 mlir::LogicalResult res = mlir::success();
1394 swop = SwitchOp::create(
1395 builder, getLoc(s.getBeginLoc()), condV,
1396 /*switchBuilder=*/
1397 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
1398 curLexScope->setAsSwitch();
1399
1400 condTypeStack.push_back(condV.getType());
1401
1402 res = emitSwitchBody(s.getBody());
1403
1404 condTypeStack.pop_back();
1405 });
1406
1407 return res;
1408 };
1409
1410 // The switch scope contains the full source range for SwitchStmt.
1411 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1412 mlir::LogicalResult res = mlir::success();
1413 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1414 [&](mlir::OpBuilder &b, mlir::Location loc) {
1415 LexicalScope lexScope{*this, loc,
1416 builder.getInsertionBlock()};
1417 res = switchStmtBuilder();
1418 });
1419
1421 swop.collectCases(cases);
1422 for (auto caseOp : cases)
1423 terminateStructuredRegionBody(caseOp.getCaseRegion(), caseOp.getLoc());
1424 terminateStructuredRegionBody(swop.getBody(), swop.getLoc());
1425
1426 swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered());
1427
1428 return res;
1429}
1430
1431void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv,
1432 QualType ty) {
1433 if (rv.isScalar()) {
1434 builder.createStore(loc, rv.getValue(), returnValue);
1435 } else if (rv.isAggregate()) {
1436 Address rvAddr = rv.getAggregateAddress();
1437 // If the aggregate is already in the return slot (e.g. a callee was
1438 // invoked through a ReturnValueSlot bound to returnValue), the copy is
1439 // a no-op. Calling emitAggregateCopy here would also incorrectly
1440 // require the type to have a trivial copy/move.
1441 if (rvAddr.getPointer() != returnValue.getPointer()) {
1442 LValue dest = makeAddrLValue(returnValue, ty);
1443 LValue src = makeAddrLValue(rvAddr, ty);
1445 }
1446 } else {
1447 assert(rv.isComplex() && "Unknown rvalue kind?");
1448 builder.createStore(loc, rv.getComplexValue(), returnValue);
1449 }
1450
1451 // Classic codegen emits a branch through any cleanups before continuing to
1452 // a shared return block. Because CIR handles branching through cleanups
1453 // during the CFG flattening phase, we can just emit the return statement
1454 // directly.
1455 // TODO(cir): Eliminate this redundant load and the store above when we can.
1456 // Load the value from `__retval` and return it via the `cir.return` op.
1457 cir::AllocaOp retAlloca =
1458 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
1459 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
1460 *fnRetAlloca);
1461
1462 cir::ReturnOp::create(builder, loc, {value});
1463}
static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, const Stmt *exprResult, AggValueSlot slot, Address *lastValue)
static clang::AtomicOptions getAdjustedAtomicOptions(clang::AtomicOptions ao, const AtomicAttr *aa)
Compute the atomic options that apply for the extent of a clang::atomic attributed statement,...
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:2215
Stmt * getSubStmt()
Definition Stmt.h:2251
ArrayRef< const Attr * > getAttrs() const
Definition Stmt.h:2247
BreakStmt - This represents a break.
Definition Stmt.h:3147
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 cleanups for variables whose lifetime ends in a region owned by an enclosing op rather than ...
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,...
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)
void emitLoopConditionVariable(const clang::VarDecl &d, CapturedCleanups &condCleanup, llvm::ArrayRef< QualType > extendedTemporaries)
Emit a loop's condition-variable declaration.
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 emitOMPFlattenDirective(const OMPFlattenDirective &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 emitOMPParallelDirective(const OMPParallelDirective &s)
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback, bool isFnTryBlock=false)
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)
bool checkIfLoopMustProgress(const clang::Expr *controllingExpression, bool hasEmptyBody)
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)
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts=false)
Return true if the statement contains a label in it.
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)
static llvm::SmallVector< QualType, 2 > getLifetimeExtendedTemporariesWithDestructor(const clang::VarDecl &d)
The types of the temporaries with a destructor that the initializer of the variable d,...
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:2991
CaseStmt - Represent a case statement.
Definition Stmt.h:1932
Expr * getLHS()
Definition Stmt.h:2015
Expr * getRHS()
Definition Stmt.h:2027
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1752
body_range body()
Definition Stmt.h:1815
Stmt * body_back()
Definition Stmt.h:1820
ContinueStmt - This represents a continue.
Definition Stmt.h:3131
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1643
decl_range decls()
Definition Stmt.h:1691
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2844
Expr * getCond()
Definition Stmt.h:2862
SourceLocation getEndLoc() const
Definition Stmt.h:2881
This represents one expression.
Definition Expr.h:113
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:3125
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:3728
QualType getType() const
Definition Expr.h:145
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition Stmt.h:2900
Stmt * getInit()
Definition Stmt.h:2915
VarDecl * getConditionVariable() const
Retrieve the variable declared in this "for" statement, if any.
Definition Stmt.cpp:1120
SourceLocation getEndLoc() const
Definition Stmt.h:2964
Stmt * getBody()
Definition Stmt.h:2944
Expr * getInc()
Definition Stmt.h:2943
Expr * getCond()
Definition Stmt.h:2942
GotoStmt - This represents a direct goto.
Definition Stmt.h:2981
LabelDecl * getLabel() const
Definition Stmt.h:2994
IfStmt - This represents an if/then/else.
Definition Stmt.h:2271
Stmt * getThen()
Definition Stmt.h:2360
Stmt * getInit()
Definition Stmt.h:2421
Expr * getCond()
Definition Stmt.h:2348
bool isConstexpr() const
Definition Stmt.h:2464
bool isNegatedConsteval() const
Definition Stmt.h:2460
Stmt * getElse()
Definition Stmt.h:2369
bool isConsteval() const
Definition Stmt.h:2451
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:3020
Represents the declaration of a label.
Definition Decl.h:525
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.h:555
LabelStmt - Represents a label, which has a substatement.
Definition Stmt.h:2158
LabelDecl * getDecl() const
Definition Stmt.h:2176
bool isSideEntry() const
Definition Stmt.h:2205
Stmt * getSubStmt()
Definition Stmt.h:2180
SourceLocation getKwLoc() const
Definition Stmt.h:3094
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:302
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:3172
const VarDecl * getNRVOCandidate() const
Retrieve the variable that might be used for the named return value optimization.
Definition Stmt.h:3208
Expr * getRetValue()
Definition Stmt.h:3199
Stmt - This represents one statement.
Definition Stmt.h:85
@ NoStmtClass
Definition Stmt.h:88
StmtClass getStmtClass() const
Definition Stmt.h:1505
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:2521
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:2681
Expr * getCond()
Definition Stmt.h:2584
VarDecl * getConditionVariable()
Retrieve the variable declared in this "switch" statement, if any.
Definition Stmt.cpp:1186
Stmt * getInit()
Definition Stmt.h:2601
SourceLocation getBeginLoc() const
Definition Stmt.h:2685
bool isVoidType() const
Definition TypeBase.h:9068
Represents a variable declaration or definition.
Definition Decl.h:933
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1537
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2826
WhileStmt - This represents a 'while' stmt.
Definition Stmt.h:2709
Expr * getCond()
Definition Stmt.h:2761
VarDecl * getConditionVariable()
Retrieve the variable declared in this "while" statement, if any.
Definition Stmt.cpp:1247
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.h:2823
Stmt * getBody()
Definition Stmt.h:2773
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
bool hasEmptyLoopBody(const LoopStmt &S)
Definition StmtUtils.h:39
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:1775
static bool aggValueSlotGC()
static bool createProfileWeightsForLoop()
static bool loopInfoStack()
static bool emitCondLikelihoodViaExpectIntrinsic()
static bool constantFoldSwitchStatement()
static bool insertBuiltinUnpredictable()
static bool generateDebugInfo()
static bool incrementProfileCounter()
unsigned ignore_denormal_mode
Represents a scope, including function bodies, compound statements, and the substatements of if/while...