Annotation of uae/src/cpuopti.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * UAE - The Un*x Amiga Emulator
                      3:  *
                      4:  * cpuopti.c - Small optimizer for cpu*.s files
                      5:  *             Based on work by Tauno Taipaleenmaki
                      6:  *
                      7:  * Copyright 1996 Bernd Schmidt
                      8:  */
                      9: 
                     10: #include "sysconfig.h"
                     11: #include "sysdeps.h"
                     12: #include <ctype.h>
                     13: 
                     14: struct line {
                     15:     struct line *next, *prev;
1.1.1.3   root       16:     int delet;
1.1       root       17:     char *data;
                     18: };
                     19: 
                     20: struct func {
                     21:     struct line *first_line, *last_line;
                     22:     int initial_offset;
                     23: };
                     24: 
                     25: static void oops(void)
                     26: {
                     27:     fprintf(stderr, "Corrupted assembly file!\n");
                     28:     abort();
                     29: }
                     30: 
1.1.1.5   root       31: /* Not strictly true to definition, as it only checks for match/no match,
                     32:    not for ordering */
                     33: static int mystrncmp(const char* a, const char* b, int len)
                     34: {
                     35:     int biswhite=0;
                     36:     while (len) {
                     37:        if (isspace(*a)) {
                     38:            if (!biswhite) {
                     39:                biswhite=isspace(*b++);
                     40:                while (isspace(*b))
                     41:                    b++;
                     42:            }
                     43:            if (!biswhite)
                     44:                return -1;
                     45:        }
                     46:        else {
                     47:            biswhite=0;
                     48:            if (*a!=*b++)
                     49:                return -1;
                     50:        }
                     51:        a++;
                     52:        len--;
                     53:     }
                     54:     return 0;
                     55: }
                     56: 
                     57: 
1.1       root       58: static char * match(struct line *l, const char *m)
                     59: {
                     60:     char *str = l->data;
                     61:     int len = strlen(m);
                     62:     while (isspace(*str))
                     63:        str++;
1.1.1.3   root       64: 
1.1.1.5   root       65:     if (mystrncmp(str, m, len) != 0)
1.1       root       66:        return NULL;
                     67:     return str + len;
                     68: }
                     69: 
1.1.1.3   root       70: static int insn_references_reg (struct line *l, char *reg)
                     71: {
                     72:     if (reg[0] != 'e') {
                     73:        fprintf(stderr, "Unknown register?!?\n");
                     74:        abort();
                     75:     }
                     76:     if (strstr (l->data, reg) != 0)
                     77:        return 1;
                     78:     if (strstr (l->data, reg+1) != 0)
                     79:        return 1;
                     80:     if (strcmp (reg, "eax") == 0
                     81:        && (strstr (l->data, "%al") != 0 || strstr (l->data, "%ah") != 0))
                     82:        return 1;
                     83:     if (strcmp (reg, "ebx") == 0
                     84:        && (strstr (l->data, "%bl") != 0 || strstr (l->data, "%bh") != 0))
                     85:        return 1;
                     86:     if (strcmp (reg, "ecx") == 0
                     87:        && (strstr (l->data, "%cl") != 0 || strstr (l->data, "%ch") != 0))
                     88:        return 1;
                     89:     if (strcmp (reg, "edx") == 0
                     90:        && (strstr (l->data, "%dl") != 0 || strstr (l->data, "%dh") != 0))
                     91:        return 1;
                     92:     return 0;
                     93: }
                     94: 
