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