xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenStmt.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // Emit Stmt nodes as CIR code.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "CIRGenBuilder.h"
14*700637cbSDimitry Andric #include "CIRGenFunction.h"
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric #include "mlir/IR/Builders.h"
17*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
18*700637cbSDimitry Andric #include "clang/AST/Stmt.h"
19*700637cbSDimitry Andric #include "clang/AST/StmtOpenACC.h"
20*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h"
21*700637cbSDimitry Andric 
22*700637cbSDimitry Andric using namespace clang;
23*700637cbSDimitry Andric using namespace clang::CIRGen;
24*700637cbSDimitry Andric using namespace cir;
25*700637cbSDimitry Andric 
emitCompoundStmtWithoutScope(const CompoundStmt & s)26*700637cbSDimitry Andric void CIRGenFunction::emitCompoundStmtWithoutScope(const CompoundStmt &s) {
27*700637cbSDimitry Andric   for (auto *curStmt : s.body()) {
28*700637cbSDimitry Andric     if (emitStmt(curStmt, /*useCurrentScope=*/false).failed())
29*700637cbSDimitry Andric       getCIRGenModule().errorNYI(curStmt->getSourceRange(),
30*700637cbSDimitry Andric                                  std::string("emitCompoundStmtWithoutScope: ") +
31*700637cbSDimitry Andric                                      curStmt->getStmtClassName());
32*700637cbSDimitry Andric   }
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric 
emitCompoundStmt(const CompoundStmt & s)35*700637cbSDimitry Andric void CIRGenFunction::emitCompoundStmt(const CompoundStmt &s) {
36*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
37*700637cbSDimitry Andric   mlir::OpBuilder::InsertPoint scopeInsPt;
38*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(
39*700637cbSDimitry Andric       scopeLoc, [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
40*700637cbSDimitry Andric         scopeInsPt = b.saveInsertionPoint();
41*700637cbSDimitry Andric       });
42*700637cbSDimitry Andric   {
43*700637cbSDimitry Andric     mlir::OpBuilder::InsertionGuard guard(builder);
44*700637cbSDimitry Andric     builder.restoreInsertionPoint(scopeInsPt);
45*700637cbSDimitry Andric     LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
46*700637cbSDimitry Andric     emitCompoundStmtWithoutScope(s);
47*700637cbSDimitry Andric   }
48*700637cbSDimitry Andric }
49*700637cbSDimitry Andric 
emitStopPoint(const Stmt * s)50*700637cbSDimitry Andric void CIRGenFunction::emitStopPoint(const Stmt *s) {
51*700637cbSDimitry Andric   assert(!cir::MissingFeatures::generateDebugInfo());
52*700637cbSDimitry Andric }
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric // Build CIR for a statement. useCurrentScope should be true if no new scopes
55*700637cbSDimitry Andric // need to be created when finding a compound statement.
emitStmt(const Stmt * s,bool useCurrentScope,ArrayRef<const Attr * > attr)56*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
57*700637cbSDimitry Andric                                              bool useCurrentScope,
58*700637cbSDimitry Andric                                              ArrayRef<const Attr *> attr) {
59*700637cbSDimitry Andric   if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
60*700637cbSDimitry Andric     return mlir::success();
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric   switch (s->getStmtClass()) {
63*700637cbSDimitry Andric   case Stmt::NoStmtClass:
64*700637cbSDimitry Andric   case Stmt::CXXCatchStmtClass:
65*700637cbSDimitry Andric   case Stmt::SEHExceptStmtClass:
66*700637cbSDimitry Andric   case Stmt::SEHFinallyStmtClass:
67*700637cbSDimitry Andric   case Stmt::MSDependentExistsStmtClass:
68*700637cbSDimitry Andric     llvm_unreachable("invalid statement class to emit generically");
69*700637cbSDimitry Andric   case Stmt::BreakStmtClass:
70*700637cbSDimitry Andric   case Stmt::NullStmtClass:
71*700637cbSDimitry Andric   case Stmt::CompoundStmtClass:
72*700637cbSDimitry Andric   case Stmt::ContinueStmtClass:
73*700637cbSDimitry Andric   case Stmt::DeclStmtClass:
74*700637cbSDimitry Andric   case Stmt::ReturnStmtClass:
75*700637cbSDimitry Andric     llvm_unreachable("should have emitted these statements as simple");
76*700637cbSDimitry Andric 
77*700637cbSDimitry Andric #define STMT(Type, Base)
78*700637cbSDimitry Andric #define ABSTRACT_STMT(Op)
79*700637cbSDimitry Andric #define EXPR(Type, Base) case Stmt::Type##Class:
80*700637cbSDimitry Andric #include "clang/AST/StmtNodes.inc"
81*700637cbSDimitry Andric     {
82*700637cbSDimitry Andric       // Remember the block we came in on.
83*700637cbSDimitry Andric       mlir::Block *incoming = builder.getInsertionBlock();
84*700637cbSDimitry Andric       assert(incoming && "expression emission must have an insertion point");
85*700637cbSDimitry Andric 
86*700637cbSDimitry Andric       emitIgnoredExpr(cast<Expr>(s));
87*700637cbSDimitry Andric 
88*700637cbSDimitry Andric       mlir::Block *outgoing = builder.getInsertionBlock();
89*700637cbSDimitry Andric       assert(outgoing && "expression emission cleared block!");
90*700637cbSDimitry Andric       return mlir::success();
91*700637cbSDimitry Andric     }
92*700637cbSDimitry Andric   case Stmt::IfStmtClass:
93*700637cbSDimitry Andric     return emitIfStmt(cast<IfStmt>(*s));
94*700637cbSDimitry Andric   case Stmt::SwitchStmtClass:
95*700637cbSDimitry Andric     return emitSwitchStmt(cast<SwitchStmt>(*s));
96*700637cbSDimitry Andric   case Stmt::ForStmtClass:
97*700637cbSDimitry Andric     return emitForStmt(cast<ForStmt>(*s));
98*700637cbSDimitry Andric   case Stmt::WhileStmtClass:
99*700637cbSDimitry Andric     return emitWhileStmt(cast<WhileStmt>(*s));
100*700637cbSDimitry Andric   case Stmt::DoStmtClass:
101*700637cbSDimitry Andric     return emitDoStmt(cast<DoStmt>(*s));
102*700637cbSDimitry Andric   case Stmt::CXXForRangeStmtClass:
103*700637cbSDimitry Andric     return emitCXXForRangeStmt(cast<CXXForRangeStmt>(*s), attr);
104*700637cbSDimitry Andric   case Stmt::OpenACCComputeConstructClass:
105*700637cbSDimitry Andric     return emitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*s));
106*700637cbSDimitry Andric   case Stmt::OpenACCLoopConstructClass:
107*700637cbSDimitry Andric     return emitOpenACCLoopConstruct(cast<OpenACCLoopConstruct>(*s));
108*700637cbSDimitry Andric   case Stmt::OpenACCCombinedConstructClass:
109*700637cbSDimitry Andric     return emitOpenACCCombinedConstruct(cast<OpenACCCombinedConstruct>(*s));
110*700637cbSDimitry Andric   case Stmt::OpenACCDataConstructClass:
111*700637cbSDimitry Andric     return emitOpenACCDataConstruct(cast<OpenACCDataConstruct>(*s));
112*700637cbSDimitry Andric   case Stmt::OpenACCEnterDataConstructClass:
113*700637cbSDimitry Andric     return emitOpenACCEnterDataConstruct(cast<OpenACCEnterDataConstruct>(*s));
114*700637cbSDimitry Andric   case Stmt::OpenACCExitDataConstructClass:
115*700637cbSDimitry Andric     return emitOpenACCExitDataConstruct(cast<OpenACCExitDataConstruct>(*s));
116*700637cbSDimitry Andric   case Stmt::OpenACCHostDataConstructClass:
117*700637cbSDimitry Andric     return emitOpenACCHostDataConstruct(cast<OpenACCHostDataConstruct>(*s));
118*700637cbSDimitry Andric   case Stmt::OpenACCWaitConstructClass:
119*700637cbSDimitry Andric     return emitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*s));
120*700637cbSDimitry Andric   case Stmt::OpenACCInitConstructClass:
121*700637cbSDimitry Andric     return emitOpenACCInitConstruct(cast<OpenACCInitConstruct>(*s));
122*700637cbSDimitry Andric   case Stmt::OpenACCShutdownConstructClass:
123*700637cbSDimitry Andric     return emitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*s));
124*700637cbSDimitry Andric   case Stmt::OpenACCSetConstructClass:
125*700637cbSDimitry Andric     return emitOpenACCSetConstruct(cast<OpenACCSetConstruct>(*s));
126*700637cbSDimitry Andric   case Stmt::OpenACCUpdateConstructClass:
127*700637cbSDimitry Andric     return emitOpenACCUpdateConstruct(cast<OpenACCUpdateConstruct>(*s));
128*700637cbSDimitry Andric   case Stmt::OpenACCCacheConstructClass:
129*700637cbSDimitry Andric     return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));
130*700637cbSDimitry Andric   case Stmt::OpenACCAtomicConstructClass:
131*700637cbSDimitry Andric     return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));
132*700637cbSDimitry Andric   case Stmt::OMPScopeDirectiveClass:
133*700637cbSDimitry Andric   case Stmt::OMPErrorDirectiveClass:
134*700637cbSDimitry Andric   case Stmt::LabelStmtClass:
135*700637cbSDimitry Andric   case Stmt::AttributedStmtClass:
136*700637cbSDimitry Andric   case Stmt::GotoStmtClass:
137*700637cbSDimitry Andric   case Stmt::DefaultStmtClass:
138*700637cbSDimitry Andric   case Stmt::CaseStmtClass:
139*700637cbSDimitry Andric   case Stmt::SEHLeaveStmtClass:
140*700637cbSDimitry Andric   case Stmt::SYCLKernelCallStmtClass:
141*700637cbSDimitry Andric   case Stmt::CoroutineBodyStmtClass:
142*700637cbSDimitry Andric   case Stmt::CoreturnStmtClass:
143*700637cbSDimitry Andric   case Stmt::CXXTryStmtClass:
144*700637cbSDimitry Andric   case Stmt::IndirectGotoStmtClass:
145*700637cbSDimitry Andric   case Stmt::GCCAsmStmtClass:
146*700637cbSDimitry Andric   case Stmt::MSAsmStmtClass:
147*700637cbSDimitry Andric   case Stmt::OMPParallelDirectiveClass:
148*700637cbSDimitry Andric   case Stmt::OMPTaskwaitDirectiveClass:
149*700637cbSDimitry Andric   case Stmt::OMPTaskyieldDirectiveClass:
150*700637cbSDimitry Andric   case Stmt::OMPBarrierDirectiveClass:
151*700637cbSDimitry Andric   case Stmt::CapturedStmtClass:
152*700637cbSDimitry Andric   case Stmt::ObjCAtTryStmtClass:
153*700637cbSDimitry Andric   case Stmt::ObjCAtThrowStmtClass:
154*700637cbSDimitry Andric   case Stmt::ObjCAtSynchronizedStmtClass:
155*700637cbSDimitry Andric   case Stmt::ObjCForCollectionStmtClass:
156*700637cbSDimitry Andric   case Stmt::ObjCAutoreleasePoolStmtClass:
157*700637cbSDimitry Andric   case Stmt::SEHTryStmtClass:
158*700637cbSDimitry Andric   case Stmt::OMPMetaDirectiveClass:
159*700637cbSDimitry Andric   case Stmt::OMPCanonicalLoopClass:
160*700637cbSDimitry Andric   case Stmt::OMPSimdDirectiveClass:
161*700637cbSDimitry Andric   case Stmt::OMPTileDirectiveClass:
162*700637cbSDimitry Andric   case Stmt::OMPUnrollDirectiveClass:
163*700637cbSDimitry Andric   case Stmt::OMPForDirectiveClass:
164*700637cbSDimitry Andric   case Stmt::OMPForSimdDirectiveClass:
165*700637cbSDimitry Andric   case Stmt::OMPSectionsDirectiveClass:
166*700637cbSDimitry Andric   case Stmt::OMPSectionDirectiveClass:
167*700637cbSDimitry Andric   case Stmt::OMPSingleDirectiveClass:
168*700637cbSDimitry Andric   case Stmt::OMPMasterDirectiveClass:
169*700637cbSDimitry Andric   case Stmt::OMPCriticalDirectiveClass:
170*700637cbSDimitry Andric   case Stmt::OMPParallelForDirectiveClass:
171*700637cbSDimitry Andric   case Stmt::OMPParallelForSimdDirectiveClass:
172*700637cbSDimitry Andric   case Stmt::OMPParallelMasterDirectiveClass:
173*700637cbSDimitry Andric   case Stmt::OMPParallelSectionsDirectiveClass:
174*700637cbSDimitry Andric   case Stmt::OMPTaskDirectiveClass:
175*700637cbSDimitry Andric   case Stmt::OMPTaskgroupDirectiveClass:
176*700637cbSDimitry Andric   case Stmt::OMPFlushDirectiveClass:
177*700637cbSDimitry Andric   case Stmt::OMPDepobjDirectiveClass:
178*700637cbSDimitry Andric   case Stmt::OMPScanDirectiveClass:
179*700637cbSDimitry Andric   case Stmt::OMPOrderedDirectiveClass:
180*700637cbSDimitry Andric   case Stmt::OMPAtomicDirectiveClass:
181*700637cbSDimitry Andric   case Stmt::OMPTargetDirectiveClass:
182*700637cbSDimitry Andric   case Stmt::OMPTeamsDirectiveClass:
183*700637cbSDimitry Andric   case Stmt::OMPCancellationPointDirectiveClass:
184*700637cbSDimitry Andric   case Stmt::OMPCancelDirectiveClass:
185*700637cbSDimitry Andric   case Stmt::OMPTargetDataDirectiveClass:
186*700637cbSDimitry Andric   case Stmt::OMPTargetEnterDataDirectiveClass:
187*700637cbSDimitry Andric   case Stmt::OMPTargetExitDataDirectiveClass:
188*700637cbSDimitry Andric   case Stmt::OMPTargetParallelDirectiveClass:
189*700637cbSDimitry Andric   case Stmt::OMPTargetParallelForDirectiveClass:
190*700637cbSDimitry Andric   case Stmt::OMPTaskLoopDirectiveClass:
191*700637cbSDimitry Andric   case Stmt::OMPTaskLoopSimdDirectiveClass:
192*700637cbSDimitry Andric   case Stmt::OMPMaskedTaskLoopDirectiveClass:
193*700637cbSDimitry Andric   case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
194*700637cbSDimitry Andric   case Stmt::OMPMasterTaskLoopDirectiveClass:
195*700637cbSDimitry Andric   case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
196*700637cbSDimitry Andric   case Stmt::OMPParallelGenericLoopDirectiveClass:
197*700637cbSDimitry Andric   case Stmt::OMPParallelMaskedDirectiveClass:
198*700637cbSDimitry Andric   case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
199*700637cbSDimitry Andric   case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
200*700637cbSDimitry Andric   case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
201*700637cbSDimitry Andric   case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
202*700637cbSDimitry Andric   case Stmt::OMPDistributeDirectiveClass:
203*700637cbSDimitry Andric   case Stmt::OMPDistributeParallelForDirectiveClass:
204*700637cbSDimitry Andric   case Stmt::OMPDistributeParallelForSimdDirectiveClass:
205*700637cbSDimitry Andric   case Stmt::OMPDistributeSimdDirectiveClass:
206*700637cbSDimitry Andric   case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
207*700637cbSDimitry Andric   case Stmt::OMPTargetParallelForSimdDirectiveClass:
208*700637cbSDimitry Andric   case Stmt::OMPTargetSimdDirectiveClass:
209*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
210*700637cbSDimitry Andric   case Stmt::OMPTargetUpdateDirectiveClass:
211*700637cbSDimitry Andric   case Stmt::OMPTeamsDistributeDirectiveClass:
212*700637cbSDimitry Andric   case Stmt::OMPTeamsDistributeSimdDirectiveClass:
213*700637cbSDimitry Andric   case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
214*700637cbSDimitry Andric   case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
215*700637cbSDimitry Andric   case Stmt::OMPTeamsGenericLoopDirectiveClass:
216*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsDirectiveClass:
217*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsDistributeDirectiveClass:
218*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
219*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
220*700637cbSDimitry Andric   case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
221*700637cbSDimitry Andric   case Stmt::OMPInteropDirectiveClass:
222*700637cbSDimitry Andric   case Stmt::OMPDispatchDirectiveClass:
223*700637cbSDimitry Andric   case Stmt::OMPGenericLoopDirectiveClass:
224*700637cbSDimitry Andric   case Stmt::OMPReverseDirectiveClass:
225*700637cbSDimitry Andric   case Stmt::OMPInterchangeDirectiveClass:
226*700637cbSDimitry Andric   case Stmt::OMPAssumeDirectiveClass:
227*700637cbSDimitry Andric   case Stmt::OMPMaskedDirectiveClass:
228*700637cbSDimitry Andric   case Stmt::OMPStripeDirectiveClass:
229*700637cbSDimitry Andric   case Stmt::ObjCAtCatchStmtClass:
230*700637cbSDimitry Andric   case Stmt::ObjCAtFinallyStmtClass:
231*700637cbSDimitry Andric     cgm.errorNYI(s->getSourceRange(),
232*700637cbSDimitry Andric                  std::string("emitStmt: ") + s->getStmtClassName());
233*700637cbSDimitry Andric     return mlir::failure();
234*700637cbSDimitry Andric   }
235*700637cbSDimitry Andric 
236*700637cbSDimitry Andric   llvm_unreachable("Unexpected statement class");
237*700637cbSDimitry Andric }
238*700637cbSDimitry Andric 
emitSimpleStmt(const Stmt * s,bool useCurrentScope)239*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
240*700637cbSDimitry Andric                                                    bool useCurrentScope) {
241*700637cbSDimitry Andric   switch (s->getStmtClass()) {
242*700637cbSDimitry Andric   default:
243*700637cbSDimitry Andric     return mlir::failure();
244*700637cbSDimitry Andric   case Stmt::DeclStmtClass:
245*700637cbSDimitry Andric     return emitDeclStmt(cast<DeclStmt>(*s));
246*700637cbSDimitry Andric   case Stmt::CompoundStmtClass:
247*700637cbSDimitry Andric     if (useCurrentScope)
248*700637cbSDimitry Andric       emitCompoundStmtWithoutScope(cast<CompoundStmt>(*s));
249*700637cbSDimitry Andric     else
250*700637cbSDimitry Andric       emitCompoundStmt(cast<CompoundStmt>(*s));
251*700637cbSDimitry Andric     break;
252*700637cbSDimitry Andric   case Stmt::ContinueStmtClass:
253*700637cbSDimitry Andric     return emitContinueStmt(cast<ContinueStmt>(*s));
254*700637cbSDimitry Andric 
255*700637cbSDimitry Andric   // NullStmt doesn't need any handling, but we need to say we handled it.
256*700637cbSDimitry Andric   case Stmt::NullStmtClass:
257*700637cbSDimitry Andric     break;
258*700637cbSDimitry Andric   case Stmt::CaseStmtClass:
259*700637cbSDimitry Andric   case Stmt::DefaultStmtClass:
260*700637cbSDimitry Andric     // If we reached here, we must not handling a switch case in the top level.
261*700637cbSDimitry Andric     return emitSwitchCase(cast<SwitchCase>(*s),
262*700637cbSDimitry Andric                           /*buildingTopLevelCase=*/false);
263*700637cbSDimitry Andric     break;
264*700637cbSDimitry Andric 
265*700637cbSDimitry Andric   case Stmt::BreakStmtClass:
266*700637cbSDimitry Andric     return emitBreakStmt(cast<BreakStmt>(*s));
267*700637cbSDimitry Andric   case Stmt::ReturnStmtClass:
268*700637cbSDimitry Andric     return emitReturnStmt(cast<ReturnStmt>(*s));
269*700637cbSDimitry Andric   }
270*700637cbSDimitry Andric 
271*700637cbSDimitry Andric   return mlir::success();
272*700637cbSDimitry Andric }
273*700637cbSDimitry Andric 
274*700637cbSDimitry Andric // Add a terminating yield on a body region if no other terminators are used.
terminateBody(CIRGenBuilderTy & builder,mlir::Region & r,mlir::Location loc)275*700637cbSDimitry Andric static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r,
276*700637cbSDimitry Andric                           mlir::Location loc) {
277*700637cbSDimitry Andric   if (r.empty())
278*700637cbSDimitry Andric     return;
279*700637cbSDimitry Andric 
280*700637cbSDimitry Andric   SmallVector<mlir::Block *, 4> eraseBlocks;
281*700637cbSDimitry Andric   unsigned numBlocks = r.getBlocks().size();
282*700637cbSDimitry Andric   for (auto &block : r.getBlocks()) {
283*700637cbSDimitry Andric     // Already cleanup after return operations, which might create
284*700637cbSDimitry Andric     // empty blocks if emitted as last stmt.
285*700637cbSDimitry Andric     if (numBlocks != 1 && block.empty() && block.hasNoPredecessors() &&
286*700637cbSDimitry Andric         block.hasNoSuccessors())
287*700637cbSDimitry Andric       eraseBlocks.push_back(&block);
288*700637cbSDimitry Andric 
289*700637cbSDimitry Andric     if (block.empty() ||
290*700637cbSDimitry Andric         !block.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
291*700637cbSDimitry Andric       mlir::OpBuilder::InsertionGuard guardCase(builder);
292*700637cbSDimitry Andric       builder.setInsertionPointToEnd(&block);
293*700637cbSDimitry Andric       builder.createYield(loc);
294*700637cbSDimitry Andric     }
295*700637cbSDimitry Andric   }
296*700637cbSDimitry Andric 
297*700637cbSDimitry Andric   for (auto *b : eraseBlocks)
298*700637cbSDimitry Andric     b->erase();
299*700637cbSDimitry Andric }
300*700637cbSDimitry Andric 
emitIfStmt(const IfStmt & s)301*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
302*700637cbSDimitry Andric   mlir::LogicalResult res = mlir::success();
303*700637cbSDimitry Andric   // The else branch of a consteval if statement is always the only branch
304*700637cbSDimitry Andric   // that can be runtime evaluated.
305*700637cbSDimitry Andric   const Stmt *constevalExecuted;
306*700637cbSDimitry Andric   if (s.isConsteval()) {
307*700637cbSDimitry Andric     constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
308*700637cbSDimitry Andric     if (!constevalExecuted) {
309*700637cbSDimitry Andric       // No runtime code execution required
310*700637cbSDimitry Andric       return res;
311*700637cbSDimitry Andric     }
312*700637cbSDimitry Andric   }
313*700637cbSDimitry Andric 
314*700637cbSDimitry Andric   // C99 6.8.4.1: The first substatement is executed if the expression
315*700637cbSDimitry Andric   // compares unequal to 0.  The condition must be a scalar type.
316*700637cbSDimitry Andric   auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
317*700637cbSDimitry Andric     if (s.isConsteval())
318*700637cbSDimitry Andric       return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
319*700637cbSDimitry Andric 
320*700637cbSDimitry Andric     if (s.getInit())
321*700637cbSDimitry Andric       if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
322*700637cbSDimitry Andric         return mlir::failure();
323*700637cbSDimitry Andric 
324*700637cbSDimitry Andric     if (s.getConditionVariable())
325*700637cbSDimitry Andric       emitDecl(*s.getConditionVariable());
326*700637cbSDimitry Andric 
327*700637cbSDimitry Andric     // If the condition folds to a constant and this is an 'if constexpr',
328*700637cbSDimitry Andric     // we simplify it early in CIRGen to avoid emitting the full 'if'.
329*700637cbSDimitry Andric     bool condConstant;
330*700637cbSDimitry Andric     if (constantFoldsToBool(s.getCond(), condConstant, s.isConstexpr())) {
331*700637cbSDimitry Andric       if (s.isConstexpr()) {
332*700637cbSDimitry Andric         // Handle "if constexpr" explicitly here to avoid generating some
333*700637cbSDimitry Andric         // ill-formed code since in CIR the "if" is no longer simplified
334*700637cbSDimitry Andric         // in this lambda like in Clang but postponed to other MLIR
335*700637cbSDimitry Andric         // passes.
336*700637cbSDimitry Andric         if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())
337*700637cbSDimitry Andric           return emitStmt(executed, /*useCurrentScope=*/true);
338*700637cbSDimitry Andric         // There is nothing to execute at runtime.
339*700637cbSDimitry Andric         // TODO(cir): there is still an empty cir.scope generated by the caller.
340*700637cbSDimitry Andric         return mlir::success();
341*700637cbSDimitry Andric       }
342*700637cbSDimitry Andric     }
343*700637cbSDimitry Andric 
344*700637cbSDimitry Andric     assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
345*700637cbSDimitry Andric     assert(!cir::MissingFeatures::incrementProfileCounter());
346*700637cbSDimitry Andric     return emitIfOnBoolExpr(s.getCond(), s.getThen(), s.getElse());
347*700637cbSDimitry Andric   };
348*700637cbSDimitry Andric 
349*700637cbSDimitry Andric   // TODO: Add a new scoped symbol table.
350*700637cbSDimitry Andric   // LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
351*700637cbSDimitry Andric   // The if scope contains the full source range for IfStmt.
352*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
353*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(
354*700637cbSDimitry Andric       scopeLoc, /*scopeBuilder=*/
355*700637cbSDimitry Andric       [&](mlir::OpBuilder &b, mlir::Location loc) {
356*700637cbSDimitry Andric         LexicalScope lexScope{*this, scopeLoc, builder.getInsertionBlock()};
357*700637cbSDimitry Andric         res = ifStmtBuilder();
358*700637cbSDimitry Andric       });
359*700637cbSDimitry Andric 
360*700637cbSDimitry Andric   return res;
361*700637cbSDimitry Andric }
362*700637cbSDimitry Andric 
emitDeclStmt(const DeclStmt & s)363*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
364*700637cbSDimitry Andric   assert(builder.getInsertionBlock() && "expected valid insertion point");
365*700637cbSDimitry Andric 
366*700637cbSDimitry Andric   for (const Decl *I : s.decls())
367*700637cbSDimitry Andric     emitDecl(*I);
368*700637cbSDimitry Andric 
369*700637cbSDimitry Andric   return mlir::success();
370*700637cbSDimitry Andric }
371*700637cbSDimitry Andric 
emitReturnStmt(const ReturnStmt & s)372*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
373*700637cbSDimitry Andric   mlir::Location loc = getLoc(s.getSourceRange());
374*700637cbSDimitry Andric   const Expr *rv = s.getRetValue();
375*700637cbSDimitry Andric 
376*700637cbSDimitry Andric   if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() &&
377*700637cbSDimitry Andric       s.getNRVOCandidate()->isNRVOVariable()) {
378*700637cbSDimitry Andric     getCIRGenModule().errorNYI(s.getSourceRange(),
379*700637cbSDimitry Andric                                "named return value optimization");
380*700637cbSDimitry Andric   } else if (!rv) {
381*700637cbSDimitry Andric     // No return expression. Do nothing.
382*700637cbSDimitry Andric   } else if (rv->getType()->isVoidType()) {
383*700637cbSDimitry Andric     // Make sure not to return anything, but evaluate the expression
384*700637cbSDimitry Andric     // for side effects.
385*700637cbSDimitry Andric     if (rv) {
386*700637cbSDimitry Andric       emitAnyExpr(rv);
387*700637cbSDimitry Andric     }
388*700637cbSDimitry Andric   } else if (cast<FunctionDecl>(curGD.getDecl())
389*700637cbSDimitry Andric                  ->getReturnType()
390*700637cbSDimitry Andric                  ->isReferenceType()) {
391*700637cbSDimitry Andric     // If this function returns a reference, take the address of the
392*700637cbSDimitry Andric     // expression rather than the value.
393*700637cbSDimitry Andric     RValue result = emitReferenceBindingToExpr(rv);
394*700637cbSDimitry Andric     builder.CIRBaseBuilderTy::createStore(loc, result.getValue(), *fnRetAlloca);
395*700637cbSDimitry Andric   } else {
396*700637cbSDimitry Andric     mlir::Value value = nullptr;
397*700637cbSDimitry Andric     switch (CIRGenFunction::getEvaluationKind(rv->getType())) {
398*700637cbSDimitry Andric     case cir::TEK_Scalar:
399*700637cbSDimitry Andric       value = emitScalarExpr(rv);
400*700637cbSDimitry Andric       if (value) { // Change this to an assert once emitScalarExpr is complete
401*700637cbSDimitry Andric         builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
402*700637cbSDimitry Andric       }
403*700637cbSDimitry Andric       break;
404*700637cbSDimitry Andric     default:
405*700637cbSDimitry Andric       getCIRGenModule().errorNYI(s.getSourceRange(),
406*700637cbSDimitry Andric                                  "non-scalar function return type");
407*700637cbSDimitry Andric       break;
408*700637cbSDimitry Andric     }
409*700637cbSDimitry Andric   }
410*700637cbSDimitry Andric 
411*700637cbSDimitry Andric   auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
412*700637cbSDimitry Andric   builder.create<cir::BrOp>(loc, retBlock);
413*700637cbSDimitry Andric   builder.createBlock(builder.getBlock()->getParent());
414*700637cbSDimitry Andric 
415*700637cbSDimitry Andric   return mlir::success();
416*700637cbSDimitry Andric }
417*700637cbSDimitry Andric 
418*700637cbSDimitry Andric mlir::LogicalResult
emitContinueStmt(const clang::ContinueStmt & s)419*700637cbSDimitry Andric CIRGenFunction::emitContinueStmt(const clang::ContinueStmt &s) {
420*700637cbSDimitry Andric   builder.createContinue(getLoc(s.getContinueLoc()));
421*700637cbSDimitry Andric 
422*700637cbSDimitry Andric   // Insert the new block to continue codegen after the continue statement.
423*700637cbSDimitry Andric   builder.createBlock(builder.getBlock()->getParent());
424*700637cbSDimitry Andric 
425*700637cbSDimitry Andric   return mlir::success();
426*700637cbSDimitry Andric }
427*700637cbSDimitry Andric 
emitBreakStmt(const clang::BreakStmt & s)428*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
429*700637cbSDimitry Andric   builder.createBreak(getLoc(s.getBreakLoc()));
430*700637cbSDimitry Andric 
431*700637cbSDimitry Andric   // Insert the new block to continue codegen after the break statement.
432*700637cbSDimitry Andric   builder.createBlock(builder.getBlock()->getParent());
433*700637cbSDimitry Andric 
434*700637cbSDimitry Andric   return mlir::success();
435*700637cbSDimitry Andric }
436*700637cbSDimitry Andric 
437*700637cbSDimitry Andric template <typename T>
438*700637cbSDimitry Andric mlir::LogicalResult
emitCaseDefaultCascade(const T * stmt,mlir::Type condType,mlir::ArrayAttr value,CaseOpKind kind,bool buildingTopLevelCase)439*700637cbSDimitry Andric CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
440*700637cbSDimitry Andric                                        mlir::ArrayAttr value, CaseOpKind kind,
441*700637cbSDimitry Andric                                        bool buildingTopLevelCase) {
442*700637cbSDimitry Andric 
443*700637cbSDimitry Andric   assert((isa<CaseStmt, DefaultStmt>(stmt)) &&
444*700637cbSDimitry Andric          "only case or default stmt go here");
445*700637cbSDimitry Andric 
446*700637cbSDimitry Andric   mlir::LogicalResult result = mlir::success();
447*700637cbSDimitry Andric 
448*700637cbSDimitry Andric   mlir::Location loc = getLoc(stmt->getBeginLoc());
449*700637cbSDimitry Andric 
450*700637cbSDimitry Andric   enum class SubStmtKind { Case, Default, Other };
451*700637cbSDimitry Andric   SubStmtKind subStmtKind = SubStmtKind::Other;
452*700637cbSDimitry Andric   const Stmt *sub = stmt->getSubStmt();
453*700637cbSDimitry Andric 
454*700637cbSDimitry Andric   mlir::OpBuilder::InsertPoint insertPoint;
455*700637cbSDimitry Andric   builder.create<CaseOp>(loc, value, kind, insertPoint);
456*700637cbSDimitry Andric 
457*700637cbSDimitry Andric   {
458*700637cbSDimitry Andric     mlir::OpBuilder::InsertionGuard guardSwitch(builder);
459*700637cbSDimitry Andric     builder.restoreInsertionPoint(insertPoint);
460*700637cbSDimitry Andric 
461*700637cbSDimitry Andric     if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
462*700637cbSDimitry Andric       subStmtKind = SubStmtKind::Default;
463*700637cbSDimitry Andric       builder.createYield(loc);
464*700637cbSDimitry Andric     } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
465*700637cbSDimitry Andric       subStmtKind = SubStmtKind::Case;
466*700637cbSDimitry Andric       builder.createYield(loc);
467*700637cbSDimitry Andric     } else {
468*700637cbSDimitry Andric       result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
469*700637cbSDimitry Andric     }
470*700637cbSDimitry Andric 
471*700637cbSDimitry Andric     insertPoint = builder.saveInsertionPoint();
472*700637cbSDimitry Andric   }
473*700637cbSDimitry Andric 
474*700637cbSDimitry Andric   // If the substmt is default stmt or case stmt, try to handle the special case
475*700637cbSDimitry Andric   // to make it into the simple form. e.g.
476*700637cbSDimitry Andric   //
477*700637cbSDimitry Andric   //  swtich () {
478*700637cbSDimitry Andric   //    case 1:
479*700637cbSDimitry Andric   //    default:
480*700637cbSDimitry Andric   //      ...
481*700637cbSDimitry Andric   //  }
482*700637cbSDimitry Andric   //
483*700637cbSDimitry Andric   // we prefer generating
484*700637cbSDimitry Andric   //
485*700637cbSDimitry Andric   //  cir.switch() {
486*700637cbSDimitry Andric   //     cir.case(equal, 1) {
487*700637cbSDimitry Andric   //        cir.yield
488*700637cbSDimitry Andric   //     }
489*700637cbSDimitry Andric   //     cir.case(default) {
490*700637cbSDimitry Andric   //        ...
491*700637cbSDimitry Andric   //     }
492*700637cbSDimitry Andric   //  }
493*700637cbSDimitry Andric   //
494*700637cbSDimitry Andric   // than
495*700637cbSDimitry Andric   //
496*700637cbSDimitry Andric   //  cir.switch() {
497*700637cbSDimitry Andric   //     cir.case(equal, 1) {
498*700637cbSDimitry Andric   //       cir.case(default) {
499*700637cbSDimitry Andric   //         ...
500*700637cbSDimitry Andric   //       }
501*700637cbSDimitry Andric   //     }
502*700637cbSDimitry Andric   //  }
503*700637cbSDimitry Andric   //
504*700637cbSDimitry Andric   // We don't need to revert this if we find the current switch can't be in
505*700637cbSDimitry Andric   // simple form later since the conversion itself should be harmless.
506*700637cbSDimitry Andric   if (subStmtKind == SubStmtKind::Case) {
507*700637cbSDimitry Andric     result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
508*700637cbSDimitry Andric   } else if (subStmtKind == SubStmtKind::Default) {
509*700637cbSDimitry Andric     result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
510*700637cbSDimitry Andric                              buildingTopLevelCase);
511*700637cbSDimitry Andric   } else if (buildingTopLevelCase) {
512*700637cbSDimitry Andric     // If we're building a top level case, try to restore the insert point to
513*700637cbSDimitry Andric     // the case we're building, then we can attach more random stmts to the
514*700637cbSDimitry Andric     // case to make generating `cir.switch` operation to be a simple form.
515*700637cbSDimitry Andric     builder.restoreInsertionPoint(insertPoint);
516*700637cbSDimitry Andric   }
517*700637cbSDimitry Andric 
518*700637cbSDimitry Andric   return result;
519*700637cbSDimitry Andric }
520*700637cbSDimitry Andric 
emitCaseStmt(const CaseStmt & s,mlir::Type condType,bool buildingTopLevelCase)521*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
522*700637cbSDimitry Andric                                                  mlir::Type condType,
523*700637cbSDimitry Andric                                                  bool buildingTopLevelCase) {
524*700637cbSDimitry Andric   cir::CaseOpKind kind;
525*700637cbSDimitry Andric   mlir::ArrayAttr value;
526*700637cbSDimitry Andric   llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
527*700637cbSDimitry Andric 
528*700637cbSDimitry Andric   // If the case statement has an RHS value, it is representing a GNU
529*700637cbSDimitry Andric   // case range statement, where LHS is the beginning of the range
530*700637cbSDimitry Andric   // and RHS is the end of the range.
531*700637cbSDimitry Andric   if (const Expr *rhs = s.getRHS()) {
532*700637cbSDimitry Andric     llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
533*700637cbSDimitry Andric     value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
534*700637cbSDimitry Andric                                   cir::IntAttr::get(condType, endVal)});
535*700637cbSDimitry Andric     kind = cir::CaseOpKind::Range;
536*700637cbSDimitry Andric   } else {
537*700637cbSDimitry Andric     value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
538*700637cbSDimitry Andric     kind = cir::CaseOpKind::Equal;
539*700637cbSDimitry Andric   }
540*700637cbSDimitry Andric 
541*700637cbSDimitry Andric   return emitCaseDefaultCascade(&s, condType, value, kind,
542*700637cbSDimitry Andric                                 buildingTopLevelCase);
543*700637cbSDimitry Andric }
544*700637cbSDimitry Andric 
emitDefaultStmt(const clang::DefaultStmt & s,mlir::Type condType,bool buildingTopLevelCase)545*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitDefaultStmt(const clang::DefaultStmt &s,
546*700637cbSDimitry Andric                                                     mlir::Type condType,
547*700637cbSDimitry Andric                                                     bool buildingTopLevelCase) {
548*700637cbSDimitry Andric   return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
549*700637cbSDimitry Andric                                 cir::CaseOpKind::Default, buildingTopLevelCase);
550*700637cbSDimitry Andric }
551*700637cbSDimitry Andric 
emitSwitchCase(const SwitchCase & s,bool buildingTopLevelCase)552*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
553*700637cbSDimitry Andric                                                    bool buildingTopLevelCase) {
554*700637cbSDimitry Andric   assert(!condTypeStack.empty() &&
555*700637cbSDimitry Andric          "build switch case without specifying the type of the condition");
556*700637cbSDimitry Andric 
557*700637cbSDimitry Andric   if (s.getStmtClass() == Stmt::CaseStmtClass)
558*700637cbSDimitry Andric     return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
559*700637cbSDimitry Andric                         buildingTopLevelCase);
560*700637cbSDimitry Andric 
561*700637cbSDimitry Andric   if (s.getStmtClass() == Stmt::DefaultStmtClass)
562*700637cbSDimitry Andric     return emitDefaultStmt(cast<DefaultStmt>(s), condTypeStack.back(),
563*700637cbSDimitry Andric                            buildingTopLevelCase);
564*700637cbSDimitry Andric 
565*700637cbSDimitry Andric   llvm_unreachable("expect case or default stmt");
566*700637cbSDimitry Andric }
567*700637cbSDimitry Andric 
568*700637cbSDimitry Andric mlir::LogicalResult
emitCXXForRangeStmt(const CXXForRangeStmt & s,ArrayRef<const Attr * > forAttrs)569*700637cbSDimitry Andric CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt &s,
570*700637cbSDimitry Andric                                     ArrayRef<const Attr *> forAttrs) {
571*700637cbSDimitry Andric   cir::ForOp forOp;
572*700637cbSDimitry Andric 
573*700637cbSDimitry Andric   // TODO(cir): pass in array of attributes.
574*700637cbSDimitry Andric   auto forStmtBuilder = [&]() -> mlir::LogicalResult {
575*700637cbSDimitry Andric     mlir::LogicalResult loopRes = mlir::success();
576*700637cbSDimitry Andric     // Evaluate the first pieces before the loop.
577*700637cbSDimitry Andric     if (s.getInit())
578*700637cbSDimitry Andric       if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
579*700637cbSDimitry Andric         return mlir::failure();
580*700637cbSDimitry Andric     if (emitStmt(s.getRangeStmt(), /*useCurrentScope=*/true).failed())
581*700637cbSDimitry Andric       return mlir::failure();
582*700637cbSDimitry Andric     if (emitStmt(s.getBeginStmt(), /*useCurrentScope=*/true).failed())
583*700637cbSDimitry Andric       return mlir::failure();
584*700637cbSDimitry Andric     if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
585*700637cbSDimitry Andric       return mlir::failure();
586*700637cbSDimitry Andric 
587*700637cbSDimitry Andric     assert(!cir::MissingFeatures::loopInfoStack());
588*700637cbSDimitry Andric     // From LLVM: if there are any cleanups between here and the loop-exit
589*700637cbSDimitry Andric     // scope, create a block to stage a loop exit along.
590*700637cbSDimitry Andric     // We probably already do the right thing because of ScopeOp, but make
591*700637cbSDimitry Andric     // sure we handle all cases.
592*700637cbSDimitry Andric     assert(!cir::MissingFeatures::requiresCleanups());
593*700637cbSDimitry Andric 
594*700637cbSDimitry Andric     forOp = builder.createFor(
595*700637cbSDimitry Andric         getLoc(s.getSourceRange()),
596*700637cbSDimitry Andric         /*condBuilder=*/
597*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
598*700637cbSDimitry Andric           assert(!cir::MissingFeatures::createProfileWeightsForLoop());
599*700637cbSDimitry Andric           assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
600*700637cbSDimitry Andric           mlir::Value condVal = evaluateExprAsBool(s.getCond());
601*700637cbSDimitry Andric           builder.createCondition(condVal);
602*700637cbSDimitry Andric         },
603*700637cbSDimitry Andric         /*bodyBuilder=*/
604*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
605*700637cbSDimitry Andric           // https://en.cppreference.com/w/cpp/language/for
606*700637cbSDimitry Andric           // In C++ the scope of the init-statement and the scope of
607*700637cbSDimitry Andric           // statement are one and the same.
608*700637cbSDimitry Andric           bool useCurrentScope = true;
609*700637cbSDimitry Andric           if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
610*700637cbSDimitry Andric             loopRes = mlir::failure();
611*700637cbSDimitry Andric           if (emitStmt(s.getBody(), useCurrentScope).failed())
612*700637cbSDimitry Andric             loopRes = mlir::failure();
613*700637cbSDimitry Andric           emitStopPoint(&s);
614*700637cbSDimitry Andric         },
615*700637cbSDimitry Andric         /*stepBuilder=*/
616*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
617*700637cbSDimitry Andric           if (s.getInc())
618*700637cbSDimitry Andric             if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
619*700637cbSDimitry Andric               loopRes = mlir::failure();
620*700637cbSDimitry Andric           builder.createYield(loc);
621*700637cbSDimitry Andric         });
622*700637cbSDimitry Andric     return loopRes;
623*700637cbSDimitry Andric   };
624*700637cbSDimitry Andric 
625*700637cbSDimitry Andric   mlir::LogicalResult res = mlir::success();
626*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
627*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
628*700637cbSDimitry Andric                                [&](mlir::OpBuilder &b, mlir::Location loc) {
629*700637cbSDimitry Andric                                  // Create a cleanup scope for the condition
630*700637cbSDimitry Andric                                  // variable cleanups. Logical equivalent from
631*700637cbSDimitry Andric                                  // LLVM codegn for LexicalScope
632*700637cbSDimitry Andric                                  // ConditionScope(*this, S.getSourceRange())...
633*700637cbSDimitry Andric                                  LexicalScope lexScope{
634*700637cbSDimitry Andric                                      *this, loc, builder.getInsertionBlock()};
635*700637cbSDimitry Andric                                  res = forStmtBuilder();
636*700637cbSDimitry Andric                                });
637*700637cbSDimitry Andric 
638*700637cbSDimitry Andric   if (res.failed())
639*700637cbSDimitry Andric     return res;
640*700637cbSDimitry Andric 
641*700637cbSDimitry Andric   terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
642*700637cbSDimitry Andric   return mlir::success();
643*700637cbSDimitry Andric }
644*700637cbSDimitry Andric 
emitForStmt(const ForStmt & s)645*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
646*700637cbSDimitry Andric   cir::ForOp forOp;
647*700637cbSDimitry Andric 
648*700637cbSDimitry Andric   // TODO: pass in an array of attributes.
649*700637cbSDimitry Andric   auto forStmtBuilder = [&]() -> mlir::LogicalResult {
650*700637cbSDimitry Andric     mlir::LogicalResult loopRes = mlir::success();
651*700637cbSDimitry Andric     // Evaluate the first part before the loop.
652*700637cbSDimitry Andric     if (s.getInit())
653*700637cbSDimitry Andric       if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
654*700637cbSDimitry Andric         return mlir::failure();
655*700637cbSDimitry Andric     assert(!cir::MissingFeatures::loopInfoStack());
656*700637cbSDimitry Andric     // In the classic codegen, if there are any cleanups between here and the
657*700637cbSDimitry Andric     // loop-exit scope, a block is created to stage the loop exit. We probably
658*700637cbSDimitry Andric     // already do the right thing because of ScopeOp, but we need more testing
659*700637cbSDimitry Andric     // to be sure we handle all cases.
660*700637cbSDimitry Andric     assert(!cir::MissingFeatures::requiresCleanups());
661*700637cbSDimitry Andric 
662*700637cbSDimitry Andric     forOp = builder.createFor(
663*700637cbSDimitry Andric         getLoc(s.getSourceRange()),
664*700637cbSDimitry Andric         /*condBuilder=*/
665*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
666*700637cbSDimitry Andric           assert(!cir::MissingFeatures::createProfileWeightsForLoop());
667*700637cbSDimitry Andric           assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
668*700637cbSDimitry Andric           mlir::Value condVal;
669*700637cbSDimitry Andric           if (s.getCond()) {
670*700637cbSDimitry Andric             // If the for statement has a condition scope,
671*700637cbSDimitry Andric             // emit the local variable declaration.
672*700637cbSDimitry Andric             if (s.getConditionVariable())
673*700637cbSDimitry Andric               emitDecl(*s.getConditionVariable());
674*700637cbSDimitry Andric             // C99 6.8.5p2/p4: The first substatement is executed if the
675*700637cbSDimitry Andric             // expression compares unequal to 0. The condition must be a
676*700637cbSDimitry Andric             // scalar type.
677*700637cbSDimitry Andric             condVal = evaluateExprAsBool(s.getCond());
678*700637cbSDimitry Andric           } else {
679*700637cbSDimitry Andric             condVal = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
680*700637cbSDimitry Andric           }
681*700637cbSDimitry Andric           builder.createCondition(condVal);
682*700637cbSDimitry Andric         },
683*700637cbSDimitry Andric         /*bodyBuilder=*/
684*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
685*700637cbSDimitry Andric           // The scope of the for loop body is nested within the scope of the
686*700637cbSDimitry Andric           // for loop's init-statement and condition.
687*700637cbSDimitry Andric           if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
688*700637cbSDimitry Andric             loopRes = mlir::failure();
689*700637cbSDimitry Andric           emitStopPoint(&s);
690*700637cbSDimitry Andric         },
691*700637cbSDimitry Andric         /*stepBuilder=*/
692*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
693*700637cbSDimitry Andric           if (s.getInc())
694*700637cbSDimitry Andric             if (emitStmt(s.getInc(), /*useCurrentScope=*/true).failed())
695*700637cbSDimitry Andric               loopRes = mlir::failure();
696*700637cbSDimitry Andric           builder.createYield(loc);
697*700637cbSDimitry Andric         });
698*700637cbSDimitry Andric     return loopRes;
699*700637cbSDimitry Andric   };
700*700637cbSDimitry Andric 
701*700637cbSDimitry Andric   auto res = mlir::success();
702*700637cbSDimitry Andric   auto scopeLoc = getLoc(s.getSourceRange());
703*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
704*700637cbSDimitry Andric                                [&](mlir::OpBuilder &b, mlir::Location loc) {
705*700637cbSDimitry Andric                                  LexicalScope lexScope{
706*700637cbSDimitry Andric                                      *this, loc, builder.getInsertionBlock()};
707*700637cbSDimitry Andric                                  res = forStmtBuilder();
708*700637cbSDimitry Andric                                });
709*700637cbSDimitry Andric 
710*700637cbSDimitry Andric   if (res.failed())
711*700637cbSDimitry Andric     return res;
712*700637cbSDimitry Andric 
713*700637cbSDimitry Andric   terminateBody(builder, forOp.getBody(), getLoc(s.getEndLoc()));
714*700637cbSDimitry Andric   return mlir::success();
715*700637cbSDimitry Andric }
716*700637cbSDimitry Andric 
emitDoStmt(const DoStmt & s)717*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitDoStmt(const DoStmt &s) {
718*700637cbSDimitry Andric   cir::DoWhileOp doWhileOp;
719*700637cbSDimitry Andric 
720*700637cbSDimitry Andric   // TODO: pass in array of attributes.
721*700637cbSDimitry Andric   auto doStmtBuilder = [&]() -> mlir::LogicalResult {
722*700637cbSDimitry Andric     mlir::LogicalResult loopRes = mlir::success();
723*700637cbSDimitry Andric     assert(!cir::MissingFeatures::loopInfoStack());
724*700637cbSDimitry Andric     // From LLVM: if there are any cleanups between here and the loop-exit
725*700637cbSDimitry Andric     // scope, create a block to stage a loop exit along.
726*700637cbSDimitry Andric     // We probably already do the right thing because of ScopeOp, but make
727*700637cbSDimitry Andric     // sure we handle all cases.
728*700637cbSDimitry Andric     assert(!cir::MissingFeatures::requiresCleanups());
729*700637cbSDimitry Andric 
730*700637cbSDimitry Andric     doWhileOp = builder.createDoWhile(
731*700637cbSDimitry Andric         getLoc(s.getSourceRange()),
732*700637cbSDimitry Andric         /*condBuilder=*/
733*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
734*700637cbSDimitry Andric           assert(!cir::MissingFeatures::createProfileWeightsForLoop());
735*700637cbSDimitry Andric           assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
736*700637cbSDimitry Andric           // C99 6.8.5p2/p4: The first substatement is executed if the
737*700637cbSDimitry Andric           // expression compares unequal to 0. The condition must be a
738*700637cbSDimitry Andric           // scalar type.
739*700637cbSDimitry Andric           mlir::Value condVal = evaluateExprAsBool(s.getCond());
740*700637cbSDimitry Andric           builder.createCondition(condVal);
741*700637cbSDimitry Andric         },
742*700637cbSDimitry Andric         /*bodyBuilder=*/
743*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
744*700637cbSDimitry Andric           // The scope of the do-while loop body is a nested scope.
745*700637cbSDimitry Andric           if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
746*700637cbSDimitry Andric             loopRes = mlir::failure();
747*700637cbSDimitry Andric           emitStopPoint(&s);
748*700637cbSDimitry Andric         });
749*700637cbSDimitry Andric     return loopRes;
750*700637cbSDimitry Andric   };
751*700637cbSDimitry Andric 
752*700637cbSDimitry Andric   mlir::LogicalResult res = mlir::success();
753*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
754*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
755*700637cbSDimitry Andric                                [&](mlir::OpBuilder &b, mlir::Location loc) {
756*700637cbSDimitry Andric                                  LexicalScope lexScope{
757*700637cbSDimitry Andric                                      *this, loc, builder.getInsertionBlock()};
758*700637cbSDimitry Andric                                  res = doStmtBuilder();
759*700637cbSDimitry Andric                                });
760*700637cbSDimitry Andric 
761*700637cbSDimitry Andric   if (res.failed())
762*700637cbSDimitry Andric     return res;
763*700637cbSDimitry Andric 
764*700637cbSDimitry Andric   terminateBody(builder, doWhileOp.getBody(), getLoc(s.getEndLoc()));
765*700637cbSDimitry Andric   return mlir::success();
766*700637cbSDimitry Andric }
767*700637cbSDimitry Andric 
emitWhileStmt(const WhileStmt & s)768*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitWhileStmt(const WhileStmt &s) {
769*700637cbSDimitry Andric   cir::WhileOp whileOp;
770*700637cbSDimitry Andric 
771*700637cbSDimitry Andric   // TODO: pass in array of attributes.
772*700637cbSDimitry Andric   auto whileStmtBuilder = [&]() -> mlir::LogicalResult {
773*700637cbSDimitry Andric     mlir::LogicalResult loopRes = mlir::success();
774*700637cbSDimitry Andric     assert(!cir::MissingFeatures::loopInfoStack());
775*700637cbSDimitry Andric     // From LLVM: if there are any cleanups between here and the loop-exit
776*700637cbSDimitry Andric     // scope, create a block to stage a loop exit along.
777*700637cbSDimitry Andric     // We probably already do the right thing because of ScopeOp, but make
778*700637cbSDimitry Andric     // sure we handle all cases.
779*700637cbSDimitry Andric     assert(!cir::MissingFeatures::requiresCleanups());
780*700637cbSDimitry Andric 
781*700637cbSDimitry Andric     whileOp = builder.createWhile(
782*700637cbSDimitry Andric         getLoc(s.getSourceRange()),
783*700637cbSDimitry Andric         /*condBuilder=*/
784*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
785*700637cbSDimitry Andric           assert(!cir::MissingFeatures::createProfileWeightsForLoop());
786*700637cbSDimitry Andric           assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
787*700637cbSDimitry Andric           mlir::Value condVal;
788*700637cbSDimitry Andric           // If the for statement has a condition scope,
789*700637cbSDimitry Andric           // emit the local variable declaration.
790*700637cbSDimitry Andric           if (s.getConditionVariable())
791*700637cbSDimitry Andric             emitDecl(*s.getConditionVariable());
792*700637cbSDimitry Andric           // C99 6.8.5p2/p4: The first substatement is executed if the
793*700637cbSDimitry Andric           // expression compares unequal to 0. The condition must be a
794*700637cbSDimitry Andric           // scalar type.
795*700637cbSDimitry Andric           condVal = evaluateExprAsBool(s.getCond());
796*700637cbSDimitry Andric           builder.createCondition(condVal);
797*700637cbSDimitry Andric         },
798*700637cbSDimitry Andric         /*bodyBuilder=*/
799*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc) {
800*700637cbSDimitry Andric           // The scope of the while loop body is a nested scope.
801*700637cbSDimitry Andric           if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
802*700637cbSDimitry Andric             loopRes = mlir::failure();
803*700637cbSDimitry Andric           emitStopPoint(&s);
804*700637cbSDimitry Andric         });
805*700637cbSDimitry Andric     return loopRes;
806*700637cbSDimitry Andric   };
807*700637cbSDimitry Andric 
808*700637cbSDimitry Andric   mlir::LogicalResult res = mlir::success();
809*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
810*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
811*700637cbSDimitry Andric                                [&](mlir::OpBuilder &b, mlir::Location loc) {
812*700637cbSDimitry Andric                                  LexicalScope lexScope{
813*700637cbSDimitry Andric                                      *this, loc, builder.getInsertionBlock()};
814*700637cbSDimitry Andric                                  res = whileStmtBuilder();
815*700637cbSDimitry Andric                                });
816*700637cbSDimitry Andric 
817*700637cbSDimitry Andric   if (res.failed())
818*700637cbSDimitry Andric     return res;
819*700637cbSDimitry Andric 
820*700637cbSDimitry Andric   terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));
821*700637cbSDimitry Andric   return mlir::success();
822*700637cbSDimitry Andric }
823*700637cbSDimitry Andric 
emitSwitchBody(const Stmt * s)824*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
825*700637cbSDimitry Andric   // It is rare but legal if the switch body is not a compound stmt. e.g.,
826*700637cbSDimitry Andric   //
827*700637cbSDimitry Andric   //  switch(a)
828*700637cbSDimitry Andric   //    while(...) {
829*700637cbSDimitry Andric   //      case1
830*700637cbSDimitry Andric   //      ...
831*700637cbSDimitry Andric   //      case2
832*700637cbSDimitry Andric   //      ...
833*700637cbSDimitry Andric   //    }
834*700637cbSDimitry Andric   if (!isa<CompoundStmt>(s))
835*700637cbSDimitry Andric     return emitStmt(s, /*useCurrentScope=*/true);
836*700637cbSDimitry Andric 
837*700637cbSDimitry Andric   auto *compoundStmt = cast<CompoundStmt>(s);
838*700637cbSDimitry Andric 
839*700637cbSDimitry Andric   mlir::Block *swtichBlock = builder.getBlock();
840*700637cbSDimitry Andric   for (auto *c : compoundStmt->body()) {
841*700637cbSDimitry Andric     if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
842*700637cbSDimitry Andric       builder.setInsertionPointToEnd(swtichBlock);
843*700637cbSDimitry Andric       // Reset insert point automatically, so that we can attach following
844*700637cbSDimitry Andric       // random stmt to the region of previous built case op to try to make
845*700637cbSDimitry Andric       // the being generated `cir.switch` to be in simple form.
846*700637cbSDimitry Andric       if (mlir::failed(
847*700637cbSDimitry Andric               emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
848*700637cbSDimitry Andric         return mlir::failure();
849*700637cbSDimitry Andric 
850*700637cbSDimitry Andric       continue;
851*700637cbSDimitry Andric     }
852*700637cbSDimitry Andric 
853*700637cbSDimitry Andric     // Otherwise, just build the statements in the nearest case region.
854*700637cbSDimitry Andric     if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
855*700637cbSDimitry Andric       return mlir::failure();
856*700637cbSDimitry Andric   }
857*700637cbSDimitry Andric 
858*700637cbSDimitry Andric   return mlir::success();
859*700637cbSDimitry Andric }
860*700637cbSDimitry Andric 
emitSwitchStmt(const clang::SwitchStmt & s)861*700637cbSDimitry Andric mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) {
862*700637cbSDimitry Andric   // TODO: LLVM codegen does some early optimization to fold the condition and
863*700637cbSDimitry Andric   // only emit live cases. CIR should use MLIR to achieve similar things,
864*700637cbSDimitry Andric   // nothing to be done here.
865*700637cbSDimitry Andric   // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
866*700637cbSDimitry Andric   assert(!cir::MissingFeatures::constantFoldSwitchStatement());
867*700637cbSDimitry Andric 
868*700637cbSDimitry Andric   SwitchOp swop;
869*700637cbSDimitry Andric   auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
870*700637cbSDimitry Andric     if (s.getInit())
871*700637cbSDimitry Andric       if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
872*700637cbSDimitry Andric         return mlir::failure();
873*700637cbSDimitry Andric 
874*700637cbSDimitry Andric     if (s.getConditionVariable())
875*700637cbSDimitry Andric       emitDecl(*s.getConditionVariable());
876*700637cbSDimitry Andric 
877*700637cbSDimitry Andric     mlir::Value condV = emitScalarExpr(s.getCond());
878*700637cbSDimitry Andric 
879*700637cbSDimitry Andric     // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
880*700637cbSDimitry Andric     assert(!cir::MissingFeatures::pgoUse());
881*700637cbSDimitry Andric     assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
882*700637cbSDimitry Andric     // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
883*700637cbSDimitry Andric     assert(!cir::MissingFeatures::insertBuiltinUnpredictable());
884*700637cbSDimitry Andric 
885*700637cbSDimitry Andric     mlir::LogicalResult res = mlir::success();
886*700637cbSDimitry Andric     swop = builder.create<SwitchOp>(
887*700637cbSDimitry Andric         getLoc(s.getBeginLoc()), condV,
888*700637cbSDimitry Andric         /*switchBuilder=*/
889*700637cbSDimitry Andric         [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
890*700637cbSDimitry Andric           curLexScope->setAsSwitch();
891*700637cbSDimitry Andric 
892*700637cbSDimitry Andric           condTypeStack.push_back(condV.getType());
893*700637cbSDimitry Andric 
894*700637cbSDimitry Andric           res = emitSwitchBody(s.getBody());
895*700637cbSDimitry Andric 
896*700637cbSDimitry Andric           condTypeStack.pop_back();
897*700637cbSDimitry Andric         });
898*700637cbSDimitry Andric 
899*700637cbSDimitry Andric     return res;
900*700637cbSDimitry Andric   };
901*700637cbSDimitry Andric 
902*700637cbSDimitry Andric   // The switch scope contains the full source range for SwitchStmt.
903*700637cbSDimitry Andric   mlir::Location scopeLoc = getLoc(s.getSourceRange());
904*700637cbSDimitry Andric   mlir::LogicalResult res = mlir::success();
905*700637cbSDimitry Andric   builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
906*700637cbSDimitry Andric                                [&](mlir::OpBuilder &b, mlir::Location loc) {
907*700637cbSDimitry Andric                                  LexicalScope lexScope{
908*700637cbSDimitry Andric                                      *this, loc, builder.getInsertionBlock()};
909*700637cbSDimitry Andric                                  res = switchStmtBuilder();
910*700637cbSDimitry Andric                                });
911*700637cbSDimitry Andric 
912*700637cbSDimitry Andric   llvm::SmallVector<CaseOp> cases;
913*700637cbSDimitry Andric   swop.collectCases(cases);
914*700637cbSDimitry Andric   for (auto caseOp : cases)
915*700637cbSDimitry Andric     terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());
916*700637cbSDimitry Andric   terminateBody(builder, swop.getBody(), swop.getLoc());
917*700637cbSDimitry Andric 
918*700637cbSDimitry Andric   return res;
919*700637cbSDimitry Andric }
920