Skip to content

Commit 9a87c5d

Browse files
authored
[mlir][EmitC] Add support for external functions (#80547)
This adds a conversion from an externaly defined `func.func`, a `func.func` without function body, to an `emitc.func` with an `extern` specifier.
1 parent 702664e commit 9a87c5d

File tree

8 files changed

+50
-26
lines changed

8 files changed

+50
-26
lines changed

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ def EmitC_FuncOp : EmitC_Op<"func", [
498498
emitc.return %0 : i32
499499
}
500500

501+
// An external function definition:
502+
emitc.func private @extern_func(i32)
503+
attributes {specifiers = ["extern"]}
501504
```
502505
}];
503506
let arguments = (ins SymbolNameAttr:$sym_name,

mlir/lib/Conversion/FuncToEmitC/FuncToEmitC.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ class FuncOpConversion final : public OpConversionPattern<func::FuncOp> {
5757
return rewriter.notifyMatchFailure(
5858
funcOp, "only functions with zero or one result can be converted");
5959

60-
if (funcOp.isDeclaration())
61-
return rewriter.notifyMatchFailure(funcOp,
62-
"declarations cannot be converted");
63-
6460
// Create the converted `emitc.func` op.
6561
emitc::FuncOp newFuncOp = rewriter.create<emitc::FuncOp>(
6662
funcOp.getLoc(), funcOp.getName(), funcOp.getFunctionType());
@@ -72,14 +68,22 @@ class FuncOpConversion final : public OpConversionPattern<func::FuncOp> {
7268
newFuncOp->setAttr(namedAttr.getName(), namedAttr.getValue());
7369
}
7470

75-
// Add `static` to specifiers if `func.func` is private.
76-
if (funcOp.isPrivate()) {
71+
// Add `extern` to specifiers if `func.func` is declaration only.
72+
if (funcOp.isDeclaration()) {
73+
ArrayAttr specifiers = rewriter.getStrArrayAttr({"extern"});
74+
newFuncOp.setSpecifiersAttr(specifiers);
75+
}
76+
77+
// Add `static` to specifiers if `func.func` is private but not a
78+
// declaration.
79+
if (funcOp.isPrivate() && !funcOp.isDeclaration()) {
7780
ArrayAttr specifiers = rewriter.getStrArrayAttr({"static"});
7881
newFuncOp.setSpecifiersAttr(specifiers);
7982
}
8083

81-
rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
82-
newFuncOp.end());
84+
if (!funcOp.isDeclaration())
85+
rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
86+
newFuncOp.end());
8387
rewriter.eraseOp(funcOp);
8488

8589
return success();

mlir/lib/Dialect/EmitC/IR/EmitC.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,6 @@ LogicalResult FuncOp::verify() {
437437
return emitOpError("requires zero or exactly one result, but has ")
438438
<< getNumResults();
439439

440-
if (isExternal())
441-
return emitOpError("does not support empty function bodies");
442-
443440
return success();
444441
}
445442

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -773,19 +773,27 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
773773

774774
static LogicalResult printFunctionArgs(CppEmitter &emitter,
775775
Operation *functionOp,
776-
Region::BlockArgListType arguments) {
776+
ArrayRef<Type> arguments) {
777777
raw_indented_ostream &os = emitter.ostream();
778778

779-
if (failed(interleaveCommaWithError(
780-
arguments, os, [&](BlockArgument arg) -> LogicalResult {
781-
if (failed(emitter.emitType(functionOp->getLoc(), arg.getType())))
782-
return failure();
783-
os << " " << emitter.getOrCreateName(arg);
784-
return success();
785-
})))
786-
return failure();
779+
return (
780+
interleaveCommaWithError(arguments, os, [&](Type arg) -> LogicalResult {
781+
return emitter.emitType(functionOp->getLoc(), arg);
782+
}));
783+
}
787784

788-
return success();
785+
static LogicalResult printFunctionArgs(CppEmitter &emitter,
786+
Operation *functionOp,
787+
Region::BlockArgListType arguments) {
788+
raw_indented_ostream &os = emitter.ostream();
789+
790+
return (interleaveCommaWithError(
791+
arguments, os, [&](BlockArgument arg) -> LogicalResult {
792+
if (failed(emitter.emitType(functionOp->getLoc(), arg.getType())))
793+
return failure();
794+
os << " " << emitter.getOrCreateName(arg);
795+
return success();
796+
}));
789797
}
790798

791799
static LogicalResult printFunctionBody(CppEmitter &emitter,
@@ -913,6 +921,13 @@ static LogicalResult printOperation(CppEmitter &emitter,
913921

914922
os << "(";
915923
Operation *operation = functionOp.getOperation();
924+
if (functionOp.isExternal()) {
925+
if (failed(printFunctionArgs(emitter, operation,
926+
functionOp.getArgumentTypes())))
927+
return failure();
928+
os << ");";
929+
return success();
930+
}
916931
if (failed(printFunctionArgs(emitter, operation, functionOp.getArguments())))
917932
return failure();
918933
os << ") {\n";

mlir/test/Conversion/FuncToEmitC/func-to-emitc.mlir

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,8 @@ func.func @call(%arg0: i32) -> i32 {
5353
%0 = call @return_i32(%arg0) : (i32) -> (i32)
5454
return %0 : i32
5555
}
56+
57+
// -----
58+
59+
// CHECK-LABEL: emitc.func private @return_i32(i32) -> i32 attributes {specifiers = ["extern"]}
60+
func.func private @return_i32(%arg0: i32) -> i32

mlir/test/Dialect/EmitC/invalid_ops.mlir

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,3 @@ func.func @return_inside_func.func(%0: i32) -> (i32) {
321321

322322
// expected-error@+1 {{expected non-function type}}
323323
emitc.func @func_variadic(...)
324-
325-
// -----
326-
327-
// expected-error@+1 {{'emitc.func' op does not support empty function bodies}}
328-
emitc.func private @empty()

mlir/test/Dialect/EmitC/ops.mlir

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ emitc.func @call() -> i32 {
3030
emitc.return %0 : i32
3131
}
3232

33+
emitc.func private @extern(i32) attributes {specifiers = ["extern"]}
34+
3335
func.func @cast(%arg0: i32) {
3436
%1 = emitc.cast %arg0: i32 to f32
3537
return

mlir/test/Target/Cpp/func.mlir

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ emitc.func @emitc_call() -> i32 {
3737
// CPP-DECLTOP-NEXT: int32_t [[V0:[^ ]*]];
3838
// CPP-DECLTOP-NEXT: [[V0:[^ ]*]] = return_i32();
3939
// CPP-DECLTOP-NEXT: return [[V0:[^ ]*]];
40+
41+
emitc.func private @extern_func(i32) attributes {specifiers = ["extern"]}
42+
// CPP-DEFAULT: extern void extern_func(int32_t);

0 commit comments

Comments
 (0)