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"
27#include "llvm/Support/SaveAndRestore.h"
28
29using namespace clang;
30using namespace clang::CIRGen;
31using namespace cir;
32
33/// Compute the atomic options that apply for the extent of a clang::atomic
34/// attributed statement, starting from the enclosing options adjustments on top
35/// of them.
37 const AtomicAttr *aa) {
38 if (!aa)
39 return ao;
40 for (auto option : aa->atomicOptions()) {
41 switch (option) {
42 case AtomicAttr::remote_memory:
43 ao.remote_memory = true;
44 break;
45 case AtomicAttr::no_remote_memory:
46 ao.remote_memory = false;
47 break;
48 case AtomicAttr::fine_grained_memory:
49 ao.fine_grained_memory = true;
50 break;
51 case AtomicAttr::no_fine_grained_memory:
52 ao.fine_grained_memory = false;
53 break;
54 case AtomicAttr::ignore_denormal_mode:
55 ao.ignore_denormal_mode = true;
56 break;
57 case AtomicAttr::no_ignore_denormal_mode:
58 ao.ignore_denormal_mode = false;
59 break;
60 }
61 }
62 return ao;
63}
64
65static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf,
66 const Stmt *exprResult,
67 AggValueSlot slot,
68 Address *lastValue) {
69 // We have to special case labels here. They are statements, but when put
70 // at the end of a statement expression, they yield the value of their
71 // subexpression. Handle this by walking through all labels we encounter,
72 // emitting them before we evaluate the subexpr.
73 // Similar issues arise for attributed statements.
74 while (!isa<Expr>(exprResult)) {
75 if (const auto *ls = dyn_cast<LabelStmt>(exprResult)) {
76 if (cgf.emitLabel(*ls->getDecl()).failed())
77 return mlir::failure();
78 exprResult = ls->getSubStmt();
79 } else if (const auto *as = dyn_cast<AttributedStmt>(exprResult)) {
80 // FIXME: Update this if we ever have attributes that affect the
81 // semantics of an expression.
82 exprResult = as->getSubStmt();
83 } else {
84 llvm_unreachable("Unknown value statement");
85 }
86 }
87
88 const Expr *e = cast<Expr>(exprResult);
89 QualType exprTy = e->getType();
90 if (cgf.hasAggregateEvaluationKind(exprTy)) {
91 cgf.emitAggExpr(e, slot);
92 } else {
93 // We can't return an RValue here because there might be cleanups at
94 // the end of the StmtExpr. Because of that, we have to emit the result
95 // here into a temporary alloca.
96 cgf.emitAnyExprToMem(e, *lastValue, Qualifiers(),
97 /*IsInit*/ false);
98 }
99
100 return mlir::success();
101}
102
104 const CompoundStmt &s, Address *lastValue, AggValueSlot slot) {
105 mlir::LogicalResult result = mlir::success();
106 const Stmt *exprResult = s.body_back();
107 assert((!lastValue || (lastValue && exprResult)) &&
108 "If lastValue is not null then the CompoundStmt must have a "
109 "StmtExprResult");
110
111 for (const Stmt *curStmt : s.body()) {
112 const bool saveResult = lastValue && exprResult == curStmt;
113 if (saveResult) {
114 if (emitStmtWithResult(*this, exprResult, slot, lastValue).failed())
115 result = mlir::failure();
116 } else {
117 if (emitStmt(curStmt, /*useCurrentScope=*/false).failed())
118 result = mlir::failure();
119 }
120 }
121 return result;
122}
123
124mlir::LogicalResult
126
127 bool noinline = inNoInlineAttributedStmt;
128 bool alwaysinline = inAlwaysInlineAttributedStmt;
129 const CallExpr *musttail = mustTailCall;
130 const AtomicAttr *atomicAttr = nullptr;
131
132 for (const Attr *attr : s.getAttrs()) {
133 switch (attr->getKind()) {
134 default:
135 break;
136 case attr::Atomic:
137 atomicAttr = cast<AtomicAttr>(attr);
138 break;
139 case attr::NoMerge:
140 case attr::NoConvergent:
141 case attr::AMDGPUAvailableVisible:
142 case attr::HLSLControlFlowHint:
143 cgm.errorNYI(s.getSourceRange(),
144 "Unimplemented statement attribute: ", attr->getKind());
145 break;
146 case attr::NoInline:
147 noinline = true;
148 alwaysinline = false;
149 break;
150 case attr::AlwaysInline:
151 alwaysinline = true;
152 noinline = false;
153 break;
154 case attr::MustTail: {
155 const Stmt *sub = s.getSubStmt();
156 const ReturnStmt *ret = cast<ReturnStmt>(sub);
157 musttail = cast<CallExpr>(ret->getRetValue()->IgnoreParens());
158 break;
159 }
160 case attr::CXXAssume: {
161 const Expr *assumptionExpr = cast<CXXAssumeAttr>(attr)->getAssumption();
162 if (getLangOpts().CXXAssumptions && builder.getInsertionBlock() &&
163 !assumptionExpr->HasSideEffects(getContext())) {
164 mlir::Value assumptionValue = emitCheckedArgForAssume(assumptionExpr);
165 cir::AssumeOp::create(builder, getLoc(s.getSourceRange()),
166 assumptionValue, cir::AssumeBundleKind::None,
167 mlir::ValueRange{});
168 }
169 } break;
170 }
171 }
172
173 assert(!(alwaysinline && noinline) &&
174 "alwaysinline and noinline are mutually exclusive");
175
176 SaveAndRestore save_noinline(inNoInlineAttributedStmt, noinline);
177 SaveAndRestore save_alwaysinline(inAlwaysInlineAttributedStmt, alwaysinline);
178
179 SaveAndRestore save_musttail(mustTailCall, musttail);
180
181 // clang::atomic adjusts the atomic options for the extent of the statement it
182 // is attached to, so they are saved and restored around it.
183 clang::AtomicOptions savedAtomicOpts = cgm.getAtomicOpts();
184 cgm.setAtomicOpts(getAdjustedAtomicOptions(savedAtomicOpts, atomicAttr));
185
186 mlir::LogicalResult result =
187 emitStmt(s.getSubStmt(), /*useCurrentScope=*/false, s.getAttrs());
188
189 cgm.setAtomicOpts(savedAtomicOpts);
190 return result;
191}
192
194 Address *lastValue,
195 AggValueSlot slot) {
196 // Add local scope to track new declared variables.
198 mlir::Location scopeLoc = getLoc(s.getSourceRange());
199 mlir::OpBuilder::InsertPoint scopeInsPt;
200 cir::ScopeOp::create(
201 builder, scopeLoc,
202 [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
203 scopeInsPt = b.saveInsertionPoint();
204 });
205 mlir::OpBuilder::InsertionGuard guard(builder);
206 builder.restoreInsertionPoint(scopeInsPt);
207 LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
208 return emitCompoundStmtWithoutScope(s, lastValue, slot);
209}
210
214
215// Build CIR for a statement. useCurrentScope should be true if no new scopes
216// need to be created when finding a compound statement.
217mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
218 bool useCurrentScope,
220 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
221 return mlir::success();
222
223 switch (s->getStmtClass()) {
225 case Stmt::CXXCatchStmtClass:
226 case Stmt::SEHExceptStmtClass:
227 case Stmt::SEHFinallyStmtClass:
228 case Stmt::MSDependentExistsStmtClass:
229 case Stmt::UnresolvedSYCLKernelCallStmtClass:
230 llvm_unreachable("invalid statement class to emit generically");
231 case Stmt::BreakStmtClass:
232 case Stmt::NullStmtClass:
233 case Stmt::CompoundStmtClass:
234 case Stmt::ContinueStmtClass:
235 case Stmt::DeclStmtClass:
236 case Stmt::ReturnStmtClass:
237 llvm_unreachable("should have emitted these statements as simple");
238
239#define STMT(Type, Base)
240#define ABSTRACT_STMT(Op)
241#define EXPR(Type, Base) case Stmt::Type##Class:
242#include "clang/AST/StmtNodes.inc"
243 {
244 assert(builder.getInsertionBlock() &&
245 "expression emission must have an insertion point");
246
248
249 // Classic codegen has a check here to see if the emitter created a new
250 // block that isn't used (comparing the incoming and outgoing insertion
251 // points) and deletes the outgoing block if it's not used. In CIR, we
252 // will handle that during the cir.canonicalize pass.
253 return mlir::success();
254 }
255 case Stmt::IfStmtClass:
256 return emitIfStmt(cast<IfStmt>(*s));
257 case Stmt::SwitchStmtClass:
259 case Stmt::ForStmtClass:
260 return emitForStmt(cast<ForStmt>(*s), attr);
261 case Stmt::WhileStmtClass:
263 case Stmt::DoStmtClass:
264 return emitDoStmt(cast<DoStmt>(*s), attr);
265 case Stmt::CXXTryStmtClass:
267 case Stmt::CXXForRangeStmtClass:
269 case Stmt::CoroutineBodyStmtClass:
271 case Stmt::IndirectGotoStmtClass:
273 case Stmt::CoreturnStmtClass:
275 case Stmt::SYCLKernelCallStmtClass:
277 case Stmt::OpenACCComputeConstructClass:
279 case Stmt::OpenACCLoopConstructClass:
281 case Stmt::OpenACCCombinedConstructClass:
283 case Stmt::OpenACCDataConstructClass:
285 case Stmt::OpenACCEnterDataConstructClass:
287 case Stmt::OpenACCExitDataConstructClass:
289 case Stmt::OpenACCHostDataConstructClass:
291 case Stmt::OpenACCWaitConstructClass:
293 case Stmt::OpenACCInitConstructClass:
295 case Stmt::OpenACCShutdownConstructClass:
297 case Stmt::OpenACCSetConstructClass:
299 case Stmt::OpenACCUpdateConstructClass:
301 case Stmt::OpenACCCacheConstructClass:
303 case Stmt::OpenACCAtomicConstructClass:
305 case Stmt::GCCAsmStmtClass:
306 case Stmt::MSAsmStmtClass:
307 return emitAsmStmt(cast<AsmStmt>(*s));
308 case Stmt::OMPScopeDirectiveClass:
310 case Stmt::OMPErrorDirectiveClass:
312 case Stmt::OMPParallelDirectiveClass:
314 case Stmt::OMPTaskwaitDirectiveClass:
316 case Stmt::OMPTaskyieldDirectiveClass:
318 case Stmt::OMPBarrierDirectiveClass:
320 case Stmt::OMPMetaDirectiveClass:
322 case Stmt::OMPCanonicalLoopClass:
324 case Stmt::OMPSimdDirectiveClass:
326 case Stmt::OMPTileDirectiveClass:
328 case Stmt::OMPUnrollDirectiveClass:
330 case Stmt::OMPFuseDirectiveClass:
332 case Stmt::OMPForDirectiveClass:
334 case Stmt::OMPForSimdDirectiveClass:
336 case Stmt::OMPSectionsDirectiveClass:
338 case Stmt::OMPSectionDirectiveClass:
340 case Stmt::OMPSingleDirectiveClass:
342 case Stmt::OMPMasterDirectiveClass:
344 case Stmt::OMPCriticalDirectiveClass:
346 case Stmt::OMPParallelForDirectiveClass:
348 case Stmt::OMPParallelForSimdDirectiveClass:
351 case Stmt::OMPParallelMasterDirectiveClass:
353 case Stmt::OMPParallelSectionsDirectiveClass:
356 case Stmt::OMPTaskDirectiveClass:
358 case Stmt::OMPTaskgroupDirectiveClass:
360 case Stmt::OMPFlushDirectiveClass:
362 case Stmt::OMPDepobjDirectiveClass:
364 case Stmt::OMPScanDirectiveClass:
366 case Stmt::OMPOrderedStandaloneDirectiveClass:
369 case Stmt::OMPOrderedBlockAssocDirectiveClass:
372 case Stmt::OMPAtomicDirectiveClass:
374 case Stmt::OMPTargetDirectiveClass:
376 case Stmt::OMPTeamsDirectiveClass:
378 case Stmt::OMPCancellationPointDirectiveClass:
381 case Stmt::OMPCancelDirectiveClass:
383 case Stmt::OMPTargetDataDirectiveClass:
385 case Stmt::OMPTargetEnterDataDirectiveClass:
388 case Stmt::OMPTargetExitDataDirectiveClass:
390 case Stmt::OMPTargetParallelDirectiveClass:
392 case Stmt::OMPTargetParallelForDirectiveClass:
395 case Stmt::OMPTaskLoopDirectiveClass:
397 case Stmt::OMPTaskLoopSimdDirectiveClass:
399 case Stmt::OMPMaskedTaskLoopDirectiveClass:
401 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
404 case Stmt::OMPMasterTaskLoopDirectiveClass:
406 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
409 case Stmt::OMPParallelGenericLoopDirectiveClass:
412 case Stmt::OMPParallelMaskedDirectiveClass:
414 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
417 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
420 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
423 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
426 case Stmt::OMPDistributeDirectiveClass:
428 case Stmt::OMPDistributeParallelForDirectiveClass:
431 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
434 case Stmt::OMPDistributeSimdDirectiveClass:
436 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
439 case Stmt::OMPTargetParallelForSimdDirectiveClass:
442 case Stmt::OMPTargetSimdDirectiveClass:
444 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
447 case Stmt::OMPTargetUpdateDirectiveClass:
449 case Stmt::OMPTeamsDistributeDirectiveClass:
452 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
455 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
458 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
461 case Stmt::OMPTeamsGenericLoopDirectiveClass:
464 case Stmt::OMPTargetTeamsDirectiveClass:
466 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
469 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
472 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
475 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
478 case Stmt::OMPInteropDirectiveClass:
480 case Stmt::OMPDispatchDirectiveClass:
482 case Stmt::OMPGenericLoopDirectiveClass:
484 case Stmt::OMPReverseDirectiveClass:
486 case Stmt::OMPSplitDirectiveClass:
488 case Stmt::OMPInterchangeDirectiveClass:
490 case Stmt::OMPFlattenDirectiveClass:
492 case Stmt::OMPAssumeDirectiveClass:
494 case Stmt::OMPMaskedDirectiveClass:
496 case Stmt::OMPStripeDirectiveClass:
498 case Stmt::LabelStmtClass:
499 case Stmt::AttributedStmtClass:
500 case Stmt::GotoStmtClass:
501 case Stmt::DefaultStmtClass:
502 case Stmt::CaseStmtClass:
503 case Stmt::SEHLeaveStmtClass:
504 case Stmt::ObjCAtTryStmtClass:
505 case Stmt::ObjCAtThrowStmtClass:
506 case Stmt::ObjCAtSynchronizedStmtClass:
507 case Stmt::ObjCForCollectionStmtClass:
508 case Stmt::ObjCAutoreleasePoolStmtClass:
509 case Stmt::SEHTryStmtClass:
510 case Stmt::ObjCAtCatchStmtClass:
511 case Stmt::ObjCAtFinallyStmtClass:
512 case Stmt::DeferStmtClass:
513 case Stmt::CXXExpansionStmtPatternClass:
514 case Stmt::CXXExpansionStmtInstantiationClass:
515 cgm.errorNYI(s->getSourceRange(),
516 std::string("emitStmt: ") + s->getStmtClassName());
517 return mlir::failure();
518 case Stmt::CapturedStmtClass:
519 llvm_unreachable("CapturedStmt must be handled by the parent directive");
520 }
521
522 llvm_unreachable("Unexpected statement class");
523}
524
525mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
526 bool useCurrentScope) {
527 switch (s->getStmtClass()) {
528 default:
529 return mlir::failure();
530 case Stmt::DeclStmtClass:
531 return emitDeclStmt(cast<DeclStmt>(*s));
532 case Stmt::CompoundStmtClass:
533 if (useCurrentScope)
536 case Stmt::GotoStmtClass:
537 return emitGotoStmt(cast<GotoStmt>(*s));
538 case Stmt::ContinueStmtClass:
540
541 // NullStmt doesn't need any handling, but we need to say we handled it.
542 case Stmt::NullStmtClass:
543 break;
544
545 case Stmt::LabelStmtClass:
546 return emitLabelStmt(cast<LabelStmt>(*s));
547 case Stmt::CaseStmtClass:
548 case Stmt::DefaultStmtClass:
549 // If we reached here, we must not handling a switch case in the top level.
551 /*buildingTopLevelCase=*/false);
552 break;
553
554 case Stmt::BreakStmtClass:
555 return emitBreakStmt(cast<BreakStmt>(*s));
556 case Stmt::ReturnStmtClass:
558 case Stmt::AttributedStmtClass:
560 }
561
562 return mlir::success();
563}
564
565mlir::LogicalResult CIRGenFunction::emitLabelStmt(const clang::LabelStmt &s) {
566
567 if (emitLabel(*s.getDecl()).failed())
568 return mlir::failure();
569
570 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())
571 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");
572
573 return emitStmt(s.getSubStmt(), /*useCurrentScope=*/false);
574}
575
576// Add a terminating yield on a body region if no other terminators are used.
578 mlir::Location loc) {
579 if (r.empty())
580 return;
581
583 unsigned numBlocks = r.getBlocks().size();
584 for (auto &block : r.getBlocks()) {
585 // Already cleanup after return operations, which might create
586 // empty blocks if emitted as last stmt.
587 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
588 block.hasNoSuccessors())
589 eraseBlocks.push_back(&block);
590
591 if (block.empty() ||
592 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
593 mlir::OpBuilder::InsertionGuard guardCase(builder);
594 builder.setInsertionPointToEnd(&block);
595 builder.createYield(loc);
596 }
597 }
598
599 for (auto *b : eraseBlocks)
600 b->erase();
601}
602
603mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
604 mlir::LogicalResult res = mlir::success();
605 // The else branch of a consteval if statement is always the only branch
606 // that can be runtime evaluated.
607 const Stmt *constevalExecuted;
608 if (s.isConsteval()) {
609 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
610 if (!constevalExecuted) {
611 // No runtime code execution required
612 return res;
613 }
614 }
615
616 // C99 6.8.4.1: The first substatement is executed if the expression
617 // compares unequal to 0. The condition must be a scalar type.
618 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
619 if (s.isConsteval())
620 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
621
622 if (s.getInit())
623 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
624 return mlir::failure();
625
626 if (s.getConditionVariable())
628
629 // If the condition constant folds and can be elided, try to avoid
630 // emitting the condition and the dead arm of the if/else.
631 bool condConstant;
632 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
633 // Figure out which block (then or else) is executed.
634 const Stmt *executed = s.getThen();
635 const Stmt *skipped = s.getElse();
636 if (!condConstant) // Condition false?
637 std::swap(executed, skipped);
638
639 // If the skipped block has no labels in it, just emit the executed block.
640 // This avoids emitting dead code and simplifies the CFG substantially.
641 if (s.isConstexpr() || !containsLabel(skipped)) {
642 if (executed)
643 return emitStmt(executed, /*useCurrentScope=*/true);
644 // There is nothing to execute at runtime.
645 // TODO(cir): there is still an empty cir.scope generated by the caller.
646 return mlir::success();
647 }
648 }
649
652 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
653 };
654
655 // TODO: Add a new scoped symbol table.
656 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
657 // The if scope contains the full source range for IfStmt.
658 mlir::Location scopeLoc = getLoc(s.getSourceRange());
659 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
660 [&](mlir::OpBuilder &b, mlir::Location loc) {
661 LexicalScope lexScope{*this, scopeLoc,
662 builder.getInsertionBlock()};
663 res = ifStmtBuilder();
664 });
665
666 return res;
667}
668
669mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
670 assert(builder.getInsertionBlock() && "expected valid insertion point");
671
672 for (const Decl *i : s.decls())
673 emitDecl(*i, /*evaluateConditionDecl=*/true);
674
675 return mlir::success();
676}
677
678mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
679 mlir::Location loc = getLoc(s.getSourceRange());
680 const Expr *rv = s.getRetValue();
681
682 RunCleanupsScope cleanupScope(*this);
683 bool createNewScope = false;
684 if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) {
685 rv = ewc->getSubExpr();
686 createNewScope = true;
687 }
688
689 auto handleReturnVal = [&]() {
690 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
693 // Apply the named return value optimization for this return statement,
694 // which means doing nothing: the appropriate result has already been
695 // constructed into the NRVO variable.
696
697 // If there is an NRVO flag for this variable, set it to 1 into indicate
698 // that the cleanup code should not destroy the variable.
699 if (auto nrvoFlag = nrvoFlags[s.getNRVOCandidate()])
700 builder.createFlagStore(loc, true, nrvoFlag);
701 } else if (!rv) {
702 // No return expression. Do nothing.
703 } else if (rv->getType()->isVoidType()) {
704 // Make sure not to return anything, but evaluate the expression
705 // for side effects.
706 if (rv) {
707 emitAnyExpr(rv);
708 }
709 } else if (cast<FunctionDecl>(curGD.getDecl())
710 ->getReturnType()
711 ->isReferenceType()) {
712 // If this function returns a reference, take the address of the
713 // expression rather than the value.
715 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(),
716 *fnRetAlloca);
717 } else {
718 mlir::Value value = nullptr;
720 case cir::TEK_Scalar:
721 value = emitScalarExpr(rv);
722 if (value) { // Change this to an assert once emitScalarExpr is complete
723 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
724 }
725 break;
726 case cir::TEK_Complex:
729 /*isInit=*/true);
730 break;
737 break;
738 }
739 }
740 };
741
742 if (!createNewScope) {
743 handleReturnVal();
744 } else {
745 FullExprCleanupScope fullExprScope(*this, rv);
746 handleReturnVal();
747 }
748
749 cleanupScope.forceCleanup();
750
751 // Classic codegen emits a branch through any cleanups before continuing to
752 // a shared return block. Because CIR handles branching through cleanups
753 // during the CFG flattening phase, we can just emit the return statement
754 // directly.
755 // TODO(cir): Eliminate this redundant load and the store above when we can.
756 if (fnRetAlloca) {
757 // Load the value from `__retval` and return it via the `cir.return` op.
758 cir::AllocaOp retAlloca =
759 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
760 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
761 *fnRetAlloca);
762
763 cir::ReturnOp::create(builder, loc, {value});
764 } else {
765 cir::ReturnOp::create(builder, loc);
766 }
767
768 // Insert the new block to continue codegen after the return statement.
769 // This will get deleted if we don't populate it. This handles the case of
770 // unreachable statements below a return.
771 builder.createBlock(builder.getBlock()->getParent());
772 return mlir::success();
773}
774
775mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
776 // FIXME: LLVM codegen inserts emit a stop point here for debug info
777 // sake when the insertion point is available, but doesn't do
778 // anything special when there isn't. We haven't implemented debug
779 // info support just yet, look at this again once we have it.
781
782 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),
783 s.getLabel()->getName());
784
785 // A goto marks the end of a block, create a new one for codegen after
786 // emitGotoStmt can resume building in that block.
787 // Insert the new block to continue codegen after goto.
788 builder.createBlock(builder.getBlock()->getParent());
789
790 return mlir::success();
791}
792
793mlir::LogicalResult
795 // An indirect goto with an active cleanup may leave its scope. Determining
796 // whether its dynamic destination requires cleanup is not implemented.
797 if (ehStack.stable_begin() != prologueCleanupDepth) {
798 cgm.errorNYI(s.getSourceRange(), "indirect goto with active cleanup");
799 return mlir::success();
800 }
801
802 mlir::Value val = emitScalarExpr(s.getTarget());
803 // Emit a symbolic indirect goto. GotoSolver resolves it into the shared
804 // indirect-branch block after FlattenCFG merges regions, so this stays valid
805 // even when the goto sits inside a nested scope.
806 cir::IndirectGotoOp::create(builder, getLoc(s.getSourceRange()), val);
807
808 // The indirect goto ends the block; open a fresh one so codegen can resume.
809 builder.createBlock(builder.getBlock()->getParent());
810 return mlir::success();
811}
812
813mlir::LogicalResult
815 builder.createContinue(getLoc(s.getKwLoc()));
816
817 // Insert the new block to continue codegen after the continue statement.
818 builder.createBlock(builder.getBlock()->getParent());
819
820 return mlir::success();
821}
822
823mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
824 // Create a new block to tag with a label and add a branch from
825 // the current one to it. If the block is empty just call attach it
826 // to this label.
827 mlir::Block *currBlock = builder.getBlock();
828 mlir::Block *labelBlock = currBlock;
829
830 if (!currBlock->empty() || currBlock->isEntryBlock()) {
831 {
832 mlir::OpBuilder::InsertionGuard guard(builder);
833 labelBlock = builder.createBlock(builder.getBlock()->getParent());
834 }
835 cir::BrOp::create(builder, getLoc(d.getSourceRange()), labelBlock);
836 }
837
838 builder.setInsertionPointToEnd(labelBlock);
839 cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
840 // In a coroutine, the label makes the end of the body reachable again even
841 // after a co_return, so the implicit `co_return;` must not be left out.
842 if (curLexScope)
843 curLexScope->clearCoreturnInEnclosingScopes();
844 // FIXME: emit debug info for labels, incrementProfileCounter
847 return mlir::success();
848}
849
850mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
851 builder.createBreak(getLoc(s.getKwLoc()));
852
853 // Insert the new block to continue codegen after the break statement.
854 builder.createBlock(builder.getBlock()->getParent());
855
856 return mlir::success();
857}
858
859template <typename T>
860mlir::LogicalResult
862 mlir::ArrayAttr value, CaseOpKind kind,
863 bool buildingTopLevelCase) {
864
866 "only case or default stmt go here");
867
868 mlir::LogicalResult result = mlir::success();
869
870 mlir::Location loc = getLoc(stmt->getBeginLoc());
871
872 enum class SubStmtKind { Case, Default, Other };
873 SubStmtKind subStmtKind = SubStmtKind::Other;
874 const Stmt *sub = stmt->getSubStmt();
875
876 mlir::OpBuilder::InsertPoint insertPoint;
877 CaseOp::create(builder, loc, value, kind, insertPoint);
878
879 {
880 mlir::OpBuilder::InsertionGuard guardSwitch(builder);
881 builder.restoreInsertionPoint(insertPoint);
882
883 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
884 subStmtKind = SubStmtKind::Default;
885 builder.createYield(loc);
886 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
887 subStmtKind = SubStmtKind::Case;
888 builder.createYield(loc);
889 } else {
890 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
891 }
892
893 insertPoint = builder.saveInsertionPoint();
894 }
895
896 // If the substmt is default stmt or case stmt, try to handle the special case
897 // to make it into the simple form. e.g.
898 //
899 // switch () {
900 // case 1:
901 // default:
902 // ...
903 // }
904 //
905 // we prefer generating
906 //
907 // cir.switch() {
908 // cir.case(equal, 1) {
909 // cir.yield
910 // }
911 // cir.case(default) {
912 // ...
913 // }
914 // }
915 //
916 // than
917 //
918 // cir.switch() {
919 // cir.case(equal, 1) {
920 // cir.case(default) {
921 // ...
922 // }
923 // }
924 // }
925 //
926 // We don't need to revert this if we find the current switch can't be in
927 // simple form later since the conversion itself should be harmless.
928 if (subStmtKind == SubStmtKind::Case) {
929 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
930 } else if (subStmtKind == SubStmtKind::Default) {
931 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
932 buildingTopLevelCase);
933 } else if (buildingTopLevelCase) {
934 // If we're building a top level case, try to restore the insert point to
935 // the case we're building, then we can attach more random stmts to the
936 // case to make generating `cir.switch` operation to be a simple form.
937 builder.restoreInsertionPoint(insertPoint);
938 }
939
940 return result;
941}
942
943mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
944 mlir::Type condType,
945 bool buildingTopLevelCase) {
946 cir::CaseOpKind kind;
947 mlir::ArrayAttr value;
948 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
949
950 // Coerce a bool to an i1 for a switch, so we can just treat all its elements
951 // as an int later on.
952 if (isa<cir::BoolType>(condType))
953 condType = builder.getUIntNTy(1);
954
955 // If the case statement has an RHS value, it is representing a GNU
956 // case range statement, where LHS is the beginning of the range
957 // and RHS is the end of the range.
958 if (const Expr *rhs = s.getRHS()) {
959 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
960 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
961 cir::IntAttr::get(condType, endVal)});
962 kind = cir::CaseOpKind::Range;
963 } else {
964 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
965 kind = cir::CaseOpKind::Equal;
966 }
967
968 return emitCaseDefaultCascade(&s, condType, value, kind,
969 buildingTopLevelCase);
970}
971
973 mlir::Type condType,
974 bool buildingTopLevelCase) {
975 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
976 cir::CaseOpKind::Default, buildingTopLevelCase);
977}
978
979mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
980 bool buildingTopLevelCase) {
981 assert(!condTypeStack.empty() &&
982 "build switch case without specifying the type of the condition");
983
984 if (s.getStmtClass() == Stmt::CaseStmtClass)
985 return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
986 buildingTopLevelCase);
987
988 if (s.getStmtClass() == Stmt::DefaultStmtClass)
990 buildingTopLevelCase);
991
992 llvm_unreachable("expect case or default stmt");
993}
994
996 bool mustProgress) {
997 // Determine the state of the hints, the same way classic codegen does.
1000 cgm.getCodeGenOpts(), attrs, mustProgress);
1001
1002 // Memory accesses in a `parallel` loop are tagged as parallel accesses when
1003 // CIR is lowered.
1005 mlir::MLIRContext *ctx = &getMLIRContext();
1006
1007 auto convertFlag = [&](bool set) {
1008 return set ? mlir::UnitAttr::get(ctx) : mlir::UnitAttr();
1009 };
1010 auto convertStateToBool =
1012 switch (state) {
1014 return mlir::BoolAttr();
1016 return mlir::BoolAttr::get(ctx, true);
1018 return mlir::BoolAttr::get(ctx, false);
1020 llvm_unreachable("'full' only applies to unrolling");
1021 }
1022 llvm_unreachable("unknown bool state");
1023 };
1024
1025 auto convertUnrollMode = [](CodeGenUtils::LoopAttributes::LVEnableState state)
1026 -> std::optional<cir::LoopUnrollMode> {
1027 switch (state) {
1029 return std::nullopt;
1031 return cir::LoopUnrollMode::Enable;
1033 return cir::LoopUnrollMode::Disable;
1035 return cir::LoopUnrollMode::Full;
1036 }
1037
1038 llvm_unreachable("unknown unroll state");
1039 };
1040
1041 // Only OMP seems to generate this, so leave as an NYI for now. The dialect
1042 // can comprehend this/it will work correctly, but no tests exist. Once we get
1043 // good OMP tests for this, we should be able to remove this NYI.
1044 if (loopAttrs.VectorizeEnable ==
1046 loopAttrs.VectorizeEnable ==
1048 cgm.errorNYI(SourceLocation{}, "unsupported vector-enable loop state");
1049
1050 auto hints = cir::LoopHintAttr::get(
1051 ctx, convertFlag(loopAttrs.MustProgress),
1052 convertStateToBool(loopAttrs.VectorizeEnable), loopAttrs.VectorizeWidth,
1053 convertStateToBool(loopAttrs.VectorizeScalable),
1054 convertStateToBool(loopAttrs.VectorizePredicateEnable),
1055 loopAttrs.InterleaveCount, convertUnrollMode(loopAttrs.UnrollEnable),
1056 loopAttrs.UnrollCount, convertUnrollMode(loopAttrs.UnrollAndJamEnable),
1057 loopAttrs.UnrollAndJamCount,
1058 convertStateToBool(loopAttrs.DistributeEnable),
1059 convertFlag(loopAttrs.PipelineDisabled),
1060 loopAttrs.PipelineInitiationInterval, convertFlag(loopAttrs.LICMDisabled),
1061 convertFlag(loopAttrs.IsParallel), loopAttrs.CodeAlign);
1062
1063 if (hints.isEmpty())
1064 return {};
1065 return hints;
1066}
1067
1068static void setLoopHints(cir::LoopOpInterface loopOp,
1069 cir::LoopHintAttr loopHints) {
1070 if (!loopHints)
1071 return;
1072 loopOp.setLoopHintsAttr(loopHints);
1073 loopOp.setLoopIdAttr(
1074 mlir::DistinctAttr::create(mlir::UnitAttr::get(loopOp->getContext())));
1075}
1076
1077mlir::LogicalResult
1079 ArrayRef<const Attr *> forAttrs) {
1080 cir::ForOp forOp;
1081
1082 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
1083 mlir::LogicalResult loopRes = mlir::success();
1084 // Evaluate the first pieces before the loop.
1085 if (s.getInit())
1086 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1087 return mlir::failure();
1088 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
1089 return mlir::failure();
1090 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
1091 return mlir::failure();
1092 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
1093 return mlir::failure();
1094
1095 // FIXME: Classic codegen never sets 'must progress' on these loops, but
1096 // probably could?
1097 cir::LoopHintAttr loopHints =
1098 getLoopHints(forAttrs, /*mustProgress=*/false);
1099
1100 forOp = builder.createFor(
1102 /*condBuilder=*/
1103 [&](mlir::OpBuilder &b, mlir::Location loc) {
1104 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
1105 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
1106 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1107 builder.createCondition(condVal);
1108 },
1109 /*bodyBuilder=*/
1110 [&](mlir::OpBuilder &b, mlir::Location loc) {
1111 // https://en.cppreference.com/w/cpp/language/for
1112 // In C++ the scope of the init-statement and the scope of
1113 // statement are one and the same.
1114 RunCleanupsScope bodyScope(*this);
1115 bool useCurrentScope = true;
1116 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
1117 loopRes = mlir::failure();
1118 if (emitStmt(s.getBody(), useCurrentScope).failed())
1119 loopRes = mlir::failure();
1120 emitStopPoint(&s);
1121 },
1122 /*stepBuilder=*/
1123 [&](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 setLoopHints(forOp, loopHints);
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 // Create a cleanup scope for the condition
1138 // variable cleanups. Logical equivalent from
1139 // LLVM codegn for LexicalScope
1140 // ConditionScope(*this, S.getSourceRange())...
1141 LexicalScope lexScope{*this, loc,
1142 builder.getInsertionBlock()};
1143 res = forStmtBuilder();
1144 });
1145
1146 if (res.failed())
1147 return res;
1148
1149 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1150 return mlir::success();
1151}
1152
1153mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s,
1154 ArrayRef<const Attr *> attrs) {
1155 cir::ForOp forOp;
1156
1157 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
1158 mlir::LogicalResult loopRes = mlir::success();
1159 // Evaluate the first part before the loop.
1160 if (s.getInit())
1161 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1162 return mlir::failure();
1163 bool mustProgress =
1165 cir::LoopHintAttr loopHints = getLoopHints(attrs, mustProgress);
1166
1167 // A condition variable's lifetime is a single iteration, so capture its
1168 // destructor and lifetime-end cleanups, and those of the temporaries that
1169 // its initializer lifetime-extends, and emit them into the loop's
1170 // per-iteration cleanup region. This scope is constructed after the
1171 // init-statement so the init-statement's cleanups are not captured.
1172 const VarDecl *condVar = s.getConditionVariable();
1173 SmallVector<QualType, 2> condVarExtendedTemporaries;
1174 if (condVar)
1175 condVarExtendedTemporaries =
1177 bool needsCondCleanup =
1178 condVar &&
1180 shouldEmitLifetimeMarkersForAutoVar() ||
1181 !condVarExtendedTemporaries.empty());
1182 CapturedCleanups loopCondScope(*this, needsCondCleanup);
1183
1184 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1187 mlir::Value condVal;
1188 if (s.getCond()) {
1189 // If the for statement declares a condition variable, emit that here.
1190 if (condVar)
1191 emitLoopConditionVariable(*condVar, loopCondScope,
1192 condVarExtendedTemporaries);
1193 // C99 6.8.5p2/p4: The first substatement is executed if the
1194 // expression compares unequal to 0. The condition must be a
1195 // scalar type.
1196 condVal = evaluateExprAsBool(s.getCond());
1197 } else {
1198 condVal = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
1199 }
1200 builder.createCondition(condVal);
1201 };
1202 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1203 // The scope of the for loop body is nested within the scope of the
1204 // for loop's init-statement and condition.
1205 RunCleanupsScope bodyScope(*this);
1206 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1207 loopRes = mlir::failure();
1208 emitStopPoint(&s);
1209 };
1210 auto stepBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1211 if (s.getInc())
1212 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
1213 loopRes = mlir::failure();
1214 builder.createYield(loc);
1215 };
1216
1217 if (needsCondCleanup) {
1218 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1219 ? cir::CleanupKind::All
1220 : cir::CleanupKind::Normal;
1221 forOp = builder.createFor(
1222 getLoc(s.getSourceRange()), condBuilder, bodyBuilder, stepBuilder,
1223 /*cleanupBuilder=*/
1224 [&](mlir::OpBuilder &b, mlir::Location loc) {
1225 loopCondScope.emitIntoCleanupRegion(loc);
1226 builder.createYield(loc);
1227 },
1228 cleanupKind);
1229 } else {
1230 forOp = builder.createFor(getLoc(s.getSourceRange()), condBuilder,
1231 bodyBuilder, stepBuilder);
1232 }
1233
1234 setLoopHints(forOp, loopHints);
1235 return loopRes;
1236 };
1237
1238 auto res = mlir::success();
1239 auto scopeLoc = getLoc(s.getSourceRange());
1240 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1241 [&](mlir::OpBuilder &b, mlir::Location loc) {
1242 LexicalScope lexScope{*this, loc,
1243 builder.getInsertionBlock()};
1244 res = forStmtBuilder();
1245 });
1246
1247 if (res.failed())
1248 return res;
1249
1250 terminateStructuredRegionBody(forOp.getBody(), getLoc(s.getEndLoc()));
1251 return mlir::success();
1252}
1253
1254mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s,
1255 ArrayRef<const Attr *> attrs) {
1256 cir::DoWhileOp doWhileOp;
1257
1258 auto doStmtBuilder = [&]() -> mlir::LogicalResult {
1259 mlir::LogicalResult loopRes = mlir::success();
1260 bool mustProgress =
1262 cir::LoopHintAttr loopHints = getLoopHints(attrs, mustProgress);
1263
1264 doWhileOp = builder.createDoWhile(
1266 /*condBuilder=*/
1267 [&](mlir::OpBuilder &b, mlir::Location loc) {
1268 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
1269 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
1270 // C99 6.8.5p2/p4: The first substatement is executed if the
1271 // expression compares unequal to 0. The condition must be a
1272 // scalar type.
1273 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1274 builder.createCondition(condVal);
1275 },
1276 /*bodyBuilder=*/
1277 [&](mlir::OpBuilder &b, mlir::Location loc) {
1278 // The scope of the do-while loop body is a nested scope.
1279 RunCleanupsScope bodyScope(*this);
1280 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1281 loopRes = mlir::failure();
1282 emitStopPoint(&s);
1283 });
1284 setLoopHints(doWhileOp, loopHints);
1285 return loopRes;
1286 };
1287
1288 mlir::LogicalResult res = mlir::success();
1289 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1290 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1291 [&](mlir::OpBuilder &b, mlir::Location loc) {
1292 LexicalScope lexScope{*this, loc,
1293 builder.getInsertionBlock()};
1294 res = doStmtBuilder();
1295 });
1296
1297 if (res.failed())
1298 return res;
1299
1300 terminateStructuredRegionBody(doWhileOp.getBody(), getLoc(s.getEndLoc()));
1301 return mlir::success();
1302}
1303
1304mlir::LogicalResult
1306 ArrayRef<const Attr *> attrs) {
1307 cir::WhileOp whileOp;
1308
1309 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
1310 mlir::LogicalResult loopRes = mlir::success();
1311 bool mustProgress =
1313 cir::LoopHintAttr loopHints = getLoopHints(attrs, mustProgress);
1314
1315 // A condition variable's lifetime is a single iteration, so capture its
1316 // destructor and lifetime-end cleanups, and those of the temporaries that
1317 // its initializer lifetime-extends, and emit them into the loop's
1318 // per-iteration cleanup region.
1319 const VarDecl *condVar = s.getConditionVariable();
1320 SmallVector<QualType, 2> condVarExtendedTemporaries;
1321 if (condVar)
1322 condVarExtendedTemporaries =
1324 bool needsCondCleanup =
1325 condVar &&
1327 shouldEmitLifetimeMarkersForAutoVar() ||
1328 !condVarExtendedTemporaries.empty());
1329 CapturedCleanups loopCondScope(*this, needsCondCleanup);
1330
1331 auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1334 // If the while statement declares a condition variable, emit that here.
1335 if (condVar)
1336 emitLoopConditionVariable(*condVar, loopCondScope,
1337 condVarExtendedTemporaries);
1338 // C99 6.8.5p2/p4: The first substatement is executed if the
1339 // expression compares unequal to 0. The condition must be a
1340 // scalar type.
1341 mlir::Value condVal = evaluateExprAsBool(s.getCond());
1342 builder.createCondition(condVal);
1343 };
1344 auto bodyBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1345 // The scope of the while loop body is a nested scope.
1346 RunCleanupsScope bodyScope(*this);
1347 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
1348 loopRes = mlir::failure();
1349 emitStopPoint(&s);
1350 };
1351
1352 if (needsCondCleanup) {
1353 cir::CleanupKind cleanupKind = getLangOpts().Exceptions
1354 ? cir::CleanupKind::All
1355 : cir::CleanupKind::Normal;
1356 whileOp = builder.createWhile(
1357 getLoc(s.getSourceRange()), condBuilder, bodyBuilder,
1358 /*cleanupBuilder=*/
1359 [&](mlir::OpBuilder &b, mlir::Location loc) {
1360 loopCondScope.emitIntoCleanupRegion(loc);
1361 builder.createYield(loc);
1362 },
1363 cleanupKind);
1364 } else {
1365 whileOp = builder.createWhile(getLoc(s.getSourceRange()), condBuilder,
1366 bodyBuilder);
1367 }
1368 setLoopHints(whileOp, loopHints);
1369 return loopRes;
1370 };
1371
1372 mlir::LogicalResult res = mlir::success();
1373 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1374 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1375 [&](mlir::OpBuilder &b, mlir::Location loc) {
1376 LexicalScope lexScope{*this, loc,
1377 builder.getInsertionBlock()};
1378 res = whileStmtBuilder();
1379 });
1380
1381 if (res.failed())
1382 return res;
1383
1384 terminateStructuredRegionBody(whileOp.getBody(), getLoc(s.getEndLoc()));
1385 return mlir::success();
1386}
1387
1388mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
1389 // It is rare but legal if the switch body is not a compound stmt. e.g.,
1390 //
1391 // switch(a)
1392 // while(...) {
1393 // case1
1394 // ...
1395 // case2
1396 // ...
1397 // }
1398 if (!isa<CompoundStmt>(s))
1399 return emitStmt(s, /*useCurrentScope=*/true);
1400
1402
1403 ArrayRef<Stmt *> body{compoundStmt->body_begin(), compoundStmt->body_end()};
1404
1405 mlir::Block *switchBlock = builder.getBlock();
1406
1407 // Any statements appearing before the first case statement are 'unassociated'
1408 // with anything. So we have to create them FIRST in their own block. After
1409 // that, the 'case' regions will take care of future ones.
1410 if (!body.empty() && !isa<SwitchCase>(body.front())) {
1411 builder.setInsertionPointToEnd(switchBlock);
1412 {
1413 // This is needed to handle cleanups in a compound statement before the
1414 // first case statement.
1415 RunCleanupsScope preCaseScope(*this);
1416 while (!body.empty() && !isa<SwitchCase>(body.front())) {
1417
1418 auto *c = body.front();
1419 if (mlir::failed(
1420 emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1421 return mlir::failure();
1422
1423 body = body.drop_front();
1424 }
1425 }
1426
1427 // Now that we've emitted ALL of the statements, we can create a new block
1428 // for the actual case statements/etc to appear.
1429 mlir::Block *lastBlock = builder.getBlock();
1430 switchBlock = builder.createBlock(switchBlock->getParent());
1431 builder.setInsertionPointToEnd(lastBlock);
1432 cir::BrOp::create(builder, getLoc(s->getSourceRange()), switchBlock);
1433 }
1434
1435 for (auto *c : body) {
1436 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
1437 builder.setInsertionPointToEnd(switchBlock);
1438 // Reset insert point automatically, so that we can attach following
1439 // random stmt to the region of previous built case op to try to make
1440 // the being generated `cir.switch` to be in simple form.
1441 if (mlir::failed(
1442 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
1443 return mlir::failure();
1444
1445 continue;
1446 }
1447
1448 // Otherwise, just build the statements in the nearest case region.
1449 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1450 return mlir::failure();
1451 }
1452
1453 return mlir::success();
1454}
1455
1457 // TODO: LLVM codegen does some early optimization to fold the condition and
1458 // only emit live cases. CIR should use MLIR to achieve similar things,
1459 // nothing to be done here.
1460 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
1462
1463 SwitchOp swop;
1464 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
1465 if (s.getInit())
1466 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1467 return mlir::failure();
1468
1469 if (s.getConditionVariable())
1470 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
1471
1472 mlir::Value condV = emitScalarExpr(s.getCond());
1473
1474 // Coerce bool values to an i1. There is no real sensible reason we need to
1475 // represent a 'switch' of scoped-enum-with-bool-backing-type specially
1476 // here. It is a rarely used thing, and would result in a lot of work to
1477 // properly handle this everywhere.
1478 if (isa<cir::BoolType>(condV.getType()))
1479 condV = builder.createBoolToInt(condV, builder.getUIntNTy(1));
1480
1481 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
1484 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
1486
1487 mlir::LogicalResult res = mlir::success();
1488 swop = SwitchOp::create(
1489 builder, getLoc(s.getBeginLoc()), condV,
1490 /*switchBuilder=*/
1491 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
1492 curLexScope->setAsSwitch();
1493
1494 condTypeStack.push_back(condV.getType());
1495
1496 res = emitSwitchBody(s.getBody());
1497
1498 condTypeStack.pop_back();
1499 });
1500
1501 return res;
1502 };
1503
1504 // The switch scope contains the full source range for SwitchStmt.
1505 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1506 mlir::LogicalResult res = mlir::success();
1507 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1508 [&](mlir::OpBuilder &b, mlir::Location loc) {
1509 LexicalScope lexScope{*this, loc,
1510 builder.getInsertionBlock()};
1511 res = switchStmtBuilder();
1512 });
1513
1515 swop.collectCases(cases);
1516 for (auto caseOp : cases)
1517 terminateStructuredRegionBody(caseOp.getCaseRegion(), caseOp.getLoc());
1518 terminateStructuredRegionBody(swop.getBody(), swop.getLoc());
1519
1520 swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered());
1521
1522 return res;
1523}
1524
1525void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv,
1526 QualType ty) {
1527 if (rv.isScalar()) {
1528 builder.createStore(loc, rv.getValue(), returnValue);
1529 } else if (rv.isAggregate()) {
1530 Address rvAddr = rv.getAggregateAddress();
1531 // If the aggregate is already in the return slot (e.g. a callee was
1532 // invoked through a ReturnValueSlot bound to returnValue), the copy is
1533 // a no-op. Calling emitAggregateCopy here would also incorrectly
1534 // require the type to have a trivial copy/move.
1535 if (rvAddr.getPointer() != returnValue.getPointer()) {
1536 LValue dest = makeAddrLValue(returnValue, ty);
1537 LValue src = makeAddrLValue(rvAddr, ty);
1539 }
1540 } else {
1541 assert(rv.isComplex() && "Unknown rvalue kind?");
1542 builder.createStore(loc, rv.getComplexValue(), returnValue);
1543 }
1544
1545 // Classic codegen emits a branch through any cleanups before continuing to
1546 // a shared return block. Because CIR handles branching through cleanups
1547 // during the CFG flattening phase, we can just emit the return statement
1548 // directly.
1549 // TODO(cir): Eliminate this redundant load and the store above when we can.
1550 // Load the value from `__retval` and return it via the `cir.return` op.
1551 cir::AllocaOp retAlloca =
1552 mlir::cast<cir::AllocaOp>(fnRetAlloca->getDefiningOp());
1553 auto value = cir::LoadOp::create(builder, loc, retAlloca.getAllocaType(),
1554 *fnRetAlloca);
1555
1556 cir::ReturnOp::create(builder, loc, {value});
1557}
static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, const Stmt *exprResult, AggValueSlot slot, Address *lastValue)
static void setLoopHints(cir::LoopOpInterface loopOp, cir::LoopHintAttr loopHints)
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:47
Represents an attribute applied to a statement.
Definition Stmt.h:2214
Stmt * getSubStmt()
Definition Stmt.h:2250
ArrayRef< const Attr * > getAttrs() const
Definition Stmt.h:2246
BreakStmt - This represents a break.
Definition Stmt.h:3148
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 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 emitForStmt(const clang::ForStmt &s, llvm::ArrayRef< const Attr * > attrs={})
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 emitDoStmt(const clang::DoStmt &s, llvm::ArrayRef< const Attr * > attrs={})
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 emitWhileStmt(const clang::WhileStmt &s, llvm::ArrayRef< const Attr * > attrs={})
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 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)
cir::LoopHintAttr getLoopHints(llvm::ArrayRef< const Attr * > attrs, bool mustProgress)
Build the hints that get attached to a loop, or a null attribute if there is nothing to say about it.
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::MLIRContext & getMLIRContext()
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 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:3012
CaseStmt - Represent a case statement.
Definition Stmt.h:1931
Expr * getLHS()
Definition Stmt.h:2014
Expr * getRHS()
Definition Stmt.h:2026
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1751
body_range body()
Definition Stmt.h:1814
Stmt * body_back()
Definition Stmt.h:1819
ContinueStmt - This represents a continue.
Definition Stmt.h:3132
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1642
decl_range decls()
Definition Stmt.h:1690
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2843
Expr * getCond()
Definition Stmt.h:2861
SourceLocation getEndLoc() const
Definition Stmt.h:2880
This represents one expression.
Definition Expr.h:114
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:146
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition Stmt.h:2899
Stmt * getInit()
Definition Stmt.h:2914
VarDecl * getConditionVariable() const
Retrieve the variable declared in this "for" statement, if any.
Definition Stmt.cpp:1120
SourceLocation getEndLoc() const
Definition Stmt.h:2963
Stmt * getBody()
Definition Stmt.h:2943
Expr * getInc()
Definition Stmt.h:2942
Expr * getCond()
Definition Stmt.h:2941
GotoStmt - This represents a direct goto.
Definition Stmt.h:2980
LabelDecl * getLabel() const
Definition Stmt.h:2993
IfStmt - This represents an if/then/else.
Definition Stmt.h:2270
Stmt * getThen()
Definition Stmt.h:2359
Stmt * getInit()
Definition Stmt.h:2420
Expr * getCond()
Definition Stmt.h:2347
bool isConstexpr() const
Definition Stmt.h:2463
bool isNegatedConsteval() const
Definition Stmt.h:2459
Stmt * getElse()
Definition Stmt.h:2368
bool isConsteval() const
Definition Stmt.h:2450
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:3019
Represents the declaration of a label.
Definition Decl.h:526
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.h:556
LabelStmt - Represents a label, which has a substatement.
Definition Stmt.h:2157
LabelDecl * getDecl() const
Definition Stmt.h:2175
bool isSideEntry() const
Definition Stmt.h:2204
Stmt * getSubStmt()
Definition Stmt.h:2179
SourceLocation getKwLoc() const
Definition Stmt.h:3093
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:303
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:3173
const VarDecl * getNRVOCandidate() const
Retrieve the variable that might be used for the named return value optimization.
Definition Stmt.h:3209
Expr * getRetValue()
Definition Stmt.h:3200
Encodes a location in the source.
Stmt - This represents one statement.
Definition Stmt.h:85
@ NoStmtClass
Definition Stmt.h:88
StmtClass getStmtClass() const
Definition Stmt.h:1504
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:2520
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:2680
Expr * getCond()
Definition Stmt.h:2583
VarDecl * getConditionVariable()
Retrieve the variable declared in this "switch" statement, if any.
Definition Stmt.cpp:1186
Stmt * getInit()
Definition Stmt.h:2600
SourceLocation getBeginLoc() const
Definition Stmt.h:2684
bool isVoidType() const
Definition TypeBase.h:9200
Represents a variable declaration or definition.
Definition Decl.h:934
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1549
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2843
WhileStmt - This represents a 'while' stmt.
Definition Stmt.h:2708
Expr * getCond()
Definition Stmt.h:2760
VarDecl * getConditionVariable()
Retrieve the variable declared in this "while" statement, if any.
Definition Stmt.cpp:1247
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.h:2822
Stmt * getBody()
Definition Stmt.h:2772
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
void updateLoopAttributes(LoopAttributes &Attrs, ASTContext &Ctx, const CodeGenOptions &CGOpts, llvm::ArrayRef< const Attr * > StmtAttrs, bool MustProgress)
Update Attrs with the loop hints in StmtAttrs (#pragma clang loop, #pragma unroll,...
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:1787
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...
Attributes that may be specified on loops.
bool LICMDisabled
Value for llvm.licm.disable metadata.
LVEnableState VectorizeEnable
Value for llvm.loop.vectorize.enable metadata.
LVEnableState UnrollEnable
Value for llvm.loop.unroll.* metadata (enable, disable, or full).
unsigned PipelineInitiationInterval
Value for llvm.loop.pipeline.iicount metadata.
unsigned UnrollAndJamCount
llvm.unroll.
unsigned CodeAlign
Value for 'llvm.loop.align' metadata.
unsigned VectorizeWidth
Value for llvm.loop.vectorize.width metadata.
LVEnableState UnrollAndJamEnable
Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
LVEnableState VectorizePredicateEnable
Value for llvm.loop.vectorize.predicate metadata.
bool PipelineDisabled
Value for llvm.loop.pipeline.disable metadata.
bool IsParallel
Generate llvm.loop.parallel metadata for loads and stores.
LVEnableState
State of loop vectorization or unrolling.
bool MustProgress
Value for whether the loop is required to make progress.
LVEnableState DistributeEnable
Value for llvm.loop.distribute.enable metadata.
unsigned InterleaveCount
Value for llvm.loop.interleave.count metadata.