Skip to content

Commit

Permalink
[SV] Move emitAsComment to SVAttributeAttr; remove SVAttributesAttr (#…
Browse files Browse the repository at this point in the history
…4743)

* [SV] Move emitAsComment to SVAttributeAttr; remove SVAttributesAttr

Move the `emitAsComments` flag from `SVAttributesAttr` (plural) to
`SVAttributeAttr` (singular). Then remove `SVAttributesAttr` (plural)
since it only contains a single array field after `emitAsComments` is
gone.

Add add, remove, and read-modify-write functions to deal with SV
attributes on operations more conveniently. Also enforce deduplicated
SV attributes where easily possible. The new functions now allow for
easy addition and removal of individual SV attributes.

Adapt ExportVerilog to handle the fact that emission as comments is now
a per-attribute option. The emission code now can emit multiple
`/*...*/` and `(*...*)` groups if needed, but tries to pack as many
consecutive attributes with the same `emitAsComment` flag into one
group.

* [ExportVerilog] PP-ify SV attribute emission.

* Test pretty-printing of SV attributes on statements.

* Tweak whitespaces between SV attributes

---------

Co-authored-by: Will Dietz <[email protected]>
  • Loading branch information
fabianschuiki and dtzSiFive authored Mar 1, 2023
1 parent 38b1f39 commit 811f79d
Show file tree
Hide file tree
Showing 15 changed files with 415 additions and 184 deletions.
14 changes: 4 additions & 10 deletions include/circt-c/Dialect/SV.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,13 @@ MLIR_CAPI_EXPORTED void registerSVPasses();
//===----------------------------------------------------------------------===//

MLIR_CAPI_EXPORTED bool svAttrIsASVAttributeAttr(MlirAttribute);
MLIR_CAPI_EXPORTED MlirAttribute svSVAttributeAttrGet(MlirContext cCtxt,
MLIR_CAPI_EXPORTED MlirAttribute svSVAttributeAttrGet(MlirContext,
MlirStringRef name,
MlirStringRef expression);
MlirStringRef expression,
bool emitAsComment);
MLIR_CAPI_EXPORTED MlirStringRef svSVAttributeAttrGetName(MlirAttribute);
MLIR_CAPI_EXPORTED MlirStringRef svSVAttributeAttrGetExpression(MlirAttribute);

MLIR_CAPI_EXPORTED bool svAttrIsASVAttributesAttr(MlirAttribute);
MLIR_CAPI_EXPORTED MlirAttribute svSVAttributesAttrGet(MlirContext cCtxt,
MlirAttribute attributes,
bool emitAsComments);
MLIR_CAPI_EXPORTED MlirAttribute svSVAttributesAttrGetAttributes(MlirAttribute);
MLIR_CAPI_EXPORTED
bool svSVAttributesAttrGetEmitAsComments(MlirAttribute);
MLIR_CAPI_EXPORTED bool svSVAttributeAttrGetEmitAsComment(MlirAttribute);

#ifdef __cplusplus
}
Expand Down
56 changes: 49 additions & 7 deletions include/circt/Dialect/SV/SVAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,65 @@

#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"

#include "circt/Dialect/SV/SVEnums.h.inc"
#define GET_ATTRDEF_CLASSES
#include "circt/Dialect/SV/SVAttributes.h.inc"

namespace circt {
namespace sv {
class SVAttributesAttr;

/// Helper functions to handle SV attributes.
bool hasSVAttributes(mlir::Operation *op);
SVAttributesAttr getSVAttributes(mlir::Operation *op);
void setSVAttributes(mlir::Operation *op, mlir::Attribute);

} // namespace sv
/// Return all the SV attributes of an operation, or null if there are none. All
/// array elements are `SVAttributeAttr`.
mlir::ArrayAttr getSVAttributes(mlir::Operation *op);

} // namespace circt
/// Set the SV attributes of an operation. If `attrs` is null or contains no
/// attributes, the attribute is removed from the op.
void setSVAttributes(mlir::Operation *op, mlir::ArrayAttr attrs);

#define GET_ATTRDEF_CLASSES
#include "circt/Dialect/SV/SVAttributes.h.inc"
/// Set the SV attributes of an operation. If `attrs` is empty the attribute is
/// removed from the op. The attributes are deduplicated such that only one copy
/// of each attribute is kept on the operation.
void setSVAttributes(mlir::Operation *op,
mlir::ArrayRef<SVAttributeAttr> attrs);

/// Check if an op contains a specific SV attribute.
inline bool hasSVAttribute(mlir::Operation *op, SVAttributeAttr attr) {
return llvm::is_contained(getSVAttributes(op), attr);
}

