EtchedPixels / Fuzix-Compiler-Kit

Fuzix C Compiler Project
Other
49 stars 13 forks source link

be-codegen-6800.c Optimizes addition and subtraction with signed/unsigned char. #167

Open zu2 opened 4 days ago

zu2 commented 4 days ago

Currently, addition with signed/unsigned char pushes the augend onto the stack, sign-extends the addend, and then calls a helper function.

This patch provides shorter code.

--- ../Fuzix-Compiler-Kit/be-codegen-6800.c 2024-11-18 09:16:57
+++ be-codegen-6800.c   2024-11-18 21:02:24
@@ -514,6 +514,20 @@
            invalidate_d();
            add_d_const(v);
            return 1;
+       }
+       if (s == 2 && r->op == T_CAST && (r->type&~UNSIGNED) == CSHORT && is_simple(r->right)) {
+           if (r->right->type == UCHAR) {
+               op8_on_node(r->right, "add", 0);
+               puts("\tadca #0");
+               return 1;
+           }else if (r->right->type == CCHAR) {
+               unsigned l = ++label;
+               write_uni_op(r->right, "tst", 0);
+               printf("\tbpl X%u\n\tdeca\nX%u:\n",l,l);
+               op8_on_node(r->right, "add", 0);
+               puts("\tadca #0");
+               return 1;
+           }
        }
        return write_opd(r, "add", "adc", 0);
    case T_MINUS:
@@ -527,6 +541,20 @@
            if (s == 1) {
                add_b_const(-r->value);
                b_val -= r->value;
+               return 1;
+           }
+       }
+       if (s == 2 && r->op == T_CAST && (r->type&~UNSIGNED) == CSHORT && is_simple(r->right)) {
+           if (r->right->type == UCHAR) {
+               op8_on_node(r->right, "sub", 0);
+               puts("\tsbca #0");
+               return 1;
+           }else if (r->right->type == CCHAR) {
+               unsigned l = ++label;
+               write_uni_op(r->right, "tst", 0);
+               printf("\tbpl X%u\n\tinca\nX%u:\n",l,l);
+               op8_on_node(r->right, "sub", 0);
+               puts("\tsbca #0");
                return 1;
            }
        }

the patch pass this test program.

#include    "cprintf.c"

int
main(int argc,char **argv)
{
    signed char c1, c2;
    int i1,i2;

    for(i1=-128; i1<=127; i1++){
        for(i2=-128; i2<=127; i2++){
            c1 = i1;
            c2 = i2;
            if(c1+c2 != i1+i2){
                cprintf("%d+%d=%d (!=%d)\n",i1,i2,c1+c2,i1+i2);
                return 1;
            }
            if(c1-c2 != i1-i2){
                cprintf("%d+%d=%d (!=%d)\n",i1,i2,c1-c2,i1-i2);
                return 2;
            }
        }
    }

    return 0;
}

before

        ldb 0,x
        clra
        asrb
        rolb
        sbca #0
        pshb
        psha
        ldb 1,x
        clra
        asrb
        rolb
        sbca #0
        jsr __plus

after.

        ldb 0,x
        clra
        asrb
        rolb
        sbca #0
        tst 1,x
        bpl X1
        deca
X1:
        addb 1,x
        adca #0

This patch does not shorten the form p - q as memcmp uses. I am looking for a way to do this.

zu2 commented 3 days ago

In the signed case, this results in better code. use gen_shortcut.

@@ -1393,6 +1428,38 @@
        return do_xeqop(n, "xoreq");
    case T_HATEQ:
        return do_xeqop(n, "xhateq");
+   case T_PLUS:
+       if (s==2 && n->type==CSHORT
+       &&  r->op == T_CAST && r->type == CSHORT
+       &&  l->op == T_CAST && l->type == CSHORT
+       &&  r->right->type == CCHAR
+       &&  l->right->type == CCHAR ){
+           if (is_simple(r->right)){
+               codegen_lr(l->right);
+               puts("\tclra");
+                       op8_on_node(r->right, "add", 0);
+               printf("\tbge X%d\n\tdeca\n",++label);
+               printf("X%d:\n",label);
+               return 1;
+           }
+       }
+       return 0;
+   case T_MINUS:
+       if (s==2 && n->type==CSHORT
+       &&  r->op == T_CAST && r->type == CSHORT
+       &&  l->op == T_CAST && l->type == CSHORT
+       &&  r->right->type == CCHAR
+       &&  l->right->type == CCHAR ){
+           if (is_simple(r->right)){
+               codegen_lr(l->right);
+               puts("\tclra");
+                       op8_on_node(r->right, "sub", 0);
+               printf("\tbge X%d\n\tdeca\n",++label);
+               printf("X%d:\n",label);
+               return 1;
+           }
+       }
+       return 0;