isl_ast_node_print: avoid duplicate declarations in printed code
authorSven Verdoolaege <skimo@kotnet.org>
Fri, 29 Mar 2013 13:53:13 +0000 (29 14:53 +0100)
committerSven Verdoolaege <skimo@kotnet.org>
Sun, 7 Apr 2013 15:33:09 +0000 (7 17:33 +0200)
If a loop has only one iteration but if the expression
for this single iteration is too complicated to be substituted into the AST,
then the expression is assigned to a variable corresponding to the loop
iterator.
If two such loops occur in the same block, then we would end up with
two declarations of the same variable.  Avoid this problem by introducing
a block around the declaration if it appears in a sequence of statements.

Reported-by: Tobias Grosser <tobias@grosser.es>
Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
isl_ast.c
test_inputs/codegen/unroll4.c [new file with mode: 0644]
test_inputs/codegen/unroll4.in [new file with mode: 0644]

index 3094bab..05a79a4 100644 (file)
--- a/isl_ast.c
+++ b/isl_ast.c
@@ -1315,7 +1315,7 @@ static int need_block(__isl_keep isl_ast_node *node)
 
 static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p,
        __isl_keep isl_ast_node *node,
-       __isl_keep isl_ast_print_options *options, int in_block);
+       __isl_keep isl_ast_print_options *options, int in_block, int in_list);
 static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p,
        __isl_keep isl_ast_node *node,
        __isl_keep isl_ast_print_options *options, int new_line);
