diff --git a/include/dynamatic/Support/RTL/RTL.h b/include/dynamatic/Support/RTL/RTL.h index 0d775930c0..4957c9d188 100644 --- a/include/dynamatic/Support/RTL/RTL.h +++ b/include/dynamatic/Support/RTL/RTL.h @@ -91,7 +91,7 @@ class RTLParameter { RTLParameter &operator=(const RTLParameter &) = delete; RTLParameter(RTLParameter &&other) noexcept - : name(std::move(other.name)), type(std::move(other.type)){}; + : name(std::move(other.name)), type(std::move(other.type)) {}; RTLParameter &operator=(RTLParameter &&other) noexcept { name = std::move(other.name); @@ -156,7 +156,7 @@ struct ParamMatch { /// Construts a parameter match object from the state and an optional /// serialization for the parameter value. ParamMatch(State state, const llvm::Twine &serial = "") - : state(state), serialized(serial.str()){}; + : state(state), serialized(serial.str()) {}; }; /// A parameterized request for RTL components that match certain properties. @@ -169,7 +169,7 @@ class RTLRequest { Location loc; /// Creates an RTL request reporting errors at the provided location. - RTLRequest(Location loc) : loc(loc){}; + RTLRequest(Location loc) : loc(loc) {}; /// Returns the MLIR attribute holding the RTL parameter's value if it exists; /// otherwise returns nullptr. @@ -294,14 +294,6 @@ class RTLMatch { /// (generation_params in the future) LogicalResult registerParameters(hw::HWModuleExternOp &modOp); - LogicalResult registerBitwidthParameter(hw::HWModuleExternOp &modOp, - llvm::StringRef modName, - hw::ModuleType &modType); - - LogicalResult registerExtraSignalParameters(hw::HWModuleExternOp &modOp, - llvm::StringRef modName, - hw::ModuleType &modType); - /// Attempts to concretize the matched RTL component using the original RTL /// request that created the match. Generic components are copied to the /// output directory while generated components are produced by the diff --git a/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp b/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp index 3cb605cca5..5ea2c40457 100644 --- a/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp +++ b/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp @@ -23,6 +23,7 @@ #include "dynamatic/Dialect/Handshake/MemoryInterfaces.h" #include "dynamatic/Support/Attribute.h" #include "dynamatic/Support/Backedge.h" +#include "dynamatic/Support/RTL/RTL.h" #include "dynamatic/Support/Utils/Utils.h" #include "dynamatic/Transforms/HandshakeMaterialize.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" @@ -99,6 +100,44 @@ static Type lowerType(Type type) { .Default([](auto type) { return nullptr; }); } +// Local helper: return handshake type bitwidth as string. Kept local to this +// translation unit because it's only used by the Handshake->HW conversion. +static std::string getBitwidthString(mlir::Type type) { + return std::to_string(dynamatic::handshake::getHandshakeTypeBitWidth(type)); +} + +// Local helper: serialize ExtraSignals attached to a ChannelType/ControlType +// into the same JSON-ish string form previously exposed from the RTL header. +static std::string serializeExtraSignalsLocal(const mlir::Type &type) { + assert(type.isa() && + "type should be ChannelType or ControlType"); + + dynamatic::handshake::ExtraSignalsTypeInterface extraSignalsType = + type.cast(); + + std::string extraSignalsValue; + llvm::raw_string_ostream extraSignals(extraSignalsValue); + + extraSignals << "{"; + bool first = true; + for (const dynamatic::handshake::ExtraSignal &extraSignal : + extraSignalsType.getExtraSignals()) { + if (!first) + extraSignals << ", "; + first = false; + + extraSignals << "\"" << extraSignal.name << "\": "; + extraSignals << extraSignal.getBitWidth(); + } + extraSignals << "}"; + + return std::string("'") + extraSignals.str() + std::string("'"); +} + +// NOTE: The definition of `dynamatic::computeSerializedParameters` is +// provided after the `ModuleDiscriminator` implementation so it can forward +// to the static method placed next to the discriminator's logic. + namespace { /// Helper class to build HW modules progressively by adding inputs/outputs @@ -107,7 +146,7 @@ class ModuleBuilder { public: /// The MLIR context is used to create string attributes for port names /// and types for the clock and reset ports, should they be added. - ModuleBuilder(MLIRContext *ctx) : ctx(ctx) {}; + ModuleBuilder(MLIRContext *ctx) : ctx(ctx) {} /// Builds the module port information from the current list of inputs and /// outputs. @@ -234,7 +273,7 @@ struct InternalMemLoweringState { InternalMemLoweringState(handshake::RAMOp ramOp, handshake::MemoryOpInterface memInterface) : ramOp(ramOp), memInterface(memInterface), - ports(getMemoryPorts(memInterface)), portNames(memInterface) {}; + ports(getMemoryPorts(memInterface)), portNames(memInterface) {} }; /// Summarizes information to convert a Handshake function into a @@ -347,7 +386,7 @@ MemLoweringState::getMemOutputPorts(hw::HWModuleOp modOp) { LoweringState::LoweringState(mlir::ModuleOp modOp, NameAnalysis &namer, OpBuilder &builder) - : modOp(modOp), namer(namer), edgeBuilder(builder, modOp.getLoc()) {}; + : modOp(modOp), namer(namer), edgeBuilder(builder, modOp.getLoc()) {} /// Attempts to find an external HW module in the MLIR module with the /// provided name. Returns it if it exists, otherwise returns `nullptr`. @@ -470,6 +509,12 @@ class ModuleDiscriminator { /// component. void setParameters(hw::HWModuleExternOp modOp); + /// Computes the textual/serialized parameter mappings for an operation given + /// its handshake operation name and the external module type. + static ::dynamatic::ParameterMappings + computeSerializedParameters(llvm::StringRef handshakeOp, + hw::ModuleType modType); + /// Whether the operations is currently unsupported. Check after construction /// and produce a failure if this returns true. bool opUnsupported() { return unsupported; } @@ -910,6 +955,140 @@ void ModuleDiscriminator::setParameters(hw::HWModuleExternOp modOp) { DictionaryAttr::get(ctx, parameters)); } +// Implementation of the parameter serialization logic colocated with the +// ModuleDiscriminator. +::dynamatic::ParameterMappings +ModuleDiscriminator::computeSerializedParameters(llvm::StringRef handshakeOp, + hw::ModuleType modType) { + ParameterMappings pm; + + // Bitwidth + if ( + // default + handshakeOp == "handshake.addi" || handshakeOp == "handshake.andi" || + handshakeOp == "handshake.buffer" || handshakeOp == "handshake.cmpi" || + handshakeOp == "handshake.fork" || handshakeOp == "handshake.lazy_fork" || + handshakeOp == "handshake.merge" || handshakeOp == "handshake.muli" || + handshakeOp == "handshake.sink" || handshakeOp == "handshake.subi" || + handshakeOp == "handshake.shli" || handshakeOp == "handshake.blocker" || + handshakeOp == "handshake.uitofp" || handshakeOp == "handshake.sitofp" || + handshakeOp == "handshake.fptosi" || + handshakeOp == "handshake.rigidifier" || handshakeOp == "handshake.ori" || + handshakeOp == "handshake.shrsi" || handshakeOp == "handshake.xori" || + handshakeOp == "handshake.negf" || handshakeOp == "handshake.divsi" || + handshakeOp == "handshake.absf" || handshakeOp == "handshake.divui" || + handshakeOp == "handshake.shrui" || handshakeOp == "handshake.remsi" || + handshakeOp == "handshake.not" || + // the first input has data bitwidth + handshakeOp == "handshake.speculator" || + handshakeOp == "handshake.spec_commit" || + handshakeOp == "handshake.spec_save_commit" || + handshakeOp == "handshake.sharing_wrapper" || + handshakeOp == "handshake.non_spec") { + pm["BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + } else if (handshakeOp == "handshake.cond_br" || + handshakeOp == "handshake.select") { + pm["BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + } else if (handshakeOp == "handshake.constant") { + pm["BITWIDTH"] = getBitwidthString(modType.getOutputType(0)); + } else if (handshakeOp == "handshake.control_merge") { + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["INDEX_BITWIDTH"] = getBitwidthString(modType.getOutputType(1)); + } else if (handshakeOp == "handshake.extsi" || + handshakeOp == "handshake.trunci" || + handshakeOp == "handshake.extui") { + pm["INPUT_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["OUTPUT_BITWIDTH"] = getBitwidthString(modType.getOutputType(0)); + } else if (handshakeOp == "handshake.load") { + pm["ADDR_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getOutputType(1)); + } else if (handshakeOp == "handshake.mux") { + pm["INDEX_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + } else if (handshakeOp == "handshake.store") { + pm["ADDR_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + } else if (handshakeOp == "handshake.speculating_branch") { + pm["SPEC_TAG_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + } else if (handshakeOp == "handshake.mem_controller" || + handshakeOp == "handshake.lsq") { + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["ADDR_BITWIDTH"] = + getBitwidthString(modType.getOutputType(modType.getNumOutputs() - 2)); + } else if (handshakeOp == "mem_to_bram") { + pm["ADDR_BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + pm["DATA_BITWIDTH"] = getBitwidthString(modType.getInputType(4)); + } else if (handshakeOp == "handshake.addf" || + handshakeOp == "handshake.cmpf" || + handshakeOp == "handshake.mulf" || + handshakeOp == "handshake.subf" || + handshakeOp == "handshake.divf") { + int bitwidth = handshake::getHandshakeTypeBitWidth(modType.getInputType(0)); + pm["IS_DOUBLE"] = bitwidth == 64 ? "True" : "False"; + } else if (handshakeOp == "handshake.valid_merger") { + pm["LEFT_BITWIDTH"] = getBitwidthString(modType.getInputType(0)); + pm["RIGHT_BITWIDTH"] = getBitwidthString(modType.getInputType(1)); + } else if (handshakeOp == "handshake.source" || + handshakeOp == "mem_controller" || + handshakeOp == "handshake.truncf" || + handshakeOp == "handshake.extf" || + handshakeOp == "handshake.maximumf" || + handshakeOp == "handshake.minimumf" || + handshakeOp == "handshake.join") { + // nothing + } else if (handshakeOp == "handshake.ram") { + pm["ADDR_WIDTH"] = getBitwidthString(modType.getInputType(1)); + pm["DATA_WIDTH"] = getBitwidthString(modType.getInputType(4)); + } + + // Extra signals + if ( + // default + handshakeOp == "handshake.addf" || handshakeOp == "handshake.addi" || + handshakeOp == "handshake.andi" || handshakeOp == "handshake.buffer" || + handshakeOp == "handshake.cmpf" || handshakeOp == "handshake.cmpi" || + handshakeOp == "handshake.cond_br" || + handshakeOp == "handshake.constant" || handshakeOp == "handshake.extsi" || + handshakeOp == "handshake.fork" || handshakeOp == "handshake.merge" || + handshakeOp == "handshake.mulf" || handshakeOp == "handshake.muli" || + handshakeOp == "handshake.select" || handshakeOp == "handshake.sink" || + handshakeOp == "handshake.subf" || handshakeOp == "handshake.extui" || + handshakeOp == "handshake.shli" || handshakeOp == "handshake.subi" || + handshakeOp == "handshake.spec_save_commit" || + handshakeOp == "handshake.speculator" || + handshakeOp == "handshake.trunci" || handshakeOp == "handshake.mux" || + handshakeOp == "handshake.control_merge" || + handshakeOp == "handshake.blocker" || handshakeOp == "handshake.uitofp" || + handshakeOp == "handshake.sitofp" || handshakeOp == "handshake.fptosi" || + handshakeOp == "handshake.lazy_fork" || handshakeOp == "handshake.divf" || + handshakeOp == "handshake.ori" || handshakeOp == "handshake.shrsi" || + handshakeOp == "handshake.xori" || handshakeOp == "handshake.negf" || + handshakeOp == "handshake.truncf" || handshakeOp == "handshake.divsi" || + handshakeOp == "handshake.absf" || handshakeOp == "handshake.divui" || + handshakeOp == "handshake.extf" || handshakeOp == "handshake.maximumf" || + handshakeOp == "handshake.minimumf" || handshakeOp == "handshake.shrui" || + handshakeOp == "handshake.join" || handshakeOp == "handshake.remsi" || + handshakeOp == "handshake.not" || + // the first input has extra signals + handshakeOp == "handshake.load" || handshakeOp == "handshake.store" || + handshakeOp == "handshake.spec_commit" || + handshakeOp == "handshake.speculating_branch") { + pm["EXTRA_SIGNALS"] = serializeExtraSignalsLocal(modType.getInputType(0)); + } else if (handshakeOp == "handshake.source" || + handshakeOp == "handshake.non_spec") { + pm["EXTRA_SIGNALS"] = serializeExtraSignalsLocal(modType.getOutputType(0)); + } + + return pm; +} + +// NOTE: The serialized-parameter helper has been moved inside this +// translation unit and is invoked directly from the places that need it +// (see usage sites below). We intentionally do not provide a free-function +// in the `dynamatic` namespace here to avoid exposing this handshake-specific +// logic from the general RTL header. + namespace { /// Builder for hardware instances (`hw::InstanceOp`) and their associated @@ -921,7 +1100,7 @@ namespace { class HWBuilder { public: /// Creates the hardware builder. - HWBuilder(MLIRContext *ctx) : modBuilder(ctx) {}; + HWBuilder(MLIRContext *ctx) : modBuilder(ctx) {} /// Adds a value to the list of operands for the future instance, and its type /// to the future external module's input port information. @@ -1109,6 +1288,26 @@ hw::InstanceOp HWBuilder::createInstance(ModuleDiscriminator &discriminator, extModOp = builder.create(loc, modNameAttr, modBuilder.getPortInfo()); discriminator.setParameters(extModOp); + + // Compute serialized textual parameters and put them to the external module + // so export-rtl can read them. + MLIRContext *ctx = extModOp.getContext(); + StringRef rtlName = + extModOp->getAttrOfType(RTL_NAME_ATTR_NAME).getValue(); + auto serialized = ModuleDiscriminator::computeSerializedParameters( + rtlName, extModOp.getModuleType()); + std::vector serialAttrs; + for (auto it = serialized.begin(); it != serialized.end(); ++it) { + StringRef key = it->first(); + const std::string &val = it->second; + serialAttrs.emplace_back(StringAttr::get(ctx, key), + StringAttr::get(ctx, val)); + } + if (!serialAttrs.empty()) { + extModOp->setAttr(StringAttr::get(ctx, "hw.serialized_parameters"), + DictionaryAttr::get(ctx, serialAttrs)); + } + builder.restoreInsertionPoint(instInsertPoint); } @@ -1797,8 +1996,7 @@ class MemToBRAMConverter : public ConverterBuilder { OpBuilder &builder) : ConverterBuilder(buildExternalModule(circuitMod, state, builder), IOMapping(state.outputIdx, 0, 5), IOMapping(0, 0, 8), - IOMapping(0, 5, 2), - IOMapping(8, state.inputIdx, 1)) {}; + IOMapping(0, 5, 2), IOMapping(8, state.inputIdx, 1)) {} private: /// Creates, inserts, and returns the external harware module corresponding to @@ -1905,6 +2103,20 @@ MemToBRAMConverter::buildExternalModule(hw::HWModuleOp circuitMod, IntegerAttr::get(i32, memState.ports.addrWidth)); extModOp->setAttr(RTL_PARAMETERS_ATTR_NAME, DictionaryAttr::get(ctx, parameters)); + // Compute and add serialized parameters so the RTL exporter can read them + { + ParameterMappings pm = ModuleDiscriminator::computeSerializedParameters( + HW_NAME, extModOp.getModuleType()); + std::vector serializedAttrs; + for (auto it = pm.begin(); it != pm.end(); ++it) { + StringRef key = it->getKey(); + std::string &val = it->getValue(); + serializedAttrs.emplace_back(StringAttr::get(ctx, key), + StringAttr::get(ctx, val)); + } + extModOp->setAttr(StringAttr::get(ctx, "hw.serialized_parameters"), + DictionaryAttr::get(ctx, serializedAttrs)); + } return extModOp; } diff --git a/lib/Support/RTL/RTL.cpp b/lib/Support/RTL/RTL.cpp index 01ffe8b3cd..938be4b458 100644 --- a/lib/Support/RTL/RTL.cpp +++ b/lib/Support/RTL/RTL.cpp @@ -98,8 +98,7 @@ std::string dynamatic::substituteParams(StringRef input, RTLRequestFromOp::RTLRequestFromOp(Operation *op, const llvm::Twine &name) : RTLRequest(op->getLoc()), name(name.str()), op(op), - parameters(op->getAttrOfType(RTL_PARAMETERS_ATTR_NAME)) { - }; + parameters(op->getAttrOfType(RTL_PARAMETERS_ATTR_NAME)) {} Attribute RTLRequestFromOp::getParameter(const RTLParameter ¶m) const { if (!parameters) @@ -246,221 +245,32 @@ MapVector RTLMatch::getGenericParameterValues() const { return values; } -static std::string serializeExtraSignalsInner(const Type &type) { - assert(type.isa() && - "type should be ChannelType or ControlType"); - - handshake::ExtraSignalsTypeInterface extraSignalsType = - type.cast(); - - std::string extraSignalsValue; - llvm::raw_string_ostream extraSignals(extraSignalsValue); - - extraSignals << "{"; - bool first = true; - for (const handshake::ExtraSignal &extraSignal : - extraSignalsType.getExtraSignals()) { - if (!first) - extraSignals << ", "; - first = false; - - extraSignals << "\"" << extraSignal.name << "\": "; - extraSignals << extraSignal.getBitWidth(); - } - extraSignals << "}"; - - return extraSignals.str(); -} - -static std::string serializeExtraSignals(const Type &type) { - return "'" + serializeExtraSignalsInner(type) + "'"; -} - -/// Returns the bitwidth of the type as string. -/// If the type is a control type, returns "0". -static std::string getBitwidthString(Type type) { - return std::to_string(handshake::getHandshakeTypeBitWidth(type)); -} - LogicalResult RTLMatch::registerParameters(hw::HWModuleExternOp &modOp) { - auto handshakeOp = - modOp->template getAttrOfType(RTL_NAME_ATTR_NAME).getValue(); - auto modType = modOp.getModuleType(); - - LogicalResult gotBitwidth = - registerBitwidthParameter(modOp, handshakeOp, modType); - LogicalResult gotExtraSignals = - registerExtraSignalParameters(modOp, handshakeOp, modType); - - return success(gotBitwidth.succeeded() && gotExtraSignals.succeeded()); -} - -LogicalResult RTLMatch::registerBitwidthParameter(hw::HWModuleExternOp &modOp, - llvm::StringRef handshakeOp, - hw::ModuleType &modType) { - if ( - // default (All(Data)TypesMatch) - handshakeOp == "handshake.addi" || handshakeOp == "handshake.andi" || - handshakeOp == "handshake.buffer" || handshakeOp == "handshake.cmpi" || - handshakeOp == "handshake.fork" || handshakeOp == "handshake.lazy_fork" || - handshakeOp == "handshake.merge" || handshakeOp == "handshake.muli" || - handshakeOp == "handshake.sink" || handshakeOp == "handshake.subi" || - handshakeOp == "handshake.shli" || handshakeOp == "handshake.blocker" || - handshakeOp == "handshake.uitofp" || handshakeOp == "handshake.sitofp" || - handshakeOp == "handshake.fptosi" || - handshakeOp == "handshake.rigidifier" || handshakeOp == "handshake.ori" || - handshakeOp == "handshake.shrsi" || handshakeOp == "handshake.xori" || - handshakeOp == "handshake.negf" || handshakeOp == "handshake.divsi" || - handshakeOp == "handshake.absf" || handshakeOp == "handshake.divui" || - handshakeOp == "handshake.shrui" || handshakeOp == "handshake.remsi" || - handshakeOp == "handshake.not" || - // the first input has data bitwidth - handshakeOp == "handshake.speculator" || - handshakeOp == "handshake.spec_commit" || - handshakeOp == "handshake.spec_save_commit" || - handshakeOp == "handshake.sharing_wrapper" || - handshakeOp == "handshake.non_spec") { - // Default - serializedParams["BITWIDTH"] = getBitwidthString(modType.getInputType(0)); - } else if (handshakeOp == "handshake.cond_br" || - handshakeOp == "handshake.select") { - serializedParams["BITWIDTH"] = getBitwidthString(modType.getInputType(1)); - } else if (handshakeOp == "handshake.constant") { - serializedParams["BITWIDTH"] = getBitwidthString(modType.getOutputType(0)); - } else if (handshakeOp == "handshake.control_merge") { - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["INDEX_BITWIDTH"] = - getBitwidthString(modType.getOutputType(1)); - } else if (handshakeOp == "handshake.extsi" || - handshakeOp == "handshake.trunci" || - handshakeOp == "handshake.extui") { - serializedParams["INPUT_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["OUTPUT_BITWIDTH"] = - getBitwidthString(modType.getOutputType(0)); - } else if (handshakeOp == "handshake.load") { - serializedParams["ADDR_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getOutputType(1)); - } else if (handshakeOp == "handshake.mux") { - serializedParams["INDEX_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(1)); - } else if (handshakeOp == "handshake.store") { - serializedParams["ADDR_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(1)); - } else if (handshakeOp == "handshake.speculating_branch") { - serializedParams["SPEC_TAG_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(1)); - } else if (handshakeOp == "handshake.mem_controller" || - handshakeOp == "handshake.lsq") { - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - // Warning: Ports differ from instance to instance. - // Therefore, mod.getNumOutputs() is also variable. - serializedParams["ADDR_BITWIDTH"] = - getBitwidthString(modType.getOutputType(modType.getNumOutputs() - 2)); - } else if (handshakeOp == "mem_to_bram") { - serializedParams["ADDR_BITWIDTH"] = - getBitwidthString(modType.getInputType(1)); - serializedParams["DATA_BITWIDTH"] = - getBitwidthString(modType.getInputType(4)); - } else if (handshakeOp == "handshake.addf" || - handshakeOp == "handshake.cmpf" || - handshakeOp == "handshake.mulf" || - handshakeOp == "handshake.subf" || - handshakeOp == "handshake.divf") { - int bitwidth = handshake::getHandshakeTypeBitWidth(modType.getInputType(0)); - serializedParams["IS_DOUBLE"] = bitwidth == 64 ? "True" : "False"; - } else if (handshakeOp == "handshake.valid_merger") { - serializedParams["LEFT_BITWIDTH"] = - getBitwidthString(modType.getInputType(0)); - serializedParams["RIGHT_BITWIDTH"] = - getBitwidthString(modType.getInputType(1)); - } else if (handshakeOp == "handshake.source" || - handshakeOp == "mem_controller" || - handshakeOp == "handshake.truncf" || - handshakeOp == "handshake.extf" || - handshakeOp == "handshake.maximumf" || - handshakeOp == "handshake.minimumf" || - handshakeOp == "handshake.join") { - // Skip - } else if (handshakeOp == "handshake.ram") { - // NOTE: this port order is currently hardcoded in HandshakeToHW.cpp - // Input 0: loadEn - // Input 1: loadAddr - // Input 2: storeEn - // Input 3: storeAddr - // Input 4: storeData - // Output 0: loadData - serializedParams["ADDR_WIDTH"] = getBitwidthString(modType.getInputType(1)); - serializedParams["DATA_WIDTH"] = getBitwidthString(modType.getInputType(4)); - } else { - modOp->emitError("Failed to get bitwidth of operation"); - return failure(); + // Require precomputed serialized parameters attached during lowering since + // the `hw.serialized_parameters` attribute. + if (auto dict = + modOp->getAttrOfType("hw.serialized_parameters")) { + for (auto namedAttr : dict.getValue()) { + StringRef key = namedAttr.getName().getValue(); + Attribute val = namedAttr.getValue(); + if (auto s = val.dyn_cast()) { + serializedParams[key.str()] = s.getValue().str(); + } else if (auto i = val.dyn_cast()) { + serializedParams[key.str()] = std::to_string(i.getInt()); + } else { + // // neither string nor integer attribute... use print method of + // attribute std::string tmp; llvm::raw_string_ostream os(tmp); + // val.print(os); + // serializedParams[key.str()] = os.str(); + return failure(); + } + } + return success(); } - return success(); -} -LogicalResult -RTLMatch::registerExtraSignalParameters(hw::HWModuleExternOp &modOp, - llvm::StringRef handshakeOp, - hw::ModuleType &modType) { - - if ( - // default (AllExtraSignalsMatch) - handshakeOp == "handshake.addf" || handshakeOp == "handshake.addi" || - handshakeOp == "handshake.andi" || handshakeOp == "handshake.buffer" || - handshakeOp == "handshake.cmpf" || handshakeOp == "handshake.cmpi" || - handshakeOp == "handshake.cond_br" || - handshakeOp == "handshake.constant" || handshakeOp == "handshake.extsi" || - handshakeOp == "handshake.fork" || handshakeOp == "handshake.merge" || - handshakeOp == "handshake.mulf" || handshakeOp == "handshake.muli" || - handshakeOp == "handshake.select" || handshakeOp == "handshake.sink" || - handshakeOp == "handshake.subf" || handshakeOp == "handshake.extui" || - handshakeOp == "handshake.shli" || handshakeOp == "handshake.subi" || - handshakeOp == "handshake.spec_save_commit" || - handshakeOp == "handshake.speculator" || - handshakeOp == "handshake.trunci" || handshakeOp == "handshake.mux" || - handshakeOp == "handshake.control_merge" || - handshakeOp == "handshake.blocker" || handshakeOp == "handshake.uitofp" || - handshakeOp == "handshake.sitofp" || handshakeOp == "handshake.fptosi" || - handshakeOp == "handshake.lazy_fork" || handshakeOp == "handshake.divf" || - handshakeOp == "handshake.ori" || handshakeOp == "handshake.shrsi" || - handshakeOp == "handshake.xori" || handshakeOp == "handshake.negf" || - handshakeOp == "handshake.truncf" || handshakeOp == "handshake.divsi" || - handshakeOp == "handshake.absf" || handshakeOp == "handshake.divui" || - handshakeOp == "handshake.extf" || handshakeOp == "handshake.maximumf" || - handshakeOp == "handshake.minimumf" || handshakeOp == "handshake.shrui" || - handshakeOp == "handshake.join" || handshakeOp == "handshake.remsi" || - handshakeOp == "handshake.not" || - // the first input has extra signals - handshakeOp == "handshake.load" || handshakeOp == "handshake.store" || - handshakeOp == "handshake.spec_commit" || - handshakeOp == "handshake.speculating_branch") { - serializedParams["EXTRA_SIGNALS"] = - serializeExtraSignals(modType.getInputType(0)); - } else if (handshakeOp == "handshake.source" || - handshakeOp == "handshake.non_spec") { - serializedParams["EXTRA_SIGNALS"] = - serializeExtraSignals(modType.getOutputType(0)); - } else if (handshakeOp == "handshake.mem_controller" || - handshakeOp == "mem_to_bram" || handshakeOp == "handshake.lsq" || - handshakeOp == "handshake.sharing_wrapper" || - handshakeOp == "handshake.ram") { - // Skip - } else { - modOp.emitError("Failed to get extra signals of operation"); - return failure(); - } - return success(); + // No serialized parameters found => failure + modOp.emitError("No serialized parameters found (hw.serialized_parameters)"); + return failure(); } LogicalResult RTLMatch::concretize(const RTLRequest &request, diff --git a/test/Conversion/HandshakeToHW/types.mlir b/test/Conversion/HandshakeToHW/types.mlir index 70e692511b..75ac4aa20c 100644 --- a/test/Conversion/HandshakeToHW/types.mlir +++ b/test/Conversion/HandshakeToHW/types.mlir @@ -7,7 +7,7 @@ // CHECK: hw.instance "sink0" @handshake_sink_0(ins: %[[VAL_0]]: !handshake.channel, clk: %[[VAL_2]]: i1, rst: %[[VAL_3]]: i1) -> () // CHECK: hw.output %[[VAL_1]] : !handshake.control<> // CHECK: } -// CHECK: hw.module.extern @handshake_sink_0(in %[[VAL_5:.*]] : !handshake.channel, in %[[VAL_6:.*]] : i1, in %[[VAL_7:.*]] : i1) attributes {hw.name = "handshake.sink", hw.parameters = {DATA_TYPE = !handshake.channel}} +// CHECK: hw.module.extern @handshake_sink_0(in %[[VAL_5:.*]] : !handshake.channel, in %[[VAL_6:.*]] : i1, in %[[VAL_7:.*]] : i1) attributes {hw.name = "handshake.sink", hw.parameters = {DATA_TYPE = !handshake.channel}, hw.serialized_parameters = {BITWIDTH = "32", EXTRA_SIGNALS = "'{}'"}} handshake.func @dontChangeTypes(%arg : !handshake.channel, %start: !handshake.control<>) -> !handshake.control<> { sink %arg : end %start : <> @@ -21,7 +21,9 @@ handshake.func @dontChangeTypes(%arg : !handshake.channel, %start: !handsha // CHECK: %[[VAL_4:.*]] = hw.instance "addf0" @handshake_addf_0(lhs: %[[VAL_0]]: !handshake.channel, rhs: %[[VAL_1]]: !handshake.channel, clk: %[[VAL_2]]: i1, rst: %[[VAL_3]]: i1) -> (result: !handshake.channel) // CHECK: hw.output %[[VAL_4]] : !handshake.channel // CHECK: } -// CHECK: hw.module.extern @handshake_addf_0(in %[[VAL_6:.*]] : !handshake.channel, in %[[VAL_7:.*]] : !handshake.channel, in %[[VAL_8:.*]] : i1, in %[[VAL_9:.*]] : i1, out result : !handshake.channel) attributes {hw.name = "handshake.addf", hw.parameters = {DATA_TYPE = !handshake.channel, FPU_IMPL = "flopoco", INTERNAL_DELAY = "0_0", LATENCY = 1 : ui32}} +// CHECK: hw.module.extern @handshake_addf_0(in %[[VAL_6:.*]] : !handshake.channel, in %[[VAL_7:.*]] : !handshake.channel, in %[[VAL_8:.*]] : i1, in %[[VAL_9:.*]] : i1, out result : !handshake.channel) attributes {hw.name = "handshake.addf", +// CHECK-SAME: hw.parameters = {DATA_TYPE = !handshake.channel, FPU_IMPL = "flopoco", INTERNAL_DELAY = "0_0", LATENCY = 1 : ui32} +// CHECK-SAME: hw.serialized_parameters handshake.func @lowerNonIntTypes(%arg0 : !handshake.channel, %arg1 : !handshake.channel) -> !handshake.channel { %res = addf %arg0, %arg1 {latency = 1}: end %res : diff --git a/tools/integration/TEST_SUITE.cpp b/tools/integration/TEST_SUITE.cpp index 2f45eb34c6..d09f4dbc89 100644 --- a/tools/integration/TEST_SUITE.cpp +++ b/tools/integration/TEST_SUITE.cpp @@ -355,4 +355,4 @@ INSTANTIATE_TEST_SUITE_P(SpecBenchmarks, SpecFixture, "subdiag_fast" ), [](const auto &info) { return "spec_" + info.param; }); -// clang-format on +// clang-format on \ No newline at end of file