From 14206e222c810879da5949aac4b716662e62d1f6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 25 Mar 2017 11:11:02 +0000 Subject: [PATCH] Lower architecture function bodies only where necessary --- src/common.c | 12 ++++++--- src/eval.c | 35 ++++++++++++++++++++---- src/lower.c | 61 ++++++++++++++++++++++++++++++------------ src/nvc.c | 4 +-- src/phase.h | 8 ++++-- src/util.c | 11 ++++++-- test/elab/issue19.vhd | 9 +++++++ test/simp/issue309.vhd | 9 +++++-- test/test_elab.c | 44 ++++++------------------------ 9 files changed, 123 insertions(+), 70 deletions(-) diff --git a/src/common.c b/src/common.c index 9ad82191..11ffa270 100644 --- a/src/common.c +++ b/src/common.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2013-2016 Nick Gasson +// Copyright (C) 2013-2017 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -39,14 +39,18 @@ int64_t assume_int(tree_t t) case T_REF: { tree_t ref = tree_ref(t); - assert(tree_kind(ref) == T_ENUM_LIT); - return tree_pos(ref); + if (tree_kind(ref) == T_CONST_DECL) + return assume_int(tree_value(ref)); + else { + assert(tree_kind(ref) == T_ENUM_LIT); + return tree_pos(ref); + } } case T_FCALL: { const eval_flags_t flags = - EVAL_FCALL | EVAL_BOUNDS | EVAL_WARN | EVAL_REPORT; + EVAL_FCALL | EVAL_BOUNDS | EVAL_WARN | EVAL_REPORT | EVAL_LOWER; tree_t new = eval(t, flags); const tree_kind_t new_kind = tree_kind(new); if (new_kind == T_LITERAL || new_kind == T_REF) diff --git a/src/eval.c b/src/eval.c index ec3aff86..314baf15 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2013-2016 Nick Gasson +// Copyright (C) 2013-2017 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -100,10 +100,10 @@ static bool eval_params_possible(tree_t fcall, eval_flags_t flags) const int nparams = tree_params(fcall); for (int i = 0; i < nparams; i++) { tree_t p = tree_value(tree_param(fcall, i)); - const bool fcall = tree_kind(p) == T_FCALL; - if ((flags & EVAL_FOLDING) && fcall && type_is_scalar(tree_type(p))) + const bool is_fcall = tree_kind(p) == T_FCALL; + if ((flags & EVAL_FOLDING) && is_fcall && type_is_scalar(tree_type(p))) return false; // Would have been folded already if possible - else if (fcall && !(flags & EVAL_FCALL)) + else if (is_fcall && !(flags & EVAL_FCALL)) return false; else if (!eval_possible(p, flags)) return false; @@ -112,6 +112,22 @@ static bool eval_params_possible(tree_t fcall, eval_flags_t flags) return true; } +static bool eval_have_lowered(tree_t body, eval_flags_t flags) +{ + if (tree_attr_str(body, builtin_i)) + return true; + + ident_t mangled = tree_attr_str(body, mangled_i); + if (mangled == NULL || vcode_find_unit(mangled) == NULL) { + if (!(flags & EVAL_LOWER)) + return false; + + return lower_func(body) != NULL; + } + else + return true; +} + static bool eval_possible(tree_t t, eval_flags_t flags) { switch (tree_kind(t)) { @@ -119,7 +135,13 @@ static bool eval_possible(tree_t t, eval_flags_t flags) { if (!(flags & EVAL_FCALL)) return false; - else if (tree_flags(tree_ref(t)) & TREE_F_IMPURE) + else if (tree_flags(tree_ref(t)) & TREE_F_IMPURE) { + if (flags & EVAL_WARN) + warn_at(tree_loc(t), + "impure function call prevents constant folding"); + return false; + } + else if (!eval_have_lowered(tree_ref(t), flags)) return false; return eval_params_possible(t, flags); @@ -143,6 +165,9 @@ static bool eval_possible(tree_t t, eval_flags_t flags) return eval_possible(tree_value(decl), flags); default: + if (flags & EVAL_WARN) + warn_at(tree_loc(t), "reference to %s prevents constant folding", + istr(tree_ident(t))); return false; } } diff --git a/src/lower.c b/src/lower.c index cdacc094..613d0b0f 100644 --- a/src/lower.c +++ b/src/lower.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2014-2016 Nick Gasson +// Copyright (C) 2014-2017 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -79,7 +79,7 @@ static vcode_reg_t lower_expr(tree_t expr, expr_ctx_t ctx); static vcode_reg_t lower_reify_expr(tree_t expr); static vcode_type_t lower_bounds(type_t type); static void lower_stmt(tree_t stmt, loop_stack_t *loops); -static void lower_func_body(tree_t body, vcode_unit_t context); +static vcode_unit_t lower_func_body(tree_t body, vcode_unit_t context); static void lower_proc_body(tree_t body, vcode_unit_t context); static vcode_reg_t lower_signal_ref(tree_t decl, expr_ctx_t ctx); static vcode_reg_t lower_record_aggregate(tree_t expr, bool nest, @@ -4362,13 +4362,14 @@ static void lower_decls(tree_t scope, vcode_unit_t context) if (mode == LOWER_THUNK && (kind == T_SIGNAL_DECL || kind == T_PROT_BODY)) continue; - else if (kind == T_FUNC_BODY || kind == T_PROC_BODY - || kind == T_PROT_BODY) { - if (nested) { + else if (kind == T_FUNC_BODY || kind == T_PROC_BODY || kind == T_FUNC_DECL + || kind == T_PROC_DECL) { + if (nested) tree_add_attr_int(d, nested_i, nest_depth + 1); - lower_mangle_func(d, context); - } + lower_mangle_func(d, context); } + else if (kind == T_PROT_BODY) + ; else if (scope_kind != T_PROT_BODY) lower_decl(d); } @@ -4463,7 +4464,7 @@ static void lower_subprogram_ports(tree_t body, bool has_subprograms) } } -static bool lower_have_subprogram(ident_t name, vcode_unit_t context) +static vcode_unit_t lower_find_subprogram(ident_t name, vcode_unit_t context) { vcode_unit_t vu = vcode_find_unit(name); if (vu == NULL) @@ -4473,10 +4474,11 @@ static bool lower_have_subprogram(ident_t name, vcode_unit_t context) vcode_state_save(&state); vcode_select_unit(vu); - const bool same_context = vcode_unit_context() == context; + const bool same_context = vcode_unit_context() == context + || (mode == LOWER_THUNK && vcode_unit_kind() == VCODE_UNIT_THUNK); vcode_state_restore(&state); - return same_context; + return same_context ? vu : NULL; } static void lower_proc_body(tree_t body, vcode_unit_t context) @@ -4487,12 +4489,12 @@ static void lower_proc_body(tree_t body, vcode_unit_t context) vcode_select_unit(context); ident_t name = lower_mangle_func(body, context); - if (lower_have_subprogram(name, context)) + vcode_unit_t vu = lower_find_subprogram(name, context); + if (vu != NULL) return; tree_add_attr_str(body, mangled_i, name); - vcode_unit_t vu; if (never_waits) vu = emit_function(name, context, VCODE_INVALID_TYPE); else @@ -4518,18 +4520,19 @@ static void lower_proc_body(tree_t body, vcode_unit_t context) vcode_unit_unref(vu); } -static void lower_func_body(tree_t body, vcode_unit_t context) +static vcode_unit_t lower_func_body(tree_t body, vcode_unit_t context) { vcode_select_unit(context); vcode_type_t vtype = lower_func_result_type(body); ident_t name = lower_mangle_func(body, context); - if (lower_have_subprogram(name, context)) - return; + vcode_unit_t vu = lower_find_subprogram(name, context); + if (vu != NULL) + return vu; tree_add_attr_str(body, mangled_i, name); - vcode_unit_t vu = emit_function(name, context, vtype); + vu = emit_function(name, context, vtype); emit_debug_info(tree_loc(body)); const bool has_subprograms = lower_has_subprograms(body); @@ -4543,8 +4546,12 @@ static void lower_func_body(tree_t body, vcode_unit_t context) lower_finished(); - if (vcode_unit_has_undefined()) + if (vcode_unit_has_undefined()) { vcode_unit_unref(vu); + return NULL; + } + else + return vu; } static bool lower_driver_nets(tree_t t, tree_t *decl, @@ -4879,3 +4886,23 @@ vcode_unit_t lower_thunk(tree_t fcall) vcode_close(); return thunk; } + +vcode_unit_t lower_func(tree_t body) +{ + lower_set_verbose(); + + vcode_unit_t context = emit_context(thunk_i); + + vcode_select_unit(context); + vcode_objs = hash_new(128, true); + mode = LOWER_THUNK; + tmp_alloc_used = false; + + vcode_unit_t vu = lower_func_body(body, context); + vcode_close(); + + hash_free(vcode_objs); + vcode_objs = NULL; + + return vu; +} diff --git a/src/nvc.c b/src/nvc.c index 093b0b74..05b33449 100644 --- a/src/nvc.c +++ b/src/nvc.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2016 Nick Gasson +// Copyright (C) 2011-2017 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #endif const char *copy_string = - "Copyright (C) 2011-2016 Nick Gasson\n" + "Copyright (C) 2011-2017 Nick Gasson\n" "This program comes with ABSOLUTELY NO WARRANTY. This is free software, " "and\nyou are welcome to redistribute it under certain conditions. See " "the GNU\nGeneral Public Licence for details."; diff --git a/src/phase.h b/src/phase.h index f08c4291..2abe6411 100644 --- a/src/phase.h +++ b/src/phase.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2016 Nick Gasson +// Copyright (C) 2011-2017 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -26,7 +26,8 @@ typedef enum { EVAL_WARN = (1 << 2), EVAL_VERBOSE = (1 << 4), EVAL_REPORT = (1 << 5), - EVAL_FOLDING = (1 << 6) + EVAL_FOLDING = (1 << 6), + EVAL_LOWER = (1 << 7) } eval_flags_t; // Annotate types and perform other semantics checks on a tree. @@ -97,4 +98,7 @@ vcode_unit_t lower_unit(tree_t unit); // Generate vcode for an isolated function call vcode_unit_t lower_thunk(tree_t fcall); +// Lower an isolated function body +vcode_unit_t lower_func(tree_t body); + #endif // _PHASE_H diff --git a/src/util.c b/src/util.c index 7505912c..4f9b238d 100644 --- a/src/util.c +++ b/src/util.c @@ -338,6 +338,14 @@ void notef(const char *fmt, ...) va_end(ap); } +static void fatalf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fmt_color(ANSI_FG_RED, "Fatal", fmt, ap); + va_end(ap); +} + static void def_error_fn(const char *msg, const loc_t *loc) { if (message_style == MESSAGE_COMPACT) @@ -456,8 +464,7 @@ void fatal_at(const loc_t *loc, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fmt_color(ANSI_FG_RED, "Fatal", fmt, ap); - fmt_loc(stderr, loc); + catch_in_unit_test(fatalf, loc, fmt, ap); va_end(ap); if (fatal_fn != NULL) diff --git a/test/elab/issue19.vhd b/test/elab/issue19.vhd index 8fcac017..bfc6da71 100644 --- a/test/elab/issue19.vhd +++ b/test/elab/issue19.vhd @@ -53,6 +53,15 @@ signal tmp3 : integer := cnum3; begin y <= x; + + g1: if cnum /= 32 generate + assert false; + end generate; + + g2: if cnum3 /= 32 generate + assert false; + end generate; + end architecture; ------------------------------------------------------------------------------- diff --git a/test/simp/issue309.vhd b/test/simp/issue309.vhd index 40a6a9de..312af0f7 100644 --- a/test/simp/issue309.vhd +++ b/test/simp/issue309.vhd @@ -32,7 +32,12 @@ architecture MODEL of issue309 is begin - assert c; - assert d; + g1: if not (c or true) generate -- XXXX + assert false; + end generate; + + g2: if not (d or true) generate -- XXXX + assert false; + end generate; end MODEL; diff --git a/test/test_elab.c b/test/test_elab.c index a5c2d368..1ce05271 100644 --- a/test/test_elab.c +++ b/test/test_elab.c @@ -6,6 +6,7 @@ #include #include +#include START_TEST(test_elab1) { @@ -130,32 +131,7 @@ START_TEST(test_issue19) expect_errors(expect); tree_t e = run_elab(); - - tree_t tmp = NULL; - const int ndecls = tree_decls(e); - for (int i = 0; (i < ndecls) && (tmp == NULL); i++) { - tree_t t = tree_decl(e, i); - if (icmp(tree_ident(t), ":comp6:c1:tmp")) - tmp = t; - } - - fail_if(tmp == NULL); - - tree_t value = tree_value(tmp); - fail_unless(tree_kind(value) == T_LITERAL); - fail_unless(tree_ival(value) == 32); - - for (int i = 0; (i < ndecls) && (tmp == NULL); i++) { - tree_t t = tree_decl(e, i); - if (icmp(tree_ident(t), ":comp6:c1:tmp3")) - tmp = t; - } - - fail_if(tmp == NULL); - - value = tree_value(tmp); - fail_unless(tree_kind(value) == T_LITERAL); - fail_unless(tree_ival(value) == 32); + fail_unless(tree_stmts(e) == 1); } END_TEST @@ -249,10 +225,7 @@ START_TEST(test_issue93) expect_errors(expect); tree_t top = run_elab(); - tree_t c_order = tree_value(tree_decl(top, 2)); - fail_unless(tree_kind(c_order) == T_LITERAL); - fail_unless(tree_subkind(c_order) == L_INT); - fail_unless(tree_ival(c_order) == 4); + fail_unless(tree_stmts(top) == 4); } END_TEST @@ -268,11 +241,9 @@ START_TEST(test_const1) tree_t top = run_elab(); tree_t ctr_r = tree_decl(top, tree_decls(top) - 1); + fail_unless(tree_kind(ctr_r) == T_SIGNAL_DECL); fail_unless(tree_ident(ctr_r) == ident_new(":top:pwm_1:ctr_r")); - - range_t r = type_dim(tree_type(ctr_r), 0); - fail_unless(tree_kind(r.left) == T_LITERAL); - fail_unless(tree_ival(r.left) == 14); + fail_unless(tree_nets(ctr_r) == 15); } END_TEST @@ -435,7 +406,8 @@ START_TEST(test_eval1) const error_t expect[] = { { 12, "array index -1 outside bounds 7 downto 0" }, - { 16, "while evaluating call to FUNC" }, + { 16, "while evaluating call to \"=\"" }, + { 16, "expression cannot be folded to an integer constant" }, { -1, NULL } }; expect_errors(expect); @@ -513,7 +485,7 @@ int main(void) tcase_add_test(tc, test_libbind3); tcase_add_test(tc, test_issue251); tcase_add_test(tc, test_jcore1); - tcase_add_test(tc, test_eval1); + tcase_add_exit_test(tc, test_eval1, EXIT_FAILURE); tcase_add_test(tc, test_issue305); tcase_add_test(tc, test_gbounds); tcase_add_test(tc, test_issue307); -- 2.39.2