Skip to content

Commit 89404b5

Browse files
[CIR] Upstream LabelOp
1 parent 87404ea commit 89404b5

File tree

7 files changed

+163
-2
lines changed

7 files changed

+163
-2
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,20 @@ def CIR_BrOp : CIR_Op<"br",[
10601060
}];
10611061
}
10621062

1063+
//===----------------------------------------------------------------------===//
1064+
// LabelOp
1065+
//===----------------------------------------------------------------------===//
1066+
1067+
// The LabelOp has AlwaysSpeculatable trait in order to not to be swept by canonicalizer
1068+
def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
1069+
let description = [{
1070+
An identifier which may be referred by cir.goto operation
1071+
}];
1072+
let arguments = (ins StrAttr:$label);
1073+
let assemblyFormat = [{ $label attr-dict }];
1074+
let hasVerifier = 1;
1075+
}
1076+
10631077
//===----------------------------------------------------------------------===//
10641078
// UnaryOp
10651079
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,9 @@ class CIRGenFunction : public CIRGenTypeCache {
11251125

11261126
mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond);
11271127

1128+
mlir::LogicalResult emitLabel(const clang::LabelDecl *d);
1129+
mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s);
1130+
11281131
mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);
11291132

11301133
/// Emit code to compute the specified expression,

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
256256
// NullStmt doesn't need any handling, but we need to say we handled it.
257257
case Stmt::NullStmtClass:
258258
break;
259+
260+
case Stmt::LabelStmtClass:
261+
return emitLabelStmt(cast<LabelStmt>(*s));
259262
case Stmt::CaseStmtClass:
260263
case Stmt::DefaultStmtClass:
261264
// If we reached here, we must not handling a switch case in the top level.
@@ -272,6 +275,17 @@ mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
272275
return mlir::success();
273276
}
274277

278+
mlir::LogicalResult CIRGenFunction::emitLabelStmt(const clang::LabelStmt &s) {
279+
280+
if (emitLabel(s.getDecl()).failed())
281+
return mlir::failure();
282+
283+
// IsEHa: not implemented.
284+
assert(!(getContext().getLangOpts().EHAsynch && s.isSideEntry()));
285+
286+
return emitStmt(s.getSubStmt(), /*useCurrentScope*/ true);
287+
}
288+
275289
// Add a terminating yield on a body region if no other terminators are used.
276290
static void terminateBody(CIRGenBuilderTy &builder, mlir::Region &r,
277291
mlir::Location loc) {
@@ -429,6 +443,32 @@ CIRGenFunction::emitContinueStmt(const clang::ContinueStmt &s) {
429443
return mlir::success();
430444
}
431445

446+
mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl *d) {
447+
// Create a new block to tag with a label and add a branch from
448+
// the current one to it. If the block is empty just call attach it
449+
// to this label.
450+
mlir::Block *currBlock = builder.getBlock();
451+
mlir::Block *labelBlock = currBlock;
452+
453+
if (!currBlock->empty()) {
454+
{
455+
mlir::OpBuilder::InsertionGuard guard(builder);
456+
labelBlock = builder.createBlock(builder.getBlock()->getParent());
457+
}
458+
builder.create<cir::BrOp>(getLoc(d->getSourceRange()), labelBlock);
459+
}
460+
461+
builder.setInsertionPointToEnd(labelBlock);
462+
builder.create<cir::LabelOp>(getLoc(d->getSourceRange()), d->getName());
463+
builder.setInsertionPointToEnd(labelBlock);
464+
465+
// FIXME: emit debug info for labels, incrementProfileCounter
466+
assert(!cir::MissingFeatures::ehstackBranches());
467+
assert(!cir::MissingFeatures::incrementProfileCounter());
468+
assert(!cir::MissingFeatures::generateDebugInfo());
469+
return mlir::success();
470+
}
471+
432472
mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
433473
builder.createBreak(getLoc(s.getBreakLoc()));
434474

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,19 @@ LogicalResult cir::ShiftOp::verify() {
17621762
return mlir::success();
17631763
}
17641764

