summaryrefslogtreecommitdiff
path: root/copt
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>1997-02-25 20:42:19 +0100
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:38:07 +0200
commit4c36e9a0c125ccfff37aa440dab2cf58c4152fff (patch)
treea5d9c84ba2661029ddb2223dacd50529a361c3d5 /copt
parentf8de35da65c5d93bb733073cf40da154bc1c0748 (diff)
parent9696d7b0e1f3a1b0f5fd4a0428eb75afe8ad4ed6 (diff)
downloaddev86-4c36e9a0c125ccfff37aa440dab2cf58c4152fff.tar.gz
Import Dev86src-0.0.11.tar.gzv0.0.11
Diffstat (limited to 'copt')
-rw-r--r--copt/Makefile6
-rw-r--r--copt/README25
-rw-r--r--copt/copt.c826
-rw-r--r--copt/rules.386427
-rw-r--r--copt/rules.86427
-rw-r--r--copt/rules.end18
-rw-r--r--copt/rules.inl8
-rw-r--r--copt/rules.net42
-rw-r--r--copt/rules.start19
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
+