Skip to content

Commit

Permalink
Merge pull request #390 from MrAnno/literal-expr-prop-optimization
Browse files Browse the repository at this point in the history
FilterX operator optimization for literals
  • Loading branch information
alltilla authored Nov 29, 2024
2 parents 49bf68b + adf1cd2 commit b8f7853
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 61 deletions.
78 changes: 62 additions & 16 deletions lib/filterx/expr-boolalg.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@
*/
#include "filterx/expr-boolalg.h"
#include "filterx/object-primitive.h"
#include "filterx/expr-literal.h"

static inline gboolean
_literal_expr_truthy(FilterXExpr *expr)
{
FilterXObject *result = filterx_expr_eval(expr);
g_assert(result);

gboolean truthy = filterx_object_truthy(result);
filterx_object_unref(result);

return truthy;
}

static FilterXObject *
_eval_not(FilterXExpr *s)
Expand All @@ -44,6 +57,9 @@ _eval_not(FilterXExpr *s)
FilterXExpr *
filterx_unary_not_new(FilterXExpr *operand)
{
if (filterx_expr_is_literal(operand))
return filterx_literal_new(filterx_boolean_new(!_literal_expr_truthy(operand)));

FilterXUnaryOp *self = g_new0(FilterXUnaryOp, 1);

filterx_unary_op_init_instance(self, operand);
Expand All @@ -59,17 +75,20 @@ _eval_and(FilterXExpr *s)
/* we only evaluate our rhs if lhs is true, e.g. we do fast circuit
* evaluation just like most languages */

FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;
if (self->lhs)
{
FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;

gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);
gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);

if (!lhs_truthy)
return filterx_boolean_new(FALSE);
if (!lhs_truthy)
return filterx_boolean_new(FALSE);
}

result = filterx_expr_eval(self->rhs);
FilterXObject *result = filterx_expr_eval(self->rhs);
if (!result)
return NULL;

Expand All @@ -85,9 +104,21 @@ _eval_and(FilterXExpr *s)
FilterXExpr *
filterx_binary_and_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
if (!_literal_expr_truthy(lhs))
return filterx_literal_new(filterx_boolean_new(FALSE));

if (filterx_expr_is_literal(rhs))
return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs)));
}

FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1);

filterx_binary_op_init_instance(self, lhs, rhs);
if (filterx_expr_is_literal(lhs))
self->lhs = NULL;

self->super.eval = _eval_and;
return &self->super;
}
Expand All @@ -100,17 +131,20 @@ _eval_or(FilterXExpr *s)
/* we only evaluate our rhs if lhs is false, e.g. we do fast circuit
* evaluation just like most languages */

FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;
if (self->lhs)
{
FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;

gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);
gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);

if (lhs_truthy)
return filterx_boolean_new(TRUE);
if (lhs_truthy)
return filterx_boolean_new(TRUE);
}

result = filterx_expr_eval(self->rhs);
FilterXObject *result = filterx_expr_eval(self->rhs);
if (!result)
return NULL;

Expand All @@ -126,9 +160,21 @@ _eval_or(FilterXExpr *s)
FilterXExpr *
filterx_binary_or_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
if (_literal_expr_truthy(lhs))
return filterx_literal_new(filterx_boolean_new(TRUE));

if (filterx_expr_is_literal(rhs))
return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs)));
}

FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1);

filterx_binary_op_init_instance(self, lhs, rhs);
if (filterx_expr_is_literal(lhs))
self->lhs = NULL;

self->super.eval = _eval_or;
return &self->super;
}
45 changes: 40 additions & 5 deletions lib/filterx/expr-comparison.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "filterx/object-message-value.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "filterx/expr-literal.h"
#include "object-primitive.h"
#include "generic-number.h"
#include "parse-number.h"
Expand All @@ -42,6 +43,8 @@ typedef struct _FilterXComparison
{
FilterXBinaryOp super;
gint operator;
FilterXObject *literal_lhs;
FilterXObject *literal_rhs;
} FilterXComparison;

