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.getStmtExprResult();
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 builder.create<cir::ScopeOp>(
95 scopeLoc, [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
96 scopeInsPt = b.saveInsertionPoint();
97 });
98 mlir::OpBuilder::InsertionGuard guard(builder);
99 builder.restoreInsertionPoint(scopeInsPt);
100 LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
101 return emitCompoundStmtWithoutScope(s, lastValue, slot);
102}
103
106}
107
108// Build CIR for a statement. useCurrentScope should be true if no new scopes
109// need to be created when finding a compound statement.
110mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
111 bool useCurrentScope,
113 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
114 return mlir::success();
115
116 switch (s->getStmtClass()) {
118 case Stmt::CXXCatchStmtClass:
119 case Stmt::SEHExceptStmtClass:
120 case Stmt::SEHFinallyStmtClass:
121 case Stmt::MSDependentExistsStmtClass:
122 llvm_unreachable("invalid statement class to emit generically");
123 case Stmt::BreakStmtClass:
124 case Stmt::NullStmtClass:
125 case Stmt::CompoundStmtClass:
126 case Stmt::ContinueStmtClass:
127 case Stmt::DeclStmtClass:
128 case Stmt::ReturnStmtClass:
129 llvm_unreachable("should have emitted these statements as simple");
130
131#define STMT(Type, Base)
132#define ABSTRACT_STMT(Op)
133#define EXPR(Type, Base) case Stmt::Type##Class:
134#include "clang/AST/StmtNodes.inc"
135 {
136 assert(builder.getInsertionBlock() &&
137 "expression emission must have an insertion point");
138
139 emitIgnoredExpr(cast<Expr>(s));
140
141 // Classic codegen has a check here to see if the emitter created a new
142 // block that isn't used (comparing the incoming and outgoing insertion
143 // points) and deletes the outgoing block if it's not used. In CIR, we
144 // will handle that during the cir.canonicalize pass.
145 return mlir::success();
146 }
147 case Stmt::IfStmtClass:
148 return emitIfStmt(cast<IfStmt>(*s));
149 case Stmt::SwitchStmtClass:
150 return emitSwitchStmt(cast<SwitchStmt>(*s));
151 case Stmt::ForStmtClass:
152 return emitForStmt(cast<ForStmt>(*s));
153 case Stmt::WhileStmtClass:
154 return emitWhileStmt(cast<WhileStmt>(*s));
155 case Stmt::DoStmtClass:
156 return emitDoStmt(cast<DoStmt>(*s));
157 case Stmt::CXXForRangeStmtClass:
158 return emitCXXForRangeStmt(cast<CXXForRangeStmt>(*s), attr);
159 case Stmt::OpenACCComputeConstructClass:
160 return emitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*s));
161 case Stmt::OpenACCLoopConstructClass:
162 return emitOpenACCLoopConstruct(cast<OpenACCLoopConstruct>(*s));
163 case Stmt::OpenACCCombinedConstructClass:
164 return emitOpenACCCombinedConstruct(cast<OpenACCCombinedConstruct>(*s));
165 case Stmt::OpenACCDataConstructClass:
166 return emitOpenACCDataConstruct(cast<OpenACCDataConstruct>(*s));
167 case Stmt::OpenACCEnterDataConstructClass:
168 return emitOpenACCEnterDataConstruct(cast<OpenACCEnterDataConstruct>(*s));
169 case Stmt::OpenACCExitDataConstructClass:
170 return emitOpenACCExitDataConstruct(cast<OpenACCExitDataConstruct>(*s));
171 case Stmt::OpenACCHostDataConstructClass:
172 return emitOpenACCHostDataConstruct(cast<OpenACCHostDataConstruct>(*s));
173 case Stmt::OpenACCWaitConstructClass:
174 return emitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*s));
175 case Stmt::OpenACCInitConstructClass:
176 return emitOpenACCInitConstruct(cast<OpenACCInitConstruct>(*s));
177 case Stmt::OpenACCShutdownConstructClass:
178 return emitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*s));
179 case Stmt::OpenACCSetConstructClass:
180 return emitOpenACCSetConstruct(cast<OpenACCSetConstruct>(*s));
181 case Stmt::OpenACCUpdateConstructClass:
182 return emitOpenACCUpdateConstruct(cast<OpenACCUpdateConstruct>(*s));
183 case Stmt::OpenACCCacheConstructClass:
184 return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));
185 case Stmt::OpenACCAtomicConstructClass:
186 return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));
187 case Stmt::GCCAsmStmtClass:
188 case Stmt::MSAsmStmtClass:
189 return emitAsmStmt(cast<AsmStmt>(*s));
190 case Stmt::OMPScopeDirectiveClass:
191 case Stmt::OMPErrorDirectiveClass:
192 case Stmt::LabelStmtClass:
193 case Stmt::AttributedStmtClass:
194 case Stmt::GotoStmtClass:
195 case Stmt::DefaultStmtClass:
196 case Stmt::CaseStmtClass:
197 case Stmt::SEHLeaveStmtClass:
198 case Stmt::SYCLKernelCallStmtClass:
199 case Stmt::CoroutineBodyStmtClass:
200 case Stmt::CoreturnStmtClass:
201 case Stmt::CXXTryStmtClass:
202 case Stmt::IndirectGotoStmtClass:
203 case Stmt::OMPParallelDirectiveClass:
204 case Stmt::OMPTaskwaitDirectiveClass:
205 case Stmt::OMPTaskyieldDirectiveClass:
206 case Stmt::OMPBarrierDirectiveClass:
207 case Stmt::CapturedStmtClass:
208 case Stmt::ObjCAtTryStmtClass:
209 case Stmt::ObjCAtThrowStmtClass:
210 case Stmt::ObjCAtSynchronizedStmtClass:
211 case Stmt::ObjCForCollectionStmtClass:
212 case Stmt::ObjCAutoreleasePoolStmtClass:
213 case Stmt::SEHTryStmtClass:
214 case Stmt::OMPMetaDirectiveClass:
215 case Stmt::OMPCanonicalLoopClass:
216 case Stmt::OMPSimdDirectiveClass:
217 case Stmt::OMPTileDirectiveClass:
218 case Stmt::OMPUnrollDirectiveClass:
219 case Stmt::OMPForDirectiveClass:
220 case Stmt::OMPForSimdDirectiveClass:
221 case Stmt::OMPSectionsDirectiveClass:
222 case Stmt::OMPSectionDirectiveClass:
223 case Stmt::OMPSingleDirectiveClass:
224 case Stmt::OMPMasterDirectiveClass:
225 case Stmt::OMPCriticalDirectiveClass:
226 case Stmt::OMPParallelForDirectiveClass:
227 case Stmt::OMPParallelForSimdDirectiveClass:
228 case Stmt::OMPParallelMasterDirectiveClass:
229 case Stmt::OMPParallelSectionsDirectiveClass:
230 case Stmt::OMPTaskDirectiveClass:
231 case Stmt::OMPTaskgroupDirectiveClass:
232 case Stmt::OMPFlushDirectiveClass:
233 case Stmt::OMPDepobjDirectiveClass:
234 case Stmt::OMPScanDirectiveClass:
235 case Stmt::OMPOrderedDirectiveClass:
236 case Stmt::OMPAtomicDirectiveClass:
237 case Stmt::OMPTargetDirectiveClass:
238 case Stmt::OMPTeamsDirectiveClass:
239 case Stmt::OMPCancellationPointDirectiveClass:
240 case Stmt::OMPCancelDirectiveClass:
241 case Stmt::OMPTargetDataDirectiveClass:
242 case Stmt::OMPTargetEnterDataDirectiveClass:
243 case Stmt::OMPTargetExitDataDirectiveClass:
244 case Stmt::OMPTargetParallelDirectiveClass:
245 case Stmt::OMPTargetParallelForDirectiveClass:
246 case Stmt::OMPTaskLoopDirectiveClass:
247 case Stmt::OMPTaskLoopSimdDirectiveClass:
248 case Stmt::OMPMaskedTaskLoopDirectiveClass:
249 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
250 case Stmt::OMPMasterTaskLoopDirectiveClass:
251 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
252 case Stmt::OMPParallelGenericLoopDirectiveClass:
253 case Stmt::OMPParallelMaskedDirectiveClass:
254 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
255 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
256 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
257 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
258 case Stmt::OMPDistributeDirectiveClass:
259 case Stmt::OMPDistributeParallelForDirectiveClass:
260 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
261 case Stmt::OMPDistributeSimdDirectiveClass:
262 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
263 case Stmt::OMPTargetParallelForSimdDirectiveClass:
264 case Stmt::OMPTargetSimdDirectiveClass:
265 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
266 case Stmt::OMPTargetUpdateDirectiveClass:
267 case Stmt::OMPTeamsDistributeDirectiveClass:
268 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
269 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
270 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
271 case Stmt::OMPTeamsGenericLoopDirectiveClass:
272 case Stmt::OMPTargetTeamsDirectiveClass:
273 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
274 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
275 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
276 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
277 case Stmt::OMPInteropDirectiveClass:
278 case Stmt::OMPDispatchDirectiveClass:
279 case Stmt::OMPGenericLoopDirectiveClass:
280 case Stmt::OMPReverseDirectiveClass:
281 case Stmt::OMPInterchangeDirectiveClass:
282 case Stmt::OMPAssumeDirectiveClass:
283 case Stmt::OMPMaskedDirectiveClass:
284 case Stmt::OMPStripeDirectiveClass:
285 case Stmt::ObjCAtCatchStmtClass:
286 case Stmt::ObjCAtFinallyStmtClass:
287 cgm.errorNYI(s->getSourceRange(),
288 std::string("emitStmt: ") + s->getStmtClassName());
289 return mlir::failure();
290 }
291
292 llvm_unreachable("Unexpected statement class");
293}
294
295mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
296 bool useCurrentScope) {
297 switch (s->getStmtClass()) {
298 default:
299 return mlir::failure();
300 case Stmt::DeclStmtClass:
301 return emitDeclStmt(cast<DeclStmt>(*s));
302 case Stmt::CompoundStmtClass:
303 if (useCurrentScope)
304 return emitCompoundStmtWithoutScope(cast<CompoundStmt>(*s));
305 return emitCompoundStmt(cast<CompoundStmt>(*s));
306 case Stmt::GotoStmtClass:
307 return emitGotoStmt(cast<GotoStmt>(*s));
308 case Stmt::ContinueStmtClass:
309 return emitContinueStmt(cast<ContinueStmt>(*s));
310
311 // NullStmt doesn't need any handling, but we need to say we handled it.
312 case Stmt::NullStmtClass:
313 break;
314
315 case Stmt::LabelStmtClass:
316 return emitLabelStmt(cast<LabelStmt>(*s));
317 case Stmt::CaseStmtClass:
318 case Stmt::DefaultStmtClass:
319 // If we reached here, we must not handling a switch case in the top level.
320 return emitSwitchCase(cast<SwitchCase>(*s),
321 /*buildingTopLevelCase=*/false);
322 break;
323
324 case Stmt::BreakStmtClass:
325 return emitBreakStmt(cast<BreakStmt>(*s));
326 case Stmt::ReturnStmtClass:
327 return emitReturnStmt(cast<ReturnStmt>(*s));
328 }
329
330 return mlir::success();
331}
332
334
335 if (emitLabel(*s.getDecl()).failed())
336 return mlir::failure();
337
338 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())
339 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");
340
341 return emitStmt(s.getSubStmt(), /*useCurrentScope*/ true);
342}
343
344// Add a terminating yield on a body region if no other terminators are used.
345static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r,
346 mlir::Location loc) {
347 if (r.empty())
348 return;
349
351 unsigned numBlocks = r.getBlocks().size();
352 for (auto &block : r.getBlocks()) {
353 // Already cleanup after return operations, which might create
354 // empty blocks if emitted as last stmt.
355 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
356 block.hasNoSuccessors())
357 eraseBlocks.push_back(&block);
358
359 if (block.empty() ||
360 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
361 mlir::OpBuilder::InsertionGuard guardCase(builder);
362 builder.setInsertionPointToEnd(&block);
363 builder.createYield(loc);
364 }
365 }
366
367 for (auto *b : eraseBlocks)
368 b->erase();
369}
370
371mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
372 mlir::LogicalResult res = mlir::success();
373 // The else branch of a consteval if statement is always the only branch
374 // that can be runtime evaluated.
375 const Stmt *constevalExecuted;
376 if (s.isConsteval()) {
377 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
378 if (!constevalExecuted) {
379 // No runtime code execution required
380 return res;
381 }
382 }
383
384 // C99 6.8.4.1: The first substatement is executed if the expression
385 // compares unequal to 0. The condition must be a scalar type.
386 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
387 if (s.isConsteval())
388 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
389
390 if (s.getInit())
391 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
392 return mlir::failure();
393
394 if (s.getConditionVariable())
395 emitDecl(*s.getConditionVariable());
396
397 // If the condition folds to a constant and this is an 'if constexpr',
398 // we simplify it early in CIRGen to avoid emitting the full 'if'.
399 bool condConstant;
400 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
401 if (s.isConstexpr()) {
402 // Handle "if constexpr" explicitly here to avoid generating some
403 // ill-formed code since in CIR the "if" is no longer simplified
404 // in this lambda like in Clang but postponed to other MLIR
405 // passes.
406 if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())
407 return emitStmt(executed, /*useCurrentScope=*/true);
408 // There is nothing to execute at runtime.
409 // TODO(cir): there is still an empty cir.scope generated by the caller.
410 return mlir::success();
411 }
412 }
413
416 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
417 };
418
419 // TODO: Add a new scoped symbol table.
420 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
421 // The if scope contains the full source range for IfStmt.
422 mlir::Location scopeLoc = getLoc(s.getSourceRange());
423 builder.create<cir::ScopeOp>(
424 scopeLoc, /*scopeBuilder=*/
425 [&](mlir::OpBuilder &b, mlir::Location loc) {
426 LexicalScope lexScope{*this, scopeLoc, builder.getInsertionBlock()};
427 res = ifStmtBuilder();
428 });
429
430 return res;
431}
432
433mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
434 assert(builder.getInsertionBlock() && "expected valid insertion point");
435
436 for (const Decl *i : s.decls())
437 emitDecl(*i, /*evaluateConditionDecl=*/true);
438
439 return mlir::success();
440}
441
442mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
443 mlir::Location loc = getLoc(s.getSourceRange());
444 const Expr *rv = s.getRetValue();
445
446 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
447 s.getNRVOCandidate()->isNRVOVariable()) {
448 getCIRGenModule().errorNYI(s.getSourceRange(),
449 "named return value optimization");
450 } else if (!rv) {
451 // No return expression. Do nothing.
452 } else if (rv->getType()->isVoidType()) {
453 // Make sure not to return anything, but evaluate the expression
454 // for side effects.
455 if (rv) {
456 emitAnyExpr(rv);
457 }
458 } else if (cast<FunctionDecl>(curGD.getDecl())
459 ->getReturnType()
460 ->isReferenceType()) {
461 // If this function returns a reference, take the address of the
462 // expression rather than the value.
464 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(), *fnRetAlloca);
465 } else {
466 mlir::Value value = nullptr;
468 case cir::TEK_Scalar:
469 value = emitScalarExpr(rv);
470 if (value) { // Change this to an assert once emitScalarExpr is complete
471 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
472 }
473 break;
474 default:
475 getCIRGenModule().errorNYI(s.getSourceRange(),
476 "non-scalar function return type");
477 break;
478 }
479 }
480
481 auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
482 // This should emit a branch through the cleanup block if one exists.
483 builder.create<cir::BrOp>(loc, retBlock);
485 cgm.errorNYI(s.getSourceRange(), "return with cleanup stack");
486 builder.createBlock(builder.getBlock()->getParent());
487
488 return mlir::success();
489}
490
491mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
492 // FIXME: LLVM codegen inserts emit a stop point here for debug info
493 // sake when the insertion point is available, but doesn't do
494 // anything special when there isn't. We haven't implemented debug
495 // info support just yet, look at this again once we have it.
497
498 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),
499 s.getLabel()->getName());
500
501 // A goto marks the end of a block, create a new one for codegen after
502 // emitGotoStmt can resume building in that block.
503 // Insert the new block to continue codegen after goto.
504 builder.createBlock(builder.getBlock()->getParent());
505
506 return mlir::success();
507}
508
509mlir::LogicalResult
511 builder.createContinue(getLoc(s.getContinueLoc()));
512
513 // Insert the new block to continue codegen after the continue statement.
514 builder.createBlock(builder.getBlock()->getParent());
515
516 return mlir::success();
517}
518
519mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
520 // Create a new block to tag with a label and add a branch from
521 // the current one to it. If the block is empty just call attach it
522 // to this label.
523 mlir::Block *currBlock = builder.getBlock();
524 mlir::Block *labelBlock = currBlock;
525
526 if (!currBlock->empty()) {
527 {
528 mlir::OpBuilder::InsertionGuard guard(builder);
529 labelBlock = builder.createBlock(builder.getBlock()->getParent());
530 }
531 builder.create<cir::BrOp>(getLoc(d.getSourceRange()), labelBlock);
532 }
533
534 builder.setInsertionPointToEnd(labelBlock);
535 builder.create<cir::LabelOp>(getLoc(d.getSourceRange()), d.getName());
536 builder.setInsertionPointToEnd(labelBlock);
537
538 // FIXME: emit debug info for labels, incrementProfileCounter
542 return mlir::success();
543}
544
546 builder.createBreak(getLoc(s.getBreakLoc()));
547
548 // Insert the new block to continue codegen after the break statement.
549 builder.createBlock(builder.getBlock()->getParent());
550
551 return mlir::success();
552}
553
554template <typename T>
555mlir::LogicalResult
557 mlir::ArrayAttr value, CaseOpKind kind,
558 bool buildingTopLevelCase) {
559
560 assert((isa<CaseStmt, DefaultStmt>(stmt)) &&
561 "only case or default stmt go here");
562
563 mlir::LogicalResult result = mlir::success();
564
565 mlir::Location loc = getLoc(stmt->getBeginLoc());
566
567 enum class SubStmtKind { Case, Default, Other };
568 SubStmtKind subStmtKind = SubStmtKind::Other;
569 const Stmt *sub = stmt->getSubStmt();
570
571 mlir::OpBuilder::InsertPoint insertPoint;
572 builder.create<CaseOp>(loc, value, kind, insertPoint);
573
574 {
575 mlir::OpBuilder::InsertionGuard guardSwitch(builder);
576 builder.restoreInsertionPoint(insertPoint);
577
578 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
579 subStmtKind = SubStmtKind::Default;
580 builder.createYield(loc);
581 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
582 subStmtKind = SubStmtKind::Case;
583 builder.createYield(loc);
584 } else {
585 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
586 }
587
588 insertPoint = builder.saveInsertionPoint();
589 }
590
591 // If the substmt is default stmt or case stmt, try to handle the special case
592 // to make it into the simple form. e.g.
593 //
594 // swtich () {
595 // case 1:
596 // default:
597 // ...
598 // }
599 //
600 // we prefer generating
601 //
602 // cir.switch() {
603 // cir.case(equal, 1) {
604 // cir.yield
605 // }
606 // cir.case(default) {
607 // ...
608 // }
609 // }
610 //
611 // than
612 //
613 // cir.switch() {
614 // cir.case(equal, 1) {
615 // cir.case(default) {
616 // ...
617 // }
618 // }
619 // }
620 //
621 // We don't need to revert this if we find the current switch can't be in
622 // simple form later since the conversion itself should be harmless.
623 if (subStmtKind == SubStmtKind::Case) {
624 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
625 } else if (subStmtKind == SubStmtKind::Default) {
626 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
627 buildingTopLevelCase);
628 } else if (buildingTopLevelCase) {
629 // If we're building a top level case, try to restore the insert point to
630 // the case we're building, then we can attach more random stmts to the
631 // case to make generating `cir.switch` operation to be a simple form.
632 builder.restoreInsertionPoint(insertPoint);
633 }
634
635 return result;
636}
637
638mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
639 mlir::Type condType,
640 bool buildingTopLevelCase) {
641 cir::CaseOpKind kind;
642 mlir::ArrayAttr value;
643 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
644
645 // If the case statement has an RHS value, it is representing a GNU
646 // case range statement, where LHS is the beginning of the range
647 // and RHS is the end of the range.
648 if (const Expr *rhs = s.getRHS()) {
649 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
650 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
651 cir::IntAttr::get(condType, endVal)});
652 kind = cir::CaseOpKind::Range;
653 } else {
654 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
655 kind = cir::CaseOpKind::Equal;
656 }
657
658 return emitCaseDefaultCascade(&s, condType, value, kind,
659 buildingTopLevelCase);
660}
661
663 mlir::Type condType,
664 bool buildingTopLevelCase) {
665 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
666 cir::CaseOpKind::Default, buildingTopLevelCase);
667}
668
669mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
670 bool buildingTopLevelCase) {
671 assert(!condTypeStack.empty() &&
672 "build switch case without specifying the type of the condition");
673
674 if (s.getStmtClass() == Stmt::CaseStmtClass)
675 return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
676 buildingTopLevelCase);
677
678 if (s.getStmtClass() == Stmt::DefaultStmtClass)
679 return emitDefaultStmt(cast<DefaultStmt>(s), condTypeStack.back(),
680 buildingTopLevelCase);
681
682 llvm_unreachable("expect case or default stmt");
683}
684
685mlir::LogicalResult
687 ArrayRef<const Attr *> forAttrs) {
688 cir::ForOp forOp;
689
690 // TODO(cir): pass in array of attributes.
691 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
692 mlir::LogicalResult loopRes = mlir::success();
693 // Evaluate the first pieces before the loop.
694 if (s.getInit())
695 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
696 return mlir::failure();
697 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
698 return mlir::failure();
699 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
700 return mlir::failure();
701 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
702 return mlir::failure();
703
705 // From LLVM: if there are any cleanups between here and the loop-exit
706 // scope, create a block to stage a loop exit along.
707 // We probably already do the right thing because of ScopeOp, but make
708 // sure we handle all cases.
710
711 forOp = builder.createFor(
712 getLoc(s.getSourceRange()),
713 /*condBuilder=*/
714 [&](mlir::OpBuilder &b, mlir::Location loc) {
715 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
716 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
717 mlir::Value condVal = evaluateExprAsBool(s.getCond());
718 builder.createCondition(condVal);
719 },
720 /*bodyBuilder=*/
721 [&](mlir::OpBuilder &b, mlir::Location loc) {
722 // https://en.cppreference.com/w/cpp/language/for
723 // In C++ the scope of the init-statement and the scope of
724 // statement are one and the same.
725 bool useCurrentScope = true;
726 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
727 loopRes = mlir::failure();
728 if (emitStmt(s.getBody(), useCurrentScope).failed())
729 loopRes = mlir::failure();
730 emitStopPoint(&s);
731 },
732 /*stepBuilder=*/
733 [&](mlir::OpBuilder &b, mlir::Location loc) {
734 if (s.getInc())
735 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
736 loopRes = mlir::failure();
737 builder.createYield(loc);
738 });
739 return loopRes;
740 };
741
742 mlir::LogicalResult res = mlir::success();
743 mlir::Location scopeLoc = getLoc(s.getSourceRange());
744 builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
745 [&](mlir::OpBuilder &b, mlir::Location loc) {
746 // Create a cleanup scope for the condition
747 // variable cleanups. Logical equivalent from
748 // LLVM codegn for LexicalScope
749 // ConditionScope(*this, S.getSourceRange())...
750 LexicalScope lexScope{
751 *this, loc, builder.getInsertionBlock()};
752 res = forStmtBuilder();
753 });
754
755 if (res.failed())
756 return res;
757
758 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
759 return mlir::success();
760}
761
762mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
763 cir::ForOp forOp;
764
765 // TODO: pass in an array of attributes.
766 auto forStmtBuilder = [&]() -> mlir::LogicalResult {
767 mlir::LogicalResult loopRes = mlir::success();
768 // Evaluate the first part before the loop.
769 if (s.getInit())
770 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
771 return mlir::failure();
773 // In the classic codegen, if there are any cleanups between here and the
774 // loop-exit scope, a block is created to stage the loop exit. We probably
775 // already do the right thing because of ScopeOp, but we need more testing
776 // to be sure we handle all cases.
778
779 forOp = builder.createFor(
780 getLoc(s.getSourceRange()),
781 /*condBuilder=*/
782 [&](mlir::OpBuilder &b, mlir::Location loc) {
783 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
784 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
785 mlir::Value condVal;
786 if (s.getCond()) {
787 // If the for statement has a condition scope,
788 // emit the local variable declaration.
789 if (s.getConditionVariable())
790 emitDecl(*s.getConditionVariable());
791 // C99 6.8.5p2/p4: The first substatement is executed if the
792 // expression compares unequal to 0. The condition must be a
793 // scalar type.
794 condVal = evaluateExprAsBool(s.getCond());
795 } else {
796 condVal = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
797 }
798 builder.createCondition(condVal);
799 },
800 /*bodyBuilder=*/
801 [&](mlir::OpBuilder &b, mlir::Location loc) {
802 // The scope of the for loop body is nested within the scope of the
803 // for loop's init-statement and condition.
804 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
805 loopRes = mlir::failure();
807 },
808 /*stepBuilder=*/
809 [&](mlir::OpBuilder &b, mlir::Location loc) {
810 if (s.getInc())
811 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
812 loopRes = mlir::failure();
813 builder.createYield(loc);
814 });
815 return loopRes;
816 };
817
818 auto res = mlir::success();
819 auto scopeLoc = getLoc(s.getSourceRange());
820 builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
821 [&](mlir::OpBuilder &b, mlir::Location loc) {
822 LexicalScope lexScope{
823 *this, loc, builder.getInsertionBlock()};
824 res = forStmtBuilder();
825 });
826
827 if (res.failed())
828 return res;
829
830 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
831 return mlir::success();
832}
833
834mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
835 cir::DoWhileOp doWhileOp;
836
837 // TODO: pass in array of attributes.
838 auto doStmtBuilder = [&]() -> mlir::LogicalResult {
839 mlir::LogicalResult loopRes = mlir::success();
841 // From LLVM: if there are any cleanups between here and the loop-exit
842 // scope, create a block to stage a loop exit along.
843 // We probably already do the right thing because of ScopeOp, but make
844 // sure we handle all cases.
846
847 doWhileOp = builder.createDoWhile(
848 getLoc(s.getSourceRange()),
849 /*condBuilder=*/
850 [&](mlir::OpBuilder &b, mlir::Location loc) {
851 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
852 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
853 // C99 6.8.5p2/p4: The first substatement is executed if the
854 // expression compares unequal to 0. The condition must be a
855 // scalar type.
856 mlir::Value condVal = evaluateExprAsBool(s.getCond());
857 builder.createCondition(condVal);
858 },
859 /*bodyBuilder=*/
860 [&](mlir::OpBuilder &b, mlir::Location loc) {
861 // The scope of the do-while loop body is a nested scope.
862 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
863 loopRes = mlir::failure();
864 emitStopPoint(&s);
865 });
866 return loopRes;
867 };
868
869 mlir::LogicalResult res = mlir::success();
870 mlir::Location scopeLoc = getLoc(s.getSourceRange());
871 builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
872 [&](mlir::OpBuilder &b, mlir::Location loc) {
873 LexicalScope lexScope{
874 *this, loc, builder.getInsertionBlock()};
875 res = doStmtBuilder();
876 });
877
878 if (res.failed())
879 return res;
880
881 terminateBody(builder, doWhileOp.getBody(), getLoc(s.getEndLoc()));
882 return mlir::success();
883}
884
885mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
886 cir::WhileOp whileOp;
887
888 // TODO: pass in array of attributes.
889 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
890 mlir::LogicalResult loopRes = mlir::success();
892 // From LLVM: if there are any cleanups between here and the loop-exit
893 // scope, create a block to stage a loop exit along.
894 // We probably already do the right thing because of ScopeOp, but make
895 // sure we handle all cases.
897
898 whileOp = builder.createWhile(
899 getLoc(s.getSourceRange()),
900 /*condBuilder=*/
901 [&](mlir::OpBuilder &b, mlir::Location loc) {
902 assert(!cir::MissingFeatures::createProfileWeightsForLoop());
903 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
904 mlir::Value condVal;
905 // If the for statement has a condition scope,
906 // emit the local variable declaration.
907 if (s.getConditionVariable())
908 emitDecl(*s.getConditionVariable());
909 // C99 6.8.5p2/p4: The first substatement is executed if the
910 // expression compares unequal to 0. The condition must be a
911 // scalar type.
912 condVal = evaluateExprAsBool(s.getCond());
913 builder.createCondition(condVal);
914 },
915 /*bodyBuilder=*/
916 [&](mlir::OpBuilder &b, mlir::Location loc) {
917 // The scope of the while loop body is a nested scope.
918 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
919 loopRes = mlir::failure();
920 emitStopPoint(&s);
921 });
922 return loopRes;
923 };
924
925 mlir::LogicalResult res = mlir::success();
926 mlir::Location scopeLoc = getLoc(s.getSourceRange());
927 builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
928 [&](mlir::OpBuilder &b, mlir::Location loc) {
929 LexicalScope lexScope{
930 *this, loc, builder.getInsertionBlock()};
931 res = whileStmtBuilder();
932 });
933
934 if (res.failed())
935 return res;
936
937 terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));
938 return mlir::success();
939}
940
941mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
942 // It is rare but legal if the switch body is not a compound stmt. e.g.,
943 //
944 // switch(a)
945 // while(...) {
946 // case1
947 // ...
948 // case2
949 // ...
950 // }
951 if (!isa<CompoundStmt>(s))
952 return emitStmt(s, /*useCurrentScope=*/true);
953
954 auto *compoundStmt = cast<CompoundStmt>(s);
955
956 mlir::Block *swtichBlock = builder.getBlock();
957 for (auto *c : compoundStmt->body()) {
958 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
959 builder.setInsertionPointToEnd(swtichBlock);
960 // Reset insert point automatically, so that we can attach following
961 // random stmt to the region of previous built case op to try to make
962 // the being generated `cir.switch` to be in simple form.
963 if (mlir::failed(
964 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
965 return mlir::failure();
966
967 continue;
968 }
969
970 // Otherwise, just build the statements in the nearest case region.
971 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
972 return mlir::failure();
973 }
974
975 return mlir::success();
976}
977
979 // TODO: LLVM codegen does some early optimization to fold the condition and
980 // only emit live cases. CIR should use MLIR to achieve similar things,
981 // nothing to be done here.
982 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
984
985 SwitchOp swop;
986 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
987 if (s.getInit())
988 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
989 return mlir::failure();
990
991 if (s.getConditionVariable())
992 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
993
994 mlir::Value condV = emitScalarExpr(s.getCond());
995
996 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
999 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
1001
1002 mlir::LogicalResult res = mlir::success();
1003 swop = builder.create<SwitchOp>(
1004 getLoc(s.getBeginLoc()), condV,
1005 /*switchBuilder=*/
1006 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
1008
1009 condTypeStack.push_back(condV.getType());
1010
1011 res = emitSwitchBody(s.getBody());
1012
1013 condTypeStack.pop_back();
1014 });
1015
1016 return res;
1017 };
1018
1019 // The switch scope contains the full source range for SwitchStmt.
1020 mlir::Location scopeLoc = getLoc(s.getSourceRange());
1021 mlir::LogicalResult res = mlir::success();
1022 builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
1023 [&](mlir::OpBuilder &b, mlir::Location loc) {
1024 LexicalScope lexScope{
1025 *this, loc, builder.getInsertionBlock()};
1026 res = switchStmtBuilder();
1027 });
1028
1030 swop.collectCases(cases);
1031 for (auto caseOp : cases)
1032 terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());
1033 terminateBody(builder, swop.getBody(), swop.getLoc());
1034
1035 return res;
1036}
static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r, mlir::Location loc)
Definition: CIRGenStmt.cpp:345
static mlir::LogicalResult emitStmtWithResult(CIRGenFunction &cgf, const Stmt *exprResult, AggValueSlot slot, Address *lastValue)
Definition: CIRGenStmt.cpp:28
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::WhileOp createWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a while operation.
cir::BreakOp createBreak(mlir::Location loc)
Create a break operation.
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::ForOp createFor(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> stepBuilder)
Create a for operation.
cir::DoWhileOp createDoWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a do-while operation.
cir::ContinueOp createContinue(mlir::Location loc)
Create a continue operation.
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
BreakStmt - This represents a break.
Definition: Stmt.h:3090
An aggregate value slot.
Definition: CIRGenValue.h:302
mlir::LogicalResult emitDoStmt(const clang::DoStmt &s)
Definition: CIRGenStmt.cpp:834
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)
Definition: CIRGenStmt.cpp:686
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)
Definition: CIRGenStmt.cpp:442
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.
llvm::ScopedHashTableScope< const clang::Decl *, mlir::Value > SymTableScopeTy
mlir::LogicalResult emitOpenACCSetConstruct(const OpenACCSetConstruct &s)
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
RValue emitAnyExpr(const clang::Expr *e, AggValueSlot aggSlot=AggValueSlot::ignored())
Emit code to compute the specified expression which can have any type.
mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s)
Definition: CIRGenStmt.cpp:978
mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s, mlir::Type condType, bool buildingTopLevelCase)
Definition: CIRGenStmt.cpp:638
mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s, bool useCurrentScope)
Definition: CIRGenStmt.cpp:295
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)
Definition: CIRGenStmt.cpp:941
mlir::LogicalResult emitForStmt(const clang::ForStmt &s)
Definition: CIRGenStmt.cpp:762
std::optional< mlir::Value > fnRetAlloca
The compiler-generated variable that holds the return value.
mlir::LogicalResult emitLabel(const clang::LabelDecl &d)
Definition: CIRGenStmt.cpp:519
static bool hasAggregateEvaluationKind(clang::QualType type)
mlir::LogicalResult emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s)
mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s)
Definition: CIRGenStmt.cpp:545
mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s)
Definition: CIRGenStmt.cpp:510
llvm::SmallVector< mlir::Type, 2 > condTypeStack
The type of the condition for the emitting switch statement.
mlir::Value emitScalarExpr(const clang::Expr *e)
Emit the computation of the specified expression of scalar type.
void emitStopPoint(const Stmt *s)
Build a debug stoppoint if we are emitting debug info.
Definition: CIRGenStmt.cpp:104
mlir::LogicalResult emitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &s)
mlir::LogicalResult emitIfStmt(const clang::IfStmt &s)
Definition: CIRGenStmt.cpp:371
mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s, bool buildingTopLevelCase)
Definition: CIRGenStmt.cpp:669
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl=false)
Definition: CIRGenDecl.cpp:530
CIRGenModule & getCIRGenModule()
mlir::LogicalResult emitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &s)
mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType, mlir::ArrayAttr value, cir::CaseOpKind kind, bool buildingTopLevelCase)
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s)
Definition: CIRGenStmt.cpp:433
mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s, mlir::Type condType, bool buildingTopLevelCase)
Definition: CIRGenStmt.cpp:662
mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s)
Definition: CIRGenStmt.cpp:885
mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s)
Definition: CIRGenStmt.cpp:333
EHScopeStack::stable_iterator currentCleanupStackDepth
clang::ASTContext & getContext() const
mlir::LogicalResult emitCompoundStmt(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
Definition: CIRGenStmt.cpp:87
mlir::LogicalResult emitGotoStmt(const clang::GotoStmt &s)
Definition: CIRGenStmt.cpp:491
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
Definition: CIRGenStmt.cpp:110
mlir::LogicalResult emitCompoundStmtWithoutScope(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
Definition: CIRGenStmt.cpp:66
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.
stable_iterator stable_begin() const
Create a stable reference to the top of the EH stack.
Definition: EHScopeStack.h:174
This trivial value class is used to represent the result of an expression that is evaluated.
Definition: CIRGenValue.h:33
mlir::Value getValue() const
Return the value of this scalar value.
Definition: CIRGenValue.h:56
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:1931
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1731
ContinueStmt - This represents a continue.
Definition: Stmt.h:3060
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1622
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
DoStmt - This represents a 'do/while' stmt.
Definition: Stmt.h:2835
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:2891
const Decl * getDecl() const
Definition: GlobalDecl.h:106
GotoStmt - This represents a direct goto.
Definition: Stmt.h:2972
IfStmt - This represents an if/then/else.
Definition: Stmt.h:2262
Represents the declaration of a label.
Definition: Decl.h:523
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition: Decl.h:553
LabelStmt - Represents a label, which has a substatement.
Definition: Stmt.h:2157
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:300
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:3129
Stmt - This represents one statement.
Definition: Stmt.h:85
@ NoStmtClass
Definition: Stmt.h:88
SwitchStmt - This represents a 'switch' stmt.
Definition: Stmt.h:2512
bool isVoidType() const
Definition: TypeBase.h:8936
WhileStmt - This represents a 'while' stmt.
Definition: Stmt.h:2700
Definition: ABIArgInfo.h:22
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
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.
const FunctionProtoType * T
@ Other
Other implicit parameter.
static bool loopInfoStack()
static bool emitCondLikelihoodViaExpectIntrinsic()
static bool constantFoldSwitchStatement()
static bool insertBuiltinUnpredictable()
static bool ehstackBranches()
static bool requiresCleanups()
static bool generateDebugInfo()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
mlir::Block * getOrCreateRetBlock(CIRGenFunction &cgf, mlir::Location loc)