Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -607,13 +607,12 @@ def ConditionOp : CIR_Op<"condition", [

def YieldOpKind_BK : I32EnumAttrCase<"Break", 1, "break">;
def YieldOpKind_FT : I32EnumAttrCase<"Fallthrough", 2, "fallthrough">;
def YieldOpKind_CE : I32EnumAttrCase<"Continue", 3, "continue">;
def YieldOpKind_NS : I32EnumAttrCase<"NoSuspend", 4, "nosuspend">;

def YieldOpKind : I32EnumAttr<
"YieldOpKind",
"yield kind",
[YieldOpKind_BK, YieldOpKind_FT, YieldOpKind_CE, YieldOpKind_NS]> {
[YieldOpKind_BK, YieldOpKind_FT, YieldOpKind_NS]> {
let cppNamespace = "::mlir::cir";
}

Expand All @@ -634,8 +633,6 @@ def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
cannot be used if not dominated by these parent operations.
- `fallthrough`: execution falls to the next region in `cir.switch` case list.
Only available inside `cir.switch` regions.
- `continue`: only allowed under `cir.loop`, continue execution to the next
loop step.
- `nosuspend`: specific to the `ready` region inside `cir.await` op, it makes
control-flow to be transfered back to the parent, preventing suspension.

Expand All @@ -657,11 +654,6 @@ def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
}, ...
]

cir.loop (cond : {...}, step : {...}) {
...
cir.yield continue
}