static void
Expand Down Expand Up @@ -187,22 +190,28 @@ _evaluate_type_and_value_based(FilterXObject *lhs, FilterXObject *rhs, gint oper
return _evaluate_type_aware(lhs, rhs, operator);
}

static inline FilterXObject *
_eval_based_on_compare_mode(FilterXExpr *expr, gint compare_mode)
{
gboolean typed_eval_needed = compare_mode & FCMPX_TYPE_AWARE || compare_mode & FCMPX_TYPE_AND_VALUE_BASED;
return typed_eval_needed ? filterx_expr_eval_typed(expr) : filterx_expr_eval(expr);
}

static FilterXObject *
_eval(FilterXExpr *s)
{
FilterXComparison *self = (FilterXComparison *) s;

gint compare_mode = self->operator & FCMPX_MODE_MASK;
gint operator = self->operator & FCMPX_OP_MASK;
gboolean typed_eval_needed = compare_mode & FCMPX_TYPE_AWARE || compare_mode & FCMPX_TYPE_AND_VALUE_BASED;

FilterXObject *lhs_object = typed_eval_needed ? filterx_expr_eval_typed(self->super.lhs) : filterx_expr_eval(
self->super.lhs);
FilterXObject *lhs_object = self->literal_lhs ? filterx_object_ref(self->literal_lhs)
: _eval_based_on_compare_mode(self->super.lhs, compare_mode);
if (!lhs_object)
return NULL;

FilterXObject *rhs_object = typed_eval_needed ? filterx_expr_eval_typed(self->super.rhs) : filterx_expr_eval(
self->super.rhs);
FilterXObject *rhs_object = self->literal_rhs ? filterx_object_ref(self->literal_rhs)
: _eval_based_on_compare_mode(self->super.rhs, compare_mode);
if (!rhs_object)
{
filterx_object_unref(lhs_object);
Expand All @@ -228,6 +237,16 @@ _eval(FilterXExpr *s)
return filterx_boolean_new(result);
}

static void
_filterx_comparison_free(FilterXExpr *s)
{
FilterXComparison *self = (FilterXComparison *) s;
filterx_object_unref(self->literal_lhs);
filterx_object_unref(self->literal_rhs);

filterx_binary_op_free_method(s);
}

/* NOTE: takes the object reference */
FilterXExpr *
filterx_comparison_new(FilterXExpr *lhs, FilterXExpr *rhs, gint operator)
Expand All @@ -236,6 +255,22 @@ filterx_comparison_new(FilterXExpr *lhs, FilterXExpr *rhs, gint operator)

filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
self->super.super.free_fn = _filterx_comparison_free;
self->operator = operator;

gint compare_mode = self->operator & FCMPX_MODE_MASK;
if (filterx_expr_is_literal(lhs))
self->literal_lhs = _eval_based_on_compare_mode(lhs, compare_mode);

if (filterx_expr_is_literal(rhs))
self->literal_rhs = _eval_based_on_compare_mode(rhs, compare_mode);

if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs))
{
FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super));
filterx_expr_unref(&self->super.super);
return optimized;
}

return &self->super.super;
}
35 changes: 35 additions & 0 deletions lib/filterx/expr-condition.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

#include "filterx/expr-condition.h"
#include "filterx/expr-literal.h"
#include "filterx/object-primitive.h"
#include "scratch-buffers.h"

Expand Down Expand Up @@ -182,3 +183,37 @@ filterx_conditional_find_tail(FilterXExpr *s)
}
return s;
}

