[Mlir-commits] [mlir] [MLIR] emitc: Add emitc.file op (PR #123298)
Matthias Gehre
llvmlistbot at llvm.org
Tue Jan 28 09:30:25 PST 2025
https://github.com/mgehre-amd updated https://github.com/llvm/llvm-project/pull/123298
>From 58b6d86ef3924fd2fec64e910f9b0aef441711b9 Mon Sep 17 00:00:00 2001
From: Matthias Gehre <matthias.gehre at amd.com>
Date: Tue, 5 Nov 2024 09:27:49 +0100
Subject: [PATCH] [MLIR] emitc: Add emitc file op
A `emitc.file` represents a file that can be emitted
into a single C++ file.
This allows to manage multiple source files within the same MLIR module,
but emit them into separate files.
This feature is opt-in.
By default, `mlir-translate` emits all ops outside of `emitc.file`
and ignores all `emitc.file` ops and their bodies.
When specifying the `-file-id=id` flag,
`mlir-translate` emits all ops outside of `emitc.file` and
the ops within the `emitc.file` with matching `id`.
Example:
```mlir
emitc.file "main" {
func @func_one() {
return
}
}
emitc.file "test" {
func @func_two() {
return
}
}
```
`mlir-translate -file-id=main` will emit `func_one` and
`mlir-translate -file-id=test` will emit `func_two`.
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 46 +++++++++++++++++++
mlir/include/mlir/Target/Cpp/CppEmitter.h | 6 ++-
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 9 ++++
mlir/lib/Target/Cpp/TranslateRegistration.cpp | 7 ++-
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 40 +++++++++++++---
mlir/test/Target/Cpp/file.mlir | 29 ++++++++++++
6 files changed, 128 insertions(+), 9 deletions(-)
create mode 100644 mlir/test/Target/Cpp/file.mlir
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index b16f5a8619fe7b..7946622bdbb4cc 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -23,6 +23,7 @@ include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/IR/OpAsmInterface.td"
include "mlir/IR/RegionKindInterface.td"
+include "mlir/IR/BuiltinAttributes.td"
//===----------------------------------------------------------------------===//
// EmitC op definitions
@@ -56,6 +57,51 @@ def IntegerIndexOrOpaqueType : Type<CPred<"emitc::isIntegerIndexOrOpaqueType($_s
"integer, index or opaque type supported by EmitC">;
def FloatIntegerIndexOrOpaqueType : AnyTypeOf<[EmitCFloatType, IntegerIndexOrOpaqueType]>;
+def EmitC_FileOp
+ : EmitC_Op<"file", [IsolatedFromAbove, NoRegionArguments, SymbolTable,
+ OpAsmOpInterface]#GraphRegionNoTerminator.traits> {
+ let summary = "A file container operation";
+ let description = [{
+ A `file` represents a single C/C++ file.
+
+ `mlir-translate` emits only the file selected via
+ the `-translation-unit-id=id` flag. By default, no file is emitted.
+
+ Example:
+
+ ```mlir
+ emitc.file "main" {
+ emitc.func @func_one() {
+ emitc.return
+ }
+ }
+ ```
+ }];
+
+ let arguments = (ins Builtin_StringAttr:$id);
+ let regions = (region SizedRegion<1>:$bodyRegion);
+
+ let assemblyFormat = "$id attr-dict-with-keyword $bodyRegion";
+ let builders = [OpBuilder<(ins CArg<"StringRef">:$id)>];
+ let extraClassDeclaration = [{
+ /// Construct a file op from the given location with an optional name.
+ static FileOp create(Location loc, StringRef name);
+
+ //===------------------------------------------------------------------===//
+ // OpAsmOpInterface Methods
+ //===------------------------------------------------------------------===//
+
+ /// EmitC ops in the body can omit their 'emitc.' prefix in the assembly.
+ static ::llvm::StringRef getDefaultDialect() {
+ return "emitc";
+ }
+ }];
+
+ // We need to ensure that the body region has a block;
+ // the auto-generated builders do not guarantee that.
+ let skipDefaultBuilders = 1;
+}
+
def EmitC_AddOp : EmitC_BinaryOp<"add", [CExpression]> {
let summary = "Addition operation";
let description = [{
diff --git a/mlir/include/mlir/Target/Cpp/CppEmitter.h b/mlir/include/mlir/Target/Cpp/CppEmitter.h
index 99d8696cc8e077..7c5747a8882616 100644
--- a/mlir/include/mlir/Target/Cpp/CppEmitter.h
+++ b/mlir/include/mlir/Target/Cpp/CppEmitter.h
@@ -14,6 +14,7 @@
#define MLIR_TARGET_CPP_CPPEMITTER_H
#include "mlir/Support/LLVM.h"
+#include "llvm/ADT/StringRef.h"
namespace mlir {
class Operation;
@@ -23,8 +24,11 @@ namespace emitc {
/// the region of 'op' need almost all be in EmitC dialect. The parameter
/// 'declareVariablesAtTop' enforces that all variables for op results and block
/// arguments are declared at the beginning of the function.
+/// If parameter 'fileId' is non-empty, then body of `emitc.file` ops
+/// with matching id are emitted.
LogicalResult translateToCpp(Operation *op, raw_ostream &os,
- bool declareVariablesAtTop = false);
+ bool declareVariablesAtTop = false,
+ StringRef fileId = {});
} // namespace emitc
} // namespace mlir
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index fdc21d6c6e24b9..6b85abf2b720a5 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -1289,6 +1289,15 @@ void SwitchOp::getRegionInvocationBounds(
bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
}
+//===----------------------------------------------------------------------===//
+// FileOp
+//===----------------------------------------------------------------------===//
+void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {
+ state.addRegion()->emplaceBlock();
+ state.attributes.push_back(
+ builder.getNamedAttr("id", builder.getStringAttr(id)));
+}
+
//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateRegistration.cpp b/mlir/lib/Target/Cpp/TranslateRegistration.cpp
index 1aa98834a73f49..2108ffd414c568 100644
--- a/mlir/lib/Target/Cpp/TranslateRegistration.cpp
+++ b/mlir/lib/Target/Cpp/TranslateRegistration.cpp
@@ -29,12 +29,17 @@ void registerToCppTranslation() {
llvm::cl::desc("Declare variables at top when emitting C/C++"),
llvm::cl::init(false));
+ static llvm::cl::opt<std::string> fileId(
+ "file-id", llvm::cl::desc("Emit emitc.file ops with matching id"),
+ llvm::cl::init(""));
+
TranslateFromMLIRRegistration reg(
"mlir-to-cpp", "translate from mlir to cpp",
[](Operation *op, raw_ostream &output) {
return emitc::translateToCpp(
op, output,
- /*declareVariablesAtTop=*/declareVariablesAtTop);
+ /*declareVariablesAtTop=*/declareVariablesAtTop,
+ /*fileId=*/fileId);
},
[](DialectRegistry ®istry) {
// clang-format off
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index a91f5ab9311401..f634d385754f58 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -114,7 +114,8 @@ static FailureOr<int> getOperatorPrecedence(Operation *operation) {
namespace {
/// Emitter that uses dialect specific emitters to emit C++ code.
struct CppEmitter {
- explicit CppEmitter(raw_ostream &os, bool declareVariablesAtTop);
+ explicit CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
+ StringRef fileId);
/// Emits attribute or returns failure.
LogicalResult emitAttribute(Location loc, Attribute attr);
@@ -231,6 +232,11 @@ struct CppEmitter {
/// be declared at the beginning of a function.
bool shouldDeclareVariablesAtTop() { return declareVariablesAtTop; };
+ /// Returns whether this translation unit should be emitted
+ bool shouldEmitFile(FileOp file) {
+ return !fileId.empty() && file.getId() == fileId;
+ }
+
/// Get expression currently being emitted.
ExpressionOp getEmittedExpression() { return emittedExpression; }
@@ -258,6 +264,9 @@ struct CppEmitter {
/// includes results from ops located in nested regions.
bool declareVariablesAtTop;
+ /// Only emit translation units whos id matches this value.
+ std::string fileId;
+
/// Map from value to name of C++ variable that contain the name.
ValueMapper valueMapper;
@@ -960,6 +969,19 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
return success();
}
+static LogicalResult printOperation(CppEmitter &emitter, FileOp file) {
+ if (!emitter.shouldEmitFile(file))
+ return success();
+
+ CppEmitter::Scope scope(emitter);
+
+ for (Operation &op : file) {
+ if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
+ return failure();
+ }
+ return success();
+}
+
static LogicalResult printFunctionArgs(CppEmitter &emitter,
Operation *functionOp,
ArrayRef<Type> arguments) {
@@ -1159,8 +1181,10 @@ static LogicalResult printOperation(CppEmitter &emitter,
return success();
}
-CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop)
- : os(os), declareVariablesAtTop(declareVariablesAtTop) {
+CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
+ StringRef fileId)
+ : os(os), declareVariablesAtTop(declareVariablesAtTop),
+ fileId(fileId.str()) {
valueInScopeCount.push(0);
labelInScopeCount.push(0);
}
@@ -1561,8 +1585,9 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, emitc::LoadOp,
emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
- emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
- emitc::VariableOp, emitc::VerbatimOp>(
+ emitc::SwitchOp, emitc::FileOp, emitc::UnaryMinusOp,
+ emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>(
+
[&](auto op) { return printOperation(*this, op); })
// Func ops.
.Case<func::CallOp, func::FuncOp, func::ReturnOp>(
@@ -1742,7 +1767,8 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
}
LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os,
- bool declareVariablesAtTop) {
- CppEmitter emitter(os, declareVariablesAtTop);
+ bool declareVariablesAtTop,
+ StringRef fileId) {
+ CppEmitter emitter(os, declareVariablesAtTop, fileId);
return emitter.emitOperation(*op, /*trailingSemicolon=*/false);
}
diff --git a/mlir/test/Target/Cpp/file.mlir b/mlir/test/Target/Cpp/file.mlir
new file mode 100644
index 00000000000000..262d3cdac27d4a
--- /dev/null
+++ b/mlir/test/Target/Cpp/file.mlir
@@ -0,0 +1,29 @@
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s --check-prefix NO-FILTER
+// RUN: mlir-translate -mlir-to-cpp -file-id=non-existing %s | FileCheck %s --check-prefix NON-EXISTING
+// RUN: mlir-translate -mlir-to-cpp -file-id=file_one %s | FileCheck %s --check-prefix FILE-ONE
+// RUN: mlir-translate -mlir-to-cpp -file-id=file_two %s | FileCheck %s --check-prefix FILE-TWO
+
+
+// NO-FILTER-NOT: func_one
+// NO-FILTER-NOT: func_two
+
+// NON-EXISTING-NOT: func_one
+// NON-EXISTING-NOT: func_two
+
+// FILE-ONE: func_one
+// FILE-ONE-NOT: func_two
+
+// FILE-TWO-NOT: func_one
+// FILE-TWO: func_two
+
+emitc.file "file_one" {
+ emitc.func @func_one(%arg: f32) {
+ emitc.return
+ }
+}
+
+emitc.file "file_two" {
+ emitc.func @func_two(%arg: f32) {
+ emitc.return
+ }
+}
More information about the Mlir-commits
mailing list