/// Modify the list of SV attributes of an operation. This function offers a
/// read-modify-write interface where the callback can modify the list of
/// attributes how it sees fit. Returns true if any modifications occurred.
bool modifySVAttributes(
mlir::Operation *op,
llvm::function_ref<void(llvm::SmallVectorImpl<SVAttributeAttr> &)>
modifyCallback);

/// Add a list of SV attributes to an operation. The attributes are deduplicated
/// such that only one copy of each attribute is kept on the operation. Returns
/// the number of attributes that were added.
unsigned addSVAttributes(mlir::Operation *op,
llvm::ArrayRef<SVAttributeAttr> attrs);

/// Remove the SV attributes from an operation for which `removeCallback`
/// returns true. Returns the number of attributes actually removed.
unsigned
removeSVAttributes(mlir::Operation *op,
llvm::function_ref<bool(SVAttributeAttr)> removeCallback);

/// Remove a list of SV attributes from an operation. Returns the number of
/// attributes actually removed.
unsigned removeSVAttributes(mlir::Operation *op,
llvm::ArrayRef<SVAttributeAttr> attrs);

} // namespace sv
} // namespace circt

#endif // CIRCT_DIALECT_SV_SVATTRIBUTES_H
65 changes: 32 additions & 33 deletions include/circt/Dialect/SV/SVAttributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -53,42 +53,41 @@ def SVAttributeAttr : AttrDef<SVDialect, "SVAttribute"> {
For more information, refer to Section 5.12 of the SystemVerilog (1800-2017)
specification.
}];
let parameters = (ins "::mlir::StringAttr":$name,
OptionalParameter<"::mlir::StringAttr">:$expression);
let parameters = (ins
"::mlir::StringAttr":$name,
OptionalParameter<"::mlir::StringAttr">:$expression,
DefaultValuedParameter<
"mlir::BoolAttr", "mlir::BoolAttr::get($_ctxt, false)">:$emitAsComment
);

let assemblyFormat = [{ `<` $name ( `=` $expression^ )? `>` }];
let builders = [
AttrBuilder<(ins "::llvm::StringRef":$name,
CArg<"bool", "false">: $emitAsComment), [{
return get(context, StringAttr::get(context, name), StringAttr(),
BoolAttr::get(context, emitAsComment));
}]>,
AttrBuilder<(ins "::mlir::StringAttr":$name,
CArg<"bool", "false">: $emitAsComment), [{
return get(context, name, StringAttr(),
BoolAttr::get(context, emitAsComment));
}]>,
AttrBuilder<(ins "::llvm::StringRef":$name,
"::llvm::StringRef":$expression,
CArg<"bool", "false">: $emitAsComment), [{
return get(context, StringAttr::get(context, name),
StringAttr::get(context, expression),
BoolAttr::get(context, emitAsComment));
}]>,
AttrBuilder<(ins "::mlir::StringAttr":$name,
"::mlir::StringAttr":$expression,
CArg<"bool", "false">: $emitAsComment), [{
return get(context, name, expression,
BoolAttr::get(context, emitAsComment));
}]>
];
let hasCustomAssemblyFormat = true;
let extraClassDeclaration = [{
static inline llvm::StringRef
getSVAttributesAttrName() { return "sv.attributes"; }
}];
}

def SVAttributesAttr : AttrDef<SVDialect, "SVAttributes"> {
let summary = "A container of system verilog attributes";
let mnemonic = "attributes";
let description = [{
This attribute is used to store SV attributes. The `attributes` field
represents SV attributes we want to annotate. The `emitAsComments` field
controls its emission style: SV spec defines the syntax of SV attributes as
`(* identifier (= identifer)? *)`. However, unfortunately many vendor-specific
pragmas violate the syntax and they are intended to be attached as comments.
Hence we emit given attributes as comments if `emitAsComments` field is true.
}];
let parameters = (ins "mlir::ArrayAttr":$attributes,
DefaultValuedParameter<"mlir::BoolAttr",
"mlir::BoolAttr::get($_ctxt, false)">:$emitAsComments);
let builders = [
AttrBuilder<(ins "llvm::ArrayRef<llvm::StringRef>":$strings,
CArg<"bool", "false">: $emitAsComments), [{
SmallVector<Attribute> attrs;
for (auto str : strings)
attrs.push_back(sv::SVAttributeAttr::get(
$_ctxt, ::mlir::StringAttr::get($_ctxt, str), ::mlir::StringAttr()));
return $_get($_ctxt, ::mlir::ArrayAttr::get($_ctxt, attrs),
::mlir::BoolAttr::get($_ctxt, emitAsComments));
}]>,
AttrBuilder<(ins
"llvm::ArrayRef<std::pair<llvm::StringRef, llvm::StringRef>>":$keyValuePairs,
CArg<"bool", "false">: $emitAsComments)>];
let hasCustomAssemblyFormat = true;
}
5 changes: 2 additions & 3 deletions integration_test/Bindings/Python/dialects/seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@ def top(module):
# CHECK: %FuBar = seq.compreg {{.+}}
seq.reg(reg_input, module.clk, name="FuBar")

