Cerata
A library to generate structural hardware designs
flattype.cc
1 // Copyright 2018-2019 Delft University of Technology
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "cerata/flattype.h"
16 
17 #include <optional>
18 #include <utility>
19 #include <memory>
20 #include <vector>
21 #include <string>
22 #include <iomanip>
23 #include <iostream>
24 
25 #include "cerata/utils.h"
26 #include "cerata/type.h"
27 #include "cerata/node.h"
28 #include "cerata/expression.h"
29 
30 namespace cerata {
31 
32 std::string FlatType::name(const NamePart &root, const std::string &sep) const {
33  std::stringstream ret;
34  if (root.sep && !name_parts_.empty()) {
35  ret << root.str + sep;
36  } else {
37  ret << root.str;
38  }
39  for (size_t p = 0; p < name_parts_.size(); p++) {
40  if ((p != name_parts_.size() - 1) && name_parts_[p].sep) {
41  ret << name_parts_[p].str + sep;
42  } else {
43  ret << name_parts_[p].str;
44  }
45  }
46  return ret.str();
47 }
48 
49 FlatType::FlatType(Type *t, std::vector<NamePart> prefix, const std::string &name, bool invert)
50  : type_(t), reverse_(invert) {
51  name_parts_ = std::move(prefix);
52  name_parts_.emplace_back(name, true);
53 }
54 
55 bool operator<(const FlatType &a, const FlatType &b) {
56  if (a.nesting_level_ == b.nesting_level_) {
57  return a.name() < b.name();
58  } else {
59  return a.nesting_level_ < b.nesting_level_;
60  }
61 }
62 
63 void FlattenRecord(std::vector<FlatType> *list,
64  const Record *record,
65  const std::optional<FlatType> &parent,
66  bool invert) {
67  for (const auto &f : record->fields()) {
68  Flatten(list, f->type().get(), parent, f->name(), invert != f->reversed(), f->sep());
69  }
70 }
71 
72 void Flatten(std::vector<FlatType> *list,
73  Type *type,
74  const std::optional<FlatType> &parent,
75  const std::string &name,
76  bool invert,
77  bool sep) {
78  FlatType result;
79  result.reverse_ = invert;
80  if (parent) {
81  result.nesting_level_ = (*parent).nesting_level_ + 1;
82  result.name_parts_ = (*parent).name_parts_;
83  }
84  result.type_ = type;
85  if (!name.empty()) {
86  result.name_parts_.emplace_back(name, sep);
87  }
88  list->push_back(result);
89 
90  switch (type->id()) {
91  case Type::RECORD:FlattenRecord(list, dynamic_cast<Record *>(type), result, invert);
92  break;
93  default:break;
94  }
95 }
96 
97 std::vector<FlatType> Flatten(Type *type) {
98  std::vector<FlatType> result;
99  Flatten(&result, type, {}, "", false);
100  return result;
101 }
102 
103 std::string ToString(std::vector<FlatType> flat_type_list) {
104  std::stringstream ret;
105  for (size_t i = 0; i < flat_type_list.size(); i++) {
106  const auto &ft = flat_type_list[i];
107  auto name = ft.name(ft.nesting_level_ == 0 ? NamePart("(root)") : NamePart());
108  ret << std::setw(3) << std::right << i << " :"
109  << std::setw(32) << std::left
110  << std::string(static_cast<int64_t>(2 * ft.nesting_level_), ' ') + name << " | "
111  << std::setw(16) << std::left << ft.type_->name() << " | "
112  << std::setw(3) << std::right << ft.nesting_level_ << " | ";
113  if (ft.type_->width()) {
114  ret << std::setw(3) << std::right << (*ft.type_->width())->ToString() << " | ";
115  } else {
116  ret << std::setw(3) << std::right << 0 << " | ";
117  }
118  ret << std::setw(8) << std::left << ft.type_->ToString(true) << std::endl;
119  }
120  return ret.str();
121 }
122 
123 bool ContainsFlatType(const std::vector<FlatType> &flat_types_list, const Type *type) {
124  for (const auto &ft : flat_types_list) {
125  if (ft.type_ == type) {
126  return true;
127  }
128  }
129  return false;
130 }
131 
132 int64_t IndexOfFlatType(const std::vector<FlatType> &flat_types_list, const Type *type) {
133  for (size_t i = 0; i < flat_types_list.size(); i++) {
134  if (flat_types_list[i].type_ == type) {
135  return i;
136  }
137  }
138  return static_cast<int64_t>(-1);
139 }
140 
142  : Named(a->name() + "_to_" + b->name()),
143  fa_(Flatten(a)), fb_(Flatten(b)),
144  a_(a), b_(b),
145  matrix_(MappingMatrix<int64_t>(fa_.size(), fb_.size())) {
146  // If the types are the same, the mapping is trivial and implicitly constructed.
147  // The matrix will be the identity matrix.
148  if (a_ == b_) {
149  for (size_t i = 0; i < fa_.size(); i++) {
150  matrix_(i, i) = 1;
151  }
152  }
153 }
154 
155 std::shared_ptr<TypeMapper> TypeMapper::Make(Type *a, Type *b) {
156  auto ret = std::make_shared<TypeMapper>(a, b);
157  return ret;
158 }
159 
160 std::shared_ptr<TypeMapper> TypeMapper::MakeImplicit(Type *a, Type *b) {
161  auto ret = std::make_shared<TypeMapper>(a, b);
162  if (a->IsEqual(*b)) {
163  for (size_t i = 0; i < ret->flat_a().size(); i++) {
164  ret->Add(i, i);
165  }
166  }
167  return ret;
168 }
169 
170 TypeMapper &TypeMapper::Add(int64_t a, int64_t b) {
171  matrix_.SetNext(a, b);
172  return *this;
173 }
174 
175 std::string TypeMapper::ToString() const {
176  constexpr int w = 20;
177  std::stringstream ret;
178  ret << "TypeMapper (a) " << a()->ToString(true, true) + " => (b) " + b()->ToString(true, true) + "\n";
179  ret << " Meta: " + ::cerata::ToString(meta) + "\n";
180  ret << std::setw(w) << " " << " | ";
181 
182  for (const auto &x : fb_) {
183  ret << std::setw(w) << x.name() << " | ";
184  }
185  ret << std::endl;
186  ret << std::setw(w) << " " << " | ";
187  for (const auto &x : fb_) {
188  ret << std::setw(w) << x.type_->ToString() << " | ";
189  }
190  ret << "\n";
191 
192  // Separator
193  for (size_t i = 0; i < fb_.size() + 1; i++) { ret << std::string(w, '-') << " | "; }
194  ret << "\n";
195 
196  for (size_t y = 0; y < fa_.size(); y++) {
197  ret << std::setw(w) << fa_[y].name() << " | ";
198  for (size_t x = 0; x < fb_.size(); x++) {
199  ret << std::setw(w) << " " << " | ";
200  }
201  ret << "\n";
202  ret << std::setw(w) << fa_[y].type_->ToString() << " | ";
203  for (size_t x = 0; x < fb_.size(); x++) {
204  auto val = matrix_(y, x);
205  ret << std::setw(w) << val << " | ";
206  }
207  ret << "\n";
208  // Separator
209  for (size_t i = 0; i < fb_.size() + 1; i++) { ret << std::string(w, '-') << " | "; }
210  ret << "\n";
211  }
212  return ret.str();
213 }
214 
216 
217 std::vector<FlatType> TypeMapper::flat_a() const { return fa_; }
218 
219 std::vector<FlatType> TypeMapper::flat_b() const { return fb_; }
220 
221 bool TypeMapper::CanConvert(const Type *a, const Type *b) const {
222  return ((a_ == a) && (b_ == b));
223 }
224 
225 std::shared_ptr<TypeMapper> TypeMapper::Inverse() const {
226  auto result = std::make_shared<TypeMapper>(b_, a_); // Create a new mapper.
227  result->matrix_ = matrix_.Transpose(); // Copy over a transposed version of the mapping matrix.
228  result->meta = this->meta; // Copy over metadata.
229  return result;
230 }
231 
232 std::vector<MappingPair> TypeMapper::GetUniqueMappingPairs() {
233  std::vector<MappingPair> pairs;
234  // Find mappings that are one to one
235  for (size_t ia = 0; ia < fa_.size(); ia++) {
236  auto maps_a = matrix_.mapping_row(ia);
237  if (maps_a.size() == 1) {
238  auto ib = maps_a.front().first;
239  auto maps_b = matrix_.mapping_column(ib);
240  if (maps_b.size() == 1) {
241  MappingPair mp;
242  mp.a.emplace_back(ia, 0, fa_[ia]);
243  mp.b.emplace_back(ib, 0, fb_[ib]);
244  pairs.push_back(mp);
245  }
246  }
247  }
248 
249  // B stuff that is concatenated on A
250  for (size_t ia = 0; ia < fa_.size(); ia++) {
251  auto maps = matrix_.mapping_row(ia);
252  if (maps.size() > 1) {
253  MappingPair mp;
254  mp.a.emplace_back(ia, 0, fa_[ia]);
255  for (const auto &m : maps) {
256  mp.b.emplace_back(m.first, m.second, fb_[m.first]);
257  }
258  pairs.push_back(mp);
259  }
260  }
261 
262  // A stuff that is concatenated on B
263  for (size_t ib = 0; ib < fb_.size(); ib++) {
264  auto maps = matrix_.mapping_column(ib);
265  if (maps.size() > 1) {
266  MappingPair mp;
267  mp.b.emplace_back(ib, 0, fb_[ib]);
268  for (const auto &m : maps) {
269  mp.a.emplace_back(m.first, m.second, fa_[m.first]);
270  }
271  pairs.push_back(mp);
272  }
273  }
274  return pairs;
275 }
276 
277 std::shared_ptr<TypeMapper> TypeMapper::Make(Type *a) {
278  return std::make_shared<TypeMapper>(a, a);
279 }
280 
282  matrix_ = std::move(map_matrix);
283 }
284 
285 std::shared_ptr<TypeMapper> TypeMapper::Make(const std::shared_ptr<Type> &a, const std::shared_ptr<Type> &b) {
286  return Make(a.get(), b.get());
287 }
288 
289 std::string MappingPair::ToString() const {
290  std::stringstream ret;
291  ret << "MappingPair: " << std::endl;
292  for (size_t i = 0; i < std::max(a.size(), b.size()); i++) {
293  if (i < a.size()) {
294  ret << " idx: " << std::setw(3) << index_a(i);
295  ret << " off: " << std::setw(3) << offset_a(i);
296  ret << std::setw(30) << flat_type_a(i).name();
297  ret << std::setw(30) << flat_type_a(i).type_->ToString();
298  } else {
299  ret << std::setw(74) << " ";
300  }
301  ret << " --> ";
302  if (i < b.size()) {
303  ret << " idx: " << std::setw(3) << index_b(i);
304  ret << " off: " << std::setw(3) << offset_b(i);
305  ret << std::setw(30) << flat_type_b(i).name();
306  ret << std::setw(30) << flat_type_b(i).type_->ToString();
307  } else {
308  ret << std::setw(74) << " ";
309  }
310  ret << std::endl;
311  }
312  // output total width of both sides
313  ret << " w: " << std::setw(74) << width_a()->ToString();
314  ret << " ";
315  ret << " w: " << std::setw(74) << width_b()->ToString();
316  ret << std::endl;
317  return ret.str();
318 }
319 
320 std::shared_ptr<Node> MappingPair::width_a(const std::optional<std::shared_ptr<Node>> &no_width_increment) const {
321  std::shared_ptr<Node> result = intl(0);
322  for (int64_t i = 0; i < num_a(); i++) {
323  auto fw = flat_type_a(i).type_->width();
324  if (fw) {
325  result = result + fw.value();
326  } else if (no_width_increment) {
327  result = result + *no_width_increment;
328  }
329  }
330  return result;
331 }
332 
333 std::shared_ptr<Node> MappingPair::width_b(const std::optional<std::shared_ptr<Node>> &no_width_increment) const {
334  std::shared_ptr<Node> result = intl(0);
335  for (int64_t i = 0; i < num_b(); i++) {
336  auto fw = flat_type_b(i).type_->width();
337  if (fw) {
338  result = result + fw.value();
339  } else if (no_width_increment) {
340  result = result + *no_width_increment;
341  }
342  }
343  return result;
344 }
345 
346 } // namespace cerata
cerata::Type::RECORD
@ RECORD
? | ? | Yes
Definition: type.h:77
cerata::NamePart::sep
bool sep
Whether we should insert a separator after this part.
Definition: flattype.h:47
cerata::TypeMapper::Make
static std::shared_ptr< TypeMapper > Make(Type *a)
Construct a new TypeMapper from some type to itself, and return a smart pointer to it.
Definition: flattype.cc:277
cerata::MappingPair::width_b
std::shared_ptr< Node > width_b(const OptionalNode &no_width_increment={}) const
Return the total width of the types on side B.
Definition: flattype.cc:333
cerata::MappingMatrix::mapping_row
std::vector< std::pair< int64_t, T > > mapping_row(int64_t y)
Obtain non-zero element indices and value from row y, sorted by value.
Definition: flattype.h:209
cerata::TypeMapper::fa_
std::vector< FlatType > fa_
The list of flattened types on the "a"-side.
Definition: flattype.h:372
cerata::TypeMapper::b_
Type * b_
Type of the "b"-side.
Definition: flattype.h:378
cerata::MappingPair::flat_type_a
FlatType flat_type_a(int64_t i) const
Return the i-th FlatType on the "a"-side in the mapping matrix.
Definition: flattype.h:299
cerata::TypeMapper::ToString
std::string ToString() const
Return a human-readable string of this TypeMapper.
Definition: flattype.cc:175
cerata::FlatType::type_
Type * type_
A pointer to the original type.
Definition: flattype.h:56
cerata::Type::IsEqual
virtual bool IsEqual(const Type &other) const
Determine if this Type is exactly equal to an other Type.
Definition: type.cc:159
cerata::Type
A Type.
Definition: type.h:63
cerata::Record
A Record type containing zero or more fields.
Definition: type.h:301
cerata::TypeMapper
A structure to dynamically define type mappings between flattened types.
Definition: flattype.h:326
cerata::TypeMapper::Inverse
std::shared_ptr< TypeMapper > Inverse() const
Return a new TypeMapper that is the inverse of this TypeMapper.
Definition: flattype.cc:225
cerata::MappingMatrix::SetNext
MappingMatrix & SetNext(int64_t y, int64_t x)
Set the next (existing maximum + 1) value in a matrix at some position.
Definition: flattype.h:225
cerata::TypeMapper::flat_b
std::vector< FlatType > flat_b() const
Return the list of flattened types on the "b"-side.
Definition: flattype.cc:219
cerata
Contains every Cerata class, function, etc...
Definition: api.h:41
cerata::MappingPair::width_a
std::shared_ptr< Node > width_a(const OptionalNode &no_width_increment={}) const
Return the total width of the types on side A.
Definition: flattype.cc:320
cerata::MappingMatrix::Transpose
MappingMatrix Transpose() const
Transpose the matrix.
Definition: flattype.h:231
cerata::NamePart
Convenience struct to generate names in parts.
Definition: flattype.h:40
cerata::Type::id
ID id() const
Return the Type ID.
Definition: type.h:88
cerata::TypeMapper::CanConvert
bool CanConvert(const Type *a, const Type *b) const
Return true if this TypeMapper can map type a to type b.
Definition: flattype.cc:221
cerata::TypeMapper::GetUniqueMappingPairs
std::vector< MappingPair > GetUniqueMappingPairs()
Get a list of unique mapping pairs.
Definition: flattype.cc:232
cerata::ToString
std::string ToString(Expression::Op operation)
Human-readable expression operator.
Definition: expression.cc:149
cerata::Type::ToString
std::string ToString(bool show_meta=false, bool show_mappers=false) const
Return the Type ID as a human-readable string.
Definition: type.cc:34
cerata::TypeMapper::a
Type * a() const
Return the type on the "a"-side.
Definition: flattype.h:351
cerata::FlatType::name_parts_
std::vector< NamePart > name_parts_
Name parts of this flattened type.
Definition: flattype.h:60
cerata::FlatType
A flattened type.
Definition: flattype.h:51
cerata::MappingMatrix::mapping_column
std::vector< std::pair< int64_t, T > > mapping_column(int64_t x)
Obtain non-zero element indices and value from column x, sorted by value.
Definition: flattype.h:194
cerata::IndexOfFlatType
int64_t IndexOfFlatType(const std::vector< FlatType > &flat_types_list, const Type *type)
Return the index of some Type in a list of FlatTypes.
Definition: flattype.cc:132
cerata::operator<
bool operator<(const FlatType &a, const FlatType &b)
Compares two FlatTypes first by name, then by nesting level. Useful for sorting.
Definition: flattype.cc:55
cerata::ContainsFlatType
bool ContainsFlatType(const std::vector< FlatType > &flat_types_list, const Type *type)
Return true if some Type is contained in a list of FlatTypes, false otherwise.
Definition: flattype.cc:123
cerata::TypeMapper::MakeImplicit
static std::shared_ptr< TypeMapper > MakeImplicit(Type *a, Type *b)
Construct a new TypeMapper from some type to another type, and automatically determine the type mappi...
Definition: flattype.cc:160
cerata::intl
std::shared_ptr< Literal > intl(int64_t i)
Obtain a shared pointer to an integer literal from the default node pool.
Definition: pool.h:144
cerata::FlatType::reverse_
bool reverse_
Whether to invert this flattened type if it would be on a terminator node.
Definition: flattype.h:62
cerata::MappingPair::num_b
int64_t num_b() const
Return the number of FlatTypes on the "b"-side.
Definition: flattype.h:289
cerata::FlattenRecord
void FlattenRecord(std::vector< FlatType > *list, const Record *record, const std::optional< FlatType > &parent, bool invert)
Flatten a Record.
Definition: flattype.cc:63
cerata::MappingPair::index_b
index index_b(int64_t i) const
Return the index of the i-th FlatType on the "b"-side in the mapping matrix.
Definition: flattype.h:293
cerata::TypeMapper::TypeMapper
TypeMapper(Type *a, Type *b)
TypeMapper constructor. Constructs an empty type mapping.
Definition: flattype.cc:141
cerata::MappingPair::flat_type_b
FlatType flat_type_b(int64_t i) const
Return the i-th FlatType on the "b"-side in the mapping matrix.
Definition: flattype.h:301
cerata::Named
Convenience structure for anything that is named. Names are case-sensitive.
Definition: utils.h:40
cerata::Type::width
virtual std::optional< Node * > width() const
Return the width of the type, if it is synthesizable.
Definition: type.h:106
cerata::FlatType::name
std::string name(const NamePart &root=NamePart(), const std::string &sep="_") const
Return the name of this flattened type, constructed from the name parts.
Definition: flattype.cc:32
cerata::MappingPair::index_a
index index_a(int64_t i) const
Return the index of the i-th FlatType on the "a"-side in the mapping matrix.
Definition: flattype.h:291
cerata::TypeMapper::b
Type * b() const
Return the type on the "b"-side.
Definition: flattype.h:353
cerata::MappingPair::offset_b
offset offset_b(int64_t i) const
Return the offset of the i-th FlatType on the "b"-side in the mapping matrix.
Definition: flattype.h:297
cerata::record
std::shared_ptr< Record > record(const std::string &name, const std::vector< std::shared_ptr< Field >> &fields)
Create a new Record type, and return a shared pointer to it.
Definition: type.cc:308
cerata::TypeMapper::meta
std::unordered_map< std::string, std::string > meta
KV storage for metadata of tools or specific backend implementations.
Definition: flattype.h:368
cerata::NamePart::str
std::string str
The string of this name part.
Definition: flattype.h:45
cerata::MappingPair
A structure representing a mapping pair for a type mapping.
Definition: flattype.h:276
cerata::Flatten
void Flatten(std::vector< FlatType > *list, Type *type, const std::optional< FlatType > &parent, const std::string &name, bool invert, bool sep)
Flatten any Type.
Definition: flattype.cc:72
cerata::TypeMapper::map_matrix
MappingMatrix< int64_t > map_matrix()
Return the mapping matrix of this TypeMapper.
Definition: flattype.cc:215
cerata::TypeMapper::Add
TypeMapper & Add(int64_t a, int64_t b)
Add a mapping between two FlatTypes to the mapper.
Definition: flattype.cc:170
cerata::MappingMatrix
A matrix used for TypeMapper.
Definition: flattype.h:109
cerata::MappingPair::a
std::vector< IOF > a
Flattype and its index in a mapping matrix on the "a"-side.
Definition: flattype.h:283
cerata::TypeMapper::SetMappingMatrix
void SetMappingMatrix(MappingMatrix< int64_t > map_matrix)
Set the mapping matrix of this TypeMapper.
Definition: flattype.cc:281
cerata::TypeMapper::flat_a
std::vector< FlatType > flat_a() const
Return the list of flattened types on the "a"-side.
Definition: flattype.cc:217
cerata::TypeMapper::a_
Type * a_
Type of the "a"-side.
Definition: flattype.h:376
cerata::TypeMapper::fb_
std::vector< FlatType > fb_
The list of flattened types on the "b"-side.
Definition: flattype.h:374
cerata::TypeMapper::matrix_
MappingMatrix< int64_t > matrix_
The mapping matrix.
Definition: flattype.h:380
cerata::FlatType::nesting_level_
int nesting_level_
Nesting level in a type hierarchy.
Definition: flattype.h:58
cerata::MappingPair::b
std::vector< IOF > b
Flattype and its index in a mapping matrix on the "b"-side.
Definition: flattype.h:285
cerata::MappingPair::offset_a
offset offset_a(int64_t i) const
Return the offset of the i-th FlatType on the "a"-side in the mapping matrix.
Definition: flattype.h:295
cerata::MappingPair::num_a
int64_t num_a() const
Return the number of FlatTypes on the "a"-side.
Definition: flattype.h:287
cerata::MappingPair::ToString
std::string ToString() const
Generate a human-readable version of this MappingPair.
Definition: flattype.cc:289