aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/nasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/nasm.c')
-rw-r--r--src/codegen/nasm.c64
1 files changed, 62 insertions, 2 deletions
diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c
index 8bcdda3..198cb5c 100644
--- a/src/codegen/nasm.c
+++ b/src/codegen/nasm.c
@@ -14,6 +14,10 @@ static void emit_const_expr(struct Expr* expr, FILE* out)
case EXPR_PRIMARY:
fprintf(out, "%.*s", (int)expr->primary.token.length, expr->primary.token.start);
break;
+ case EXPR_UNARY:
+ fprintf(out, "%.*s", (int)expr->unary.op.length, expr->unary.op.start);
+ emit_const_expr(expr->unary.operand, out);
+ break;
case EXPR_BINARY:
emit_const_expr(expr->binary.left, out);
fprintf(out, " %.*s ", (int)expr->binary.op.length, expr->binary.op.start);
@@ -370,6 +374,14 @@ static bool fold_const(struct Program* program, struct Expr* expr, uint64_t* out
return fold_const(program, program->consts[i].value, out);
return false;
}
+ case EXPR_UNARY:
+ {
+ uint64_t value;
+ if (!fold_const(program, expr->unary.operand, &value))
+ return false;
+ *out = 0 - value;
+ return true;
+ }
case EXPR_BINARY:
{
uint64_t left;
@@ -470,6 +482,14 @@ static bool emit_operand(struct Emitter* emitter, struct Expr* expr)
fprintf(emitter->out, ".%.*s", (int)expr->member.member.length, expr->member.member.start);
return true;
}
+ case EXPR_UNARY:
+ {
+ uint64_t value;
+ if (!fold_const(emitter->program, expr, &value))
+ return false;
+ fprintf(emitter->out, "%lld", (long long)value);
+ return true;
+ }
case EXPR_BINARY:
case EXPR_DEREF:
return false;
@@ -536,10 +556,22 @@ static bool expr_supported(struct Emitter* emitter, struct Expr* expr)
case EXPR_MEMBER:
case EXPR_DEREF:
return true;
+ case EXPR_UNARY:
+ {
+ uint64_t value;
+ return fold_const(emitter->program, expr, &value);
+ }
case EXPR_BINARY:
if (expr->binary.right->kind != EXPR_PRIMARY &&
- expr->binary.right->kind != EXPR_MEMBER)
+ expr->binary.right->kind != EXPR_MEMBER &&
+ expr->binary.right->kind != EXPR_UNARY)
return false;
+ if (expr->binary.right->kind == EXPR_UNARY)
+ {
+ uint64_t value;
+ if (!fold_const(emitter->program, expr->binary.right, &value))
+ return false;
+ }
if (expr->binary.right->kind == EXPR_PRIMARY &&
is_buffer_name(emitter, expr->binary.right->primary.token))
return false;
@@ -549,10 +581,35 @@ static bool expr_supported(struct Emitter* emitter, struct Expr* expr)
return false;
}
-// dst = [address], zero-extending narrower loads into the full register
+// dst = [address], extending narrower loads into the full register. Unsigned
+// loads zero-extend (movzx / a 32-bit mov); signed loads sign-extend (movsx,
+// or movsxd for a dword).
static void emit_load(struct Emitter* emitter, const char* dst, struct DerefExpr* deref)
{
FILE* out = emitter->out;
+ if (deref->is_signed)
+ {
+ switch (deref->size)
+ {
+ case STORE_SIZE_BYTE:
+ fprintf(out, "\tmovsx %s, byte [", dst);
+ break;
+ case STORE_SIZE_WORD:
+ fprintf(out, "\tmovsx %s, word [", dst);
+ break;
+ case STORE_SIZE_DWORD:
+ fprintf(out, "\tmovsxd %s, dword [", dst);
+ break;
+ default:
+ fprintf(out, "\tmov %s, [", dst);
+ break;
+ }
+
+ emit_operand(emitter, deref->address);
+ fprintf(out, "]\n");
+ return;
+ }
+
switch (deref->size)
{
case STORE_SIZE_BYTE:
@@ -1073,6 +1130,9 @@ static void collect_floats_expr(struct FloatTable* floats, struct Expr* expr)
case EXPR_PRIMARY:
collect_float(floats, expr->primary.token);
break;
+ case EXPR_UNARY:
+ collect_floats_expr(floats, expr->unary.operand);
+ break;
case EXPR_BINARY:
collect_floats_expr(floats, expr->binary.left);
collect_floats_expr(floats, expr->binary.right);