# CHECK: %reg1 = seq.compreg %[[INPUT_VAL]], %clk {sv.attributes = #sv.attributes<[#sv.attribute<"no_merge">]>} : i32
# CHECK: %reg1 = seq.compreg %[[INPUT_VAL]], %clk {sv.attributes = [#sv.attribute<"no_merge">]} : i32
sv_attr = sv.SVAttributeAttr.get("no_merge")
reg1 = seq.CompRegOp.create(i32, clk=module.clk, name="reg1")

reg1.attributes["sv.attributes"] = sv.SVAttributesAttr.get(
ArrayAttr.get([sv_attr]))
reg1.attributes["sv.attributes"] = ArrayAttr.get([sv_attr])
connect(reg1.input, reg_input)

# CHECK: %reg2 = seq.compreg %[[INPUT_VAL]], %clk
Expand Down
33 changes: 10 additions & 23 deletions lib/Bindings/Python/SVModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void circt::python::populateDialectSVSubmodule(py::module &m) {
.def_classmethod(
"get",
[](py::object cls, std::string name, py::object expressionObj,
MlirContext ctxt) {
bool emitAsComment, MlirContext ctxt) {
// Need temporary storage for casted string.
std::string expr;
MlirStringRef expression = {nullptr, 0};
Expand All @@ -40,40 +40,27 @@ void circt::python::populateDialectSVSubmodule(py::module &m) {
expression = mlirStringRefCreateFromCString(expr.c_str());
}
return cls(svSVAttributeAttrGet(
ctxt, mlirStringRefCreateFromCString(name.c_str()),
expression));
ctxt, mlirStringRefCreateFromCString(name.c_str()), expression,
emitAsComment));
},
"Create a SystemVerilog attribute", py::arg(), py::arg("name"),
py::arg("expression") = py::none(), py::arg("ctxt") = py::none())
py::arg("expression") = py::none(),
py::arg("emit_as_comment") = py::none(), py::arg("ctxt") = py::none())
.def_property_readonly("name",
[](MlirAttribute self) {
MlirStringRef name =
svSVAttributeAttrGetName(self);
return std::string(name.data, name.length);
})
.def_property_readonly(
"expression", [](MlirAttribute self) -> py::object {
"expression",
[](MlirAttribute self) -> py::object {
MlirStringRef name = svSVAttributeAttrGetExpression(self);
if (name.data == nullptr)
return py::none();
return py::str(std::string(name.data, name.length));
});

mlir_attribute_subclass(m, "SVAttributesAttr", svAttrIsASVAttributesAttr)
.def_classmethod(
"get",
[](py::object cls, MlirAttribute attributes, bool emitAsComments,
MlirContext ctxt) {
return cls(svSVAttributesAttrGet(ctxt, attributes, emitAsComments));
},
"Create SV attributes attr", py::arg(), py::arg("attributes"),
py::arg("emit_as_comments") = py::none(),
py::arg("ctxt") = py::none())
.def_property_readonly("attributes",
[](MlirAttribute self) {
return svSVAttributesAttrGetAttributes(self);
})
.def_property_readonly("emit_as_comments", [](MlirAttribute self) {
return svSVAttributesAttrGetEmitAsComments(self);
})
.def_property_readonly("emit_as_comment", [](MlirAttribute self) {
return svSVAttributeAttrGetEmitAsComment(self);
});
}
32 changes: 9 additions & 23 deletions lib/CAPI/Dialect/SV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ bool svAttrIsASVAttributeAttr(MlirAttribute cAttr) {
}

MlirAttribute svSVAttributeAttrGet(MlirContext cCtxt, MlirStringRef cName,
MlirStringRef cExpression) {
MlirStringRef cExpression,
bool emitAsComment) {
mlir::MLIRContext *ctxt = unwrap(cCtxt);
mlir::StringAttr expr;
if (cExpression.data != nullptr)
expr = mlir::StringAttr::get(ctxt, unwrap(cExpression));
return wrap(SVAttributeAttr::get(
ctxt, mlir::StringAttr::get(ctxt, unwrap(cName)), expr));
return wrap(
SVAttributeAttr::get(ctxt, mlir::StringAttr::get(ctxt, unwrap(cName)),
expr, mlir::BoolAttr::get(ctxt, emitAsComment)));
}

