static int group_net_to_field(type_t type, netid_t nid) { int count = 0; if (type_is_record(type)) { const int nfields = type_fields(type); netid_t first = 0; for (int i = 0; i < nfields; i++) { tree_t field = type_field(type, i); type_t ftype = tree_type(field); const netid_t next = first + type_width(tree_type(field)); if (nid >= first && nid < next) { if (type_is_array(ftype) || type_is_record(ftype)) return count + group_net_to_field(ftype, nid - first); else return count; } first = next; count += type_width(ftype); } fatal_trace("group_net_to_field failed to find field for nid=%d type=%s", nid, type_pp(type)); } else if (type_is_array(type)) { type_t elem = type_elem(type); const int width = type_width(elem); if (type_is_record(elem)) return (nid / width) * width + group_net_to_field(elem, nid % width); else return group_net_to_field(elem, nid % width); } else return 0; }
int record_field_to_net(type_t type, ident_t name) { int offset = 0; const int nfields = type_fields(type); for (int i = 0; i < nfields; i++) { tree_t field = type_field(type, i); if (tree_ident(field) == name) return offset; else offset += type_width(tree_type(field)); } assert(false); }
unsigned type_width(type_t type) { if (type_is_array(type)) { const unsigned elem_w = type_width(type_elem(type)); unsigned w = 1; const int ndims = type_dims(type); for (int i = 0; i < ndims; i++) { int64_t low, high; range_bounds(type_dim(type, i), &low, &high); w *= MAX(high - low + 1, 0) * elem_w; } return w; } else if (type_is_record(type)) { type_t base = type_base_recur(type); unsigned w = 0; const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) w += type_width(tree_type(type_field(base, i))); return w; } else return 1; }
static void group_target(tree_t t, group_nets_ctx_t *ctx) { switch (tree_kind(t)) { case T_REF: group_ref(t, ctx, 0, -1); break; case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { type_t type = tree_type(t); if (!type_known_width(type)) ungroup_name(t, ctx); else if (!group_name(t, ctx, 0, type_width(type))) ungroup_name(t, ctx); } break; case T_LITERAL: case T_OPEN: // Constant folding can cause this to appear break; case T_AGGREGATE: { const int nassocs = tree_assocs(t); for (int i = 0; i < nassocs; i++) group_target(tree_value(tree_assoc(t, i)), ctx); } break; default: fmt_loc(stdout, tree_loc(t)); fatal_trace("Cannot handle tree kind %s in group_target", tree_kind_str(tree_kind(t))); } }
static bool group_name(tree_t target, group_nets_ctx_t *ctx, int start, int n) { switch (tree_kind(target)) { case T_REF: group_ref(target, ctx, start, n); return true; case T_ARRAY_REF: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; int offset = 0; const int nparams = tree_params(target); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(target, i)); const int stride = type_width(type_elem(type)); if (tree_kind(index) != T_LITERAL) { if (i > 0) return false; const int twidth = type_width(type); for (int j = 0; j < twidth; j += stride) group_name(value, ctx, start + j, n); return true; } else { if (i > 0) { range_t type_r = range_of(type, i); int64_t low, high; range_bounds(type_r, &low, &high); offset *= high - low + 1; } offset += stride * rebase_index(type, i, assume_int(index)); } } return group_name(value, ctx, start + offset, n); } case T_ARRAY_SLICE: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; // Only in procedure range_t slice = tree_range(target, 0 ); if (tree_kind(slice.left) != T_LITERAL || tree_kind(slice.right) != T_LITERAL) return false; int64_t low, high; range_bounds(slice, &low, &high); const int64_t low0 = rebase_index(type, 0, assume_int(slice.left)); const int stride = type_width(type_elem(type)); return group_name(value, ctx, start + low0 * stride, n); } case T_RECORD_REF: { tree_t value = tree_value(target); type_t rec = tree_type(value); const int offset = record_field_to_net(rec, tree_ident(target)); return group_name(value, ctx, start + offset, n); } case T_AGGREGATE: case T_LITERAL: // This can appear due to assignments to open ports with a // default value return true; default: fatal_at(tree_loc(target), "tree kind %s not yet supported for offset " "calculation", tree_kind_str(tree_kind(target))); } }