1104 lines · cpp
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-exception6//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"21#include "clang/AST/StmtOpenACC.h"22#include "clang/CIR/MissingFeatures.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 put33 // at the end of a statement expression, they yield the value of their34 // 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 the44 // 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 at57 // the end of the StmtExpr. Because of that, we have to emit the result58 // here into a temporary alloca.59 cgf.emitAnyExprToMem(e, *lastValue, Qualifiers(),60 /*IsInit*/ false);61 }62 63 return mlir::success();64}65 66mlir::LogicalResult CIRGenFunction::emitCompoundStmtWithoutScope(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 87mlir::LogicalResult CIRGenFunction::emitCompoundStmt(const CompoundStmt &s,88 Address *lastValue,89 AggValueSlot slot) {90 // Add local scope to track new declared variables.91 SymTableScopeTy varScope(symbolTable);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 105void CIRGenFunction::emitStopPoint(const Stmt *s) {106 assert(!cir::MissingFeatures::generateDebugInfo());107}108 109// Build CIR for a statement. useCurrentScope should be true if no new scopes110// need to be created when finding a compound statement.111mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,112 bool useCurrentScope,113 ArrayRef<const Attr *> attr) {114 if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))115 return mlir::success();116 117 switch (s->getStmtClass()) {118 case Stmt::NoStmtClass: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 140 emitIgnoredExpr(cast<Expr>(s));141 142 // Classic codegen has a check here to see if the emitter created a new143 // block that isn't used (comparing the incoming and outgoing insertion144 // points) and deletes the outgoing block if it's not used. In CIR, we145 // 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:151 return emitSwitchStmt(cast<SwitchStmt>(*s));152 case Stmt::ForStmtClass:153 return emitForStmt(cast<ForStmt>(*s));154 case Stmt::WhileStmtClass:155 return emitWhileStmt(cast<WhileStmt>(*s));156 case Stmt::DoStmtClass:157 return emitDoStmt(cast<DoStmt>(*s));158 case Stmt::CXXTryStmtClass:159 return emitCXXTryStmt(cast<CXXTryStmt>(*s));160 case Stmt::CXXForRangeStmtClass:161 return emitCXXForRangeStmt(cast<CXXForRangeStmt>(*s), attr);162 case Stmt::OpenACCComputeConstructClass:163 return emitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*s));164 case Stmt::OpenACCLoopConstructClass:165 return emitOpenACCLoopConstruct(cast<OpenACCLoopConstruct>(*s));166 case Stmt::OpenACCCombinedConstructClass:167 return emitOpenACCCombinedConstruct(cast<OpenACCCombinedConstruct>(*s));168 case Stmt::OpenACCDataConstructClass:169 return emitOpenACCDataConstruct(cast<OpenACCDataConstruct>(*s));170 case Stmt::OpenACCEnterDataConstructClass:171 return emitOpenACCEnterDataConstruct(cast<OpenACCEnterDataConstruct>(*s));172 case Stmt::OpenACCExitDataConstructClass:173 return emitOpenACCExitDataConstruct(cast<OpenACCExitDataConstruct>(*s));174 case Stmt::OpenACCHostDataConstructClass:175 return emitOpenACCHostDataConstruct(cast<OpenACCHostDataConstruct>(*s));176 case Stmt::OpenACCWaitConstructClass:177 return emitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*s));178 case Stmt::OpenACCInitConstructClass:179 return emitOpenACCInitConstruct(cast<OpenACCInitConstruct>(*s));180 case Stmt::OpenACCShutdownConstructClass:181 return emitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*s));182 case Stmt::OpenACCSetConstructClass:183 return emitOpenACCSetConstruct(cast<OpenACCSetConstruct>(*s));184 case Stmt::OpenACCUpdateConstructClass:185 return emitOpenACCUpdateConstruct(cast<OpenACCUpdateConstruct>(*s));186 case Stmt::OpenACCCacheConstructClass:187 return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));188 case Stmt::OpenACCAtomicConstructClass:189 return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));190 case Stmt::GCCAsmStmtClass:191 case Stmt::MSAsmStmtClass:192 return emitAsmStmt(cast<AsmStmt>(*s));193 case Stmt::OMPScopeDirectiveClass:194 case Stmt::OMPErrorDirectiveClass:195 case Stmt::LabelStmtClass:196 case Stmt::AttributedStmtClass:197 case Stmt::GotoStmtClass:198 case Stmt::DefaultStmtClass:199 case Stmt::CaseStmtClass:200 case Stmt::SEHLeaveStmtClass:201 case Stmt::SYCLKernelCallStmtClass:202 case Stmt::CoroutineBodyStmtClass:203 return emitCoroutineBody(cast<CoroutineBodyStmt>(*s));204 case Stmt::CoreturnStmtClass:205 case Stmt::IndirectGotoStmtClass:206 case Stmt::OMPParallelDirectiveClass:207 case Stmt::OMPTaskwaitDirectiveClass:208 case Stmt::OMPTaskyieldDirectiveClass:209 case Stmt::OMPBarrierDirectiveClass:210 case Stmt::CapturedStmtClass:211 case Stmt::ObjCAtTryStmtClass:212 case Stmt::ObjCAtThrowStmtClass:213 case Stmt::ObjCAtSynchronizedStmtClass:214 case Stmt::ObjCForCollectionStmtClass:215 case Stmt::ObjCAutoreleasePoolStmtClass:216 case Stmt::SEHTryStmtClass:217 case Stmt::OMPMetaDirectiveClass:218 case Stmt::OMPCanonicalLoopClass:219 case Stmt::OMPSimdDirectiveClass:220 case Stmt::OMPTileDirectiveClass:221 case Stmt::OMPUnrollDirectiveClass:222 case Stmt::OMPFuseDirectiveClass:223 case Stmt::OMPForDirectiveClass:224 case Stmt::OMPForSimdDirectiveClass:225 case Stmt::OMPSectionsDirectiveClass:226 case Stmt::OMPSectionDirectiveClass:227 case Stmt::OMPSingleDirectiveClass:228 case Stmt::OMPMasterDirectiveClass:229 case Stmt::OMPCriticalDirectiveClass:230 case Stmt::OMPParallelForDirectiveClass:231 case Stmt::OMPParallelForSimdDirectiveClass:232 case Stmt::OMPParallelMasterDirectiveClass:233 case Stmt::OMPParallelSectionsDirectiveClass:234 case Stmt::OMPTaskDirectiveClass:235 case Stmt::OMPTaskgroupDirectiveClass:236 case Stmt::OMPFlushDirectiveClass:237 case Stmt::OMPDepobjDirectiveClass:238 case Stmt::OMPScanDirectiveClass:239 case Stmt::OMPOrderedDirectiveClass:240 case Stmt::OMPAtomicDirectiveClass:241 case Stmt::OMPTargetDirectiveClass:242 case Stmt::OMPTeamsDirectiveClass:243 case Stmt::OMPCancellationPointDirectiveClass:244 case Stmt::OMPCancelDirectiveClass:245 case Stmt::OMPTargetDataDirectiveClass:246 case Stmt::OMPTargetEnterDataDirectiveClass:247 case Stmt::OMPTargetExitDataDirectiveClass:248 case Stmt::OMPTargetParallelDirectiveClass:249 case Stmt::OMPTargetParallelForDirectiveClass:250 case Stmt::OMPTaskLoopDirectiveClass:251 case Stmt::OMPTaskLoopSimdDirectiveClass:252 case Stmt::OMPMaskedTaskLoopDirectiveClass:253 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:254 case Stmt::OMPMasterTaskLoopDirectiveClass:255 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:256 case Stmt::OMPParallelGenericLoopDirectiveClass:257 case Stmt::OMPParallelMaskedDirectiveClass:258 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:259 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:260 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:261 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:262 case Stmt::OMPDistributeDirectiveClass:263 case Stmt::OMPDistributeParallelForDirectiveClass:264 case Stmt::OMPDistributeParallelForSimdDirectiveClass:265 case Stmt::OMPDistributeSimdDirectiveClass:266 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:267 case Stmt::OMPTargetParallelForSimdDirectiveClass:268 case Stmt::OMPTargetSimdDirectiveClass:269 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:270 case Stmt::OMPTargetUpdateDirectiveClass:271 case Stmt::OMPTeamsDistributeDirectiveClass:272 case Stmt::OMPTeamsDistributeSimdDirectiveClass:273 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:274 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:275 case Stmt::OMPTeamsGenericLoopDirectiveClass:276 case Stmt::OMPTargetTeamsDirectiveClass:277 case Stmt::OMPTargetTeamsDistributeDirectiveClass:278 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:279 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:280 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:281 case Stmt::OMPInteropDirectiveClass:282 case Stmt::OMPDispatchDirectiveClass:283 case Stmt::OMPGenericLoopDirectiveClass:284 case Stmt::OMPReverseDirectiveClass:285 case Stmt::OMPInterchangeDirectiveClass:286 case Stmt::OMPAssumeDirectiveClass:287 case Stmt::OMPMaskedDirectiveClass:288 case Stmt::OMPStripeDirectiveClass:289 case Stmt::ObjCAtCatchStmtClass:290 case Stmt::ObjCAtFinallyStmtClass:291 cgm.errorNYI(s->getSourceRange(),292 std::string("emitStmt: ") + s->getStmtClassName());293 return mlir::failure();294 }295 296 llvm_unreachable("Unexpected statement class");297}298 299mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,300 bool useCurrentScope) {301 switch (s->getStmtClass()) {302 default:303 return mlir::failure();304 case Stmt::DeclStmtClass:305 return emitDeclStmt(cast<DeclStmt>(*s));306 case Stmt::CompoundStmtClass:307 if (useCurrentScope)308 return emitCompoundStmtWithoutScope(cast<CompoundStmt>(*s));309 return emitCompoundStmt(cast<CompoundStmt>(*s));310 case Stmt::GotoStmtClass:311 return emitGotoStmt(cast<GotoStmt>(*s));312 case Stmt::ContinueStmtClass:313 return emitContinueStmt(cast<ContinueStmt>(*s));314 315 // NullStmt doesn't need any handling, but we need to say we handled it.316 case Stmt::NullStmtClass:317 break;318 319 case Stmt::LabelStmtClass:320 return emitLabelStmt(cast<LabelStmt>(*s));321 case Stmt::CaseStmtClass:322 case Stmt::DefaultStmtClass:323 // If we reached here, we must not handling a switch case in the top level.324 return emitSwitchCase(cast<SwitchCase>(*s),325 /*buildingTopLevelCase=*/false);326 break;327 328 case Stmt::BreakStmtClass:329 return emitBreakStmt(cast<BreakStmt>(*s));330 case Stmt::ReturnStmtClass:331 return emitReturnStmt(cast<ReturnStmt>(*s));332 }333 334 return mlir::success();335}336 337mlir::LogicalResult CIRGenFunction::emitLabelStmt(const clang::LabelStmt &s) {338 339 if (emitLabel(*s.getDecl()).failed())340 return mlir::failure();341 342 if (getContext().getLangOpts().EHAsynch && s.isSideEntry())343 getCIRGenModule().errorNYI(s.getSourceRange(), "IsEHa: not implemented.");344 345 return emitStmt(s.getSubStmt(), /*useCurrentScope*/ true);346}347 348// Add a terminating yield on a body region if no other terminators are used.349static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r,350 mlir::Location loc) {351 if (r.empty())352 return;353 354 SmallVector<mlir::Block *, 4> eraseBlocks;355 unsigned numBlocks = r.getBlocks().size();356 for (auto &block : r.getBlocks()) {357 // Already cleanup after return operations, which might create358 // empty blocks if emitted as last stmt.359 if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&360 block.hasNoSuccessors())361 eraseBlocks.push_back(&block);362 363 if (block.empty() ||364 !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {365 mlir::OpBuilder::InsertionGuard guardCase(builder);366 builder.setInsertionPointToEnd(&block);367 builder.createYield(loc);368 }369 }370 371 for (auto *b : eraseBlocks)372 b->erase();373}374 375mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {376 mlir::LogicalResult res = mlir::success();377 // The else branch of a consteval if statement is always the only branch378 // that can be runtime evaluated.379 const Stmt *constevalExecuted;380 if (s.isConsteval()) {381 constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();382 if (!constevalExecuted) {383 // No runtime code execution required384 return res;385 }386 }387 388 // C99 6.8.4.1: The first substatement is executed if the expression389 // compares unequal to 0. The condition must be a scalar type.390 auto ifStmtBuilder = [&]() -> mlir::LogicalResult {391 if (s.isConsteval())392 return emitStmt(constevalExecuted, /*useCurrentScope=*/true);393 394 if (s.getInit())395 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())396 return mlir::failure();397 398 if (s.getConditionVariable())399 emitDecl(*s.getConditionVariable());400 401 // If the condition folds to a constant and this is an 'if constexpr',402 // we simplify it early in CIRGen to avoid emitting the full 'if'.403 bool condConstant;404 if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {405 if (s.isConstexpr()) {406 // Handle "if constexpr" explicitly here to avoid generating some407 // ill-formed code since in CIR the "if" is no longer simplified408 // in this lambda like in Clang but postponed to other MLIR409 // passes.410 if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())411 return emitStmt(executed, /*useCurrentScope=*/true);412 // There is nothing to execute at runtime.413 // TODO(cir): there is still an empty cir.scope generated by the caller.414 return mlir::success();415 }416 }417 418 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());419 assert(!cir::MissingFeatures::incrementProfileCounter());420 return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());421 };422 423 // TODO: Add a new scoped symbol table.424 // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());425 // The if scope contains the full source range for IfStmt.426 mlir::Location scopeLoc = getLoc(s.getSourceRange());427 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/428 [&](mlir::OpBuilder &b, mlir::Location loc) {429 LexicalScope lexScope{*this, scopeLoc,430 builder.getInsertionBlock()};431 res = ifStmtBuilder();432 });433 434 return res;435}436 437mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {438 assert(builder.getInsertionBlock() && "expected valid insertion point");439 440 for (const Decl *i : s.decls())441 emitDecl(*i, /*evaluateConditionDecl=*/true);442 443 return mlir::success();444}445 446mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {447 mlir::Location loc = getLoc(s.getSourceRange());448 const Expr *rv = s.getRetValue();449 450 RunCleanupsScope cleanupScope(*this);451 bool createNewScope = false;452 if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) {453 rv = ewc->getSubExpr();454 createNewScope = true;455 }456 457 auto handleReturnVal = [&]() {458 if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&459 s.getNRVOCandidate()->isNRVOVariable()) {460 assert(!cir::MissingFeatures::openMP());461 assert(!cir::MissingFeatures::nrvo());462 } else if (!rv) {463 // No return expression. Do nothing.464 } else if (rv->getType()->isVoidType()) {465 // Make sure not to return anything, but evaluate the expression466 // for side effects.467 if (rv) {468 emitAnyExpr(rv);469 }470 } else if (cast<FunctionDecl>(curGD.getDecl())471 ->getReturnType()472 ->isReferenceType()) {473 // If this function returns a reference, take the address of the474 // expression rather than the value.475 RValue result = emitReferenceBindingToExpr(rv);476 builder.CIRBaseBuilderTy::createStore(loc, result.getValue(),477 *fnRetAlloca);478 } else {479 mlir::Value value = nullptr;480 switch (CIRGenFunction::getEvaluationKind(rv->getType())) {481 case cir::TEK_Scalar:482 value = emitScalarExpr(rv);483 if (value) { // Change this to an assert once emitScalarExpr is complete484 builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);485 }486 break;487 case cir::TEK_Complex:488 emitComplexExprIntoLValue(rv,489 makeAddrLValue(returnValue, rv->getType()),490 /*isInit=*/true);491 break;492 case cir::TEK_Aggregate:493 assert(!cir::MissingFeatures::aggValueSlotGC());494 emitAggExpr(rv, AggValueSlot::forAddr(returnValue, Qualifiers(),495 AggValueSlot::IsDestructed,496 AggValueSlot::IsNotAliased,497 getOverlapForReturnValue()));498 break;499 }500 }501 };502 503 if (!createNewScope) {504 handleReturnVal();505 } else {506 mlir::Location scopeLoc =507 getLoc(rv ? rv->getSourceRange() : s.getSourceRange());508 // First create cir.scope and later emit it's body. Otherwise all CIRGen509 // dispatched by `handleReturnVal()` might needs to manipulate blocks and510 // look into parents, which are all unlinked.511 mlir::OpBuilder::InsertPoint scopeBody;512 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/513 [&](mlir::OpBuilder &b, mlir::Location loc) {514 scopeBody = b.saveInsertionPoint();515 });516 {517 mlir::OpBuilder::InsertionGuard guard(builder);518 builder.restoreInsertionPoint(scopeBody);519 CIRGenFunction::LexicalScope lexScope{*this, scopeLoc,520 builder.getInsertionBlock()};521 handleReturnVal();522 }523 }524 525 cleanupScope.forceCleanup();526 527 // In CIR we might have returns in different scopes.528 // FIXME(cir): cleanup code is handling actual return emission, the logic529 // should try to match traditional codegen more closely (to the extent which530 // is possible).531 auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);532 emitBranchThroughCleanup(loc, returnBlock(retBlock));533 534 // Insert the new block to continue codegen after branch to ret block.535 builder.createBlock(builder.getBlock()->getParent());536 537 return mlir::success();538}539 540mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {541 // FIXME: LLVM codegen inserts emit a stop point here for debug info542 // sake when the insertion point is available, but doesn't do543 // anything special when there isn't. We haven't implemented debug544 // info support just yet, look at this again once we have it.545 assert(!cir::MissingFeatures::generateDebugInfo());546 547 cir::GotoOp::create(builder, getLoc(s.getSourceRange()),548 s.getLabel()->getName());549 550 // A goto marks the end of a block, create a new one for codegen after551 // emitGotoStmt can resume building in that block.552 // Insert the new block to continue codegen after goto.553 builder.createBlock(builder.getBlock()->getParent());554 555 return mlir::success();556}557 558mlir::LogicalResult559CIRGenFunction::emitContinueStmt(const clang::ContinueStmt &s) {560 builder.createContinue(getLoc(s.getKwLoc()));561 562 // Insert the new block to continue codegen after the continue statement.563 builder.createBlock(builder.getBlock()->getParent());564 565 return mlir::success();566}567 568mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {569 // Create a new block to tag with a label and add a branch from570 // the current one to it. If the block is empty just call attach it571 // to this label.572 mlir::Block *currBlock = builder.getBlock();573 mlir::Block *labelBlock = currBlock;574 575 if (!currBlock->empty() || currBlock->isEntryBlock()) {576 {577 mlir::OpBuilder::InsertionGuard guard(builder);578 labelBlock = builder.createBlock(builder.getBlock()->getParent());579 }580 cir::BrOp::create(builder, getLoc(d.getSourceRange()), labelBlock);581 }582 583 builder.setInsertionPointToEnd(labelBlock);584 cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());585 builder.setInsertionPointToEnd(labelBlock);586 587 // FIXME: emit debug info for labels, incrementProfileCounter588 assert(!cir::MissingFeatures::ehstackBranches());589 assert(!cir::MissingFeatures::incrementProfileCounter());590 assert(!cir::MissingFeatures::generateDebugInfo());591 return mlir::success();592}593 594mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {595 builder.createBreak(getLoc(s.getKwLoc()));596 597 // Insert the new block to continue codegen after the break statement.598 builder.createBlock(builder.getBlock()->getParent());599 600 return mlir::success();601}602 603template <typename T>604mlir::LogicalResult605CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,606 mlir::ArrayAttr value, CaseOpKind kind,607 bool buildingTopLevelCase) {608 609 assert((isa<CaseStmt, DefaultStmt>(stmt)) &&610 "only case or default stmt go here");611 612 mlir::LogicalResult result = mlir::success();613 614 mlir::Location loc = getLoc(stmt->getBeginLoc());615 616 enum class SubStmtKind { Case, Default, Other };617 SubStmtKind subStmtKind = SubStmtKind::Other;618 const Stmt *sub = stmt->getSubStmt();619 620 mlir::OpBuilder::InsertPoint insertPoint;621 CaseOp::create(builder, loc, value, kind, insertPoint);622 623 {624 mlir::OpBuilder::InsertionGuard guardSwitch(builder);625 builder.restoreInsertionPoint(insertPoint);626 627 if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {628 subStmtKind = SubStmtKind::Default;629 builder.createYield(loc);630 } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {631 subStmtKind = SubStmtKind::Case;632 builder.createYield(loc);633 } else {634 result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));635 }636 637 insertPoint = builder.saveInsertionPoint();638 }639 640 // If the substmt is default stmt or case stmt, try to handle the special case641 // to make it into the simple form. e.g.642 //643 // swtich () {644 // case 1:645 // default:646 // ...647 // }648 //649 // we prefer generating650 //651 // cir.switch() {652 // cir.case(equal, 1) {653 // cir.yield654 // }655 // cir.case(default) {656 // ...657 // }658 // }659 //660 // than661 //662 // cir.switch() {663 // cir.case(equal, 1) {664 // cir.case(default) {665 // ...666 // }667 // }668 // }669 //670 // We don't need to revert this if we find the current switch can't be in671 // simple form later since the conversion itself should be harmless.672 if (subStmtKind == SubStmtKind::Case) {673 result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);674 } else if (subStmtKind == SubStmtKind::Default) {675 result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,676 buildingTopLevelCase);677 } else if (buildingTopLevelCase) {678 // If we're building a top level case, try to restore the insert point to679 // the case we're building, then we can attach more random stmts to the680 // case to make generating `cir.switch` operation to be a simple form.681 builder.restoreInsertionPoint(insertPoint);682 }683 684 return result;685}686 687mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,688 mlir::Type condType,689 bool buildingTopLevelCase) {690 cir::CaseOpKind kind;691 mlir::ArrayAttr value;692 llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());693 694 // If the case statement has an RHS value, it is representing a GNU695 // case range statement, where LHS is the beginning of the range696 // and RHS is the end of the range.697 if (const Expr *rhs = s.getRHS()) {698 llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());699 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),700 cir::IntAttr::get(condType, endVal)});701 kind = cir::CaseOpKind::Range;702 } else {703 value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});704 kind = cir::CaseOpKind::Equal;705 }706 707 return emitCaseDefaultCascade(&s, condType, value, kind,708 buildingTopLevelCase);709}710 711mlir::LogicalResult CIRGenFunction::emitDefaultStmt(const clang::DefaultStmt &s,712 mlir::Type condType,713 bool buildingTopLevelCase) {714 return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),715 cir::CaseOpKind::Default, buildingTopLevelCase);716}717 718mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,719 bool buildingTopLevelCase) {720 assert(!condTypeStack.empty() &&721 "build switch case without specifying the type of the condition");722 723 if (s.getStmtClass() == Stmt::CaseStmtClass)724 return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),725 buildingTopLevelCase);726 727 if (s.getStmtClass() == Stmt::DefaultStmtClass)728 return emitDefaultStmt(cast<DefaultStmt>(s), condTypeStack.back(),729 buildingTopLevelCase);730 731 llvm_unreachable("expect case or default stmt");732}733 734mlir::LogicalResult735CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt &s,736 ArrayRef<const Attr *> forAttrs) {737 cir::ForOp forOp;738 739 // TODO(cir): pass in array of attributes.740 auto forStmtBuilder = [&]() -> mlir::LogicalResult {741 mlir::LogicalResult loopRes = mlir::success();742 // Evaluate the first pieces before the loop.743 if (s.getInit())744 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())745 return mlir::failure();746 if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())747 return mlir::failure();748 if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())749 return mlir::failure();750 if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())751 return mlir::failure();752 753 assert(!cir::MissingFeatures::loopInfoStack());754 // From LLVM: if there are any cleanups between here and the loop-exit755 // scope, create a block to stage a loop exit along.756 // We probably already do the right thing because of ScopeOp, but make757 // sure we handle all cases.758 assert(!cir::MissingFeatures::requiresCleanups());759 760 forOp = builder.createFor(761 getLoc(s.getSourceRange()),762 /*condBuilder=*/763 [&](mlir::OpBuilder &b, mlir::Location loc) {764 assert(!cir::MissingFeatures::createProfileWeightsForLoop());765 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());766 mlir::Value condVal = evaluateExprAsBool(s.getCond());767 builder.createCondition(condVal);768 },769 /*bodyBuilder=*/770 [&](mlir::OpBuilder &b, mlir::Location loc) {771 // https://en.cppreference.com/w/cpp/language/for772 // In C++ the scope of the init-statement and the scope of773 // statement are one and the same.774 bool useCurrentScope = true;775 if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())776 loopRes = mlir::failure();777 if (emitStmt(s.getBody(), useCurrentScope).failed())778 loopRes = mlir::failure();779 emitStopPoint(&s);780 },781 /*stepBuilder=*/782 [&](mlir::OpBuilder &b, mlir::Location loc) {783 if (s.getInc())784 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())785 loopRes = mlir::failure();786 builder.createYield(loc);787 });788 return loopRes;789 };790 791 mlir::LogicalResult res = mlir::success();792 mlir::Location scopeLoc = getLoc(s.getSourceRange());793 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/794 [&](mlir::OpBuilder &b, mlir::Location loc) {795 // Create a cleanup scope for the condition796 // variable cleanups. Logical equivalent from797 // LLVM codegn for LexicalScope798 // ConditionScope(*this, S.getSourceRange())...799 LexicalScope lexScope{*this, loc,800 builder.getInsertionBlock()};801 res = forStmtBuilder();802 });803 804 if (res.failed())805 return res;806 807 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));808 return mlir::success();809}810 811mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {812 cir::ForOp forOp;813 814 // TODO: pass in an array of attributes.815 auto forStmtBuilder = [&]() -> mlir::LogicalResult {816 mlir::LogicalResult loopRes = mlir::success();817 // Evaluate the first part before the loop.818 if (s.getInit())819 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())820 return mlir::failure();821 assert(!cir::MissingFeatures::loopInfoStack());822 // In the classic codegen, if there are any cleanups between here and the823 // loop-exit scope, a block is created to stage the loop exit. We probably824 // already do the right thing because of ScopeOp, but we need more testing825 // to be sure we handle all cases.826 assert(!cir::MissingFeatures::requiresCleanups());827 828 forOp = builder.createFor(829 getLoc(s.getSourceRange()),830 /*condBuilder=*/831 [&](mlir::OpBuilder &b, mlir::Location loc) {832 assert(!cir::MissingFeatures::createProfileWeightsForLoop());833 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());834 mlir::Value condVal;835 if (s.getCond()) {836 // If the for statement has a condition scope,837 // emit the local variable declaration.838 if (s.getConditionVariable())839 emitDecl(*s.getConditionVariable());840 // C99 6.8.5p2/p4: The first substatement is executed if the841 // expression compares unequal to 0. The condition must be a842 // scalar type.843 condVal = evaluateExprAsBool(s.getCond());844 } else {845 condVal = cir::ConstantOp::create(b, loc, builder.getTrueAttr());846 }847 builder.createCondition(condVal);848 },849 /*bodyBuilder=*/850 [&](mlir::OpBuilder &b, mlir::Location loc) {851 // The scope of the for loop body is nested within the scope of the852 // for loop's init-statement and condition.853 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())854 loopRes = mlir::failure();855 emitStopPoint(&s);856 },857 /*stepBuilder=*/858 [&](mlir::OpBuilder &b, mlir::Location loc) {859 if (s.getInc())860 if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())861 loopRes = mlir::failure();862 builder.createYield(loc);863 });864 return loopRes;865 };866 867 auto res = mlir::success();868 auto scopeLoc = getLoc(s.getSourceRange());869 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/870 [&](mlir::OpBuilder &b, mlir::Location loc) {871 LexicalScope lexScope{*this, loc,872 builder.getInsertionBlock()};873 res = forStmtBuilder();874 });875 876 if (res.failed())877 return res;878 879 terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));880 return mlir::success();881}882 883mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {884 cir::DoWhileOp doWhileOp;885 886 // TODO: pass in array of attributes.887 auto doStmtBuilder = [&]() -> mlir::LogicalResult {888 mlir::LogicalResult loopRes = mlir::success();889 assert(!cir::MissingFeatures::loopInfoStack());890 // From LLVM: if there are any cleanups between here and the loop-exit891 // scope, create a block to stage a loop exit along.892 // We probably already do the right thing because of ScopeOp, but make893 // sure we handle all cases.894 assert(!cir::MissingFeatures::requiresCleanups());895 896 doWhileOp = builder.createDoWhile(897 getLoc(s.getSourceRange()),898 /*condBuilder=*/899 [&](mlir::OpBuilder &b, mlir::Location loc) {900 assert(!cir::MissingFeatures::createProfileWeightsForLoop());901 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());902 // C99 6.8.5p2/p4: The first substatement is executed if the903 // expression compares unequal to 0. The condition must be a904 // scalar type.905 mlir::Value condVal = evaluateExprAsBool(s.getCond());906 builder.createCondition(condVal);907 },908 /*bodyBuilder=*/909 [&](mlir::OpBuilder &b, mlir::Location loc) {910 // The scope of the do-while loop body is a nested scope.911 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())912 loopRes = mlir::failure();913 emitStopPoint(&s);914 });915 return loopRes;916 };917 918 mlir::LogicalResult res = mlir::success();919 mlir::Location scopeLoc = getLoc(s.getSourceRange());920 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/921 [&](mlir::OpBuilder &b, mlir::Location loc) {922 LexicalScope lexScope{*this, loc,923 builder.getInsertionBlock()};924 res = doStmtBuilder();925 });926 927 if (res.failed())928 return res;929 930 terminateBody(builder, doWhileOp.getBody(), getLoc(s.getEndLoc()));931 return mlir::success();932}933 934mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {935 cir::WhileOp whileOp;936 937 // TODO: pass in array of attributes.938 auto whileStmtBuilder = [&]() -> mlir::LogicalResult {939 mlir::LogicalResult loopRes = mlir::success();940 assert(!cir::MissingFeatures::loopInfoStack());941 // From LLVM: if there are any cleanups between here and the loop-exit942 // scope, create a block to stage a loop exit along.943 // We probably already do the right thing because of ScopeOp, but make944 // sure we handle all cases.945 assert(!cir::MissingFeatures::requiresCleanups());946 947 whileOp = builder.createWhile(948 getLoc(s.getSourceRange()),949 /*condBuilder=*/950 [&](mlir::OpBuilder &b, mlir::Location loc) {951 assert(!cir::MissingFeatures::createProfileWeightsForLoop());952 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());953 mlir::Value condVal;954 // If the for statement has a condition scope,955 // emit the local variable declaration.956 if (s.getConditionVariable())957 emitDecl(*s.getConditionVariable());958 // C99 6.8.5p2/p4: The first substatement is executed if the959 // expression compares unequal to 0. The condition must be a960 // scalar type.961 condVal = evaluateExprAsBool(s.getCond());962 builder.createCondition(condVal);963 },964 /*bodyBuilder=*/965 [&](mlir::OpBuilder &b, mlir::Location loc) {966 // The scope of the while loop body is a nested scope.967 if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())968 loopRes = mlir::failure();969 emitStopPoint(&s);970 });971 return loopRes;972 };973 974 mlir::LogicalResult res = mlir::success();975 mlir::Location scopeLoc = getLoc(s.getSourceRange());976 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/977 [&](mlir::OpBuilder &b, mlir::Location loc) {978 LexicalScope lexScope{*this, loc,979 builder.getInsertionBlock()};980 res = whileStmtBuilder();981 });982 983 if (res.failed())984 return res;985 986 terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));987 return mlir::success();988}989 990mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {991 // It is rare but legal if the switch body is not a compound stmt. e.g.,992 //993 // switch(a)994 // while(...) {995 // case1996 // ...997 // case2998 // ...999 // }1000 if (!isa<CompoundStmt>(s))1001 return emitStmt(s, /*useCurrentScope=*/true);1002 1003 auto *compoundStmt = cast<CompoundStmt>(s);1004 1005 mlir::Block *swtichBlock = builder.getBlock();1006 for (auto *c : compoundStmt->body()) {1007 if (auto *switchCase = dyn_cast<SwitchCase>(c)) {1008 builder.setInsertionPointToEnd(swtichBlock);1009 // Reset insert point automatically, so that we can attach following1010 // random stmt to the region of previous built case op to try to make1011 // the being generated `cir.switch` to be in simple form.1012 if (mlir::failed(1013 emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))1014 return mlir::failure();1015 1016 continue;1017 }1018 1019 // Otherwise, just build the statements in the nearest case region.1020 if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))1021 return mlir::failure();1022 }1023 1024 return mlir::success();1025}1026 1027mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) {1028 // TODO: LLVM codegen does some early optimization to fold the condition and1029 // only emit live cases. CIR should use MLIR to achieve similar things,1030 // nothing to be done here.1031 // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...1032 assert(!cir::MissingFeatures::constantFoldSwitchStatement());1033 1034 SwitchOp swop;1035 auto switchStmtBuilder = [&]() -> mlir::LogicalResult {1036 if (s.getInit())1037 if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())1038 return mlir::failure();1039 1040 if (s.getConditionVariable())1041 emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);1042 1043 mlir::Value condV = emitScalarExpr(s.getCond());1044 1045 // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())1046 assert(!cir::MissingFeatures::pgoUse());1047 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());1048 // TODO: if the switch has a condition wrapped by __builtin_unpredictable?1049 assert(!cir::MissingFeatures::insertBuiltinUnpredictable());1050 1051 mlir::LogicalResult res = mlir::success();1052 swop = SwitchOp::create(1053 builder, getLoc(s.getBeginLoc()), condV,1054 /*switchBuilder=*/1055 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {1056 curLexScope->setAsSwitch();1057 1058 condTypeStack.push_back(condV.getType());1059 1060 res = emitSwitchBody(s.getBody());1061 1062 condTypeStack.pop_back();1063 });1064 1065 return res;1066 };1067 1068 // The switch scope contains the full source range for SwitchStmt.1069 mlir::Location scopeLoc = getLoc(s.getSourceRange());1070 mlir::LogicalResult res = mlir::success();1071 cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/1072 [&](mlir::OpBuilder &b, mlir::Location loc) {1073 LexicalScope lexScope{*this, loc,1074 builder.getInsertionBlock()};1075 res = switchStmtBuilder();1076 });1077 1078 llvm::SmallVector<CaseOp> cases;1079 swop.collectCases(cases);1080 for (auto caseOp : cases)1081 terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());1082 terminateBody(builder, swop.getBody(), swop.getLoc());1083 1084 return res;1085}1086 1087void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv,1088 QualType ty) {1089 if (rv.isScalar()) {1090 builder.createStore(loc, rv.getValue(), returnValue);1091 } else if (rv.isAggregate()) {1092 LValue dest = makeAddrLValue(returnValue, ty);1093 LValue src = makeAddrLValue(rv.getAggregateAddress(), ty);1094 emitAggregateCopy(dest, src, ty, getOverlapForReturnValue());1095 } else {1096 cgm.errorNYI(loc, "emitReturnOfRValue: complex return type");1097 }1098 mlir::Block *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);1099 assert(!cir::MissingFeatures::emitBranchThroughCleanup());1100 cir::BrOp::create(builder, loc, retBlock);1101 if (ehStack.stable_begin() != currentCleanupStackDepth)1102 cgm.errorNYI(loc, "return of r-value with cleanup stack");1103}1104