]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
peephole optimization for logical &&, ||
authorAlan T. DeKok <aland@freeradius.org>
Tue, 23 Aug 2022 21:25:42 +0000 (17:25 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 25 Aug 2022 13:20:19 +0000 (09:20 -0400)
src/lib/unlang/xlat_expr.c
src/tests/unit/xlat/expr.txt

index de5b96d77085b72a740e012bf62303ba8c302fdb..0f9fea692eeb6ece556f7aabb730094b2bf37b49 100644 (file)
@@ -2451,6 +2451,64 @@ static bool valid_type(xlat_exp_t *node)
        return true;
 }
 
+static bool is_truthy(xlat_exp_t const *node, bool *out)
+{
+       fr_value_box_t const *box;
+
+       if (node->type == XLAT_BOX) {
+               box = &node->data;
+
+       } else if ((node->type == XLAT_TMPL) && tmpl_is_data(node->vpt)) {
+               box = tmpl_value(node->vpt);
+
+       } else {
+               *out = false;
+               return false;
+       }
+
+       *out = fr_value_box_is_truthy(box);
+       return true;
+}
+
+/*
+ *     Do local optimizations.
+ *
+ *     @todo - check for tail of LHS
+ *
+ *     if ((lhs->type == XLAT_FUNC) && (lhs->call.func->token == op))
+ *             && tail is truthy, then remove tail, replace it with RHS
+ *             and return LHS.
+ *
+ *     lhs->call.args->flags.can_purify |= rhs->flags.can_purify | rhs->flags.pure;
+ *     lhs->flags.can_purify = lhs->call.args->flags.can_purify;
+ */
+static xlat_exp_t *logical_purify(xlat_exp_t *lhs, fr_token_t op, xlat_exp_t *rhs)
+{
+       bool value;
+
+       if (!is_truthy(lhs, &value)) return NULL;
+
+       /*
+        *      1 && FOO   --> FOO
+        *      0 && FOO   --> 0
+        *      FOO && BAR --> FOO && BAR
+        */
+
+
+       /*
+        *      1 || FOO   --> 1
+        *      0 || FOO   --> FOO
+        *      FOO || BAR --> FOO || BAR
+        */
+       if (value == (op != T_LAND)) {
+               talloc_free(rhs);
+               return lhs;
+       }
+       
+       talloc_free(lhs);
+       return rhs;
+}
+
 /** Tokenize a mathematical operation.
  *
  *     (EXPR)
@@ -2625,21 +2683,41 @@ redo:
        fr_assert(func != NULL);
 
        /*
-        *      If it's a logical operator, then perhaps we can
-        *      statically evaluate the arguments, and simplify the
-        *      condition.  If we can't simplify the con
+        *      If it's a logical operator, check for rcodes, and also
+        *      merge sequences of the same operator together.
         */
-       if (logical_ops[op] && (lhs->type == XLAT_FUNC) && (lhs->call.func->token == op)) {
+       if (logical_ops[op]) {
                if (reparse_rcode(head, &rhs, true) < 0) {
                        fr_sbuff_set(&our_in, &m_rhs);
                        return -fr_sbuff_used(&our_in);
                }
+               fr_assert(rhs != NULL);
+
+               if ((lhs->type == XLAT_FUNC) && (lhs->call.func->token == op)) {
+                       xlat_func_append_arg(lhs, rhs, cond);
+
+                       lhs->call.args->flags.can_purify |= rhs->flags.can_purify | rhs->flags.pure;
+                       lhs->flags.can_purify = lhs->call.args->flags.can_purify;
+                       goto redo;
+               }
 
-               xlat_func_append_arg(lhs, rhs, cond);
+               if (reparse_rcode(head, &lhs, true) < 0) {
+                       fr_sbuff_set(&our_in, &m_lhs);
+                       return -fr_sbuff_used(&our_in);
+               }
 
-               lhs->call.args->flags.can_purify |= rhs->flags.can_purify | rhs->flags.pure;
-               lhs->flags.can_purify = lhs->call.args->flags.can_purify;
-               goto redo;
+               /*
+                *      Peephole optimizer.
+                *
+                *              FOO || 0 --> FOO
+                *              FOO && 1 --> 1
+                */
+               node = logical_purify(lhs, op, rhs);
+               if (node) {
+                       lhs = node;
+                       rhs = node = NULL;
+                       goto redo;
+               }
        }
 
        /*
@@ -2662,27 +2740,12 @@ redo:
                        fr_sbuff_set(&our_in, &m_rhs);
                        return -fr_sbuff_used(&our_in);
                }
-       }
-
-       /*
-        *      Convert a bare
-        *
-        *              handled
-        *
-        *      to
-        *
-        *              %{rcode:handled}
-        */
-       if (logical_ops[op]) {
-               if (reparse_rcode(head, &lhs, true) < 0) {
-                       fr_sbuff_set(&our_in, &m_lhs);
-                       return -fr_sbuff_used(&our_in);
-               }
 
-               if (reparse_rcode(head, &rhs, true) < 0) {
-                       fr_sbuff_set(&our_in, &m_rhs);
-                       return -fr_sbuff_used(&our_in);
-               }
+               /*
+                *      @todo - peephole optimization.  If both LHS
+                *      and RHS are static values, then just call the
+                *      relevant condition code to get the result.
+                */
        }
 
        /*
index f9fcaa8d57e9cbf9e16ec01199e4f4841981510a..bc233eab0b9b7f6ec0277b6355cc6079ac6ef2ff 100644 (file)
@@ -74,8 +74,11 @@ match (192.168.0.0/24 > &Framed-IP-Address)
 xlat_expr 1 < 2 || 4 > 3
 match ((1 < 2) || (4 > 3))
 
+#
+#  Peephole optimization for some cases
+#
 xlat_expr 2 || (1 > 4)
-match (2 || (1 > 4))
+match 2
 
 #
 #  Repeated operations of the same type are mashed together into one list.