FilterXExpr *
filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch)
{
g_assert(filterx_expr_is_literal(condition));

FilterXObject *condition_value = filterx_expr_eval(condition);
g_assert(condition_value);

FilterXExpr *optimized = NULL;

if (filterx_object_truthy(condition_value))
{
if (true_branch)
optimized = true_branch;
else
optimized = filterx_expr_ref(condition);

filterx_expr_unref(false_branch);
}
else
{
if (false_branch)
optimized = false_branch;
else
optimized = filterx_literal_new(filterx_boolean_new(TRUE));

filterx_expr_unref(true_branch);
}

filterx_object_unref(condition_value);
filterx_expr_unref(condition);
return optimized;
}
2 changes: 2 additions & 0 deletions lib/filterx/expr-condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ void filterx_conditional_set_false_branch(FilterXExpr *s, FilterXExpr *false_bra
FilterXExpr *filterx_conditional_find_tail(FilterXExpr *s);
FilterXExpr *filterx_conditional_new(FilterXExpr *condition);

FilterXExpr *filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch);

#endif
14 changes: 14 additions & 0 deletions lib/filterx/expr-null-coalesce.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include "filterx/expr-null-coalesce.h"
#include "filterx/expr-literal.h"
#include "filterx/object-null.h"
#include "filterx/filterx-eval.h"
#include "filterx/object-message-value.h"
Expand Down Expand Up @@ -61,6 +62,19 @@ _eval(FilterXExpr *s)
FilterXExpr *
filterx_null_coalesce_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
FilterXObject *lhs_object = filterx_expr_eval(lhs);
if (!lhs_object || filterx_object_is_type(lhs_object, &FILTERX_TYPE_NAME(null)))
{
filterx_object_unref(lhs_object);
return rhs;
}

filterx_object_unref(lhs_object);
return lhs;
}

FilterXNullCoalesce *self = g_new0(FilterXNullCoalesce, 1);
filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
Expand Down
34 changes: 32 additions & 2 deletions lib/filterx/expr-plus.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,28 @@
#include "expr-plus.h"
#include "object-string.h"
#include "filterx-eval.h"
#include "filterx/expr-literal.h"
#include "scratch-buffers.h"

typedef struct FilterXOperatorPlus
{
FilterXBinaryOp super;
FilterXObject *literal_lhs;
FilterXObject *literal_rhs;
} FilterXOperatorPlus;

static FilterXObject *
_eval(FilterXExpr *s)
{
FilterXOperatorPlus *self = (FilterXOperatorPlus *) s;

FilterXObject *lhs_object = filterx_expr_eval_typed(self->super.lhs);
FilterXObject *lhs_object = self->literal_lhs ? filterx_object_ref(self->literal_lhs)
: filterx_expr_eval_typed(self->super.lhs);
if (!lhs_object)
return NULL;

FilterXObject *rhs_object = filterx_expr_eval(self->super.rhs);
FilterXObject *rhs_object = self->literal_rhs ? filterx_object_ref(self->literal_rhs)
: filterx_expr_eval(self->super.rhs);
if (!rhs_object)
{
filterx_object_unref(lhs_object);
Expand All @@ -52,11 +57,36 @@ _eval(FilterXExpr *s)
return res;
}

static void
_filterx_operator_plus_free(FilterXExpr *s)
{
FilterXOperatorPlus *self = (FilterXOperatorPlus *) s;
filterx_object_unref(self->literal_lhs);
filterx_object_unref(self->literal_rhs);

filterx_binary_op_free_method(s);
}

FilterXExpr *
filterx_operator_plus_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
FilterXOperatorPlus *self = g_new0(FilterXOperatorPlus, 1);
filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
self->super.super.free_fn = _filterx_operator_plus_free;

if (filterx_expr_is_literal(lhs))
self->literal_lhs = filterx_expr_eval_typed(lhs);

if (filterx_expr_is_literal(rhs))
self->literal_rhs = filterx_expr_eval(rhs);

if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs))
{
FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super));
filterx_expr_unref(&self->super.super);
return optimized;
}

return &self->super.super;
}
Loading

0 comments on commit b8f7853

Please sign in to comment.