cir.await(init, ready : {
// Call std::suspend_always::await_ready
%18 = cir.call @_ZNSt14suspend_always11await_readyEv(...)
Expand Down Expand Up @@ -718,9 +710,6 @@ def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
bool isBreak() {
return !isPlain() && *getKind() == YieldOpKind::Break;
}
bool isContinue() {
return !isPlain() && *getKind() == YieldOpKind::Continue;
}
bool isNoSuspend() {
return !isPlain() && *getKind() == YieldOpKind::NoSuspend;
}
Expand All @@ -729,6 +718,20 @@ def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// ContinueOp
//===----------------------------------------------------------------------===//

def ContinueOp : CIR_Op<"continue", [Terminator]> {
let summary = "C/C++ `continue` statement equivalent";
let description = [{
The `cir.continue` operation is used to continue execution to the next
iteration of a loop. It is only allowed within `cir.loop` regions.
}];
let assemblyFormat = "attr-dict";
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// ScopeOp
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1166,7 +1169,7 @@ def LoopOp : CIR_Op<"loop",
`cir.loop` represents C/C++ loop forms. It defines 3 blocks:
- `cond`: region can contain multiple blocks, terminated by regular
`cir.yield` when control should yield back to the parent, and
`cir.yield continue` when execution continues to another region.
`cir.continue` when execution continues to the next region.
The region destination depends on the loop form specified.
- `step`: region with one block, containing code to compute the
loop step, must be terminated with `cir.yield`.
Expand All @@ -1181,7 +1184,7 @@ def LoopOp : CIR_Op<"loop",
// i = i + 1;
// }
cir.loop while(cond : {
cir.yield continue
cir.continue
}, step : {
cir.yield
}) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,11 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
return create<mlir::cir::ConditionOp>(condition.getLoc(), condition);
}

/// Create a continue operation.
mlir::cir::ContinueOp createContinue(mlir::Location loc) {
return create<mlir::cir::ContinueOp>(loc);
}

mlir::cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
mlir::Value src, mlir::Value len) {
return create<mlir::cir::MemCpyOp>(loc, dst, src, len);
Expand Down
7 changes: 1 addition & 6 deletions clang/lib/CIR/CodeGen/CIRGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ mlir::LogicalResult CIRGenFunction::buildSimpleStmt(const Stmt *S,
return buildGotoStmt(cast<GotoStmt>(*S));
case Stmt::ContinueStmtClass:
return buildContinueStmt(cast<ContinueStmt>(*S));

case Stmt::NullStmtClass:
break;

Expand Down Expand Up @@ -570,11 +569,7 @@ mlir::LogicalResult CIRGenFunction::buildLabel(const LabelDecl *D) {

mlir::LogicalResult
CIRGenFunction::buildContinueStmt(const clang::ContinueStmt &S) {
builder.create<YieldOp>(
getLoc(S.getContinueLoc()),
mlir::cir::YieldOpKindAttr::get(builder.getContext(),
mlir::cir::YieldOpKind::Continue),
mlir::ValueRange({}));
builder.createContinue(getLoc(S.getContinueLoc()));
return mlir::success();
}

Expand Down
25 changes: 10 additions & 15 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,16 @@ static void printConstantValue(OpAsmPrinter &p, cir::ConstantOp op,

OpFoldResult ConstantOp::fold(FoldAdaptor /*adaptor*/) { return getValue(); }

//===----------------------------------------------------------------------===//
// ContinueOp
//===----------------------------------------------------------------------===//

LogicalResult ContinueOp::verify() {
if (!this->getOperation()->getParentOfType<LoopOp>())
return emitOpError("must be within a loop");
return success();
}

//===----------------------------------------------------------------------===//
// CastOp
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -797,15 +807,6 @@ mlir::LogicalResult YieldOp::verify() {
return false;
};

auto isDominatedByLoop = [](Operation *parentOp) {
while (!llvm::isa<cir::FuncOp>(parentOp)) {
if (llvm::isa<cir::LoopOp>(parentOp))
return true;
parentOp = parentOp->getParentOp();
}
return false;
};

if (isNoSuspend()) {
if (!isDominatedByProperAwaitRegion(getOperation()->getParentOp(),
getOperation()->getParentRegion()))
Expand All @@ -819,12 +820,6 @@ mlir::LogicalResult YieldOp::verify() {
return mlir::success();
}

if (isContinue()) {
if (!isDominatedByLoop(getOperation()->getParentOp()))
return emitOpError() << "shall be dominated by 'cir.loop'";
return mlir::success();
}

if (isFallthrough()) {
if (!llvm::isa<SwitchOp>(getOperation()->getParentOp()))
return emitOpError() << "fallthrough only expected within 'cir.switch'";
Expand Down
66 changes: 48 additions & 18 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Types.h"
#include "mlir/IR/Value.h"
#include "mlir/IR/ValueRange.h"
#include "mlir/IR/Visitors.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
Expand Down Expand Up @@ -65,6 +67,36 @@ using namespace llvm;
namespace cir {
namespace direct {

//===----------------------------------------------------------------------===//
// Helper Methods
//===----------------------------------------------------------------------===//

namespace {

/// Lowers operations with the terminator trait that have a single successor.
void lowerTerminator(mlir::Operation *op, mlir::Block *dest,
mlir::ConversionPatternRewriter &rewriter) {
assert(op->hasTrait<mlir::OpTrait::IsTerminator>() && "not a terminator");
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPoint(op);
rewriter.replaceOpWithNewOp<mlir::cir::BrOp>(op, dest);
}

/// Walks a region while skipping operations of type `Ops`. This ensures the
/// callback is not applied to said operations and its children.
template <typename... Ops>
void walkRegionSkipping(mlir::Region &region,
mlir::function_ref<void(mlir::Operation *)> callback) {
region.walk<mlir::WalkOrder::PreOrder>([&](mlir::Operation *op) {
if (isa<Ops...>(op))
return mlir::WalkResult::skip();
callback(op);
return mlir::WalkResult::advance();
});
}

} // namespace

//===----------------------------------------------------------------------===//
// Visitors for Lowering CIR Const Attributes
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -441,8 +473,15 @@ class CIRLoopOpLowering : public mlir::OpConversionPattern<mlir::cir::LoopOp> {

lowerNestedYield(mlir::cir::YieldOpKind::Break, rewriter, bodyRegion,
continueBlock);
lowerNestedYield(mlir::cir::YieldOpKind::Continue, rewriter, bodyRegion,
&stepBlock);

// Lower continue statements.
mlir::Block &dest =
(kind != LoopKind::For ? condFrontBlock : stepFrontBlock);
walkRegionSkipping<mlir::cir::LoopOp>(
loopOp.getBody(), [&](mlir::Operation *op) {
if (isa<mlir::cir::ContinueOp>(op))
lowerTerminator(op, &dest, rewriter);
});

// Move loop op region contents to current CFG.
rewriter.inlineRegionBefore(condRegion, continueBlock);
Expand Down Expand Up @@ -672,9 +711,8 @@ class CIRCastOpLowering : public mlir::OpConversionPattern<mlir::cir::CastOp> {
}
};

static bool isBreakOrContinue(mlir::cir::YieldOp &op) {
return op.getKind() == mlir::cir::YieldOpKind::Break ||
op.getKind() == mlir::cir::YieldOpKind::Continue;
static bool isBreak(mlir::cir::YieldOp &op) {
return op.getKind() == mlir::cir::YieldOpKind::Break;
}

class CIRIfLowering : public mlir::OpConversionPattern<mlir::cir::IfOp> {
Expand Down Expand Up @@ -705,12 +743,10 @@ class CIRIfLowering : public mlir::OpConversionPattern<mlir::cir::IfOp> {
rewriter.setInsertionPointToEnd(thenAfterBody);
if (auto thenYieldOp =
dyn_cast<mlir::cir::YieldOp>(thenAfterBody->getTerminator())) {
if (!isBreakOrContinue(thenYieldOp)) // lowering of parent loop yields is
// deferred to loop lowering
if (!isBreak(thenYieldOp)) // lowering of parent loop yields is
// deferred to loop lowering
rewriter.replaceOpWithNewOp<mlir::cir::BrOp>(
thenYieldOp, thenYieldOp.getArgs(), continueBlock);
} else if (!dyn_cast<mlir::cir::ReturnOp>(thenAfterBody->getTerminator())) {
llvm_unreachable("what are we terminating with?");
}

rewriter.setInsertionPointToEnd(continueBlock);
Expand All @@ -736,13 +772,10 @@ class CIRIfLowering : public mlir::OpConversionPattern<mlir::cir::IfOp> {
rewriter.setInsertionPointToEnd(elseAfterBody);
if (auto elseYieldOp =
dyn_cast<mlir::cir::YieldOp>(elseAfterBody->getTerminator())) {
if (!isBreakOrContinue(elseYieldOp)) // lowering of parent loop yields
// is deferred to loop lowering
if (!isBreak(elseYieldOp)) // lowering of parent loop yields
// is deferred to loop lowering
rewriter.replaceOpWithNewOp<mlir::cir::BrOp>(
elseYieldOp, elseYieldOp.getArgs(), continueBlock);
} else if (!dyn_cast<mlir::cir::ReturnOp>(
elseAfterBody->getTerminator())) {
llvm_unreachable("what are we terminating with?");
}
}

Expand Down Expand Up @@ -798,7 +831,7 @@ class CIRScopeOpLowering
rewriter.setInsertionPointToEnd(afterBody);
auto yieldOp = dyn_cast<mlir::cir::YieldOp>(afterBody->getTerminator());

if (yieldOp && !isBreakOrContinue(yieldOp)) {
if (yieldOp && !isBreak(yieldOp)) {
auto branchOp = rewriter.replaceOpWithNewOp<mlir::cir::BrOp>(
yieldOp, yieldOp.getArgs(), continueBlock);

Expand Down Expand Up @@ -1400,9 +1433,6 @@ class CIRSwitchOpLowering
case mlir::cir::YieldOpKind::Break:
rewriteYieldOp(rewriter, yieldOp, exitBlock);
break;
case mlir::cir::YieldOpKind::Continue: // Continue is handled only in
// loop lowering
break;
default:
return op->emitError("invalid yield kind in case statement");
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ void l4() {
// CHECK-NEXT: %11 = cir.const(#cir.int<10> : !s32i) : !s32i
// CHECK-NEXT: %12 = cir.cmp(lt, %10, %11) : !s32i, !cir.bool
// CHECK-NEXT: cir.if %12 {
// CHECK-NEXT: cir.yield continue
// CHECK-NEXT: cir.continue
// CHECK-NEXT: }
// CHECK-NEXT: }

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/IR/invalid.cir
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ cir.func @yieldbreak() {
cir.func @yieldcontinue() {
%0 = cir.const(#true) : !cir.bool
cir.if %0 {
cir.yield continue // expected-error {{shall be dominated by 'cir.loop'}}
cir.continue // expected-error {{op must be within a loop}}
}
cir.return
}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/IR/loop.cir
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ cir.func @l0() {
cir.store %6, %0 : !u32i, cir.ptr <!u32i>
%7 = cir.const(#true) : !cir.bool
cir.if %7 {
cir.yield continue
cir.continue
}
cir.yield
}
Expand Down Expand Up @@ -118,7 +118,7 @@ cir.func @l0() {
// CHECK-NEXT: cir.store %6, %0 : !u32i, cir.ptr <!u32i>
// CHECK-NEXT: %7 = cir.const(#true) : !cir.bool
// CHECK-NEXT: cir.if %7 {
// CHECK-NEXT: cir.yield continue
// CHECK-NEXT: cir.continue
// CHECK-NEXT: }
// CHECK-NEXT: cir.yield
// CHECK-NEXT: }
Expand Down
8 changes: 4 additions & 4 deletions clang/test/CIR/Lowering/loops-with-continue.cir
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module {
%4 = cir.cmp(eq, %2, %3) : !s32i, !s32i
%5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool
cir.if %5 {
cir.yield continue
cir.continue
}
}
}
Expand Down Expand Up @@ -107,7 +107,7 @@ module {
%6 = cir.cmp(eq, %4, %5) : !s32i, !s32i
%7 = cir.cast(int_to_bool, %6 : !s32i), !cir.bool
cir.if %7 {
cir.yield continue
cir.continue
}
}
}
Expand Down Expand Up @@ -189,7 +189,7 @@ cir.func @testWhile() {
%6 = cir.cmp(eq, %4, %5) : !s32i, !s32i
%7 = cir.cast(int_to_bool, %6 : !s32i), !cir.bool
cir.if %7 {
cir.yield continue
cir.continue
}
}
cir.yield
Expand Down Expand Up @@ -243,7 +243,7 @@ cir.func @testWhile() {
%6 = cir.cmp(eq, %4, %5) : !s32i, !s32i
%7 = cir.cast(int_to_bool, %6 : !s32i), !cir.bool
cir.if %7 {
cir.yield continue
cir.continue
}
}
cir.yield
Expand Down