diff --git a/emitter.c b/emitter.c index 7bcae50..fba0d76 100644 --- a/emitter.c +++ b/emitter.c @@ -11,6 +11,7 @@ Emitter emitter_create(uint8_t* code_address) .pos = 0, .loop_counter = 0, .cmp_flags_set = false, + .rax_contains_copy = false, }; } @@ -52,6 +53,9 @@ void emitter_push_u64(Emitter* emitter, uint64_t value) emitter->pos += 1; } +inline bool is_8(int value) { return value >= -128 && value <= 127; } +inline bool is_16(int value) { return value >= -32768 && value <= 32767; } + void emitter_emit_expr(Emitter* emitter, Expr* expr) { emitter->cmp_flags_set = false; @@ -61,32 +65,48 @@ void emitter_emit_expr(Emitter* emitter, Expr* expr) exit(1); break; case ExprType_Incr: - // add BYTE [rbx], 1 + // add BYTE [rbx], emitter_push_u8(emitter, 0x80); emitter_push_u8(emitter, 0x03); - emitter_push_u8(emitter, expr->value); + emitter_push_u8(emitter, (uint8_t)expr->value); emitter->cmp_flags_set = true; break; case ExprType_Decr: - // sub BYTE [rbx], 1 + // sub BYTE [rbx], emitter_push_u8(emitter, 0x80); emitter_push_u8(emitter, 0x2b); - emitter_push_u8(emitter, expr->value); + emitter_push_u8(emitter, (uint8_t)expr->value); emitter->cmp_flags_set = true; break; case ExprType_Left: - // sub rbx, 1 - emitter_push_u8(emitter, 0x48); - emitter_push_u8(emitter, 0x83); - emitter_push_u8(emitter, 0xeb); - emitter_push_u8(emitter, expr->value); + if (is_8(expr->value)) { + // sub rbx, + emitter_push_u8(emitter, 0x48); + emitter_push_u8(emitter, 0x83); + emitter_push_u8(emitter, 0xeb); + emitter_push_u8(emitter, (uint8_t)expr->value); + } else { + // sub rbx, + emitter_push_u8(emitter, 0x48); + emitter_push_u8(emitter, 0x81); + emitter_push_u8(emitter, 0xeb); + emitter_push_u32(emitter, expr->value); + } break; case ExprType_Right: - // add rbx, 1 - emitter_push_u8(emitter, 0x48); - emitter_push_u8(emitter, 0x83); - emitter_push_u8(emitter, 0xc3); - emitter_push_u8(emitter, expr->value); + if (is_8(expr->value)) { + // add rbx, + emitter_push_u8(emitter, 0x48); + emitter_push_u8(emitter, 0x83); + emitter_push_u8(emitter, 0xc3); + emitter_push_u8(emitter, (uint8_t)expr->value); + } else { + // add rbx, + emitter_push_u8(emitter, 0x48); + emitter_push_u8(emitter, 0x81); + emitter_push_u8(emitter, 0xc3); + emitter_push_u32(emitter, expr->value); + } break; case ExprType_Output: // movzx edi, BYTE [rbx] @@ -124,6 +144,30 @@ void emitter_emit_expr(Emitter* emitter, Expr* expr) emitter_push_u8(emitter, 0x00); emitter->cmp_flags_set = true; break; + case ExprType_Add: + if (!emitter->rax_contains_copy) { + // movzx rax, BYTE [rbx] + emitter_push_u8(emitter, 0x48); + emitter_push_u8(emitter, 0x0f); + emitter_push_u8(emitter, 0xb6); + emitter_push_u8(emitter, 0x03); + emitter->rax_contains_copy = true; + } + if (is_8(expr->value)) { + // add BYTE [rbx + ], al + emitter_push_u8(emitter, 0x00); + emitter_push_u8(emitter, 0x43); + emitter_push_u8(emitter, (uint8_t)expr->value); + } else { + // add BYTE [rbx + ], al + emitter_push_u8(emitter, 0x00); + emitter_push_u8(emitter, 0x83); + emitter_push_u32(emitter, expr->value); + } + break; + } + if (expr->type != ExprType_Add) { + emitter->rax_contains_copy = false; } } diff --git a/emitter.h b/emitter.h index 72111dd..c3fd6bf 100644 --- a/emitter.h +++ b/emitter.h @@ -11,6 +11,7 @@ typedef struct { size_t pos; int loop_counter; bool cmp_flags_set; + bool rax_contains_copy; } Emitter; Emitter emitter_create(uint8_t* code_address); diff --git a/expr.c b/expr.c index 050d2d7..2e06f04 100644 --- a/expr.c +++ b/expr.c @@ -40,6 +40,24 @@ Expr expr_vec_pop(ExprVec* vec) return vec->data[vec->length]; } +void expr_vec_stringify(ExprVec* vec, char* acc, int depth) +{ + strcat(acc, color_bold); + strcat(acc, expr_bracket_color(depth)); + strcat(acc, "["); + strcat(acc, color_reset); + for (size_t i = 0; i < vec->length; ++i) { + if (i != 0) { + strcat(acc, " "); + } + expr_stringify(&vec->data[i], acc, depth + 1); + } + strcat(acc, color_bold); + strcat(acc, expr_bracket_color(depth)); + strcat(acc, "]"); + strcat(acc, color_reset); +} + bool expr_vec_equal(const ExprVec* self, const ExprVec* other) { if (self->length != other->length) { @@ -53,6 +71,16 @@ bool expr_vec_equal(const ExprVec* self, const ExprVec* other) return true; } +ExprVec expr_vec_clone(const ExprVec* original) +{ + ExprVec vec; + expr_vec_construct(&vec); + for (size_t i = 0; i < original->length; ++i) { + expr_vec_push(&vec, expr_clone(&original->data[i])); + } + return vec; +} + void expr_free(Expr* expr) { switch (expr->type) { @@ -92,24 +120,6 @@ void expr_stringify_concat_value(Expr* expr, char* acc, int depth) strcat(acc, color_reset); } -void expr_vec_stringify(ExprVec* vec, char* acc, int depth) -{ - strcat(acc, color_bold); - strcat(acc, expr_bracket_color(depth)); - strcat(acc, "["); - strcat(acc, color_reset); - for (size_t i = 0; i < vec->length; ++i) { - if (i != 0) { - strcat(acc, " "); - } - expr_stringify(&vec->data[i], acc, depth + 1); - } - strcat(acc, color_bold); - strcat(acc, expr_bracket_color(depth)); - strcat(acc, "]"); - strcat(acc, color_reset); -} - void expr_stringify(Expr* expr, char* acc, int depth) { switch (expr->type) { @@ -163,6 +173,12 @@ void expr_stringify(Expr* expr, char* acc, int depth) strcat(acc, "Zero"); strcat(acc, color_reset); break; + case ExprType_Add: + strcat(acc, color_cyan); + strcat(acc, "Add"); + strcat(acc, color_reset); + expr_stringify_concat_value(expr, acc, depth); + break; } } @@ -190,3 +206,15 @@ bool expr_equal(const Expr* self, const Expr* other) } return true; } + +Expr expr_clone(const Expr* expr) +{ + if (expr->type == ExprType_Loop) { + return (Expr) { + .type = ExprType_Loop, + .exprs = expr_vec_clone(&expr->exprs), + }; + } else { + return *expr; + } +} diff --git a/expr.h b/expr.h index 8b6c2ad..54536f5 100644 --- a/expr.h +++ b/expr.h @@ -14,6 +14,7 @@ typedef enum { ExprType_Input, ExprType_Loop, ExprType_Zero, + ExprType_Add, } ExprType; typedef struct Expr Expr; @@ -29,7 +30,9 @@ void expr_vec_destroy(ExprVec* vec); void expr_vec_free(ExprVec* vec); void expr_vec_push(ExprVec* vec, Expr expr); Expr expr_vec_pop(ExprVec* vec); +void expr_vec_stringify(ExprVec* vec, char* acc, int depth); bool expr_vec_equal(const ExprVec* self, const ExprVec* other); +ExprVec expr_vec_clone(const ExprVec* original); struct Expr { ExprType type; @@ -42,8 +45,9 @@ struct Expr { void expr_free(Expr* expr); const char* expr_bracket_color(int depth); void expr_stringify_concat_value(Expr* expr, char* acc, int depth); -void expr_vec_stringify(ExprVec* vec, char* acc, int depth); +void expr_stringify_concat_pair(Expr* expr, char* acc, int depth); void expr_stringify(Expr* expr, char* acc, int depth); bool expr_equal(const Expr* self, const Expr* other); +Expr expr_clone(const Expr* expr); #endif diff --git a/main.c b/main.c index aac86a8..ac033a1 100644 --- a/main.c +++ b/main.c @@ -10,13 +10,27 @@ #include #include +#define ADD_OPTIMIZATION_WO_FREE_AST(NAME) \ + previous_ast = ast; \ + ast = optimize_##NAME(&ast); \ + printf("%s" #NAME ":%s\n", color_bold, color_reset); \ + if (!expr_vec_equal(&ast, &previous_ast)) { \ + ast_string[0] = '\0'; \ + expr_vec_stringify(&ast, ast_string, 0); \ + puts(ast_string); \ + } + +#define ADD_OPTIMIZATION(NAME) \ + expr_vec_free(&previous_ast); \ + ADD_OPTIMIZATION_WO_FREE_AST(NAME) + int main(int argc, char** argv) { - const char* text = "++++++++++[>+<-]"; - printf("\ntext:%s\n\"%s\"%s\n", color_bright_green, text, color_reset); - Parser parser = parser_create(lexer_from_string(text, strlen(text))); + // const char* text = "++++++++++[>+<-]"; + // printf("\ntext:%s\n\"%s\"%s\n", color_bright_green, text, color_reset); + // Parser parser = parser_create(lexer_from_string(text, strlen(text))); - // Parser parser = parser_create(lexer_from_args_or_stdin(argc, argv)); + Parser parser = parser_create(lexer_from_args_or_stdin(argc, argv)); char* ast_string = malloc(sizeof(char) * 33768); ast_string[0] = '\0'; @@ -42,44 +56,11 @@ int main(int argc, char** argv) if (!first) { expr_vec_free(&previous_ast); } - previous_ast = ast; - ast = optimize_fold_adjecent(&ast); - printf("%sfold_adjecent:%s\n", color_bold, color_reset); - if (!expr_vec_equal(&ast, &previous_ast)) { - ast_string[0] = '\0'; - expr_vec_stringify(&ast, ast_string, 0); - puts(ast_string); - } - - expr_vec_free(&previous_ast); - previous_ast = ast; - ast = optimize_eliminate_negation(&ast); - printf("%seliminate_negation:%s\n", color_bold, color_reset); - if (!expr_vec_equal(&ast, &previous_ast)) { - ast_string[0] = '\0'; - expr_vec_stringify(&ast, ast_string, 0); - puts(ast_string); - } - - expr_vec_free(&previous_ast); - previous_ast = ast; - ast = optimize_eliminate_overflow(&ast); - printf("%seliminate_overflow:%s\n", color_bold, color_reset); - if (!expr_vec_equal(&ast, &previous_ast)) { - ast_string[0] = '\0'; - expr_vec_stringify(&ast, ast_string, 0); - puts(ast_string); - } - - expr_vec_free(&previous_ast); - previous_ast = ast; - ast = optimize_replace_zeroing_loops(&ast); - printf("%sreplace_zeroing_loops:%s\n", color_bold, color_reset); - if (!expr_vec_equal(&ast, &previous_ast)) { - ast_string[0] = '\0'; - expr_vec_stringify(&ast, ast_string, 0); - puts(ast_string); - } + ADD_OPTIMIZATION_WO_FREE_AST(fold_adjecent); + ADD_OPTIMIZATION(eliminate_negation); + ADD_OPTIMIZATION(eliminate_overflow); + ADD_OPTIMIZATION(replace_zeroing_loops); + ADD_OPTIMIZATION(replace_copying_loops); if (first) { first = false; @@ -112,12 +93,15 @@ int main(int argc, char** argv) printf("\n%scode:%s\n", color_bold, color_reset); - for (size_t y = 0; y < 8; ++y) { - for (size_t x = 0; x < 8; ++x) { + for (size_t y = 0; y < 40; ++y) { + for (size_t x = 0; x < 16; ++x) { uint8_t v = ((uint8_t*)code)[y * 8 + x]; if (v == 0) { fputs(color_gray, stdout); } + if (x == 8) { + fputc(' ', stdout); + } printf("%02x ", v); fputs(color_reset, stdout); } @@ -135,7 +119,7 @@ int main(int argc, char** argv) printf("\n%smemory:%s\n", color_bold, color_reset); - for (size_t y = 0; y < 8; ++y) { + for (size_t y = 0; y < 4; ++y) { for (size_t x = 0; x < 8; ++x) { uint8_t v = memory[y * 8 + x]; if (v == 0) { diff --git a/optimizer.c b/optimizer.c index d8e9804..3eb584e 100644 --- a/optimizer.c +++ b/optimizer.c @@ -4,9 +4,9 @@ /* * fold adjecent * - * A(N) :: { Incr(N) | Decr(N) | Right(N) | Left(N) } + * A(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) } * - * [A(N1) A(N2)] -> [A(N1 + N2)] + * [A(n1) A(n2)] -> [A(n1 + n2)] * */ @@ -49,20 +49,20 @@ Expr expr_optimize_fold_adjecent(const Expr* expr) .exprs = optimize_fold_adjecent(&expr->exprs), }; } else { - return *expr; + return expr_clone(expr); } } /* * eliminate negation * - * A(N), B(N) :: { Incr(N) | Decr(N) | Right(N) | Left(N) } + * A(n), B(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) } * - * [A(N) B(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)] + * [A(n1) B(n2)] ? n1 == n2 -> [] + * [A(n1) B(n2)] ? n1 < n2 -> [B(n2 - n1)] + * [A(n1) B(n2)] ? n1 > n2 -> [A(n1 - n2)] * */ @@ -140,18 +140,18 @@ Expr expr_optimize_eliminate_negation(const Expr* expr) .exprs = optimize_eliminate_negation(&expr->exprs), }; } else { - return *expr; + return expr_clone(expr); } } /* * eliminate overflow * - * A(N) :: { Incr(N) | Decr(N) | Right(N) | Left(N) } + * A(n) :: { Incr(n) | Decr(n) | Right(n) | Left(n) } * - * N > 255 + * n > 255 * - * A(N) -> A(N % 256) + * A(n) -> A(n % 256) * */ @@ -175,18 +175,18 @@ Expr expr_optimize_eliminate_overflow(const Expr* expr) } else if (expr->value > 255) { return (Expr) { .type = expr->type, .value = expr->value % 256 }; } else { - return *expr; + return expr_clone(expr); } } /* * replace zeroing loops * - * A(N) :: { Incr(N) | Decr(N) } + * A(n) :: { Incr(n) | Decr(n) } * - * N % 2 == 1 + * n % 2 == 1 * - * Loop[A(N)] -> Zero + * Loop[A(n)] -> Zero * */ @@ -217,6 +217,67 @@ Expr expr_optimize_replace_zeroing_loops(const Expr* expr) }; } } else { - return *expr; + 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; +} diff --git a/optimizer.h b/optimizer.h index 6ed7c65..f72ad66 100644 --- a/optimizer.h +++ b/optimizer.h @@ -15,4 +15,6 @@ Expr expr_optimize_eliminate_overflow(const Expr* expr); ExprVec optimize_replace_zeroing_loops(const ExprVec* vec); Expr expr_optimize_replace_zeroing_loops(const Expr* expr); +ExprVec optimize_replace_copying_loops(const ExprVec* vec); + #endif