Skip to content

Commit ed20cea

Browse files
marbremgehre-amd
authored andcommitted
[mlir][EmitC] Add support for external functions (llvm#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 0bcc782 commit ed20cea

File tree

8 files changed

+43
-16
lines changed

8 files changed

+43
-16
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
@@ -438,9 +438,6 @@ LogicalResult FuncOp::verify() {
438438
return emitOpError("requires zero or exactly one result, but has ")
439439
<< getNumResults();
440440

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

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,17 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
784784
return success();
785785
}
786786

787+
static LogicalResult printFunctionArgs(CppEmitter &emitter,
788+
Operation *functionOp,
789+
ArrayRef<Type> arguments) {
790+
raw_indented_ostream &os = emitter.ostream();
791+
792+
return (
793+
interleaveCommaWithError(arguments, os, [&](Type arg) -> LogicalResult {
794+
return emitter.emitType(functionOp->getLoc(), arg);
795+
}));
796+
}
797+
787798
static LogicalResult printFunctionArgs(CppEmitter &emitter,
788799
Operation *functionOp,
789800
Region::BlockArgListType arguments) {
@@ -925,6 +936,13 @@ static LogicalResult printOperation(CppEmitter &emitter,
925936

926937
os << "(";
927938
Operation *operation = functionOp.getOperation();
939+
if (functionOp.isExternal()) {
940+
if (failed(printFunctionArgs(emitter, operation,
941+
functionOp.getArgumentTypes())))
942+
return failure();
943+
os << ");";
944+
return success();
945+
}
928946
if (failed(printFunctionArgs(emitter, operation, functionOp.getArguments())))
929947
return failure();
930948
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
@@ -329,8 +329,3 @@ func.func @return_inside_func.func(%0: i32) -> (i32) {
329329

330330
// expected-error@+1 {{expected non-function type}}
331331
emitc.func @func_variadic(...)
332-
333-
// -----
334-
335-
// expected-error@+1 {{'emitc.func' op does not support empty function bodies}}
336-
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)