Permalink
Browse files

Constant folding for array references

  • Loading branch information...
1 parent fa11422 commit b0df00a7face6944e34a975ed683fcded1e003bf @nickg committed Oct 2, 2011
Showing with 166 additions and 4 deletions.
  1. +1 −1 src/nvc.c
  2. +3 −0 src/phase.h
  3. +10 −0 src/sem.c
  4. +88 −0 src/simp.c
  5. +1 −0 test/regress/testlist.txt
  6. +5 −3 test/run_regr.rb
  7. +10 −0 test/simp/cfold.vhd
  8. +48 −0 test/test_simp.c
View
@@ -92,7 +92,7 @@ static int analyse(int argc, char **argv)
tree_gc();
- if (parse_errors() > 0 || sem_errors() > 0)
+ if (parse_errors() + sem_errors() + simplify_errors() > 0)
return EXIT_FAILURE;
lib_save(lib_work());
View
@@ -33,6 +33,9 @@ void sem_bootstrap_en(bool en);
// Fold all constant expressions
void simplify(tree_t top);
+// Number of errors found during simplification
+int simplify_errors(void);
+
// Find all drivers associated with signals
void driver_extract(tree_t top);
View
@@ -1423,6 +1423,16 @@ static bool sem_check_array_ref(tree_t t)
if (type_kind(type) != T_CARRAY)
sem_error(t, "invalid array reference");
+ bool ok = true;
+ for (unsigned i = 0; i < tree_params(t); i++) {
+ param_t p = tree_param(t, i);
+ if (p.kind != P_POS)
+ sem_error(t, "only scalar references supported");
+
+ // TODO: push type set containing index type of array
+ ok = sem_check(p.value) && ok;
+ }
+
tree_set_type(t, type_base(type));
tree_set_ref(t, tree_ref(value));
return true;
View
@@ -28,6 +28,11 @@ static tree_t simp_expr(tree_t t);
static ident_t std_bool_i = NULL;
static ident_t builtin_i = NULL;
+static int errors = 0;
+
+#define simp_error(t, __VA_ARGS__) \
+ { errors++; error_at(tree_loc(t), __VA_ARGS__); return t; }
+
static bool folded_num(tree_t t, literal_t *l)
{
if (tree_kind(t) == T_LITERAL) {
@@ -52,6 +57,14 @@ static bool folded_bool(tree_t t, bool *b)
return false;
}
+static int64_t assume_int(tree_t t)
+{
+ assert(tree_kind(t) == T_LITERAL);
+ literal_t l = tree_literal(t);
+ assert(l.kind == L_INT);
+ return l.i;
+}
+
static tree_t get_int_lit(tree_t t, int64_t i)
{
tree_t fdecl = tree_ref(t);
@@ -228,6 +241,73 @@ static tree_t simp_attr_ref(tree_t t)
}
}
+static tree_t simp_array_ref(tree_t t)
+{
+ tree_set_value(t, simp_expr(tree_value(t)));
+
+ literal_t indexes[tree_params(t)];
+ bool can_fold = true;
+ for (unsigned i = 0; i < tree_params(t); i++) {
+ param_t p = tree_param(t, i);
+ assert(p.kind == P_POS);
+ p.value = simp_expr(p.value);
+ tree_change_param(t, i, p);
+ can_fold = can_fold && folded_num(p.value, &indexes[i]);
+ }
+
+ if (!can_fold)
+ return t;
+
+ assert(tree_params(t) == 1);
+
+ tree_t decl = tree_ref(t);
+ // XXX: may not be decl e.g. nested array ref
+
+ switch (tree_kind(decl)) {
+ case T_CONST_DECL:
+ {
+ tree_t v = tree_value(decl);
+ assert(tree_kind(v) == T_AGGREGATE);
+ assert(indexes[0].kind == L_INT);
+
+ range_t bounds = type_dim(tree_type(decl), 0);
+ int64_t left = assume_int(bounds.left);
+ int64_t right = assume_int(bounds.right);
+
+ if (indexes[0].i < left || indexes[0].i > right)
+ simp_error(t, "array reference out of bounds");
+
+ for (unsigned i = 0; i < tree_assocs(v); i++) {
+ assoc_t a = tree_assoc(v, i);
+ switch (a.kind) {
+ case A_POS:
+ if (a.pos + left == indexes[0].i)
+ return a.value;
+ break;
+
+ case A_OTHERS:
+ return a.value;
+
+ case A_RANGE:
+ if ((indexes[0].i >= assume_int(a.range.left))
+ && (indexes[0].i <= assume_int(a.range.right)))
+ return a.value;
+ break;
+
+ case A_NAMED:
+ if (assume_int(a.name) == indexes[0].i)
+ return a.value;
+ break;
+ }
+ }
+
+ assert(false);
+ }
+ default:
+ return t;
+ }
+}
+
static tree_t simp_expr(tree_t t)
{
switch (tree_kind(t)) {
@@ -267,6 +347,9 @@ static tree_t simp_expr(tree_t t)
case T_ATTR_REF:
return simp_attr_ref(t);
+ case T_ARRAY_REF:
+ return simp_array_ref(t);
+
default:
assert(false);
}
@@ -407,3 +490,8 @@ void simplify(tree_t top)
assert(false);
}
}
+
+int simplify_errors(void)
+{
+ return errors;
+}
@@ -6,3 +6,4 @@ arith1 normal
signal1 normal
attr1 normal
signal2 normal
+#signal3 normal
View
@@ -14,9 +14,11 @@
def read_tests
tests = []
File.open(TestDir + "regress/testlist.txt").each_line do |l|
- parts = l.split /\s+/
- flags = parts[1].split /,/
- tests << { :name => parts[0], :flags => flags }
+ parts = l.gsub(/\#.*$/, '').strip.split(/\s+/)
+ if parts.length > 0 then
+ flags = parts[1].split /,/
+ tests << { :name => parts[0], :flags => flags }
+ end
end
tests
end
View
@@ -6,6 +6,10 @@ architecture a of e is
type t is range -5 to 11 - 3;
constant c : integer := +4 + 1;
signal y : t;
+ type int_array is array (integer range <>) of integer;
+ constant a1 : int_array(1 to 5) := (1, 2, 3, 4, 5);
+ constant a2 : int_array(1 to 7) := (2 to 3 => 6, others => 5);
+ constant a3 : int_array(1 to 9) := (8 => 24, others => 0);
begin
process is
@@ -27,6 +31,12 @@ begin
b := false nand false;
b := false nor true;
b := 7 > 5 and 6 < 2;
+ x <= a1(2);
+ x <= a2(1);
+ x <= a2(3);
+ x <= a3(8);
+ x <= a3(10); -- Error!
+ x <= a3(-1); -- Error!
end process;
end architecture;
View
@@ -8,6 +8,14 @@
#include <stdio.h>
#include <string.h>
+typedef struct error {
+ int line;
+ const char *snippet;
+} error_t;
+
+static const error_t *error_lines = NULL;
+static error_fn_t orig_error_fn = NULL;
+
static void setup(void)
{
lib_set_work(lib_tmp());
@@ -18,6 +26,33 @@ static void teardown(void)
lib_free(lib_work());
}
+static void test_error_fn(const char *msg, const loc_t *loc)
+{
+ fail_if(error_lines == NULL);
+
+ bool unexpected = error_lines->line == -1
+ || error_lines->snippet == NULL
+ || error_lines->line != loc->first_line
+ || strstr(msg, error_lines->snippet) == NULL;
+
+ if (unexpected) {
+ orig_error_fn(msg, loc);
+ printf("expected line %d '%s'\n",
+ error_lines->line, error_lines->snippet);
+ }
+
+ fail_if(unexpected);
+
+ error_lines++;
+}
+
+static void expect_errors(const error_t *lines)
+{
+ fail_unless(orig_error_fn == NULL);
+ orig_error_fn = set_error_fn(test_error_fn);
+ error_lines = lines;
+}
+
static bool folded_i(tree_t t, int64_t i)
{
if (tree_kind(t) != T_LITERAL)
@@ -50,6 +85,13 @@ START_TEST(test_cfold)
tree_t e, a, p, s;
range_t r;
+ const error_t expect[] = {
+ { 38, "array reference out of bounds" },
+ { 39, "array reference out of bounds" },
+ { -1, NULL }
+ };
+ expect_errors(expect);
+
fail_unless(input_from_file(TESTDIR "/simp/cfold.vhd"));
e = parse();
@@ -98,6 +140,12 @@ START_TEST(test_cfold)
fail_unless(folded_b(tree_value(tree_stmt(p, 13)), true));
fail_unless(folded_b(tree_value(tree_stmt(p, 14)), false));
fail_unless(folded_b(tree_value(tree_stmt(p, 15)), false));
+ fail_unless(folded_i(tree_value(tree_stmt(p, 16)), 2));
+ fail_unless(folded_i(tree_value(tree_stmt(p, 17)), 5));
+ fail_unless(folded_i(tree_value(tree_stmt(p, 18)), 6));
+ fail_unless(folded_i(tree_value(tree_stmt(p, 19)), 24));
+
+ fail_unless(simplify_errors() == (sizeof(expect) / sizeof(error_t)) - 1);
}
END_TEST

0 comments on commit b0df00a

Please sign in to comment.