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;
+}