mirror of
https://github.com/SimonFJ20/bfjit
synced 2026-01-16 05:27:30 +01:00
284 lines
7.9 KiB
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;
|
|
}
|