static void opt_elide_array_ref_bounds(tree_t t) { tree_t value = tree_value(t); if (tree_kind(value) != T_REF) return; tree_t decl = tree_ref(value); const int nparams = tree_params(t); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(t, i)); if (tree_kind(index) != T_REF) return; tree_t index_decl = tree_ref(index); tree_t range_var = tree_attr_tree(index_decl, range_var_i); if (range_var == NULL) return; if (range_var != decl) return; } tree_add_attr_int(t, elide_bounds_i, 1); }
static void opt_tag_last_value_fcall(tree_t t) { tree_t decl = tree_ref(t); if (tree_attr_str(decl, builtin_i) != NULL) return; // A regular subprogram call may pass parameters as class signal which // could access 'LAST_VALUE in the body const int nports = tree_ports(decl); for (int i = 0; i < nports; i++) { tree_t port = tree_port(decl, i); if (tree_class(port) != C_SIGNAL) continue; tree_t value = tree_value(tree_param(t, i)); tree_kind_t kind; while ((kind = tree_kind(value)) != T_REF) { assert((kind == T_ARRAY_REF) || (kind == T_ARRAY_SLICE)); value = tree_value(value); } tree_add_attr_int(tree_ref(value), last_value_i, 1); } }
static tree_t fixup_entity_refs(tree_t t, void *context) { // Rewrite references to an entity to point at the selected architecture // so attributes like 'PATH_NAME are correct if (tree_kind(t) != T_REF) return t; tree_t arch = context; if (tree_ref(t) == tree_ref(arch)) tree_set_ref(t, arch); return t; }
static tree_t get_bool_lit(tree_t t, bool v) { tree_t fdecl = tree_ref(t); assert(tree_kind(fdecl) == T_FUNC_DECL); static type_t bool_type = NULL; if (bool_type == NULL) { lib_t std = lib_find("std", true, true); assert(std != NULL); tree_t standard = lib_get(std, ident_new("STD.STANDARD")); assert(standard != NULL); const int ndecls = tree_decls(standard); for (int i = 0; (i < ndecls) && (bool_type == NULL); i++) { tree_t d = tree_decl(standard, i); if (tree_ident(d) == std_bool_i) bool_type = tree_type(d); } assert(bool_type != NULL); } tree_t lit = type_enum_literal(bool_type, v ? 1 : 0); tree_t b = tree_new(T_REF); tree_set_loc(b, tree_loc(t)); tree_set_ref(b, lit); tree_set_type(b, bool_type); tree_set_ident(b, tree_ident(lit)); return b; }
static void ungroup_proc_params(tree_t t, group_nets_ctx_t *ctx) { // Ungroup any signal that is passed to a procedure as in general we // cannot guarantee anything about the procedure's behaviour const int nparams = tree_params(t); for (int i = 0; i < nparams; i++) { tree_t value = tree_value(tree_param(t, i)); tree_kind_t kind = tree_kind(value); while (kind == T_ARRAY_REF || kind == T_ARRAY_SLICE) { value = tree_value(value); kind = tree_kind(value); } if (kind != T_REF) continue; tree_t decl = tree_ref(value); if (tree_kind(decl) != T_SIGNAL_DECL) continue; const int nnets = tree_nets(decl); for (int i = 0; i < nnets; i++) group_add(ctx, tree_net(decl, i), 1); } }
static void ungroup_ref(tree_t target, group_nets_ctx_t *ctx) { tree_t decl = tree_ref(target); if (tree_kind(decl) == T_SIGNAL_DECL) { const int nnets = tree_nets(decl); for (int i = 0; i < nnets; i++) group_add(ctx, tree_net(decl, i), 1); } }
class_t class_of(tree_t t) { switch (tree_kind(t)) { case T_VAR_DECL: return C_VARIABLE; case T_SIGNAL_DECL: return C_SIGNAL; case T_CONST_DECL: return C_CONSTANT; case T_PORT_DECL: return tree_class(t); case T_ENUM_LIT: case T_GENVAR: case T_ALIAS: case T_FIELD_DECL: return C_DEFAULT; case T_UNIT_DECL: return C_UNITS; case T_ARCH: return C_ARCHITECTURE; case T_FUNC_DECL: case T_FUNC_BODY: return C_FUNCTION; case T_PROC_DECL: case T_PROC_BODY: return C_PROCEDURE; case T_ENTITY: return C_ENTITY; case T_TYPE_DECL: return C_TYPE; case T_FILE_DECL: return C_FILE; case T_PROCESS: case T_BLOCK: case T_FOR: return C_LABEL; case T_COMPONENT: return C_COMPONENT; case T_REF: return class_of(tree_ref(t)); case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: return class_of(tree_value(t)); case T_PACKAGE: return C_PACKAGE; case T_LIBRARY: return C_LIBRARY; case T_ELAB: return C_ELAB; default: fatal("missing class_of for %s", tree_kind_str(tree_kind(t))); } }
bool folded_enum(tree_t t, unsigned *pos) { if (tree_kind(t) == T_REF) { tree_t decl = tree_ref(t); if (tree_kind(decl) == T_ENUM_LIT) { *pos = tree_pos(decl); return true; } } return false; }
bool folded_bool(tree_t t, bool *b) { if (tree_kind(t) == T_REF) { tree_t decl = tree_ref(t); if (tree_kind(decl) == T_ENUM_LIT && type_ident(tree_type(decl)) == std_bool_i) { *b = (tree_pos(decl) == 1); return true; } } return false; }
bool folded_bool(tree_t t, bool *b) { ident_t std_bool_i = ident_new("STD.STANDARD.BOOLEAN"); if (tree_kind(t) == T_REF) { tree_t decl = tree_ref(t); if (tree_kind(decl) == T_ENUM_LIT && type_ident(tree_type(decl)) == std_bool_i) { *b = (tree_pos(decl) == 1); return true; } } return false; }
static void group_ref(tree_t target, group_nets_ctx_t *ctx, int start, int n) { assert(tree_kind(target) == T_REF); tree_t decl = tree_ref(target); switch (tree_kind(decl)) { case T_SIGNAL_DECL: group_decl(decl, ctx, start, n); break; case T_ALIAS: group_target(tree_value(decl), ctx); break; default: break; } }
int tree_route_get(const str *user) { struct tree *tree; int route; /* Find match in tree */ tree = tree_ref(); if (NULL == tree) { return -1; } route = tree_item_get(tree->root, user); tree_deref(tree); return route; }
static tree_t rewrite_refs(tree_t t, void *context) { rewrite_params_t *params = context; if (tree_kind(t) != T_REF) return t; tree_t decl = tree_ref(t); for (int i = 0; i < params->count; i++) { if (decl != params->formals[i]) continue; // Do not rewrite references if they appear as formal names if (tree_attr_int(t, formal_i, 0)) continue; // Skip assignments to OPEN ports if (params->actuals[i] == NULL) continue; switch (tree_kind(params->actuals[i])) { case T_SIGNAL_DECL: case T_ENUM_LIT: tree_set_ref(t, params->actuals[i]); tree_set_type(t, tree_type(params->actuals[i])); return t; case T_LITERAL: case T_AGGREGATE: case T_REF: case T_ARRAY_SLICE: case T_ARRAY_REF: case T_FCALL: case T_CONCAT: return params->actuals[i]; case T_TYPE_CONV: // XXX: this only works in trivial cases return tree_value(tree_param(params->actuals[i], 0)); default: fatal_at(tree_loc(params->actuals[i]), "cannot handle tree kind %s " "in rewrite_refs", tree_kind_str(tree_kind(params->actuals[i]))); } } return t; }
static void opt_tag_last_value_attr_ref(tree_t t) { static ident_t last_value_attr_i = NULL; if (last_value_attr_i == NULL) last_value_attr_i = ident_new("LAST_VALUE"); if (tree_ident(t) == last_value_attr_i) { tree_t signal = tree_ref(tree_name(t)); if (tree_kind(signal) != T_SIGNAL_DECL) return; // A signal in a package will not have nets assigned yet so we cannot // optimise out 'LAST_VALUE if (tree_nets(signal) > 0) tree_add_attr_int(signal, last_value_i, 1); } }
void tree_print(FILE *f) { struct tree *tree; tree = tree_ref(); fprintf(f, "Prefix route tree:\n"); if (tree) { fprintf(f, " reference count: %d\n", atomic_get(&tree->refcnt)); tree_item_print(tree->root, f, 0); } else { fprintf(f, " (no tree)\n"); } tree_deref(tree); }
int64_t assume_int(tree_t t) { switch (tree_kind(t)) { case T_LITERAL: assert(tree_subkind(t) == L_INT); return tree_ival(t); case T_REF: { tree_t ref = tree_ref(t); assert(tree_kind(ref) == T_ENUM_LIT); return tree_pos(ref); } default: fatal_at(tree_loc(t), "expression cannot be folded to " "an integer constant"); } }
END_TEST START_TEST(test_lib_save) { { tree_t ent = tree_new(T_ENTITY); tree_set_ident(ent, ident_new("name")); tree_add_attr_str(ent, ident_new("attr"), ident_new("test string")); type_t e = type_new(T_ENUM); type_set_ident(e, ident_new("myenum")); tree_t a = tree_new(T_ENUM_LIT); tree_set_ident(a, ident_new("a")); tree_set_type(a, e); tree_set_pos(a, 55); type_enum_add_literal(e, a); tree_t b = tree_new(T_ENUM_LIT); tree_set_ident(b, ident_new("b")); tree_set_type(b, e); type_enum_add_literal(e, b); tree_t p1 = tree_new(T_PORT_DECL); tree_set_ident(p1, ident_new("foo")); tree_set_subkind(p1, PORT_OUT); tree_set_type(p1, type_universal_int()); tree_add_port(ent, p1); tree_t p2 = tree_new(T_PORT_DECL); tree_set_ident(p2, ident_new("bar")); tree_set_subkind(p2, PORT_IN); tree_set_type(p2, e); tree_add_port(ent, p2); tree_t ar = tree_new(T_ARCH); tree_set_ident(ar, ident_new("arch")); tree_set_ident2(ar, ident_new("foo")); tree_t pr = tree_new(T_PROCESS); tree_set_ident(pr, ident_new("proc")); tree_add_stmt(ar, pr); tree_t v1 = tree_new(T_VAR_DECL); tree_set_ident(v1, ident_new("v1")); tree_set_type(v1, e); tree_t r = tree_new(T_REF); tree_set_ident(r, ident_new("v1")); tree_set_ref(r, v1); tree_t s = tree_new(T_VAR_ASSIGN); tree_set_ident(s, ident_new("var_assign")); tree_set_target(s, r); tree_set_value(s, r); tree_add_stmt(pr, s); tree_t c = tree_new(T_LITERAL); tree_set_subkind(c, L_INT); tree_set_ival(c, 53); tree_t s2 = tree_new(T_VAR_ASSIGN); tree_set_ident(s2, ident_new("var_assign")); tree_set_target(s2, r); tree_set_value(s2, c); tree_add_stmt(pr, s2); tree_t s3 = tree_new(T_VAR_ASSIGN); tree_set_ident(s3, ident_new("var_assign")); tree_set_target(s3, r); tree_set_value(s3, str_to_agg("foobar", NULL)); tree_add_stmt(pr, s3); tree_t s4 = tree_new(T_ASSERT); tree_set_ident(s4, ident_new("assert")); tree_set_value(s4, c); tree_set_severity(s4, c); tree_set_message(s4, str_to_agg("message", NULL)); tree_add_stmt(pr, s4); lib_put(work, ar); lib_put(work, ent); } tree_gc(); lib_save(work); lib_free(work); lib_add_search_path("/tmp"); work = lib_find(ident_new("test_lib"), false); fail_if(work == NULL); { tree_t ent = lib_get(work, ident_new("name")); fail_if(ent == NULL); fail_unless(tree_kind(ent) == T_ENTITY); fail_unless(tree_ident(ent) == ident_new("name")); fail_unless(tree_ports(ent) == 2); ident_t attr = tree_attr_str(ent, ident_new("attr")); fail_if(attr == NULL); fail_unless(icmp(attr, "test string")); tree_t p1 = tree_port(ent, 0); fail_unless(tree_kind(p1) == T_PORT_DECL); fail_unless(tree_subkind(p1) == PORT_OUT); fail_unless(type_kind(tree_type(p1)) == T_INTEGER); tree_t p2 = tree_port(ent, 1); fail_unless(tree_kind(p2) == T_PORT_DECL); fail_unless(tree_subkind(p2) == PORT_IN); type_t e = tree_type(p2); fail_unless(type_kind(e) == T_ENUM); fail_unless(type_enum_literals(e) == 2); tree_t a = type_enum_literal(e, 0); fail_unless(tree_kind(a) == T_ENUM_LIT); fail_unless(tree_ident(a) == ident_new("a")); fail_unless(tree_type(a) == e); fail_unless(tree_pos(a) == 55); tree_t b = type_enum_literal(e, 1); fail_unless(tree_kind(b) == T_ENUM_LIT); fail_unless(tree_ident(b) == ident_new("b")); fail_unless(tree_type(b) == e); tree_t ar = lib_get(work, ident_new("arch")); fail_if(ar == NULL); fail_unless(tree_ident(ar) == ident_new("arch")); fail_unless(tree_ident2(ar) == ident_new("foo")); tree_t pr = tree_stmt(ar, 0); fail_unless(tree_kind(pr) == T_PROCESS); fail_unless(tree_ident(pr) == ident_new("proc")); tree_t s = tree_stmt(pr, 0); fail_unless(tree_kind(s) == T_VAR_ASSIGN); tree_t r = tree_target(s); fail_unless(tree_kind(r) == T_REF); fail_unless(tree_value(s) == r); tree_t s2 = tree_stmt(pr, 1); fail_unless(tree_kind(s2) == T_VAR_ASSIGN); fail_unless(tree_target(s2) == r); tree_t s3 = tree_stmt(pr, 2); fail_unless(tree_kind(s3) == T_VAR_ASSIGN); fail_unless(tree_target(s3) == r); fail_unless(tree_kind(tree_value(s3)) == T_AGGREGATE); tree_t s4 = tree_stmt(pr, 3); fail_unless(tree_kind(s4) == T_ASSERT); fail_unless(tree_ident(s4) == ident_new("assert")); tree_t c = tree_value(s2); fail_unless(tree_kind(c) == T_LITERAL); fail_unless(tree_subkind(c) == L_INT); fail_unless(tree_ival(c) == 53); // Type declaration and reference written to different units // so two copies of the type declaration will be read back // hence can't check for pointer equality here fail_unless(type_eq(tree_type(tree_ref(r)), e)); } }
static map_list_t *elab_map(tree_t t, tree_t arch, tree_formals_t tree_Fs, tree_formal_t tree_F, tree_actuals_t tree_As, tree_actual_t tree_A) { tree_t unit = tree_ref(arch); assert(tree_kind(unit) == T_ENTITY); const int nformals = tree_Fs(unit); const int nactuals = (tree_As != NULL) ? tree_As(t) : 0; bool *have_formals = xmalloc(sizeof(bool) * nformals); for (int i = 0; i < nformals; i++) have_formals[i] = false; const int maxr = nformals + nactuals; tree_t *rformals = xmalloc(sizeof(tree_t) * maxr); tree_t *ractuals = xmalloc(sizeof(tree_t) * maxr); int count = 0; map_list_t *maps = NULL; for (int i = 0; i < nactuals; i++) { tree_t p = tree_A(t, i); tree_t formal = NULL; switch (tree_subkind(p)) { case P_POS: { const int pos = tree_pos(p); formal = tree_F(unit, pos); have_formals[pos] = true; } break; case P_NAMED: { ident_t name = elab_formal_name(tree_name(p)); for (int j = 0; j < nformals; j++) { tree_t port = tree_F(unit, j); if (tree_ident(port) == name) { formal = port; have_formals[j] = true; break; } } } break; default: assert(false); } assert(formal != NULL); switch (tree_class(formal)) { case C_SIGNAL: ractuals[count] = elab_signal_port(arch, formal, p, &maps); break; case C_CONSTANT: ractuals[count] = tree_value(p); break; default: assert(false); } rformals[count] = formal; count++; } // Assign default values for (unsigned i = 0; i < nformals; i++) { if (!have_formals[i]) { tree_t f = tree_F(unit, i); if (tree_has_value(f)) { rformals[count] = f; ractuals[count] = tree_value(f); count++; } } } assert(count <= maxr); if (count > 0) { rewrite_params_t params = { .formals = rformals, .actuals = ractuals, .count = count }; tree_rewrite(arch, rewrite_refs, ¶ms); tree_t ent = tree_ref(arch); if (tree_stmts(ent) > 0 || tree_decls(ent) > 0) tree_rewrite(ent, rewrite_refs, ¶ms); }
static tree_t elab_signal_port(tree_t arch, tree_t formal, tree_t param, map_list_t **maps) { assert(tree_kind(param) == T_PARAM); tree_t actual = tree_value(param); // NULL name means associate the whole port tree_t name = NULL; if (tree_subkind(param) == P_NAMED) { tree_t n = tree_name(param); if (tree_kind(n) != T_REF) name = n; } const bool partial_map = name != NULL; switch (tree_kind(actual)) { case T_REF: case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { // Replace the formal port with a signal and connect its nets to // those of the actual tree_t ref = actual; tree_kind_t ref_kind; while ((ref_kind = tree_kind(ref)) != T_REF) { if ((ref_kind == T_AGGREGATE) || (ref_kind == T_LITERAL)) return actual; else ref = tree_value(ref); } tree_t decl = tree_ref(ref); tree_kind_t decl_kind = tree_kind(decl); if (decl_kind == T_SIGNAL_DECL) { tree_t s = elab_port_to_signal(arch, formal, actual); if (partial_map) tree_add_attr_int(s, partial_map_i, 1); map_list_t *m = xmalloc(sizeof(map_list_t)); m->next = *maps; m->formal = formal; m->actual = actual; m->signal = s; m->name = name; *maps = m; return s; } else if (decl_kind == T_PORT_DECL) return NULL; // Port was OPEN at a higher level else return actual; } case T_LITERAL: case T_AGGREGATE: { type_t formal_type = tree_type(formal); if (!type_is_unconstrained(formal_type)) tree_set_type(actual, formal_type); return actual; } case T_OPEN: return NULL; case T_TYPE_CONV: // Only allow simple array type conversions for now { type_t to_type = tree_type(actual); type_t from_type = tree_type(tree_value(tree_param(actual, 0))); if (type_is_array(to_type) && type_is_array(from_type)) return actual; else fatal_at(tree_loc(actual), "sorry, this form of type conversion " "is not supported as an actual"); } default: fatal_at(tree_loc(actual), "tree %s not supported as actual", tree_kind_str(tree_kind(actual))); } }