MlirStringRef svSVAttributeAttrGetName(MlirAttribute cAttr) {
Expand All @@ -42,25 +44,9 @@ MlirStringRef svSVAttributeAttrGetExpression(MlirAttribute cAttr) {
return {nullptr, 0};
}

bool svAttrIsASVAttributesAttr(MlirAttribute cAttr) {
return unwrap(cAttr).isa<SVAttributesAttr>();
}

MlirAttribute svSVAttributesAttrGet(MlirContext cCtxt, MlirAttribute attributes,
bool emitAsComments) {
mlir::MLIRContext *ctxt = unwrap(cCtxt);
return wrap(SVAttributesAttr::get(ctxt,
unwrap(attributes).cast<mlir::ArrayAttr>(),
mlir::BoolAttr::get(ctxt, emitAsComments)));
}

MlirAttribute svSVAttributesAttrGetAttributes(MlirAttribute attributes) {
return wrap(unwrap(attributes).cast<SVAttributesAttr>().getAttributes());
}

bool svSVAttributesAttrGetEmitAsComments(MlirAttribute attributes) {
return unwrap(attributes)
.cast<SVAttributesAttr>()
.getEmitAsComments()
bool svSVAttributeAttrGetEmitAsComment(MlirAttribute attribute) {
return unwrap(attribute)
.cast<SVAttributeAttr>()
.getEmitAsComment()
.getValue();
}
67 changes: 53 additions & 14 deletions lib/Conversion/ExportVerilog/ExportVerilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,18 +751,57 @@ static IfOp findNestedElseIf(Block *elseBlock) {

/// Emit SystemVerilog attributes.
template <typename PPS>
static void emitSVAttributesImpl(PPS &os, sv::SVAttributesAttr svAttrs) {
// Emit without any breaks.
auto body = svAttrs.getAttributes();
auto emitAsComments = svAttrs.getEmitAsComments().getValue();
os << (emitAsComments ? "/* " : "(* ");
llvm::interleaveComma(body, os, [&](Attribute attr) {
auto svattr = attr.cast<SVAttributeAttr>();
os << PPExtString(svattr.getName().getValue());
if (svattr.getExpression())
os << " = " << PPExtString(svattr.getExpression().getValue());
static void emitSVAttributesImpl(PPS &ps, ArrayAttr attrs, bool mayBreak) {
enum Container { NoContainer, InComment, InAttr };
Container currentContainer = NoContainer;

auto closeContainer = [&] {
if (currentContainer == NoContainer)
return;
if (currentContainer == InComment)
ps << " */";
else if (currentContainer == InAttr)
ps << " *)";
ps << PP::end << PP::end;

currentContainer = NoContainer;
};

bool isFirstContainer = true;
auto openContainer = [&](Container newContainer) {
assert(newContainer != NoContainer);
if (currentContainer == newContainer)
return false;
closeContainer();
// If not first container, insert break point but no space.
if (!isFirstContainer)
ps << (mayBreak ? PP::space : PP::nbsp);
isFirstContainer = false;
// fit container on one line if possible, break if needed.
ps << PP::ibox0;
if (newContainer == InComment)
ps << "/* ";
else if (newContainer == InAttr)
ps << "(* ";
currentContainer = newContainer;
// Pack attributes within to fit, align to current column when breaking.
ps << PP::ibox0;
return true;
};

// Break containers to starting column (0), put all on same line OR
// put each on their own line (cbox).
ps.scopedBox(PP::cbox0, [&]() {
for (auto attr : attrs.getAsRange<SVAttributeAttr>()) {
if (!openContainer(attr.getEmitAsComment().getValue() ? InComment
: InAttr))
ps << "," << (mayBreak ? PP::space : PP::nbsp);
ps << PPExtString(attr.getName().getValue());
if (attr.getExpression())
ps << " = " << PPExtString(attr.getExpression().getValue());
}
closeContainer();
});
os << (emitAsComments ? " */" : " *)");
}

/// Retrieve value's verilog name from IR. The name must already have been
Expand Down Expand Up @@ -2055,7 +2094,7 @@ void ExprEmitter::emitSVAttributes(Operation *op) {

// For now, no breaks for attributes.
ps << PP::nbsp;
emitSVAttributesImpl(ps, svAttrs);
emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/false);
}

/// If the specified extension is a zero extended version of another value,
Expand Down Expand Up @@ -3003,7 +3042,7 @@ void StmtEmitter::emitSVAttributes(Operation *op) {
return;

startStatement(); // For attributes.
emitSVAttributesImpl(ps, svAttrs);
emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/true);
setPendingNewline();
}

Expand Down Expand Up @@ -4486,7 +4525,7 @@ void ModuleEmitter::emitSVAttributes(Operation *op) {
return;

startStatement(); // For attributes.
emitSVAttributesImpl(ps, svAttrs);
emitSVAttributesImpl(ps, svAttrs, /*mayBreak=*/true);
setPendingNewline();
}

Expand Down
Loading

0 comments on commit 811f79d

Please sign in to comment.