[Mlir-commits] [mlir] [mlir][EmitC] Add `verbatim` op (PR #79584)

Simon Camphausen llvmlistbot at llvm.org
Wed Jan 31 00:43:25 PST 2024


https://github.com/simon-camp updated https://github.com/llvm/llvm-project/pull/79584

>From ab8cc1bb9064e0530d11db580bf1a214bd93035c Mon Sep 17 00:00:00 2001
From: Simon Camphausen <simon.camphausen at iml.fraunhofer.de>
Date: Fri, 26 Jan 2024 11:49:20 +0000
Subject: [PATCH 1/3] [mlir][EmitC] Add `verbatim` op

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.
---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 39 +++++++++++++++++++++
 mlir/lib/Dialect/EmitC/IR/EmitC.cpp         | 11 ++++++
 mlir/lib/Target/Cpp/TranslateToCpp.cpp      | 23 ++++++++----
 mlir/test/Dialect/EmitC/invalid_ops.mlir    |  8 +++++
 mlir/test/Dialect/EmitC/ops.mlir            | 11 ++++++
 mlir/test/Target/Cpp/verbatim.mlir          | 21 +++++++++++
 6 files changed, 107 insertions(+), 6 deletions(-)
 create mode 100644 mlir/test/Target/Cpp/verbatim.mlir

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index b8f8f1e2d818d..4d3d6c20e9b2c 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 5f502f1f7a171..921cce5829431 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 c32cb03caf9db..657f6ae092aef 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 46eccb1c24eea..2d98c505ac243 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 45ce2bcb99092..a50883b38d14a 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 0000000000000..cf17486050f98
--- /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;

>From 73cd31bb6b8347ba69f8ffd036e7d043df90549c Mon Sep 17 00:00:00 2001
From: Simon Camphausen <simon.camphausen at iml.fraunhofer.de>
Date: Wed, 31 Jan 2024 08:07:48 +0000
Subject: [PATCH 2/3] Remove trailing_semicolon attribute

---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td |  6 ++----
 mlir/lib/Dialect/EmitC/IR/EmitC.cpp         | 11 -----------
 mlir/lib/Target/Cpp/TranslateToCpp.cpp      |  2 --
 mlir/test/Dialect/EmitC/invalid_ops.mlir    |  8 --------
 mlir/test/Dialect/EmitC/ops.mlir            |  4 ++--
 mlir/test/Target/Cpp/verbatim.mlir          |  4 ++--
 6 files changed, 6 insertions(+), 29 deletions(-)

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 4d3d6c20e9b2c..a0ca2fa80b6c6 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -548,8 +548,7 @@ 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.
+    followed by a '\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
@@ -579,8 +578,7 @@ def EmitC_VerbatimOp : EmitC_Op<"verbatim"> {
     StrAttr:$value,
     UnitAttr:$trailing_semicolon
   );
-  let assemblyFormat = "$value (`trailing_semicolon` $trailing_semicolon^)? attr-dict";
-  let hasVerifier = 1;
+  let assemblyFormat = "$value attr-dict";
 }
 
 def EmitC_AssignOp : EmitC_Op<"assign", []> {
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 921cce5829431..5f502f1f7a171 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -584,17 +584,6 @@ 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 657f6ae092aef..72b382709925e 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -435,8 +435,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
 
   os << verbatimOp.getValue();
 
-  if (verbatimOp.getTrailingSemicolon())
-    os << ";";
   return success();
 }
 
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 2d98c505ac243..46eccb1c24eea 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -289,11 +289,3 @@ 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 a50883b38d14a..7ad3787558b7f 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -175,5 +175,5 @@ 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
+emitc.verbatim "typedef int32_t i32;"
+emitc.verbatim "typedef float f32;"
diff --git a/mlir/test/Target/Cpp/verbatim.mlir b/mlir/test/Target/Cpp/verbatim.mlir
index cf17486050f98..10465dd781a81 100644
--- a/mlir/test/Target/Cpp/verbatim.mlir
+++ b/mlir/test/Target/Cpp/verbatim.mlir
@@ -15,7 +15,7 @@ emitc.verbatim "}  // extern \"C\""
 emitc.verbatim "#endif  // __cplusplus"
 // CHECK-NEXT: #endif  // __cplusplus
 
-emitc.verbatim "typedef int32_t i32" {trailing_semicolon = unit}
+emitc.verbatim "typedef int32_t i32;"
 // CHECK-NEXT: typedef int32_t i32;
-emitc.verbatim "typedef float f32" trailing_semicolon
+emitc.verbatim "typedef float f32;"
 // CHECK-NEXT: typedef float f32;

>From 0844ddbd2d7713798c796ad774d72222ef100d4b Mon Sep 17 00:00:00 2001
From: Simon Camphausen <simon.camphausen at iml.fraunhofer.de>
Date: Wed, 31 Jan 2024 09:43:18 +0100
Subject: [PATCH 3/3] Update mlir/include/mlir/Dialect/EmitC/IR/EmitC.td

Co-authored-by: Marius Brehler <marius.brehler at iml.fraunhofer.de>
---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index a0ca2fa80b6c6..ca040f2555e13 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -548,7 +548,7 @@ 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
-    followed by a '\n' character during translation.
+    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



More information about the Mlir-commits mailing list