Skip to content

Commit a03e89c

Browse files
committed
[mlir][EmitC] Add func, call and return operations
This adds a `func`, `call` and `return` operation to the EmitC dialect, closely related to the corresponding operations of the Func dialect. In contrast to the operations of the Func dialect, the EmitC operations do not support multiple results. The `emitc.func` op features a `specifiers` argument that for example allows, with corresponding support in the emitter, to emit `inline static` functions.
1 parent ba4cf31 commit a03e89c

File tree

9 files changed

+574
-29
lines changed

9 files changed

+574
-29
lines changed

mlir/include/mlir/Dialect/EmitC/IR/EmitC.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "mlir/IR/Dialect.h"
2121
#include "mlir/Interfaces/CastInterfaces.h"
2222
#include "mlir/Interfaces/ControlFlowInterfaces.h"
23+
#include "mlir/Interfaces/FunctionInterfaces.h"
2324
#include "mlir/Interfaces/SideEffectInterfaces.h"
2425

2526
#include "mlir/Dialect/EmitC/IR/EmitCDialect.h.inc"

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

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
include "mlir/Dialect/EmitC/IR/EmitCAttributes.td"
1717
include "mlir/Dialect/EmitC/IR/EmitCTypes.td"
1818

19+
include "mlir/Interfaces/CallInterfaces.td"
1920
include "mlir/Interfaces/CastInterfaces.td"
2021
include "mlir/Interfaces/ControlFlowInterfaces.td"
22+
include "mlir/Interfaces/FunctionInterfaces.td"
2123
include "mlir/Interfaces/SideEffectInterfaces.td"
2224
include "mlir/IR/RegionKindInterface.td"
2325

@@ -386,6 +388,190 @@ def EmitC_ForOp : EmitC_Op<"for",
386388
let hasRegionVerifier = 1;
387389
}
388390

