-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[CIR] Upstream GotoOp #153701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CIR] Upstream GotoOp #153701
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -250,6 +250,8 @@ mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s, | |||||
| else | ||||||
| emitCompoundStmt(cast<CompoundStmt>(*s)); | ||||||
| break; | ||||||
| case Stmt::GotoStmtClass: | ||||||
| return emitGotoStmt(cast<GotoStmt>(*s)); | ||||||
| case Stmt::ContinueStmtClass: | ||||||
| return emitContinueStmt(cast<ContinueStmt>(*s)); | ||||||
|
|
||||||
|
|
@@ -433,6 +435,25 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) { | |||||
| return mlir::success(); | ||||||
| } | ||||||
|
|
||||||
| mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) { | ||||||
| // FIXME: LLVM codegen inserts emit stop point here for debug info | ||||||
| // sake when the insertion point is available, but doesn't do | ||||||
| // anything special when there isn't. We haven't implemented debug | ||||||
| // info support just yet, look at this again once we have it. | ||||||
bcardosolopes marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| if (!builder.getInsertionBlock()) | ||||||
|
||||||
| if (!builder.getInsertionBlock()) | |
| assert(!cir::MissingFeatures::generateDebugInfo()); |
This seems backwards. According to the comment, the stop point is only needed when we have an insertion point. I think it's better to just put a missing feature marker here.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| builder.create<cir::GotoOp>(getLoc(s.getSourceRange()), | |
| cir::GotoOp::create(builder, getLoc(s.getSourceRange()), |
MLIR is moving to this new idiom. The incubator code predates that idiom, so this is something to watch for as you're upstreaming things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so I guess in lowering we should also start moving to this idiom for llvm ir. Is this change planned as a big PR, or will it be done progressively?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like:
perl -pi -e 's/builder\.create<\s*cir::(\w+)\s*>\s*\(/cir::$1::create(builder, /g'There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been done already in the llvm-project/mlir subdirectories. @xlauko has been gradually updating the existing CIR code, and we're trying to catch other cases as we migrate them from the incubator. Before the last rebase, the incubator didn't have the necessary MLIR support to move to this idiom. It probably does now after the rebase that @lanza completed recently.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1649,7 +1649,27 @@ void cir::FuncOp::print(OpAsmPrinter &p) { | |||||
|
|
||||||
| // TODO(CIR): The properties of functions that require verification haven't | ||||||
| // been implemented yet. | ||||||
| mlir::LogicalResult cir::FuncOp::verify() { return success(); } | ||||||
| mlir::LogicalResult cir::FuncOp::verify() { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can now remove the comment above. |
||||||
|
|
||||||
| std::set<llvm::StringRef> labels; | ||||||
|
||||||
| std::set<llvm::StringRef> gotos; | ||||||
|
|
||||||
| getOperation()->walk([&](mlir::Operation *op) { | ||||||
| if (auto lab = dyn_cast<cir::LabelOp>(op)) { | ||||||
| labels.emplace(lab.getLabel()); | ||||||
| } else if (auto goTo = dyn_cast<cir::GotoOp>(op)) { | ||||||
| gotos.emplace(goTo.getLabel()); | ||||||
| } | ||||||
| }); | ||||||
|
|
||||||
| std::vector<llvm::StringRef> mismatched; | ||||||
| std::set_difference(gotos.begin(), gotos.end(), labels.begin(), labels.end(), | ||||||
|
||||||
| std::set_difference(gotos.begin(), gotos.end(), labels.begin(), labels.end(), | |
| SmallSet<llvm::StringRef, 16> mismatched = llvm::set_difference(gotos, labels)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir | ||
| // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR | ||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll | ||
| // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG | ||
|
|
||
| int shouldNotGenBranchRet(int x) { | ||
| if (x > 5) | ||
| goto err; | ||
| return 0; | ||
| err: | ||
| return -1; | ||
| } | ||
| // CIR: cir.func dso_local @_Z21shouldNotGenBranchReti | ||
| // CIR: cir.if {{.*}} { | ||
| // CIR: cir.goto "err" | ||
| // CIR: } | ||
| // CIR: ^bb1: | ||
| // CIR: [[LOAD:%.*]] = cir.load [[ZERO:%.*]] : !cir.ptr<!s32i>, !s32i | ||
|
||
| // CIR: cir.return [[LOAD]] : !s32i | ||
| // CIR: ^bb2: | ||
| // CIR: cir.label "err" | ||
|
|
||
| // OGCG: define dso_local noundef i32 @_Z21shouldNotGenBranchReti | ||
| // OGCG: if.then: | ||
| // OGCG: br label %err | ||
| // OGCG: if.end: | ||
| // OGCG: br label %return | ||
| // OGCG: err: | ||
| // OGCG: br label %return | ||
| // OGCG: return: | ||
|
|
||
| int shouldGenBranch(int x) { | ||
| if (x > 5) | ||
| goto err; | ||
| x++; | ||
| err: | ||
| return -1; | ||
| } | ||
| // CIR: cir.func dso_local @_Z15shouldGenBranchi | ||
| // CIR: cir.if {{.*}} { | ||
| // CIR: cir.goto "err" | ||
| // CIR: } | ||
| // CIR: cir.br ^bb1 | ||
| // CIR: ^bb1: | ||
| // CIR: cir.label "err" | ||
|
|
||
| // OGCG: define dso_local noundef i32 @_Z15shouldGenBranchi | ||
| // OGCG: if.then: | ||
| // OGCG: br label %err | ||
| // OGCG: if.end: | ||
| // OGCG: br label %err | ||
| // OGCG: err: | ||
| // OGCG: ret | ||
|
|
||
| void severalLabelsInARow(int a) { | ||
| int b = a; | ||
| goto end1; | ||
| b = b + 1; | ||
| goto end2; | ||
| end1: | ||
| end2: | ||
| b = b + 2; | ||
| } | ||
| // CIR: cir.func dso_local @_Z19severalLabelsInARowi | ||
| // CIR: cir.goto "end1" | ||
| // CIR: ^bb[[#BLK1:]] | ||
| // CIR: cir.goto "end2" | ||
| // CIR: ^bb[[#BLK2:]]: | ||
| // CIR: cir.label "end1" | ||
| // CIR: cir.br ^bb[[#BLK3:]] | ||
| // CIR: ^bb[[#BLK3]]: | ||
| // CIR: cir.label "end2" | ||
|
|
||
| // OGCG: define dso_local void @_Z19severalLabelsInARowi | ||
| // OGCG: br label %end1 | ||
| // OGCG: end1: | ||
| // OGCG: br label %end2 | ||
| // OGCG: end2: | ||
| // OGCG: ret | ||
|
|
||
| void severalGotosInARow(int a) { | ||
| int b = a; | ||
| goto end; | ||
| goto end; | ||
| end: | ||
| b = b + 2; | ||
| } | ||
| // CIR: cir.func dso_local @_Z18severalGotosInARowi | ||
| // CIR: cir.goto "end" | ||
| // CIR: ^bb[[#BLK1:]]: | ||
| // CIR: cir.goto "end" | ||
| // CIR: ^bb[[#BLK2:]]: | ||
| // CIR: cir.label "end" | ||
|
|
||
| // OGCG: define dso_local void @_Z18severalGotosInARowi(i32 noundef %a) #0 { | ||
| // OGCG: br label %end | ||
| // OGCG: end: | ||
| // OGCG: ret void | ||
|
|
||
| extern "C" void action1(); | ||
| extern "C" void action2(); | ||
| extern "C" void multiple_non_case(int v) { | ||
| switch (v) { | ||
| default: | ||
| action1(); | ||
| l2: | ||
| action2(); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // CIR: cir.func dso_local @multiple_non_case | ||
| // CIR: cir.switch | ||
| // CIR: cir.case(default, []) { | ||
| // CIR: cir.call @action1() | ||
| // CIR: cir.br ^[[BB1:[a-zA-Z0-9]+]] | ||
| // CIR: ^[[BB1]]: | ||
| // CIR: cir.label | ||
| // CIR: cir.call @action2() | ||
| // CIR: cir.break | ||
|
|
||
| // OGCG: define dso_local void @multiple_non_case | ||
| // OGCG: sw.default: | ||
| // OGCG: call void @action1() | ||
| // OGCG: br label %l2 | ||
| // OGCG: l2: | ||
| // OGCG: call void @action2() | ||
| // OGCG: br label [[BREAK:%.*]] | ||
|
|
||
| extern "C" void case_follow_label(int v) { | ||
| switch (v) { | ||
| case 1: | ||
| label: | ||
| case 2: | ||
| action1(); | ||
| break; | ||
| default: | ||
| action2(); | ||
| goto label; | ||
| } | ||
| } | ||
|
|
||
| // CIR: cir.func dso_local @case_follow_label | ||
| // CIR: cir.switch | ||
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { | ||
| // CIR: cir.label "label" | ||
| // CIR: cir.case(equal, [#cir.int<2> : !s32i]) { | ||
| // CIR: cir.call @action1() | ||
| // CIR: cir.break | ||
| // CIR: cir.case(default, []) { | ||
| // CIR: cir.call @action2() | ||
| // CIR: cir.goto "label" | ||
|
|
||
| // OGCG: define dso_local void @case_follow_label | ||
| // OGCG: sw.bb: | ||
| // OGCG: br label %label | ||
| // OGCG: label: | ||
| // OGCG: br label %sw.bb1 | ||
| // OGCG: sw.bb1: | ||
| // OGCG: call void @action1() | ||
| // OGCG: br label %sw.epilog | ||
| // OGCG: sw.default: | ||
| // OGCG: call void @action2() | ||
| // OGCG: br label %label | ||
| // OGCG: sw.epilog: | ||
| // OGCG: ret void | ||
|
|
||
| extern "C" void default_follow_label(int v) { | ||
| switch (v) { | ||
| case 1: | ||
| case 2: | ||
| action1(); | ||
| break; | ||
| label: | ||
| default: | ||
| action2(); | ||
| goto label; | ||
| } | ||
| } | ||
|
|
||
| // CIR: cir.func dso_local @default_follow_label | ||
| // CIR: cir.switch | ||
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { | ||
| // CIR: cir.yield | ||
| // CIR: cir.case(equal, [#cir.int<2> : !s32i]) { | ||
| // CIR: cir.call @action1() | ||
| // CIR: cir.break | ||
| // CIR: cir.label "label" | ||
| // CIR: cir.case(default, []) { | ||
| // CIR: cir.call @action2() | ||
| // CIR: cir.goto "label" | ||
|
|
||
| // OGCG: define dso_local void @default_follow_label | ||
| // OGCG: sw.bb: | ||
| // OGCG: call void @action1() | ||
| // OGCG: br label %sw.epilog | ||
| // OGCG: label: | ||
| // OGCG: br label %sw.default | ||
| // OGCG: sw.default: | ||
| // OGCG: call void @action2() | ||
| // OGCG: br label %label | ||
| // OGCG: sw.epilog: | ||
| // OGCG: ret void | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| // RUN: cir-opt %s -verify-diagnostics -split-input-file | ||
|
|
||
| // expected-error@+1 {{goto/label mismatch}} | ||
| cir.func @bad_goto() -> () { | ||
| cir.goto "somewhere" | ||
| ^bb1: | ||
| cir.label "label" | ||
| cir.return | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.