bfjit/optimizer.c

284 lines
7.9 KiB
C

#include "optimizer.h"
#include "expr.h"
/*
* fold adjecent
*
* A(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) }
*
* [A(n1) A(n2)] -> [A(n1 + n2)]
*
*/
ExprVec optimize_fold_adjecent(const ExprVec* vec)
{
ExprVec exprs;
expr_vec_construct(&exprs);
if (vec->length == 0) {
return exprs;
}
Expr a = expr_optimize_fold_adjecent(&vec->data[0]);
for (size_t i = 1; i < vec->length; ++i) {
Expr b = expr_optimize_fold_adjecent(&vec->data[i]);
switch (a.type) {
case ExprType_Incr:
case ExprType_Decr:
case ExprType_Left:
case ExprType_Right:
if (a.type != b.type) {
expr_vec_push(&exprs, a);
a = b;
} else {
a.value += b.value;
}
break;
default:
expr_vec_push(&exprs, a);
a = b;
}
}
expr_vec_push(&exprs, a);
return exprs;
}
Expr expr_optimize_fold_adjecent(const Expr* expr)
{
if (expr->type == ExprType_Loop) {
return (Expr) {
.type = ExprType_Loop,
.exprs = optimize_fold_adjecent(&expr->exprs),
};
} else {
return expr_clone(expr);
}
}
/*
* eliminate negation
*
* A(n), B(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) }
*
* [A(n) B(n)] = []
*
* [A(n1) B(n2)] ? n1 == n2 -> []
* [A(n1) B(n2)] ? n1 < n2 -> [B(n2 - n1)]
* [A(n1) B(n2)] ? n1 > n2 -> [A(n1 - n2)]
*
*/
ExprVec optimize_eliminate_negation(const ExprVec* vec)
{
ExprVec exprs;
expr_vec_construct(&exprs);
if (vec->length == 0) {
return exprs;
}
expr_vec_push(&exprs, expr_optimize_eliminate_negation(&vec->data[0]));
for (size_t i = 1; i < vec->length; ++i) {
expr_vec_push(&exprs, expr_optimize_eliminate_negation(&vec->data[i]));
Expr* a = &exprs.data[i - 1];
Expr* b = &exprs.data[i];
if (a->type == ExprType_Incr && b->type == ExprType_Decr) {
if (a->value > b->value) {
a->value -= b->value;
expr_vec_pop(&exprs);
} else if (a->value < b->value) {
*a = (Expr) { .type = ExprType_Decr,
.value = b->value - a->value };
expr_vec_pop(&exprs);
} else {
expr_vec_pop(&exprs);
expr_vec_pop(&exprs);
}
} else if (a->type == ExprType_Decr && b->type == ExprType_Incr) {
if (a->value > b->value) {
a->value -= b->value;
expr_vec_pop(&exprs);
} else if (a->value < b->value) {
*a = (Expr) { .type = ExprType_Incr,
.value = b->value - a->value };
expr_vec_pop(&exprs);
} else {
expr_vec_pop(&exprs);
expr_vec_pop(&exprs);
}
}
if (a->type == ExprType_Left && b->type == ExprType_Right) {
if (a->value > b->value) {
a->value -= b->value;
expr_vec_pop(&exprs);
} else if (a->value < b->value) {
*a = (Expr) { .type = ExprType_Right,
.value = b->value - a->value };
expr_vec_pop(&exprs);
} else {
expr_vec_pop(&exprs);
expr_vec_pop(&exprs);
}
} else if (a->type == ExprType_Right && b->type == ExprType_Left) {
if (a->value > b->value) {
a->value -= b->value;
expr_vec_pop(&exprs);
} else if (a->value < b->value) {
*a = (Expr) { .type = ExprType_Left,
.value = b->value - a->value };
expr_vec_pop(&exprs);
} else {
expr_vec_pop(&exprs);
expr_vec_pop(&exprs);
}
}
}
return exprs;
}
Expr expr_optimize_eliminate_negation(const Expr* expr)
{
if (expr->type == ExprType_Loop) {
return (Expr) {
.type = ExprType_Loop,
.exprs = optimize_eliminate_negation(&expr->exprs),
};
} else {
return expr_clone(expr);
}
}
/*
* eliminate overflow
*
* A(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) }
*
* n > 255
*
* A(n) -> A(n % 256)
*
*/
ExprVec optimize_eliminate_overflow(const ExprVec* vec)
{
ExprVec exprs;
expr_vec_construct(&exprs);
for (size_t i = 0; i < vec->length; ++i) {
expr_vec_push(&exprs, expr_optimize_eliminate_overflow(&vec->data[i]));
}
return exprs;
}
Expr expr_optimize_eliminate_overflow(const Expr* expr)
{
if (expr->type == ExprType_Loop) {
return (Expr) {
.type = ExprType_Loop,
.exprs = optimize_eliminate_overflow(&expr->exprs),
};
} else if (expr->value > 255) {
return (Expr) { .type = expr->type, .value = expr->value % 256 };
} else {
return expr_clone(expr);
}
}
/*
* replace zeroing loops
*
* A(n) :: { Incr(n) | Decr(n) }
*
* n % 2 == 1
*
* Loop[A(n)] -> Zero
*
*/
ExprVec optimize_replace_zeroing_loops(const ExprVec* vec)
{
ExprVec exprs;
expr_vec_construct(&exprs);
for (size_t i = 0; i < vec->length; ++i) {
expr_vec_push(
&exprs, expr_optimize_replace_zeroing_loops(&vec->data[i])
);
}
return exprs;
}
Expr expr_optimize_replace_zeroing_loops(const Expr* expr)
{
if (expr->type == ExprType_Loop) {
if (expr->exprs.length == 1
&& (expr->exprs.data[0].type == ExprType_Incr
|| expr->exprs.data[0].type == ExprType_Decr)
&& expr->exprs.data[0].value % 2 != 0) {
return (Expr) { .type = ExprType_Zero };
} else {
return (Expr) {
.type = ExprType_Loop,
.exprs = optimize_replace_zeroing_loops(&expr->exprs),
};
}
} else {
return expr_clone(expr);
}
}
/*
* replace copying loops
*
* O(n), I(n) :: { Left(n) | Right(n) }
*
* O != I
*
* [Loop[O(n) Incr(1) I(n) Decr(1)]] -> [Copy(n) Zero]
*
*/
ExprVec optimize_replace_copying_loops(const ExprVec* original)
{
ExprVec result;
expr_vec_construct(&result);
for (size_t i = 0; i < original->length; ++i) {
const Expr* expr = &original->data[i];
if (expr->type == ExprType_Loop) {
const ExprVec* loop = &expr->exprs;
if (loop->length == 4
&& ((loop->data[0].type == ExprType_Left
&& loop->data[2].type == ExprType_Right)
|| (loop->data[0].type == ExprType_Right
&& loop->data[2].type == ExprType_Left))
&& loop->data[1].type == ExprType_Incr
&& loop->data[3].type == ExprType_Decr
&& loop->data[1].value == loop->data[3].value) {
if (loop->data[0].type == ExprType_Right) {
expr_vec_push(
&result,
(Expr) {
.type = ExprType_Add,
.value = loop->data[0].value,
}
);
} else {
expr_vec_push(
&result,
(Expr) {
.type = ExprType_Add,
.value = -loop->data[0].value,
}
);
}
expr_vec_push(&result, (Expr) { .type = ExprType_Zero });
} else {
expr_vec_push(
&result,
(Expr) {
.type = ExprType_Loop,
.exprs = optimize_replace_copying_loops(&expr->exprs),
}
);
}
} else {
expr_vec_push(&result, expr_clone(expr));
}
}
return result;
}