391+
def EmitC_CallOp : EmitC_Op<"call",
392+
[CallOpInterface,
393+
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
394+
let summary = "call operation";
395+
let description = [{
396+
The `emitc.call` operation represents a direct call to an `emitc.func`
397+
that is within the same symbol scope as the call. The operands and result type
398+
of the call must match the specified function type. The callee is encoded as a
399+
symbol reference attribute named "callee".
400+
401+
Example:
402+
403+
```mlir
404+
%2 = emitc.call @my_add(%0, %1) : (f32, f32) -> f32
405+
```
406+
}];
407+
let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$operands);
408+
let results = (outs Variadic<AnyType>);
409+
410+
let builders = [
411+
OpBuilder<(ins "FuncOp":$callee, CArg<"ValueRange", "{}">:$operands), [{
412+
$_state.addOperands(operands);
413+
$_state.addAttribute("callee", SymbolRefAttr::get(callee));
414+
$_state.addTypes(callee.getFunctionType().getResults());
415+
}]>,
416+
OpBuilder<(ins "SymbolRefAttr":$callee, "TypeRange":$results,
417+
CArg<"ValueRange", "{}">:$operands), [{
418+
$_state.addOperands(operands);
419+
$_state.addAttribute("callee", callee);
420+
$_state.addTypes(results);
421+
}]>,
422+
OpBuilder<(ins "StringAttr":$callee, "TypeRange":$results,
423+
CArg<"ValueRange", "{}">:$operands), [{
424+
build($_builder, $_state, SymbolRefAttr::get(callee), results, operands);
425+
}]>,
426+
OpBuilder<(ins "StringRef":$callee, "TypeRange":$results,
427+
CArg<"ValueRange", "{}">:$operands), [{
428+
build($_builder, $_state, StringAttr::get($_builder.getContext(), callee),
429+
results, operands);
430+
}]>];
431+
432+
let extraClassDeclaration = [{
433+
FunctionType getCalleeType();
434+
435+
/// Get the argument operands to the called function.
436+
operand_range getArgOperands() {
437+
return {arg_operand_begin(), arg_operand_end()};
438+
}
439+
440+
MutableOperandRange getArgOperandsMutable() {
441+
return getOperandsMutable();
442+
}
443+
444+
operand_iterator arg_operand_begin() { return operand_begin(); }
445+
operand_iterator arg_operand_end() { return operand_end(); }
446+
447+
/// Return the callee of this operation.
448+
CallInterfaceCallable getCallableForCallee() {
449+
return (*this)->getAttrOfType<SymbolRefAttr>("callee");
450+
}
451+
452+
/// Set the callee for this operation.
453+
void setCalleeFromCallable(CallInterfaceCallable callee) {
454+
(*this)->setAttr("callee", callee.get<SymbolRefAttr>());
455+
}
456+
}];
457+
458+
let assemblyFormat = [{
459+
$callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
460+
}];
461+
}
462+
463+
def EmitC_FuncOp : EmitC_Op<"func", [
464+
AutomaticAllocationScope,
465+
FunctionOpInterface, IsolatedFromAbove
466+
]> {
467+
let summary = "An operation with a name containing a single `SSACFG` region";
468+
let description = [{
469+
Operations within the function cannot implicitly capture values defined
470+
outside of the function, i.e. Functions are `IsolatedFromAbove`. All
471+
external references must use function arguments or attributes that establish
472+
a symbolic connection (e.g. symbols referenced by name via a string
473+
attribute like SymbolRefAttr). While the MLIR textual form provides a nice
474+
inline syntax for function arguments, they are internally represented as
475+
“block arguments” to the first block in the region.
476+
477+
Only dialect attribute names may be specified in the attribute dictionaries
478+
for function arguments, results, or the function itself.
479+
480+
Example:
481+
482+
```mlir
483+
// A function with no results:
484+
emitc.func @foo(%arg0 : i32) {
485+
emitc.call_opaque "bar" (%arg0) : (i32) -> ()
486+
emitc.return
487+
}
488+
489+
// A function with its argument as single result:
490+
emitc.func @foo(%arg0 : i32) -> i32 {
491+
emitc.return %arg0 : i32
492+
}
493+
494+
// A function with specifiers attribute:
495+
emitc.func @example_specifiers_fn_attr() -> i32
496+
attributes {specifiers = ["static","inline"]} {
497+
%0 = emitc.call_opaque "foo" (): () -> i32
498+
emitc.return %0 : i32
499+
}
500+
501+
```
502+
}];
503+
let arguments = (ins SymbolNameAttr:$sym_name,
504+
TypeAttrOf<FunctionType>:$function_type,
505+
OptionalAttr<StrArrayAttr>:$specifiers,
506+
OptionalAttr<DictArrayAttr>:$arg_attrs,
507+
OptionalAttr<DictArrayAttr>:$res_attrs);
508+
let regions = (region AnyRegion:$body);
509+
510+
let builders = [OpBuilder<(ins
511+
"StringRef":$name, "FunctionType":$type,
512+
CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
513+
CArg<"ArrayRef<DictionaryAttr>", "{}">:$argAttrs)
514+
>];
515+
let extraClassDeclaration = [{
516+
/// Create a deep copy of this function and all of its blocks, remapping any
517+
/// operands that use values outside of the function using the map that is
518+
/// provided (leaving them alone if no entry is present). If the mapper
519+
/// contains entries for function arguments, these arguments are not
520+
/// included in the new function. Replaces references to cloned sub-values
521+
/// with the corresponding value that is copied, and adds those mappings to
522+
/// the mapper.
523+
FuncOp clone(IRMapping &mapper);
524+
FuncOp clone();
525+
526+
/// Clone the internal blocks and attributes from this function into dest.
527+
/// Any cloned blocks are appended to the back of dest. This function
528+
/// asserts that the attributes of the current function and dest are
529+
/// compatible.
530+
void cloneInto(FuncOp dest, IRMapping &mapper);
531+
532+
//===------------------------------------------------------------------===//
533+
// FunctionOpInterface Methods
534+
//===------------------------------------------------------------------===//
535+
536+
/// Returns the region on the current operation that is callable. This may
537+
/// return null in the case of an external callable object, e.g. an external
538+
/// function.
539+
::mlir::Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
540+
541+
/// Returns the argument types of this function.
542+
ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }
543+
544+
/// Returns the result types of this function.
545+
ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
546+
}];
547+
let hasCustomAssemblyFormat = 1;
548+
let hasVerifier = 1;
549+
}
550+
551+
def EmitC_ReturnOp : EmitC_Op<"return", [Pure, HasParent<"FuncOp">,
552+
ReturnLike, Terminator]> {
553+
let summary = "Function return operation";
554+
let description = [{
555+
The `emitc.return` operation represents a return operation within a function.
556+
The operation takes zero or exactly one operand and produces no results.
557+
The operand number and type must match the signature of the function
558+
that contains the operation.
559+
560+
Example:
561+
562+
```mlir
563+
emitc.func @foo() : (i32) {
564+
...
565+
emitc.return %0 : i32
566+
}
567+
```
568+
}];
569+
let arguments = (ins Optional<AnyType>:$operand);
570+
571+
let assemblyFormat = "attr-dict ($operand^ `:` type($operand))?";
572+
let hasVerifier = 1;
573+
}
574+
389575
def EmitC_IncludeOp
390576
: EmitC_Op<"include", [HasParent<"ModuleOp">]> {
391577
let summary = "Include operation";

mlir/lib/Dialect/EmitC/IR/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ add_mlir_dialect_library(MLIREmitCDialect
99
MLIREmitCAttributesIncGen
1010

1111
LINK_LIBS PUBLIC
12+
MLIRCallInterfaces
1213
MLIRCastInterfaces
1314
MLIRControlFlowInterfaces
15+
MLIRFunctionInterfaces
1416
MLIRIR
1517
MLIRSideEffectInterfaces
1618
)

0 commit comments

Comments
 (0)