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:
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