diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h index 004b9c92a414..481ea6166aba 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h @@ -32,6 +32,7 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/Interfaces/ASTAttrInterfaces.h" +#include "clang/CIR/Interfaces/CIRLoopOpInterface.h" #include "clang/CIR/Interfaces/CIROpInterfaces.h" namespace mlir { diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c0d23698d449..21774597c406 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -20,6 +20,7 @@ include "clang/CIR/Dialect/IR/CIRAttrs.td" include "clang/CIR/Interfaces/ASTAttrInterfaces.td" include "clang/CIR/Interfaces/CIROpInterfaces.td" +include "clang/CIR/Interfaces/CIRLoopOpInterface.td" include "mlir/Interfaces/ControlFlowInterfaces.td" include "mlir/Interfaces/FunctionInterfaces.td" @@ -1172,7 +1173,8 @@ def LoopOpKind : I32EnumAttr< } def LoopOp : CIR_Op<"loop", - [DeclareOpInterfaceMethods, + [LoopOpInterface, + DeclareOpInterfaceMethods, DeclareOpInterfaceMethods, RecursivelySpeculatable, NoRegionArguments]> { let summary = "Loop"; @@ -1236,6 +1238,25 @@ def LoopOp : CIR_Op<"loop", ]; let hasVerifier = 1; + + let extraClassDeclaration = [{ + Region *maybeGetStep() { + if (getKind() == LoopOpKind::For) + return &getStep(); + return nullptr; + } + + llvm::SmallVector getRegionsInExecutionOrder() { + switch(getKind()) { + case LoopOpKind::For: + return llvm::SmallVector{&getCond(), &getBody(), &getStep()}; + case LoopOpKind::While: + return llvm::SmallVector{&getCond(), &getBody()}; + case LoopOpKind::DoWhile: + return llvm::SmallVector{&getBody(), &getCond()}; + } + } + }]; } //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.h b/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.h new file mode 100644 index 000000000000..2e8a0c8e8a94 --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.h @@ -0,0 +1,36 @@ +//===- CIRLoopOpInterface.h - Interface for CIR loop-like ops --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR loop operations. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_INTERFACES_CIR_CIRLOOPOPINTERFACE_H_ +#define CLANG_INTERFACES_CIR_CIRLOOPOPINTERFACE_H_ + +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/OpDefinition.h" +#include "mlir/IR/Operation.h" +#include "mlir/Interfaces/ControlFlowInterfaces.h" +#include "mlir/Interfaces/LoopLikeInterface.h" + +namespace mlir { +namespace cir { +namespace detail { + +/// Verify invariants of the LoopOpInterface. +::mlir::LogicalResult verifyLoopOpInterface(::mlir::Operation *op); + +} // namespace detail +} // namespace cir +} // namespace mlir + +/// Include the tablegen'd interface declarations. +#include "clang/CIR/Interfaces/CIRLoopOpInterface.h.inc" + +#endif // CLANG_INTERFACES_CIR_CIRLOOPOPINTERFACE_H_ diff --git a/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.td b/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.td new file mode 100644 index 000000000000..c2b871785ffd --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRLoopOpInterface.td @@ -0,0 +1,100 @@ +//===- CIRLoopOpInterface.td - Interface for CIR loop-like ops -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef CLANG_CIR_INTERFACES_CIRLOOPOPINTERFACE +#define CLANG_CIR_INTERFACES_CIRLOOPOPINTERFACE + +include "mlir/IR/OpBase.td" +include "mlir/Interfaces/ControlFlowInterfaces.td" +include "mlir/Interfaces/LoopLikeInterface.td" + +def LoopOpInterface : OpInterface<"LoopOpInterface", [ + DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods +]> { + let description = [{ + Contains helper functions to query properties and perform transformations + on a loop. + }]; + let cppNamespace = "::mlir::cir"; + + let methods = [ + InterfaceMethod<[{ + Returns the loop's conditional region. + }], + /*retTy=*/"mlir::Region &", + /*methodName=*/"getCond" + >, + InterfaceMethod<[{ + Returns the loop's body region. + }], + /*retTy=*/"mlir::Region &", + /*methodName=*/"getBody" + >, + InterfaceMethod<[{ + Returns a pointer to the loop's step region or nullptr. + }], + /*retTy=*/"mlir::Region *", + /*methodName=*/"maybeGetStep", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/"return nullptr;" + >, + InterfaceMethod<[{ + Returns the first region to be executed in the loop. + }], + /*retTy=*/"mlir::Region &", + /*methodName=*/"getEntry", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/"return $_op.getCond();" + >, + InterfaceMethod<[{ + Returns a list of regions in order of execution. + }], + /*retTy=*/"llvm::SmallVector", + /*methodName=*/"getRegionsInExecutionOrder", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return llvm::SmallVector{&$_op.getRegion(0), &$_op.getRegion(1)}; + }] + >, + InterfaceMethod<[{ + Recursively walks the body of the loop in pre-order while skipping + nested loops and executing a callback on every other operation. + }], + /*retTy=*/"mlir::WalkResult", + /*methodName=*/"walkBodySkippingNestedLoops", + /*args=*/(ins "::llvm::function_ref":$callback), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return $_op.getBody().template walk([&](Operation *op) { + if (isa(op)) + return mlir::WalkResult::skip(); + callback(op); + return mlir::WalkResult::advance(); + }); + }] + > + ]; + + let extraClassDeclaration = [{ + /// Generic method to retrieve the successors of a LoopOpInterface operation. + static void getLoopOpSuccessorRegions( + ::mlir::cir::LoopOpInterface op, ::mlir::RegionBranchPoint point, + ::mlir::SmallVectorImpl<::mlir::RegionSuccessor> ®ions); + }]; + + let verify = [{ + /// Verify invariants of the LoopOpInterface. + return detail::verifyLoopOpInterface($_op); + }]; +} + +#endif // CLANG_CIR_INTERFACES_CIRLOOPOPINTERFACE diff --git a/clang/include/clang/CIR/Interfaces/CMakeLists.txt b/clang/include/clang/CIR/Interfaces/CMakeLists.txt index fe835cade35c..c7132abca833 100644 --- a/clang/include/clang/CIR/Interfaces/CMakeLists.txt +++ b/clang/include/clang/CIR/Interfaces/CMakeLists.txt @@ -22,3 +22,4 @@ endfunction() add_clang_mlir_attr_interface(ASTAttrInterfaces) add_clang_mlir_op_interface(CIROpInterfaces) +add_clang_mlir_op_interface(CIRLoopOpInterface) diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 4c11e3eb8368..1f9d0c6d1c0b 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -43,6 +43,7 @@ add_clang_library(clangCIR MLIRCIROpsIncGen MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen ${dialect_libs} LINK_LIBS diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 4bec3353ff91..bf04b61b5721 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -14,6 +14,7 @@ #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/Interfaces/CIRLoopOpInterface.h" #include "llvm/Support/ErrorHandling.h" #include @@ -232,7 +233,7 @@ void AllocaOp::build(::mlir::OpBuilder &odsBuilder, //===----------------------------------------------------------------------===// LogicalResult BreakOp::verify() { - if (!getOperation()->getParentOfType() && + if (!getOperation()->getParentOfType() && !getOperation()->getParentOfType()) return emitOpError("must be within a loop or switch"); return success(); @@ -251,7 +252,7 @@ void ConditionOp::getSuccessorRegions( // down its list of possible successors. // Parent is a loop: condition may branch to the body or to the parent op. - if (auto loopOp = dyn_cast(getOperation()->getParentOp())) { + if (auto loopOp = dyn_cast(getOperation()->getParentOp())) { regions.emplace_back(&loopOp.getBody(), loopOp.getBody().getArguments()); regions.emplace_back(loopOp->getResults()); } @@ -269,7 +270,7 @@ ConditionOp::getMutableSuccessorOperands(RegionBranchPoint point) { } LogicalResult ConditionOp::verify() { - if (!isa(getOperation()->getParentOp())) + if (!isa(getOperation()->getParentOp())) return emitOpError("condition must be within a conditional region"); return success(); } @@ -365,7 +366,7 @@ OpFoldResult ConstantOp::fold(FoldAdaptor /*adaptor*/) { return getValue(); } //===----------------------------------------------------------------------===// LogicalResult ContinueOp::verify() { - if (!this->getOperation()->getParentOfType()) + if (!this->getOperation()->getParentOfType()) return emitOpError("must be within a loop"); return success(); } @@ -1264,38 +1265,14 @@ void LoopOp::build(OpBuilder &builder, OperationState &result, stepBuilder(builder, result.location); } -/// Given the region at `index`, or the parent operation if `index` is None, -/// return the successor regions. These are the regions that may be selected -/// during the flow of control. `operands` is a set of optional attributes -/// that correspond to a constant value for each operand, or null if that -/// operand is not a constant. void LoopOp::getSuccessorRegions(mlir::RegionBranchPoint point, SmallVectorImpl ®ions) { - // If any index all the underlying regions branch back to the parent - // operation. - if (!point.isParent()) { - regions.push_back(RegionSuccessor()); - return; - } - - // FIXME: we want to look at cond region for getting more accurate results - // if the other regions will get a chance to execute. - regions.push_back(RegionSuccessor(&this->getCond())); - regions.push_back(RegionSuccessor(&this->getBody())); - regions.push_back(RegionSuccessor(&this->getStep())); + LoopOpInterface::getLoopOpSuccessorRegions(*this, point, regions); } llvm::SmallVector LoopOp::getLoopRegions() { return {&getBody()}; } -LogicalResult LoopOp::verify() { - if (getCond().empty()) - return emitOpError() << "cond region must not be empty"; - - if (!llvm::isa(getCond().back().getTerminator())) - return emitOpError() << "cond region terminate with 'cir.condition'"; - - return success(); -} +LogicalResult LoopOp::verify() { return success(); } //===----------------------------------------------------------------------===// // GlobalOp diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index b8cc5b84e93e..f4609c3aad32 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(MLIRCIR MLIRSymbolInterfacesIncGen MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen LINK_LIBS PUBLIC MLIRIR diff --git a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp index 551024854077..ea324bd090b2 100644 --- a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp @@ -16,6 +16,7 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/Passes.h" +#include "clang/CIR/Interfaces/CIRLoopOpInterface.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SmallSet.h" @@ -674,27 +675,10 @@ void LifetimeCheckPass::checkLoop(LoopOp loopOp) { SmallVector regionsToCheck; auto setupLoopRegionsToCheck = [&](bool isSubsequentTaken = false) { - regionsToCheck.clear(); - switch (loopOp.getKind()) { - case LoopOpKind::For: { - regionsToCheck.push_back(&loopOp.getCond()); - regionsToCheck.push_back(&loopOp.getBody()); - if (!isSubsequentTaken) - regionsToCheck.push_back(&loopOp.getStep()); - break; - } - case LoopOpKind::While: { - regionsToCheck.push_back(&loopOp.getCond()); - regionsToCheck.push_back(&loopOp.getBody()); - break; - } - case LoopOpKind::DoWhile: { - // Note this is the reverse order from While above. - regionsToCheck.push_back(&loopOp.getBody()); - regionsToCheck.push_back(&loopOp.getCond()); - break; - } - } + regionsToCheck = loopOp.getRegionsInExecutionOrder(); + // Drop step if it exists and we are not checking the subsequent taken. + if (loopOp.maybeGetStep() && !isSubsequentTaken) + regionsToCheck.pop_back(); }; // From 2.4.9 "Note": diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt index 31ca49fedf44..077bd733cbd8 100644 --- a/clang/lib/CIR/FrontendAction/CMakeLists.txt +++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangCIRFrontendAction MLIRCIROpsIncGen MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen MLIRBuiltinLocationAttributesIncGen MLIRBuiltinTypeInterfacesIncGen MLIRFunctionInterfacesIncGen diff --git a/clang/lib/CIR/Interfaces/CIRLoopOpInterface.cpp b/clang/lib/CIR/Interfaces/CIRLoopOpInterface.cpp new file mode 100644 index 000000000000..ae5947a56944 --- /dev/null +++ b/clang/lib/CIR/Interfaces/CIRLoopOpInterface.cpp @@ -0,0 +1,54 @@ +//===- CIRLoopOpInterface.cpp - Interface for CIR loop-like ops *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#include "clang/CIR/Interfaces/CIRLoopOpInterface.h" + +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Interfaces/CIRLoopOpInterface.cpp.inc" +#include "llvm/Support/ErrorHandling.h" + +namespace mlir { +namespace cir { + +void LoopOpInterface::getLoopOpSuccessorRegions( + LoopOpInterface op, RegionBranchPoint point, + SmallVectorImpl ®ions) { + assert(point.isParent() || point.getRegionOrNull()); + + // Branching to first region: go to condition or body (do-while). + if (point.isParent()) { + regions.emplace_back(&op.getEntry(), op.getEntry().getArguments()); + } + // Branching from condition: go to body or exit. + else if (&op.getCond() == point.getRegionOrNull()) { + regions.emplace_back(RegionSuccessor(op->getResults())); + regions.emplace_back(&op.getBody(), op.getBody().getArguments()); + } + // Branching from body: go to step (for) or condition. + else if (&op.getBody() == point.getRegionOrNull()) { + // FIXME(cir): Should we consider break/continue statements here? + auto *afterBody = (op.maybeGetStep() ? op.maybeGetStep() : &op.getCond()); + regions.emplace_back(afterBody, afterBody->getArguments()); + } + // Branching from step: go to condition. + else if (op.maybeGetStep() == point.getRegionOrNull()) { + regions.emplace_back(&op.getCond(), op.getCond().getArguments()); + } +} + +/// Verify invariants of the LoopOpInterface. +LogicalResult detail::verifyLoopOpInterface(Operation *op) { + auto loopOp = cast(op); + if (!isa(loopOp.getCond().back().getTerminator())) + return op->emitOpError( + "expected condition region to terminate with 'cir.condition'"); + return success(); +} + +} // namespace cir +} // namespace mlir diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt index f672eb3f6a9c..84322f4836e0 100644 --- a/clang/lib/CIR/Interfaces/CMakeLists.txt +++ b/clang/lib/CIR/Interfaces/CMakeLists.txt @@ -1,6 +1,7 @@ add_clang_library(MLIRCIRInterfaces ASTAttrInterfaces.cpp CIROpInterfaces.cpp + CIRLoopOpInterface.cpp ADDITIONAL_HEADER_DIRS ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces @@ -8,6 +9,7 @@ add_clang_library(MLIRCIRInterfaces DEPENDS MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen LINK_LIBS ${dialect_libs} diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt index eb6991852332..7cf80d0b0a0e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangCIRLoweringDirectToLLVM MLIRCIROpsIncGen MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen MLIRBuiltinLocationAttributesIncGen MLIRBuiltinTypeInterfacesIncGen MLIRFunctionInterfacesIncGen diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 1f75712c5728..f6ddc2553a9f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -448,14 +448,14 @@ class CIRLoopOpLowering : public mlir::OpConversionPattern { // Lower continue statements. mlir::Block &dest = (kind != LoopKind::For ? condFrontBlock : stepFrontBlock); - walkRegionSkipping( + walkRegionSkipping( loopOp.getBody(), [&](mlir::Operation *op) { if (isa(op)) lowerTerminator(op, &dest, rewriter); }); // Lower break statements. - walkRegionSkipping( + walkRegionSkipping( loopOp.getBody(), [&](mlir::Operation *op) { if (isa(op)) lowerTerminator(op, continueBlock, rewriter); @@ -1387,7 +1387,7 @@ class CIRSwitchOpLowering } // Handle break statements. - walkRegionSkipping( + walkRegionSkipping( region, [&](mlir::Operation *op) { if (isa(op)) lowerTerminator(op, exitBlock, rewriter); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt index b92ae800918f..e3f125aed84a 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangCIRLoweringThroughMLIR MLIRCIREnumsGen MLIRCIRASTAttrInterfacesIncGen MLIRCIROpInterfacesIncGen + MLIRCIRLoopOpInterfaceIncGen MLIRBuiltinLocationAttributesIncGen MLIRBuiltinTypeInterfacesIncGen MLIRFunctionInterfacesIncGen diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 00ecacdcacad..a8601342919a 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -306,7 +306,7 @@ cir.func @cast24(%p : !u32i) { #true = #cir.bool : !cir.bool cir.func @b0() { cir.scope { - cir.loop while(cond : { // expected-error {{cond region terminate with 'cir.condition'}} + cir.loop while(cond : { // expected-error {{expected condition region to terminate with 'cir.condition'}} cir.yield }, step : { cir.yield diff --git a/clang/test/CIR/Transforms/merge-cleanups.cir b/clang/test/CIR/Transforms/merge-cleanups.cir index 52ba8b7842d2..17880efeac2a 100644 --- a/clang/test/CIR/Transforms/merge-cleanups.cir +++ b/clang/test/CIR/Transforms/merge-cleanups.cir @@ -61,22 +61,6 @@ module { cir.return } - cir.func @l0() { - cir.scope { - cir.loop while(cond : { - %0 = cir.const(#true) : !cir.bool - cir.condition(%0) - }, step : { - cir.yield - }) { - cir.br ^bb1 - ^bb1: - cir.return - } - } - cir.return - } - // CHECK: cir.switch (%4 : !s32i) [ // CHECK-NEXT: case (equal, 0) { // CHECK-NEXT: %5 = cir.load %2 : cir.ptr , !s32i @@ -114,20 +98,6 @@ module { // CHECK-NEXT: } // CHECK-NEXT: ] -// CHECK: cir.func @l0 -// CHECK-NEXT: cir.scope { -// CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: %0 = cir.const(#true) : !cir.bool -// CHECK-NEXT: cir.condition(%0) -// CHECK-NEXT: }, step : { -// CHECK-NEXT: cir.yield -// CHECK-NEXT: }) { -// CHECK-NEXT: cir.return -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: cir.return -// CHECK-NEXT: } - // Should remove empty scopes. cir.func @removeEmptyScope() { cir.scope {