]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Change linearization of branches in switch instruction
authorOndrej Zajicek <santiago@crfreenet.org>
Sat, 7 Jan 2023 19:18:44 +0000 (20:18 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sat, 7 Jan 2023 19:18:44 +0000 (20:18 +0100)
Most branching instructions (FI_CONDITION, FI_AND, FI_OR) linearize its
branches in a recursive way, while FI_SWITCH branches are linearized
from parser even before the switch instruction is allocated.

Change linearization of FI_SWITCH branches to make it similar to other
branching instructions. This also fixes an issue with constant
switch evaluation, where linearized branch is mistaken for
non-linearized during switch construction.

Thanks to Jiten Kumar Pathy for the bugreport.

filter/config.Y
filter/data.h
filter/f-inst.c
filter/tree.c

index 68ee1a847c9de0168e8b4f720437e9cf9763f6ea..1d9d9aa970ee1b7734f727ef80ee334578537d09 100644 (file)
@@ -676,16 +676,15 @@ switch_body: /* EMPTY */ { $$ = NULL; }
  | switch_body switch_items ':' cmds_scoped  {
      /* Fill data fields */
      struct f_tree *t;
-     struct f_line *line = f_linearize($4, 0);
      for (t = $2; t; t = t->left)
-       t->data = line;
+       t->data = $4;
      $$ = f_merge_items($1, $2);
    }
  | switch_body ELSECOL cmds_scoped {
      struct f_tree *t = f_new_tree();
      t->from.type = t->to.type = T_VOID;
      t->right = t;
-     t->data = f_linearize($3, 0);
+     t->data = $3;
      $$ = f_merge_items($1, t);
  }
  ;
@@ -972,7 +971,7 @@ cmd:
    }
  | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
  | CASE term '{' switch_body '}' {
-      $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
+      $$ = f_new_inst(FI_SWITCH, $2, $4);
    }
 
  | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
index 5edeaedb7220590ede59676ff3ddd86ab2ad26e6..700609e9de8cc2ef88aef2565281d9f41f07b64a 100644 (file)
@@ -198,6 +198,7 @@ struct f_trie_walk_state
 struct f_tree *f_new_tree(void);
 struct f_tree *build_tree(struct f_tree *);
 const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
+const struct f_tree *find_tree_linear(const struct f_tree *t, const struct f_val *val);
 int same_tree(const struct f_tree *t0, const struct f_tree *t2);
 int tree_node_count(const struct f_tree *t);
 void tree_format(const struct f_tree *t, buffer *buf);
index 9a3a22abc62bc555722619bf25e8850c8072f787..2d2a30e4f7da5a2150e360086dddee76e9091409 100644 (file)
 
     FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
 
+    FID_LINEARIZE_BODY()
+    /* Linearize all branches in switch */
+    struct f_inst *last_inst = NULL;
+    struct f_line *last_line = NULL;
+    for (struct f_tree *t = whati->tree; t; t = t->left)
+    {
+      if (t->data != last_inst)
+      {
+       last_inst = t->data;
+       last_line = f_linearize(t->data, 0);
+      }
+
+      t->data = last_line;
+    }
+
+    /* Balance the tree */
+    item->tree = build_tree(whati->tree);
+
     FID_ITERATE_BODY()
-      tree_walk(whati->tree, f_add_tree_lines, fit);
+    tree_walk(whati->tree, f_add_tree_lines, fit);
 
     FID_INTERPRET_BODY()
-    const struct f_tree *t = find_tree(tree, &v1);
+    /* In parse-time use find_tree_linear(), in runtime use find_tree() */
+    const struct f_tree *t = FID_HIC(,find_tree,find_tree_linear)(tree, &v1);
     if (!t) {
       v1.type = T_VOID;
-      t = find_tree(tree, &v1);
+      t = FID_HIC(,find_tree,find_tree_linear)(tree, &v1);
       if (!t) {
        debug( "No else statement?\n");
        FID_HIC(,break,return NULL);
index 97bf7dae5eff788455f23d1c10574b1094f15045..25cf93e49a66f5ba90a08be5e0f1af24a83fa06d 100644 (file)
@@ -38,6 +38,26 @@ find_tree(const struct f_tree *t, const struct f_val *val)
     return find_tree(t->left, val);
 }
 
+/**
+ * find_tree_linear
+ * @t: tree to search in
+ * @val: value to find
+ *
+ * Search for given value in the degenerated linear tree, which is generated by
+ * parser before build_tree() is applied. The tree is not sorted and all nodes
+ * are linked by left ptr.
+ */
+const struct f_tree *
+find_tree_linear(const struct f_tree *t, const struct f_val *val)
+{
+  for (; t; t = t->left)
+    if ((val_compare(&(t->from), val) != 1) &&
+       (val_compare(&(t->to), val) != -1))
+      return t;
+
+  return NULL;
+}
+
 static struct f_tree *
 build_tree_rec(struct f_tree **buf, int l, int h)
 {