@@ -1355,7 +1355,7 @@ static __isl_give isl_printer *print_body_c(__isl_take isl_printer *p,
        p = isl_printer_print_str(p, " {");
        p = isl_printer_end_line(p);
        p = isl_printer_indent(p, 2);
-       p = print_ast_node_c(p, node, options, 1);
+       p = print_ast_node_c(p, node, options, 1, 0);
        p = isl_printer_indent(p, -2);
        p = isl_printer_start_line(p);
        p = isl_printer_print_str(p, "}");
@@ -1410,12 +1410,15 @@ static __isl_give isl_printer *end_block(__isl_take isl_printer *p)
  *             body
  *
  * "in_block" is set if we are currently inside a block.
- * We simply pass it along to print_ast_node_c in case of a degenerate
- * for loop.
+ * "in_list" is set if the current node is not alone in the block.
+ * If we are not in a block or if the current not is not alone in the block
+ * then we print a block around a degenerate for loop such that the variable
+ * declaration will not conflict with any potential other declaration
+ * of the same variable.
  */
 static __isl_give isl_printer *print_for_c(__isl_take isl_printer *p,
        __isl_keep isl_ast_node *node,
-       __isl_keep isl_ast_print_options *options, int in_block)
+       __isl_keep isl_ast_print_options *options, int in_block, int in_list)
 {
        isl_id *id;
        const char *name;
@@ -1445,6 +1448,8 @@ static __isl_give isl_printer *print_for_c(__isl_take isl_printer *p,
                id = isl_ast_expr_get_id(node->u.f.iterator);
                name = isl_id_get_name(id);
                isl_id_free(id);
+               if (!in_block || in_list)
+                       p = start_block(p);
                p = isl_printer_start_line(p);
                p = isl_printer_print_str(p, type);
                p = isl_printer_print_str(p, " ");
@@ -1453,7 +1458,9 @@ static __isl_give isl_printer *print_for_c(__isl_take isl_printer *p,
                p = isl_printer_print_ast_expr(p, node->u.f.init);
                p = isl_printer_print_str(p, ";");
                p = isl_printer_end_line(p);
-               p = print_ast_node_c(p, node->u.f.body, options, in_block);
+               p = print_ast_node_c(p, node->u.f.body, options, 1, 0);
+               if (!in_block || in_list)
+                       p = end_block(p);
        }
 
        return p;
@@ -1482,10 +1489,12 @@ static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p,
  * If so, we do not print a block around the children of a block node.
  * We do this to avoid an extra block around the body of a degenerate
  * for node.
+ *
+ * "in_list" is set if the current node is not alone in the block.
  */
 static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p,
        __isl_keep isl_ast_node *node,
-       __isl_keep isl_ast_print_options *options, int in_block)
+       __isl_keep isl_ast_print_options *options, int in_block, int in_list)
 {
        switch (node->type) {
        case isl_ast_node_for:
@@ -1493,7 +1502,7 @@ static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p,
                        return options->print_for(p,
                                        isl_ast_print_options_copy(options),
                                        node, options->print_for_user);
-               p = print_for_c(p, node, options, in_block);
+               p = print_for_c(p, node, options, in_block, in_list);
                break;
        case isl_ast_node_if:
                p = print_if_c(p, node, options, 1);
@@ -1531,7 +1540,7 @@ __isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node,
        if (node->type != isl_ast_node_for)
                isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
                        "not a for node", goto error);
-       p = print_for_c(p, node, options, 0);
+       p = print_for_c(p, node, options, 0, 0);
        isl_ast_print_options_free(options);
        return p;
 error:
@@ -1566,7 +1575,7 @@ __isl_give isl_printer *isl_ast_node_print(__isl_keep isl_ast_node *node,
 {
        if (!options || !node)
                goto error;
-       p = print_ast_node_c(p, node, options, 0);
+       p = print_ast_node_c(p, node, options, 0, 0);
        isl_ast_print_options_free(options);
        return p;
 error:
@@ -1616,7 +1625,7 @@ __isl_give isl_printer *isl_ast_node_list_print(
                return isl_printer_free(p);
 
        for (i = 0; i < list->n; ++i)
-               p = print_ast_node_c(p, list->p[i], options, 1);
+               p = print_ast_node_c(p, list->p[i], options, 1, 1);
 
        return p;
 }
diff --git a/test_inputs/codegen/unroll4.c b/test_inputs/codegen/unroll4.c
new file mode 100644 (file)
index 0000000..9bf1884
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  write_shared_A(3, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1);
+  if (t1 % 3 == 0 && t2 >= 1 && t2 <= 2)
+    write_shared_A(3, (-t1 + 12) / 3, t2 + 32);
+  {
+    int c3 = t2 <= 1 || (t2 >= 2 && ((3 * t1 + t2 + 3) % 4) + 1 >= t2) ? t2 + 32 : t2;
+    if (c3 == t2 + 32 || (c3 == t2 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) >= 5 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) <= 8))
+      write_shared_A(3, ((t1 + 3) % 4) + 5, c3);
+  }
+  if (t2 >= t1 + 1 && t2 <= 4 && t1 >= 1)
+    write_shared_A(3, t1 + 4, t2 + 32);
+  write_shared_A(4, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1);
+  if (t1 % 3 == 0 && t2 >= 1 && t2 <= 2)
+    write_shared_A(4, (-t1 + 12) / 3, t2 + 32);
+  {
+    int c3 = t2 <= 1 || (t2 >= 2 && ((3 * t1 + t2 + 3) % 4) + 1 >= t2) ? t2 + 32 : t2;
+    if (c3 == t2 + 32 || (c3 == t2 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) >= 5 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) <= 8))
+      write_shared_A(4, ((t1 + 3) % 4) + 5, c3);
+  }
+  if (t2 >= t1 + 1 && t2 <= 4 && t1 >= 1)
+    write_shared_A(4, t1 + 4, t2 + 32);
+}
diff --git a/test_inputs/codegen/unroll4.in b/test_inputs/codegen/unroll4.in
new file mode 100644 (file)
index 0000000..d8be866
--- /dev/null
@@ -0,0 +1,5 @@
+# Check that the generated code does not contain two declarations
+# of the same variable in the same scope.
+[t1, t2, g] -> { write_shared_A[a, b, c] -> [0, a, b, c] : exists (e0, e1 = [(-t1 + b)/4], e2 = [(-t2 + c)/32]: 4e1 = -t1 + b and 32e2 = -t2 + c and e0 <= 2 + 3g and e0 >= 3g and a <= 4 and a >= 3 and t2 >= 0 and t1 <= 3 and 2e0 >= 5 - c + 6g and 2e0 <= 36 - c + 6g and 2e0 >= 5 - b + 6g and 2e0 <= 8 - b + 6g and 2e0 <= 638 - c and 2e0 <= 638 - b and 2e0 >= 2 - a + 6g and 2e0 >= -8 + a + 6g and 2e0 <= 1 + a + 6g and 2e0 <= 11 - a + 6g and e0 >= 0 and e0 <= 254 and t1 >= 0 and t2 <= 31 and b >= 1 and b <= 126 and c >= 1 and c <= 126 and g <= 3 and g >= 0) }
+[t1, t2, g] -> { : g <= 3 and g >= 0 and t1 >= 0 and t1 <= 3 and t2 >= 0 and t2 <= 5 }
+[t1, t2] -> { [i0, i1, i2, i3] -> unroll[x] }