1765+
//===----------------------------------------------------------------------===//
1766+
// LabelOp Definitions
1767+
//===----------------------------------------------------------------------===//
1768+
1769+
LogicalResult cir::LabelOp::verify() {
1770+
mlir::Operation *op = getOperation();
1771+
mlir::Block *blk = op->getBlock();
1772+
if (&blk->front() != op)
1773+
return emitError() << "must be the first operation in a block";
1774+
1775+
return mlir::success();
1776+
}
1777+
17651778
//===----------------------------------------------------------------------===//
17661779
// UnaryOp
17671780
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ struct RemoveRedundantBranches : public OpRewritePattern<BrOp> {
4747
Block *block = op.getOperation()->getBlock();
4848
Block *dest = op.getDest();
4949

50-
assert(!cir::MissingFeatures::labelOp());
51-
50+
if (isa<cir::LabelOp>(dest->front()))
51+
return failure();
5252
// Single edge between blocks: merge it.
5353
if (block->getNumSuccessors() == 1 &&
5454
dest->getSinglePredecessor() == block) {

clang/test/CIR/CodeGen/label.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
5+
6+
void label() {
7+
labelA:
8+
return;
9+
}
10+
11+
// CIR: cir.func no_proto dso_local @label
12+
// CIR: cir.label "labelA"
13+
// CIR: cir.return
14+
15+
// OGCG: define dso_local void @label
16+
// OGCG: br label %labelA
17+
// OGCG: labelA:
18+
// OGCG: ret void
19+
20+
void multiple_labels() {
21+
labelB:
22+
labelC:
23+
return;
24+
}
25+
26+
// CIR: cir.func no_proto dso_local @multiple_labels
27+
// CIR: cir.label "labelB"
28+
// CIR: cir.br ^bb1
29+
// CIR: ^bb1: // pred: ^bb0
30+
// CIR: cir.label "labelC"
31+
// CIR: cir.return
32+
33+
// OGCG: define dso_local void @multiple_labels
34+
// OGCG: br label %labelB
35+
// OGCG: labelB:
36+
// OGCG: br label %labelC
37+
// OGCG: labelC:
38+
// OGCG: ret void
39+
40+
void label_in_if(int cond) {
41+
if (cond) {
42+
labelD:
43+
cond++;
44+
}
45+
}
46+
47+
// CIR: cir.func dso_local @label_in_if
48+
// CIR: cir.if {{.*}} {
49+
// CIR: cir.label "labelD"
50+
// CIR: [[LOAD:%.*]] = cir.load align(4) [[COND:%.*]] : !cir.ptr<!s32i>, !s32i
51+
// CIR: [[INC:%.*]] = cir.unary(inc, %3) nsw : !s32i, !s32i
52+
// CIR: cir.store align(4) [[INC]], [[COND]] : !s32i, !cir.ptr<!s32i>
53+
// CIR: }
54+
// CIR: cir.return
55+
56+
// OGCG: define dso_local void @label_in_if
57+
// OGCG: if.then:
58+
// OGCG: br label %labelD
59+
// OGCG: labelD:
60+
// OGCG: [[LOAD:%.*]] = load i32, ptr [[COND:%.*]], align 4
61+
// OGCG: [[INC:%.*]] = add nsw i32 %1, 1
62+
// OGCG: store i32 [[INC]], ptr [[COND]], align 4
63+
// OGCG: br label %if.end
64+
// OGCG: if.end:
65+
// OGCG: ret void

clang/test/CIR/IR/label.cir

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: cir-opt %s | FileCheck %s
2+
3+
!s32i = !cir.int<s, 32>
4+
5+
module {
6+
cir.func @label() {
7+
cir.label "label"
8+
cir.return
9+
}
10+
11+
cir.func @label2() {
12+
%0 = cir.const #cir.int<0> : !s32i
13+
cir.br ^bb1
14+
^bb1: // pred: ^bb0
15+
cir.label "label2"
16+
cir.return
17+
}
18+
}
19+
20+
// CHECK: cir.func @label
21+
// CHECK-NEXT: cir.label "label"
22+
23+
// CHECK: cir.func @label2
24+
// CHECK: cir.br ^bb1
25+
// CHECK-NEXT: ^bb1: // pred: ^bb0
26+
// CHECK-NEXT: cir.label "label2"

0 commit comments

Comments
 (0)