diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f08c8f..8f9d9de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=undefined -rdynamic") include_directories(.) include_directories(lexer) +include_directories(optimize) include_directories(parser) include_directories(quads) include_directories(target_x86) @@ -40,6 +41,8 @@ include_directories(${GENERATED}) add_executable(dcc ${BISON_dcc_parser_OUTPUTS} ${FLEX_dcc_lexer_OUTPUTS} + optimize/opt_flatten_adjacent_mov.c + optimize/optimization.c parser/ast.c parser/ast_print.c parser/symtab.c diff --git a/main.c b/main.c index cb77ace..da63094 100644 --- a/main.c +++ b/main.c @@ -9,11 +9,12 @@ #include #include "asmgen.h" +#include "optimization.h" #include "parser.tab.h" #include "quads.h" #include "util.h" -#define DCC_VERSION "0.2.0" +#define DCC_VERSION "0.2.0_opt" #define DCC_ARCHITECTURE "x86_32" #define BRED "\033[1;31m" @@ -32,11 +33,15 @@ FILE* tmp; static struct opt { bool debug; bool asm_out; + bool optimize; const char* out_file; const char* in_file; } opt = { + .debug = false, .asm_out = false, + .optimize = false, .out_file = NULL, + .in_file = NULL }; static void print_usage_additional() { @@ -61,6 +66,7 @@ static void print_usage() { "\n -h show extended usage" "\n -o output_file specify output file" "\n -S output assembly only" + "\n -O enable optimization." "\n -v debug mode:" "\n -v: enable INFO messages" "\n -vv: enable VERBOSE messages" @@ -74,7 +80,7 @@ static void print_usage() { static void get_options(int argc, char** argv) { int a; opterr = 0; - while ((a = getopt(argc, argv, "hvVSo:")) != -1) { + while ((a = getopt(argc, argv, "hvVSOo:")) != -1) { switch (a) { case 'h': print_usage(); @@ -93,6 +99,9 @@ static void get_options(int argc, char** argv) { case 'S': opt.asm_out = true; break; + case 'O': + opt.optimize = true; + break; case 'o': opt.out_file = optarg; break; @@ -207,6 +216,10 @@ int main(int argc, char** argv) { fclose(tmp); } -void parse_done_cb(const BBL* root) { +void parse_done_cb(BBL* root) { + if (opt.optimize) { + // optimization passes + dcc_optimize(root); + } asmgen(root, tmp); } diff --git a/main.h b/main.h index f83524b..4829e16 100644 --- a/main.h +++ b/main.h @@ -1,6 +1,6 @@ #ifndef MAIN_H #define MAIN_H -void parse_done_cb(const BBL* root); +void parse_done_cb(BBL* root); #endif diff --git a/optimize/opt_flatten_adjacent_mov.c b/optimize/opt_flatten_adjacent_mov.c new file mode 100644 index 0000000..0612f3f --- /dev/null +++ b/optimize/opt_flatten_adjacent_mov.c @@ -0,0 +1,78 @@ +#include "opt_flatten_adjacent_mov.h" + +#include + +#include "quads.h" +#include "quads_cf.h" + +unsigned total_replaced = 0; + +void try_replace_temp(astn* n, struct astn_qtemp* del, struct astn_qtemp* replace) { + if (n && n->type == ASTN_QTEMP && n->Qtemp.tempno == del->tempno) + n->Qtemp = *replace; + + total_replaced++; +} + +void opt_flatten_adjacent_mov(BBL* root, unsigned passes) { + BBL* head = root; + unsigned hits = 0; + for (unsigned pass = 1; pass <= passes; pass++) { + // fprintf(stderr, "Pass %d/%d running...\n", pass, passes); + unsigned this_hits = 0, quads_visited = 0; + BBL* bbl = head; + if (head == &bb_root) bbl = bbl_next(bbl); + + while (bbl) { + BB* b = bbl_data(bbl); + bbl = bbl_next(bbl); + quad *q = b->start; + + while (q && q->next && q->next->next) { + quads_visited++; + quad *n = q->next; + quad *nn = n->next; + if ((q->op == Q_MOV && n->op == Q_MOV) && + (q->target->type == ASTN_SYMPTR && q->src1->type == ASTN_QTEMP) && + (n->target->type == ASTN_QTEMP && n->src1->type == ASTN_SYMPTR) && + (q->target->Symptr.e == n->src1->Symptr.e)) { + this_hits++; + // we found the pattern. + // now we will remove the second quad entirely + // and replace all references to its target with the parent's source. + struct astn_qtemp* del = &n->target->Qtemp; + struct astn_qtemp* replace = &q->src1->Qtemp; + //fprintf(stderr, "del is %u, replace is %u\n", del->tempno, replace->tempno); + + q->next = nn; + free(n); // todo: potentially still leaky? + + while (nn) { + try_replace_temp(nn->target, del, replace); + try_replace_temp(nn->src1, del, replace); + try_replace_temp(nn->src2, del, replace); + nn = nn->next; + } + } + q = q->next; + } + } + hits += this_hits; + // fprintf(stderr, "--> Quads visited: %d | hits for this pass: %d, all passes: %d\n", quads_visited, this_hits, hits); + } + BBL* bbl = head; + if (head == &bb_root) bbl = bbl_next(bbl); + + + unsigned remaining_quads = 0; + while (bbl) { + BB* b = bbl_data(bbl); + bbl = bbl_next(bbl); + quad *q = b->start; + while (q) { + q = q->next; + remaining_quads++; + } + } + // fprintf(stderr, "Remaining quads after optimization: %d\n", remaining_quads); +} diff --git a/optimize/opt_flatten_adjacent_mov.h b/optimize/opt_flatten_adjacent_mov.h new file mode 100644 index 0000000..cf8a345 --- /dev/null +++ b/optimize/opt_flatten_adjacent_mov.h @@ -0,0 +1,8 @@ +#ifndef OPT_FLATTEN_ADJACENT_MOV_H +#define OPT_FLATTEN_ADJACENT_MOV_H + +#include "quads_cf.h" + +void opt_flatten_adjacent_mov(BBL* root, unsigned passes); + +#endif diff --git a/optimize/optimization.c b/optimize/optimization.c new file mode 100644 index 0000000..fda241e --- /dev/null +++ b/optimize/optimization.c @@ -0,0 +1,7 @@ +#include "optimization.h" + +#include "opt_flatten_adjacent_mov.h" + +void dcc_optimize(BBL* head) { + opt_flatten_adjacent_mov(head, 1); +} diff --git a/optimize/optimization.h b/optimize/optimization.h new file mode 100644 index 0000000..f00b0db --- /dev/null +++ b/optimize/optimization.h @@ -0,0 +1,8 @@ +#ifndef OPTIMIZATION_H +#define OPTIMIZATION_H + +#include "quads_cf.h" + +void dcc_optimize(BBL* head); + +#endif diff --git a/target_x86/asmgen.c b/target_x86/asmgen.c index f1f616b..a2d3408 100644 --- a/target_x86/asmgen.c +++ b/target_x86/asmgen.c @@ -9,6 +9,8 @@ #include "types.h" #include "util.h" +#include "opt_flatten_adjacent_mov.h" + #include FILE* out; @@ -239,7 +241,7 @@ void e_cbr(const char *op, quad* q) { void e_bba(const astn *n) { e_bb(n->Qbbno.bb); } void e_bb(const BB* b) { fprintf(out, "BB.%s.%d", b->fn, b->bbno); } -void asmgen(const BBL* head, FILE* f) { +void asmgen(BBL* head, FILE* f) { // init output file out = f; fprintf(out, "# ASM OUTPUT\n# compiled poorly :)\n\n"); diff --git a/target_x86/asmgen.h b/target_x86/asmgen.h index 64309e9..6d6a90a 100644 --- a/target_x86/asmgen.h +++ b/target_x86/asmgen.h @@ -22,6 +22,6 @@ typedef struct adir { void e_cbr(const char *op, quad* q); void e_bba(const astn *n); void e_bb(const BB* b); -void asmgen(const BBL* bbl, FILE* out); +void asmgen(BBL* bbl, FILE* out); #endif