Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotation Scattering and trivial processing Pass #1808

Merged
merged 7 commits into from Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/circt/Dialect/FIRRTL/FIRParser.h
Expand Up @@ -30,6 +30,9 @@ struct FIRParserOptions {
/// If this is set to true, the @info locators are ignored, and the locations
/// are set to the location in the .fir file.
bool ignoreInfoLocators = false;
/// If this is set to true, the annotations are just attached to the circuit
/// and not scattered or processed.
bool rawAnnotations = false;
darthscsi marked this conversation as resolved.
Show resolved Hide resolved
};

mlir::OwningModuleRef importFIRFile(llvm::SourceMgr &sourceMgr,
Expand Down
3 changes: 3 additions & 0 deletions include/circt/Dialect/FIRRTL/FIRRTLAnnotations.h
Expand Up @@ -28,6 +28,9 @@ class FModuleLike;
/// Return the name of the attribute used for annotations on FIRRTL ops.
inline StringRef getAnnotationAttrName() { return "annotations"; }

/// Return the name of the attribute used for port annotations on FIRRTL ops.
inline StringRef getPortAnnotationAttrName() { return "portAnnotations"; }

/// Return the name of the dialect-prefixed attribute used for annotations.
inline StringRef getDialectAnnotationAttrName() { return "firrtl.annotations"; }

Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/FIRRTL/FIRRTLOpInterfaces.td
Expand Up @@ -41,7 +41,7 @@ def FModuleLike : OpInterface<"FModuleLike"> {
return $_op.portNames()[portIndex].template cast<StringAttr>();
}]>,

InterfaceMethod<"Get infromation about all ports",
InterfaceMethod<"Get information about all ports",
"SmallVector<PortInfo>", "getPorts">,

