harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 3f5a5cfe69e91da99680e965365f3f239d6df436
parent d0cf23e12a1f1727f0d81ab045439e658411456a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  5 Aug 2021 10:20:14 +0200

gen: basic implementation of casts

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Msrc/gen.c | 130++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Atests/907-casts.ha | 37+++++++++++++++++++++++++++++++++++++
Mtests/configure | 3++-
3 files changed, 168 insertions(+), 2 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -394,6 +394,134 @@ gen_expr_call(struct gen_context *ctx, const struct expression *expr) return rval; } +static struct gen_value +gen_expr_cast(struct gen_context *ctx, const struct expression *expr) +{ + assert(expr->cast.kind == C_CAST); // TODO + const struct type *to = expr->result, *from = expr->cast.value->result; + assert(type_dealias(to)->storage != STORAGE_TAGGED + && type_dealias(from)->storage != STORAGE_TAGGED); // TODO + + if (type_dealias(to)->storage == type_dealias(from)->storage + && to->size == from->size) { + return gen_expr(ctx, expr->cast.value); + } + + // Special cases + switch (type_dealias(to)->storage) { + case STORAGE_POINTER: + if (type_dealias(from)->storage == STORAGE_SLICE) { + assert(0); // TODO + } + break; + case STORAGE_VOID: + gen_expr(ctx, expr->cast.value); // Side-effects + return gv_void; + default: break; + } + + struct gen_value value = gen_expr(ctx, expr->cast.value); + struct qbe_value qvalue = mkqval(ctx, &value); + struct gen_value result = mktemp(ctx, expr->result, "cast.%d"); + struct qbe_value qresult = mkqval(ctx, &result); + + enum qbe_instr op; + bool is_signed = type_is_signed(from); + enum type_storage fstor = type_dealias(from)->storage, + tstor = type_dealias(to)->storage; + switch (tstor) { + case STORAGE_CHAR: + case STORAGE_ENUM: + case STORAGE_U8: + case STORAGE_I8: + case STORAGE_I16: + case STORAGE_U16: + case STORAGE_I32: + case STORAGE_U32: + case STORAGE_INT: + case STORAGE_UINT: + case STORAGE_I64: + case STORAGE_U64: + case STORAGE_UINTPTR: + case STORAGE_RUNE: + case STORAGE_SIZE: + if (type_is_integer(from) && to->size <= from->size) { + op = Q_COPY; + } else if (type_is_integer(from) && to->size > from->size) { + switch (from->size) { + case 4: op = is_signed ? Q_EXTSW : Q_EXTUW; break; + case 2: op = is_signed ? Q_EXTSH : Q_EXTUH; break; + case 1: op = is_signed ? Q_EXTSB : Q_EXTUB; break; + default: abort(); // Invariant + } + } else if (fstor == STORAGE_POINTER || fstor == STORAGE_NULL) { + assert(tstor == STORAGE_UINTPTR); + op = Q_COPY; + } else if (fstor == STORAGE_RUNE) { + assert(tstor == STORAGE_U32); + op = Q_COPY; + } else if (type_is_float(from)) { + if (type_is_signed(to)) { + switch (fstor) { + case STORAGE_F32: op = Q_STOSI; break; + case STORAGE_F64: op = Q_DTOSI; break; + default: abort(); // Invariant + } + } else { + assert(0); // TODO + } + } else { + abort(); // Invariant + } + pushi(ctx->current, &qresult, op, &qvalue, NULL); + break; + case STORAGE_F32: + case STORAGE_F64: + if (type_is_float(from) && from->size == to->size) { + op = Q_COPY; + } else if (type_is_float(from) && to->size < from->size) { + op = Q_TRUNCD; + } else if (type_is_float(from) && to->size > from->size) { + op = Q_EXTS; + } else if (type_is_integer(from)) { + if (type_is_signed(from)) { + switch (from->size) { + case 4: op = Q_SWTOF; break; + case 8: op = Q_SLTOF; break; + default: abort(); // Invariant + } + } else { + assert(0); // TODO + } + } else { + abort(); // Invariant + } + pushi(ctx->current, &qresult, op, &qvalue, NULL); + break; + case STORAGE_NULL: + case STORAGE_POINTER: + pushi(ctx->current, &qresult, Q_COPY, &qvalue, NULL); + break; + case STORAGE_ARRAY: + case STORAGE_SLICE: + assert(0); // TODO + case STORAGE_ALIAS: + case STORAGE_BOOL: + case STORAGE_FCONST: + case STORAGE_FUNCTION: + case STORAGE_ICONST: + case STORAGE_STRING: + case STORAGE_STRUCT: + case STORAGE_TAGGED: + case STORAGE_TUPLE: + case STORAGE_UNION: + case STORAGE_VOID: + abort(); // Invariant + } + + return result; +} + static void gen_const_array_at(struct gen_context *ctx, const struct expression *expr, struct gen_value out) @@ -694,7 +822,7 @@ gen_expr(struct gen_context *ctx, const struct expression *expr) case EXPR_CALL: return gen_expr_call(ctx, expr); case EXPR_CAST: - assert(0); // TODO + return gen_expr_cast(ctx, expr); case EXPR_CONSTANT: return gen_expr_const(ctx, expr); case EXPR_CONTINUE: diff --git a/tests/907-casts.ha b/tests/907-casts.ha @@ -0,0 +1,37 @@ +fn integers() void = { + let x: u8 = 42; + let y = x: int; + assert(y == 42); + + let x = 0xBEEF; + let y = x: u8; + assert(y == 0xEF); + + let x = -10i8; + let y = x: u8; + assert(y == 246); +}; + +fn floats() void = { + let x = 10; + let y = x: f32; + assert(y == 10f32); + + let x = 10; + let y = x: f64; + assert(y == 10f64); + + let x = 13.37f32; + let y = x: int; + assert(y == 13); + + let x = 13.37f64; + let y = x: int; + assert(y == 13); +}; + +export fn main() int = { + integers(); + floats(); + return 0; +}; diff --git a/tests/configure b/tests/configure @@ -10,7 +10,8 @@ tests() { 903-postfix \ 904-copy \ 905-assign \ - 906-if + 906-if \ + 907-casts do cat <<EOF tests/$t: harec tests/$t.ha tests/rt.o