commit 7fd0e10f6eedd57fbd089297678d72c2f050d29e
parent a4321b7134e3144f4ebf9169c3c0eaec27058f36
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 25 Dec 2020 14:15:48 -0500
Implement logical arithmetic
Diffstat:
5 files changed, 99 insertions(+), 16 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -40,6 +40,7 @@ bool type_is_aggregate(const struct type *type);
enum qbe_instr alloc_for_align(size_t align);
enum qbe_instr store_for_type(enum qbe_stype stype);
enum qbe_instr load_for_type(enum qbe_stype stype, bool is_signed);
-enum qbe_instr binarithm_for_op(enum binarithm_operator op);
+enum qbe_instr binarithm_for_op(enum binarithm_operator op,
+ const struct qbe_type *type, bool is_signed);
#endif
diff --git a/src/check.c b/src/check.c
@@ -133,10 +133,10 @@ check_expr_binarithm(struct context *ctx,
case BIN_LOR:
case BIN_LXOR:
case BIN_NEQUAL:
- expect(lvalue->result == &builtin_type_bool
- && rvalue->result == &builtin_type_bool,
- "Logical expressions must have boolean operands");
- assert(0); // TODO
+ // TODO: Promotion, comparibility rules
+ assert(lvalue->result->storage == rvalue->result->storage);
+ expr->result = &builtin_type_bool;
+ break;
}
}
diff --git a/src/gen.c b/src/gen.c
@@ -271,8 +271,6 @@ gen_binarithm(struct gen_context *ctx,
const struct qbe_type *etype = qtype_for_type(ctx, expr->result, false);
assert(etype == ltype && ltype == rtype); // TODO: Type promotion
- assert(expr->result != &builtin_type_bool); // TODO: Logical arithmetic
-
struct qbe_value lvalue = {0}, rvalue = {0}, result = {0};
gen_temp(ctx, &lvalue, ltype, "lvalue.%d");
gen_temp(ctx, &rvalue, rtype, "rvalue.%d");
@@ -281,8 +279,10 @@ gen_binarithm(struct gen_context *ctx,
gen_expression(ctx, expr->binarithm.lvalue, &lvalue);
gen_expression(ctx, expr->binarithm.rvalue, &rvalue);
- pushi(ctx->current, &result, binarithm_for_op(expr->binarithm.op),
- &lvalue, &rvalue, NULL);
+ pushi(ctx->current, &result,
+ binarithm_for_op(expr->binarithm.op, ltype,
+ type_is_signed(expr->binarithm.lvalue->result)),
+ &lvalue, &rvalue, NULL);
gen_store(ctx, out, &result);
}
diff --git a/src/parse.c b/src/parse.c
@@ -766,6 +766,8 @@ binop_for_token(enum lexical_token tok)
return BIN_LOR;
case T_LAND:
return BIN_LAND;
+ case T_LXOR:
+ return BIN_LXOR;
case T_BOR:
return BIN_BOR;
case T_BXOR:
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -65,9 +65,12 @@ load_for_type(enum qbe_stype stype, bool is_signed)
}
enum qbe_instr
-binarithm_for_op(enum binarithm_operator op)
+binarithm_for_op(enum binarithm_operator op,
+ const struct qbe_type *type, bool is_signed)
{
- // TODO: udiv et al
+ // TODO: NaN, udiv et al
+ enum qbe_stype stype = type->stype;
+ assert(stype != Q__AGGREGATE && stype != Q__VOID);
switch (op) {
case BIN_PLUS:
return Q_ADD;
@@ -89,16 +92,93 @@ binarithm_for_op(enum binarithm_operator op)
return Q_SHL;
case BIN_RSHIFT:
return 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:
- case BIN_LAND:
- case BIN_LEQUAL:
+ 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:
- case BIN_LXOR:
- case BIN_NEQUAL:
- assert(0); // Invariant
+ assert(0); // Handled elsewhere to address short circuiting
}
assert(0); // Unreachable
}