clang 22.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
24using namespace clang;
25using namespace clang::CIRGen;
26using namespace cir;
27
28static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf,
29 const Stmt *exprResult,
30 AggValueSlot slot,
31 Address *lastValue) {
32 // We have to special case labels here. They are statements, but when put
33 // at the end of a statement expression, they yield the value of their
34 // subexpression. Handle this by walking through all labels we encounter,
35 // emitting them before we evaluate the subexpr.
36 // Similar issues arise for attributed statements.
37 while (!isa<Expr>(exprResult)) {
38 if (const auto *ls = dyn_cast<LabelStmt>(exprResult)) {
39 if (cgf.emitLabel(*ls->getDecl()).failed())
40 return mlir::failure();
41 exprResult = ls->getSubStmt();
42 } else if (const auto *as = dyn_cast<AttributedStmt>(exprResult)) {
43 // FIXME: Update this if we ever have attributes that affect the
44 // semantics of an expression.
45 exprResult = as->getSubStmt();
46 } else {
47 llvm_unreachable("Unknown value statement");
48 }
49 }
50
51 const Expr *e = cast<Expr>(exprResult);
52 QualType exprTy = e->getType();
53 if (cgf.hasAggregateEvaluationKind(exprTy)) {
54 cgf.emitAggExpr(e, slot);
55 } else {
56 // We can't return an RValue here because there might be cleanups at
57 // the end of the StmtExpr. Because of that, we have to emit the result
58 // here into a temporary alloca.
59 cgf.emitAnyExprToMem(e, *lastValue, Qualifiers(),
60 /*IsInit*/ false);
61 }
62
63 return mlir::success();
64}
65
67 const CompoundStmt &s, Address *lastValue, AggValueSlot slot) {
68 mlir::LogicalResult result = mlir::success();
69 const Stmt *exprResult = s.body_back();
70 assert((!lastValue || (lastValue && exprResult)) &&
71 "If lastValue is not null then the CompoundStmt must have a "
72 "StmtExprResult");
73
74 for (const Stmt *curStmt : s.body()) {
75 const bool saveResult = lastValue && exprResult == curStmt;
76 if (saveResult) {
77 if (emitStmtWithResult(*this, exprResult, slot, lastValue).failed())
78 result = mlir::failure();
79 } else {
80 if (emitStmt(curStmt, /*useCurrentScope=*/false).failed())
81 result = mlir::failure();
82 }
83 }
84 return result;
85}
86
88 Address *lastValue,
89 AggValueSlot slot) {
90 // Add local scope to track new declared variables.
92 mlir::Location scopeLoc = getLoc(s.getSourceRange());
93 mlir::OpBuilder::InsertPoint scopeInsPt;
94 cir::ScopeOp::create(
95 builder, scopeLoc,
96 [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
97 scopeInsPt = b.saveInsertionPoint();
98 });
99 mlir::OpBuilder::InsertionGuard guard(builder);
100 builder.restoreInsertionPoint(scopeInsPt);
101 LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
102 return emitCompoundStmtWithoutScope(s, lastValue, slot);
103}
104
108
109// Build CIR for a statement. useCurrentScope should be true if no new scopes
110// need to be created when finding a compound statement.
111mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
112 bool useCurrentScope,
114 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
115 return mlir::success();
116
117 switch (s->getStmtClass()) {
119 case Stmt::CXXCatchStmtClass:
120 case Stmt::SEHExceptStmtClass:
121 case Stmt::SEHFinallyStmtClass:
122 case Stmt::MSDependentExistsStmtClass:
123 llvm_unreachable("invalid statement class to emit generically");
124 case Stmt::BreakStmtClass:
125 case Stmt::NullStmtClass:
126 case Stmt::CompoundStmtClass:
127 case Stmt::ContinueStmtClass:
128 case Stmt::DeclStmtClass:
129 case Stmt::ReturnStmtClass:
130 llvm_unreachable("should have emitted these statements as simple");
131
132#define STMT(Type, Base)
133#define ABSTRACT_STMT(Op)
134#define EXPR(Type, Base) case Stmt::Type##Class:
135#include "clang/AST/StmtNodes.inc"
136 {
137 assert(builder.getInsertionBlock() &&
138 "expression emission must have an insertion point");
139
141
142 // Classic codegen has a check here to see if the emitter created a new
143 // block that isn't used (comparing the incoming and outgoing insertion
144 // points) and deletes the outgoing block if it's not used. In CIR, we
145 // will handle that during the cir.canonicalize pass.
146 return mlir::success();
147 }
148 case Stmt::IfStmtClass:
149 return emitIfStmt(cast<IfStmt>(*s));
150 case Stmt::SwitchStmtClass:
152 case Stmt::ForStmtClass:
153 return emitForStmt(cast<ForStmt>(*s));
154 case Stmt::WhileStmtClass:
156 case Stmt::DoStmtClass:
157 return emitDoStmt(cast<DoStmt>(*s));
158 case Stmt::CXXTryStmtClass:
160 case Stmt::CXXForRangeStmtClass:
162 case Stmt::CoroutineBodyStmtClass:
164 case Stmt::IndirectGotoStmtClass:
166 case Stmt::OpenACCComputeConstructClass:
168 case Stmt::OpenACCLoopConstructClass:
170 case Stmt::OpenACCCombinedConstructClass:
172 case Stmt::OpenACCDataConstructClass:
174 case Stmt::OpenACCEnterDataConstructClass:
176 case Stmt::OpenACCExitDataConstructClass:
178 case Stmt::OpenACCHostDataConstructClass:
180 case Stmt::OpenACCWaitConstructClass:
182 case Stmt::OpenACCInitConstructClass:
184 case Stmt::OpenACCShutdownConstructClass:
186 case Stmt::OpenACCSetConstructClass:
188 case Stmt::OpenACCUpdateConstructClass:
190 case Stmt::OpenACCCacheConstructClass:
192 case Stmt::OpenACCAtomicConstructClass:
194 case Stmt::GCCAsmStmtClass:
195 case Stmt::MSAsmStmtClass:
196 return emitAsmStmt(cast<AsmStmt>(*s));
197 case Stmt::OMPScopeDirectiveClass:
198 case Stmt::OMPErrorDirectiveClass:
199 case Stmt::LabelStmtClass:
200 case Stmt::AttributedStmtClass:
201 case Stmt::GotoStmtClass:
202 case Stmt::DefaultStmtClass:
203 case Stmt::CaseStmtClass:
204 case Stmt::SEHLeaveStmtClass:
205 case Stmt::SYCLKernelCallStmtClass:
206 case Stmt::CoreturnStmtClass:
207 case Stmt::OMPParallelDirectiveClass:
208 case Stmt::OMPTaskwaitDirectiveClass:
209 case Stmt::OMPTaskyieldDirectiveClass:
210 case Stmt::OMPBarrierDirectiveClass:
211 case Stmt::CapturedStmtClass:
212 case Stmt::ObjCAtTryStmtClass:
213 case Stmt::ObjCAtThrowStmtClass:
214 case Stmt::ObjCAtSynchronizedStmtClass:
215 case Stmt::ObjCForCollectionStmtClass:
216 case Stmt::ObjCAutoreleasePoolStmtClass:
217 case Stmt::SEHTryStmtClass:
218 case Stmt::OMPMetaDirectiveClass:
219 case Stmt::OMPCanonicalLoopClass:
220 case Stmt::OMPSimdDirectiveClass:
221 case Stmt::OMPTileDirectiveClass:
222 case Stmt::OMPUnrollDirectiveClass:
223 case Stmt::OMPFuseDirectiveClass:
224 case Stmt::OMPForDirectiveClass:
225 case Stmt::OMPForSimdDirectiveClass:
226 case Stmt::OMPSectionsDirectiveClass:
227 case Stmt::OMPSectionDirectiveClass:
228 case Stmt::OMPSingleDirectiveClass:
229 case Stmt::OMPMasterDirectiveClass:
230 case Stmt::OMPCriticalDirectiveClass:
231 case Stmt::OMPParallelForDirectiveClass:
232 case Stmt::OMPParallelForSimdDirectiveClass:
233 case Stmt::OMPParallelMasterDirectiveClass:
234 case Stmt::OMPParallelSectionsDirectiveClass:
235 case Stmt::OMPTaskDirectiveClass:
236 case Stmt::OMPTaskgroupDirectiveClass:
237 case Stmt::OMPFlushDirectiveClass:
238 case Stmt::OMPDepobjDirectiveClass:
239 case Stmt::OMPScanDirectiveClass:
240 case Stmt::OMPOrderedDirectiveClass:
241 case Stmt::OMPAtomicDirectiveClass:
242 case Stmt::OMPTargetDirectiveClass:
243 case Stmt::OMPTeamsDirectiveClass:
244 case Stmt::OMPCancellationPointDirectiveClass:
245 case Stmt::OMPCancelDirectiveClass:
246 case Stmt::OMPTargetDataDirectiveClass:
247 case Stmt::OMPTargetEnterDataDirectiveClass:
248 case Stmt::OMPTargetExitDataDirectiveClass:
249 case Stmt::OMPTargetParallelDirectiveClass:
250 case Stmt::OMPTargetParallelForDirectiveClass:
251 case Stmt::OMPTaskLoopDirectiveClass:
252 case Stmt::OMPTaskLoopSimdDirectiveClass:
253 case Stmt::OMPMaskedTaskLoopDirectiveClass:
254 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
255 case Stmt::OMPMasterTaskLoopDirectiveClass:
256 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
257 case Stmt::OMPParallelGenericLoopDirectiveClass:
258 case Stmt::OMPParallelMaskedDirectiveClass:
259 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
260 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
261 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
262 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
263 case Stmt::OMPDistributeDirectiveClass:
264 case Stmt::OMPDistributeParallelForDirectiveClass:
265 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
266 case Stmt::OMPDistributeSimdDirectiveClass:
267 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
268 case Stmt::OMPTargetParallelForSimdDirectiveClass:
269 case Stmt::OMPTargetSimdDirectiveClass:
270 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
271 case Stmt::OMPTargetUpdateDirectiveClass:
272 case Stmt::OMPTeamsDistributeDirectiveClass:
273 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
274 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
275 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
276 case Stmt::OMPTeamsGenericLoopDirectiveClass:
277 case Stmt::OMPTargetTeamsDirectiveClass:
278 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
279 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
280 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
281 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
282 case Stmt::OMPInteropDirectiveClass:
283 case Stmt::OMPDispatchDirectiveClass:
284 case Stmt::OMPGenericLoopDirectiveClass:
285 case Stmt::OMPReverseDirectiveClass:
286 case Stmt::OMPInterchangeDirectiveClass:
287 case Stmt::OMPAssumeDirectiveClass:
288 case Stmt::OMPMaskedDirectiveClass:
289 case Stmt::OMPStripeDirectiveClass:
290 case Stmt::ObjCAtCatchStmtClass:
291 case Stmt::ObjCAtFinallyStmtClass:
292 case Stmt::DeferStmtClass:
293 cgm.errorNYI(s->getSourceRange(),
294 std::string("emitStmt: ") + s->getStmtClassName());
295 return mlir::failure();
296 }
297
298 llvm_unreachable("Unexpected statement class");
299}
300
301mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
302 bool useCurrentScope) {
303 switch (s->getStmtClass()) {
304 default:
305 return mlir::failure();
306 case Stmt::DeclStmtClass:
307 return emitDeclStmt(cast<DeclStmt>(*s));
308 case Stmt::CompoundStmtClass:
309 if (useCurrentScope)
312 case Stmt::GotoStmtClass:
313 return emitGotoStmt(cast<GotoStmt>(*s));
314 case Stmt::ContinueStmtClass:
316
317 // NullStmt doesn't need any handling, but we need to say we handled it.
318 case Stmt::NullStmtClass:
319 break;
320
321 case Stmt::LabelStmtClass:
323 case Stmt::CaseStmtClass:
324 case Stmt::DefaultStmtClass:
325 // If we reached here, we must not handling a switch case in the top level.
327 /*buildingTopLevelCase=*/false);
328 break;
329
330 case Stmt::BreakStmtClass:
332 case Stmt::ReturnStmtClass:
334 }
335
336 return mlir::success();
337}
338
340
341 if (emitLabel(*s.getDecl()).failed())
342 return mlir::failure();
343
344 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())
345 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");
346
347 return emitStmt(s.getSubStmt(), /*useCurrentScope*/ true);
348}
349
350// Add a terminating yield on a body region if no other terminators are used.
351static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r,
352 mlir::Location loc) {
353 if (r.empty())
354 return;
355
357 unsigned numBlocks = r.getBlocks().size();
358 for (auto &block : r.getBlocks()) {
359 // Already cleanup after return operations, which might create
360 // empty blocks if emitted as last stmt.
361 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
362 block.hasNoSuccessors())
363 eraseBlocks.push_back(&block);
364
365 if (block.empty() ||
366 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
367 mlir::OpBuilder::InsertionGuard guardCase(builder);
368 builder.setInsertionPointToEnd(&block);
369 builder.createYield(loc);
370 }
371 }
372
373 for (auto *b : eraseBlocks)
374 b->erase();
375}
376
377mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
378 mlir::LogicalResult res = mlir::success();
379 // The else branch of a consteval if statement is always the only branch
380 // that can be runtime evaluated.
381 const Stmt *constevalExecuted;
382 if (s.isConsteval()) {
383 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
384 if (!constevalExecuted) {
385 // No runtime code execution required
386 return res;
387 }
388 }
389
390 // C99 6.8.4.1: The first substatement is executed if the expression
391 // compares unequal to 0. The condition must be a scalar type.
392 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
393 if (s.isConsteval())
394 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
395
396 if (s.getInit())
397 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
398 return mlir::failure();
399
400 if (s.getConditionVariable())
401 emitDecl(*s.getConditionVariable());
402
403 // If the condition folds to a constant and this is an 'if constexpr',
404 // we simplify it early in CIRGen to avoid emitting the full 'if'.
405 bool condConstant;
406 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
407 if (s.isConstexpr()) {
408 // Handle "if constexpr" explicitly here to avoid generating some
409 // ill-formed code since in CIR the "if" is no longer simplified
410 // in this lambda like in Clang but postponed to other MLIR
411 // passes.
412 if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())
413 return emitStmt(executed, /*useCurrentScope=*/true);
414 // There is nothing to execute at runtime.
415 // TODO(cir): there is still an empty cir.scope generated by the caller.
416 return mlir::success();
417 }
418 }
419
422 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
423 };
424
425 // TODO: Add a new scoped symbol table.
426 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
427 // The if scope contains the full source range for IfStmt.
428 mlir::Location scopeLoc = getLoc(s.getSourceRange());
429 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
430 [&](mlir::OpBuilder &b, mlir::Location loc) {
431 LexicalScope lexScope{*this, scopeLoc,
432 builder.getInsertionBlock()};
433 res = ifStmtBuilder();
434 });
435
436 return res;
437}
438
439mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
440 assert(builder.getInsertionBlock() && "expected valid insertion point");
441
442 for (const Decl *i : s.decls())
443 emitDecl(*i, /*evaluateConditionDecl=*/true);
444
445 return mlir::success();
446}
447
448mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
449 mlir::Location loc = getLoc(s.getSourceRange());
450 const Expr *rv = s.getRetValue();
451
452 RunCleanupsScope cleanupScope(*this);
453 bool createNewScope = false;
454 if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) {
455 rv = ewc->getSubExpr();
456 createNewScope = true;
457 }
458
459 auto handleReturnVal = [&]() {
460 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
461 s.getNRVOCandidate()->isNRVOVariable()) {
463 // Apply the named return value optimization for this return statement,
464 // which means doing nothing: the appropriate result has already been
465 // constructed into the NRVO variable.
466
467 // If there is an NRVO flag for this variable, set it to 1 into indicate
468 // that the cleanup code should not destroy the variable.
469 if (auto nrvoFlag = nrvoFlags[s.getNRVOCandidate()])
470 builder.createFlagStore(loc, true, nrvoFlag);
471 } else if (!rv) {
472 // No return expression. Do nothing.
473 } else if (rv->getType()->isVoidType()) {
474 // Make sure not to return anything, but evaluate the expression
475 // for side effects.
476 if (rv) {
477 emitAnyExpr(rv);
478 }
479 } else if (cast<FunctionDecl>(curGD.getDecl())
480 ->getReturnType()
481 ->isReferenceType()) {
482 // If this function returns a reference, take the address of the
483 // expression rather than the value.
485 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(),
486 *fnRetAlloca);
487 } else {
488 mlir::Value value = nullptr;
490 case cir::TEK_Scalar:
491 value = emitScalarExpr(rv);
492 if (value) { // Change this to an assert once emitScalarExpr is complete
493 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
494 }
495 break;
496 case cir::TEK_Complex:
499 /*isInit=*/true);
500 break;
507 break;
508 }
509 }
510 };
511
512 if (!createNewScope) {
513 handleReturnVal();
514 } else {
515 mlir::Location scopeLoc =
516 getLoc(rv ? rv->getSourceRange() : s.getSourceRange());
517 // First create cir.scope and later emit it's body. Otherwise all CIRGen
518 // dispatched by `handleReturnVal()` might needs to manipulate blocks and
519 // look into parents, which are all unlinked.
520 mlir::OpBuilder::InsertPoint scopeBody;
521 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
522 [&](mlir::OpBuilder &b, mlir::Location loc) {
523 scopeBody = b.saveInsertionPoint();
524 });
525 {
526 mlir::OpBuilder::InsertionGuard guard(builder);
527 builder.restoreInsertionPoint(scopeBody);
528 CIRGenFunction::LexicalScope lexScope{*this, scopeLoc,
529 builder.getInsertionBlock()};
530 handleReturnVal();
531 }
532 }
533
534 cleanupScope.forceCleanup();
535
536 // In CIR we might have returns in different scopes.
537 // FIXME(cir): cleanup code is handling actual return emission, the logic
538 // should try to match traditional codegen more closely (to the extent which
539 // is possible).
540 auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
542
543 // Insert the new block to continue codegen after branch to ret block.
544 builder.createBlock(builder.getBlock()->getParent());
545
546 return mlir::success();
547}
548
549mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
550 // FIXME: LLVM codegen inserts emit a stop point here for debug info
551 // sake when the insertion point is available, but doesn't do
552 // anything special when there isn't. We haven't implemented debug
553 // info support just yet, look at this again once we have it.
555
556 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),
557 s.getLabel()->getName());
558
559 // A goto marks the end of a block, create a new one for codegen after
560 // emitGotoStmt can resume building in that block.
561 // Insert the new block to continue codegen after goto.
562 builder.createBlock(builder.getBlock()->getParent());
563
564 return mlir::success();
565}
566
567mlir::LogicalResult
569 mlir::Value val = emitScalarExpr(s.getTarget());
570 assert(indirectGotoBlock &&
571 "If you jumping to a indirect branch should be alareadye emitted");
572 cir::BrOp::create(builder, getLoc(s.getSourceRange()), indirectGotoBlock,
573 val);
574 builder.createBlock(builder.getBlock()->getParent());
575 return mlir::success();
576}
577
578mlir::LogicalResult
580 builder.createContinue(getLoc(s.getKwLoc()));
581
582 // Insert the new block to continue codegen after the continue statement.
583 builder.createBlock(builder.getBlock()->getParent());
584
585 return mlir::success();
586}
587
588mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
589 // Create a new block to tag with a label and add a branch from
590 // the current one to it. If the block is empty just call attach it
591 // to this label.
592 mlir::Block *currBlock = builder.getBlock();
593 mlir::Block *labelBlock = currBlock;
594
595 if (!currBlock->empty() || currBlock->isEntryBlock()) {
596 {
597 mlir::OpBuilder::InsertionGuard guard(builder);
598 labelBlock = builder.createBlock(builder.getBlock()->getParent());
599 }
600 cir::BrOp::create(builder, getLoc(d.getSourceRange()), labelBlock);
601 }
602
603 builder.setInsertionPointToEnd(labelBlock);
604 cir::LabelOp label =
605 cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
606 builder.setInsertionPointToEnd(labelBlock);
607 auto func = cast<cir::FuncOp>(curFn);
608 cgm.mapBlockAddress(cir::BlockAddrInfoAttr::get(builder.getContext(),
609 func.getSymNameAttr(),
610 label.getLabelAttr()),
611 label);
612 // FIXME: emit debug info for labels, incrementProfileCounter
616 return mlir::success();
617}
618
620 builder.createBreak(getLoc(s.getKwLoc()));
621
622 // Insert the new block to continue codegen after the break statement.
623 builder.createBlock(builder.getBlock()->getParent());
624
625 return mlir::success();
626}
627
628template <typename T>
629mlir::LogicalResult
631 mlir::ArrayAttr value, CaseOpKind kind,
632 bool buildingTopLevelCase) {
633
635 "only case or default stmt go here");
636
637 mlir::LogicalResult result = mlir::success();
638
639 mlir::Location loc = getLoc(stmt->getBeginLoc());
640
641 enum class SubStmtKind { Case, Default, Other };
642 SubStmtKind subStmtKind = SubStmtKind::Other;
643 const Stmt *sub = stmt->getSubStmt();
644
645 mlir::OpBuilder::InsertPoint insertPoint;
646 CaseOp::create(builder, loc, value, kind, insertPoint);
647
648 {
649 mlir::OpBuilder::InsertionGuard guardSwitch(builder);
650 builder.restoreInsertionPoint(insertPoint);
651
652 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
653 subStmtKind = SubStmtKind::Default;
654 builder.createYield(loc);
655 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
656 subStmtKind = SubStmtKind::Case;
657 builder.createYield(loc);
658 } else {
659 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
660 }
661
662 insertPoint = builder.saveInsertionPoint();
663 }
664
665 // If the substmt is default stmt or case stmt, try to handle the special case
666 // to make it into the simple form. e.g.
667 //
668 // swtich () {
669 // case 1:
670 // default:
671 // ...
672 // }
673 //
674 // we prefer generating
675 //
676 // cir.switch() {
677 // cir.case(equal, 1) {
678 // cir.yield
679 // }
680 // cir.case(default) {
681 // ...
682 // }
683 // }
684 //
685 // than
686 //
687 // cir.switch() {
688 // cir.case(equal, 1) {
689 // cir.case(default) {
690 // ...
691 // }
692 // }
693 // }
694 //
695 // We don't need to revert this if we find the current switch can't be in
696 // simple form later since the conversion itself should be harmless.
697 if (subStmtKind == SubStmtKind::Case) {
698 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
699 } else if (subStmtKind == SubStmtKind::Default) {
700 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
701 buildingTopLevelCase);
702 } else if (buildingTopLevelCase) {
703 // If we're building a top level case, try to restore the insert point to
704 // the case we're building, then we can attach more random stmts to the
705 // case to make generating `cir.switch` operation to be a simple form.
706 builder.restoreInsertionPoint(insertPoint);
707 }
708
709 return result;
710}
711
712mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
713 mlir::Type condType,
714 bool buildingTopLevelCase) {
715 cir::CaseOpKind kind;
716 mlir::ArrayAttr value;
717 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
718
719 // If the case statement has an RHS value, it is representing a GNU
720 // case range statement, where LHS is the beginning of the range
721 // and RHS is the end of the range.
722 if (const Expr *rhs = s.getRHS()) {
723 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
724 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
725 cir::IntAttr::get(condType, endVal)});
726 kind = cir::CaseOpKind::Range;
727 } else {
728 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
729 kind = cir::CaseOpKind::Equal;
730 }
731
732 return emitCaseDefaultCascade(&s, condType, value, kind,
733 buildingTopLevelCase);
734}
735
737 mlir::Type condType,
738 bool buildingTopLevelCase) {
739 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
740 cir::CaseOpKind::Default, buildingTopLevelCase);
741}
742
743mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
744 bool buildingTopLevelCase) {
745 assert(!condTypeStack.empty() &&
746 "build switch case without specifying the type of the condition");
747
748 if (s.getStmtClass() == Stmt::CaseStmtClass)
750 buildingTopLevelCase);
751
752 if (s.getStmtClass() == Stmt::DefaultStmtClass)
754 buildingTopLevelCase);
755
756 llvm_unreachable("expect case or default stmt");
757}
758
759mlir::LogicalResult
761 ArrayRef<const Attr *> forAttrs) {
762 cir::ForOp forOp;
763
764 // TODO(cir): pass in array of attributes.
765 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
766 mlir::LogicalResult loopRes = mlir::success();
767 // Evaluate the first pieces before the loop.
768 if (s.getInit())
769 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
770 return mlir::failure();
771 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
772 return mlir::failure();
773 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
774 return mlir::failure();
775 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
776 return mlir::failure();
777
779 // From LLVM: if there are any cleanups between here and the loop-exit
780 // scope, create a block to stage a loop exit along.
781 // We probably already do the right thing because of ScopeOp, but make
782 // sure we handle all cases.
784
785 forOp = builder.createFor(
786 getLoc(s.getSourceRange()),
787 /*condBuilder=*/
788 [&](mlir::OpBuilder &b, mlir::Location loc) {
789 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
790 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
791 mlir::Value condVal = evaluateExprAsBool(s.getCond());
792 builder.createCondition(condVal);
793 },
794 /*bodyBuilder=*/
795 [&](mlir::OpBuilder &b, mlir::Location loc) {
796 // https://en.cppreference.com/w/cpp/language/for
797 // In C++ the scope of the init-statement and the scope of
798 // statement are one and the same.
799 bool useCurrentScope = true;
800 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
801 loopRes = mlir::failure();
802 if (emitStmt(s.getBody(), useCurrentScope).failed())
803 loopRes = mlir::failure();
804 emitStopPoint(&s);
805 },
806 /*stepBuilder=*/
807 [&](mlir::OpBuilder &b, mlir::Location loc) {
808 if (s.getInc())
809 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
810 loopRes = mlir::failure();
811 builder.createYield(loc);
812 });
813 return loopRes;
814 };
815
816 mlir::LogicalResult res = mlir::success();
817 mlir::Location scopeLoc = getLoc(s.getSourceRange());
818 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
819 [&](mlir::OpBuilder &b, mlir::Location loc) {
820 // Create a cleanup scope for the condition
821 // variable cleanups. Logical equivalent from
822 // LLVM codegn for LexicalScope
823 // ConditionScope(*this, S.getSourceRange())...
824 LexicalScope lexScope{*this, loc,
825 builder.getInsertionBlock()};
826 res = forStmtBuilder();
827 });
828
829 if (res.failed())
830 return res;
831
832 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
833 return mlir::success();
834}
835
836mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
837 cir::ForOp forOp;
838
839 // TODO: pass in an array of attributes.
840 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
841 mlir::LogicalResult loopRes = mlir::success();
842 // Evaluate the first part before the loop.
843 if (s.getInit())
844 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
845 return mlir::failure();
847 // In the classic codegen, if there are any cleanups between here and the
848 // loop-exit scope, a block is created to stage the loop exit. We probably
849 // already do the right thing because of ScopeOp, but we need more testing
850 // to be sure we handle all cases.
852
853 forOp = builder.createFor(
854 getLoc(s.getSourceRange()),
855 /*condBuilder=*/
856 [&](mlir::OpBuilder &b, mlir::Location loc) {
857 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
858 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
859 mlir::Value condVal;
860 if (s.getCond()) {
861 // If the for statement has a condition scope,
862 // emit the local variable declaration.
863 if (s.getConditionVariable())
864 emitDecl(*s.getConditionVariable());
865 // C99 6.8.5p2/p4: The first substatement is executed if the
866 // expression compares unequal to 0. The condition must be a
867 // scalar type.
868 condVal = evaluateExprAsBool(s.getCond());
869 } else {
870 condVal = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
871 }
872 builder.createCondition(condVal);
873 },
874 /*bodyBuilder=*/
875 [&](mlir::OpBuilder &b, mlir::Location loc) {
876 // The scope of the for loop body is nested within the scope of the
877 // for loop's init-statement and condition.
878 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
879 loopRes = mlir::failure();
881 },
882 /*stepBuilder=*/
883 [&](mlir::OpBuilder &b, mlir::Location loc) {
884 if (s.getInc())
885 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
886 loopRes = mlir::failure();
887 builder.createYield(loc);
888 });
889 return loopRes;
890 };
891
892 auto res = mlir::success();
893 auto scopeLoc = getLoc(s.getSourceRange());
894 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
895 [&](mlir::OpBuilder &b, mlir::Location loc) {
896 LexicalScope lexScope{*this, loc,
897 builder.getInsertionBlock()};
898 res = forStmtBuilder();
899 });
900
901 if (res.failed())
902 return res;
903
904 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
905 return mlir::success();
906}
907
908mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
909 cir::DoWhileOp doWhileOp;
910
911 // TODO: pass in array of attributes.
912 auto doStmtBuilder = [&]() -> mlir::LogicalResult {
913 mlir::LogicalResult loopRes = mlir::success();
915 // From LLVM: if there are any cleanups between here and the loop-exit
916 // scope, create a block to stage a loop exit along.
917 // We probably already do the right thing because of ScopeOp, but make
918 // sure we handle all cases.
920
921 doWhileOp = builder.createDoWhile(
922 getLoc(s.getSourceRange()),
923 /*condBuilder=*/
924 [&](mlir::OpBuilder &b, mlir::Location loc) {
925 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
926 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
927 // C99 6.8.5p2/p4: The first substatement is executed if the
928 // expression compares unequal to 0. The condition must be a
929 // scalar type.
930 mlir::Value condVal = evaluateExprAsBool(s.getCond());
931 builder.createCondition(condVal);
932 },
933 /*bodyBuilder=*/
934 [&](mlir::OpBuilder &b, mlir::Location loc) {
935 // The scope of the do-while loop body is a nested scope.
936 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
937 loopRes = mlir::failure();
938 emitStopPoint(&s);
939 });
940 return loopRes;
941 };
942
943 mlir::LogicalResult res = mlir::success();
944 mlir::Location scopeLoc = getLoc(s.getSourceRange());
945 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
946 [&](mlir::OpBuilder &b, mlir::Location loc) {
947 LexicalScope lexScope{*this, loc,
948 builder.getInsertionBlock()};
949 res = doStmtBuilder();
950 });
951
952 if (res.failed())
953 return res;
954
955 terminateBody(builder, doWhileOp.getBody(), getLoc(s.getEndLoc()));
956 return mlir::success();
957}
958
959mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
960 cir::WhileOp whileOp;
961
962 // TODO: pass in array of attributes.
963 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
964 mlir::LogicalResult loopRes = mlir::success();
966 // From LLVM: if there are any cleanups between here and the loop-exit
967 // scope, create a block to stage a loop exit along.
968 // We probably already do the right thing because of ScopeOp, but make
969 // sure we handle all cases.
971
972 whileOp = builder.createWhile(
973 getLoc(s.getSourceRange()),
974 /*condBuilder=*/
975 [&](mlir::OpBuilder &b, mlir::Location loc) {
976 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
977 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
978 mlir::Value condVal;
979 // If the for statement has a condition scope,
980 // emit the local variable declaration.
981 if (s.getConditionVariable())
982 emitDecl(*s.getConditionVariable());
983 // C99 6.8.5p2/p4: The first substatement is executed if the
984 // expression compares unequal to 0. The condition must be a
985 // scalar type.
986 condVal = evaluateExprAsBool(s.getCond());
987 builder.createCondition(condVal);
988 },
989 /*bodyBuilder=*/
990 [&](mlir::OpBuilder &b, mlir::Location loc) {
991 // The scope of the while loop body is a nested scope.
992 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
993 loopRes = mlir::failure();
994 emitStopPoint(&s);
995 });
996 return loopRes;
997 };
998
999 mlir::LogicalResult res = mlir::success();
1000 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1001 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1002 [&](mlir::OpBuilder &b, mlir::Location loc) {
1003 LexicalScope lexScope{*this, loc,
1004 builder.getInsertionBlock()};
1005 res = whileStmtBuilder();
1006 });
1007
1008 if (res.failed())
1009 return res;
1010
1011 terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));
1012 return mlir::success();
1013}
1014
1015mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
1016 // It is rare but legal if the switch body is not a compound stmt. e.g.,
1017 //
1018 // switch(a)
1019 // while(...) {
1020 // case1
1021 // ...
1022 // case2
1023 // ...
1024 // }
1025 if (!isa<CompoundStmt>(s))
1026 return emitStmt(s, /*useCurrentScope=*/true);
1027
1029
1030 mlir::Block *swtichBlock = builder.getBlock();
1031 for (auto *c : compoundStmt->body()) {
1032 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
1033 builder.setInsertionPointToEnd(swtichBlock);
1034 // Reset insert point automatically, so that we can attach following
1035 // random stmt to the region of previous built case op to try to make
1036 // the being generated `cir.switch` to be in simple form.
1037 if (mlir::failed(
1038 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
1039 return mlir::failure();
1040
1041 continue;
1042 }
1043
1044 // Otherwise, just build the statements in the nearest case region.
1045 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
1046 return mlir::failure();
1047 }
1048
1049 return mlir::success();
1050}
1051
1053 // TODO: LLVM codegen does some early optimization to fold the condition and
1054 // only emit live cases. CIR should use MLIR to achieve similar things,
1055 // nothing to be done here.
1056 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
1058
1059 SwitchOp swop;
1060 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
1061 if (s.getInit())
1062 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
1063 return mlir::failure();
1064
1065 if (s.getConditionVariable())
1066 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
1067
1068 mlir::Value condV = emitScalarExpr(s.getCond());
1069
1070 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
1073 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
1075
1076 mlir::LogicalResult res = mlir::success();
1077 swop = SwitchOp::create(
1078 builder, getLoc(s.getBeginLoc()), condV,
1079 /*switchBuilder=*/
1080 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
1081 curLexScope->setAsSwitch();
1082
1083 condTypeStack.push_back(condV.getType());
1084
1085 res = emitSwitchBody(s.getBody());
1086
1087 condTypeStack.pop_back();
1088 });
1089
1090 return res;
1091 };
1092
1093 // The switch scope contains the full source range for SwitchStmt.
1094 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1095 mlir::LogicalResult res = mlir::success();
1096 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/
1097 [&](mlir::OpBuilder &b, mlir::Location loc) {
1098 LexicalScope lexScope{*this, loc,
1099 builder.getInsertionBlock()};
1100 res = switchStmtBuilder();
1101 });
1102
1104 swop.collectCases(cases);
1105 for (auto caseOp : cases)
1106 terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());
1107 terminateBody(builder, swop.getBody(), swop.getLoc());
1108
1109 swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered());
1110
1111 return res;
1112}
1113
1114void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv,
1115 QualType ty) {
1116 if (rv.isScalar()) {
1117 builder.createStore(loc, rv.getValue(), returnValue);
1118 } else if (rv.isAggregate()) {
1119 LValue dest = makeAddrLValue(returnValue, ty);
1122 } else {
1123 cgm.errorNYI(loc, "emitReturnOfRValue: complex return type");
1124 }
1125 mlir::Block *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
1127 cir::BrOp::create(builder, loc, retBlock);
1128 if (ehStack.stable_begin() != currentCleanupStackDepth)
1129 cgm.errorNYI(loc, "return of r-value with cleanup stack");
1130}
static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r, mlir::Location loc)
static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, const Stmt *exprResult, AggValueSlot slot, Address *lastValue)
Defines the clang::Expr interface and subclasses for C++ expressions.
This file defines OpenACC AST classes for statement-level contructs.
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
__device__ __2f16 float c
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
BreakStmt - This represents a break.
Definition Stmt.h:3125
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)
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
void forceCleanup()
Force the emission of cleanups now, instead of waiting until this object is destroyed.
mlir::LogicalResult emitDoStmt(const clang::DoStmt &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 emitOpenACCDataConstruct(const OpenACCDataConstruct &s)
mlir::LogicalResult emitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &s)
mlir::LogicalResult emitOpenACCWaitConstruct(const OpenACCWaitConstruct &s)
const clang::LangOptions & getLangOpts() const
mlir::LogicalResult emitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &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 emitOpenACCCacheConstruct(const OpenACCCacheConstruct &s)
mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s, llvm::ArrayRef< const Attr * > attrs)
void emitAggregateCopy(LValue dest, LValue src, QualType eltTy, AggValueSlot::Overlap_t mayOverlap, bool isVolatile=false)
Emit an aggregate copy.
JumpDest returnBlock(mlir::Block *retBlock)
Unified return block.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
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 emitOpenACCSetConstruct(const OpenACCSetConstruct &s)
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s)
mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s, mlir::Type condType, bool buildingTopLevelCase)
llvm::ScopedHashTableScope< const clang::Decl *, mlir::Value > SymTableScopeTy
mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s, bool useCurrentScope)
mlir::Block * indirectGotoBlock
IndirectBranch - The first time an indirect goto is seen we create a block reserved for the indirect ...
mlir::Operation * curFn
The current function or global initializer that is generated code for.
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s)
Definition CIRGenAsm.cpp:86
mlir::LogicalResult emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
mlir::LogicalResult emitSwitchBody(const clang::Stmt *s)
mlir::LogicalResult emitForStmt(const clang::ForStmt &s)
std::optional< mlir::Value > fnRetAlloca
The compiler-generated variable that holds the return value.
Address returnValue
The temporary alloca to hold the return value.
mlir::LogicalResult emitLabel(const clang::LabelDecl &d)
static bool hasAggregateEvaluationKind(clang::QualType type)
mlir::LogicalResult emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s)
mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s)
mlir::LogicalResult emitIndirectGotoStmt(const IndirectGotoStmt &s)
void emitReturnOfRValue(mlir::Location loc, RValue rv, QualType ty)
mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s)
llvm::SmallVector< mlir::Type, 2 > condTypeStack
The type of the condition for the emitting switch statement.
void emitStopPoint(const Stmt *s)
Build a debug stoppoint if we are emitting debug info.
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)
AggValueSlot::Overlap_t getOverlapForReturnValue()
Determine whether a return value slot may overlap some other object.
cir::BrOp emitBranchThroughCleanup(mlir::Location loc, JumpDest dest)
Build a unconditional branch to the lexical scope cleanup block or with the labeled blocked if alread...
mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s, bool buildingTopLevelCase)
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl=false)
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 emitCXXTryStmt(const clang::CXXTryStmt &s)
void emitComplexExprIntoLValue(const Expr *e, LValue dest, bool isInit)
mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType, mlir::ArrayAttr value, cir::CaseOpKind kind, bool buildingTopLevelCase)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
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 emitDeclStmt(const clang::DeclStmt &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)
EHScopeStack::stable_iterator currentCleanupStackDepth
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)
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
mlir::LogicalResult emitCompoundStmtWithoutScope(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
mlir::LogicalResult emitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &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 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
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
bool isScalar() const
Definition CIRGenValue.h:49
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Definition StmtCXX.h:135
CaseStmt - Represent a case statement.
Definition Stmt.h:1910
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1730
ContinueStmt - This represents a continue.
Definition Stmt.h:3109
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1621
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2822
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition Stmt.h:2878
GotoStmt - This represents a direct goto.
Definition Stmt.h:2959
IfStmt - This represents an if/then/else.
Definition Stmt.h:2249
IndirectGotoStmt - This represents an indirect goto.
Definition Stmt.h:2998
Represents the declaration of a label.
Definition Decl.h:524
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.h:554
LabelStmt - Represents a label, which has a substatement.
Definition Stmt.h:2136
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
A (possibly-)qualified type.
Definition TypeBase.h:937
The collection of all-type qualifiers we support.
Definition TypeBase.h:331
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3150
Stmt - This represents one statement.
Definition Stmt.h:85
@ NoStmtClass
Definition Stmt.h:88
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
SwitchStmt - This represents a 'switch' stmt.
Definition Stmt.h:2499
bool isVoidType() const
Definition TypeBase.h:8871
WhileStmt - This represents a 'while' stmt.
Definition Stmt.h:2687
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicDynCastAllOfMatcher< Stmt, CompoundStmt > compoundStmt
Matches compound statements.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, SwitchCase > switchCase
Matches case and default statements inside switch statements.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1746
static bool aggValueSlotGC()
static bool loopInfoStack()
static bool emitCondLikelihoodViaExpectIntrinsic()
static bool constantFoldSwitchStatement()
static bool insertBuiltinUnpredictable()
static bool ehstackBranches()
static bool emitBranchThroughCleanup()
static bool requiresCleanups()
static bool generateDebugInfo()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...