-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir][EmitC] Add verbatim
op
#79584
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
Conversation
This operation can be used in situations where a more suitable operation is not yet implemented in the dialect or where preprocessor directives interfere with the structure of the code.
@llvm/pr-subscribers-mlir-emitc @llvm/pr-subscribers-mlir Author: Simon Camphausen (simon-camp) ChangesThe Note: Use with caution. This operation can have arbitrary effects on the semantics of the emitted code. Use semantically more meaningful operations whenever possible. Additionally this op is NOT intended to be used to inject large snippets of code. This operation can be used in situations where a more suitable operation is not yet implemented in the dialect or where preprocessor directives interfere with the structure of the code. Full diff: https://github.com/llvm/llvm-project/pull/79584.diff 6 Files Affected:
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index b8f8f1e2d818d5..4d3d6c20e9b2c3 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -544,6 +544,45 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> {
let hasVerifier = 1;
}
+def EmitC_VerbatimOp : EmitC_Op<"verbatim"> {
+ let summary = "Verbatim operation";
+ let description = [{
+ The `verbatim` operation produces no results and the value is emitted as is
+ durung translation. If `trailing_semicolon` is present an additional
+ semicolon is emitted.
+
+ Note: Use with caution. This operation can have arbitrary effects on the
+ semantics of the emitted code. Use semantically more meaningful operations
+ whenever possible. Additionally this op is *NOT* intended to be used to
+ inject large snippets of code.
+
+ This operation can be used in situations where a more suitable operation is
+ not yet implemented in the dialect or where preprocessor directives
+ interfere with the structure of the code. One example of this is to declare
+ the linkage of external symbols to make the generated code usable in both C
+ and C++ contexts:
+
+ ```c++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+
+ ...
+
+ #ifdef __cplusplus
+ }
+ #endif
+ ```
+ }];
+
+ let arguments = (ins
+ StrAttr:$value,
+ UnitAttr:$trailing_semicolon
+ );
+ let assemblyFormat = "$value (`trailing_semicolon` $trailing_semicolon^)? attr-dict";
+ let hasVerifier = 1;
+}
+
def EmitC_AssignOp : EmitC_Op<"assign", []> {
let summary = "Assign operation";
let description = [{
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 5f502f1f7a1714..921cce58294315 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -584,6 +584,17 @@ LogicalResult emitc::VariableOp::verify() {
return verifyInitializationAttribute(getOperation(), getValueAttr());
}
+//===----------------------------------------------------------------------===//
+// VerbatimOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult emitc::VerbatimOp::verify() {
+ if (getValue().back() == ';')
+ return emitOpError() << "';' not allowed as the last character, use the "
+ "`trailing_semicolon` attribute instead";
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// YieldOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index c32cb03caf9db6..657f6ae092aef8 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -429,6 +429,17 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CmpOp cmpOp) {
return printBinaryOperation(emitter, operation, binaryOperator);
}
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::VerbatimOp verbatimOp) {
+ raw_ostream &os = emitter.ostream();
+
+ os << verbatimOp.getValue();
+
+ if (verbatimOp.getTrailingSemicolon())
+ os << ";";
+ return success();
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
cf::BranchOp branchOp) {
raw_ostream &os = emitter.ostream();
@@ -814,11 +825,10 @@ static LogicalResult printOperation(CppEmitter &emitter,
for (Operation &op : block.getOperations()) {
// When generating code for an emitc.if or cf.cond_br op no semicolon
// needs to be printed after the closing brace.
- // When generating code for an emitc.for op, printing a trailing semicolon
- // is handled within the printOperation function.
- bool trailingSemicolon =
- !isa<cf::CondBranchOp, emitc::ForOp, emitc::IfOp, emitc::LiteralOp>(
- op);
+ // When generating code for an emitc.for and emitc.verbatim op, printing a
+ // trailing semicolon is handled within the printOperation function.
+ bool trailingSemicolon = !isa<cf::CondBranchOp, emitc::ForOp, emitc::IfOp,
+ emitc::LiteralOp, emitc::VerbatimOp>(op);
if (failed(emitter.emitOperation(
op, /*trailingSemicolon=*/trailingSemicolon)))
@@ -1144,7 +1154,8 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
emitc::ConstantOp, emitc::DivOp, emitc::ExpressionOp,
emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::MulOp,
- emitc::RemOp, emitc::SubOp, emitc::VariableOp>(
+ emitc::RemOp, emitc::SubOp, emitc::VariableOp,
+ emitc::VerbatimOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
.Case<func::CallOp, func::ConstantOp, func::FuncOp, func::ReturnOp>(
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 46eccb1c24eea2..2d98c505ac2435 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -289,3 +289,11 @@ func.func @test_expression_multiple_results(%arg0: i32) -> i32 {
}
return %r : i32
}
+
+// -----
+
+func.func @verbatim_trailing_semicolon() {
+ // expected-error @+1 {{'emitc.verbatim' op ';' not allowed as the last character, use the `trailing_semicolon` attribute instead}}
+ emitc.verbatim "typedef int32_t i32;"
+ return
+}
\ No newline at end of file
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index 45ce2bcb99092c..a50883b38d14a2 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -166,3 +166,14 @@ func.func @test_for_not_index_induction(%arg0 : i16, %arg1 : i16, %arg2 : i16) {
}
return
}
+
+emitc.verbatim "#ifdef __cplusplus"
+emitc.verbatim "extern \"C\" {"
+emitc.verbatim "#endif // __cplusplus"
+
+emitc.verbatim "#ifdef __cplusplus"
+emitc.verbatim "} // extern \"C\""
+emitc.verbatim "#endif // __cplusplus"
+
+emitc.verbatim "typedef int32_t i32" {trailing_semicolon = unit}
+emitc.verbatim "typedef float f32" trailing_semicolon
diff --git a/mlir/test/Target/Cpp/verbatim.mlir b/mlir/test/Target/Cpp/verbatim.mlir
new file mode 100644
index 00000000000000..cf17486050f981
--- /dev/null
+++ b/mlir/test/Target/Cpp/verbatim.mlir
@@ -0,0 +1,21 @@
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
+// RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s
+
+
+emitc.verbatim "#ifdef __cplusplus"
+// CHECK: #ifdef __cplusplus
+emitc.verbatim "extern \"C\" {"
+// CHECK-NEXT: extern "C" {
+emitc.verbatim "#endif // __cplusplus"
+// CHECK-NEXT: #endif // __cplusplus
+emitc.verbatim "#ifdef __cplusplus"
+// CHECK-NEXT: #ifdef __cplusplus
+emitc.verbatim "} // extern \"C\""
+// CHECK-NEXT: } // extern "C"
+emitc.verbatim "#endif // __cplusplus"
+// CHECK-NEXT: #endif // __cplusplus
+
+emitc.verbatim "typedef int32_t i32" {trailing_semicolon = unit}
+// CHECK-NEXT: typedef int32_t i32;
+emitc.verbatim "typedef float f32" trailing_semicolon
+// CHECK-NEXT: typedef float f32;
|
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.
Thanks @simon-camp :) As we've already discussed this offline for quite a while, I don't have much to say. From a first quick review, there are only minor things to change.
mlir/test/Dialect/EmitC/ops.mlir
Outdated
emitc.verbatim "typedef int32_t i32" {trailing_semicolon = unit} | ||
emitc.verbatim "typedef float f32" trailing_semicolon |
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.
Do you want to add one of those or even both to the example in the description?
This is very useful! Out of curiosity, what makes the |
+1, could the attribute be avoided? |
6131bfe
to
73cd31b
Compare
Good suggestion, thank you. I'm not sure I follow the validation part. The semicolon is now part of the attribute, so there is nothing to verify. Nonetheless this made me think of the implicit |
Co-authored-by: Marius Brehler <[email protected]>
I was referring to these lines (which are now gone). |
The uses of the attribute were removed in code review of #79584, but it's definition was inadvertently kept.
The `verbatim` operation produces no results and the value is emitted as is followed by a line break ('\n' character) during translation. Note: Use with caution. This operation can have arbitrary effects on the semantics of the emitted code. Use semantically more meaningful operations whenever possible. Additionally this op is *NOT* intended to be used to inject large snippets of code. This operation can be used in situations where a more suitable operation is not yet implemented in the dialect or where preprocessor directives interfere with the structure of the code. Co-authored-by: Marius Brehler <[email protected]>
The uses of the attribute were removed in code review of llvm#79584, but it's definition was inadvertently kept.
The
verbatim
operation produces no results and the value is emitted as is followed by a line break ('\n' character) during translation.Note: Use with caution. This operation can have arbitrary effects on the semantics of the emitted code. Use semantically more meaningful operations whenever possible. Additionally this op is NOT intended to be used to inject large snippets of code.
This operation can be used in situations where a more suitable operation is not yet implemented in the dialect or where preprocessor directives interfere with the structure of the code.
Co-authored-by: Marius Brehler [email protected]