Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ibis] Add ibis.method.df operation #6163

Merged
merged 1 commit into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/circt/Dialect/Ibis/IbisOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef CIRCT_DIALECT_IBIS_IBISOPS_H
#define CIRCT_DIALECT_IBIS_IBISOPS_H

#include "circt/Dialect/Handshake/HandshakeInterfaces.h"
#include "circt/Dialect/Ibis/IbisDialect.h"
#include "circt/Dialect/Ibis/IbisTypes.h"
#include "circt/Support/InstanceGraphInterface.h"
Expand Down
59 changes: 44 additions & 15 deletions include/circt/Dialect/Ibis/IbisOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/IR/BuiltinAttributeInterfaces.td"

include "circt/Dialect/Handshake/HandshakeInterfaces.td"
include "circt/Dialect/HW/HWOpInterfaces.td"
include "circt/Dialect/Ibis/IbisInterfaces.td"
include "circt/Dialect/Ibis/IbisTypes.td"
Expand Down Expand Up @@ -136,30 +137,23 @@ def InstanceOp : InstanceOpBase<"instance"> {
}];
}

def MethodOp : IbisOp<"method", [

class MethodOpBase<string mnemonic, list<Trait> traits = []> :
IbisOp<mnemonic, !listconcat(traits, [
IsolatedFromAbove,
Symbol, FunctionOpInterface,
AutomaticAllocationScope,
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmBlockArgumentNames"]>,
HasParent<"ClassOp">]> {

let summary = "Ibis method";
let description = [{
Ibis functions are a lot like software functions: a list of named arguments
and unnamed return values.

Can only live inside of classes.
}];
HasParent<"ClassOp">
])> {

let arguments = (ins SymbolNameAttr:$sym_name,
TypeAttrOf<FunctionType>:$function_type,
ArrayAttr:$argNames,
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs);
let regions = (region AnyRegion:$body);
let hasCustomAssemblyFormat = 1;

let extraClassDeclaration = [{
code extraMethodClassDeclaration = "";
let extraClassDeclaration = extraMethodClassDeclaration # [{
//===------------------------------------------------------------------===//
// FunctionOpInterface Methods
//===------------------------------------------------------------------===//
Expand All @@ -179,8 +173,43 @@ def MethodOp : IbisOp<"method", [
}];
}

def MethodOp : MethodOpBase<"method", [
AutomaticAllocationScope,
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmBlockArgumentNames"]>
]> {

let summary = "Ibis method";
let description = [{
Ibis methods are a lot like software functions: a list of named arguments
and unnamed return values with imperative control flow.
}];

let regions = (region AnyRegion:$body);
}

def DataflowMethodOp : MethodOpBase<"method.df", [
SingleBlockImplicitTerminator<"ibis::ReturnOp">,
RegionKindInterface,
FineGrainedDataflowRegionOpInterface
]> {

let summary = "Ibis dataflow method";
let description = [{
Ibis dataflow methods share the same interface as an `ibis.method` but
without imperative CFG-based control flow. Instead, this method implements a
graph region, and control flow is expected to be defined by dataflow operations.
}];
let regions = (region SizedRegion<1>:$body);

let extraMethodClassDeclaration = [{
// Implement RegionKindInterface.
static RegionKind getRegionKind(unsigned index) { return RegionKind::Graph; }
}];
}

def ReturnOp : IbisOp<"return", [
Pure, ReturnLike, Terminator, HasParent<"MethodOp">]> {
Pure, ReturnLike, Terminator,
ParentOneOf<["MethodOp", "DataflowMethodOp"]>]> {
let summary = "Ibis method terminator";

let arguments = (ins Variadic<AnyType>:$retValues);
Expand Down
46 changes: 35 additions & 11 deletions lib/Dialect/Ibis/IbisOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ LogicalResult circt::ibis::detail::verifyScopeOpInterface(Operation *op) {
// MethodOp
//===----------------------------------------------------------------------===//

ParseResult MethodOp::parse(OpAsmParser &parser, OperationState &result) {
template <typename TOp>
ParseResult parseMethodLikeOp(OpAsmParser &parser, OperationState &result) {
// Parse the name as a symbol.
StringAttr nameAttr;
if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
Expand Down Expand Up @@ -163,8 +164,7 @@ ParseResult MethodOp::parse(OpAsmParser &parser, OperationState &result) {
return failure();

result.addAttribute("argNames", ArrayAttr::get(context, argNames));
result.addAttribute(MethodOp::getFunctionTypeAttrName(result.name),
functionType);
result.addAttribute(TOp::getFunctionTypeAttrName(result.name), functionType);

// Parse the function body.
auto *body = result.addRegion();
Expand All @@ -174,22 +174,29 @@ ParseResult MethodOp::parse(OpAsmParser &parser, OperationState &result) {
return success();
}

void MethodOp::print(OpAsmPrinter &p) {
FunctionType funcTy = getFunctionType();
template <typename TOp>
void printMethodLikeOp(TOp op, OpAsmPrinter &p) {
FunctionType funcTy = op.getFunctionType();
p << ' ';
p.printSymbolName(getSymName());
p.printSymbolName(op.getSymName());
function_interface_impl::printFunctionSignature(
p, *this, funcTy.getInputs(), /*isVariadic=*/false, funcTy.getResults());
p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
getAttributeNames());
Region &body = getBody();
p, op, funcTy.getInputs(), /*isVariadic=*/false, funcTy.getResults());
p.printOptionalAttrDictWithKeyword(op.getOperation()->getAttrs(),
op.getAttributeNames());
Region &body = op.getBody();
if (!body.empty()) {
p << ' ';
p.printRegion(body, /*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/true);
}
}

ParseResult MethodOp::parse(OpAsmParser &parser, OperationState &result) {
return parseMethodLikeOp<MethodOp>(parser, result);
}

void MethodOp::print(OpAsmPrinter &p) { return printMethodLikeOp(*this, p); }

void MethodOp::getAsmBlockArgumentNames(mlir::Region &region,
OpAsmSetValueNameFn setNameFn) {
if (region.empty())
Expand All @@ -204,11 +211,28 @@ void MethodOp::getAsmBlockArgumentNames(mlir::Region &region,
setNameFn(block->getArgument(idx), argName);
}

//===----------------------------------------------------------------------===//
// DataflowMethodOp
//===----------------------------------------------------------------------===//

ParseResult DataflowMethodOp::parse(OpAsmParser &parser,
OperationState &result) {
return parseMethodLikeOp<DataflowMethodOp>(parser, result);
}

void DataflowMethodOp::print(OpAsmPrinter &p) {
return printMethodLikeOp(*this, p);
}

//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//

void ReturnOp::build(OpBuilder &odsBuilder, OperationState &odsState) {}

LogicalResult ReturnOp::verify() {
// Check that the return operand type matches the function return type.
auto func = cast<MethodOp>((*this)->getParentOp());
auto func = cast<FunctionOpInterface>((*this)->getParentOp());
ArrayRef<Type> resTypes = func.getResultTypes();

if (getNumOperands() != resTypes.size())
Expand Down
9 changes: 9 additions & 0 deletions test/Dialect/Ibis/round-trip.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
// CHECK-NEXT: }
// CHECK-NEXT: ibis.return %0#0, %0#1 : i32, i32
// CHECK-NEXT: }
// CHECK-NEXT: ibis.method.df @bar(%arg0: none) -> none {
// CHECK-NEXT: %0 = handshake.join %arg0 : none
// CHECK-NEXT: ibis.return %0 : none
// CHECK-NEXT: }
// CHECK-NEXT: }

ibis.class @HighLevel {
Expand All @@ -39,6 +43,11 @@ ibis.class @HighLevel {
}
ibis.return %out1, %out2 : i32, i32
}

ibis.method.df @bar(%arg0 : none) -> (none) {
%0 = handshake.join %arg0 : none
ibis.return %0 : none
}
}


Expand Down