InterfaceMethod<"Get the module port directions",
Expand Down
4 changes: 4 additions & 0 deletions include/circt/Dialect/FIRRTL/Passes.h 100644 → 100755
Expand Up @@ -24,6 +24,10 @@ class Pass;
namespace circt {
namespace firrtl {

std::unique_ptr<mlir::Pass>
createLowerFIRRTLAnnotationsPass(bool ignoreUnhandledAnnotations = false,
bool ignoreClasslessAnnotations = false);

std::unique_ptr<mlir::Pass> createLowerFIRRTLTypesPass();

std::unique_ptr<mlir::Pass> createLowerBundleVectorTypesPass();
Expand Down
16 changes: 16 additions & 0 deletions include/circt/Dialect/FIRRTL/Passes.td 100644 → 100755
Expand Up @@ -15,6 +15,22 @@

include "mlir/Pass/PassBase.td"

def LowerFIRRTLAnnotations : Pass<"firrtl-lower-annotations", "firrtl::CircuitOp"> {
let summary = "Lower FIRRTL annotations to usable entities";
let description = [{
Lower FIRRTL annotations to usable forms. FIRRTL annotations are a big bag
of semi-structured, irregular json. This pass normalizes all supported
annotations and annotation paths.
}];
let constructor = "circt::firrtl::createLowerFIRRTLAnnotationsPass()";
let options = [
Option<"ignoreAnnotationClassless", "disable-annotation-classless", "bool", "false",
"Ignore classless annotations.">,
Option<"ignoreAnnotationUnknown", "disable-annotation-unknown", "bool", "true",
"Ignore unknown annotations.">
];
}

def LowerFIRRTLTypes : Pass<"firrtl-lower-types", "firrtl::CircuitOp"> {
let summary = "Lower FIRRTL types to ground types";
let description = [{
Expand Down
8 changes: 8 additions & 0 deletions lib/Dialect/FIRRTL/FIRRTLOps.cpp
Expand Up @@ -152,6 +152,14 @@ DeclKind firrtl::getDeclarationKind(Value val) {
.Default([](auto) { return DeclKind::Other; });
}

size_t firrtl::getNumPorts(Operation *op) {
if (auto extmod = dyn_cast<FExtModuleOp>(op))
return extmod.getType().getInputs().size();
if (auto mod = dyn_cast<FModuleOp>(op))
return mod.getBodyBlock()->getArguments().size();
return op->getNumResults();
Comment on lines +156 to +160
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this avoid the dynamic casts and instead use a cast to FModuleLike? Something like:

cast<FModuleLike>(op).moduleType().getInputs()

}

//===----------------------------------------------------------------------===//
// CircuitOp
//===----------------------------------------------------------------------===//
Expand Down
156 changes: 100 additions & 56 deletions lib/Dialect/FIRRTL/Import/FIRAnnotations.cpp
Expand Up @@ -251,6 +251,61 @@ static A tryGetAs(DictionaryAttr &dict, DictionaryAttr &root, StringRef key,
return valueA;
}

/// Convert arbitrary JSON to an MLIR Attribute.
static Attribute convertJSONToAttribute(MLIRContext *context,
json::Value &value, json::Path p) {
// String or quoted JSON
if (auto a = value.getAsString()) {
// Test to see if this might be quoted JSON (a string that is actually
// JSON). Sometimes FIRRTL developers will do this to serialize objects
// that the Scala FIRRTL Compiler doesn't know about.
auto unquotedValue = json::parse(a.getValue());
auto err = unquotedValue.takeError();
// If this parsed without an error, then it's more JSON and recurse on
// that.
if (!err)
return convertJSONToAttribute(context, unquotedValue.get(), p);
// If there was an error, then swallow it and handle this as a string.
handleAllErrors(std::move(err), [&](const json::ParseError &a) {});
return StringAttr::get(context, a.getValue());
}

// Integer
if (auto a = value.getAsInteger())
return IntegerAttr::get(IntegerType::get(context, 64), a.getValue());

// Float
if (auto a = value.getAsNumber())
return FloatAttr::get(mlir::FloatType::getF64(context), a.getValue());

// Boolean
if (auto a = value.getAsBoolean())
return BoolAttr::get(context, a.getValue());

// Null
if (auto a = value.getAsNull())
return mlir::UnitAttr::get(context);

// Object
if (auto a = value.getAsObject()) {
NamedAttrList metadata;
for (auto b : *a)
metadata.append(
b.first, convertJSONToAttribute(context, b.second, p.field(b.first)));
return DictionaryAttr::get(context, metadata);
}

// Array
if (auto a = value.getAsArray()) {
SmallVector<Attribute> metadata;
for (size_t i = 0, e = (*a).size(); i != e; ++i)
metadata.push_back(convertJSONToAttribute(context, (*a)[i], p.index(i)));
return ArrayAttr::get(context, metadata);
}

llvm_unreachable("Impossible unhandled JSON type");
};

/// Deserialize a JSON value into FIRRTL Annotations. Annotations are
/// represented as a Target-keyed arrays of attributes. The input JSON value is
/// checked, at runtime, to be an array of objects. Returns true if successful,
Expand Down Expand Up @@ -294,61 +349,6 @@ bool circt::firrtl::fromJSON(json::Value &value, StringRef circuitTarget,
return llvm::Optional<std::string>(target);
};

/// Convert arbitrary JSON to an MLIR Attribute.
std::function<Attribute(json::Value &, json::Path)> convertJSONToAttribute =
[&](json::Value &value, json::Path p) -> Attribute {
// String or quoted JSON
if (auto a = value.getAsString()) {
// Test to see if this might be quoted JSON (a string that is actually
// JSON). Sometimes FIRRTL developers will do this to serialize objects
// that the Scala FIRRTL Compiler doesn't know about.
auto unquotedValue = json::parse(a.getValue());
auto err = unquotedValue.takeError();
// If this parsed without an error, then it's more JSON and recurse on
// that.
if (!err)
return convertJSONToAttribute(unquotedValue.get(), p);
// If there was an error, then swallow it and handle this as a string.
handleAllErrors(std::move(err), [&](const json::ParseError &a) {});
return StringAttr::get(context, a.getValue());
}

// Integer
if (auto a = value.getAsInteger())
return IntegerAttr::get(IntegerType::get(context, 64), a.getValue());

// Float
if (auto a = value.getAsNumber())
return FloatAttr::get(mlir::FloatType::getF64(context), a.getValue());

// Boolean
if (auto a = value.getAsBoolean())
return BoolAttr::get(context, a.getValue());

// Null
if (auto a = value.getAsNull())
return mlir::UnitAttr::get(context);

// Object
if (auto a = value.getAsObject()) {
NamedAttrList metadata;
for (auto b : *a)
metadata.append(b.first,
convertJSONToAttribute(b.second, p.field(b.first)));
return DictionaryAttr::get(context, metadata);
}

// Array
if (auto a = value.getAsArray()) {
SmallVector<Attribute> metadata;
for (size_t i = 0, e = (*a).size(); i != e; ++i)
metadata.push_back(convertJSONToAttribute((*a)[i], p.index(i)));
return ArrayAttr::get(context, metadata);
}

llvm_unreachable("Impossible unhandled JSON type");
};

// The JSON value must be an array of objects. Anything else is reported as
// invalid.
auto array = value.getAsArray();
Expand Down Expand Up @@ -394,7 +394,7 @@ bool circt::firrtl::fromJSON(json::Value &value, StringRef circuitTarget,
splitAndAppendTarget(metadata, std::get<0>(NLATargets.back()), context)
.first;
for (auto field : *object) {
if (auto value = convertJSONToAttribute(field.second, p)) {
if (auto value = convertJSONToAttribute(context, field.second, p)) {
metadata.append(field.first, value);
continue;
}
Expand Down Expand Up @@ -1071,3 +1071,47 @@ bool circt::firrtl::scatterCustomAnnotations(

return true;
}

/// Deserialize a JSON value into FIRRTL Annotations. Annotations are
/// represented as a Target-keyed arrays of attributes. The input JSON value is
/// checked, at runtime, to be an array of objects. Returns true if successful,
/// false if unsuccessful.
bool circt::firrtl::fromJSONRaw(json::Value &value, StringRef circuitTarget,
SmallVectorImpl<Attribute> &attrs,
json::Path path, MLIRContext *context) {
darthscsi marked this conversation as resolved.
Show resolved Hide resolved

// The JSON value must be an array of objects. Anything else is reported as
// invalid.
auto array = value.getAsArray();
if (!array) {
path.report(
"Expected annotations to be an array, but found something else.");
return false;
}

// Build an array of annotations.
for (size_t i = 0, e = (*array).size(); i != e; ++i) {
auto object = (*array)[i].getAsObject();
auto p = path.index(i);
if (!object) {
p.report("Expected annotations to be an array of objects, but found an "
"array of something else.");
return false;
}

// Build up the Attribute to represent the Annotation
NamedAttrList metadata;

for (auto field : *object) {
if (auto value = convertJSONToAttribute(context, field.second, p)) {
metadata.append(field.first, value);
continue;
}
return false;
}

attrs.push_back(DictionaryAttr::get(context, metadata));
}

return true;
}
3 changes: 3 additions & 0 deletions lib/Dialect/FIRRTL/Import/FIRAnnotations.h
Expand Up @@ -40,6 +40,9 @@ bool scatterCustomAnnotations(llvm::StringMap<ArrayAttr> &annotationMap,
CircuitOp circuit, unsigned &annotationID,
Location loc, size_t &nlaNumber);

bool fromJSONRaw(llvm::json::Value &value, StringRef circuitTarget,
SmallVectorImpl<Attribute> &attrs, llvm::json::Path path,
MLIRContext *context);
} // namespace firrtl
} // namespace circt

Expand Down