mirror of https://github.com/llvm/circt.git
[HW] Add simple expressions to the parameter support.
This includes export verilog and legalizenames support. This is just a minimal first step. It has several issues that we need to improve over time: 1) Support variadic operators. 2) Support better .mlir syntax 3) Precedence aware printing in generated verilog.
This commit is contained in:
parent
d8ee280f8e
commit
a0afaa44f4
|
@ -12,6 +12,13 @@
|
|||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
|
||||
namespace circt {
|
||||
namespace hw {
|
||||
class PBOAttr;
|
||||
enum class PBO : uint32_t;
|
||||
} // namespace hw
|
||||
} // namespace circt
|
||||
|
||||
#define GET_ATTRDEF_CLASSES
|
||||
#include "circt/Dialect/HW/HWAttributes.h.inc"
|
||||
|
||||
|
|
|
@ -85,6 +85,22 @@ def ParamVerbatimAttr : AttrDef<HWDialect, "ParamVerbatim"> {
|
|||
let mnemonic = "param.verbatim";
|
||||
}
|
||||
|
||||
|
||||
let cppNamespace = "circt::hw" in {
|
||||
def PBO_Add : I32EnumAttrCase<"Add", 0, "add">;
|
||||
def PBO_Mul : I32EnumAttrCase<"Mul", 1, "mul">;
|
||||
def PBOAttr : I32EnumAttr<"PBO", "Parameter Binary Operation Code",
|
||||
[PBO_Add, PBO_Mul]>;
|
||||
}
|
||||
|
||||
def ParamBinaryAttr : AttrDef<HWDialect, "ParamBinary"> {
|
||||
let summary = "Binary operation combining two parameter expressions";
|
||||
let parameters = (ins "PBO":$opcode,
|
||||
"::mlir::Attribute":$lhs, "::mlir::Attribute":$rhs,
|
||||
AttributeSelfTypeParameter<"">:$type);
|
||||
let mnemonic = "param.binary";
|
||||
}
|
||||
|
||||
let cppNamespace = "circt::hw" in {
|
||||
def WUW_Undefined : I32EnumAttrCase<"Undefined", 0>;
|
||||
def WUW_PortOrder : I32EnumAttrCase<"PortOrder", 1>;
|
||||
|
|
|
@ -96,3 +96,34 @@ Attribute ParamVerbatimAttr::parse(MLIRContext *context, DialectAsmParser &p,
|
|||
void ParamVerbatimAttr::print(DialectAsmPrinter &p) const {
|
||||
p << "param.verbatim<" << getValue() << ">";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ParamBinaryAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Attribute ParamBinaryAttr::parse(MLIRContext *context, DialectAsmParser &p,
|
||||
Type type) {
|
||||
Attribute lhs, rhs;
|
||||
StringRef opcodeStr;
|
||||
auto loc = p.getCurrentLocation();
|
||||
if (p.parseLess() || p.parseKeyword(&opcodeStr) ||
|
||||
p.parseAttribute(lhs, type) || p.parseComma() ||
|
||||
p.parseAttribute(rhs, type) || p.parseGreater())
|
||||
return Attribute();
|
||||
|
||||
Optional<PBO> opcode = symbolizePBO(opcodeStr);
|
||||
if (!opcode.hasValue()) {
|
||||
p.emitError(loc, "unknown binary operator name");
|
||||
return {};
|
||||
}
|
||||
|
||||
return ParamBinaryAttr::get(context, *opcode, lhs, rhs, type);
|
||||
}
|
||||
|
||||
void ParamBinaryAttr::print(DialectAsmPrinter &p) const {
|
||||
p << "param.binary<" << stringifyPBO(getOpcode()) << " ";
|
||||
p.printAttributeWithoutType(getLhs());
|
||||
p << ", ";
|
||||
p.printAttributeWithoutType(getRhs());
|
||||
p << ">";
|
||||
}
|
||||
|
|
|
@ -52,6 +52,16 @@ LogicalResult hw::checkParameterInContext(Attribute value, Operation *module,
|
|||
value.isa<StringAttr>() || value.isa<ParamVerbatimAttr>())
|
||||
return success();
|
||||
|
||||
// Check both arms of an expression.
|
||||
if (auto binop = value.dyn_cast<ParamBinaryAttr>()) {
|
||||
if (failed(checkParameterInContext(binop.getLhs(), module, usingOp,
|
||||
disallowParamRefs)) ||
|
||||
failed(checkParameterInContext(binop.getRhs(), module, usingOp,
|
||||
disallowParamRefs)))
|
||||
return failure();
|
||||
return success();
|
||||
}
|
||||
|
||||
// Parameter references need more analysis to make sure they are valid within
|
||||
// this module.
|
||||
if (auto parameterRef = value.dyn_cast<ParamDeclRefAttr>()) {
|
||||
|
|
|
@ -220,6 +220,19 @@ remapRenamedParameters(Attribute value, HWModuleOp module,
|
|||
value.isa<StringAttr>() || value.isa<ParamVerbatimAttr>())
|
||||
return value;
|
||||
|
||||
// Remap leaves of expressions if needed.
|
||||
if (auto binOp = value.dyn_cast<ParamBinaryAttr>()) {
|
||||
auto newLHS =
|
||||
remapRenamedParameters(binOp.getLhs(), module, renamedParameterInfo);
|
||||
auto newRHS =
|
||||
remapRenamedParameters(binOp.getRhs(), module, renamedParameterInfo);
|
||||
// Don't rebuild an attribute if nothing changed.
|
||||
if (newLHS == binOp.getLhs() && newRHS == binOp.getRhs())
|
||||
return value;
|
||||
return ParamBinaryAttr::get(value.getContext(), binOp.getOpcode(), newLHS,
|
||||
newRHS, value.getType());
|
||||
}
|
||||
|
||||
// TODO: Handle nested expressions when we support them.
|
||||
|
||||
// Otherwise this must be a parameter reference.
|
||||
|
|
|
@ -83,6 +83,19 @@ static void printParamValue(Attribute value, Operation *op, StringRef paramName,
|
|||
os << verbatimParam.getValue().getValue();
|
||||
} else if (auto parameterRef = value.dyn_cast<ParamDeclRefAttr>()) {
|
||||
os << parameterRef.getName().getValue();
|
||||
} else if (auto paramBinOp = value.dyn_cast<ParamBinaryAttr>()) {
|
||||
printParamValue(paramBinOp.getLhs(), op, paramName, os);
|
||||
|
||||
// FIXME: Handle precedence, support variadic versions of these.
|
||||
switch (paramBinOp.getOpcode()) {
|
||||
case PBO::Add:
|
||||
os << " + ";
|
||||
break;
|
||||
case PBO::Mul:
|
||||
os << " * ";
|
||||
break;
|
||||
}
|
||||
printParamValue(paramBinOp.getRhs(), op, paramName, os);
|
||||
} else {
|
||||
os << "<<UNKNOWN MLIRATTR: " << value << ">>";
|
||||
emitError(op->getLoc(), "unknown parameter value '")
|
||||
|
|
|
@ -82,7 +82,12 @@ hw.module.extern @NoArg<param: i42>()
|
|||
|
||||
// CHECK-LABEL: hw.module @UseParameters<p1: i42>() {
|
||||
hw.module @UseParameters<p1: i42>() {
|
||||
// CHECK: hw.instance "verbatimparam" @NoArg<param: i42 = #hw.param.verbatim<"\22FOO\22">>() -> ()
|
||||
// CHECK: hw.instance "verbatimparam" @NoArg<param: i42 =
|
||||
// CHECK-SAME: #hw.param.verbatim<"\22FOO\22">>() -> ()
|
||||
hw.instance "verbatimparam" @NoArg<param: i42 = #hw.param.verbatim<"\"FOO\"">>() -> ()
|
||||
|
||||
// CHECK: hw.instance "verbatimparam" @NoArg<param: i42 =
|
||||
// CHECK-SAME: #hw.param.binary<add #hw.param.verbatim<"xxx">, 17>>() -> ()
|
||||
hw.instance "verbatimparam" @NoArg<param: i42 = #hw.param.binary<add #hw.param.verbatim<"xxx">, 17>>() -> ()
|
||||
hw.output
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ hw.module @parameters<p1: i42 = 17, wire: i1>(%p1: i8) {
|
|||
|
||||
// CHECK: hw.instance "inst" @module_with_bool<bparam: i1 = #hw.param.decl.ref<"wire_1">>
|
||||
hw.instance "inst" @module_with_bool<bparam: i1 = #hw.param.decl.ref<"wire">>() -> ()
|
||||
|
||||
// CHECK: hw.instance "inst2" @module_with_bool<bparam: i1 = #hw.param.binary<add #hw.param.verbatim<"wire">, true>>()
|
||||
hw.instance "inst2" @module_with_bool<bparam: i1 = #hw.param.binary<add #hw.param.verbatim<"wire">, true>>() -> ()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: hw.module @use_parameters
|
||||
|
|
|
@ -861,7 +861,7 @@ hw.module @UseParameterized(%a: i8) -> (ww: i8, xx: i8, yy: i8, zz: i8) {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: module UseParameterValue
|
||||
hw.module @UseParameterValue<xx: i42>(%arg0: i8) -> (out: i8) {
|
||||
hw.module @UseParameterValue<xx: i42>(%arg0: i8) -> (out1: i8, out2: i8) {
|
||||
// CHECK-NEXT: #(parameter [41:0] xx) (
|
||||
|
||||
// CHECK: parameters2 #(
|
||||
|
@ -869,6 +869,11 @@ hw.module @UseParameterValue<xx: i42>(%arg0: i8) -> (out: i8) {
|
|||
// CHECK-NEXT: ) inst1 (
|
||||
%a = hw.instance "inst1" @parameters2<p1: i42 = #hw.param.decl.ref<"xx">, p2: i1 = 0>(arg0: %arg0: i8) -> (out: i8)
|
||||
|
||||
hw.output %a : i8
|
||||
// CHECK: parameters2 #(
|
||||
// CHECK-NEXT: .p1(xx + 42'd17)
|
||||
// CHECK-NEXT: ) inst2 (
|
||||
%b = hw.instance "inst2" @parameters2<p1: i42 = #hw.param.binary<add #hw.param.verbatim<"xx">, 17>, p2: i1 = 0>(arg0: %arg0: i8) -> (out: i8)
|
||||
|
||||
hw.output %a, %b : i8, i8
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue