commit 7297370069e8d96cc8a5b77bd53f8e7cd01bd0c2
parent 435e53aa0c52fb02d5158f63be5f20a14f5cb746
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 15 Mar 2020 10:10:51 -0700
compiler: support logical and/or operations
- these correctly shortcut
- add test cases
Diffstat:
3 files changed, 127 insertions(+), 10 deletions(-)
diff --git a/src/compiler.c b/src/compiler.c
@@ -375,6 +375,11 @@ void gen_call(Item func);
// returns address to fixup
u32 gen_branch_cond(Item x, bool sense);
+// used by && and || on opposing code flows
+// bool1 version loads val, bool2 version loads !val
+void gen_load_bool1(Item x, bool val);
+void gen_load_bool2(Item x);
+
// generate a backward branch to addr
void gen_branch_back(u32 addr);
@@ -1173,21 +1178,63 @@ void parse_rel_expr(Item x) {
void parse_and_expr(Item x) {
parse_rel_expr(x);
- while (ctx.tok == tAND) {
- next();
- ItemRec y;
- parse_rel_expr(&y);
- error("<TODO> and op");
+ if (ctx.tok == tAND) {
+ Scope outer = push_scope(sBlock, nil);
+
+ // if !x goto nope
+ gen_branch_cond(x, false);
+ add_scope_fixup(outer);
+
+ while (ctx.tok == tAND) {
+ next();
+ ItemRec y;
+
+ // if !y goto nope
+ parse_rel_expr(&y);
+ gen_branch_cond(&y, false);
+ add_scope_fixup(outer);
+ }
+ // res = true, goto done
+ gen_load_bool1(x, true);
+ u32 l0_true = gen_branch_fwd();
+
+ // nope: res = false
+ pop_scope();
+ gen_load_bool2(x);
+
+ // done:
+ fixup_branch_fwd(l0_true);
}
}
void parse_expr(Item x) {
parse_and_expr(x);
- while (ctx.tok == tOR) {
- next();
- ItemRec y;
- parse_and_expr(&y);
- error("<TODO> or op");
+ if (ctx.tok == tOR) {
+ Scope outer = push_scope(sBlock, nil);
+
+ // if x goto yup
+ gen_branch_cond(x, true);
+ add_scope_fixup(outer);
+
+ while (ctx.tok == tOR) {
+ next();
+ ItemRec y;
+
+ // if y goto yup
+ parse_rel_expr(&y);
+ gen_branch_cond(&y, true);
+ add_scope_fixup(outer);
+ }
+ // res = false, goto done
+ gen_load_bool1(x, false);
+ u32 l0_false = gen_branch_fwd();
+
+ // yup: res = true
+ pop_scope();
+ gen_load_bool2(x);
+
+ // done:
+ fixup_branch_fwd(l0_false);
}
}
@@ -1512,6 +1559,7 @@ void parse_global_var() {
gvar->next = ctx.scope->first;
ctx.scope->first = gvar;
ctx.alloc_global = ctx.alloc_global + type->size;
+ ctx.alloc_global = (ctx.alloc_global + 3) & (~3); // round to word
if (ctx.tok == tASSIGN) {
next();
@@ -2110,6 +2158,17 @@ void gen_get_ptr(Item x) {
gen_trace("get_ptr<<<", x, nil);
}
+void gen_load_bool1(Item x, bool val) {
+ set_item(x, iReg, ctx.type_bool, get_reg_tmp(), val, 0);
+ gen_trace("load_bool1", x, nil);
+ emit_opi(MOV, x->r, 0, x->a);
+}
+
+void gen_load_bool2(Item x) {
+ gen_trace("load_bool2", x, nil);
+ emit_opi(MOV, x->r, 0, !x->a);
+}
+
u32 gen_branch_cond(Item x, bool sense) {
gen_trace_n("branch_cond", sense, x, nil);
u32 cc;
diff --git a/test/1031-logical-and-or.log b/test/1031-logical-and-or.log
@@ -0,0 +1,27 @@
+D 00000200
+D 00000201
+D 00000202
+D 00000103
+D 00000204
+D 00000205
+D 00000106
+D 00000207
+D 00000208
+D 00000109
+D 00000400
+D 00000401
+D 00000402
+D 00000303
+D 00000404
+D 00000405
+D 00000406
+D 00000307
+D 00000408
+D 00000409
+D 0000040a
+D 0000040b
+D 0000040c
+D 0000040d
+D 0000040e
+D 0000040f
+X 00000042
diff --git a/test/1031-logical-and-or.src b/test/1031-logical-and-or.src
@@ -0,0 +1,31 @@
+
+
+func or_test(n i32) {
+ if (n == 3 || n == 6 || n == 9) {
+ _hexout_(n | 0x100);
+ } else {
+ _hexout_(n | 0x200);
+ }
+}
+
+func and_test(n i32) {
+ if ((n & 1 == 1) && (n & 2 == 2) && (n < 8)) {
+ _hexout_(n | 0x300);
+ } else {
+ _hexout_(n | 0x400);
+ }
+}
+
+func start() i32 {
+ var n i32 = 0;
+ while n < 10 {
+ or_test(n);
+ n = n + 1;
+ }
+ n = 0;
+ while n < 16 {
+ and_test(n);
+ n = n + 1;
+ }
+ return 0x42;
+}