commit e9c08905bc4808d39f52e83b404dc90fd020782b
parent 4f5c228a41b0463bcb1c0934e887f044431526e9
Author: Eyal Sawady <ecs@d2evs.net>
Date: Sun, 14 Mar 2021 16:39:59 -0400
Initial pass on float support
Missing casts between floats and unsigned ints.
Diffstat:
7 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -199,6 +199,7 @@ struct ast_expression_constant {
union {
intmax_t ival;
uintmax_t uval;
+ double fval;
uint32_t rune;
bool bval;
struct {
diff --git a/src/check.c b/src/check.c
@@ -1180,7 +1180,7 @@ lower_constant(const struct type *type, struct expression *expr)
return tag;
}
if (type_is_float(type) && type_is_float(expr->result)) {
- assert(0); // TODO
+ return type;
}
if (!type_is_integer(type)) {
return NULL;
@@ -1260,6 +1260,20 @@ check_expr_constant(struct context *ctx,
expr->result = type;
}
+ if (expr->result && expr->result->storage == STORAGE_FCONST) {
+ if (hint == NULL) {
+ hint = builtin_type_for_storage(STORAGE_F64, false);
+ }
+ expr->constant.fval = aexpr->constant.fval;
+ const struct type *type = lower_constant(hint, expr);
+ if (!type) {
+ // TODO: This error message is awful
+ return error(aexpr->loc, expr, errors,
+ "Floating constant out of range");
+ }
+ expr->result = type;
+ }
+
switch (aexpr->constant.storage) {
case STORAGE_I8:
case STORAGE_I16:
@@ -1299,7 +1313,8 @@ check_expr_constant(struct context *ctx,
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_FCONST:
- assert(0); // TODO
+ expr->constant.fval = aexpr->constant.fval;
+ break;
case STORAGE_CHAR:
case STORAGE_ENUM:
case STORAGE_UINTPTR:
diff --git a/src/emit.c b/src/emit.c
@@ -94,10 +94,10 @@ emit_const(struct qbe_value *val, FILE *out)
fprintf(out, "%lu", val->lval);
break;
case Q_SINGLE:
- fprintf(out, "%f", val->sval);
+ fprintf(out, "s_%f", val->sval);
break;
case Q_DOUBLE:
- fprintf(out, "%f", val->dval);
+ fprintf(out, "d_%f", val->dval);
break;
case Q__VOID:
case Q__AGGREGATE:
diff --git a/src/gen.c b/src/gen.c
@@ -1379,6 +1379,21 @@ gen_expr_cast(struct gen_context *ctx,
} else if (from->storage == STORAGE_RUNE) {
assert(to->storage == STORAGE_U32);
op = Q_COPY;
+ } else if (type_is_float(from)) {
+ if (type_is_signed(to)) {
+ switch (qstype_for_type(from)) {
+ case Q_SINGLE:
+ op = Q_STOSI;
+ break;
+ case Q_DOUBLE:
+ op = Q_DTOSI;
+ break;
+ default:
+ assert(0);
+ }
+ } else {
+ assert(0); // TODO
+ }
} else {
assert(0); // Invariant
}
@@ -1386,7 +1401,36 @@ gen_expr_cast(struct gen_context *ctx,
break;
case STORAGE_F32:
case STORAGE_F64:
- assert(0); // TODO
+ if (type_is_float(from) && from->size == to->size) {
+ op = Q_COPY;
+ } else if (type_is_float(from) && to->size < from->size) {
+ assert(qstype_for_type(from) == Q_DOUBLE
+ && qstype_for_type(to) == Q_SINGLE);
+ op = Q_TRUNCD;
+ } else if (type_is_float(from) && to->size > from->size) {
+ assert(qstype_for_type(from) == Q_SINGLE
+ && qstype_for_type(to) == Q_DOUBLE);
+ op = Q_EXTS;
+ } else if (type_is_integer(from)) {
+ if (type_is_signed(from)) {
+ switch (qstype_for_type(from)) {
+ case Q_WORD:
+ op = Q_SWTOF;
+ break;
+ case Q_LONG:
+ op = Q_SLTOF;
+ break;
+ default:
+ assert(0);
+ }
+ } else {
+ assert(0); // TODO
+ }
+ } else {
+ assert(0); // Invariant
+ }
+ pushi(ctx->current, &result, op, &in, NULL);
+ break;
case STORAGE_ARRAY:
assert(from->storage == STORAGE_ARRAY);
pushi(ctx->current, &result, Q_COPY, &in, NULL);
@@ -2660,7 +2704,9 @@ gen_data_item(struct gen_context *ctx, struct expression *expr,
break;
case STORAGE_F32:
case STORAGE_F64:
- assert(0); // TODO
+ item->type = QD_VALUE;
+ constd(&item->value, constant->fval);
+ break;
case STORAGE_UINTPTR:
assert(0); // TODO: What are the semantics for this?
case STORAGE_POINTER:
diff --git a/src/parse.c b/src/parse.c
@@ -876,6 +876,11 @@ parse_constant(struct lexer *lexer)
case STORAGE_INT:
exp->constant.ival = (intmax_t)tok.ival;
break;
+ case STORAGE_F32:
+ case STORAGE_F64:
+ case STORAGE_FCONST:
+ exp->constant.fval = tok.fval;
+ break;
case STORAGE_RUNE:
exp->constant.rune = tok.rune;
break;
@@ -894,8 +899,21 @@ parse_constant(struct lexer *lexer)
}
unlex(lexer, &tok);
break;
- default:
- assert(0); // TODO
+ case STORAGE_BOOL:
+ case STORAGE_NULL:
+ case STORAGE_VOID:
+ assert(0); // Handled above
+ case STORAGE_ALIAS:
+ case STORAGE_ARRAY:
+ case STORAGE_ENUM:
+ case STORAGE_FUNCTION:
+ case STORAGE_POINTER:
+ case STORAGE_SLICE:
+ case STORAGE_STRUCT:
+ case STORAGE_TAGGED:
+ case STORAGE_TUPLE:
+ case STORAGE_UNION:
+ assert(0); // Handled in a different nonterminal
}
trleave(TR_PARSE, "%s", token_str(&tok));
diff --git a/src/types.c b/src/types.c
@@ -228,7 +228,8 @@ type_is_numeric(const struct type *type)
bool
type_is_float(const struct type *type)
{
- return type->storage == STORAGE_F32 || type->storage == STORAGE_F64;
+ return type->storage == STORAGE_F32 || type->storage == STORAGE_F64
+ || type->storage == STORAGE_FCONST;
}
bool
diff --git a/tests/00-constants.ha b/tests/00-constants.ha
@@ -7,5 +7,5 @@ export fn main() void = {
let r1 = 'x', r2 = '\x0A', r3 = '\u1234', r4 = '\0', r5 = '\a',
r6 = '\b', r7 = '\f', r8 = '\n', r9 = '\r', r10 = '\t',
r11 = '\v', r12 = '\\', r13 = '\'', r14 = '\"';
- // TODO: Floating constants
+ let f1 = 1.0, f2 = 1f32, f3 = 1.0e2, f4 = 1.0f64;
};