From a64ebcc26cb43c6043f219dba4b643585b0cf15a Mon Sep 17 00:00:00 2001 From: Matthias Gehre Date: Tue, 5 Nov 2024 09:27:49 +0100 Subject: [PATCH] Add emitc.tu --- mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 43 +++++++++++++++++++ mlir/include/mlir/Target/Cpp/CppEmitter.h | 4 +- mlir/lib/Target/Cpp/TranslateRegistration.cpp | 8 +++- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 37 +++++++++++++--- mlir/test/Target/Cpp/tu.mlir | 29 +++++++++++++ 5 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 mlir/test/Target/Cpp/tu.mlir diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td index 1a1b58e3cbf386..78c420997dac65 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td @@ -21,7 +21,9 @@ include "mlir/Interfaces/CastInterfaces.td" include "mlir/Interfaces/ControlFlowInterfaces.td" 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 @@ -55,6 +57,47 @@ def IntegerIndexOrOpaqueType : Type; def FloatIntegerIndexOrOpaqueType : AnyTypeOf<[EmitCFloatType, IntegerIndexOrOpaqueType]>; +def EmitC_TranslationUnitOp : EmitC_Op<"tu", + [IsolatedFromAbove, NoRegionArguments, SymbolTable, + OpAsmOpInterface + ] # GraphRegionNoTerminator.traits> { + let summary = "A translation unit container operation"; + let description = [{ + A `tu` represents a translation unit that can be emitted + into a single C++ file. + + `mlir-translate` emits only the translation unit selected via + the `-translation-unit-id=id` flag. By default, no translation units are + emitted. + + Example: + + ```mlir + emitc.tu "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 extraClassDeclaration = [{ + //===------------------------------------------------------------------===// + // OpAsmOpInterface Methods + //===------------------------------------------------------------------===// + + /// EmitC ops in the body of the translation_unit can omit their 'emitc.' + /// prefix in the assembly. + static ::llvm::StringRef getDefaultDialect() { + return "emitc"; + } + }]; +} + 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..d76cfc9107332e 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; @@ -24,7 +25,8 @@ namespace emitc { /// 'declareVariablesAtTop' enforces that all variables for op results and block /// arguments are declared at the beginning of the function. LogicalResult translateToCpp(Operation *op, raw_ostream &os, - bool declareVariablesAtTop = false); + bool declareVariablesAtTop = false, + StringRef onlyTu = ""); } // namespace emitc } // namespace mlir diff --git a/mlir/lib/Target/Cpp/TranslateRegistration.cpp b/mlir/lib/Target/Cpp/TranslateRegistration.cpp index 1aa98834a73f49..7e2bc9ad012b38 100644 --- a/mlir/lib/Target/Cpp/TranslateRegistration.cpp +++ b/mlir/lib/Target/Cpp/TranslateRegistration.cpp @@ -29,12 +29,18 @@ void registerToCppTranslation() { llvm::cl::desc("Declare variables at top when emitting C/C++"), llvm::cl::init(false)); + static llvm::cl::opt onlyTu( + "translation-unit-id", + llvm::cl::desc("Only emit the translation unit with the 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, + /*onlyTu=*/onlyTu); }, [](DialectRegistry ®istry) { // clang-format off diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index bc73d415e6e8c8..60ad20bf7a0926 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -115,7 +115,8 @@ static FailureOr 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 onlyTu); /// Emits attribute or returns failure. LogicalResult emitAttribute(Location loc, Attribute attr); @@ -231,6 +232,9 @@ struct CppEmitter { /// be declared at the beginning of a function. bool shouldDeclareVariablesAtTop() { return declareVariablesAtTop; }; + /// Returns whether this translation unit should be emitted + bool shouldEmitTu(TranslationUnitOp tu) { return tu.getId() == onlyTu; } + /// Get expression currently being emitted. ExpressionOp getEmittedExpression() { return emittedExpression; } @@ -258,6 +262,9 @@ struct CppEmitter { /// includes results from ops located in nested regions. bool declareVariablesAtTop; + /// Only emit translation units whos id matches this value. + std::string onlyTu; + /// Map from value to name of C++ variable that contain the name. ValueMapper valueMapper; @@ -936,6 +943,19 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) { return success(); } +static LogicalResult printOperation(CppEmitter &emitter, TranslationUnitOp tu) { + if (!emitter.shouldEmitTu(tu)) + return success(); + + CppEmitter::Scope scope(emitter); + + for (Operation &op : tu) { + if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false))) + return failure(); + } + return success(); +} + template static LogicalResult printFunctionArgs(CppEmitter &emitter, FuncOpClass functionOp, @@ -1177,8 +1197,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 onlyTu) + : os(os), declareVariablesAtTop(declareVariablesAtTop), + onlyTu(onlyTu.str()) { valueInScopeCount.push(0); labelInScopeCount.push(0); } @@ -1580,8 +1602,8 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) { emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp, - emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp, - emitc::VerbatimOp>( + emitc::TranslationUnitOp, emitc::UnaryMinusOp, + emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>( [&](auto op) { return printOperation(*this, op); }) // Func ops. .Case( @@ -1791,7 +1813,8 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { } LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os, - bool declareVariablesAtTop) { - CppEmitter emitter(os, declareVariablesAtTop); + bool declareVariablesAtTop, + StringRef onlyTu) { + CppEmitter emitter(os, declareVariablesAtTop, onlyTu); return emitter.emitOperation(*op, /*trailingSemicolon=*/false); } diff --git a/mlir/test/Target/Cpp/tu.mlir b/mlir/test/Target/Cpp/tu.mlir new file mode 100644 index 00000000000000..ca10e0263a64fc --- /dev/null +++ b/mlir/test/Target/Cpp/tu.mlir @@ -0,0 +1,29 @@ +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s --check-prefix NO-FILTER +// RUN: mlir-translate -mlir-to-cpp -translation-unit-id=non-existing %s | FileCheck %s --check-prefix NON-EXISTING +// RUN: mlir-translate -mlir-to-cpp -translation-unit-id=tu_one %s | FileCheck %s --check-prefix TU-ONE +// RUN: mlir-translate -mlir-to-cpp -translation-unit-id=tu_two %s | FileCheck %s --check-prefix TU-TWO + + +// NO-FILTER-NOT: func_one +// NO-FILTER-NOT: func_two + +// NON-EXISTING-NOT: func_one +// NON-EXISTING-NOT: func_two + +// TU-ONE: func_one +// TU-ONE-NOT: func_two + +// TU-TWO-NOT: func_one +// TU-TWO: func_two + +emitc.tu "tu_one" { + emitc.func @func_one(%arg: f32) { + emitc.return + } +} + +emitc.tu "tu_two" { + emitc.func @func_two(%arg: f32) { + emitc.return + } +}