From 58ccd204b7b9d72db9d11f7fc8b233b547daf521 Mon Sep 17 00:00:00 2001 From: Vinicius Couto Espindola <34522047+sitio-couto@users.noreply.github.com> Date: Tue, 9 Jan 2024 22:42:35 -0300 Subject: [PATCH] [CIR][IR] Implement loop's conditional operation (#391) Like SCF's `scf.condition`, the `cir.condition` simplifies codegen of loop conditions by removing the need of a contitional branch. It takes a single boolean operand which, if true, executes the body region, otherwise exits the loop. This also simplifies lowering and the dialect it self. A new constraint is now enforced on `cir.loops`: the condition region must terminate with a `cir.condition` operation. A few tests were removed as they became redundant, and others where simplified. The merge-cleanups pass no longer simplifies compile-time constant conditions, as the condition body terminator is no longer allowed to be terminated with a `cir.yield`. To circumvent this, a proper folder should be implemented to fold constant conditions, but this was left as future work. Co-authored-by: Bruno Cardoso Lopes --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 19 + clang/lib/CIR/CodeGen/CIRGenBuilder.h | 5 + clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 32 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 47 ++- .../CIR/Dialect/Transforms/MergeCleanups.cpp | 45 --- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 43 +-- clang/test/CIR/CodeGen/loop.cpp | 58 +-- clang/test/CIR/CodeGen/rangefor.cpp | 6 +- clang/test/CIR/IR/branch.cir | 69 +--- clang/test/CIR/IR/invalid.cir | 9 +- clang/test/CIR/IR/loop.cir | 48 +-- clang/test/CIR/Lowering/dot.cir | 26 +- clang/test/CIR/Lowering/loop.cir | 332 +++++------------- clang/test/CIR/Lowering/loops-with-break.cir | 60 +--- .../test/CIR/Lowering/loops-with-continue.cir | 60 +--- clang/test/CIR/Transforms/merge-cleanups.cir | 42 +-- 16 files changed, 230 insertions(+), 671 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index fed38ccc1930..53682e28c20f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -582,6 +582,25 @@ def TernaryOp : CIR_Op<"ternary", }]; } +//===----------------------------------------------------------------------===// +// ConditionOp +//===----------------------------------------------------------------------===// + +def ConditionOp : CIR_Op<"condition", [ + Terminator, + DeclareOpInterfaceMethods +]> { + let summary = "Loop continuation condition."; + let description = [{ + The `cir.condition` termintes loop's conditional regions. It takes a single + `cir.bool` operand. if the operand is true, the loop continues, otherwise + it terminates. + }]; + let arguments = (ins CIR_BoolType:$condition); + let assemblyFormat = " `(` $condition `)` attr-dict "; +} + //===----------------------------------------------------------------------===// // YieldOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 49a0fa276832..26d81622f54c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -578,6 +578,11 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { return create(dst.getLoc(), dst, src); } + /// Create a loop condition. + mlir::cir::ConditionOp createCondition(mlir::Value condition) { + return create(condition.getLoc(), condition); + } + mlir::cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst, mlir::Value src, mlir::Value len) { return create(loc, dst, src, len); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 233a1b216283..cedcdac48621 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -652,26 +652,6 @@ CIRGenFunction::buildDefaultStmt(const DefaultStmt &S, mlir::Type condType, return buildCaseDefaultCascade(&S, condType, caseAttrs, os); } -static mlir::LogicalResult buildLoopCondYield(mlir::OpBuilder &builder, - mlir::Location loc, - mlir::Value cond) { - mlir::Block *trueBB = nullptr, *falseBB = nullptr; - { - mlir::OpBuilder::InsertionGuard guard(builder); - trueBB = builder.createBlock(builder.getBlock()->getParent()); - builder.create(loc, YieldOpKind::Continue); - } - { - mlir::OpBuilder::InsertionGuard guard(builder); - falseBB = builder.createBlock(builder.getBlock()->getParent()); - builder.create(loc); - } - - assert((trueBB && falseBB) && "expected both blocks to exist"); - builder.create(loc, cond, trueBB, falseBB); - return mlir::success(); -} - mlir::LogicalResult CIRGenFunction::buildCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef ForAttrs) { @@ -705,8 +685,7 @@ CIRGenFunction::buildCXXForRangeStmt(const CXXForRangeStmt &S, assert(!UnimplementedFeature::createProfileWeightsForLoop()); assert(!UnimplementedFeature::emitCondLikelihoodViaExpectIntrinsic()); mlir::Value condVal = evaluateExprAsBool(S.getCond()); - if (buildLoopCondYield(b, loc, condVal).failed()) - loopRes = mlir::failure(); + builder.createCondition(condVal); }, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { @@ -788,8 +767,7 @@ mlir::LogicalResult CIRGenFunction::buildForStmt(const ForStmt &S) { loc, boolTy, mlir::cir::BoolAttr::get(b.getContext(), boolTy, true)); } - if (buildLoopCondYield(b, loc, condVal).failed()) - loopRes = mlir::failure(); + builder.createCondition(condVal); }, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { @@ -852,8 +830,7 @@ mlir::LogicalResult CIRGenFunction::buildDoStmt(const DoStmt &S) { // expression compares unequal to 0. The condition must be a // scalar type. mlir::Value condVal = evaluateExprAsBool(S.getCond()); - if (buildLoopCondYield(b, loc, condVal).failed()) - loopRes = mlir::failure(); + builder.createCondition(condVal); }, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { @@ -912,8 +889,7 @@ mlir::LogicalResult CIRGenFunction::buildWhileStmt(const WhileStmt &S) { // expression compares unequal to 0. The condition must be a // scalar type. condVal = evaluateExprAsBool(S.getCond()); - if (buildLoopCondYield(b, loc, condVal).failed()) - loopRes = mlir::failure(); + builder.createCondition(condVal); }, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index cab294012cd7..0a6e10812b0c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -225,6 +225,30 @@ void AllocaOp::build(::mlir::OpBuilder &odsBuilder, odsState.addTypes(addr); } +//===----------------------------------------------------------------------===// +// ConditionOp +//===-----------------------------------------------------------------------===// + +//===---------------------------------- +// BranchOpTerminatorInterface Methods + +void ConditionOp::getSuccessorRegions( + ArrayRef operands, SmallVectorImpl ®ions) { + auto loopOp = cast(getOperation()->getParentOp()); + + // TODO(cir): The condition value may be folded to a constant, narrowing + // down its list of possible successors. + // Condition may branch to the body or to the parent op. + regions.emplace_back(&loopOp.getBody(), loopOp.getBody().getArguments()); + regions.emplace_back(loopOp->getResults()); +} + +MutableOperandRange +ConditionOp::getMutableSuccessorOperands(RegionBranchPoint point) { + // No values are yielded to the successor region. + return MutableOperandRange(getOperation(), 0, 0); +} + //===----------------------------------------------------------------------===// // ConstantOp //===----------------------------------------------------------------------===// @@ -1303,26 +1327,11 @@ void LoopOp::getSuccessorRegions(mlir::RegionBranchPoint point, llvm::SmallVector LoopOp::getLoopRegions() { return {&getBody()}; } LogicalResult LoopOp::verify() { - // Cond regions should only terminate with plain 'cir.yield' or - // 'cir.yield continue'. - auto terminateError = [&]() { - return emitOpError() << "cond region must be terminated with " - "'cir.yield' or 'cir.yield continue'"; - }; + if (getCond().empty()) + return emitOpError() << "cond region must not be empty"; - auto &blocks = getCond().getBlocks(); - for (Block &block : blocks) { - if (block.empty()) - continue; - auto &op = block.back(); - if (isa(op)) - continue; - if (!isa(op)) - terminateError(); - auto y = cast(op); - if (!(y.isPlain() || y.isContinue())) - terminateError(); - } + if (!llvm::isa(getCond().back().getTerminator())) + return emitOpError() << "cond region terminate with 'cir.condition'"; return success(); } diff --git a/clang/lib/CIR/Dialect/Transforms/MergeCleanups.cpp b/clang/lib/CIR/Dialect/Transforms/MergeCleanups.cpp index 473b0e71ca96..e4848a21d0bd 100644 --- a/clang/lib/CIR/Dialect/Transforms/MergeCleanups.cpp +++ b/clang/lib/CIR/Dialect/Transforms/MergeCleanups.cpp @@ -54,50 +54,6 @@ struct RemoveRedudantBranches : public OpRewritePattern { } }; -/// Merges basic blocks of trivial conditional branches. This is useful when a -/// the condition of conditional branch is a constant and the destinations of -/// the conditional branch both have only one predecessor. -/// -/// From: -/// ^bb0: -/// %0 = cir.const(#true) : !cir.bool -/// cir.brcond %0 ^bb1, ^bb2 -/// ^bb1: // pred: ^bb0 -/// cir.yield continue -/// ^bb2: // pred: ^bb0 -/// cir.yield -/// -/// To: -/// ^bb0: -/// cir.yield continue -/// -struct MergeTrivialConditionalBranches : public OpRewritePattern { - using OpRewritePattern::OpRewritePattern; - - LogicalResult match(BrCondOp op) const final { - return success(isa(op.getCond().getDefiningOp()) && - op.getDestFalse()->hasOneUse() && - op.getDestTrue()->hasOneUse()); - } - - /// Replace conditional branch with unconditional branch. - void rewrite(BrCondOp op, PatternRewriter &rewriter) const final { - auto constOp = llvm::cast(op.getCond().getDefiningOp()); - bool cond = constOp.getValue().cast().getValue(); - auto *destTrue = op.getDestTrue(), *destFalse = op.getDestFalse(); - Block *block = op.getOperation()->getBlock(); - - rewriter.eraseOp(op); - if (cond) { - rewriter.mergeBlocks(destTrue, block); - rewriter.eraseBlock(destFalse); - } else { - rewriter.mergeBlocks(destFalse, block); - rewriter.eraseBlock(destTrue); - } - } -}; - struct RemoveEmptyScope : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; @@ -146,7 +102,6 @@ void populateMergeCleanupPatterns(RewritePatternSet &patterns) { // clang-format off patterns.add< RemoveRedudantBranches, - MergeTrivialConditionalBranches, RemoveEmptyScope, RemoveEmptySwitch >(patterns.getContext()); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 09f9170ca570..fb358bfad4b5 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -403,25 +403,14 @@ class CIRLoopOpLowering : public mlir::OpConversionPattern { using mlir::OpConversionPattern::OpConversionPattern; using LoopKind = mlir::cir::LoopOpKind; - mlir::LogicalResult - fetchCondRegionYields(mlir::Region &condRegion, - mlir::cir::YieldOp &yieldToBody, - mlir::cir::YieldOp &yieldToCont) const { - for (auto &bb : condRegion) { - if (auto yieldOp = dyn_cast(bb.getTerminator())) { - if (!yieldOp.getKind().has_value()) - yieldToCont = yieldOp; - else if (yieldOp.getKind() == mlir::cir::YieldOpKind::Continue) - yieldToBody = yieldOp; - else - return mlir::failure(); - } - } - - // Succeed only if both yields are found. - if (!yieldToBody) - return mlir::failure(); - return mlir::success(); + inline void + lowerConditionOp(mlir::cir::ConditionOp op, mlir::Block *body, + mlir::Block *exit, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPoint(op); + rewriter.replaceOpWithNewOp(op, op.getCondition(), + body, exit); } mlir::LogicalResult @@ -435,9 +424,6 @@ class CIRLoopOpLowering : public mlir::OpConversionPattern { // Fetch required info from the condition region. auto &condRegion = loopOp.getCond(); auto &condFrontBlock = condRegion.front(); - mlir::cir::YieldOp yieldToBody, yieldToCont; - if (fetchCondRegionYields(condRegion, yieldToBody, yieldToCont).failed()) - return loopOp.emitError("failed to fetch yields in cond region"); // Fetch required info from the body region. auto &bodyRegion = loopOp.getBody(); @@ -469,15 +455,10 @@ class CIRLoopOpLowering : public mlir::OpConversionPattern { auto &entry = (kind != LoopKind::DoWhile ? condFrontBlock : bodyFrontBlock); rewriter.create(loopOp.getLoc(), &entry); - // Set loop exit point to continue block. - if (yieldToCont) { - rewriter.setInsertionPoint(yieldToCont); - rewriter.replaceOpWithNewOp(yieldToCont, continueBlock); - } - - // Branch from condition to body. - rewriter.setInsertionPoint(yieldToBody); - rewriter.replaceOpWithNewOp(yieldToBody, &bodyFrontBlock); + // Branch from condition region to body or exit. + auto conditionOp = + cast(condFrontBlock.getTerminator()); + lowerConditionOp(conditionOp, &bodyFrontBlock, continueBlock, rewriter); // Branch from body to condition or to step on for-loop cases. rewriter.setInsertionPoint(bodyYield); diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp index 90831e31e898..3360692929f4 100644 --- a/clang/test/CIR/CodeGen/loop.cpp +++ b/clang/test/CIR/CodeGen/loop.cpp @@ -8,12 +8,8 @@ void l0() { // CHECK: cir.func @_Z2l0v // CHECK: cir.loop for(cond : { -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: }, step : { -// CHECK-NEXT: cir.yield -// CHECK-NEXT: }) { -// CHECK-NEXT: cir.yield -// CHECK-NEXT: } +// CHECK: %[[#TRUE:]] = cir.const(#true) : !cir.bool +// CHECK: cir.condition(%[[#TRUE]]) void l1() { int x = 0; @@ -27,11 +23,7 @@ void l1() { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !s32i // CHECK-NEXT: %5 = cir.const(#cir.int<10> : !s32i) : !s32i // CHECK-NEXT: %6 = cir.cmp(lt, %4, %5) : !s32i, !cir.bool -// CHECK-NEXT: cir.brcond %6 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%6) // CHECK-NEXT: }, step : { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !s32i // CHECK-NEXT: %5 = cir.const(#cir.int<1> : !s32i) : !s32i @@ -63,11 +55,7 @@ void l2(bool cond) { // CHECK: cir.scope { // CHECK-NEXT: cir.loop while(cond : { // CHECK-NEXT: %3 = cir.load %0 : cir.ptr , !cir.bool -// CHECK-NEXT: cir.brcond %3 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%3) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -80,7 +68,8 @@ void l2(bool cond) { // CHECK-NEXT: } // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield continue +// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool +// CHECK-NEXT: cir.condition(%[[#TRUE]]) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -95,11 +84,7 @@ void l2(bool cond) { // CHECK-NEXT: cir.loop while(cond : { // CHECK-NEXT: %3 = cir.const(#cir.int<1> : !s32i) : !s32i // CHECK-NEXT: %4 = cir.cast(int_to_bool, %3 : !s32i), !cir.bool -// CHECK-NEXT: cir.brcond %4 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%4) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -127,12 +112,8 @@ void l3(bool cond) { // CHECK: cir.func @_Z2l3b // CHECK: cir.scope { // CHECK-NEXT: cir.loop dowhile(cond : { -// CHECK-NEXT: %3 = cir.load %0 : cir.ptr , !cir.bool -// CHECK-NEXT: cir.brcond %3 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: %[[#TRUE:]] = cir.load %0 : cir.ptr , !cir.bool +// CHECK-NEXT: cir.condition(%[[#TRUE]]) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -145,7 +126,8 @@ void l3(bool cond) { // CHECK-NEXT: } // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop dowhile(cond : { -// CHECK-NEXT: cir.yield continue +// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool +// CHECK-NEXT: cir.condition(%[[#TRUE]]) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -160,11 +142,7 @@ void l3(bool cond) { // CHECK-NEXT: cir.loop dowhile(cond : { // CHECK-NEXT: %3 = cir.const(#cir.int<1> : !s32i) : !s32i // CHECK-NEXT: %4 = cir.cast(int_to_bool, %3 : !s32i), !cir.bool -// CHECK-NEXT: cir.brcond %4 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%4) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -188,7 +166,8 @@ void l4() { // CHECK: cir.func @_Z2l4v // CHECK: cir.loop while(cond : { -// CHECK-NEXT: cir.yield continue +// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool +// CHECK-NEXT: cir.condition(%[[#TRUE]]) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -215,11 +194,7 @@ void l5() { // CHECK-NEXT: cir.loop dowhile(cond : { // CHECK-NEXT: %0 = cir.const(#cir.int<0> : !s32i) : !s32i // CHECK-NEXT: %1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool -// CHECK-NEXT: cir.brcond %1 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%1) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -238,7 +213,8 @@ void l6() { // CHECK: cir.func @_Z2l6v() // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield continue +// CHECK-NEXT: %[[#TRUE:]] = cir.const(#true) : !cir.bool +// CHECK-NEXT: cir.condition(%[[#TRUE]]) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { diff --git a/clang/test/CIR/CodeGen/rangefor.cpp b/clang/test/CIR/CodeGen/rangefor.cpp index 19281fbcd447..0176f511353c 100644 --- a/clang/test/CIR/CodeGen/rangefor.cpp +++ b/clang/test/CIR/CodeGen/rangefor.cpp @@ -46,11 +46,7 @@ void init(unsigned numImages) { // CHECK: cir.store %11, %6 : ![[VEC_IT]], cir.ptr // CHECK: cir.loop for(cond : { // CHECK: %12 = cir.call @_ZNK17__vector_iteratorI6triplePS0_RS0_EneERKS3_(%5, %6) : (!cir.ptr, !cir.ptr) -> !cir.bool -// CHECK: cir.brcond %12 ^bb1, ^bb2 -// CHECK: ^bb1: // pred: ^bb0 -// CHECK: cir.yield continue -// CHECK: ^bb2: // pred: ^bb0 -// CHECK: cir.yield +// CHECK: cir.condition(%12) // CHECK: }, step : { // CHECK: %12 = cir.call @_ZN17__vector_iteratorI6triplePS0_RS0_EppEv(%5) : (!cir.ptr) -> !cir.ptr // CHECK: cir.yield diff --git a/clang/test/CIR/IR/branch.cir b/clang/test/CIR/IR/branch.cir index 6f75d9e25bd3..7f418908a94c 100644 --- a/clang/test/CIR/IR/branch.cir +++ b/clang/test/CIR/IR/branch.cir @@ -1,60 +1,21 @@ // RUN: cir-opt %s | FileCheck %s -#false = #cir.bool : !cir.bool -#true = #cir.bool : !cir.bool - -cir.func @b0() { - cir.scope { - cir.loop while(cond : { - %0 = cir.const(#true) : !cir.bool - cir.brcond %0 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield - }, step : { - cir.yield - }) { - cir.br ^bb1 - ^bb1: - cir.return - } - } +cir.func @test_branch_parsing(%arg0: !cir.bool) { + // CHECK: cir.br ^bb1 + cir.br ^bb1 +^bb1: + // CHECK: cir.br ^bb2(%arg0 : !cir.bool) + cir.br ^bb2(%arg0 : !cir.bool) +// CHECK: ^bb2(%0: !cir.bool): +^bb2(%x: !cir.bool): cir.return } -// CHECK: cir.func @b0 -// CHECK-NEXT: cir.scope { -// CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: %0 = cir.const(#true) : !cir.bool -// CHECK-NEXT: cir.brcond %0 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield -// CHECK-NEXT: }, step : { -// CHECK-NEXT: cir.yield -// CHECK-NEXT: }) { -// CHECK-NEXT: cir.br ^bb1 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.return -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: cir.return -// CHECK-NEXT: } - - -!s32i = !cir.int -cir.func @test_br() -> !s32i { - %0 = cir.const(#cir.int<0>: !s32i) : !s32i - cir.br ^bb1(%0 : !s32i) - ^bb1(%x: !s32i): - cir.return %x : !s32i +cir.func @test_conditional_branch_parsing(%arg0 : !cir.bool) { + // CHEK: cir.brcond %arg0 ^bb1, ^bb2 + cir.brcond %arg0 ^bb1, ^bb2 +^bb1: + cir.return +^bb2: + cir.return } - -// CHECK: cir.func @test_br() -> !s32i { -// CHECK-NEXT: %0 = cir.const(#cir.int<0> : !s32i) : !s32i -// CHECK-NEXT: cir.br ^bb1(%0 : !s32i) -// CHECK-NEXT: ^bb1(%1: !s32i): // pred: ^bb0 -// CHECK-NEXT: cir.return %1 : !s32i -// CHECK-NEXT: } diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 278909d59850..d353c7d7b878 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -318,13 +318,8 @@ cir.func @cast24(%p : !u32i) { #true = #cir.bool : !cir.bool cir.func @b0() { cir.scope { - cir.loop while(cond : { // expected-error {{cond region must be terminated with 'cir.yield' or 'cir.yield continue'}} - %0 = cir.const(#true) : !cir.bool - cir.brcond %0 ^bb1, ^bb2 - ^bb1: - cir.yield break - ^bb2: - cir.yield + cir.loop while(cond : { // expected-error {{cond region terminate with 'cir.condition'}} + cir.yield }, step : { cir.yield }) { diff --git a/clang/test/CIR/IR/loop.cir b/clang/test/CIR/IR/loop.cir index ac9658a304d3..798aaaeb5ae9 100644 --- a/clang/test/CIR/IR/loop.cir +++ b/clang/test/CIR/IR/loop.cir @@ -15,11 +15,7 @@ cir.func @l0() { %4 = cir.load %2 : cir.ptr , !u32i %5 = cir.const(#cir.int<10> : !u32i) : !u32i %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool - cir.brcond %6 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield + cir.condition(%6) }, step : { %4 = cir.load %2 : cir.ptr , !u32i %5 = cir.const(#cir.int<1> : !u32i) : !u32i @@ -46,11 +42,7 @@ cir.func @l0() { %4 = cir.load %2 : cir.ptr , !u32i %5 = cir.const(#cir.int<10> : !u32i) : !u32i %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool - cir.brcond %6 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield + cir.condition(%6) }, step : { cir.yield }) { @@ -74,11 +66,7 @@ cir.func @l0() { %4 = cir.load %2 : cir.ptr , !u32i %5 = cir.const(#cir.int<10> : !u32i) : !u32i %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool - cir.brcond %6 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield + cir.condition(%6) }, step : { cir.yield }) { @@ -97,11 +85,7 @@ cir.func @l0() { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !u32i // CHECK-NEXT: %5 = cir.const(#cir.int<10> : !u32i) : !u32i // CHECK-NEXT: %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool -// CHECK-NEXT: cir.brcond %6 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%6) // CHECK-NEXT: }, step : { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !u32i // CHECK-NEXT: %5 = cir.const(#cir.int<1> : !u32i) : !u32i @@ -124,11 +108,7 @@ cir.func @l0() { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !u32i // CHECK-NEXT: %5 = cir.const(#cir.int<10> : !u32i) : !u32i // CHECK-NEXT: %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool -// CHECK-NEXT: cir.brcond %6 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%6) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -147,11 +127,7 @@ cir.func @l0() { // CHECK-NEXT: %4 = cir.load %2 : cir.ptr , !u32i // CHECK-NEXT: %5 = cir.const(#cir.int<10> : !u32i) : !u32i // CHECK-NEXT: %6 = cir.cmp(lt, %4, %5) : !u32i, !cir.bool -// CHECK-NEXT: cir.brcond %6 ^bb1, ^bb2 -// CHECK-NEXT: ^bb1: -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: ^bb2: -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%6) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -162,10 +138,10 @@ cir.func @l0() { // CHECK-NEXT: cir.yield // CHECK-NEXT: } -cir.func @l1() { +cir.func @l1(%arg0 : !cir.bool) { cir.scope { cir.loop while(cond : { - cir.yield continue + cir.condition(%arg0) }, step : { cir.yield }) { @@ -178,7 +154,7 @@ cir.func @l1() { // CHECK: cir.func @l1 // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield continue +// CHECK-NEXT: cir.condition(%arg0) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { @@ -188,10 +164,10 @@ cir.func @l1() { // CHECK-NEXT: cir.return // CHECK-NEXT: } -cir.func @l2() { +cir.func @l2(%arg0 : !cir.bool) { cir.scope { cir.loop while(cond : { - cir.yield + cir.condition(%arg0) }, step : { cir.yield }) { @@ -204,7 +180,7 @@ cir.func @l2() { // CHECK: cir.func @l2 // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield +// CHECK-NEXT: cir.condition(%arg0) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) { diff --git a/clang/test/CIR/Lowering/dot.cir b/clang/test/CIR/Lowering/dot.cir index e889dcd05827..4f588e1f05f9 100644 --- a/clang/test/CIR/Lowering/dot.cir +++ b/clang/test/CIR/Lowering/dot.cir @@ -1,4 +1,4 @@ -// RUN: cir-opt %s -cir-to-llvm -o %t.mlir +// RUN: cir-opt %s -cir-to-llvm --reconcile-unrealized-casts -o %t.mlir // RUN: FileCheck --input-file=%t.mlir %s -check-prefix=MLIR !s32i = !cir.int @@ -23,11 +23,7 @@ module { %11 = cir.load %2 : cir.ptr , !s32i %12 = cir.cmp(lt, %10, %11) : !s32i, !s32i %13 = cir.cast(int_to_bool, %12 : !s32i), !cir.bool - cir.brcond %13 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%13) }, step : { %10 = cir.load %8 : cir.ptr , !s32i %11 = cir.unary(inc, %10) : !s32i, !s32i @@ -80,7 +76,7 @@ module { // MLIR-NEXT: %13 = llvm.mlir.constant(0 : i32) : i32 // MLIR-NEXT: llvm.store %13, %12 : i32, !llvm.ptr // MLIR-NEXT: llvm.br ^bb2 -// MLIR-NEXT: ^bb2: // 2 preds: ^bb1, ^bb6 +// MLIR-NEXT: ^bb2: // 2 preds: ^bb1, ^bb4 // MLIR-NEXT: %14 = llvm.load %12 : !llvm.ptr -> i32 // MLIR-NEXT: %15 = llvm.load %5 : !llvm.ptr -> i32 // MLIR-NEXT: %16 = llvm.icmp "slt" %14, %15 : i32 @@ -89,12 +85,8 @@ module { // MLIR-NEXT: %19 = llvm.icmp "ne" %17, %18 : i32 // MLIR-NEXT: %20 = llvm.zext %19 : i1 to i8 // MLIR-NEXT: %21 = llvm.trunc %20 : i8 to i1 -// MLIR-NEXT: llvm.cond_br %21, ^bb3, ^bb4 +// MLIR-NEXT: llvm.cond_br %21, ^bb3, ^bb5 // MLIR-NEXT: ^bb3: // pred: ^bb2 -// MLIR-NEXT: llvm.br ^bb5 -// MLIR-NEXT: ^bb4: // pred: ^bb2 -// MLIR-NEXT: llvm.br ^bb7 -// MLIR-NEXT: ^bb5: // pred: ^bb3 // MLIR-NEXT: %22 = llvm.load %1 : !llvm.ptr -> !llvm.ptr // MLIR-NEXT: %23 = llvm.load %12 : !llvm.ptr -> i32 // MLIR-NEXT: %24 = llvm.getelementptr %22[%23] : (!llvm.ptr, i32) -> !llvm.ptr, f64 @@ -107,16 +99,16 @@ module { // MLIR-NEXT: %31 = llvm.load %9 : !llvm.ptr -> f64 // MLIR-NEXT: %32 = llvm.fadd %31, %30 : f64 // MLIR-NEXT: llvm.store %32, %9 : f64, !llvm.ptr -// MLIR-NEXT: llvm.br ^bb6 -// MLIR-NEXT: ^bb6: // pred: ^bb5 +// MLIR-NEXT: llvm.br ^bb4 +// MLIR-NEXT: ^bb4: // pred: ^bb3 // MLIR-NEXT: %33 = llvm.load %12 : !llvm.ptr -> i32 // MLIR-NEXT: %34 = llvm.mlir.constant(1 : i32) : i32 // MLIR-NEXT: %35 = llvm.add %33, %34 : i32 // MLIR-NEXT: llvm.store %35, %12 : i32, !llvm.ptr // MLIR-NEXT: llvm.br ^bb2 -// MLIR-NEXT: ^bb7: // pred: ^bb4 -// MLIR-NEXT: llvm.br ^bb8 -// MLIR-NEXT: ^bb8: // pred: ^bb7 +// MLIR-NEXT: ^bb5: // pred: ^bb2 +// MLIR-NEXT: llvm.br ^bb6 +// MLIR-NEXT: ^bb6: // pred: ^bb5 // MLIR-NEXT: %36 = llvm.load %9 : !llvm.ptr -> f64 // MLIR-NEXT: llvm.store %36, %7 : f64, !llvm.ptr // MLIR-NEXT: %37 = llvm.load %7 : !llvm.ptr -> f64 diff --git a/clang/test/CIR/Lowering/loop.cir b/clang/test/CIR/Lowering/loop.cir index 685792a5b342..bbe42d179273 100644 --- a/clang/test/CIR/Lowering/loop.cir +++ b/clang/test/CIR/Lowering/loop.cir @@ -1,26 +1,15 @@ // RUN: cir-opt %s -cir-to-llvm -o %t.mlir -// RUN: FileCheck --input-file=%t.mlir %s -check-prefix=MLIR - +// RUN: FileCheck --input-file=%t.mlir %s +#true = #cir.bool : !cir.bool !s32i = !cir.int + + module { - cir.func @testFor() { - %0 = cir.alloca !s32i, cir.ptr , ["i", init] {alignment = 4 : i64} - %1 = cir.const(#cir.int<0> : !s32i) : !s32i - cir.store %1, %0 : !s32i, cir.ptr + + cir.func @testFor(%arg0 : !cir.bool) { cir.loop for(cond : { - %2 = cir.load %0 : cir.ptr , !s32i - %3 = cir.const(#cir.int<10> : !s32i) : !s32i - %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i - %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%arg0) }, step : { - %2 = cir.load %0 : cir.ptr , !s32i - %3 = cir.unary(inc, %2) : !s32i, !s32i - cir.store %3, %0 : !s32i, cir.ptr cir.yield }) { cir.yield @@ -28,271 +17,116 @@ module { cir.return } -// MLIR: module { -// MLIR-NEXT: llvm.func @testFor() -// MLIR-NEXT: %0 = llvm.mlir.constant(1 : index) : i64 -// MLIR-NEXT: %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i64) -> !llvm.ptr -// MLIR-NEXT: %2 = llvm.mlir.constant(0 : i32) : i32 -// MLIR-NEXT: llvm.store %2, %1 : i32, !llvm.ptr -// MLIR-NEXT: llvm.br ^bb1 -// ============= Condition block ============= -// MLIR-NEXT: ^bb1: // 2 preds: ^bb0, ^bb5 -// MLIR-NEXT: %3 = llvm.load %1 : !llvm.ptr -> i32 -// MLIR-NEXT: %4 = llvm.mlir.constant(10 : i32) : i32 -// MLIR-NEXT: %5 = llvm.icmp "slt" %3, %4 : i32 -// MLIR-NEXT: %6 = llvm.zext %5 : i1 to i32 -// MLIR-NEXT: %7 = llvm.mlir.constant(0 : i32) : i32 -// MLIR-NEXT: %8 = llvm.icmp "ne" %6, %7 : i32 -// MLIR-NEXT: %9 = llvm.zext %8 : i1 to i8 -// MLIR-NEXT: %10 = llvm.trunc %9 : i8 to i1 -// MLIR-NEXT: llvm.cond_br %10, ^bb2, ^bb3 -// MLIR-NEXT: ^bb2: // pred: ^bb1 -// MLIR-NEXT: llvm.br ^bb4 -// MLIR-NEXT: ^bb3: // pred: ^bb1 -// MLIR-NEXT: llvm.br ^bb6 -// ============= Body block ============= -// MLIR-NEXT: ^bb4: // pred: ^bb2 -// MLIR-NEXT: llvm.br ^bb5 -// ============= Step block ============= -// MLIR-NEXT: ^bb5: // pred: ^bb4 -// MLIR-NEXT: %11 = llvm.load %1 : !llvm.ptr -> i32 -// MLIR-NEXT: %12 = llvm.mlir.constant(1 : i32) : i32 -// MLIR-NEXT: %13 = llvm.add %11, %12 : i32 -// MLIR-NEXT: llvm.store %13, %1 : i32, !llvm.ptr -// MLIR-NEXT: llvm.br ^bb1 -// ============= Exit block ============= -// MLIR-NEXT: ^bb6: // pred: ^bb3 -// MLIR-NEXT: llvm.return -// MLIR-NEXT: } +// CHECK: @testFor +// CHECK: llvm.br ^bb[[#COND:]] +// CHECK: ^bb[[#COND]]: +// CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] +// CHECK: ^bb[[#BODY]]: +// CHECK: llvm.br ^bb[[#STEP:]] +// CHECK: ^bb[[#STEP]]: +// CHECK: llvm.br ^bb[[#COND]] +// CHECK: ^bb[[#EXIT]]: + + // Test while cir.loop operation lowering. - cir.func @testWhile(%arg0: !s32i) { - %0 = cir.alloca !s32i, cir.ptr , ["i", init] {alignment = 4 : i64} - cir.store %arg0, %0 : !s32i, cir.ptr - cir.scope { - cir.loop while(cond : { - %1 = cir.load %0 : cir.ptr , !s32i - %2 = cir.const(#cir.int<10> : !s32i) : !s32i - %3 = cir.cmp(lt, %1, %2) : !s32i, !s32i - %4 = cir.cast(int_to_bool, %3 : !s32i), !cir.bool - cir.brcond %4 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield - }, step : { - cir.yield - }) { - %1 = cir.load %0 : cir.ptr , !s32i - %2 = cir.unary(inc, %1) : !s32i, !s32i - cir.store %2, %0 : !s32i, cir.ptr - cir.yield - } + cir.func @testWhile(%arg0 : !cir.bool) { + cir.loop while(cond : { + cir.condition(%arg0) + }, step : { // Droped when lowering while statements. + cir.yield + }) { + cir.yield } cir.return } - // MLIR: llvm.func @testWhile(%arg0: i32) - // MLIR-NEXT: %0 = llvm.mlir.constant(1 : index) : i64 - // MLIR-NEXT: %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i64) -> !llvm.ptr - // MLIR-NEXT: llvm.store %arg0, %1 : i32, !llvm.ptr - // MLIR-NEXT: llvm.br ^bb1 - // MLIR-NEXT: ^bb1: - // MLIR-NEXT: llvm.br ^bb2 - // ============= Condition block ============= - // MLIR-NEXT: ^bb2: // 2 preds: ^bb1, ^bb5 - // MLIR-NEXT: %2 = llvm.load %1 : !llvm.ptr -> i32 - // MLIR-NEXT: %3 = llvm.mlir.constant(10 : i32) : i32 - // MLIR-NEXT: %4 = llvm.icmp "slt" %2, %3 : i32 - // MLIR-NEXT: %5 = llvm.zext %4 : i1 to i32 - // MLIR-NEXT: %6 = llvm.mlir.constant(0 : i32) : i32 - // MLIR-NEXT: %7 = llvm.icmp "ne" %5, %6 : i32 - // MLIR-NEXT: %8 = llvm.zext %7 : i1 to i8 - // MLIR-NEXT: %9 = llvm.trunc %8 : i8 to i1 - // MLIR-NEXT: llvm.cond_br %9, ^bb3, ^bb4 - // MLIR-NEXT: ^bb3: // pred: ^bb2 - // MLIR-NEXT: llvm.br ^bb5 - // MLIR-NEXT: ^bb4: // pred: ^bb2 - // MLIR-NEXT: llvm.br ^bb6 - // ============= Body block ============= - // MLIR-NEXT: ^bb5: // pred: ^bb3 - // MLIR-NEXT: %10 = llvm.load %1 : !llvm.ptr -> i32 - // MLIR-NEXT: %11 = llvm.mlir.constant(1 : i32) : i32 - // MLIR-NEXT: %12 = llvm.add %10, %11 : i32 - // MLIR-NEXT: llvm.store %12, %1 : i32, !llvm.ptr - // MLIR-NEXT: llvm.br ^bb2 - // ============= Exit block ============= - // MLIR-NEXT: ^bb6: // pred: ^bb4 - // MLIR-NEXT: llvm.br ^bb7 +// CHECK: @testWhile +// CHECK: llvm.br ^bb[[#COND:]] +// CHECK: ^bb[[#COND]]: +// CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] +// CHECK: ^bb[[#BODY]]: +// CHECK: llvm.br ^bb[[#COND]] +// CHECK: ^bb[[#EXIT]]: + + // Test do-while cir.loop operation lowering. - cir.func @testDoWhile(%arg0: !s32i) { - %0 = cir.alloca !s32i, cir.ptr , ["i", init] {alignment = 4 : i64} - cir.store %arg0, %0 : !s32i, cir.ptr - cir.scope { - cir.loop dowhile(cond : { - %1 = cir.load %0 : cir.ptr , !s32i - %2 = cir.const(#cir.int<10> : !s32i) : !s32i - %3 = cir.cmp(lt, %1, %2) : !s32i, !s32i - %4 = cir.cast(int_to_bool, %3 : !s32i), !cir.bool - cir.brcond %4 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield - }, step : { - cir.yield - }) { - %1 = cir.load %0 : cir.ptr , !s32i - %2 = cir.unary(inc, %1) : !s32i, !s32i - cir.store %2, %0 : !s32i, cir.ptr - cir.yield - } + cir.func @testDoWhile(%arg0 : !cir.bool) { + cir.loop dowhile(cond : { + cir.condition(%arg0) + }, step : { // Droped when lowering while statements. + cir.yield + }) { + cir.yield } cir.return } - // MLIR: llvm.func @testDoWhile(%arg0: i32) - // MLIR-NEXT: %0 = llvm.mlir.constant(1 : index) : i64 - // MLIR-NEXT: %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i64) -> !llvm.ptr - // MLIR-NEXT: llvm.store %arg0, %1 : i32, !llvm.ptr - // MLIR-NEXT: llvm.br ^bb1 - // MLIR-NEXT: ^bb1: - // MLIR-NEXT: llvm.br ^bb5 - // ============= Condition block ============= - // MLIR-NEXT: ^bb2: - // MLIR-NEXT: %2 = llvm.load %1 : !llvm.ptr -> i32 - // MLIR-NEXT: %3 = llvm.mlir.constant(10 : i32) : i32 - // MLIR-NEXT: %4 = llvm.icmp "slt" %2, %3 : i32 - // MLIR-NEXT: %5 = llvm.zext %4 : i1 to i32 - // MLIR-NEXT: %6 = llvm.mlir.constant(0 : i32) : i32 - // MLIR-NEXT: %7 = llvm.icmp "ne" %5, %6 : i32 - // MLIR-NEXT: %8 = llvm.zext %7 : i1 to i8 - // MLIR-NEXT: %9 = llvm.trunc %8 : i8 to i1 - // MLIR-NEXT: llvm.cond_br %9, ^bb3, ^bb4 - // MLIR-NEXT: ^bb3: - // MLIR-NEXT: llvm.br ^bb5 - // MLIR-NEXT: ^bb4: - // MLIR-NEXT: llvm.br ^bb6 - // ============= Body block ============= - // MLIR-NEXT: ^bb5: - // MLIR-NEXT: %10 = llvm.load %1 : !llvm.ptr -> i32 - // MLIR-NEXT: %11 = llvm.mlir.constant(1 : i32) : i32 - // MLIR-NEXT: %12 = llvm.add %10, %11 : i32 - // MLIR-NEXT: llvm.store %12, %1 : i32, !llvm.ptr - // MLIR-NEXT: llvm.br ^bb2 - // ============= Exit block ============= - // MLIR-NEXT: ^bb6: - // MLIR-NEXT: llvm.br ^bb7 +// CHECK: @testDoWhile +// CHECK: llvm.br ^bb[[#BODY:]] +// CHECK: ^bb[[#COND:]]: +// CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] +// CHECK: ^bb[[#BODY]]: +// CHECK: llvm.br ^bb[[#COND]] +// CHECK: ^bb[[#EXIT]]: - // Test endless cir.loop lowering. - cir.func @testEndless() { - cir.scope { - cir.loop for(cond : { - cir.yield continue - }, step : { - cir.yield - }) { - cir.yield - } - } - cir.return - } - // MLIR: llvm.func @testEndless() - // MLIR-NEXT: llvm.br ^bb1 - // MLIR-NEXT: ^bb1: - // MLIR-NEXT: llvm.br ^bb2 - // ============= Condition block ============= - // MLIR-NEXT: ^bb2: - // MLIR-NEXT: llvm.br ^bb3 - // ============= Body block ============= - // MLIR-NEXT: ^bb3: - // MLIR-NEXT: llvm.br ^bb4 - // ============= Step block ============= - // MLIR-NEXT: ^bb4: - // MLIR-NEXT: llvm.br ^bb2 - // ============= Exit block ============= - // MLIR-NEXT: ^bb5: - // MLIR-NEXT: llvm.br ^bb6 - // MLIR-NEXT: ^bb6: - // MLIR-NEXT: llvm.return // test corner case // while (1) { // break; // } - cir.func @whileCornerCase() { - cir.scope { - cir.loop while(cond : { - %0 = cir.const(#cir.int<1> : !s32i) : !s32i - %1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool - cir.brcond %1 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield - }, step : { - cir.yield - }) { - cir.yield break - } + cir.func @testWhileWithBreakTerminatedBody(%arg0 : !cir.bool) { + cir.loop while(cond : { + cir.condition(%arg0) + }, step : { // Droped when lowering while statements. + cir.yield + }) { + cir.yield break } cir.return } - // MLIR: llvm.func @whileCornerCase() - // MLIR: %0 = llvm.mlir.constant(1 : i32) : i32 - // MLIR-NEXT: %1 = llvm.mlir.constant(0 : i32) : i32 - // MLIR-NEXT: %2 = llvm.icmp "ne" %0, %1 : i32 - // MLIR-NEXT: %3 = llvm.zext %2 : i1 to i8 - // MLIR-NEXT: %4 = llvm.trunc %3 : i8 to i - // MLIR-NEXT: llvm.cond_br %4, ^bb3, ^bb4 - // MLIR-NEXT: ^bb3: // pred: ^bb2 - // MLIR-NEXT: llvm.br ^bb5 - // MLIR-NEXT: ^bb4: // pred: ^bb2 - // MLIR-NEXT: llvm.br ^bb6 - // MLIR-NEXT: ^bb5: // pred: ^bb3 - // MLIR-NEXT: llvm.br ^bb6 - // MLIR-NEXT: ^bb6: // 2 preds: ^bb4, ^bb5 - // MLIR-NEXT: llvm.br ^bb7 - // MLIR-NEXT: ^bb7: // pred: ^bb6 - // MLIR-NEXT: llvm.return - // test corner case - no fails during the lowering +// CHECK: @testWhileWithBreakTerminatedBody +// CHECK: llvm.br ^bb[[#COND:]] +// CHECK: ^bb[[#COND]]: +// CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] +// CHECK: ^bb[[#BODY]]: +// CHECK: llvm.br ^bb[[#EXIT]] +// CHECK: ^bb[[#EXIT]]: + + + + // test C only corner case - no fails during the lowering // for (;;) { // break; // } - cir.func @forCornerCase() { - cir.scope { + cir.func @forWithBreakTerminatedScopeInBody(%arg0 : !cir.bool) { cir.loop for(cond : { - cir.yield continue + cir.condition(%arg0) }, step : { cir.yield }) { - cir.scope { + cir.scope { // FIXME(cir): Redundant scope emitted during C codegen. cir.yield break } cir.yield } - } cir.return } -// MLIR: llvm.func @forCornerCase() -// MLIR: llvm.br ^bb1 -// MLIR-NEXT: ^bb1: // pred: ^bb0 -// MLIR-NEXT: llvm.br ^bb2 -// MLIR-NEXT: ^bb2: // 2 preds: ^bb1, ^bb6 -// MLIR-NEXT: llvm.br ^bb3 -// MLIR-NEXT: ^bb3: // pred: ^bb2 -// MLIR-NEXT: llvm.br ^bb4 -// MLIR-NEXT: ^bb4: // pred: ^bb3 -// MLIR-NEXT: llvm.br ^bb7 -// MLIR-NEXT: ^bb5: // no predecessors -// MLIR-NEXT: llvm.br ^bb6 -// MLIR-NEXT: ^bb6: // pred: ^bb5 -// MLIR-NEXT: llvm.br ^bb2 -// MLIR-NEXT: ^bb7: // pred: ^bb4 -// MLIR-NEXT: llvm.br ^bb8 -// MLIR-NEXT: ^bb8: // pred: ^bb7 -// MLIR-NEXT: llvm.return + +// CHECK: @forWithBreakTerminatedScopeInBody +// CHECK: llvm.br ^bb[[#COND:]] +// CHECK: ^bb[[#COND:]]: +// CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] +// CHECK: ^bb[[#BODY]]: +// CHECK: llvm.br ^bb[[#SCOPE_IN:]] +// CHECK: ^bb[[#SCOPE_IN]]: +// CHECK: llvm.br ^bb[[#EXIT]] +// CHECK: ^bb[[#SCOPE_EXIT:]]: +// CHECK: llvm.br ^bb[[#STEP:]] +// CHECK: ^bb[[#STEP]]: +// CHECK: llvm.br ^bb[[#COND]] +// CHECK: ^bb[[#EXIT]]: } diff --git a/clang/test/CIR/Lowering/loops-with-break.cir b/clang/test/CIR/Lowering/loops-with-break.cir index f22865ebcc78..5bccde54df27 100644 --- a/clang/test/CIR/Lowering/loops-with-break.cir +++ b/clang/test/CIR/Lowering/loops-with-break.cir @@ -13,11 +13,7 @@ module { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { %2 = cir.load %0 : cir.ptr , !s32i %3 = cir.unary(inc, %2) : !s32i, !s32i @@ -46,11 +42,7 @@ module { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBREAK0:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preBREAK0]]: - // CHECK: llvm.br ^bb[[#preBREAK1:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBREAK1:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#preBREAK1]]: // CHECK: llvm.br ^bb[[#preBREAK2:]] // CHECK: ^bb[[#preBREAK2]]: @@ -83,11 +75,7 @@ module { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { %2 = cir.load %0 : cir.ptr , !s32i %3 = cir.unary(inc, %2) : !s32i, !s32i @@ -104,11 +92,7 @@ module { %5 = cir.const(#cir.int<10> : !s32i) : !s32i %6 = cir.cmp(lt, %4, %5) : !s32i, !s32i %7 = cir.cast(int_to_bool, %6 : !s32i), !cir.bool - cir.brcond %7 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%7) }, step : { %4 = cir.load %2 : cir.ptr , !s32i %5 = cir.unary(inc, %4) : !s32i, !s32i @@ -141,11 +125,7 @@ module { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preNESTED0:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preNESTED0]]: - // CHECK: llvm.br ^bb[[#preNESTED1:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preNESTED1:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#preNESTED1]]: // CHECK: llvm.br ^bb[[#preNESTED2:]] // CHECK: ^bb[[#preNESTED2]]: @@ -155,11 +135,7 @@ module { // CHECK: llvm.br ^bb[[#COND_NESTED:]] // CHECK: ^bb[[#COND_NESTED]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBREAK0:]], ^bb[[#preEXIT1:]] - // CHECK: ^bb[[#preBREAK0]]: - // CHECK: llvm.br ^bb[[#preBREAK1:]] - // CHECK: ^bb[[#preEXIT1]]: - // CHECK: llvm.br ^bb[[#EXIT_NESTED:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBREAK1:]], ^bb[[#EXIT_NESTED:]] // CHECK: ^bb[[#preBREAK1]]: // CHECK: llvm.br ^bb[[#preBREAK2:]] // CHECK: ^bb[[#preBREAK2]]: @@ -200,11 +176,7 @@ module { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { cir.yield }) { @@ -232,11 +204,7 @@ module { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBODY:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preBODY]]: - // CHECK: llvm.br ^bb[[#BODY:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#BODY]]: // [...] // CHECK: llvm.br ^bb[[#BREAK:]] @@ -265,11 +233,7 @@ cir.func @testDoWhile() { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { cir.yield }) { @@ -296,11 +260,7 @@ cir.func @testDoWhile() { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBODY:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preBODY]]: - // CHECK: llvm.br ^bb[[#BODY:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#BODY]]: // [...] // CHECK: llvm.br ^bb[[#BREAK:]] diff --git a/clang/test/CIR/Lowering/loops-with-continue.cir b/clang/test/CIR/Lowering/loops-with-continue.cir index c0f2c2658c2c..5dac140f7e24 100644 --- a/clang/test/CIR/Lowering/loops-with-continue.cir +++ b/clang/test/CIR/Lowering/loops-with-continue.cir @@ -13,11 +13,7 @@ module { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { %2 = cir.load %0 : cir.ptr , !s32i %3 = cir.unary(inc, %2) : !s32i, !s32i @@ -46,11 +42,7 @@ module { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preCONTINUE0:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preCONTINUE0]]: - // CHECK: llvm.br ^bb[[#preCONTINUE1:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preCONTINUE1:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#preCONTINUE1]]: // CHECK: llvm.br ^bb[[#preCONTINUE2:]] // CHECK: ^bb[[#preCONTINUE2]]: @@ -84,11 +76,7 @@ module { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { %2 = cir.load %0 : cir.ptr , !s32i %3 = cir.unary(inc, %2) : !s32i, !s32i @@ -105,11 +93,7 @@ module { %5 = cir.const(#cir.int<10> : !s32i) : !s32i %6 = cir.cmp(lt, %4, %5) : !s32i, !s32i %7 = cir.cast(int_to_bool, %6 : !s32i), !cir.bool - cir.brcond %7 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%7) }, step : { %4 = cir.load %2 : cir.ptr , !s32i %5 = cir.unary(inc, %4) : !s32i, !s32i @@ -142,11 +126,7 @@ module { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preNESTED0:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preNESTED0]]: - // CHECK: llvm.br ^bb[[#preNESTED1:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preNESTED1:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#preNESTED1]]: // CHECK: llvm.br ^bb[[#preNESTED2:]] // CHECK: ^bb[[#preNESTED2]]: @@ -156,11 +136,7 @@ module { // CHECK: llvm.br ^bb[[#COND_NESTED:]] // CHECK: ^bb[[#COND_NESTED]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preCONTINUE0:]], ^bb[[#preEXIT1:]] - // CHECK: ^bb[[#preCONTINUE0]]: - // CHECK: llvm.br ^bb[[#preCONTINUE1:]] - // CHECK: ^bb[[#preEXIT1]]: - // CHECK: llvm.br ^bb[[#EXIT_NESTED:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preCONTINUE1:]], ^bb[[#EXIT_NESTED:]] // CHECK: ^bb[[#preCONTINUE1]]: // CHECK: llvm.br ^bb[[#preCONTINUE2:]] // CHECK: ^bb[[#preCONTINUE2]]: @@ -200,11 +176,7 @@ cir.func @testWhile() { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { cir.yield }) { @@ -231,11 +203,7 @@ cir.func @testWhile() { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBODY:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preBODY]]: - // CHECK: llvm.br ^bb[[#BODY:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#BODY]]: // [...] // CHECK: llvm.br ^bb[[#CONTINUE:]] @@ -262,11 +230,7 @@ cir.func @testWhile() { %3 = cir.const(#cir.int<10> : !s32i) : !s32i %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool - cir.brcond %5 ^bb1, ^bb2 - ^bb1: // pred: ^bb0 - cir.yield continue - ^bb2: // pred: ^bb0 - cir.yield + cir.condition(%5) }, step : { cir.yield }) { @@ -294,11 +258,7 @@ cir.func @testWhile() { // CHECK: llvm.br ^bb[[#COND:]] // CHECK: ^bb[[#COND]]: // [...] - // CHECK: llvm.cond_br %{{.+}}, ^bb[[#preBODY:]], ^bb[[#preEXIT0:]] - // CHECK: ^bb[[#preBODY]]: - // CHECK: llvm.br ^bb[[#BODY:]] - // CHECK: ^bb[[#preEXIT0]]: - // CHECK: llvm.br ^bb[[#EXIT:]] + // CHECK: llvm.cond_br %{{.+}}, ^bb[[#BODY:]], ^bb[[#EXIT:]] // CHECK: ^bb[[#BODY]]: // [...] // CHECK: llvm.br ^bb[[#CONTINUE:]] diff --git a/clang/test/CIR/Transforms/merge-cleanups.cir b/clang/test/CIR/Transforms/merge-cleanups.cir index 3b0b21e935fe..8d84201aee35 100644 --- a/clang/test/CIR/Transforms/merge-cleanups.cir +++ b/clang/test/CIR/Transforms/merge-cleanups.cir @@ -65,31 +65,7 @@ module { cir.scope { cir.loop while(cond : { %0 = cir.const(#true) : !cir.bool - cir.brcond %0 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield - }, step : { - cir.yield - }) { - cir.br ^bb1 - ^bb1: - cir.return - } - } - cir.return - } - - cir.func @l1() { - cir.scope { - cir.loop while(cond : { - %0 = cir.const(#false) : !cir.bool - cir.brcond %0 ^bb1, ^bb2 - ^bb1: - cir.yield continue - ^bb2: - cir.yield + cir.condition(%0) }, step : { cir.yield }) { @@ -141,20 +117,8 @@ module { // CHECK: cir.func @l0 // CHECK-NEXT: cir.scope { // CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield continue -// CHECK-NEXT: }, step : { -// CHECK-NEXT: cir.yield -// CHECK-NEXT: }) { -// CHECK-NEXT: cir.return -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: cir.return -// CHECK-NEXT: } - -// CHECK: cir.func @l1 -// CHECK-NEXT: cir.scope { -// CHECK-NEXT: cir.loop while(cond : { -// CHECK-NEXT: cir.yield +// CHECK-NEXT: %0 = cir.const(#true) : !cir.bool +// CHECK-NEXT: cir.condition(%0) // CHECK-NEXT: }, step : { // CHECK-NEXT: cir.yield // CHECK-NEXT: }) {