basic constant folding
authorcassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 19:03:17 +0000 (12:03 -0700)
committercassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 19:03:17 +0000 (12:03 -0700)
src/compile/emit.c
src/compile/ir.c
src/data/value.h

index 33225b0..8c460da 100644 (file)
@@ -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("<forward jump>\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 {
index 612e6e0..cdd9f88 100644 (file)
@@ -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);
index b6bc921..439e060 100644 (file)
@@ -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 })