Skip to content
Closed
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
6 changes: 6 additions & 0 deletions xls/contrib/mlir/IR/xls_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,12 @@ LogicalResult SprocOp::verify() {
}
}

if (getIsTop() && !getChannelArguments().empty()) {
if (!getBoundaryChannels().has_value()) {
return emitOpError() << "top sprocs must have boundary channels";
}
}

return success();
}

Expand Down
25 changes: 21 additions & 4 deletions xls/contrib/mlir/IR/xls_ops.td
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,24 @@ def Xls_FifoConfig : Xls_Attr<"FifoConfig"> {
let assemblyFormat = "`<` struct(params) `>`";
}

def Xls_BoundaryChannelAttr : Xls_Attr<"BoundaryChannelAttr"> {
let summary = "Boundary channel attribute";
let description = [{
Contains attributes associated with boundary channels for SprocOps.
}];
let parameters = (ins
"::mlir::StringAttr":$name,
OptionalParameter<"FifoConfig", "">:$fifo_config,
OptionalParameter<"FlopKindAttr", "">:$input_flop_kind,
OptionalParameter<"FlopKindAttr", "">:$output_flop_kind
);
let mnemonic = "boundary_channel";
let assemblyFormat = "`<` struct(params) `>`";
}

def Xls_BoundaryChannelArrayAttr :
TypedArrayAttrBase<Xls_BoundaryChannelAttr, "array of boundary_channel">;

class GetShapeSplat<string name> :
StrFunc<"getShapeSplat($" # name # ".getType())">;

Expand Down Expand Up @@ -1874,9 +1892,8 @@ def Xls_SprocOp : Xls_Op<"sproc", [
region contains Schan declarations and "spawns" of other Sprocs. The only way
to create an Sproc is to spawn another Sproc.

Sprocs may be marked as "top" if they EITHER:
a) Have no channels.
b) Have the optional `boundary_channel_names` attribute set.
Sprocs may be marked as "top" if they populate the `boundary_channels`
list per argument.

