type_t type_universal_real(void) { static type_t t = NULL; if (t == NULL) { tree_t min = tree_new(T_LITERAL); tree_set_subkind(min, L_REAL); tree_set_dval(min, -DBL_MAX); tree_t max = tree_new(T_LITERAL); tree_set_subkind(max, L_REAL); tree_set_dval(max, DBL_MAX); t = type_make_universal(T_REAL, "universal real", min, max); } return t; }
type_t type_universal_int(void) { static type_t t = NULL; if (t == NULL) { tree_t min = tree_new(T_LITERAL); tree_set_subkind(min, L_INT); tree_set_ival(min, -INT_MAX); tree_t max = tree_new(T_LITERAL); tree_set_subkind(max, L_INT); tree_set_ival(max, INT_MAX); t = type_make_universal(T_INTEGER, "universal integer", min, max); } return t; }
tree_t get_real_lit(tree_t t, double r) { tree_t f = tree_new(T_LITERAL); tree_set_loc(f, tree_loc(t)); tree_set_subkind(f, L_REAL); tree_set_dval(f, r); tree_set_type(f, tree_type(t)); return f; }
tree_t get_int_lit(tree_t t, int64_t i) { tree_t f = tree_new(T_LITERAL); tree_set_subkind(f, L_INT); tree_set_ival(f, i); tree_set_loc(f, tree_loc(t)); tree_set_type(f, tree_type(t)); return f; }
static tree_t str_to_agg(const char *p, const char *end) { tree_t t = tree_new(T_AGGREGATE); unsigned len = 0; while (*p != '\0' && p != end) { const char ch[] = { '\'', *p++, '\'', '\0' }; tree_t ref = tree_new(T_REF); tree_set_ident(ref, ident_new(ch)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, ref); tree_add_assoc(t, a); ++len; } tree_t left = tree_new(T_LITERAL); tree_set_subkind(left, L_INT); tree_set_ival(left, 0); tree_t right = tree_new(T_LITERAL); tree_set_subkind(right, L_INT); tree_set_ival(right, len - 1); type_t type = type_new(T_CARRAY); type_set_ident(type, ident_new("string")); type_set_elem(type, type_universal_int()); range_t r = { .kind = RANGE_DOWNTO, .left = left, .right = right }; type_add_dim(type, r); tree_set_type(t, type); return t; }
tree_t add_param(tree_t call, tree_t value, param_kind_t kind, tree_t name) { tree_t p = tree_new(T_PARAM); tree_set_loc(p, tree_loc(value)); tree_set_subkind(p, kind); tree_set_value(p, value); if (kind == P_NAMED) { assert(name != NULL); tree_set_name(p, name); } tree_add_param(call, p); return p; }
tree_t str_to_literal(const char *start, const char *end, type_t type) { tree_t t = tree_new(T_LITERAL); tree_set_subkind(t, L_STRING); type_t elem = NULL; if (type != NULL) { tree_set_type(t, type); elem = type_elem(type); } char last = '\0'; for (const char *p = start; *p != '\0' && p != end; p++) { if (*p == -127) continue; else if (*p == '"' && last == '"') { last = '\0'; continue; } else last = *p; const char ch[] = { '\'', *p, '\'', '\0' }; ident_t id = ident_new(ch); tree_t ref = tree_new(T_REF); tree_set_ident(ref, id); tree_add_char(t, ref); if (elem != NULL) { const int nlit = type_enum_literals(elem); for (int i = 0; i < nlit; i++) { tree_t lit = type_enum_literal(elem, i); if (tree_ident(lit) == id) { tree_set_ref(ref, lit); break; } } } } return t; }
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)); } }
tree_t call_builtin(const char *builtin, type_t type, ...) { struct decl_cache { struct decl_cache *next; ident_t bname; tree_t decl; }; char *name = xasprintf("NVC.BUILTIN.%s", builtin); for (char *p = name; *p != '\0'; p++) *p = toupper((int)*p); static struct decl_cache *cache = NULL; ident_t bname = ident_new(builtin); ident_t name_i = ident_new(name); free(name); struct decl_cache *it; tree_t decl = NULL; for (it = cache; it != NULL; it = it->next) { if (it->bname == bname) { decl = it->decl; break; } } if (decl == NULL) { decl = tree_new(T_FUNC_DECL); tree_set_ident(decl, name_i); tree_add_attr_str(decl, builtin_i, ident_new(builtin)); } struct decl_cache *c = xmalloc(sizeof(struct decl_cache)); c->next = cache; c->bname = bname; c->decl = decl; cache = c; tree_t call = tree_new(T_FCALL); tree_set_ident(call, name_i); tree_set_ref(call, decl); if (type != NULL) tree_set_type(call, type); va_list ap; va_start(ap, type); tree_t arg; while ((arg = va_arg(ap, tree_t))) { tree_t p = tree_new(T_PARAM); tree_set_value(p, arg); tree_set_loc(p, tree_loc(arg)); tree_set_subkind(p, P_POS); tree_add_param(call, p); } va_end(ap); return call; }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: { int64_t val = 0; const bool folded = folded_int(type_dim(type, 0).left, &val); if (folded) return make_ref(type_enum_literal(base, (unsigned) val)); else return type_dim(type, 0).left; } case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } case T_UNRESOLVED: return NULL; default: fatal_trace("cannot handle type %s in %s", type_kind_str(type_kind(base)), __func__); } }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: return make_ref(type_enum_literal(base, 0)); case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } default: assert(false); } }