aboutsummaryrefslogtreecommitdiff
path: root/src/optimizer.c
diff options
context:
space:
mode:
authorElis Eriksson <spelis@spelis.li>2026-06-20 20:12:29 +0200
committerElis Eriksson <spelis@spelis.li>2026-06-20 20:12:29 +0200
commit38942c34a497a4c6edf080dc64440c1bc486fc46 (patch)
tree8fd3c891dff03f649b21aeb02c594e3e50f3160c /src/optimizer.c
parentde91ec0542aea5959376ee0d2c9d486268dd9392 (diff)
downloadbfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar.gz
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar.bz2
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar.lz
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar.xz
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.tar.zst
bfc-38942c34a497a4c6edf080dc64440c1bc486fc46.zip
Pattern matching optimizer and more
it's not the best optimizer but it works. Also added a -ast_dump flag which dumps the AST to stderr. Also input is now done in raw mode just because it can be.
Diffstat (limited to 'src/optimizer.c')
-rw-r--r--src/optimizer.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/optimizer.c b/src/optimizer.c
new file mode 100644
index 0000000..18a88c5
--- /dev/null
+++ b/src/optimizer.c
@@ -0,0 +1,134 @@
+#include "all.h"
+#include <stdbool.h>
+#include <stddef.h>
+
+static void mark_changed(bool *ch) { *ch = true; }
+
+static bool is_arith(ast_type_e t) { return t == AST_INC || t == AST_DEC; }
+
+static bool is_ptr(ast_type_e t) {
+ return t == AST_PTR_INC || t == AST_PTR_DEC;
+}
+
+static int node_signed_value(const ast_node_t *n) {
+ if (n->type == AST_DEC || n->type == AST_PTR_DEC)
+ return -n->val;
+ return n->val;
+}
+
+static void set_arith_node(ast_node_t *n, int v) {
+ if (v > 0) {
+ n->type = AST_INC;
+ n->val = v;
+ } else {
+ n->type = AST_DEC;
+ n->val = -v;
+ }
+}
+
+static void set_ptr_node(ast_node_t *n, int v) {
+ if (v > 0) {
+ n->type = AST_PTR_INC;
+ n->val = v;
+ } else {
+ n->type = AST_PTR_DEC;
+ n->val = -v;
+ }
+}
+
+static void optimize_list(ast_node_t **head, bool *ch);
+
+static void optimize_loop_node(ast_node_t *n, bool *ch) {
+ if (!n || n->type != AST_LOOP)
+ return;
+
+ if (n->children.len == 0 || n->children._data[0] == NULL) {
+ n->children.len = 0;
+ return;
+ }
+
+ optimize_list(&n->children._data[0], ch);
+
+ if (n->children._data[0] == NULL) {
+ n->children.len = 0;
+ return;
+ }
+
+ if (n->children.len == 1) {
+ ast_node_t *c = n->children._data[0];
+
+ if ((c->type == AST_INC || c->type == AST_DEC) && c->val == 1) {
+ n->type = AST_CLEAR;
+ n->val = 0;
+ n->children.len = 0;
+ n->children._data[0] = NULL;
+ mark_changed(ch);
+ }
+ }
+}
+
+static void optimize_list(ast_node_t **head, bool *ch) {
+ ast_node_t **p = head;
+
+ while (*p) {
+ ast_node_t *n = *p;
+
+ if (n->type == AST_LOOP) {
+ optimize_loop_node(n, ch);
+
+ if (n->type == AST_LOOP && n->children.len == 0) {
+ *p = n->next;
+ mark_changed(ch);
+ continue;
+ }
+ }
+
+ if (*p && (*p)->next) {
+ ast_node_t *a = *p;
+ ast_node_t *b = a->next;
+
+ if (is_arith(a->type) && is_arith(b->type)) {
+ int v = node_signed_value(a) + node_signed_value(b);
+
+ if (v == 0) {
+ a->next = b->next;
+ mark_changed(ch);
+ continue;
+ }
+
+ set_arith_node(a, v);
+ a->next = b->next;
+ mark_changed(ch);
+ continue;
+ }
+
+ if (is_ptr(a->type) && is_ptr(b->type)) {
+ int v = node_signed_value(a) + node_signed_value(b);
+
+ if (v == 0) {
+ a->next = b->next;
+ mark_changed(ch);
+ continue;
+ }
+
+ set_ptr_node(a, v);
+ a->next = b->next;
+ mark_changed(ch);
+ continue;
+ }
+ }
+
+ p = &(*p)->next;
+ }
+}
+
+ast_node_t *optimize_ast(ast_node_t *ast) {
+ bool ch;
+
+ do {
+ ch = false;
+ optimize_list(&ast, &ch);
+ } while (ch);
+
+ return ast;
+}