commit cfe2d815bea0dd47d0ebeae933d673f4bf16cd6d
parent 7297370069e8d96cc8a5b77bd53f8e7cd01bd0c2
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 15 Mar 2020 12:53:04 -0700
compiler: logical and/or improvements
- compatible_type() now adjusts items as needed
(so an iComp can become and iBool for param/assignment/etc)
- correctly flag missing parameters to function calls
- don't allow parse_operand() to find "nothing" and leave x
uninitialized
- testcase to illustrate short-circuit behaviour working
Diffstat:
3 files changed, 103 insertions(+), 6 deletions(-)
diff --git a/src/compiler.c b/src/compiler.c
@@ -370,6 +370,8 @@ void gen_ref_param(u32 n, Item val);
// call func, consumes parameters and func
void gen_call(Item func);
+void gen_bool_from_comp(Item x);
+
// generate a forward conditional branch
// consumes x which must be Bool or Cond
// returns address to fixup
@@ -561,9 +563,14 @@ bool same_type(Type a, Type b) {
}
// for assignments, etc
-bool compatible_type(Type dst, Type src) {
+bool compatible_type(Type dst, Type src, Item x) {
+ if (x->kind == iComp) {
+ // collapse comparisons into bools for storage
+ gen_bool_from_comp(x);
+ src = ctx.type_bool;
+ }
if (dst->kind == tInt32) {
- if (src->kind == tByte) {
+ if ((src->kind == tByte) || (src->kind == tBool)) {
return true;
}
}
@@ -1028,6 +1035,8 @@ void parse_operand(Item x) {
error("unknown identifier '%s'", str->text);
}
gen_item_from_obj(x, obj);
+ } else {
+ error("invalid expression");
}
next();
}
@@ -1065,12 +1074,15 @@ void parse_primary_expr(Item x) {
u32 n = 0;
Object param = x->type->first;
while (param != nil) {
+ if (ctx.tok == tCPAREN) {
+ error("too few parameters for %s()", x->type->obj->name->text);
+ }
if (n != 0) {
require(tCOMMA);
}
ItemRec y;
parse_expr(&y);
- if (!compatible_type(param->type, y.type)) {
+ if (!compatible_type(param->type, y.type, &y)) {
error("incompatible type for parameter '%s'\n", param->name->text);
}
if (param->type->kind == tArray) {
@@ -1221,7 +1233,7 @@ void parse_expr(Item x) {
ItemRec y;
// if y goto yup
- parse_rel_expr(&y);
+ parse_and_expr(&y);
gen_branch_cond(&y, true);
add_scope_fixup(outer);
}
@@ -1430,7 +1442,7 @@ void parse_return() {
x.type = ctx.type_void;
} else {
parse_expr(&x);
- if (!compatible_type(ctx.fn->type->base, x.type)) {
+ if (!compatible_type(ctx.fn->type->base, x.type, &x)) {
error("return types do not match");
}
require(tSEMI);
@@ -1593,6 +1605,9 @@ void parse_expr_statement() {
next();
ItemRec y;
parse_expr(&y);
+ if (!compatible_type(x.type, y.type, &x)) {
+ error("incompatible type in assignment");
+ }
gen_store(&y, &x);
} else if ((ctx.tok & tcMASK) == tcAEQOP) {
u32 op = ctx.tok - tADDEQ;
@@ -2169,6 +2184,25 @@ void gen_load_bool2(Item x) {
emit_opi(MOV, x->r, 0, !x->a);
}
+void gen_bool_from_comp(Item x) {
+ gen_trace("bool_from_cond", x, nil);
+ emit_op(SUB, x->a, x->a, x->b);
+ put_reg(x->b);
+ u32 l0_br_to_true = ctx.pc;
+ emit_bi(rel_op_to_cc(x->r), 0);
+ emit_opi(MOV, x->a, 0, 0);
+ u32 l1_br_to_done = ctx.pc;
+ emit_bi(AL, 0);
+ fixup_branch_fwd(l0_br_to_true);
+ emit_opi(MOV, x->a, 0, 1);
+ fixup_branch_fwd(l1_br_to_done);
+ x->kind = iReg;
+ x->type = ctx.type_bool;
+ x->r = x->a;
+ x->a = 0;
+ x->b = 0;
+}
+
u32 gen_branch_cond(Item x, bool sense) {
gen_trace_n("branch_cond", sense, x, nil);
u32 cc;
@@ -2389,6 +2423,7 @@ void gen_rel_op(u32 op, Item x, Item y) {
// fuse x and y items into the new Comparison Item x
x->kind = iComp;
+ x->type = ctx.type_bool;
x->a = x->r;
x->b = y->r;
x->r = op;
diff --git a/test/1031-logical-and-or.log b/test/1031-logical-and-or.log
@@ -8,6 +8,43 @@ D 00000106
D 00000207
D 00000208
D 00000109
+D 00000333
+D 00000666
+D 00000999
+D 00002200
+D 00000333
+D 00000666
+D 00000999
+D 00002201
+D 00000333
+D 00000666
+D 00000999
+D 00002202
+D 00000333
+D 00001103
+D 00000333
+D 00000666
+D 00000999
+D 00002204
+D 00000333
+D 00000666
+D 00000999
+D 00002205
+D 00000333
+D 00000666
+D 00001106
+D 00000333
+D 00000666
+D 00000999
+D 00002207
+D 00000333
+D 00000666
+D 00000999
+D 00002208
+D 00000333
+D 00000666
+D 00000999
+D 00001109
D 00000400
D 00000401
D 00000402
diff --git a/test/1031-logical-and-or.src b/test/1031-logical-and-or.src
@@ -1,4 +1,24 @@
+func is_three(n i32) bool {
+ _hexout_(0x333);
+ return n == 3;
+}
+func is_six(n i32) bool {
+ _hexout_(0x666);
+ return n == 6;
+}
+func is_nine(n i32) bool {
+ _hexout_(0x999);
+ return n == 9;
+}
+
+func or_test2(n i32) {
+ if (is_three(n) || is_six(n) || is_nine(n)) {
+ _hexout_(n | 0x1100);
+ } else {
+ _hexout_(n | 0x2200);
+ }
+}
func or_test(n i32) {
if (n == 3 || n == 6 || n == 9) {
@@ -7,7 +27,6 @@ func or_test(n i32) {
_hexout_(n | 0x200);
}
}
-
func and_test(n i32) {
if ((n & 1 == 1) && (n & 2 == 2) && (n < 8)) {
_hexout_(n | 0x300);
@@ -23,9 +42,15 @@ func start() i32 {
n = n + 1;
}
n = 0;
+ while n < 10 {
+ or_test2(n);
+ n = n + 1;
+ }
+ n = 0;
while n < 16 {
and_test(n);
n = n + 1;
}
return 0x42;
}
+