home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / uae_cpu / cpuopti.c < prev    next >
C/C++ Source or Header  |  1999-10-03  |  6KB  |  299 lines

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