static void elab_add_context(tree_t t, const elab_ctx_t *ctx) { ident_t cname = tree_ident(t); ident_t lname = ident_until(cname, '.'); lib_t lib = elab_find_lib(lname, ctx); tree_t unit = lib_get(lib, cname); if (unit == NULL) fatal_at(tree_loc(t), "cannot find unit %s", istr(cname)); else if (tree_kind(unit) == T_PACKAGE) { elab_copy_context(unit, ctx); ident_t name = tree_ident(unit); ident_t body_i = ident_prefix(name, ident_new("body"), '-'); tree_t body = lib_get(lib, body_i); if (body != NULL) elab_copy_context(unit, ctx); } // Always use real library name rather than WORK alias tree_set_ident(t, tree_ident(unit)); tree_add_context(ctx->out, t); }
static int make_cmd(int argc, char **argv) { set_work_lib(); static struct option long_options[] = { { "deps-only", no_argument, 0, 'd' }, { "native", no_argument, 0, 'n' }, { "posix", no_argument, 0, 'p' }, { 0, 0, 0, 0 } }; int c, index = 0; const char *spec = ""; optind = 1; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': // getopt_long already printed an error message exit(EXIT_FAILURE); case 'd': opt_set_int("make-deps-only", 1); break; case 'n': opt_set_int("native", 1); break; case 'p': opt_set_int("make-posix", 1); break; default: abort(); } } const int count = argc - optind; tree_t *targets = xmalloc(count * sizeof(tree_t)); lib_t work = lib_work(); for (int i = optind; i < argc; i++) { ident_t name = to_unit_name(argv[i]); ident_t elab = ident_prefix(name, ident_new("elab"), '.'); if ((targets[i - optind] = lib_get(work, elab)) == NULL) { if ((targets[i - optind] = lib_get(work, name)) == NULL) fatal("cannot find unit %s in library %s", istr(name), istr(lib_name(work))); } } make(targets, count, stdout); return EXIT_SUCCESS; }
static int make_cmd(int argc, char **argv) { static struct option long_options[] = { { "deps-only", no_argument, 0, 'd' }, { "native", no_argument, 0, 'n' }, { "posix", no_argument, 0, 'p' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised make option %s", argv[optind - 1]); case 'd': opt_set_int("make-deps-only", 1); break; case 'n': opt_set_int("native", 1); break; case 'p': opt_set_int("make-posix", 1); break; default: abort(); } } const int count = next_cmd - optind; tree_t *targets = xmalloc(count * sizeof(tree_t)); lib_t work = lib_work(); for (int i = optind; i < next_cmd; i++) { ident_t name = to_unit_name(argv[i]); ident_t elab = ident_prefix(name, ident_new("elab"), '.'); if ((targets[i - optind] = lib_get(work, elab)) == NULL) { if ((targets[i - optind] = lib_get(work, name)) == NULL) fatal("cannot find unit %s in library %s", istr(name), istr(lib_name(work))); } } make(targets, count, stdout); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
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 link_context_package(tree_t unit, lib_t lib, FILE *deps, context_fn_t fn) { assert(n_linked < MAX_ARGS - 1); if (pack_needs_cgen(unit) && !link_already_have(unit)) { (*fn)(lib, unit, deps); linked[n_linked++] = unit; } link_all_context(unit, deps, fn); ident_t name = tree_ident(unit); ident_t body_i = ident_prefix(name, ident_new("body"), '-'); tree_t body = lib_get(lib, body_i); if (body == NULL) { if (link_needs_body(unit)) fatal("missing body for package %s", istr(name)); else return; } link_all_context(body, deps, fn); if (!link_already_have(body)) { (*fn)(lib, body, deps); linked[n_linked++] = body; } }
static int codegen(int argc, char **argv) { set_work_lib(); static struct option long_options[] = { {0, 0, 0, 0} }; int c, index = 0; const char *spec = ""; optind = 1; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': // getopt_long already printed an error message exit(EXIT_FAILURE); default: abort(); } } if (optind == argc) fatal("missing top-level unit name"); ident_t unit_i = to_unit_name(argv[optind]); tree_t pack = lib_get(lib_work(), unit_i); if (pack == NULL) fatal("cannot find unit %s in library %s", istr(unit_i), istr(lib_name(lib_work()))); if (tree_kind(pack) != T_PACKAGE) fatal("this command can only be used with packages"); if (pack_needs_cgen(pack)) link_package(pack); ident_t body_i = ident_prefix(unit_i, ident_new("body"), '-'); tree_t body = lib_get(lib_work(), body_i); if (body != NULL) link_package(body); return EXIT_SUCCESS; }
static void link_walk_lib(ident_t name, int kind, void *context) { lib_walk_params_t *params = context; if (kind == T_PACKAGE) link_context_package(lib_get(params->lib, name), params->lib, params->deps, params->fn); }
static int codegen(int argc, char **argv) { static struct option long_options[] = { { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised codegen option %s", argv[optind - 1]); default: abort(); } } set_top_level(argv, next_cmd); tree_t pack = lib_get(lib_work(), top_level); if (pack == NULL) fatal("cannot find unit %s in library %s", istr(top_level), istr(lib_name(lib_work()))); if (tree_kind(pack) != T_PACKAGE) fatal("this command can only be used with packages"); if (pack_needs_cgen(pack)) link_package(pack); ident_t body_i = ident_prefix(top_level, ident_new("body"), '-'); tree_t body = lib_get(lib_work(), body_i); if (body != NULL) link_package(body); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int dump_cmd(int argc, char **argv) { set_work_lib(); static struct option long_options[] = { {"elab", no_argument, 0, 'e'}, {"body", no_argument, 0, 'b'}, {"nets", no_argument, 0, 'n'}, {0, 0, 0, 0} }; bool add_elab = false, add_body = false, nets = false; int c, index = 0; const char *spec = "eb"; optind = 1; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': // getopt_long already printed an error message exit(EXIT_FAILURE); case 'e': add_elab = true; break; case 'b': add_body = true; break; case 'n': add_elab = true; nets = true; break; default: abort(); } } if (optind == argc) fatal("missing unit name"); for (int i = optind; i < argc; i++) { ident_t name = to_unit_name(argv[i]); if (add_elab) name = ident_prefix(name, ident_new("elab"), '.'); else if (add_body) name = ident_prefix(name, ident_new("body"), '-'); tree_t top = lib_get(lib_work(), name); if (top == NULL) fatal("%s not analysed", istr(name)); (nets ? dump_nets : dump)(top); } return EXIT_SUCCESS; }
static int dump_cmd(int argc, char **argv) { static struct option long_options[] = { { "elab", no_argument, 0, 'E' }, { "body", no_argument, 0, 'b' }, { "nets", no_argument, 0, 'n' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); bool add_elab = false, add_body = false, nets = false; int c, index = 0; const char *spec = "Eb"; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised dump option %s", argv[optind - 1]); case 'E': add_elab = true; break; case 'b': add_body = true; break; case 'n': add_elab = true; nets = true; break; default: abort(); } } if (optind == next_cmd) fatal("missing unit name"); for (int i = optind; i < next_cmd; i++) { ident_t name = to_unit_name(argv[i]); if (add_elab) name = ident_prefix(name, ident_new("elab"), '.'); else if (add_body) name = ident_prefix(name, ident_new("body"), '-'); tree_t top = lib_get(lib_work(), name); if (top == NULL) fatal("%s not analysed", istr(name)); (nets ? dump_nets : dump)(top); } argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
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 int elaborate(int argc, char **argv) { set_work_lib(); static struct option long_options[] = { {"disable-opt", no_argument, 0, 'o'}, {"dump-llvm", no_argument, 0, 'd'}, {"native", no_argument, 0, 'n'}, {"cover", no_argument, 0, 'c'}, {0, 0, 0, 0} }; int c, index = 0; const char *spec = ""; optind = 1; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 'o': opt_set_int("optimise", 0); break; case 'd': opt_set_int("dump-llvm", 1); break; case 'n': opt_set_int("native", 1); break; case 'c': opt_set_int("cover", 1); break; case 0: // Set a flag break; case '?': // getopt_long already printed an error message exit(EXIT_FAILURE); default: abort(); } } if (optind == argc) fatal("missing top-level unit name"); ident_t unit_i = to_unit_name(argv[optind]); tree_t unit = lib_get(lib_work(), unit_i); if (unit == NULL) fatal("cannot find unit %s in library %s", istr(unit_i), istr(lib_name(lib_work()))); tree_t e = elab(unit); if (e == NULL) return EXIT_FAILURE; opt(e); group_nets(e); // Save the library now so the code generator can attach temporary // meta data to trees lib_save(lib_work()); cgen(e); link_bc(e); return EXIT_SUCCESS; }
static int elaborate(int argc, char **argv) { set_work_lib(); static struct option long_options[] = { { "disable-opt", no_argument, 0, 'o' }, { "dump-llvm", no_argument, 0, 'd' }, { "dump-vcode", optional_argument, 0, 'V' }, { "native", no_argument, 0, 'n' }, { "cover", no_argument, 0, 'c' }, { "verbose", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; bool verbose = false; int c, index = 0; const char *spec = "v"; optind = 1; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 'o': opt_set_int("optimise", 0); break; case 'd': opt_set_int("dump-llvm", 1); break; case 'V': opt_set_str("dump-vcode", optarg ?: ""); break; case 'n': opt_set_int("native", 1); break; case 'c': opt_set_int("cover", 1); break; case 'v': verbose = true; break; case 0: // Set a flag break; case '?': fatal("unrecognised elaborate option %s", argv[optind - 1]); default: abort(); } } if (optind == argc) fatal("missing top-level unit name"); elab_verbose(verbose, "initialising"); ident_t unit_i = to_unit_name(argv[optind]); tree_t unit = lib_get(lib_work(), unit_i); if (unit == NULL) fatal("cannot find unit %s in library %s", istr(unit_i), istr(lib_name(lib_work()))); elab_verbose(verbose, "loading top-level unit"); tree_t e = elab(unit); if (e == NULL) return EXIT_FAILURE; elab_verbose(verbose, "elaborating design"); opt(e); elab_verbose(verbose, "optimising design"); group_nets(e); elab_verbose(verbose, "grouping nets"); // Save the library now so the code generator can attach temporary // meta data to trees lib_save(lib_work()); elab_verbose(verbose, "saving library"); lower_unit(e); elab_verbose(verbose, "generating intermediate code"); cgen(e); elab_verbose(verbose, "generating LLVM"); link_bc(e); elab_verbose(verbose, "linking"); return EXIT_SUCCESS; }