From f62bc6f0ce6b4286d319434ac0f56e1f0e329ecf Mon Sep 17 00:00:00 2001 From: schilkp Date: Fri, 7 Feb 2025 08:50:39 +0100 Subject: [PATCH] [xls][mlir] Support XLS fifo properties/config in MLIR channels. This also adds support for converting these properties to/from XLS, and updates different passes (array_to_bits, index_type_conversion) to ensure these attributes are maintained when channels are modified. Finally, these properties are also exposed for sproc channels, and the proc elaboration pass is updated to assign said properties to all eproc channels that are generated from an sproc channel. --- xls/contrib/mlir/IR/xls_ops.cc | 7 ++++ xls/contrib/mlir/IR/xls_ops.td | 38 ++++++++++++++++-- xls/contrib/mlir/testdata/array_to_bits.mlir | 4 +- .../mlir/testdata/index_type_conversion.mlir | 6 +-- .../mlir/testdata/proc_elaboration.mlir | 4 +- xls/contrib/mlir/testdata/translate_chn.mlir | 27 +++++++++++++ .../mlir/testdata/translate_from_xls/proc.ir | 10 ++++- .../xls_translate/xls_translate_from_mlir.cc | 39 ++++++++++++++++++- .../xls_translate/xls_translate_to_mlir.cc | 36 +++++++++++++++++ xls/contrib/mlir/transforms/array_to_bits.cc | 8 ++-- .../mlir/transforms/index_type_conversion.cc | 7 ++-- .../mlir/transforms/proc_elaboration.cc | 17 ++++++-- xls/contrib/mlir/transforms/scalarize.cc | 9 +++-- 13 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 xls/contrib/mlir/testdata/translate_chn.mlir diff --git a/xls/contrib/mlir/IR/xls_ops.cc b/xls/contrib/mlir/IR/xls_ops.cc index 31d1dfc508..4ede398a4f 100644 --- a/xls/contrib/mlir/IR/xls_ops.cc +++ b/xls/contrib/mlir/IR/xls_ops.cc @@ -620,6 +620,11 @@ ParseResult SchanOp::parse(OpAsmParser& parser, OperationState& result) { result.addAttribute("type", TypeAttr::get(type)); result.types.push_back(SchanType::get(parser.getContext(), type, false)); result.types.push_back(SchanType::get(parser.getContext(), type, true)); + + if (parser.parseOptionalAttrDictWithKeyword(result.attributes)) { + return failure(); + } + return success(); } @@ -630,6 +635,8 @@ void SchanOp::print(OpAsmPrinter& printer) { printer << '('; printer.printString(getName()); printer << ')'; + printer << ") "; + printer.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(), {"type", "name"}); } void SprocOp::print(OpAsmPrinter& printer) { diff --git a/xls/contrib/mlir/IR/xls_ops.td b/xls/contrib/mlir/IR/xls_ops.td index 5d4fa6dfef..f42e5aad69 100644 --- a/xls/contrib/mlir/IR/xls_ops.td +++ b/xls/contrib/mlir/IR/xls_ops.td @@ -135,6 +135,33 @@ def Xls_TranslationLinkage : Xls_Attr<"TranslationLinkage"> { let attrName = "xls.translation_linkage"; } +def Xls_FlopKindNone : I32EnumAttrCase<"kNone", 0, "none">; +def Xls_FlopKindFlop : I32EnumAttrCase<"kFlop", 1, "flop">; +def Xls_FlopKindSkid : I32EnumAttrCase<"kSkid", 2, "skid">; +def Xls_FlopKindZeroLatency : I32EnumAttrCase<"kZeroLatency", 3, "zero-latency">; +def Xls_FlopKind : I32EnumAttr<"FlopKind", "XLS flop kind", + [Xls_FlopKindNone, Xls_FlopKindFlop, Xls_FlopKindSkid, Xls_FlopKindZeroLatency]> { + let genSpecializedAttr = 0; + let cppNamespace = "::mlir::xls"; +} +def Xls_FlopKindAttr : EnumAttr; + +def Xls_FifoConfig : Xls_Attr<"FifoConfig"> { + let summary = "TODO"; + let description = [{TODO}]; + + let parameters = (ins + "int64_t":$fifo_depth, + "bool":$bypass, + "bool":$register_push_outputs, + "bool":$register_pop_outputs + ); + + let mnemonic = "fifo_config"; + + let assemblyFormat = "`<` struct(params) `>`"; +} + class GetShapeSplat : StrFunc<"getShapeSplat($" # name # ".getType())">; @@ -1626,6 +1653,9 @@ def Xls_ChanOp : Xls_Op<"chan", [ let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$type, + OptionalAttr: $fifo_config, + OptionalAttr: $input_flop_kind, + OptionalAttr: $output_flop_kind, DefaultValuedAttr:$send_supported, DefaultValuedAttr:$recv_supported ); @@ -1653,7 +1683,6 @@ def Xls_ChanOp : Xls_Op<"chan", [ void setArgAttrsAttr(ArrayAttr) { return; } void setResAttrsAttr(ArrayAttr) { return; } }]; - } def Xls_InstantiateEprocOp : Xls_Op<"instantiate_eproc", [DeclareOpInterfaceMethods]> { @@ -1753,7 +1782,10 @@ def Xls_SchanOp : Xls_Op<"schan", [Pure, HasParent<"SprocOp">]> { }]; let arguments = (ins StrAttr:$name, - TypeAttr:$type + TypeAttr:$type, + OptionalAttr: $fifo_config, + OptionalAttr: $input_flop_kind, + OptionalAttr: $output_flop_kind ); let results = (outs Xls_SchanType:$out, @@ -1764,7 +1796,7 @@ def Xls_SchanOp : Xls_Op<"schan", [Pure, HasParent<"SprocOp">]> { OpBuilder<(ins "::mlir::StringRef":$name, "::mlir::Type":$element_type), [{ auto inChanTy = SchanType::get($_builder.getContext(), element_type, /*isInput=*/true); auto outChanTy = SchanType::get($_builder.getContext(), element_type, /*isInput=*/false); - build($_builder, $_state, ::mlir::TypeRange{outChanTy, inChanTy}, name, element_type); + build($_builder, $_state, ::mlir::TypeRange{outChanTy, inChanTy}, name, element_type, /*fifo_config=*/nullptr, /*input_flop_kind=*/nullptr, /*output_flop_kind=*/nullptr); }]> ]; } diff --git a/xls/contrib/mlir/testdata/array_to_bits.mlir b/xls/contrib/mlir/testdata/array_to_bits.mlir index ce6a4f1999..2ffeeb579e 100644 --- a/xls/contrib/mlir/testdata/array_to_bits.mlir +++ b/xls/contrib/mlir/testdata/array_to_bits.mlir @@ -215,8 +215,8 @@ func.func @tensor_empty() -> !xls.array<4 x i32> attributes {xls = true} { return %0 : !xls.array<4 x i32> } -// CHECK-LABEL: xls.chan @mychan : i24 -xls.chan @mychan : !xls.array<3 x i8> +// CHECK-LABEL: xls.chan @mychan {fifo_config = #xls.fifo_config} : i24 +xls.chan @mychan {fifo_config = #xls.fifo_config} : !xls.array<3 x i8> // CHECK-LABEL: xls.eproc @eproc( // CHECK-SAME: %[[VAL_0:.*]]: i32) zeroinitializer { diff --git a/xls/contrib/mlir/testdata/index_type_conversion.mlir b/xls/contrib/mlir/testdata/index_type_conversion.mlir index 811a3e62ea..dde2ec0d7b 100644 --- a/xls/contrib/mlir/testdata/index_type_conversion.mlir +++ b/xls/contrib/mlir/testdata/index_type_conversion.mlir @@ -164,7 +164,7 @@ func.func @forloop(%arg0: i32, %arg1: i8, %arg2: i9) -> i32 attributes {xls = tr return %0 : i32 } -// INDEX32-LABEL: xls.chan @mychan : i32 -// INDEX64-LABEL: xls.chan @mychan : i64 -xls.chan @mychan : index +// INDEX32-LABEL: xls.chan @mychan {fifo_config = #xls.fifo_config} : i32 +// INDEX64-LABEL: xls.chan @mychan {fifo_config = #xls.fifo_config} : i64 +xls.chan @mychan {fifo_config = #xls.fifo_config} : index diff --git a/xls/contrib/mlir/testdata/proc_elaboration.mlir b/xls/contrib/mlir/testdata/proc_elaboration.mlir index a7ed4d0ec2..4be7dbac13 100644 --- a/xls/contrib/mlir/testdata/proc_elaboration.mlir +++ b/xls/contrib/mlir/testdata/proc_elaboration.mlir @@ -1,6 +1,6 @@ // RUN: xls_opt -elaborate-procs -split-input-file %s 2>&1 | FileCheck %s // CHECK: xls.chan @req : i32 -// CHECK-NEXT: xls.chan @resp : i32 +// CHECK-NEXT: xls.chan @resp {fifo_config = #xls.fifo_config} : i32 // CHECK-NEXT: xls.chan @rom1_req : i32 // CHECK-NEXT: xls.chan @rom1_resp : i32 // CHECK-NEXT: xls.eproc @rom(%arg0: i32) zeroinitializer discardable { @@ -45,7 +45,7 @@ xls.sproc @fetch() top { spawns { %req_out, %req_in = xls.schan("req") - %resp_out, %resp_in = xls.schan("resp") + %resp_out, %resp_in = xls.schan("resp") attributes { fifo_config = #xls.fifo_config } xls.spawn @proxy(%req_in, %resp_out) : !xls.schan, !xls.schan xls.yield %req_out, %resp_in : !xls.schan, !xls.schan } diff --git a/xls/contrib/mlir/testdata/translate_chn.mlir b/xls/contrib/mlir/testdata/translate_chn.mlir new file mode 100644 index 0000000000..8dd7cd9614 --- /dev/null +++ b/xls/contrib/mlir/testdata/translate_chn.mlir @@ -0,0 +1,27 @@ +// RUN: xls_translate --mlir-xls-to-xls %s -- 2>&1 | FileCheck %s + +// CHECK-LABEL: chan ch_inp +// CHECK-SAME: kind=streaming +// CHECK-SAME: ops=receive_only +xls.chan @ch_inp {send_supported = false} : i32 + +// CHECK-LABEL: chan ch_out +// CHECK-SAME: kind=streaming +// CHECK-SAME: ops=send_only +// CHECK-SAME: fifo_depth=1 +// CHECK-SAME: bypass=true +// CHECK-SAME: register_push_outputs=true +// CHECK-SAME: register_pop_outputs=false +xls.chan @ch_out { + fifo_config = #xls.fifo_config, + recv_supported = false +} : i32 + +// CHECK: top proc eproc +xls.eproc @eproc() zeroinitializer { + %tok0 = xls.after_all : !xls.token + %tok1, %val = xls.blocking_receive %tok0, @ch_inp : i32 + xls.send %tok1, %val, @ch_out : i32 + xls.yield +} + diff --git a/xls/contrib/mlir/testdata/translate_from_xls/proc.ir b/xls/contrib/mlir/testdata/translate_from_xls/proc.ir index 3df2e02632..dd824b6081 100644 --- a/xls/contrib/mlir/testdata/translate_from_xls/proc.ir +++ b/xls/contrib/mlir/testdata/translate_from_xls/proc.ir @@ -7,8 +7,14 @@ file_number 0 "./simple_proc.x" // CHECK-LABEL: xls.chan @ch_inp {send_supported = false} : i32 chan ch_inp(bits[32], id=0, kind=streaming, ops=receive_only, metadata="") -// CHECK-LABEL: xls.chan @ch_out {recv_supported = false} : i32 -chan ch_out(bits[32], id=1, kind=streaming, ops=send_only, metadata="") + +// CHECK-LABEL: xls.chan @ch_out { +// CHECK-SAME: fifo_config = #xls.fifo_config, +// CHECK-SAME: input_flop_kind = #xls, +// CHECK-SAME: output_flop_kind = #xls +// CHECK-SAME: recv_supported = false +// CHECK-SAME: } : i32 +chan ch_out(bits[32], id=1, kind=streaming, ops=send_only, flow_control=ready_valid, strictness=proven_mutually_exclusive, fifo_depth=1, bypass=true, register_push_outputs=true, register_pop_outputs=false, input_flop_kind=zero_latency, output_flop_kind=skid, metadata="") // CHECK-LABEL: xls.eproc @ident() zeroinitializer { // CHECK: xls.yield diff --git a/xls/contrib/mlir/tools/xls_translate/xls_translate_from_mlir.cc b/xls/contrib/mlir/tools/xls_translate/xls_translate_from_mlir.cc index db7c31afd2..631d2014a1 100644 --- a/xls/contrib/mlir/tools/xls_translate/xls_translate_from_mlir.cc +++ b/xls/contrib/mlir/tools/xls_translate/xls_translate_from_mlir.cc @@ -68,6 +68,7 @@ #include "xls/common/file/get_runfile_path.h" #include "xls/contrib/mlir/IR/xls_ops.h" #include "xls/ir/bits.h" +#include "xls/ir/channel.h" #include "xls/ir/foreign_function.h" #include "xls/ir/foreign_function_data.pb.h" #include "xls/ir/nodes.h" @@ -1406,6 +1407,19 @@ absl::StatusOr<::xls::Function*> wrapDslxFunctionIfNeeded( return xlsFunc; } +::xls::FlopKind convertFlopKind(FlopKind kind) { + switch (kind) { + case FlopKind::kNone: + return ::xls::FlopKind::kNone; + case FlopKind::kFlop: + return ::xls::FlopKind::kFlop; + case FlopKind::kSkid: + return ::xls::FlopKind::kSkid; + case FlopKind::kZeroLatency: + return ::xls::FlopKind::kZeroLatency; + } +} + FailureOr> mlirXlsToXls( Operation* op, llvm::StringRef dslx_search_path, DslxPackageCache& dslx_cache) { @@ -1450,7 +1464,30 @@ FailureOr> mlirXlsToXls( } else if (!chan_op.getRecvSupported()) { kind = ::xls::ChannelOps::kSendOnly; // NOLINT } - auto channel = package->CreateStreamingChannel(name, kind, xls_type); + + std::optional<::xls::FifoConfig> fifo_config = std::nullopt; + if (auto mlir_fifo_config = chan_op.getFifoConfig()) { + fifo_config = ::xls::FifoConfig( + mlir_fifo_config->getFifoDepth(), mlir_fifo_config->getBypass(), + mlir_fifo_config->getRegisterPushOutputs(), + mlir_fifo_config->getRegisterPopOutputs()); + } + + std::optional<::xls::FlopKind> input_flop = std::nullopt; + std::optional<::xls::FlopKind> output_flop = std::nullopt; + if (auto attr = chan_op.getInputFlopKind()) { + input_flop = convertFlopKind(*attr); + } + if (auto attr = chan_op.getOutputFlopKind()) { + output_flop = convertFlopKind(*attr); + } + + auto channel_config = + ::xls::ChannelConfig(fifo_config, input_flop, output_flop); + + auto channel = package->CreateStreamingChannel(name, kind, xls_type, {}, + channel_config); + if (!channel.ok()) { chan_op.emitOpError("failed to create streaming channel: ") << channel.status().message(); diff --git a/xls/contrib/mlir/tools/xls_translate/xls_translate_to_mlir.cc b/xls/contrib/mlir/tools/xls_translate/xls_translate_to_mlir.cc index e48d2412d3..4c50cffb04 100644 --- a/xls/contrib/mlir/tools/xls_translate/xls_translate_to_mlir.cc +++ b/xls/contrib/mlir/tools/xls_translate/xls_translate_to_mlir.cc @@ -45,6 +45,7 @@ #include "xls/ir/bits.h" #include "xls/ir/channel.h" #include "xls/ir/fileno.h" +#include "xls/ir/channel.h" #include "xls/ir/function.h" #include "xls/ir/function_base.h" #include "xls/ir/lsb_or_msb.h" @@ -1633,15 +1634,50 @@ absl::StatusOr translateProc(::xls::Proc& xls_proc, // Channel Translation //===----------------------------------------------------------------------===// +FlopKind convertFlopKind(::xls::FlopKind kind) { + switch (kind) { + case ::xls::FlopKind::kNone: + return FlopKind::kNone; + case ::xls::FlopKind::kFlop: + return FlopKind::kFlop; + case ::xls::FlopKind::kSkid: + return FlopKind::kSkid; + case ::xls::FlopKind::kZeroLatency: + return FlopKind::kZeroLatency; + } +} + absl::Status translateChannel(::xls::Channel& xls_chn, OpBuilder& builder, MLIRContext* ctx, TranslationState& state) { auto chn = builder.create( builder.getUnknownLoc(), /*name=*/builder.getStringAttr(xls_chn.name()), /*type=*/TypeAttr::get(translateType(xls_chn.type(), builder, ctx)), + /*fifo_config=*/nullptr, + /*input_flop_kind=*/nullptr, + /*output_flop_kind=*/nullptr, /*send_supported=*/builder.getBoolAttr(xls_chn.CanSend()), /*recv_supported=*/builder.getBoolAttr(xls_chn.CanReceive())); + if (auto xls_streaming_chn = + dynamic_cast<::xls::StreamingChannel*>(&xls_chn)) { + auto xls_ch_config = xls_streaming_chn->channel_config(); + if (auto xls_fifo_config = xls_ch_config.fifo_config()) { + chn.setFifoConfigAttr(FifoConfig::get( + ctx, xls_fifo_config->depth(), xls_fifo_config->bypass(), + xls_fifo_config->register_push_outputs(), + xls_fifo_config->register_pop_outputs())); + } + + if (auto xls_input_flop = xls_ch_config.input_flop_kind()) { + chn.setInputFlopKind(convertFlopKind(*xls_input_flop)); + } + + if (auto xls_output_flop = xls_ch_config.output_flop_kind()) { + chn.setOutputFlopKind(convertFlopKind(*xls_output_flop)); + } + } + return state.setChannel(std::string(xls_chn.name()), SymbolRefAttr::get(chn.getNameAttr())); } diff --git a/xls/contrib/mlir/transforms/array_to_bits.cc b/xls/contrib/mlir/transforms/array_to_bits.cc index 41226f29bc..a9df1b495f 100644 --- a/xls/contrib/mlir/transforms/array_to_bits.cc +++ b/xls/contrib/mlir/transforms/array_to_bits.cc @@ -147,10 +147,10 @@ class LegalizeChanOpPattern : public OpConversionPattern { ChanOp op, OpAdaptor adaptor, ConversionPatternRewriter& rewriter) const override { (void)adaptor; - auto newOp = rewriter.replaceOpWithNewOp( - op, op.getSymName(), typeConverter->convertType(op.getType())); - newOp.setSendSupported(op.getSendSupported()); - newOp.setRecvSupported(op.getRecvSupported()); + rewriter.replaceOpWithNewOp( + op, op.getSymName(), typeConverter->convertType(op.getType()), + op.getFifoConfigAttr(), op.getInputFlopKindAttr(), op.getOutputFlopKindAttr(), + op.getSendSupported(), op.getRecvSupported()); return success(); } }; diff --git a/xls/contrib/mlir/transforms/index_type_conversion.cc b/xls/contrib/mlir/transforms/index_type_conversion.cc index 6cf1f85c89..aa96582ef8 100644 --- a/xls/contrib/mlir/transforms/index_type_conversion.cc +++ b/xls/contrib/mlir/transforms/index_type_conversion.cc @@ -246,9 +246,10 @@ class LegalizeChanOp : public OpConversionPattern { ChanOp op, OpAdaptor /*adaptor*/, ConversionPatternRewriter &rewriter) const override { Type resultType = getTypeConverter()->convertType(op.getType()); - rewriter.replaceOpWithNewOp(op, op.getSymName(), resultType, - op.getSendSupported(), - op.getRecvSupported()); + rewriter.replaceOpWithNewOp( + op, op.getSymName(), resultType, op.getFifoConfigAttr(), + op.getInputFlopKindAttr(), op.getOutputFlopKindAttr(), op.getSendSupported(), + op.getRecvSupported()); return success(); } }; diff --git a/xls/contrib/mlir/transforms/proc_elaboration.cc b/xls/contrib/mlir/transforms/proc_elaboration.cc index 8a91ba1428..087c3a71df 100644 --- a/xls/contrib/mlir/transforms/proc_elaboration.cc +++ b/xls/contrib/mlir/transforms/proc_elaboration.cc @@ -141,7 +141,10 @@ class ElaborationContext for (auto [i, arg] : llvm::enumerate(sproc.getNextChannels())) { auto chan = builder.create( sproc.getLoc(), absl::StrFormat("%s_arg%d", originalName.str(), i), - cast(arg.getType()).getElementType()); + cast(arg.getType()).getElementType(), + /*fifo_config=*/nullptr, + /*input_flop_kind=*/nullptr, + /*output_flop_kind=*/nullptr); eprocChannels.push_back(chan); chanMap[mapping.lookup(arg)] = SymbolRefAttr::get(chan.getSymNameAttr()); } @@ -222,8 +225,10 @@ class ElaborationInterpreter absl::Status Interpret(SchanOp op, ElaborationContext& ctx) { std::string name = op.getName().str(); auto uniqueName = ctx.Uniquify(op.getNameAttr()); - ChanOp chan = - ctx.getBuilder().create(op.getLoc(), uniqueName, op.getType()); + ChanOp chan = ctx.getBuilder().create( + op.getLoc(), uniqueName, op.getType(), op.getFifoConfigAttr(), + op.getInputFlopKindAttr(), op.getOutputFlopKindAttr()); + ctx.getSymbolTable().insert(chan); ctx.Set(op.getResult(0), chan); ctx.Set(op.getResult(1), chan); @@ -316,7 +321,11 @@ void ProcElaborationPass::runOnOperation() { SchanType schan = cast(arg.getType()); auto nameAttr = cast(name); auto echan = builder.create(sproc.getLoc(), nameAttr.str(), - schan.getElementType()); + schan.getElementType(), + /*fifo_config=*/nullptr, + /*input_flop_kind=*/nullptr, + /*output_flop_kind=*/nullptr); + if (schan.getIsInput()) { echan.setSendSupported(false); } else { diff --git a/xls/contrib/mlir/transforms/scalarize.cc b/xls/contrib/mlir/transforms/scalarize.cc index 5d3d28875d..b6feda4a04 100644 --- a/xls/contrib/mlir/transforms/scalarize.cc +++ b/xls/contrib/mlir/transforms/scalarize.cc @@ -546,10 +546,11 @@ class LegalizeChanOpPattern : public OpConversionPattern { ChanOp op, OpAdaptor adaptor, ConversionPatternRewriter& rewriter) const override { (void)adaptor; - auto newOp = rewriter.replaceOpWithNewOp( - op, op.getSymName(), typeConverter->convertType(op.getType())); - newOp.setSendSupported(op.getSendSupported()); - newOp.setRecvSupported(op.getRecvSupported()); + rewriter.replaceOpWithNewOp( + op, op.getSymName(), typeConverter->convertType(op.getType()), + op.getFifoConfigAttr(), op.getInputFlopKindAttr(), + op.getOutputFlopKindAttr(), op.getSendSupported(), + op.getRecvSupported()); return success(); } };