Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions docs/FIRRTLAnnotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,106 @@ Example:
}
```

### OMIRFileAnnotation

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `freechips.rocketchip.objectmodel.OMIRFileAnnotation` |
| filename | string | Output file to emit OMIR to |

This annotation defines the output file to write the JSON-serialized OMIR to after compilation.

Example:
```json
{
"class": "freechips.rocketchip.objectmodel.OMIRFileAnnotation",
"filename": "path/to/omir.json"
}
```

### OMIRAnnotation

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `freechips.rocketchip.objectmodel.OMIRAnnotation` |
| nodes | array | A list of OMIR nodes |

This annotation specifies a piece of Object Model 2.0 IR. The `nodes` field
is an array of individual OMIR nodes (Scala class `OMNode`), which have the
following form:
```json
{
"info": "@[FileA line:col FileB line:col ...]",
"id": "OMID:42",
"fields": [/*...*/]
}
```
The `fields` entry is an array of individual OMIR fields (Scala class `OMField`), which have the following form:
```json
{
"info": "@[FileA line:col FileB line:col ...]",
"name": "foo",
"value": /*...*/
}
```
The `value` field can be a JSON array or dictionary (corresponding to the `OMArray` and `OMMap` Scala classes, respectively), or any of the string-encoded OMIR classes:

- `OMMap:<fields>`
- `OMArray:<elements>`
- `OMReference:<id>`
- `OMBigInt:<value>`
- `OMInt:<value>`
- `OMLong:<value>`
- `OMString:<value>`
- `OMBoolean:<value>`
- `OMDouble:<value>`
- `OMBigDecimal:<value>`
- `OMFrozenTarget:<omir>`
- `OMDeleted`
- `OMConstant:<literal>`
- `OMReferenceTarget:<target>`
- `OMMemberReferenceTarget:<target>`
- `OMMemberInstanceTarget:<target>`
- `OMInstanceTarget:<target>`
- `OMDontTouchedReferenceTarget:<target>`

Example:
```json
{
"class": "freechips.rocketchip.objectmodel.OMIRAnnotation",
"nodes": [
{
"info": "",
"id": "OMID:0",
"fields": [
{"info": "", "name": "a", "value": "OMReference:0"},
{"info": "", "name": "b", "value": "OMBigInt:42"},
{"info": "", "name": "c", "value": "OMLong:ff"},
{"info": "", "name": "d", "value": "OMString:hello"},
{"info": "", "name": "f", "value": "OMBigDecimal:10.5"},
{"info": "", "name": "g", "value": "OMDeleted:"},
{"info": "", "name": "h", "value": "OMConstant:UInt<2>(\"h1\")"},
{"info": "", "name": "i", "value": 42},
{"info": "", "name": "j", "value": true},
{"info": "", "name": "k", "value": 3.14}
]
},
{
"info": "",
"id": "OMID:1",
"fields": [
{"info": "", "name": "a", "value": "OMReferenceTarget:~Foo|Foo"},
{"info": "", "name": "b", "value": "OMInstanceTarget:~Foo|Foo"},
{"info": "", "name": "c", "value": "OMMemberReferenceTarget:~Foo|Foo"},
{"info": "", "name": "d", "value": "OMMemberInstanceTarget:~Foo|Foo"},
{"info": "", "name": "e", "value": "OMDontTouchedReferenceTarget:~Foo|Foo"},
{"info": "", "name": "f", "value": "OMReferenceTarget:~Foo|Bar"}
]
}
]
}
```

### RetimeModuleAnnotation

| Property | Type | Description |
Expand Down
2 changes: 2 additions & 0 deletions include/circt/Dialect/FIRRTL/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ createCreateSiFiveMetadataPass(bool replSeqMem = false,
StringRef replSeqMemCircuit = "",
StringRef replSeqMemFile = "");

std::unique_ptr<mlir::Pass> createEmitOMIRPass(StringRef outputFilename = "");

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

std::unique_ptr<mlir::Pass> createInferWidthsPass();
Expand Down
13 changes: 13 additions & 0 deletions include/circt/Dialect/FIRRTL/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ def CreateSiFiveMetadata : Pass<"firrtl-emit-metadata", "firrtl::CircuitOp"> {
];
}

def EmitOMIR : Pass<"firrtl-emit-omir", "firrtl::CircuitOp"> {
let summary = "Emit OMIR annotations";
let description = [{
This pass gathers the `OMIRAnnotation`s in the design, updates the contained
targets with the trackers that were scattered throughout the design upon
reading the OMIR, and serializes the resulting data into a JSON file.
}];
let constructor = "circt::firrtl::createEmitOMIRPass()";
let options = [Option<"outputFilename", "file", "std::string", "",
Copy link
Contributor

Choose a reason for hiding this comment

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

This pass only makes sense with an output file, yes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now there's still a OMIRFileAnnotation, which we probably want to get rid of in favor of command line args.

"Output file for the JSON-serialized OMIR data">];
let dependentDialects = ["sv::SVDialect", "hw::HWDialect"];
}

def ExpandWhens : Pass<"firrtl-expand-whens", "firrtl::FModuleOp"> {
let summary = "Remove all when conditional blocks.";
let description = [{
Expand Down
4 changes: 3 additions & 1 deletion lib/Dialect/FIRRTL/Import/FIRAnnotations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace json = llvm::json;

using namespace circt;
using namespace firrtl;
using mlir::UnitAttr;

/// Split a target into a base target (including a reference if one exists) and
/// an optional array of subfield/subindex tokens.
Expand Down Expand Up @@ -891,6 +892,7 @@ scatterOMIR(Attribute original, unsigned &annotationID,
NamedAttrList fields;
fields.append("id",
IntegerAttr::get(IntegerType::get(ctx, 64), annotationID++));
fields.append("omir.tracker", UnitAttr::get(ctx));
fields.append("type", StringAttr::get(ctx, tpe));
Comment on lines +895 to 896
Copy link
Member

Choose a reason for hiding this comment

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

Is adding this singleton strictly necessary?

Note: I like omir.tracker better than the "freechips.rocketchip.objectmodel.OMIRTracker" which I made up for the scattered targets.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem here is that when you see {type = "asdf", id = 42} in the value field (or nested within it), it's not clear if this is a OMMap with fields "type" and "id", or if this used to be a OM.+Target. Adding the omir.tracker unit is an unambiguous marker that the dictionary is actually a OM.+Target, because there's nothing in the original OMIR input JSON that can generate such a unit attr.

Copy link
Contributor Author

@fabianschuiki fabianschuiki Oct 20, 2021

Choose a reason for hiding this comment

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

Also, for the OMIRTracker annotations it's important that we still have a "class" field, since that's what we implicitly require for the annotations array on operations.

return DictionaryAttr::getWithSorted(ctx, fields);
};
Expand All @@ -916,9 +918,9 @@ scatterOMIR(Attribute original, unsigned &annotationID,
tpe == "OMMemberInstanceTarget" || tpe == "OMInstanceTarget" ||
tpe == "OMDontTouchedReferenceTarget") {
NamedAttrList tracker;
tracker.append("class", StringAttr::get(ctx, omirTrackerAnnoClass));
tracker.append(
"id", IntegerAttr::get(IntegerType::get(ctx, 64), annotationID));
tracker.append("type", StringAttr::get(ctx, tpe));

auto canonTarget = canonicalizeTarget(value);
if (!canonTarget)
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/FIRRTL/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_circt_dialect_library(CIRCTFIRRTLTransforms
BlackBoxReader.cpp
CheckCombCycles.cpp
CreateSiFiveMetadata.cpp
EmitOMIR.cpp
ExpandWhens.cpp
GrandCentral.cpp
GrandCentralTaps.cpp
Expand Down
Loading