harec

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

commit 770ed9ded1cc982eeeee7fd86146e2fe75f36afb
parent c52c5f48e8937a8270326fa4aba85247bdcba1d8
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 12 Jul 2021 01:17:03 +0200

gen: implement basic binarithm cases

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

Diffstat:
Minclude/gen.h | 2++
Msrc/gen.c | 39++++++++++++++++++++++++++++++++++++++-
Msrc/qinstr.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/901-primitives.ha | 13+++++++++++++
Mtests/configure | 3++-
5 files changed, 176 insertions(+), 2 deletions(-)

diff --git a/include/gen.h b/include/gen.h @@ -81,6 +81,8 @@ const struct gen_binding *binding_lookup(struct gen_context *ctx, enum qbe_instr alloc_for_align(size_t align); enum qbe_instr store_for_type(struct gen_context *ctx, const struct type *type); enum qbe_instr load_for_type(struct gen_context *ctx, const struct type *type); +enum qbe_instr binarithm_for_op(struct gen_context *ctx, + enum binarithm_operator op, const struct type *type); // qtype.c const struct qbe_type *qtype_lookup(struct gen_context *ctx, diff --git a/src/gen.c b/src/gen.c @@ -346,6 +346,42 @@ gen_expr_assign(struct gen_context *ctx, } static void +gen_expr_binarithm(struct gen_context *ctx, + const struct expression *expr, + const struct gen_temp *out) +{ + assert(expr->binarithm.op != BIN_LAND && expr->binarithm.op != BIN_LOR); // TODO + assert(!type_is_aggregate(expr->result)); // TODO + + const struct expression *lvexpr = expr->binarithm.lvalue; + const struct expression *rvexpr = expr->binarithm.rvalue; + + struct qbe_value lvalue, rvalue; + gen_qtemp(ctx, &lvalue, + qtype_lookup(ctx, lvexpr->result, false), "lvalue.%d"); + gen_qtemp(ctx, &rvalue, + qtype_lookup(ctx, rvexpr->result, false), "rvalue.%d"); + + struct gen_temp lvg = { + .name = lvalue.name, + .type = lvexpr->result, + .indirect = false, + }, rvg = { + .name = rvalue.name, + .type = rvexpr->result, + .indirect = false, + }; + gen_expr(ctx, lvexpr, &lvg); + gen_expr(ctx, rvexpr, &rvg); + + enum qbe_instr instr = binarithm_for_op( + ctx, expr->binarithm.op, lvexpr->result); + struct qbe_value qout; + qval_temp(ctx, &qout, out); + pushi(ctx->current, &qout, instr, &lvalue, &rvalue, NULL); +} + +static void gen_expr_binding(struct gen_context *ctx, const struct expression *expr, const struct gen_temp *out) @@ -643,7 +679,8 @@ gen_expr(struct gen_context *ctx, gen_expr_assign(ctx, expr, out); break; case EXPR_BINARITHM: - assert(0); // TODO + gen_expr_binarithm(ctx, expr, out); + break; case EXPR_BINDING: gen_expr_binding(ctx, expr, out); break; diff --git a/src/qinstr.c b/src/qinstr.c @@ -152,3 +152,124 @@ load_for_type(struct gen_context *ctx, const struct type *type) } abort(); // Unreachable } + +enum qbe_instr +binarithm_for_op(struct gen_context *ctx, + enum binarithm_operator op, + const struct type *type) +{ + // TODO: NaN, udiv et al + bool is_signed = type_is_signed(type); + enum qbe_stype stype = qtype_lookup(ctx, type, false)->stype; + assert(stype != Q__AGGREGATE && stype != Q__VOID); + switch (op) { + case BIN_PLUS: + return Q_ADD; + case BIN_BAND: + return Q_AND; + case BIN_DIV: + return is_signed ? Q_DIV : Q_UDIV; + case BIN_MINUS: + return Q_SUB; + case BIN_TIMES: + return Q_MUL; + case BIN_MODULO: + return is_signed ? Q_REM : Q_UREM; + case BIN_BOR: + return Q_OR; + case BIN_BXOR: + return Q_XOR; + case BIN_LSHIFT: + return Q_SHL; + case BIN_RSHIFT: + return is_signed ? Q_SAR : Q_SHR; + case BIN_LEQUAL: + switch (stype) { + case Q_WORD: + return Q_CEQW; + case Q_LONG: + return Q_CEQL; + case Q_SINGLE: + return Q_CEQS; + case Q_DOUBLE: + return Q_CEQD; + default: + assert(0); + } + break; + case BIN_NEQUAL: + case BIN_LXOR: + switch (stype) { + case Q_WORD: + return Q_CNEW; + case Q_LONG: + return Q_CNEL; + case Q_SINGLE: + return Q_CNES; + case Q_DOUBLE: + return Q_CNED; + default: + assert(0); + } + break; + case BIN_GREATER: + switch (stype) { + case Q_WORD: + return is_signed ? Q_CSGTW : Q_CUGTW; + case Q_LONG: + return is_signed ? Q_CSGTL : Q_CUGTL; + case Q_SINGLE: + return Q_CGTS; + case Q_DOUBLE: + return Q_CGTD; + default: + assert(0); + } + case BIN_GREATEREQ: + switch (stype) { + case Q_WORD: + return is_signed ? Q_CSGEW : Q_CUGEW; + case Q_LONG: + return is_signed ? Q_CSGEL : Q_CUGEL; + case Q_SINGLE: + return Q_CGES; + case Q_DOUBLE: + return Q_CGED; + default: + assert(0); + } + break; + case BIN_LESS: + switch (stype) { + case Q_WORD: + return is_signed ? Q_CSLTW : Q_CULTW; + case Q_LONG: + return is_signed ? Q_CSLTL : Q_CULTL; + case Q_SINGLE: + return Q_CLTS; + case Q_DOUBLE: + return Q_CLTD; + default: + assert(0); + } + break; + case BIN_LESSEQ: + switch (stype) { + case Q_WORD: + return is_signed ? Q_CSLEW : Q_CULEW; + case Q_LONG: + return is_signed ? Q_CSLEL : Q_CULEL; + case Q_SINGLE: + return Q_CLES; + case Q_DOUBLE: + return Q_CLED; + default: + assert(0); + } + break; + case BIN_LAND: + case BIN_LOR: + assert(0); // Handled elsewhere to address short circuiting + } + assert(0); // Unreachable +} diff --git a/tests/901-primitives.ha b/tests/901-primitives.ha @@ -0,0 +1,13 @@ +export fn main() int = { + let a: int = 10; + assert(a == 10); + a = 20; + assert(a == 20); + + let a: u8 = 5u8; + assert(a == 5u8); + a = 10u8; + assert(a == 10u8); + + return 0; +}; diff --git a/tests/configure b/tests/configure @@ -4,7 +4,8 @@ all="$all tests" tests() { # Temporary test suite for t in \ - 900-basics + 900-basics \ + 901-primitives do cat <<EOF tests/$t: tests/$t.ha