1.1       root       95: static void do_function(struct func *f)
                     96: {
1.1.1.4   root       97:     int v;
1.1       root       98:     int pops_at_end = 0;
1.1.1.4   root       99:     struct line *l, *l1, *fl, *l2;
1.1       root      100:     char *s, *s2;
                    101:     int in_pop_area = 1;
1.1.1.3   root      102: 
1.1       root      103:     f->initial_offset = 0;
1.1.1.3   root      104: 
1.1       root      105:     l = f->last_line;
                    106:     fl = f->first_line;
                    107: 
                    108:     if (!match(l,"ret"))
                    109:        oops();
1.1.1.3   root      110: 
1.1       root      111:     while (!match(fl, "op_"))
                    112:        fl = fl->next;
                    113:     fl = fl->next;
1.1.1.3   root      114: 
                    115:     /* Try reordering the insns at the end of the function so that the
                    116:      * pops are all at the end. */
                    117:     l2 = l->prev;
                    118:     /* Tolerate one stack adjustment */
                    119:     if (match (l2, "addl $") && strstr(l2->data, "esp") != 0)
                    120:        l2 = l2->prev;
                    121:     for (;;) {
                    122:        char *forbidden_reg;
                    123:        struct line *l3, *l4;
                    124: 
                    125:        while (match (l2, "popl %"))
                    126:            l2 = l2->prev;
                    127: 
                    128:        l3 = l2;
                    129:        for (;;) {
                    130:            forbidden_reg = match (l3, "popl %");
                    131:            if (forbidden_reg)
                    132:                break;
                    133:            if (l3 == fl)
                    134:                goto reordered;
                    135:            /* Jumps and labels put an end to our attempts... */
                    136:            if (strstr (l3->data, ".L") != 0)
                    137:                goto reordered;
                    138:            /* Likewise accesses to the stack pointer... */
                    139:            if (strstr (l3->data, "esp") != 0)
                    140:                goto reordered;
                    141:            /* Function calls... */
                    142:            if (strstr (l3->data, "call") != 0)
                    143:                goto reordered;
                    144:            l3 = l3->prev;
                    145:        }
                    146:        if (l3 == l2)
                    147:            abort();
                    148:        for (l4 = l2; l4 != l3; l4 = l4->prev) {
                    149:            /* The register may not be referenced by any of the insns that we
                    150:             * move the popl past */
                    151:            if (insn_references_reg (l4, forbidden_reg))
                    152:                goto reordered;
                    153:        }
                    154:        l3->prev->next = l3->next;
                    155:        l3->next->prev = l3->prev;
                    156:        l2->next->prev = l3;
                    157:        l3->next = l2->next;
                    158:        l2->next = l3;
                    159:        l3->prev = l2;
                    160:     }
                    161: reordered:
                    162: 
                    163:     l = l->prev;
                    164: 
1.1.1.4   root      165:     s = match (l, "addl $");
                    166:     s2 = match (fl, "subl $");
                    167: 
                    168:     l1 = l;
                    169:     if (s == 0) {
                    170:        char *t = match (l, "popl %");
                    171:        if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
                    172:            s = "4,%esp";
                    173:            l = l->prev;
                    174:            t = match (l, "popl %");
                    175:            if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
                    176:                s = "8,%esp";
1.1.1.3   root      177:                l = l->prev;
1.1.1.4   root      178:            }
                    179:        }
                    180:     } else {
                    181:        l = l->prev;
                    182:     }
                    183: 
                    184:     if (s && s2) {
                    185:        int v = 0;
                    186:        if (strcmp (s, s2) != 0) {
                    187:            fprintf (stderr, "Stack adjustment not matching.\n");
                    188:            return;
                    189:        }
                    190: 
                    191:        while (isdigit(*s)) {
                    192:            v = v * 10 + (*s) - '0';
                    193:            s++;
1.1.1.3   root      194:        }
                    195: 
1.1.1.4   root      196:        if (strcmp (s, ",%esp") != 0) {
                    197:            fprintf (stderr, "Not adjusting the stack pointer.\n");
                    198:            return;
                    199:        }
                    200:        f->initial_offset = v;
                    201:        fl->delet = 3;
                    202:        fl = fl->next;
                    203:        l1->delet = 2;
                    204:        l1 = l1->prev;
                    205:        while (l1 != l) {
                    206:            l1->delet = 1;
                    207:            l1 = l1->prev;
                    208:        }
1.1       root      209:     }
1.1.1.4   root      210: 
1.1       root      211:     while (in_pop_area) {
                    212:        char *popm, *pushm;
1.1.1.4   root      213:        popm = match (l, "popl %");
                    214:        pushm = match (fl, "pushl %");
1.1       root      215:        if (popm && pushm && strcmp(pushm, popm) == 0) {
                    216:            pops_at_end++;
1.1.1.3   root      217:            fl->delet = l->delet = 1;
1.1       root      218:        } else
                    219:            in_pop_area = 0;
                    220:        l = l->prev;
                    221:        fl = fl->next;
                    222:     }
                    223:     if (f->initial_offset)
                    224:        f->initial_offset += 4 * pops_at_end;
                    225: }
                    226: 
                    227: static void output_function(struct func *f)
                    228: {
                    229:     struct line *l = f->first_line;
1.1.1.3   root      230: 
1.1       root      231:     while (l) {
1.1.1.3   root      232:        switch (l->delet) {
1.1       root      233:         case 1:
                    234:            break;
                    235:         case 0:
                    236:            printf("%s\n", l->data);
                    237:            break;
                    238:         case 2:
                    239:            if (f->initial_offset)
                    240:                printf("\taddl $%d,%%esp\n", f->initial_offset);
                    241:            break;
                    242:         case 3:
                    243:            if (f->initial_offset)
                    244:                printf("\tsubl $%d,%%esp\n", f->initial_offset);
                    245:            break;
                    246:        }
                    247:        l = l->next;
                    248:     }
                    249: }
                    250: 
                    251: int main(int argc, char **argv)
                    252: {
1.1.1.3   root      253:     FILE *infile = stdin;
1.1       root      254:     char tmp[4096];
                    255: 
1.1.1.3   root      256: #ifdef __mc68000__
                    257:     if(system("perl machdep/cpuopti")==-1) {
                    258:        perror("perl machdep/cpuopti");
                    259:        return 10;
                    260:    } else return 0;
1.1.1.2   root      261: #endif
                    262: 
1.1.1.3   root      263:     /* For debugging... */
                    264:     if (argc == 2)
                    265:        infile = fopen (argv[1], "r");
                    266: 
1.1       root      267:     for(;;) {
                    268:        char *s;
1.1.1.3   root      269: 
                    270:        if ((fgets(tmp, 4095, infile)) == NULL)
1.1       root      271:            break;
                    272: 
                    273:        s = strchr (tmp, '\n');
                    274:        if (s != NULL)
                    275:            *s = 0;
                    276: 
1.1.1.5   root      277:        if (mystrncmp(tmp, ".globl op_", 10) == 0) {
1.1       root      278:            struct line *first_line = NULL, *prev = NULL;
                    279:            struct line **nextp = &first_line;
                    280:            struct func f;
1.1.1.3   root      281:            int nr_rets = 0;
                    282:            int can_opt = 1;
                    283: 
1.1       root      284:            do {
                    285:                struct line *current;
                    286: 
                    287:                if (strcmp (tmp, "#APP") != 0 && strcmp (tmp, "#NO_APP") != 0) {
                    288:                    current = *nextp = (struct line *)malloc(sizeof (struct line));
                    289:                    nextp = &current->next;
                    290:                    current->prev = prev; prev = current;
                    291:                    current->next = NULL;
1.1.1.3   root      292:                    current->delet = 0;
1.1       root      293:                    current->data = my_strdup (tmp);
1.1.1.3   root      294:                    if (match (current, "movl %esp,%ebp") || match (current, "enter")) {
                    295:                        fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data);
                    296:                        can_opt = 0;
                    297:                    }
                    298: 
                    299:                    if (match (current, "ret"))
                    300:                        nr_rets++;
1.1       root      301:                }
1.1.1.3   root      302:                if ((fgets(tmp, 4095, infile)) == NULL)
1.1       root      303:                    oops();
                    304:                s = strchr (tmp, '\n');
                    305:                if (s != NULL)
                    306:                    *s = 0;
                    307:            } while (strncmp (tmp,".Lfe", 4) != 0);
                    308: 
                    309:            f.first_line = first_line;
                    310:            f.last_line = prev;
                    311: 
1.1.1.3   root      312:            if (nr_rets == 1 && can_opt)
                    313:                do_function(&f);
                    314:            /*else
                    315:                fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/
1.1       root      316:            output_function(&f);
                    317:        }
                    318:        printf("%s\n", tmp);
                    319:     }
                    320:     return 0;
                    321: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.