@@ -148,6 +148,39 @@ static RetTy parseOptionalCIRKeyword(AsmParser &parser, EnumTy defaultValue) {
148
148
return static_cast <RetTy>(index);
149
149
}
150
150
151
+ // Check if a region's termination omission is valid and, if so, creates and
152
+ // inserts the omitted terminator into the region.
153
+ LogicalResult ensureRegionTerm (OpAsmParser &parser, Region ®ion,
154
+ SMLoc errLoc) {
155
+ Location eLoc = parser.getEncodedSourceLoc (parser.getCurrentLocation ());
156
+ OpBuilder builder (parser.getBuilder ().getContext ());
157
+
158
+ // Region is empty or properly terminated: nothing to do.
159
+ if (region.empty () || region.back ().hasTerminator ())
160
+ return success ();
161
+
162
+ // Check for invalid terminator omissions.
163
+ if (!region.hasOneBlock ())
164
+ return parser.emitError (errLoc,
165
+ " multi-block region must not omit terminator" );
166
+ if (region.back ().empty ())
167
+ return parser.emitError (errLoc, " empty region must not omit terminator" );
168
+
169
+ // Terminator was omited correctly: recreate it.
170
+ region.back ().push_back (builder.create <cir::YieldOp>(eLoc));
171
+ return success ();
172
+ }
173
+
174
+ // True if the region's terminator should be omitted.
175
+ bool omitRegionTerm (mlir::Region &r) {
176
+ const auto singleNonEmptyBlock = r.hasOneBlock () && !r.front ().empty ();
177
+ const auto yieldsNothing = [&r]() {
178
+ YieldOp y = dyn_cast<YieldOp>(r.back ().back ());
179
+ return y && y.isPlain () && y.getArgs ().empty ();
180
+ };
181
+ return singleNonEmptyBlock && yieldsNothing ();
182
+ }
183
+
151
184
// ===----------------------------------------------------------------------===//
152
185
// AllocaOp
153
186
// ===----------------------------------------------------------------------===//
@@ -413,53 +446,6 @@ mlir::LogicalResult ThrowOp::verify() {
413
446
// IfOp
414
447
// ===----------------------------------------------------------------------===//
415
448
416
- static LogicalResult checkBlockTerminator (OpAsmParser &parser,
417
- llvm::SMLoc parserLoc,
418
- std::optional<Location> l, Region *r,
419
- bool ensureTerm = true ) {
420
- mlir::Builder &builder = parser.getBuilder ();
421
- if (r->hasOneBlock ()) {
422
- if (ensureTerm) {
423
- ::mlir::impl::ensureRegionTerminator (
424
- *r, builder, *l, [](OpBuilder &builder, Location loc) {
425
- OperationState state (loc, YieldOp::getOperationName ());
426
- YieldOp::build (builder, state);
427
- return Operation::create (state);
428
- });
429
- } else {
430
- assert (r && " region must not be empty" );
431
- Block &block = r->back ();
432
- if (block.empty () || !block.back ().hasTrait <OpTrait::IsTerminator>()) {
433
- return parser.emitError (
434
- parser.getCurrentLocation (),
435
- " blocks are expected to be explicitly terminated" );
436
- }
437
- }
438
- return success ();
439
- }
440
-
441
- // Empty regions don't need any handling.
442
- auto &blocks = r->getBlocks ();
443
- if (blocks.empty ())
444
- return success ();
445
-
446
- // Test that at least one block has a yield/return/throw terminator. We can
447
- // probably make this a bit more strict.
448
- for (Block &block : blocks) {
449
- if (block.empty ())
450
- continue ;
451
- auto &op = block.back ();
452
- if (op.hasTrait <mlir::OpTrait::IsTerminator>() &&
453
- isa<YieldOp, ReturnOp, ThrowOp>(op)) {
454
- return success ();
455
- }
456
- }
457
-
458
- parser.emitError (parserLoc,
459
- " expected at least one block with cir.yield or cir.return" );
460
- return failure ();
461
- }
462
-
463
449
ParseResult cir::IfOp::parse (OpAsmParser &parser, OperationState &result) {
464
450
// Create the regions for 'then'.
465
451
result.regions .reserve (2 );
@@ -479,17 +465,15 @@ ParseResult cir::IfOp::parse(OpAsmParser &parser, OperationState &result) {
479
465
if (parser.parseRegion (*thenRegion, /* arguments=*/ {},
480
466
/* argTypes=*/ {}))
481
467
return failure ();
482
- if (checkBlockTerminator (parser, parseThenLoc, result.location , thenRegion)
483
- .failed ())
468
+ if (ensureRegionTerm (parser, *thenRegion, parseThenLoc).failed ())
484
469
return failure ();
485
470
486
471
// If we find an 'else' keyword, parse the 'else' region.
487
472
if (!parser.parseOptionalKeyword (" else" )) {
488
473
auto parseElseLoc = parser.getCurrentLocation ();
489
474
if (parser.parseRegion (*elseRegion, /* arguments=*/ {}, /* argTypes=*/ {}))
490
475
return failure ();
491
- if (checkBlockTerminator (parser, parseElseLoc, result.location , elseRegion)
492
- .failed ())
476
+ if (ensureRegionTerm (parser, *elseRegion, parseElseLoc).failed ())
493
477
return failure ();
494
478
}
495
479
@@ -499,36 +483,20 @@ ParseResult cir::IfOp::parse(OpAsmParser &parser, OperationState &result) {
499
483
return success ();
500
484
}
501
485
502
- bool shouldPrintTerm (mlir::Region &r) {
503
- if (!r.hasOneBlock ())
504
- return true ;
505
- auto *entryBlock = &r.front ();
506
- if (entryBlock->empty ())
507
- return false ;
508
- if (isa<ReturnOp>(entryBlock->back ()))
509
- return true ;
510
- if (isa<ThrowOp>(entryBlock->back ()))
511
- return true ;
512
- YieldOp y = dyn_cast<YieldOp>(entryBlock->back ());
513
- if (y && (!y.isPlain () || !y.getArgs ().empty ()))
514
- return true ;
515
- return false ;
516
- }
517
-
518
486
void cir::IfOp::print (OpAsmPrinter &p) {
519
487
p << " " << getCondition () << " " ;
520
488
auto &thenRegion = this ->getThenRegion ();
521
489
p.printRegion (thenRegion,
522
490
/* printEntryBlockArgs=*/ false ,
523
- /* printBlockTerminators=*/ shouldPrintTerm (thenRegion));
491
+ /* printBlockTerminators=*/ ! omitRegionTerm (thenRegion));
524
492
525
493
// Print the 'else' regions if it exists and has a block.
526
494
auto &elseRegion = this ->getElseRegion ();
527
495
if (!elseRegion.empty ()) {
528
496
p << " else " ;
529
497
p.printRegion (elseRegion,
530
498
/* printEntryBlockArgs=*/ false ,
531
- /* printBlockTerminators=*/ shouldPrintTerm (elseRegion));
499
+ /* printBlockTerminators=*/ ! omitRegionTerm (elseRegion));
532
500
}
533
501
534
502
p.printOptionalAttrDict (getOperation ()->getAttrs ());
@@ -611,7 +579,7 @@ ParseResult cir::ScopeOp::parse(OpAsmParser &parser, OperationState &result) {
611
579
if (parser.parseRegion (*scopeRegion, /* arguments=*/ {}, /* argTypes=*/ {}))
612
580
return failure ();
613
581
614
- if (checkBlockTerminator (parser, loc, result. location , scopeRegion ).failed ())
582
+ if (ensureRegionTerm (parser, *scopeRegion, loc ).failed ())
615
583
return failure ();
616
584
617
585
// Parse the optional attribute list.
@@ -625,7 +593,7 @@ void cir::ScopeOp::print(OpAsmPrinter &p) {
625
593
auto &scopeRegion = this ->getScopeRegion ();
626
594
p.printRegion (scopeRegion,
627
595
/* printEntryBlockArgs=*/ false ,
628
- /* printBlockTerminators=*/ shouldPrintTerm (scopeRegion));
596
+ /* printBlockTerminators=*/ ! omitRegionTerm (scopeRegion));
629
597
630
598
p.printOptionalAttrDict (getOperation ()->getAttrs ());
631
599
}
@@ -866,10 +834,10 @@ parseSwitchOp(OpAsmParser &parser,
866
834
" case region shall not be empty" );
867
835
}
868
836
869
- if (checkBlockTerminator (parser, parserLoc, std::nullopt, & currRegion,
870
- /* ensureTerm= */ false )
871
- . failed ())
872
- return failure ();
837
+ if (! currRegion. back (). hasTerminator ())
838
+ return parser. emitError (parserLoc,
839
+ " case regions must be explicitly terminated " );
840
+
873
841
return success ();
874
842
};
875
843
@@ -1134,10 +1102,10 @@ parseCatchOp(OpAsmParser &parser,
1134
1102
" catch region shall not be empty" );
1135
1103
}
1136
1104
1137
- if (checkBlockTerminator (parser, parserLoc, std::nullopt, & currRegion,
1138
- /* ensureTerm= */ false )
1139
- . failed ())
1140
- return failure ();
1105
+ if (! currRegion. back (). hasTerminator ())
1106
+ return parser. emitError (
1107
+ parserLoc, " blocks are expected to be explicitly terminated " );
1108
+
1141
1109
return success ();
1142
1110
};
1143
1111
@@ -1388,9 +1356,7 @@ static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser,
1388
1356
if (ctorRegion.back ().empty ())
1389
1357
return parser.emitError (parser.getCurrentLocation (),
1390
1358
" ctor region shall not be empty" );
1391
- if (checkBlockTerminator (parser, parseLoc,
1392
- ctorRegion.back ().back ().getLoc (), &ctorRegion)
1393
- .failed ())
1359
+ if (ensureRegionTerm (parser, ctorRegion, parseLoc).failed ())
1394
1360
return failure ();
1395
1361
} else {
1396
1362
// Parse constant with initializer, examples:
@@ -1417,9 +1383,7 @@ static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser,
1417
1383
if (dtorRegion.back ().empty ())
1418
1384
return parser.emitError (parser.getCurrentLocation (),
1419
1385
" dtor region shall not be empty" );
1420
- if (checkBlockTerminator (parser, parseLoc,
1421
- dtorRegion.back ().back ().getLoc (), &dtorRegion)
1422
- .failed ())
1386
+ if (ensureRegionTerm (parser, dtorRegion, parseLoc).failed ())
1423
1387
return failure ();
1424
1388
}
1425
1389
}
@@ -2445,10 +2409,10 @@ LogicalResult GetMemberOp::verify() {
2445
2409
// these still need to be patched.
2446
2410
// Also we bypass the typechecking for the fields of incomplete types.
2447
2411
bool shouldSkipMemberTypeMismatch =
2448
- recordTy.isClass () || isIncompleteType (recordTy.getMembers ()[getIndex ()]);
2412
+ recordTy.isClass () || isIncompleteType (recordTy.getMembers ()[getIndex ()]);
2449
2413
2450
- if (!shouldSkipMemberTypeMismatch
2451
- && recordTy.getMembers ()[getIndex ()] != getResultTy ().getPointee ())
2414
+ if (!shouldSkipMemberTypeMismatch &&
2415
+ recordTy.getMembers ()[getIndex ()] != getResultTy ().getPointee ())
2452
2416
return emitError () << " member type mismatch" ;
2453
2417
2454
2418
return mlir::success ();
0 commit comments