From: cassowarii Date: Tue, 30 Jun 2026 19:03:17 +0000 (-0700) Subject: basic constant folding X-Git-Url: https://git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=cb45eb8239783023c49e198980fc2634be5cb96a;p=sarabande.git basic constant folding --- diff --git a/src/compile/emit.c b/src/compile/emit.c index 33225b0..8c460da 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -44,30 +44,30 @@ void emit_arg(sbVmCompiler *cm, i64 actual_number) { if (actual_number < 0) { number = actual_number + 65536; } - buf[1] = number >> 8; - buf[2] = number & 0xFF; + buf[1] = (number >> 8) & 0xFF; + buf[2] = (number >> 0) & 0xFF; sbVmCompiler_write_code(cm, buf, 3); } else if (-(1L << 31) < actual_number && actual_number < (1L << 31)) { buf[0] = BC_VLONG_NUM; if (actual_number < 0) { number = actual_number + (1LL << 32); } - buf[1] = (number >> 24) & 0xFF;; + buf[1] = (number >> 24) & 0xFF; buf[2] = (number >> 16) & 0xFF; - buf[3] = (number >> 8) & 0xFF; - buf[4] = number & 0xFF; + buf[3] = (number >> 8) & 0xFF; + buf[4] = (number >> 0) & 0xFF; sbVmCompiler_write_code(cm, buf, 5); } else { buf[0] = BC_VVLONG_NUM; number = (u64)actual_number; - buf[1] = (number >> 56) & 0xFF;; - buf[2] = (number >> 48) & 0xFF;; - buf[3] = (number >> 40) & 0xFF;; - buf[4] = (number >> 32) & 0xFF;; - buf[5] = (number >> 24) & 0xFF;; + buf[1] = (number >> 56) & 0xFF; + buf[2] = (number >> 48) & 0xFF; + buf[3] = (number >> 40) & 0xFF; + buf[4] = (number >> 32) & 0xFF; + buf[5] = (number >> 24) & 0xFF; buf[6] = (number >> 16) & 0xFF; - buf[7] = (number >> 8) & 0xFF; - buf[8] = number & 0xFF; + buf[7] = (number >> 8) & 0xFF; + buf[8] = (number >> 0) & 0xFF; sbVmCompiler_write_code(cm, buf, 9); } } @@ -146,7 +146,6 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) { if (stmt->jump.label->found_yet) { EARG(stmt->jump.label->block_position); } else { - debug("\n"); EMIT(BC_VLONG_NUM); /* we have to remember to come back and fill in the address later when we * know where this label is! */ @@ -220,7 +219,7 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) { EMIT(BC_LD_TRUE); } else if (expr->value.type == IT_BOOLEAN) { EMIT(BC_LD_FALSE); - } else if (expr->value.type == IT_INTEGER && expr->value.integer < (2 << 16)) { + } else if (expr->value.type == IT_INTEGER && expr->value.integer < (2 << 8)) { EMIT(BC_LD_IMM); EARG(expr->value.integer); } else { diff --git a/src/compile/ir.c b/src/compile/ir.c index 612e6e0..cdd9f88 100644 --- a/src/compile/ir.c +++ b/src/compile/ir.c @@ -62,6 +62,16 @@ void sbIrProgram_print(hIrProgram ir) { /* --- */ +static sbIrExpr SENTINEL_NIL_EXPR = { + .type = IR_E_VALUE, + .value = (hV) { .type = IT_NIL } +}; +static sbIrStmt SENTINEL_NO_STMT = {0}; +static sbIrVariable SENTINEL_NO_VAR = {0}; +static sbIrExpr *NIL_EXPR = &SENTINEL_NIL_EXPR; +static sbIrStmt *NO_STMT = &SENTINEL_NO_STMT; +static sbIrVariable *NO_VAR = &SENTINEL_NO_VAR; + static void vprogram_error(hIrProgram ir, const char *error, va_list args) { ir->error_count ++; fprintf(stderr, "error: "); @@ -139,17 +149,9 @@ static sbIrVariable *var_name(hIrChunk ck, const char *name, usize name_len) { /* TODO do a different thing here */ chunk_error(ck, "unknown variable name! '%s'\n", name); - return NULL; + return NO_VAR; } -static sbIrExpr SENTINEL_NIL_EXPR = { - .type = IR_E_VALUE, - .value = (hV) { .type = IT_NIL } -}; -static sbIrExpr *NIL_EXPR = &SENTINEL_NIL_EXPR; -static sbIrStmt SENTINEL_NO_STMT = {0}; -static sbIrStmt *NO_STMT = &SENTINEL_NO_STMT; - static sbIrLabel *new_label(hIrChunk ck) { sbIrLabel *l = sbArena_alloc(&ck->program->arena, sizeof(sbIrLabel)); ck->label_count ++; @@ -184,7 +186,43 @@ static sbIrExpr *expr_func(hIrChunk ck, sbIrChunk *func) { }); } +static flag int_constant_fold(sbAstOp op, hInteger left, hInteger right, hInteger *result) { + switch (op) { + case AST_OP_ADD: + *result = left + right; + break; + case AST_OP_SUB: + *result = left - right; + break; + case AST_OP_MUL: + *result = left * right; + break; + case AST_OP_FLDIV: + *result = left / right; + break; + case AST_OP_MOD: + *result = left % right; + break; + default: + return FALSE; + } + return TRUE; +} + static sbIrExpr *expr_op(hIrChunk ck, sbAstOp op, sbIrExpr *left, sbIrExpr *right) { + if (left->type == IR_E_VALUE && left->value.type == IT_INTEGER + && right->type == IR_E_VALUE && right->value.type == IT_INTEGER) { + /* Try constant folding */ + hInteger result; + flag folded = int_constant_fold(op, left->value.integer, right->value.integer, &result); + if (folded) { + return new_expr(ck, &(sbIrExpr) { + .type = IR_E_VALUE, + .value = HVINT(result), + }); + } + } + return new_expr(ck, &(sbIrExpr) { .type = IR_E_OP, .op.type = op, @@ -382,6 +420,10 @@ static void compile_ast_stmtseq(hIrChunk ck, sbAst seqast, flag implicit_return) compile_ast_stmt(ck, considering->seq.left, implicit_return && is_last_stmt); considering = considering->seq.right; + + if (ck->program->error_count > 0) { + return; + } } if (implicit_return) { @@ -678,7 +720,7 @@ static sbIrVariable *compile_ast_var(hIrChunk ck, sbAst node) { } else { /* TODO make errors not bad */ chunk_error(ck, "Only a variable name is permitted here. (got %d)\n", node->type); - return NULL; + return NO_VAR; } } @@ -710,6 +752,8 @@ static sbIrExpr *compile_ast_expr(hIrChunk ck, sbAst node) { return expr_op(ck, node->op.type, left, right); } else if (node->type == AST_VAL_INT) { return expr_value(ck, &HVINT(node->i)); + } else if (node->type == AST_VAL_STRING) { + return expr_value(ck, &HVSTR(node->str)); } else if (node->type == AST_NODE_NAME) { /* TODO: I don't want to use strlen. Can we remember the lengths of symbols? */ sbIrVariable *var = compile_ast_var(ck, node); diff --git a/src/data/value.h b/src/data/value.h index b6bc921..439e060 100644 --- a/src/data/value.h +++ b/src/data/value.h @@ -4,7 +4,7 @@ #include "common.h" #define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n }) -#define HVSTR(s) ((hV) { .type = IT_STRING, .string = OBJSL(s) }) +#define HVSTR(s) ((hV) { .type = IT_STRING, .string = s }) #define HVBOOL(b) ((hV) { .type = IT_BOOLEAN, .boolean = b }) #define HVFUNC(i) ((hV) { .type = IT_FUNCTION, .data = i }) #define HVNIL ((hV) { .type = IT_NIL })