@@ -26,7 +26,11 @@ namespace clang::CIRGen {
26
26
27
27
CIRGenFunction::CIRGenFunction (CIRGenModule &cgm, CIRGenBuilderTy &builder,
28
28
bool suppressNewContext)
29
- : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {}
29
+ : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {
30
+ ehStack.setCGF (this );
31
+ currentCleanupStackDepth = 0 ;
32
+ assert (ehStack.getStackDepth () == 0 );
33
+ }
30
34
31
35
CIRGenFunction::~CIRGenFunction () {}
32
36
@@ -227,6 +231,14 @@ void CIRGenFunction::LexicalScope::cleanup() {
227
231
CIRGenBuilderTy &builder = cgf.builder ;
228
232
LexicalScope *localScope = cgf.curLexScope ;
229
233
234
+ auto applyCleanup = [&]() {
235
+ if (performCleanup) {
236
+ // ApplyDebugLocation
237
+ assert (!cir::MissingFeatures::generateDebugInfo ());
238
+ forceCleanup ();
239
+ }
240
+ };
241
+
230
242
if (returnBlock != nullptr ) {
231
243
// Write out the return block, which loads the value from `__retval` and
232
244
// issues the `cir.return`.
@@ -235,46 +247,93 @@ void CIRGenFunction::LexicalScope::cleanup() {
235
247
(void )emitReturn (*returnLoc);
236
248
}
237
249
238
- mlir::Block *curBlock = builder.getBlock ();
239
- if (isGlobalInit () && !curBlock)
240
- return ;
241
- if (curBlock->mightHaveTerminator () && curBlock->getTerminator ())
242
- return ;
243
-
244
- // Get rid of any empty block at the end of the scope.
245
- bool entryBlock = builder.getInsertionBlock ()->isEntryBlock ();
246
- if (!entryBlock && curBlock->empty ()) {
247
- curBlock->erase ();
248
- if (returnBlock != nullptr && returnBlock->getUses ().empty ())
249
- returnBlock->erase ();
250
- return ;
251
- }
252
-
253
- // Reached the end of the scope.
254
- {
250
+ auto insertCleanupAndLeave = [&](mlir::Block *insPt) {
255
251
mlir::OpBuilder::InsertionGuard guard (builder);
256
- builder.setInsertionPointToEnd (curBlock);
252
+ builder.setInsertionPointToEnd (insPt);
253
+
254
+ // If we still don't have a cleanup block, it means that `applyCleanup`
255
+ // below might be able to get us one.
256
+ mlir::Block *cleanupBlock = localScope->getCleanupBlock (builder);
257
+
258
+ // Leverage and defers to RunCleanupsScope's dtor and scope handling.
259
+ applyCleanup ();
260
+
261
+ // If we now have one after `applyCleanup`, hook it up properly.
262
+ if (!cleanupBlock && localScope->getCleanupBlock (builder)) {
263
+ cleanupBlock = localScope->getCleanupBlock (builder);
264
+ builder.create <cir::BrOp>(insPt->back ().getLoc (), cleanupBlock);
265
+ if (!cleanupBlock->mightHaveTerminator ()) {
266
+ mlir::OpBuilder::InsertionGuard guard (builder);
267
+ builder.setInsertionPointToEnd (cleanupBlock);
268
+ builder.create <cir::YieldOp>(localScope->endLoc );
269
+ }
270
+ }
257
271
258
272
if (localScope->depth == 0 ) {
259
273
// Reached the end of the function.
260
274
if (returnBlock != nullptr ) {
261
- if (returnBlock->getUses ().empty ())
275
+ if (returnBlock->getUses ().empty ()) {
262
276
returnBlock->erase ();
263
- else {
277
+ } else {
278
+ // Thread return block via cleanup block.
279
+ if (cleanupBlock) {
280
+ for (mlir::BlockOperand &blockUse : returnBlock->getUses ()) {
281
+ cir::BrOp brOp = mlir::cast<cir::BrOp>(blockUse.getOwner ());
282
+ brOp.setSuccessor (cleanupBlock);
283
+ }
284
+ }
285
+
264
286
builder.create <cir::BrOp>(*returnLoc, returnBlock);
265
287
return ;
266
288
}
267
289
}
268
290
emitImplicitReturn ();
269
291
return ;
270
292
}
271
- // Reached the end of a non-function scope. Some scopes, such as those
272
- // used with the ?: operator, can return a value.
273
- if (!localScope->isTernary () && !curBlock->mightHaveTerminator ()) {
293
+
294
+ // End of any local scope != function
295
+ // Ternary ops have to deal with matching arms for yielding types
296
+ // and do return a value, it must do its own cir.yield insertion.
297
+ if (!localScope->isTernary () && !insPt->mightHaveTerminator ()) {
274
298
!retVal ? builder.create <cir::YieldOp>(localScope->endLoc )
275
299
: builder.create <cir::YieldOp>(localScope->endLoc , retVal);
276
300
}
301
+ };
302
+
303
+ // If a cleanup block has been created at some point, branch to it
304
+ // and set the insertion point to continue at the cleanup block.
305
+ // Terminators are then inserted either in the cleanup block or
306
+ // inline in this current block.
307
+ mlir::Block *cleanupBlock = localScope->getCleanupBlock (builder);
308
+ if (cleanupBlock)
309
+ insertCleanupAndLeave (cleanupBlock);
310
+
311
+ // Now deal with any pending block wrap up like implicit end of
312
+ // scope.
313
+
314
+ mlir::Block *curBlock = builder.getBlock ();
315
+ if (isGlobalInit () && !curBlock)
316
+ return ;
317
+ if (curBlock->mightHaveTerminator () && curBlock->getTerminator ())
318
+ return ;
319
+
320
+ // Get rid of any empty block at the end of the scope.
321
+ bool entryBlock = builder.getInsertionBlock ()->isEntryBlock ();
322
+ if (!entryBlock && curBlock->empty ()) {
323
+ curBlock->erase ();
324
+ if (returnBlock != nullptr && returnBlock->getUses ().empty ())
325
+ returnBlock->erase ();
326
+ return ;
277
327
}
328
+
329
+ // If there's a cleanup block, branch to it, nothing else to do.
330
+ if (cleanupBlock) {
331
+ builder.create <cir::BrOp>(curBlock->back ().getLoc (), cleanupBlock);
332
+ return ;
333
+ }
334
+
335
+ // No pre-existent cleanup block, emit cleanup code and yield/return.
336
+ insertCleanupAndLeave (curBlock);
278
337
}
279
338
280
339
cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn (mlir::Location loc) {
@@ -408,7 +467,19 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
408
467
}
409
468
}
410
469
411
- void CIRGenFunction::finishFunction (SourceLocation endLoc) {}
470
+ void CIRGenFunction::finishFunction (SourceLocation endLoc) {
471
+ // Pop any cleanups that might have been associated with the
472
+ // parameters. Do this in whatever block we're currently in; it's
473
+ // important to do this before we enter the return block or return
474
+ // edges will be *really* confused.
475
+ // TODO(cir): Use prologueCleanupDepth here.
476
+ bool hasCleanups = ehStack.getStackDepth () != currentCleanupStackDepth;
477
+ if (hasCleanups) {
478
+ assert (!cir::MissingFeatures::generateDebugInfo ());
479
+ // FIXME(cir): should we clearInsertionPoint? breaks many testcases
480
+ popCleanupBlocks (currentCleanupStackDepth);
481
+ }
482
+ }
412
483
413
484
mlir::LogicalResult CIRGenFunction::emitFunctionBody (const clang::Stmt *body) {
414
485
auto result = mlir::LogicalResult::success ();
0 commit comments