diff options
author | Robert de Bath <rdebath@poboxes.com> | 1997-02-25 20:42:19 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2013-10-23 23:38:07 +0200 |
commit | 4c36e9a0c125ccfff37aa440dab2cf58c4152fff (patch) | |
tree | a5d9c84ba2661029ddb2223dacd50529a361c3d5 /copt | |
parent | f8de35da65c5d93bb733073cf40da154bc1c0748 (diff) | |
parent | 9696d7b0e1f3a1b0f5fd4a0428eb75afe8ad4ed6 (diff) | |
download | dev86-4c36e9a0c125ccfff37aa440dab2cf58c4152fff.tar.gz |
Import Dev86src-0.0.11.tar.gzv0.0.11
Diffstat (limited to 'copt')
-rw-r--r-- | copt/Makefile | 6 | ||||
-rw-r--r-- | copt/README | 25 | ||||
-rw-r--r-- | copt/copt.c | 826 | ||||
-rw-r--r-- | copt/rules.386 | 427 | ||||
-rw-r--r-- | copt/rules.86 | 427 | ||||
-rw-r--r-- | copt/rules.end | 18 | ||||
-rw-r--r-- | copt/rules.inl | 8 | ||||
-rw-r--r-- | copt/rules.net | 42 | ||||
-rw-r--r-- | copt/rules.start | 19 |
9 files changed, 1798 insertions, 0 deletions
diff --git a/copt/Makefile b/copt/Makefile new file mode 100644 index 0000000..9f273a3 --- /dev/null +++ b/copt/Makefile @@ -0,0 +1,6 @@ + +copt: copt.c + $(CC) $(CFLAGS) -o copt copt.c + +realclean clean: + rm -f *.o copt diff --git a/copt/README b/copt/README new file mode 100644 index 0000000..2ac4453 --- /dev/null +++ b/copt/README @@ -0,0 +1,25 @@ + +From gero@gkminix.han.de Thu Jan 30 19:54:34 1997 +Date: Wed, 29 Jan 1997 23:46:50 +0100 (MET) +From: Gero Kuhlmann <gero@gkminix.han.de> +Subject: Re: 8086 Development environment + +Hello again, + +And one hint for using the optimizer I sent you in an earlier mail: the +order of the rules files matters! You should try: + +copt -c! -h"use16 386" rules.start rules.386 rules.86 rules.end + +If you don't want to optimize for 386 long integer operations, you +can leave out the -h option and the rules.386 file. The rules.net file +is only necessary for my bootrom code, and does some optimizations I +can't do with preprocessor commands. + +gero. + +>-- +Life sucks, but it's better than the alternative. + - Peter da Silva +-- +Gero Kuhlmann, Hannover 0511/6497525 (Voice) gero@gkminix.han.de diff --git a/copt/copt.c b/copt/copt.c new file mode 100644 index 0000000..83ee18f --- /dev/null +++ b/copt/copt.c @@ -0,0 +1,826 @@ +/* + ************************************************************************** + * + * Utility program to optimize the output of the BCC compiler + * + * Module: copt.c + * Purpose: Optimize BCC assembler output + * Entries: main + * + * This program is based on an idea from Christopher W. Fraser. + * + ************************************************************************** + * + * Copyright (C) 1995,1996,1997 Gero Kuhlmann <gero@gkminix.han.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +#include "utility.h" +#include "../../headers/general.h" +#include "../../headers/version.h" +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <malloc.h> +#include <string.h> +#include <ctype.h> + +#define MAXLINE 1024 +#define HASHSIZE 107 +#define NOCHAR '\177' +#define VARNUM 10 + + + +/* Struct containing each string of an input file */ +struct line_s { + char *text; + struct line_s *prev; + struct line_s *next; +}; + + +/* Struct containing one rule */ +struct rule_s { + struct line_s *old; + struct line_s *new; + struct rule_s *next; +}; + + +/* Hash table to store strings in a space saving way */ +struct hash_s { + char *text; + struct hash_s *next; +}; + + + +/* + * Global variables + */ +static struct rule_s *first = NULL; /* first rule */ +static struct rule_s *last = NULL; /* last rule */ +static struct line_s *infile = NULL; /* list of strings in input file */ +static struct hash_s *htab[HASHSIZE]; /* string hash table */ +static int hash_init = 0; /* flag if hash table initialized */ +static char *vars[VARNUM]; /* variable table */ +static char *progname; /* program name */ + + + +/* + * Allocate memory and print error if none available + */ +static void *mymalloc(int size) +{ + void *p; + + if ((p = malloc(size)) == NULL) { + fprintf(stderr, "%s: no memory\n", progname); + exit(1); + } + return(p); +} + + + +/* + * Insert a string into the hash table. If the string is already in there + * just return the pointer to that string. + */ +static char *install(char *str, int slen) +{ + struct hash_s *hp; + char *chkstr; + char *cp; + int hashval; + + /* Clear the hashing table if not already done */ + if (!hash_init) { + for (hashval = 0; hashval < HASHSIZE; hashval++) + htab[hashval] = NULL; + hash_init++; + } + + /* Get check string */ + if (slen < 0) + slen = strlen(str); + chkstr = mymalloc(slen + 1); + strncpy(chkstr, str, slen); + chkstr[slen] = '\0'; + + /* Determine hashing value of string */ + hashval = 0; + for (cp = chkstr; *cp; cp++) + hashval += *cp; + hashval %= HASHSIZE; + + /* Check if the string is already in the hashing table */ + for (hp = htab[hashval]; hp != NULL; hp = hp->next) + if (!strcmp(chkstr, hp->text)) { + free(chkstr); + return(hp->text); + } + + /* String is not in hash table, so create a new entry */ + hp = (struct hash_s *)mymalloc(sizeof(struct hash_s)); + hp->text = chkstr; + hp->next = htab[hashval]; + htab[hashval] = hp; + return(hp->text); +} + + + +/* + * Read one line from input file and skip all blanks at the beginning + */ +static char *readline(FILE *fp) +{ + static char buf[MAXLINE]; + char *cp; + + /* Read line from input file */ + if (fgets(buf, MAXLINE-1, fp) == NULL) + return(NULL); + buf[MAXLINE-1] = '\0'; + + /* Delete trailing newline */ + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + + /* Delete leading white spaces */ + for (cp = buf; *cp && isspace(*cp); cp++) ; + if (cp != buf && *cp) + strcpy(buf, cp); + + return(buf); +} + + + +/* + * Read a list of input lines. Terminate reading when the 'quit' character + * has been found in the first column of the input line. All lines with the + * 'comment' character in the first position will be skipped. + */ +static struct line_s *readlist(FILE *fp, char quit, char comment) +{ + struct line_s *lp; + struct line_s *first_line = NULL; + struct line_s *last_line = NULL; + char *cp; + + while ((cp = readline(fp)) != NULL) { + if (quit != NOCHAR && quit == *cp) + break; + if (comment != NOCHAR && comment == *cp) + continue; + if (*cp == '\0') + continue; + lp = mymalloc(sizeof(struct line_s)); + lp->text = install(cp, -1); + lp->prev = last_line; + lp->next = NULL; + if (first_line == NULL) + first_line = lp; + if (last_line != NULL) + last_line->next = lp; + last_line = lp; + } + return(first_line); +} + + + +/* + * Read pattern file + */ +static void readpattern(char *rulesdir, char *filename) +{ + static char path[MAXLINE]; + struct rule_s *rp; + FILE *fp; + + /* Open pattern file */ + if (rulesdir != NULL) + sprintf(path, "%s/%s", rulesdir, filename); + else + sprintf(path, "%s", filename); + if ((fp = fopen(path, "r")) == NULL) { + fprintf(stderr, "%s: can't open pattern file %s\n", progname, path); + exit(1); + } + + /* Read every line of the pattern file */ + while (!feof(fp)) { + rp = (struct rule_s *)mymalloc(sizeof(struct rule_s)); + rp->old = readlist(fp, '=', '#'); + rp->new = readlist(fp, '\0', '#'); + rp->next = first; + if (rp->old == NULL || rp->new == NULL) { + free(rp); + break; + } + first = rp; + if (last == NULL) + last = rp; + } + + /* Close pattern file */ + (void)fclose(fp); +} + + + +/* + * Clear pattern list to allow for another run + */ +static void clearpattern(void) +{ + struct rule_s *rp1, *rp2; + struct line_s *lp1, *lp2; + + rp1 = first; + while (rp1 != NULL) { + /* Clear old rule text list */ + lp1 = rp1->old; + while (lp1 != NULL) { + lp2 = lp1; + lp1 = lp1->next; + free(lp2); + } + /* Clear new rule text list */ + lp1 = rp1->new; + while (lp1 != NULL) { + lp2 = lp1; + lp1 = lp1->next; + free(lp2); + } + /* Clear rule itself */ + rp2 = rp1; + rp1 = rp1->next; + free(rp2); + } + + first = NULL; + last = NULL; +} + + + +/* + * Read input file + */ +static void readinfile(char *filename, char comment) +{ + FILE *fp; + + fp = stdin; + if (filename != NULL && (fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "%s: can't open input file %s\n", progname, filename); + exit(1); + } + infile = readlist(fp, NOCHAR, comment); + if (fp != stdin) + (void)fclose(fp); +} + + + +/* + * Eval an expression into an integer number + */ +static long eval(char *str, int len) +{ +#define NO_OP 0 +#define ADD_OP 1 +#define SUB_OP 2 +#define MUL_OP 3 +#define DIV_OP 4 +#define SHL_OP 5 +#define SHR_OP 6 + + char *oldcp, *cp, c; + long retval = 0; + long num = 0; + int sign = 1; + int base = 10; + int state = 0; + int op = NO_OP; + int i, varnum; + + /* Apply operation to current numeric value */ + static void doretval(void) + { + switch (op) { + case NO_OP: retval = num * sign; + break; + case ADD_OP: retval += num * sign; + break; + case SUB_OP: retval -= num * sign; + break; + case MUL_OP: retval *= num * sign; + break; + case DIV_OP: retval /= num * sign; + break; + case SHL_OP: retval <<= num; + break; + case SHR_OP: retval >>= num; + break; + } + op = NO_OP; + num = 0; + sign = 1; + base = 10; + } + + /* Scan through whole string and decode it */ + for (cp = str, i = 0; *cp && i < len; cp++, i++) { + c = toupper(*cp); + if (c == '-' && (state == 0 || state == 5)) { + state = 1; + sign = -1; + } else if (c == '+' && (state == 0 || state == 5)) { + state = 1; + sign = 1; + } else if (c == '%' && isdigit(*(cp + 1)) && (state < 2 || state == 5)) { + state = 4; + varnum = *(cp + 1) - '0'; + if (vars[varnum] == NULL || i >= len) + return(0); + num = eval(vars[varnum], strlen(vars[varnum])); + doretval(); + cp++; i++; + } else if (c == '$' && (state < 2 || state == 5)) { + state = 2; + base = 16; + } else if (base == 10 && (c >= '0' && c <= '9') && + (state <= 3 || state == 5)) { + state = 3; + num = num * 10 + (c - '0'); + } else if (base == 16 && + ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) && + (state <= 3 || state == 5)) { + state = 3; + num = num * 16 + (c >= 'A' ? c - '0' - 7 : c - '0'); + } else if (c == ' ' && (state == 3 || state == 4 || state == 5)) { + if (state == 3) { + doretval(); + state = 4; + } + } else if (strchr("+-*/<>", c) != NULL && (state == 3 || state == 4)) { + if (state == 3) + doretval(); + state = 5; + switch (c) { + case '+': op = ADD_OP; + break; + case '-': op = SUB_OP; + break; + case '*': op = MUL_OP; + break; + case '/': op = DIV_OP; + break; + case '<': op = SHL_OP; + break; + case '>': op = SHR_OP; + break; + } + } else + return(0); + } + + /* Check if the string has been terminated correctly */ + if (state != 3 && state != 4) + return(0); + if (state == 3) + doretval(); + return(retval); +} + + + +/* + * Compare an infile string with a pattern string. If there is any variable + * defined, it will be inserted into the variable list from the pattern + * string. + */ +static int match(char *ins, char *pat) +{ + char *cp, *oldpat; + long val; + int varnum; + int len; + + while (*ins && *pat) + if (pat[0] == '%' && pat[1] == '%') { + /* '%%' actually means '%' */ + if (*ins != '%') + return(0); + pat += 2; + } else if (pat[0] == '%' && (pat[1] == '*' || isdigit(pat[1]))) { + /* Copy variable text into vars array */ + pat += 2; + for (cp = ins; *ins && !match(ins, pat); ins++) ; + if (pat[-1] == '*') + continue; + len = ins - cp; + varnum = pat[-1] - '0'; + if (vars[varnum] == NULL) + vars[varnum] = install(cp, len); + else if (strlen(vars[varnum]) != len || + strncmp(vars[varnum], cp, len)) + return(0); + } else if (pat[0] == '%' && pat[1] == '[') { + /* Copy only specific variable text into vars array */ + if ((cp = strchr(pat + 2, ']')) == NULL || + (*(cp + 1) != '*' && !isdigit(*(cp + 1)))) { + if (*ins != '[') + return(0); + pat += 2; + continue; + } + oldpat = pat + 1; + pat = cp + 2; + /* Seperate allowable patterns and compare them with ins */ + while (*oldpat && *oldpat != ']') { + oldpat++; + len = strcspn(oldpat, "|]"); + if (!strncmp(ins, oldpat, len)) + break; + oldpat += len; + } + if (!*oldpat || *oldpat == ']') + return(0); + ins += len; + if (!match(ins, pat)) + return(0); + /* Install new string into variable table */ + if (*(cp + 1) == '*') + continue; + varnum = *(cp + 1) - '0'; + if (vars[varnum] == NULL) + vars[varnum] = install(oldpat, len); + else if (strlen(vars[varnum]) != len || + strncmp(vars[varnum], oldpat, len)) + return(0); + } else if (pat[0] == '%' && pat[1] == '!') { + /* Match only if the pattern string is not found */ + if (pat[2] != '[' || (cp = strchr(pat + 3, ']')) == NULL) { + if (*ins != '!') + return(0); + pat += 3; + continue; + } + oldpat = pat + 2; + pat = cp + 1; + /* Seperate allowable patterns and compare them with ins */ + while (*oldpat && *oldpat != ']') { + oldpat++; + len = strcspn(oldpat, "|]"); + if (!strncmp(ins, oldpat, len)) + return(0); + oldpat += len; + } + } else if (pat[0] == '%' && pat[1] == '(') { + /* Match ins with expression */ + if ((cp = strchr(pat + 2, ')')) == NULL) { + if (*ins != '(') + return(0); + pat += 2; + continue; + } + oldpat = pat + 2; + pat = cp + 1; + len = cp - oldpat; + val = eval(oldpat, len); + for (cp = ins; *ins && !match(ins, pat); ins++) ; + len = ins - cp; + if (val != eval(cp, len)) + return(0); + } else if (*pat++ != *ins++) + return(0); + + return(*ins == *pat); +} + + + +/* + * Substitute variables in a string + */ +static char *subst(char *pat) +{ + char buf[MAXLINE]; + char *cp, *cp1, *cp2, *varptr; + long num; + int i = 0; + int j, pos; + + while (*pat) + if (pat[0] == '%' && isdigit(pat[1])) { + /* Substitute with value of variable */ + cp = vars[pat[1] - '0']; + while (cp != NULL && *cp) { + buf[i++] = *cp++; + if (i >= MAXLINE - 1) { + fprintf(stderr, "%s: line too long\n", progname); + exit(1); + } + } + pat += 2; + } else if (pat[0] == '%' && pat[1] == '(') { + /* Substitute with expression */ + cp = pat + 2; + if ((pat = strchr(cp, ')')) == NULL || pat - cp <= 0) + num = 0; + else + num = eval(cp, pat - cp); + if (i >= MAXLINE - 20) { + fprintf(stderr, "%s: line too long\n", progname); + exit(1); + } + i += sprintf(&buf[i], "%s$%lx", num < 0 ? "-" : "", labs(num)); + pat++; + } else if (pat[0] == '%' && pat[1] == '=') { + /* Substitute with converted variable */ + /* First seperate all parts of the pattern string */ + cp = pat + 2; + cp1 = cp2 = varptr = NULL; + if (*cp == '[') { + cp1 = ++cp; + while (*cp && *cp != ']') + cp++; + if (cp[0] == ']' && cp[1] == '[') { + cp += 2; + cp2 = cp; + while (*cp && *cp != ']') + cp++; + if (cp[0] == ']' && isdigit(cp[1])) + varptr = vars[cp[1] - '0']; + } + } + if (cp1 == NULL || cp2 == NULL || varptr == NULL) { + buf[i++] = *pat++; + if (i >= MAXLINE - 1) { + fprintf(stderr, "%s: line too long\n", progname); + exit(1); + } + continue; + } + pat = cp + 2; + /* Now scan through the first string to find variable value */ + cp1--; + pos = 0; + while (*cp1 != ']') { + cp1++; + j = strcspn(cp1, "|]"); + if (strlen(varptr) == j && !strncmp(cp1, varptr, j)) + break; + pos++; + cp1 += j; + } + if (*cp1 == ']') + continue; + /* Scan through the second string to find the conversion */ + cp2--; + while (*cp2 != ']' && pos > 0) { + cp2++; + j = strcspn(cp2, "|]"); + pos--; + cp2 += j; + } + if (*cp2 == ']' || pos != 0) + continue; + /* Insert conversion string into destination */ + cp2++; + while (*cp2 != '|' && *cp2 != ']') { + buf[i++] = *cp2++; + if (i >= MAXLINE - 1) { + fprintf(stderr, "%s: line too long\n", progname); + exit(1); + } + } + } else { + buf[i++] = *pat++; + if (i >= MAXLINE - 1) { + fprintf(stderr, "%s: line too long\n", progname); + exit(1); + } + } + + buf[i] = '\0'; + return(install(buf, i)); +} + + + +/* + * Optimize one line of the input file + */ +static struct line_s *optline(struct line_s *cur) +{ + struct rule_s *rp; + struct line_s *ins, *pat; + struct line_s *lp1, *lp2; + int i; + + for (rp = first; rp != NULL; rp = rp->next) { + /* Clear variable array */ + for (i = 0; i < VARNUM; i++) + vars[i] = NULL; + + /* Scan through pattern texts and match them against the input file */ + ins = cur; + pat = rp->old; + while (ins != NULL && pat != NULL && match(ins->text, pat->text)) { + ins = ins->next; + pat = pat->next; + } + + /* Current pattern matched input line, so replace input with new */ + if (pat == NULL) { + /* Clear all lines in the source file for this pattern */ + lp1 = cur; + cur = cur->prev; + while (lp1 != ins) { + lp2 = lp1; + lp1 = lp1->next; + free(lp2); + } + /* Insert new lines into list */ + pat = rp->new; + lp1 = cur; + lp2 = NULL; + while (pat != NULL) { + lp2 = mymalloc(sizeof(struct line_s)); + lp2->text = subst(pat->text); + lp2->next = NULL; + lp2->prev = lp1; + if (lp1 != NULL) + lp1->next = lp2; + else + infile = lp2; + lp1 = lp2; + pat = pat->next; + } + if (ins != NULL) + ins->prev = lp2; + if (lp2 != NULL) + lp2->next = ins; + else if (lp1 != NULL) + lp1->next = NULL; + else + infile = NULL; + return(cur); + } + } + return(cur->next); +} + + + +/* + * Actually optimize all strings in the input file + */ +static void optimize(int backup) +{ + struct line_s *cur, *lp; + int i; + + /* Scan through all lines in the input file */ + cur = infile; + while (cur != NULL) { + if ((lp = optline(cur)) != NULL && lp != cur->next) { + for (i = 0; i < backup && lp != NULL; i++) + lp = lp->prev; + if (lp == NULL) + lp = infile; + } + cur = lp; + } +} + + + +/* + * Write out into destination file + */ +static void writeoutf(char *filename, char *headstr) +{ + FILE *fp; + struct line_s *lp; + + fp = stdout; + if (filename != NULL && (fp = fopen(filename, "w")) == NULL) { + fprintf(stderr, "%s: can't open output file %s\n", progname, filename); + exit(1); + } + if (headstr != NULL) { + fprintf(fp, headstr); + fprintf(fp, "\n"); + } + for (lp = infile; lp != NULL; lp = lp->next) + fprintf(fp, "%s\n", lp->text); + if (fp != stdout) + (void)fclose(fp); +} + + + +/* + * Print usage + */ +static void usage(void) +{ + fprintf(stderr, "usage: %s [-c<comment-char>] [-f<src-file>] [-o<out-file>]\n" + "\t\t[-b<backup-num>] [-h<head-str>] [-d<ruls-dir>] " + "<rules-file> ...\n", progname); + exit(1); +} + + + +/* + * Main program + */ +void main(int argc, char **argv) +{ + char comment = NOCHAR; + char *srcfile = NULL; + char *outfile = NULL; + char *headstr = NULL; + char *rulesdir = NULL; + int backup = 0; + int i; + + /* Get program name */ + if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + progname++; + + /* Make life easy for bcc */ + if ( argc > 4 && strcmp(argv[2], "-o") == 0 && argv[1][0] != '-' ) + { + srcfile = argv[1]; + argv++,argc--; + } + + /* Get options from command line */ + for (i = 1; i < argc; i++) + if (!strncmp(argv[i], "-c", 2)) + comment = argv[i][2]; + else if (!strncmp(argv[i], "-b", 2)) + backup = atoi(&(argv[i][3])); + else if (!strncmp(argv[i], "-f", 2)) + srcfile = &(argv[i][2]); + else if (!strncmp(argv[i], "-o", 2)) + { + if(argv[i][2]) + outfile = &(argv[i][2]); + else if(++i<argc) + outfile = argv[i]; + else + usage(); + } + else if (!strncmp(argv[i], "-h", 2)) + headstr = &(argv[i][2]); + else if (!strncmp(argv[i], "-d", 2)) + rulesdir = &(argv[i][2]); + else if (argv[i][0] == '-') + usage(); + else + break; + + /* Have to have enough parameters for rule file names */ + if ((argc - i) < 1) + usage(); + + /* Read source file and optimze it with every rules file */ + readinfile(srcfile, comment); + for ( ; i < argc; i++) { + readpattern(rulesdir, argv[i]); + optimize(backup); + clearpattern(); + } + writeoutf(outfile, headstr); +} + diff --git a/copt/rules.386 b/copt/rules.386 new file mode 100644 index 0000000..c2d07d7 --- /dev/null +++ b/copt/rules.386 @@ -0,0 +1,427 @@ +# Rules to optimize BCC assembler output for 386 + +# Rules for loading a long constant + +xor ax,ax +xor %[bx|si|di]1,%[bx|si|di]1 += +xor eax,eax + +xor eax,eax +mov %[ebx|ecx|edx]1,eax += +xor %1,%1 + +xor ax,ax +mov %[bx|si|di]*,%[*|#]0%1 += +mov eax,%0%1<<16 + +mov ax,%[*|#]0%1 +xor %[bx|si|di]2,%[bx|si|di]2 += +mov eax,%0%1 & $0000FFFF + +mov ax,%0[%1] +xor %[bx|si|di]2,%[bx|si|di]2 += +movzx eax,word ptr %0[%1] + +mov ax,%[si|di]1 +xor bx,bx += +movzx eax,%1 + +%[movzx|movsx]5 eax,%1 +mov %[ebx|ecx|edx]2,eax += +%5 %2,%1 + +%[movzx|movsx]5 %[ebx|ecx|edx]1,%2 +mov eax,%[#|*]0%3 +%[add|and|xor|or]4 eax,%[ebx|ecx|edx]1 += +%5 eax,%2 +%4 eax,%0%3 + +mov ax,%0[%1] +cwde += +movsx eax,word ptr %0[%1] + +mov ax,%[si|di]1 +cwde += +movsx eax,%1 + +mov ax,%[#|*]3%1 +mov %[bx|si|di]*,%[#|*]4%2 += +mov eax,%4%2<<16 + %1 + + +# Rules for pushing variables and constants onto the stack + +push %![dword ptr]%1[%[bx|si|di|bp]3] +push %![dword ptr]%(%1-2)[%[bx|si|di|bp]3] += +push dword ptr %(%1-2)[%3] + +push [%1+2] +push [%1] += +push dword ptr [%1] + +push %[bx|si|di]* +push ax += +push eax + +mov eax,%[#|*]0%1 +push eax += +push dword %0%1 + +mov %1,%[eax|ebx|ecx|edx]2 +push dword ptr %1 += +mov %1,%2 +push %2 + + +# Rules for loading long variables + +mov ax,[%1] +mov %[bx|si|di]*,[%1+2] += +mov eax,[%1] + +mov ax,%1[%[bx|si|di|bp]3] +mov %[bx|si|di]*,%(%1+2)[%[bx|si|di|bp]3] += +mov eax,%1[%3] + +mov ax,#%1[bx] +mov %[bx|si|di]*,#%1+2[bx] += +mov eax,#%1[bx] + +mov [%1],ax +mov [%1+2],%[bx|si|di]* += +mov [%1],eax + +mov [%1+%3],ax +mov [%1+%(%3+2)],%[bx|si|di]* += +mov [%1+%3],eax + +mov %1[%[si|di|bp]3],ax +mov %(%1+2)[%[si|di|bp]3],%[bx|si|di]* += +mov %1[%3],eax + +mov #%1[bx],ax +mov #%1+2[bx],%[bx|si|di]* += +mov #%1[bx],eax + +mov eax,%[#|*]0%1 +mov %![dword ptr]%3[%2],eax += +mov dword ptr %3[%2],%0%1 + +xor ax,ax +xor %[bx|si|di]3,%[bx|si|di]3 +mov %1[%[bx|bp]4],ax +mov %(%1+2)[%[bx|bp]4],%[bx|si|di]3 += +mov dword ptr %1[%4],#0 + +mov ax,%1 +mov %[bx|si|di]5,%2 +mov %3[%[bx|bp]6],ax +mov %(%3+2)[%[bx|bp]6],%[bx|si|di]5 += +mov eax,dword ptr %1 +mov dword ptr %3[%6],eax + + +# Long return values are in EAX, so we can skip dx + +mov dx,bx +add sp,*%1 += +add sp,*%1 + + +# Rules for manipulating long values + +call %1 +mov bx,dx += +call %1 + +call l%[tstu|tst]*l += +test eax,eax + +call l%[comu|com]*l += +not eax + +mov eax,eax +%1 += +%1 + +mov %2,%[eax|ebx|ecx|edx]1 +mov %[eax|ebx|ecx|edx]1,%2 += +mov %2,%1 + +cwd +mov bx,dx += +cwde + +mov %[ebx|ecx|edx]0,%1 +mov eax,%2 +%3 eax,%[ebc|ecx|edx]0 += +mov eax,%2 +%3 eax,%1 + +%[movzx|movsx|mov]0 %[eax|ebx|ecx|edx]2,%4 +%[add|and|xor|sub|or]1 %[eax|ebx|ecx|edx]2,%6 +mov %6,%[eax|ebx|ecx|edx]2 += +%0 %2,%4 +%1 %6,%2 + +mov eax,%[#|*]0%1 +cmp eax,%2 +%[jbe |jae |jne |jge |jle ]3 %4 += +cmp dword ptr %2,%0%1 +%=[jbe |jae |jne |jge |jle ][jae |jbe |jne |jle |jge ]3 %4 + +mov eax,%[#|*]0%1 +cmp eax,%2 +%[jb |ja |je |jg |jl ]3 %4 += +cmp dword ptr %2,%0%1 +%=[jb |ja |je |jg |jl ][ja |jb |je |jl |jg ]3 %4 + +mov eax,%1[%3] +cmp eax,dword %[#|*]0%2 += +cmp dword ptr %1[%3],%0%2 + + +# Rules for calling the bcc library routines. + +push %1 +push %2 +mov eax,%3[bp] +%4 eax,%(%3-4)[bp] +add sp,*8 += +mov edx,%2 +mov eax,%1 +%4 eax,edx + +push %1 +mov eax,%2 +push eax +mov eax,%3[bp] +%4 eax,%(%3-4)[bp] +add sp,*8 += +mov edx,%2 +mov eax,%1 +%4 eax,edx + +push %1 +xor eax,eax +push eax +mov eax,%2[bp] +%3 eax,%(%2-4)[bp] +add sp,*8 += +mov eax,%1 +%3 eax,#0 + +push %1 +mov eax,%2 +%3 eax,%4[bp] +add sp,*4 += +mov edx,%1 +mov eax,%2 +%3 eax,edx + +push %1 +mov eax,%2 +%3 eax,%4[bp] +mov %2,eax +add sp,*4 += +mov edx,%1 +%3 %2,edx + + +push %1 +push %2 +mov eax,%3[bp] +%4 eax,%(%3-4)[bp] +lea sp,%(%3+4)[bp] += +mov edx,%2 +mov eax,%1 +%4 eax,edx + +push %1 +mov eax,%2 +push eax +mov eax,%3[bp] +%4 eax,%(%3-4)[bp] +lea sp,%(%3+4)[bp] += +mov edx,%2 +mov eax,%1 +%4 eax,edx + +push %1 +xor eax,eax +push eax +mov eax,%2[bp] +%3 eax,%(%2-4)[bp] +lea sp,%(%2+4)[bp] += +mov eax,%1 +%3 eax,#0 + +push %1 +mov eax,%2 +%3 eax,%4[bp] +lea sp,%(%4+4)[bp] += +mov edx,%1 +mov eax,%2 +%3 eax,edx + + +# Rules for calling the basic bcc library routines. + +mov di,#%2 +call l%3%[ul|l]* += +%3 eax,[%2] + +lea di,%2 +call l%3%[ul|l]* += +%3 eax,%2 + +mov di,%[si|di]1 +call l%3%[ul|l]* += +%3 eax,[%1] + +mov di,%[ax|bx|cx|dx]1 +call l%3%[ul|l]* += +mov di,%[ax|bx|cx|dx]1 +%3 eax,[di] + + +# Rules for pushing short values + +mov %[ax|bx|cx|dx|si|di]2,%0[%1] +push %[ax|bx|cx|dx|si|di]2 += +push word ptr %0[%1] + +mov %[ax|bx|cx|dx|si|di]2,%[#|*]0%1 +push %[ax|bx|cx|dx|si|di]2 += +push word %0%1 + + +# Shifting rules + +%[shl|shr]2 %1,*1 +%[shl|shr]2 %1,*1 += +%2 %1,*2 + +mov cl,*%1 +%[shl|shr]2 %3,cl += +%2 %3,*%1 + +mov dx,ax +shl ax,*%1 +add ax,dx +shl ax,*%2 += +mov dx,ax +imul ax,*%(1<%1+1<%2) + +mov dx,ax +imul ax,*%1 +add ax,dx += +mov dx,ax +imul ax,*%(%1+1) + +mov dx,ax +imul ax,*%1 +shl ax,*%2 += +mov dx,ax +imul ax,*%(%1<%2) + +mov ax,%![#|*]%4 +mov dx,ax +imul ax,*%1 +%[add|and|xor|sub|or]2 ax,%![dx]%3 += +imul ax,%4,*%1 +%2 ax,%3 + +mov ax,%![#|*]%4 +mov dx,ax +imul ax,*%1 +push ax += +imul ax,%4,*%1 +push ax + +imul ax,%2,%[#|*]0%1 +add ax,%3 +mov bx,ax += +imul bx,%2,%0%1 +add bx,%3 + + +# Different rules + +%1 dword ptr %[eax|ebx|ecx|edx]3,*%2 += +%1 %3,*%2 + +%1 dword ptr %[eax|ebx|ecx|edx]3,#%2 += +%1 %3,#%2 + +eor %1,%2 += +xor %1,%2 + +com %1 += +not %1 + diff --git a/copt/rules.86 b/copt/rules.86 new file mode 100644 index 0000000..d4fe131 --- /dev/null +++ b/copt/rules.86 @@ -0,0 +1,427 @@ +# Rules for optimizing BCC assembler output + +# Rules for loading short variables + +# Chad says this one (I think) is broken +# mov %0$0[%2],%3 +# = +# mov %0[%2],%3 + +mov %2,%[ax|bx|cx|dx]1 +mov %[ax|bx|cx|dx]1,%2 += +mov %2,%1 + +mov %[ax|bx|cx|dx]3,%[#|*]0%1 +mov %2[%4],%[ax|bx|cx|dx]3 += +mov word ptr %2[%4],%0%1 + +mov %[ax|bx|cx|dx]3,%[#|*]0%1 +mov %[ax|bx|cx|dx]2,%[ax|bx|cx|dx]3 += +mov %2,%0%1 + +mov al,%[#|*]0%1 +mov %2,al += +mov byte ptr %2,%0%1 + +xor ax,ax +mov bx,%[#|*]0%1 +mov [%2],ax +mov [%2+2],bx += +mov word ptr [%2],#0 +mov word ptr [%2+2],%0%1 + +mov ax,%[#|*]0%1 +xor bx,bx +mov [%2],ax +mov [%2+2],bx += +mov word ptr [%2],%0%1 +mov word ptr [%2+2],#0 + +mov ax,%[#|*]4%1 +mov bx,%[#|*]5%3 +mov [%2],ax +mov [%2+2],bx += +mov word ptr [%2],%4%1 +mov word ptr [%2+2],%5%3 + + +# Rules for incrementing short variables + +mov %[ax|bx]2,%1 +%[inc|dec]3 %[ax|bx]2 +mov %1,%[ax|bx]2 += +%3 word ptr %1 +mov %2,%1 + + +# Rules for manipulating characters + +inc %[si|di]* +inc %[si|di]* +mov al,-1[si] +mov -1[di],al += +cld +lodsb +stosb + +inc %[si|di]* +inc %[si|di]* +mov al,-1[di] +mov -1[si],al += +cld +xchg si,di +lodsb +stosb +xchg si,di + +inc si +mov al,-1[si] += +cld +lodsb + +inc di +mov -1[di],al += +cld +stosb + +dec %[si|di]* +dec %[si|di]* +mov al,1[si] +mov 1[di],al += +std +lodsb +stosb + +dec %[si|di]* +dec %[si|di]* +mov al,1[di] +mov 1[si],al += +std +xchg si,di +lodsb +stosb +xchg si,di + +dec si +mov al,1[si] += +std +lodsb + +dec di +mov 1[di],al += +std +stosb + + +# Rules for manipulating short values + +mov %[ax|bx]2,%1 +%[add|and|xor|sub|or]4 %[ax|bx]2,%3 +mov %1,%[ax|bx]2 += +mov %2,%3 +%4 %1,%2 + +mov %[ax|bx]2,%1 +%[add|and|xor|or]4 %[ax|bx]2,%3 +mov %3,%[ax|bx]2 += +mov %2,%1 +%4 %3,%2 + +mov %[ax|bx]4,%1 +%[add|and|xor|sub|or]2 %[si|di]3,%[ax|bx]4 += +%2 %3,%1 + +mov al,%1 +xor ah,ah +%[add|and|xor|sub|or]2 ax,%[#|*]0%3 +mov %1,al += +%2 byte ptr %1,%0%3 + + +# Rules for comparing short values + +mov %[ax|bx]3,%1[%4] +cmp %[ax|bx]3,%[#|*]0%2 += +cmp word ptr %1[%4],%0%2 + +mov al,%1[%4] +cmp al,%[#|*]0%2 += +cmp byte ptr %1[%4],%0%2 + +mov %[ax|bx]3,%[ax|bx|cx|dx|si|di]2 +cmp %[ax|bx]3,%1 += +cmp %2,%1 + + +# General comparison rules + +xor %1,%1 +mov %2,%3 +cmp %2,%1 += +mov %2,%3 +cmp %2,#0 + +mov %1,%[#|*]0%2 +mov %3,%4 +cmp %3,%1 += +mov %3,%4 +cmp %3,%0%2 + +mov %1,%2 +cmp %1,%[#|*]00 +%[jne |je ]4 %3 += +mov %1,%2 +test %1,%1 +%4 %3 + +%[and|xor|or]1 %2,%3 +test %2,%2 += +%1 %2,%3 + + +# General incrementation and decrementation rules + +inc %3 ptr %1 +mov %2,%1 +dec %2 += +mov %2,%1 +inc %3 ptr %1 + +dec %3 ptr %1 +mov %2,%1 +inc %2 += +mov %2,%1 +dec %3 ptr %1 + +mov %1,%2 +inc %3 ptr %2 +push %1 += +push %3 ptr %2 +inc %3 ptr %2 + +mov %1,%2 +dec %3 ptr %2 +push %1 += +push %3 ptr %2 +dec %3 ptr %2 + + +# Misc. rules + +push word %[#|*]0%1 +inc %[si|di]2 +inc %[si|di]2 +mov %[ax|bx|cx|dx]3,%*[bp] +mov %4[%[si|di]2],%[ax|bx|cx|dx]3 +inc sp +inc sp += +mov word ptr %(%4+2)[%2],%0%1 +inc %2 +inc %2 + +push %1 +mov %[ax|bx|cx|dx]3,%2 +%[add|sub|and|xor|or]4 %[ax|bx|cx|dx]3,%*[bp] +inc sp +inc sp += +mov %3,%2 +%4 %3,%1 + +push %1 +mov %[ax|bx|cx|dx]3,%2 +%[add|sub|and|xor|or]5 %[ax|bx|cx|dx]3,%6 +%[add|sub|and|xor|or]4 %[ax|dx|cx|dx]3,%*[bp] +inc sp +inc sp += +mov %3,%2 +%5 %3,%6 +%4 %3,%1 + +push %1 +mov %[ax|bx|cx|dx]3,%*[bp] +%[add|sub|and|xor|or]4 %2,%[ax|bx|cx|dx]3 +inc sp +inc sp += +mov %3,%1 +%4 %2,%3 + +mov %1,%[ax|bx|cx|dx]2 +push %1 += +mov %1,%2 +push %2 + + +# Rules to remove superflous mov instructions + +mov %1,%2 +mov %1,%2 += +mov %1,%2 + +mov %1,%2 +.%3: +mov %1,%2 += +.%3: +mov %1,%2 + +mov %1,%2 +mov %2,%1 += +mov %1,%2 + +mov %1,%[ax|bx|cx|dx|eax|ebx|ecx|edx]2 +mov %[ax|bx|cx|dx|eax|ebx|ecx|edx]3,%1 += +mov %1,%2 +mov %3,%2 + +mov %1,%1 += +!mov %1,%1 + +# Sometimes the compiler puts a jump right after a ret or another jump +# (in if-else-if constructions). Eliminate the second unnecessary jump. +# Also it puts a jump to the next instruction in extensive if-else +# constructions. That jump can also be removed. + +jmp .%1 +jmp .%2 += +jmp %1 + +ret +jmp %2 += +ret + +jmp .%1 +.%1: += +.%1 + +jmp .%1 +.%2: +.%1: += +.%2: +.%1: + +jmp .%1 +.%3: +.%2: +.%1: += +.%3: +.%2: +.%1: + + +# When using register variables the compiler initializes them when +# they are found in the source code, and sets up the stack frame for +# other local variables lateron. Move initialization of register variables +# behind the add-sp instruction to make further optimization easier. + +proc_start +mov %[si|di]3,%1 +add sp,*%2 += +proc_start +add sp,*%2 +mov %3,%1 + +proc_start +mov %[si|di]3,%1 +dec sp +dec sp += +proc_start +dec sp +dec sp +mov %3,%1 + +add sp,*%1 +add sp,*%2 += +add sp,*%1+%2 + +dec sp +dec sp +add sp,*%1 += +add sp,*%1-2 + +add sp,*%1 +dec sp +dec sp += +add sp,*%1-2 + +inc sp +inc sp +%1 %2 +inc sp +inc sp += +%1 %2 +add sp,*4 + +inc sp +inc sp +%1 %2 +add sp,*%3 += +%1 %2 +add sp,*%3+2 + +add sp,*%3 +%1 %2 +inc sp +inc sp += +%1 %2 +add sp,*%3+2 + +add sp,*%3 +%1 %2 +add sp,*%4 += +%1 %2 +add sp,*%3+%4 + diff --git a/copt/rules.end b/copt/rules.end new file mode 100644 index 0000000..cd93d4e --- /dev/null +++ b/copt/rules.end @@ -0,0 +1,18 @@ +# Rules to optimize BCC assembler output + +# Redo the changes done in rules.start + +proc_start += +push bp +mov bp,sp +push di +push si + +proc_end += +pop si +pop di +pop bp +ret + diff --git a/copt/rules.inl b/copt/rules.inl new file mode 100644 index 0000000..8a3e218 --- /dev/null +++ b/copt/rules.inl @@ -0,0 +1,8 @@ + +mov ax,%1 +mov bx,%2 +call isr += +mov ax,%1 +mov cx,%2 +sar ax,cl diff --git a/copt/rules.net b/copt/rules.net new file mode 100644 index 0000000..356f90d --- /dev/null +++ b/copt/rules.net @@ -0,0 +1,42 @@ +# Rules for optimizing BCC assembler output + +# Rules for converting short number from host to network order + +push word %[#|*]0%1 +call __htons +inc sp +inc sp += +mov ax,#((%1 & $00FF) << 8) + ((%1 & $FF00) >> 8) + +mov ax,%[#|*]0%1 +push ax +call __htons +inc sp +inc sp += +mov ax,#((%1 & $00FF) << 8) + ((%1 & $FF00) >> 8) + +push %0[%1] +call __htons +inc sp +inc sp += +mov ax,%0[%1] +xchg al,ah + +push ax +call __htons +inc sp +inc sp += +xchg al,ah + +push %[bx|cx|dx]1 +call __htons +inc sp +inc sp += +mov ax,%1 +xchg al,ah + diff --git a/copt/rules.start b/copt/rules.start new file mode 100644 index 0000000..f494305 --- /dev/null +++ b/copt/rules.start @@ -0,0 +1,19 @@ +# Rules to optimize BCC assembler output + +# The following rules protect the procedure prolog and epilogue from +# getting optimized away in later steps + +push bp +mov bp,sp +push di +push si += +proc_start + +pop si +pop di +pop bp +ret += +proc_end + |