In the latter case, boundary channels (used by XLS for tests etc) are
created with the given names.
Expand Down Expand Up @@ -1926,7 +1943,7 @@ def Xls_SprocOp : Xls_Op<"sproc", [
let arguments = (ins
SymbolNameAttr:$sym_name,
BoolAttr:$is_top,
OptionalAttr<ArrayAttr>:$boundary_channel_names,
OptionalAttr<Xls_BoundaryChannelArrayAttr>:$boundary_channels,
DefaultValuedAttr<I64Attr, "1">:$min_pipeline_stages
);
let regions = (region
Expand Down
2 changes: 1 addition & 1 deletion xls/contrib/mlir/testdata/arith_to_xls.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ func.func @negate(%arg0: bf16) -> bf16 attributes { "xls" = true } {
// CHECK: next (
// CHECK-NEXT: %[[X:.*]] = xls.add
// CHECK-NEXT: xls.yield %[[X]] : i32
xls.sproc @sproc(%arg0: !xls.schan<i32, in>) top {
xls.sproc @sproc(%arg0: !xls.schan<i32, in>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
xls.yield
}
Expand Down
2 changes: 1 addition & 1 deletion xls/contrib/mlir/testdata/extract_as_top_level_module.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ module attributes {test.name = "sproc"} {
// CHECK-NOT: func @nope
// CHECK: xls.sproc @leaf
// CHECK-NOT: xls.sproc @unrelated
// CHECK: xls.sproc @sproc(%arg0: !xls.schan<i32, in>) top attributes {boundary_channel_names = ["arg0"]}
// CHECK: xls.sproc @sproc(%arg0: !xls.schan<i32, in>) top attributes {boundary_channels = [#xls.boundary_channel<name = "arg0">]}
func.func @nope(%arg0: !xls.token, %arg1: i32, %arg2: i1) ->i32 {
%0 = arith.constant 1 : i32
return %0 : i32
Expand Down
16 changes: 8 additions & 8 deletions xls/contrib/mlir/testdata/optimize_spawns.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ xls.sproc @fn2(%arg0: !xls.schan<tensor<8xi32>, out>) {
}

// Consumes an argument and passes to a spawn.
// CHECK: xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top {
// CHECK: xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top
// CHECK: spawns {
// CHECK: %out, %in = xls.schan<tensor<8xi32>>("x")
// CHECK: xls.spawn @fn(%arg0) : !xls.schan<tensor<8xi32>, in>
Expand All @@ -29,7 +29,7 @@ xls.sproc @fn2(%arg0: !xls.schan<tensor<8xi32>, out>) {
// CHECK: xls.yield
// CHECK: }
// CHECK: }
xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top {
xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
%out, %in = xls.schan<tensor<8xi32>>("x")
xls.spawn @fn(%in) : !xls.schan<tensor<8xi32>, in>
Expand All @@ -45,7 +45,7 @@ xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top {
}

// Produces a result from a spawn.
// CHECK: xls.sproc @produce_result(%arg0: !xls.schan<tensor<8xi32>, out>) top {
// CHECK: xls.sproc @produce_result(%arg0: !xls.schan<tensor<8xi32>, out>) top
// CHECK: spawns {
// CHECK: %out, %in = xls.schan<tensor<8xi32>>("x")
// CHECK: xls.spawn @fn2(%arg0) : !xls.schan<tensor<8xi32>, out>
Expand All @@ -55,7 +55,7 @@ xls.sproc @consume_arg(%arg0: !xls.schan<tensor<8xi32>, in>) top {
// CHECK: xls.yield
// CHECK: }
// CHECK: }
xls.sproc @produce_result(%arg0: !xls.schan<tensor<8xi32>, out>) top {
xls.sproc @produce_result(%arg0: !xls.schan<tensor<8xi32>, out>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
%out, %in = xls.schan<tensor<8xi32>>("x")
xls.spawn @fn2(%out) : !xls.schan<tensor<8xi32>, out>
Expand Down Expand Up @@ -194,13 +194,13 @@ xls.sproc @unused_args(%arg0: !xls.schan<tensor<8xi32>, in>) {

// Consumes an argument and passes to a spawn. The interior channel has a
// FifoConfig so can't be eliminated.
// CHECK: xls.sproc @consume_arg_fifo(%arg0: !xls.schan<tensor<8xi32>, in>) top {
// CHECK: xls.sproc @consume_arg_fifo(%arg0: !xls.schan<tensor<8xi32>, in>) top
// CHECK: spawns {
// CHECK: %out, %in = xls.schan<tensor<8xi32>>("x") attributes {fifo_config
// CHECK: xls.spawn @fn(%in) : !xls.schan<tensor<8xi32>, in>
// CHECK: xls.yield %arg0, %out
// CHECK: }
xls.sproc @consume_arg_fifo(%arg0: !xls.schan<tensor<8xi32>, in>) top {
xls.sproc @consume_arg_fifo(%arg0: !xls.schan<tensor<8xi32>, in>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
%out, %in = xls.schan<tensor<8xi32>>("x") attributes {fifo_config = #fifo}
xls.spawn @fn(%in) : !xls.schan<tensor<8xi32>, in>
Expand All @@ -217,13 +217,13 @@ xls.sproc @consume_arg_fifo(%arg0: !xls.schan<tensor<8xi32>, in>) top {

// Produces a result from a spawn. The interior channel has a FifoConfig so
// can't be eliminated.
// CHECK: xls.sproc @produce_result_fifo(%arg0: !xls.schan<tensor<8xi32>, out>) top {
// CHECK: xls.sproc @produce_result_fifo(%arg0: !xls.schan<tensor<8xi32>, out>) top
// CHECK: spawns {
// CHECK: %out, %in = xls.schan<tensor<8xi32>>("x") attributes {fifo_config
// CHECK: xls.spawn @fn2(%out) : !xls.schan<tensor<8xi32>, out>
// CHECK: xls.yield %in, %arg0
// CHECK: }
xls.sproc @produce_result_fifo(%arg0: !xls.schan<tensor<8xi32>, out>) top {
xls.sproc @produce_result_fifo(%arg0: !xls.schan<tensor<8xi32>, out>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
%out, %in = xls.schan<tensor<8xi32>>("x") attributes {fifo_config = #fifo}
xls.spawn @fn2(%out) : !xls.schan<tensor<8xi32>, out>
Expand Down
11 changes: 8 additions & 3 deletions xls/contrib/mlir/testdata/proc_elaboration.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
// CHECK-NEXT: xls.chan @fetch_arg0 : i32
// CHECK-NEXT: xls.chan @fetch_arg1 : i32
// CHECK-NEXT: xls.instantiate_eproc @fetch (@fetch_arg0 as @req, @fetch_arg1 as @resp)
// CHECK-NEXT: xls.chan @boundary1 {send_supported = false} : i32
// CHECK-NEXT: xls.chan @boundary1 {fifo_config = #xls.fifo_config<fifo_depth = 1, bypass = true, register_push_outputs = true, register_pop_outputs = false>, input_flop_kind = #xls<flop_kind skid>, send_supported = false} : i32
// CHECK-NEXT: xls.chan @boundary2 {recv_supported = false} : i32
// CHECK-NEXT: xls.instantiate_eproc @rom (@rom_arg0 as @boundary1, @rom_arg1 as @boundary2)

Expand Down Expand Up @@ -77,7 +77,10 @@ xls.sproc @proxy(%req: !xls.schan<i32, in>, %resp: !xls.schan<i32, out>) attribu
}
}

xls.sproc @rom(%req: !xls.schan<i32, in>, %resp: !xls.schan<i32, out>) top attributes {boundary_channel_names = ["boundary1", "boundary2"]} {
xls.sproc @rom(%req: !xls.schan<i32, in>, %resp: !xls.schan<i32, out>) top attributes {boundary_channels = [
#xls.boundary_channel<name = "boundary1", fifo_config = #xls.fifo_config<fifo_depth = 1, bypass = true, register_push_outputs = true, register_pop_outputs = false>, input_flop_kind = #xls<flop_kind skid>>,
#xls.boundary_channel<name = "boundary2">
]} {
spawns {
xls.yield %req, %resp : !xls.schan<i32, in>, !xls.schan<i32, out>
}
Expand Down Expand Up @@ -144,7 +147,9 @@ module {
xls.yield %0 : index
}
}
xls.sproc @some_wrapped_machine(%arg0: !xls.schan<tensor<i32>, in>, %arg1: !xls.schan<tensor<i32>, out>, %arg2: !xls.schan<tensor<i32>, out>) top attributes {boundary_channel_names = ["x['y']", "x['y']1", "x['y']2"]} {
xls.sproc @some_wrapped_machine(%arg0: !xls.schan<tensor<i32>, in>, %arg1: !xls.schan<tensor<i32>, out>, %arg2: !xls.schan<tensor<i32>, out>) top attributes {
boundary_channels = [#xls.boundary_channel<name = "x['y']">, #xls.boundary_channel<name = "x['y']1">, #xls.boundary_channel<name = "x['y']2">]
} {
spawns {
%out, %in = xls.schan<tensor<i32>>("x['y']")
%out_0, %in_1 = xls.schan<tensor<i32>>("x['y']")
Expand Down
2 changes: 1 addition & 1 deletion xls/contrib/mlir/testdata/symbol_dce.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ xls.sproc @sproc(%arg0: !xls.schan<i32, in>) {
// CHECK: @top_sproc
// CHECK: @top_extern_sproc
xls.extern_sproc @top_extern_sproc (arg0: !xls.schan<i32, in>)
xls.sproc @top_sproc(%arg0: !xls.schan<i32, in>) top {
xls.sproc @top_sproc(%arg0: !xls.schan<i32, in>) top attributes { boundary_channels = [#xls.boundary_channel<name = "arg0">] } {
spawns {
xls.spawn @top_extern_sproc(%arg0) : !xls.schan<i32, in>
xls.yield
Expand Down
22 changes: 13 additions & 9 deletions xls/contrib/mlir/transforms/proc_elaboration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,18 +323,19 @@ void ProcElaborationPass::runOnOperation() {

OpBuilder builder(sproc);
SmallVector<ChanOp> boundaryChannels;
if (sproc.getBoundaryChannelNames().has_value()) {
for (auto [arg, name] : llvm::zip(sproc.getChannelArguments(),
*sproc.getBoundaryChannelNames())) {
if (sproc.getBoundaryChannels().has_value()) {
for (auto [arg, boundaryChannelAttr] : llvm::zip(
sproc.getChannelArguments(), *sproc.getBoundaryChannels())) {
SchanType schan = cast<SchanType>(arg.getType());
auto nameAttr = cast<StringAttr>(name);
auto boundaryChannel = cast<BoundaryChannelAttr>(boundaryChannelAttr);
auto nameAttr = boundaryChannel.getName();
// TODO(jpienaar): Remove unnecessary default args once they are
// generated automatically.
auto echan = ChanOp::create(builder, sproc.getLoc(), nameAttr.str(),
schan.getElementType(),
/*fifo_config=*/nullptr,
/*input_flop_kind=*/nullptr,
/*output_flop_kind=*/nullptr);
auto echan = ChanOp::create(
builder, sproc.getLoc(), boundaryChannel.getName(),
schan.getElementType(), boundaryChannel.getFifoConfig(),
boundaryChannel.getInputFlopKind(),
boundaryChannel.getOutputFlopKind());
// We insert the channel in the symbol table, since there might be
// a clash with an *eproc* name later, so we need to know. Alternatively
// we could have done something similar in the constructor of the
Expand All @@ -351,6 +352,9 @@ void ProcElaborationPass::runOnOperation() {
}
boundaryChannels.push_back(echan);
}
} else if (!sproc.getChannelArguments().empty()) {
sproc.emitError() << "top sproc has channel arguments but no boundary "
"channels. This is not supported.";
}

ElaborationInterpreter interpreter;
Expand Down
13 changes: 8 additions & 5 deletions xls/contrib/mlir/util/extraction_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,19 @@ void addBoundaryChannelNames(
};
}

if (op.getBoundaryChannelNames().has_value()) {
if (op.getBoundaryChannels().has_value()) {
return;
}
::mlir::OpBuilder builder(op.getOperation());
::mlir::SmallVector<::mlir::Attribute> boundaryChannelNames;
::mlir::SmallVector<::mlir::Attribute> boundaryChannels;
for (Value value : op.getChannelArguments()) {
boundaryChannelNames.push_back(
builder.getStringAttr(boundaryChannelName(cast<BlockArgument>(value))));
BoundaryChannelAttr boundaryChannel = BoundaryChannelAttr::get(
builder.getContext(),
builder.getStringAttr(boundaryChannelName(cast<BlockArgument>(value))),
FifoConfig(), FlopKindAttr(), FlopKindAttr());
boundaryChannels.push_back(boundaryChannel);
}
op.setBoundaryChannelNamesAttr(builder.getArrayAttr(boundaryChannelNames));
op.setBoundaryChannelsAttr(builder.getArrayAttr(boundaryChannels));
}
} // namespace

Expand Down