harec

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

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:
Minclude/ast.h | 1+
Msrc/check.c | 19+++++++++++++++++--
Msrc/emit.c | 4++--
Msrc/gen.c | 50++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/parse.c | 22++++++++++++++++++++--
Msrc/types.c | 3++-
Mtests/00-constants.ha | 2+-
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; };