CIRCT  20.0.0git
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 
26 using namespace circt;
27 using namespace firrtl;
28 
29 FieldSource::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 
38 void 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 
72 void 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 
81 void 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 
90 void 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 
99 void 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 
108 void 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 
117 void FieldSource::visitMem(MemOp mem) {
118  for (auto r : mem.getResults())
119  makeNodeForValue(r, r, {}, foldFlow(r));
120 }
121 
122 void FieldSource::visitInst(InstanceOp inst) {
123  for (auto r : inst.getResults())
124  makeNodeForValue(r, r, {}, foldFlow(r));
125 }
126 
127 void 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 
139 void 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.
Definition: FIRRTLOps.cpp:212
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: sv.py:1