CIRCT 20.0.0git
Loading...
Searching...
No Matches
FIRRTLFieldSource.cpp
Go to the documentation of this file.
1//===- FIRRTLFieldSource.cpp - Field Source Analysis ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a basic points-to like analysis.
10// This analysis tracks any aggregate generated by an operation and maps any
11// value derived from indexing of that aggregate back to the source of the
12// aggregate along with a path through the type from the source. In parallel,
13// this tracks any value which is an alias for a writable storage element, even
14// if scalar. This is sufficient to allow any value used on the LHS of a
15// connect to be traced to its source, and to track any value which is a read
16// of a storage element back to the source storage element.
17//
18// There is a redundant walk of the IR going on since flow is walking backwards
19// over operations we've already visited. We need to refactor foldFlow so we
20// can build up the flow incrementally.
21//
22//===----------------------------------------------------------------------===//
23
25
26using namespace circt;
27using namespace firrtl;
28
29FieldSource::FieldSource(Operation *operation) {
30 FModuleOp mod = cast<FModuleOp>(operation);
31 // All ports define locations
32 for (auto port : mod.getBodyBlock()->getArguments())
33 makeNodeForValue(port, port, {}, foldFlow(port));
34
35 mod.walk<mlir::WalkOrder::PreOrder>([&](Operation *op) { visitOp(op); });
36}
37
38void FieldSource::visitOp(Operation *op) {
39 if (auto sf = dyn_cast<SubfieldOp>(op))
40 return visitSubfield(sf);
41 if (auto sf = dyn_cast<OpenSubfieldOp>(op))
42 return visitOpenSubfield(sf);
43
44 if (auto si = dyn_cast<SubindexOp>(op))
45 return visitSubindex(si);
46 if (auto si = dyn_cast<OpenSubindexOp>(op))
47 return visitOpenSubindex(si);
48
49 if (auto sa = dyn_cast<SubaccessOp>(op))
50 return visitSubaccess(sa);
51
52 if (isa<WireOp, RegOp, RegResetOp, InvalidValueOp, chirrtl::MemoryPortOp>(op))
53 return makeNodeForValue(op->getResult(0), op->getResult(0), {},
54 foldFlow(op->getResult(0)));
55 if (auto mem = dyn_cast<MemOp>(op))
56 return visitMem(mem);
57 if (auto inst = dyn_cast<InstanceOp>(op))
58 return visitInst(inst);
59 if (auto inst = dyn_cast<InstanceChoiceOp>(op))
60 return visitInstChoice(inst);
61
62 // Track all other definitions of aggregates.
63 if (op->getNumResults()) {
64 auto type = op->getResult(0).getType();
65 if (auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
66 baseType && !baseType.isGround())
67 makeNodeForValue(op->getResult(0), op->getResult(0), {},
68 foldFlow(op->getResult(0)));
69 }
70}
71
72void FieldSource::visitSubfield(SubfieldOp sf) {
73 auto value = sf.getInput();
74 const auto *node = nodeForValue(value);
75 assert(node && "node should be in the map");
76 auto sv = node->path;
77 sv.push_back(sf.getFieldIndex());
78 makeNodeForValue(sf.getResult(), node->src, sv, foldFlow(sf));
79}
80
81void FieldSource::visitOpenSubfield(OpenSubfieldOp sf) {
82 auto value = sf.getInput();
83 const auto *node = nodeForValue(value);
84 assert(node && "node should be in the map");
85 auto sv = node->path;
86 sv.push_back(sf.getFieldIndex());
87 makeNodeForValue(sf.getResult(), node->src, sv, foldFlow(sf));
88}
89
90void FieldSource::visitSubindex(SubindexOp si) {
91 auto value = si.getInput();
92 const auto *node = nodeForValue(value);
93 assert(node && "node should be in the map");
94 auto sv = node->path;
95 sv.push_back(si.getIndex());
96 makeNodeForValue(si.getResult(), node->src, sv, foldFlow(si));
97}
98
99void FieldSource::visitOpenSubindex(OpenSubindexOp si) {
100 auto value = si.getInput();
101 const auto *node = nodeForValue(value);
102 assert(node && "node should be in the map");
103 auto sv = node->path;
104 sv.push_back(si.getIndex());
105 makeNodeForValue(si.getResult(), node->src, sv, foldFlow(si));
106}
107
108void FieldSource::visitSubaccess(SubaccessOp sa) {
109 auto value = sa.getInput();
110 const auto *node = nodeForValue(value);
111 assert(node && "node should be in the map");
112 auto sv = node->path;
113 sv.push_back(-1);
114 makeNodeForValue(sa.getResult(), node->src, sv, foldFlow(sa));
115}
116
117void FieldSource::visitMem(MemOp mem) {
118 for (auto r : mem.getResults())
119 makeNodeForValue(r, r, {}, foldFlow(r));
120}
121
122void FieldSource::visitInst(InstanceOp inst) {
123 for (auto r : inst.getResults())
124 makeNodeForValue(r, r, {}, foldFlow(r));
125}
126
127void FieldSource::visitInstChoice(InstanceChoiceOp inst) {
128 for (auto r : inst.getResults())
129 makeNodeForValue(r, r, {}, foldFlow(r));
130}
131
133 auto ii = paths.find(v);
134 if (ii == paths.end())
135 return nullptr;
136 return &ii->second;
137}
138
139void FieldSource::makeNodeForValue(Value dst, Value src, ArrayRef<int64_t> path,
140 Flow flow) {
141 auto ii = paths.try_emplace(dst, src, path, flow);
142 (void)ii;
143 assert(ii.second && "Double insert into the map");
144}
assert(baseType &&"element must be base type")
const PathNode * nodeForValue(Value v) const
void visitSubaccess(SubaccessOp sa)
void visitOpenSubfield(OpenSubfieldOp sf)
DenseMap< Value, PathNode > paths
void visitInstChoice(InstanceChoiceOp inst)
void visitSubfield(SubfieldOp sf)
FieldSource(Operation *operation)
void visitInst(InstanceOp inst)
void visitOpenSubindex(OpenSubindexOp si)
void makeNodeForValue(Value dst, Value src, ArrayRef< int64_t > path, Flow flow)
void visitSubindex(SubindexOp si)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition sv.py:1