commit d08c090a97f2a9690f15e70fe879f068da5d1b36
parent 47d3a9dea9ae7fda2c7edfcbf2d49786734010bf
Author: Brian Swetland <swetland@frotz.net>
Date: Tue, 14 Dec 2021 13:22:33 -0800
improve conditional handling in IR and straight r5 codegen
- avoid extraneous branches by avoiding converting comparisons
into bool values when possible
Diffstat:
2 files changed, 47 insertions(+), 25 deletions(-)
diff --git a/src/codegen-ir.c b/src/codegen-ir.c
@@ -163,6 +163,7 @@ void inst_ret(i32 a) {
}
u32 rel_op_to_ins_tab[6] = { INS_BEQ, INS_BNE, INS_BLT, INS_BLE, INS_BGT, INS_BGE };
+u32 rel_op_to_inv_ins_tab[6] = { INS_BNE, INS_BEQ, INS_BGE, INS_BGT, INS_BLE, INS_BLT };
u32 add_op_to_ins_tab[4] = { INS_ADD, INS_SUB, INS_OR, INS_XOR };
u32 mul_op_to_ins_tab[6] = { INS_MUL, INS_SDIV, INS_SREM, INS_AND, INS_LSL, INS_ASR };
@@ -313,6 +314,19 @@ i32 gen_relop(Ast node, u32 op) {
return inst_phi(rtrue, rfalse);
}
+i32 gen_branch_if_expr_false(Ast node, i32 label) {
+ if (ast_kind_is_relop(node->kind)) {
+ u32 op = rel_op_to_inv_ins_tab[node->kind - AST_EQ];
+ i32 left = gen_expr(node->c0);
+ i32 right = gen_expr(node->c1);
+ return inst_br_cmp(op, label, left, right);
+ } else {
+ i32 r = gen_expr(node);
+ return inst_br_cmpi(INS_BEQ, label, r, 0);
+ }
+}
+
+
i32 gen_short_circuit_op(Ast node, u32 cc, u32 sc) {
#if 0
u32 r = gen_expr(node->c0);
@@ -432,15 +446,14 @@ void gen_while(Ast node) {
inst_label(loop_continue);
- u32 r = gen_expr(node->c0);
-
- // branch to exit if false
- inst_br_cmpi(INS_BEQ, loop_exit, r, 0);
+ gen_branch_if_expr_false(node->c0, loop_exit);
gen_block(node->c1);
inst_br(loop_continue);
+ inst_label(loop_exit);
+
// restore branch targets
loop_continue = old_loop_continue;
loop_exit = old_loop_exit;
@@ -457,9 +470,7 @@ void gen_if_else(Ast node) {
// compute if expr
// branch ahead if false;
- i32 r = gen_expr(node->c0);
-
- i32 l0_br_false = inst_br_cmpi(INS_BEQ, label_get(), r, 0);
+ i32 l0_br_false = gen_branch_if_expr_false(node->c0, label_get());
i32 l_exit = label_get();
@@ -476,9 +487,7 @@ void gen_if_else(Ast node) {
if (node->kind == AST_IFELSE) { // ifelse ...
gen_trace("gen_ifelse()");
- r = gen_expr(node->c0);
-
- i32 l0_br_false = inst_br_cmpi(INS_BEQ, label_get(), r, 0);
+ i32 l0_br_false = gen_branch_if_expr_false(node->c0, label_get());
gen_block(node->c1);
node = node->c2;
diff --git a/src/codegen-risc5-simple.c b/src/codegen-risc5-simple.c
@@ -150,6 +150,7 @@ void emit_bi(u32 op, u32 off) {
}
u8 rel_op_to_cc_tab[6] = { EQ, NE, LT, LE, GT, GE };
+u8 rel_op_to_inv_cc_tab[6] = { NE, EQ, GE, GT, LE, LT };
u32 add_op_to_ins_tab[4] = { ADD, SUB, IOR, XOR };
u32 mul_op_to_ins_tab[6] = { MUL, DIV, MOD, AND, LSL, ASR };
@@ -411,6 +412,28 @@ u32 gen_relop(Ast node, u32 cc) {
return res;
}
+u32 gen_branch_if_expr_false(Ast node) {
+ if (ast_kind_is_relop(node->kind)) {
+ u32 cc = rel_op_to_inv_cc_tab[node->kind - AST_EQ];
+ u32 left = gen_expr(node->c0);
+ u32 right = gen_expr(node->c1);
+ u32 res = get_reg_tmp();
+ emit_op(SUB, left, left, right);
+ put_reg(left);
+ put_reg(right);
+ u32 addr = ctx.pc;
+ emit_bi(cc, 0);
+ return addr;
+ } else {
+ i32 r = gen_expr(node);
+ emit_mov(R11, r); // set z flag
+ put_reg(r);
+ u32 addr = ctx.pc;
+ emit_bi(EQ, 0);
+ return addr;
+ }
+}
+
u32 gen_short_circuit_op(Ast node, u32 cc, u32 sc) {
u32 r = gen_expr(node->c0);
emit_mov(R11, r); // set z flag
@@ -535,17 +558,15 @@ void gen_while(Ast node) {
loop_exit = &list;
loop_continue = ctx.pc;
- u32 r = gen_expr(node->c0);
- emit_mov(R11, r); // set z flag
- put_reg(r);
- gen_branch_fwd(EQ, &list);
+ u32 br_false = gen_branch_if_expr_false(node->c0);
gen_block(node->c1);
gen_branch(AL, loop_continue);
- // patch breaks
+ // patch branches
+ fixup_branch_fwd(br_false);
fixup_branches_fwd(loop_exit->next);
// restore branch targets
@@ -564,11 +585,7 @@ void gen_if_else(Ast node) {
// compute if expr
// branch ahead if false;
- u32 r = gen_expr(node->c0);
- emit_mov(R11, r); // set z flag;
- put_reg(r);
- u32 l0_br_false = ctx.pc;
- emit_bi(EQ, 0);
+ u32 l0_br_false = gen_branch_if_expr_false(node->c0);
// exec then block
gen_block(node->c1);
@@ -583,11 +600,7 @@ void gen_if_else(Ast node) {
if (node->kind == AST_IFELSE) { // ifelse ...
gen_trace("gen_ifelse()");
- r = gen_expr(node->c0);
- emit_mov(R11, r); // set z flag
- put_reg(r);
- l0_br_false = ctx.pc;
- emit_bi(EQ, 0);
+ u32 l0_br_false = gen_branch_if_expr_false(node->c0);
gen_block(node->c1);
node = node->c2;
} else { // else ...