koreth@panarthea.ebay.sun.com (Steven Grimm) (10/26/89)
Submitted-by: ncar.ucar.edu!dunike!onecom!wldrdg!hans (Johann Ruegg) Posting-number: Volume 2, Issue 97 Archive-name: sozobon1.2/part06 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 6 (of 9)." # Contents: hcc/OUT_ST.C top/BRANCH.C top/PEEP3.C # Wrapped by koreth@panarthea on Tue Oct 24 18:40:46 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'hcc/OUT_ST.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hcc/OUT_ST.C'\" else echo shar: Extracting \"'hcc/OUT_ST.C'\" \(12658 characters\) sed "s/^X//" >'hcc/OUT_ST.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X * X * out.c X * X * Code generation output routines. X */ X X#include <stdio.h> X#include "param.h" X#include "nodes.h" X#include "flags.h" X#include "bstok.h" X#include "tytok.h" X#include "gen.h" X X#if dLibs X#include <ctype.h> X#endif X X#if MMCC Xoverlay "pass2" X#endif X X#if CC68 XFILE *fopen(); X#endif X X#if NEEDBUF Xchar my_obuf[BUFSIZ]; X#endif X X#define T_SEG 0 X#define D_SEG 1 X#define B_SEG 2 X X#define TO_TEXT to_seg(T_SEG) X#define TO_DATA to_seg(D_SEG) X#define TO_BSS to_seg(B_SEG) X X#define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG) X Xextern FILE *output; X Xstatic int in_seg; Xstatic int lblnum; Xstatic int dat_size; X Xout_start(outs) Xchar *outs; X{ X register int len; X char suff; X#ifdef MINIX X extern char tmpdir[]; X#endif X char oname[128]; X X len = strlen(outs); X if (len >= 2 && outs[len-2] == '.') { X suff = outs[len-1]; X if (suff != 'c' && suff != 'C') X fatals("Invalid suffix", outs); X#ifdef MINIX X sprintf(oname, "%s/%s", tmpdir, outs); X len = strlen(oname); X#else X strcpy(oname, outs); X#endif X oname[len-1] = 's'; X output = fopen(oname, "w"); X if (output == NULL) X fatals("Cant open", oname); X#if NEEDBUF X setbuf(output, my_obuf); X#endif X } else X output = stdout; X X in_seg = -1; X lblnum = 0; X dat_size = 0; X} X Xout_end() X{ X if (output != stdout) X fclose(output); X} X Xstatic char *sg_go[] = { X ".text", X ".data", X ".bss" X}; X Xto_text() X{ X TO_TEXT; X} X Xto_seg(sg) X{ X if (sg == in_seg) X return; X fprintf(output, "\t%s\n", sg_go[sg]); X in_seg = sg; X} X Xo_aln(x) X{ X if (x && (dat_size & 1)) { X dat_size++; X TO_DATA; X fprintf(output, "\t.even\n"); X } X} X Xchar *rnms[] = { X "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", X "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", X}; X Xchar *regnm(n) X{ X return rnms[n]; X} X X#define regnm(x) rnms[x] X Xchar * Xinit_str(n) X{ X char *s; X X switch (n) { X case 1: X s = ".dc.b"; break; X case 2: X s = ".dc.w"; break; X default: X s = ".dc.l"; break; X } X return s; X} X Xtlen(n) X{ X switch (n) { X case 1: X return 'b'; X case 2: X return 'w'; X default: X return 'l'; X } X} X Xo_vinit(tp, xp) XNODEP tp, xp; X{ X fprintf(output, "\t%s\t", init_str((int)tp->t_size)); X dat_size += tp->t_size; X X p2_expr(&xp); X asn_chk(tp, xp); X to_init(xp, tp); X X fputc('\n', output); X} X Xto_init(np, typ) XNODEP np, typ; X{ X NODEP tp; X X tp = allocnode(); X tp->e_token = TCONV; X tp->n_tptr = typ; X tp->n_flags |= N_COPYT; X tp->n_left = np; X tp->e_type = E_UNARY; X strcpy(tp->n_name, "i cast"); X X genx(tp, FORINIT); X} X Xout_advice(np) XNODEP np; X{ X long size; X X size = np->n_tptr->t_size; X if (size == 0) X return; X X switch (np->e_sc) { X case K_AUTO: X fprintf(output, ";var\t%d\t%d\t", (int)size, X (int)np->e_offs); X break; X case K_REGISTER: X fprintf(output, ";reg\t%d\t%s\t", (int)size, X regnm(np->e_rno)); X break; X default: X return; X } X out_nm(np); X fputc('\n', output); X} X Xout_argreg(np) XNODEP np; X{ X fprintf(output, "\tmove.%c\t%d(%s),%s\n", X tlen((int)np->n_tptr->t_size), (int)np->e_offs, X regnm(FRAMEP), regnm(np->e_rno)); X} X Xout_fstart(np) XNODEP np; X{ X extern int pflag; X X TO_TEXT; X if (np->e_sc != K_STATIC) { X fprintf(output, "\t.globl\t"); X und_nnm(np); X fputc('\n', output); X } X und_nnm(np); X fprintf(output, ":\n"); X X if (pflag) { X int tlab = new_lbl(); X X TO_BSS; X fprintf(output, "L%d:\t.ds.l\t1\n", tlab); X TO_TEXT; X fprintf(output, "\tmove.l\t#"); X und_nnm(np); X fprintf(output, ",a0\n"); X X fprintf(output, "\tmove.l\t#L%d,a1\n", tlab); X fprintf(output, "\tjsr\tmcount\n"); X } X} X Xstatic char rbuf[30]; X Xchar * Xregstr(regs) X{ X int lod, hid, loa, hia; X register i; X char *bp = rbuf; X X lod = 999; X hid = -1; X for (i=DRV_START; i<=DRV_END; i++) X if (regs & (1<<i)) { X if (i < lod) lod = i; X if (i > hid) hid = i; X } X loa = 999; X hia = -1; X for (i=ARV_START; i<=ARV_END; i++) X if (regs & (1<<i)) { X if (i < loa) loa = i; X if (i > hia) hia = i; X } X if (lod < 999) { X if (lod != hid) X sprintf(bp, "%s-%s", rnms[lod], rnms[hid]); X else X sprintf(bp, "%s", rnms[lod]); X if (loa < 999) { X bp += strlen(rbuf); X *bp++ = '/'; X } X } X if (loa < 999) { X if (loa != hia) X sprintf(bp, "%s-%s", rnms[loa], rnms[hia]); X else X sprintf(bp, "%s", rnms[loa]); X } X return rbuf; X} X Xout_fend(regs, lsize) Xlong lsize; X{ X if (lsize < 0x7fff) X fprintf(output, "\tlink\t%s,#-%d\n", rnms[FRAMEP], (int)lsize); X else X fprintf(output, "\tlink\t%s,#0\n\tsub.l\t#%ld,sp\n", X rnms[FRAMEP], lsize); X if (regs) X fprintf(output, "\tmovem.l\t%s,-(sp)\n", regstr(regs)); X} X Xout_fret(regs, strl) X{ X if (regs) X fprintf(output, "\tmovem.l\t(sp)+,%s\n", regstr(regs)); X if (strl) X fprintf(output, "\tmove.l\t#L%d,a0\n", strl); X fprintf(output, "\tunlk\t%s\n\trts\n", rnms[FRAMEP]); X} X Xout_fs(strl, size) Xlong size; X{ X TO_BSS; X def_lbl(strl); X if (size & 1) X fprintf(output, "\t.ds.b\t%ld\n", size); X else X fprintf(output, "\t.ds.w\t%ld\n", size/2); X} X Xout_gv(np, isbss) Xregister NODEP np; X{ X long sz; X char c; X X if (np->e_sc == K_STATIC) { X np->e_offs = lblnum++; X } X if (np->e_sc != K_EXTERN) { X to_seg(isbss ? B_SEG : D_SEG); X if (np->e_sc != K_STATIC) { X fprintf(output, "\t.globl\t"); X out_nm(np); X fputc('\n', output); X } X if (isbss) { X if (np->e_sc == K_STATIC) { X out_nm(np); X sz = np->n_tptr->t_size; X c = 'b'; X if (np->n_tptr->t_aln) { X c = 'w'; X sz /= 2; X } X fprintf(output, ":\t.ds.%c\t%ld\n", c, sz); X } else { X fprintf(output, "\t.comm\t"); X out_nm(np); X sz = np->n_tptr->t_size; X if (sz & 1) sz++; /* ALCYON hack */ X fprintf(output, ",%ld\n", sz); X } X } else { X out_nm(np); X fprintf(output, ":\n"); X } X } X} X Xnew_lbl() X{ X return lblnum++; X} X Xdef_lbl(l) X{ X fprintf(output, "L%d:\n", l); X} X Xout_br(l) X{ X if (l < 0) X error("bad branch"); X else X fprintf(output, "\tbra\tL%d\n", l); X} X Xstatic char *bnm[] = { X "", X "beq", X "bne", X "blt", X "bge", X "ble", X "bgt", X "bra", X "nop", X "bcs", X "bcc", X "bls", X "bhi" X}; X Xstatic char *snm[] = { X "", X "seq", X "sne", X "slt", X "sge", X "sle", X "sgt", X "", X "", X "scs", X "scc", X "sls", X "shi" X}; X Xout_b(key, l) X{ X if (key != B_NO) X fprintf(output, "\t%s\tL%d\n", bnm[key], l); X} X Xout_bnol(key) X{ X fprintf(output, "\t%s\t", bnm[key]); X} X Xout_snol(key) X{ X fprintf(output, "\t%s\t", snm[key]); X} X Xout_d0cmp(x) X{ X fprintf(output, "\tcmp.w\t#%d,d0\n", x); X} X Xout_d0sub(x) X{ X fprintf(output, "\tsub.w\t#%d,d0\n", x); X} X Xout_tlbl(l) X{ X fprintf(output, "\t.dc.l\tL%d\n", l); X} X Xout_tsw() X{ X fprintf(output, "\text.l\td0\n"); X fprintf(output, "\tasl.l\t#2,d0\n"); X fprintf(output, "\tmove.l\t4(pc,d0.l),a0\n"); X fprintf(output, "\tjmp\t(a0)\n"); X} X Xout_nm(np) XNODEP np; X{ X if (np->e_sc == K_STATIC) X fprintf(output, "L%d", (int)np->e_offs); X else X und_nnm(np); X} X Xout_zi(tp) XNODEP tp; X{ X char *s; X/* X switch (tp->t_token) { X case K_FLOAT: X fprintf(output, "\t.float\t0.0\n"); return; X case K_DOUBLE: X fprintf(output, "\t.double\t0.0\n"); return; X } X*/ X dat_size += tp->t_size; X s = init_str((int)tp->t_size); X fprintf(output, "\t%s\t0\n", s); X} X Xo_nz(sz, aln) Xlong sz; X{ X dat_size += sz; X if (aln) { X if (sz & 1) X fprintf(output, "\t.ds.b\t1\n"); X sz >>= 1; X fprintf(output, "\t.ds.w\t%ld\n", sz); X } else { X fprintf(output, "\t.ds.b\t%ld\n", sz); X } X} X Xdumpstrs(np) XNODEP np; X{ X TO_DATA; Xmore: X if (np == NULL) X return; X fprintf(output, "L%d:", (int)np->g_offs); X out_scon(np); X np = np->n_next; X goto more; X} X Xint see_esc; X Xout_scon(np) XNODEP np; X{ X int len = 0; X X if (np == NULL) X return 0; X see_esc = 0; Xmore: X if (np->n_name[0]) { X fprintf(output, "\t.dc.b\t"); X len += out_str(np->n_name); X putc('\n', output); X } X np = np->n_nmx; X if (np) X goto more; X X fprintf(output, "\t.dc.b\t0\n"); X len++; X dat_size += len; X return len; X} X Xout_str(s) Xchar *s; X{ X int len; X register c; X X len = 0; X for ( ; c = *s; s++) { X if (see_esc) { /* allow null */ X c--; X see_esc = 0; X } else if (c == 1) { X see_esc = 1; X continue; X } X if (len) { X if ((len & 15) == 0) X fprintf(output, "\n\t.dc.b\t"); X else X putc(',', output); X } X out_1c(c); X len++; X } X return len; X} X Xout_asm(np) XNODEP np; X{ X putc('\t', output); Xmore: X fprintf(output, "%s", np->n_name); /* no \0 or \1 please! */ X np = np->n_nmx; X if (np) X goto more; X putc('\n', output); X} X Xund_nnm(np) XNODEP np; X{ X fputc('_', output); X fput_nnm(np); X} X Xout_1c(c) Xchar c; X{ X fprintf(output, "$%x", c & 0xff); X} X Xoutcode(np) Xregister NODEP np; X{ X NODEP tp; X X if (np == NULL) return; X X switch (np->g_type) { X case EV_NONE: X break; X case EV_RL: X outcode(np->n_right); X outsub(np->g_betw, np); X /* fall through */ X case EV_LEFT: X outcode(np->n_left); X break; X case EV_LR: X case EV_LRSEP: X outcode(np->n_left); X outsub(np->g_betw, np); X /* fall through */ X case EV_RIGHT: X outcode(np->n_right); X break; X default: X printf("bad eval %d ", np->g_type); X } X if (np->n_flags & N_COPYT) /* g_code is a char * */ X outsub(np->g_code, np); X else /* g_code is a list of nodes */ X for (tp=np->g_code; tp != NULL; tp = tp->g_code) X outsub(tp->n_name, np); X} X Xoutsub(cp, np) Xregister char *cp; Xregister NODEP np; X{ X register char c; X X if (cp == NULL) return; X while (c = *cp++) X if (c == '<') X out_let(*cp++, np->n_left); X else if (c == '>') X out_let(*cp++, np->n_right); X else if (c == '\'') { X c = *cp++; X fputc(c, output); X } else if (c == 'L') X seelab(*cp++, np); X else if (c == 'R') X seereg(np, *cp++); X else if (c >= 'A' && c <= 'Z') { X out_let(c, np); X } else X fputc(c, output); X} X Xseereg(np, c) XNODEP np; X{ X int i; X X switch (c) { X case '0': i = np->g_rno; break; X case '1': i = np->g_r1; break; X case '2': i = np->g_r2; break; X } X fprintf(output, regnm(i)); X} X Xout_let(c, np) Xregister NODEP np; X{ X int i; X X switch (c) { X case 'A': X if (np->g_flags & IMMEDID) X fputc('#', output); X out_a(np, output); X break; X case 'E': X case 'F': /* branch if false */ X i = cctok(np); X i = (i&1) ? i+1 : i-1; /* reverse truth */ X if (c == 'F') X out_bnol(i); X else X out_snol(i); X break; X case 'H': /* last a reg (for struct assign) */ X fprintf(output, regnm(ARV_START-1)); X break; X case 'K': X fprintf(output, "%ld", np->g_bsize); X break; X case 'N': X fprintf(output, "%s", np->n_name); X break; X case 'O': X fprintf(output, "%ld", np->g_offs); X break; X case 'Q': X if (np->g_flags & IMMEDID) { X warn("constant test expr"); X if (np->g_token == ICON && np->g_offs == 0) X fprintf(output, "\tor\t#$FF,ccr\n"); X else X fprintf(output, "\tand\t#0,ccr\n"); X return; X } X fprintf(output, "\t%s.%c\t", isareg(np) ? "cmp" : "tst", X tlen(np->g_sz)); X if (isareg(np)) X fprintf(output, "#0,"); X out_let('A', np); X fputc('\n', output); X break; X case 'S': X fputc(tlen(np->g_sz), output); X break; X case 'T': /* branch if true */ X out_bnol(cctok(np)); X break; X case 'U': X fputc(np->g_ty == ET_U ? 'u' : 's', output); X break; X case 'W': /* field width 1's */ X fprintf(output, "$%x", ones(np->g_fldw)); X break; X case 'X': /* ~(W << offset) */ X fprintf(output, "$%x", (unsigned short) X (~(ones(np->g_fldw)<<np->g_fldo))); X break; X case 'Y': /* field offset */ X fprintf(output, "%d", np->g_fldo); X break; X case 'Z': /* field offset - 8 */ X fprintf(output, "%d", np->g_fldo - 8); X break; X default: X printf("bad out_let %c ", c); X } X} X Xout_a(np, fd) Xregister NODEP np; XFILE *fd; X{ X int offs = np->g_offs; X X switch (np->g_token) { X case ICON: X fprintf(fd, "%ld", np->g_offs); X break; X case FCON: X /* works for ALCYON C */ X /* otherwise depends on floating internal format */ X fprintf(fd, "$%lx", np->g_offs); X break; X case ONAME: X while (np->g_flags & (CHILDNM|RCHILDNM)) { X np = (np->g_flags & CHILDNM) ? X np->n_left : np->n_right; X } X qput_nnm(np, fd); X if (offs) X fprintf(fd, offs > 0 ? "+%d" : "%d", offs); X break; X case PUSHER: X fprintf(fd, "(sp)+"); X break; X case OREG: X if (offs) X fprintf(fd, "%d", offs); X fprintf(fd, "(%s)", regnm(np->g_rno)); X break; X case REGVAR: X fprintf(fd, regnm(np->g_rno)); X break; X case ',': X fputc(',', fd); /* for debug */ X break; X default: X if (np->g_token >= BR_TOK) { X fprintf(fd, "B_%s", bnm[np->g_token - BR_TOK]); X break; X } X printf("? tok %d ", np->g_token); X } X} X Xseelab(c, np) Xchar c; XNODEP np; X{ X c -= '1'; X fprintf(output, "L%d", (int)np->g_bsize+c); X} X Xones(n) X{ X return (1 << n) - 1; X} X END_OF_FILE if test 12658 -ne `wc -c <'hcc/OUT_ST.C'`; then echo shar: \"'hcc/OUT_ST.C'\" unpacked with wrong size! fi # end of 'hcc/OUT_ST.C' fi if test -f 'top/BRANCH.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'top/BRANCH.C'\" else echo shar: Extracting \"'top/BRANCH.C'\" \(12147 characters\) sed "s/^X//" >'top/BRANCH.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X */ X#include "top.h" X X#define TOUCHED(bp) ((bp)->flags & B_TOUCHED) X X/* X * bcomp(bc) - return the complement of the given branch code X * X * Used when a branch reversal is needed. X */ Xstatic int Xbcomp(bc) Xregister int bc; X{ X switch (bc) { X case BHI: return BLS; X case BLS: return BHI; X case BCC: return BCS; X case BCS: return BCC; X case BNE: return BEQ; X case BEQ: return BNE; X case BVC: return BVS; X case BVS: return BVC; X case BPL: return BMI; X case BMI: return BPL; X case BGE: return BLT; X case BLT: return BGE; X case BGT: return BLE; X case BLE: return BGT; X default: X fprintf(stderr, "bcomp() - bad branch code %d\n", bc); X exit(1); X } X} X X/* X * isbranch(s) - determines if 's' is a branch opcode X * X * Returns 1 for branches whose destination is the first operand, X * and 2 for branches whose dest. is the second. X */ Xstatic int Xisbranch(c) Xregister int c; X{ X switch (c) { X case BRA: case BHI: case BLS: case BCC: X case BCS: case BNE: case BEQ: case BVC: X case BVS: case BPL: case BMI: case BGE: X case BLT: case BGT: case BLE: X return 1; X X case DBRA: case DBHI: case DBLS: case DBCC: X case DBCS: case DBNE: case DBEQ: case DBMI: X case DBGE: case DBLT: case DBGT: case DBLE: X case DBT: X return 2; X X default: X return 0; X } X} X X/* X * cblock(cp) - return the first block containing some code X * X * Starting with 'cp', find a block that has one or more instructions X * in it. This is useful to collapse multiple null blocks into a single X * logical point. This happens at points in the generated code where X * there are multiple labels at the same logical location. X */ Xstatic BLOCK * Xcblock(bp) Xregister BLOCK *bp; X{ X while (bp->first == NULL && bp->bcond == NULL) { X if (bp->bfall == NULL) { X fprintf(ofp, "cblock() - error in block %s\n", X bp->name); X exit(1); X } X bp = bp->bfall; X } X X return bp; X} X X/* X * bsplit() - split up blocks with branches inside them X * X * Look for branch instructions in each block. If somewhere in the middle of X * the block, split up the block. When done, the blocks are broken down into X * true basic blocks. X */ Xstatic void Xbsplit(bp) XBLOCK *bp; X{ X register BLOCK *cp; /* the current block */ X register BLOCK *np; /* new block (if needed) */ X register INST *ip; /* current instruction */ X X for (cp = bp; cp != NULL ;cp = cp->chain) { X for (ip = cp->first; ip != NULL ;ip = ip->next) { X if (isbranch(ip->opcode) && ip->next != NULL) { X np = mksym(mktmp()); X X np->chain = cp->chain; X cp->chain = np; X X np->next = cp->next; X cp->next = np; X X np->first = ip->next; X np->first->prev = NULL; X np->last = cp->last; X X cp->last = ip; X cp->last->next = NULL; X X } else if (ip->opcode == DC) { X BLOCK *db; X X /* X * If the instruction is part of a branch X * table, both the current block and the X * destination need to be marked as "reached". X */ X cp->flags |= B_ISREACHED; X X if ((db = getsym(ip->src.astr)) != NULL) X db->flags |= B_ISREACHED; X else { X fprintf(stderr, X "bsplit() - symbol '%s' not found\n", X ip->src.astr); X exit(1); X } X } X } X } X} X X/* X * bfix() - fix up the branch pointers X * X * Go through each block setting up 'bcond' and 'bfall' properly. If the X * last instruction in the block is an unconditional branch, remove it X * and set 'bfall' instead. The idea is that there should be no branch X * instructions left when we're done. We remember the logical effect of X * each branch, but reconstruct the branches later in a more optimal way. X */ Xstatic void Xbfix(bp) Xregister BLOCK *bp; X{ X register BLOCK *cp; /* current block */ X register INST *ip; /* current instruction */ X X for (cp = bp; cp != NULL ;cp = cp->chain) { X X /* no instructions in the block */ X if (cp->first == NULL) { X cp->bcond = NULL; X cp->bfall = cp->next; X continue; X } X X /* the last instruction is a "return" */ X if (cp->last->opcode == RTS) { X cp->bcond = cp->bfall = NULL; X cp->flags |= B_RET; X continue; X } X X /* the last instruction isn't a branch */ X if (!isbranch(cp->last->opcode)) { X cp->bcond = NULL; X cp->bfall = cp->next; X continue; X } X X /* X * If we reach this point, then we've got a branch we need X * to remove at the end of this block. X */ X cp->bfall = cp->next; X if (isbranch(cp->last->opcode) == 1) { X cp->bcode = cp->last->opcode; X cp->bcond = getsym(cp->last->src.astr); X } else { X cp->bcode = -1; X cp->bcond = getsym(cp->last->dst.astr); X } X X if (cp->bcond == NULL) { X fprintf(stderr, "top: branch to bad label '%s'\n", X cp->last->src.astr); X exit(1); X } X X if (cp->bcode < 0) X continue; X X for (ip = cp->first; ip != NULL ;ip = ip->next) { X if (ip->next == cp->last) { X ip->next = NULL; X break; X } X } X free(cp->last->src.astr); X free(cp->last); X X if (cp->first == cp->last) X cp->first = cp->last = NULL; X else X cp->last = ip; X /* X * If the branch was unconditional, we want to represent X * it as a "fall through", so fix the pointers to do that. X */ X if (cp->bcode == BRA) { X s_bdel++; X cp->bfall = cp->bcond; X cp->bcond = NULL; X } X } X} X X/* X * bclean() - remove references to empty blocks X * X * Called after bsplit() and bfix(). X */ Xstatic void Xbclean(bp) Xregister BLOCK *bp; X{ X register BLOCK *cp; X X /* X * First clean up references to empty blocks X */ X for (cp = bp; cp != NULL ;cp = cp->chain) { X if (cp->bcond != NULL) X cp->bcond = cblock(cp->bcond); X if (cp->bfall != NULL) X cp->bfall = cblock(cp->bfall); X } X X /* X * Now there are generally blocks that are still linked by the X * 'chain' pointers, but no longer referenced through 'bcond' X * or 'bfall' pointers. They don't actually need to be deleted X * since they won't cause trouble anywhere else. X */ X} X X#if 0 X/* X * reachable(p1, p2) - is p2 reachable (with constraints) from p1 X * X * Try to reach p2 from p1 by following the 'bfall' pointers, without X * going through a block that has already been touched. We stop searching X * after a while since this function doesn't have to be perfect, and we're X * mainly interested in improving small loops anyway. X */ Xstatic bool Xreachable(p1, p2) Xregister BLOCK *p1, *p2; X{ X register int i; X X for (i=0; (i < 40) && (p1 != NULL) ;i++, p1 = p1->bfall) { X X if (TOUCHED(p1)) X return FALSE; X X if (p1 == p2) X return TRUE; X } X return FALSE; X} X#endif X X/* X * bwalk() - recursive walk through the branch graph X * X * Starting at the entry point, walk through the block graph placing X * blocks on the output list. By traversing the "bfall" nodes first X * we attempt to make blocks that fall through come in order so that X * branches are minimized. X * X * Joe describes this process as "grabbing the tree at the top and X * shaking". X * X * The 'lp' variable below maintains our position in the generated list X * of blocks. X */ Xstatic BLOCK *lp; /* pointer to the next block in the file */ X Xstatic bwalk(p) Xregister BLOCK *p; X{ X if (p == NULL || TOUCHED(p)) X return; X X#if 0 X /* X * The following code still needs some work, so it is disabled X * for now... X */ X /* X * Check to see if loop rotation is required. We "rotate" the loop X * by skipping the current node and traversing the 'bfall' node, X * and then the 'bcond' node. The function reachable() tells us X * that there's a loop through the 'bfall' nodes allowing us to X * make this optimization. The net result is that we try to move X * conditional branches to the bottoms of loops making the loop X * one instruction shorter. The overall number of branches remains X * the same. X * X * Rather than marking all the nodes again within the function X * "reachable", we just give up after a while if no loop is X * detected. This isn't perfect, but we get the biggest gain in X * small loops, and these will be detected accurately. X */ X if (do_lrot && p->bcond != NULL && reachable(p->bfall, p)) { X s_lrot++; X bwalk(p->bfall); X bwalk(p->bcond); X return; X } X#endif X X p->flags |= B_TOUCHED; X lp->next = p; X lp = lp->next; X X /* X * We should swap 'bfall' and 'bcond' and alter 'bcode' IF: X * X * 1. Both bfall and bcond are non-null. X * 2. The branch is a simple one (not a DBcc inst.) X * 3. Branch reversals are enabled. X * 4. The block at bfall has already been touched. X * 5. The block at bcond hasn't been touched. X * X * In this case, we can avoid an extra branch if we reverse the X * sense of the conditional branch, and swap the pointers. X */ X if (p->bfall != NULL && p->bcond != NULL && p->bcode >= 0 && X do_brev && TOUCHED(p->bfall) && !TOUCHED(p->bcond)) { X register BLOCK *tmp; X X s_brev++; X tmp = p->bfall; X p->bfall = p->bcond; X p->bcond = tmp; X if ((p->bcode = bcomp(p->bcode)) < 0) { X fprintf(stderr, "top: internal error in bwalk()\n"); X exit(1); X } X } X bwalk(p->bfall); X bwalk(p->bcond); X} X X/* X * bsort() - branch optimization X * X * Initialize and terminate the 'next' pointers before and after X * traversing the branch graph. X */ Xstatic void Xbsort(bp) Xregister BLOCK *bp; X{ X register BLOCK *cb; X X lp = bp; X X bwalk(bp); /* traverse the tree starting at the entry point */ X X /* X * Now look for other parts of the tree that don't appear to be X * reachable, but really are. This can happen through the jump X * tables created for switch statements. For each such block, X * walk the subtree starting with it. X */ X for (cb = bp; cb != NULL ;cb = cb->chain) { X if (!TOUCHED(cb) && (cb->flags & B_ISREACHED)) X bwalk(cb); X } X X lp->next = NULL; X} X X/* X * bsetlab() - figure out which blocks really need labels X * X * This can be called AFTER bsort() to mark the blocks that are going to X * need labels. Anything that we're going to branch to later gets a label. X */ Xstatic void Xbsetlab(bp) Xregister BLOCK *bp; X{ X for (; bp != NULL ;bp = bp->next) { X if (bp->bcond != NULL) X cblock(bp->bcond)->flags |= B_LABEL; X if (bp->bfall != NULL && bp->bfall != bp->next) X cblock(bp->bfall)->flags |= B_LABEL; X /* X * If the block is reached via a jump table, then we X * need a label on THIS block directly. X */ X if (bp->flags & B_ISREACHED) X bp->flags |= B_LABEL; X } X} X X/* X * bjoin() - join blocks that always come together X * X * If block 'b' always follows block 'a' unconditionally, then move the X * instructions in 'b' to the end of 'a', and remove 'b'. This allows us X * to do better peephole optimization since we can optimize sequences that X * used to span blocks. X */ Xbjoin(bp) Xregister BLOCK *bp; X{ X BLOCK *np, *bnext; X X for (; bp != NULL ;bp = bnext) { X bnext = bp->next; X X /* X * First block can't end with a conditional branch. X */ X if (bp->bcond != NULL) X continue; X X /* X * Block must fall through to the next thing in the file. X */ X if (bp->next == NULL || bp->next != bp->bfall) X continue; X X np = bp->next; X X /* X * Second block can't be the destination of a branch. X */ X if (np->flags & B_LABEL) X continue; X X /* X * Join the blocks... X */ X if (np->first != NULL) X np->first->prev = bp->last; X X if (bp->last != NULL) X bp->last->next = np->first; X else { X bp->first = np->first; X bp->last = np->last; X } X X if (np->flags & B_RET) X bp->flags |= B_RET; X X bp->last = np->last; X bp->bfall = np->bfall; X bp->bcond = np->bcond; X bp->bcode = np->bcode; X bp->next = np->next; X X /* X * Fix pointers so we don't free the instructions X * twice later on. X */ X np->first = NULL; X np->last = NULL; X X /* X * If we've done a join, then we want to loop again on X * the current block to see if any others can be joined. X */ X bnext = bp; X } X} X X/* X * bopt() - coordinates branch optimization for the given function X */ Xvoid Xbopt(bp) Xregister BLOCK *bp; X{ X bsplit(bp); X bfix(bp); X bclean(bp); X bsort(bp); X bsetlab(bp); X bjoin(bp); X} END_OF_FILE if test 12147 -ne `wc -c <'top/BRANCH.C'`; then echo shar: \"'top/BRANCH.C'\" unpacked with wrong size! fi # end of 'top/BRANCH.C' fi if test -f 'top/PEEP3.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'top/PEEP3.C'\" else echo shar: Extracting \"'top/PEEP3.C'\" \(12352 characters\) sed "s/^X//" >'top/PEEP3.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X */ X X/* X * 3-instruction peephole optimizations X */ X X#include "top.h" X X X/* X * ipeep3(bp, ip) - look for 3-instruction optimizations at the given inst. X */ Xstatic bool Xipeep3(bp, i1) Xregister BLOCK *bp; Xregister INST *i1; X{ X register INST *i2 = i1->next; /* the next instruction */ X INST *i3 = i1->next->next; /* the third instruction */ X X register int op1 = i1->opcode; X register int op2 = i2->opcode; X register int op3 = i3->opcode; X X /* X * move.l Am, Dn => lea N(Am), Ao X * add.l #N, Dn X * move.l Dn, Ao X * X * Also, Dn must be dead after the third instruction. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && X ISA(i1->src.areg) && X (i1->dst.amode == REG) && X ISD(i1->dst.areg)) { X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && X DOK(i2->src.disp) && X (i2->dst.amode == REG) && X (i2->dst.areg == i1->dst.areg)) { X X if ((op3 == MOVE) && (i3->flags & LENL) && X (i3->src.amode == REG) && X (i3->src.areg == i1->dst.areg) && X (i3->dst.amode == REG) && X ISA(i3->dst.areg) && X ((i3->live & RM(i3->src.areg)) == 0)) { X X /* X * rewrite i1 and delete i2 and i3 X */ X i1->opcode = LEA; X i1->flags = 0; X i1->dst = i3->dst; X X i1->src.amode = REGID; X i1->src.disp = i2->src.disp; X X delinst(bp, i2); X delinst(bp, i3); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X } X X /* X * move.l Dm, Dn => move.l Dm, Ao X * add.l #N, Dn lea N(Ao), Ao X * move.l Dn, Ao X * X * Also, Dn must be dead after the third instruction. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && X ISD(i1->src.areg) && X (i1->dst.amode == REG) && X ISD(i1->dst.areg)) { X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && X DOK(i2->src.disp) && X (i2->dst.amode == REG) && X (i2->dst.areg == i1->dst.areg)) { X X if ((op3 == MOVE) && (i3->flags & LENL) && X (i3->src.amode == REG) && X (i3->src.areg == i1->dst.areg) && X (i3->dst.amode == REG) && X ISA(i3->dst.areg) && X ((i3->live & RM(i3->src.areg)) == 0)) { X X /* X * rewrite i1 and i2 and delete i3 X */ X i1->dst.areg = i3->dst.areg; X X i2->opcode = LEA; X i2->flags = 0; X i2->dst = i3->dst; X X i2->src.amode = REGID; X i2->src.areg = i2->dst.areg; X i2->src.disp = i2->src.disp; X X delinst(bp, i3); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X } X X /* X * move.l Am, Dn => lea -N(Am), Ao X * sub.l #N, Dn X * move.l Dn, Ao X * X * Also, Dn must be dead after the third instruction. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && X ISA(i1->src.areg) && X (i1->dst.amode == REG) && X ISD(i1->dst.areg)) { X X if (((op2 == SUB) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && X DOK(i2->src.disp) && X (i2->dst.amode == REG) && X (i2->dst.areg == i1->dst.areg)) { X X if ((op3 == MOVE) && (i3->flags & LENL) && X (i3->src.amode == REG) && X (i3->src.areg == i1->dst.areg) && X (i3->dst.amode == REG) && X ISA(i3->dst.areg) && X ((i3->live & RM(i3->src.areg)) == 0)) { X X /* X * rewrite i1 and delete i2 and i3 X */ X i1->opcode = LEA; X i1->flags = 0; X i1->dst = i3->dst; X X i1->src.amode = REGID; X i1->src.disp = -i2->src.disp; X X delinst(bp, i2); X delinst(bp, i3); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X } X X /* X * move.l Am, Dn => lea 0(Am, Do), Ap X * add.x Do, Dn X * move.l Dn, Ap X * X * The second instruction can be either a word or long add. X * Also, Dn must be dead after the third instruction. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && X ISA(i1->src.areg) && X (i1->dst.amode == REG) && X ISD(i1->dst.areg)) { X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & (LENL|LENW)) && X (i2->src.amode == REG) && X ISD(i2->src.areg) && (i1->dst.areg != i2->src.areg) && X (i2->dst.amode == REG) && X (i2->dst.areg == i1->dst.areg)) { X X if ((op3 == MOVE) && (i3->flags & LENL) && X (i3->src.amode == REG) && X (i3->src.areg == i1->dst.areg) && X (i3->dst.amode == REG) && X ISA(i3->dst.areg) && X ((i3->live & RM(i3->src.areg)) == 0)) { X X /* X * rewrite i1 and delete i2 and i3 X */ X i1->opcode = LEA; X i1->flags = 0; X i1->dst = i3->dst; X X i1->src.amode = REGIDX; X if (i2->flags & LENL) X i1->src.amode |= XLONG; X i1->src.ireg = i2->src.areg; X i1->src.disp = 0; X X delinst(bp, i2); X delinst(bp, i3); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X } X X /* X * move.l X(Am), Dn => move.l X(Am), Ao X * add.l #N, Dn X * move.l Dn, Ao lea N(Ao), Ao X * X * Also, Dn must be dead after the third instruction. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REGI || i1->src.amode == REGID) && X (i1->dst.amode == REG) && X ISD(i1->dst.areg)) { X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && X DOK(i2->src.disp) && X (i2->dst.amode == REG) && X (i2->dst.areg == i1->dst.areg)) { X X if ((op3 == MOVE) && (i3->flags & LENL) && X (i3->src.amode == REG) && X (i3->src.areg == i1->dst.areg) && X (i3->dst.amode == REG) && X ISA(i3->dst.areg) && X ((i3->live & RM(i3->src.areg)) == 0)) { X X /* X * rewrite i1 and i3 and delete i2 X */ X i1->dst = i3->dst; X X i3->opcode = LEA; X i3->flags = 0; X i3->src.amode = REGID; X i3->src.areg = i3->dst.areg; X i3->src.disp = i2->src.disp; X X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X } X X /* X * move.x X, Dn => move.x X, Do X * ext.y Dn ext.y Do X * move.y Dn, Do X * X * Where Dn is dead. X */ X if ((op1 == MOVE)&&(op2 == EXT)&&(op3 == MOVE)&& X (i1->dst.amode == REG) && ISD(i1->dst.areg) && X (i2->src.amode == REG) && (i3->src.amode == REG) && X (i3->dst.amode == REG) && ISD(i3->dst.areg) && X (i1->dst.areg == i2->src.areg) && (i1->dst.areg == i3->src.areg) && X (i2->flags == i3->flags)) { X X if ((i3->live & RM(i3->src.areg)) == 0) { X i1->dst.areg = i3->dst.areg; X i2->src.areg = i3->dst.areg; X X delinst(bp, i3); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X X /* X * move.l X, Dm => move.l X, An X * INST INST X * move.l Dm, An ...deleted... X * X * where INST doesn't modify Dm, and Dm is dead after i3 X */ X if ((op1 == MOVE) && (op3 == MOVE) && X (i1->dst.amode == REG) && ISD(i1->dst.areg) && X (i3->src.amode == REG) && (i1->dst.areg == i3->src.areg) && X (i3->dst.amode == REG) && ISA(i3->dst.areg) && X !sets(i3, RM(i3->src.areg))) { X X if ((i3->live & i3->src.areg) == 0) { X i1->dst.areg = i3->dst.areg; X delinst(bp, i3); X X DBG(printf("%d ", __LINE__)) X return TRUE; X } X } X X /* X * move.l Am, An ...deleted... X * addq.l #1, Am ...deleted... X * ... stuff ... ... stuff ... X * ???.b ..(An).. => ???.b ..(Am)+.. X * X * An must be dead after the last instruction. Nothing in X * "stuff" can modify Am. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && ISA(i1->src.areg) && X (i1->dst.amode == REG) && ISA(i1->dst.areg)) { X X int rm = i1->src.areg; X int rn = i1->dst.areg; X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && (i2->src.disp == 1) && X (i2->dst.amode == REG) && X (i2->dst.areg == rm)) { X X while (i3 != NULL) { X if (sets(i3, RM(rm))) X goto end7; X X if (i3->src.amode==REGI && i3->src.areg==rn) { X if (i3->live & RM(rn)) X goto end7; X X if ((i3->flags & LENB) == 0) X goto end7; X X i3->src.amode |= INC; X i3->src.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X if (i3->dst.amode==REGI && i3->dst.areg==rn) { X if (i3->live & RM(rn)) X goto end7; X X if ((i3->flags & LENB) == 0) X goto end7; X X i3->dst.amode |= INC; X i3->dst.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X X if (i3->next == NULL) X goto end7; X else X i3 = i3->next; X X } X } X } Xend7: X X /* X * move.l Am, An X * addq.l #2, Am X * ... stuff ... X * ???.w ..(An).. => ???.w ..(Am)+.. X * X * An must be dead after the last instruction. Nothing in X * "stuff" can modify Am. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && ISA(i1->src.areg) && X (i1->dst.amode == REG) && ISA(i1->dst.areg)) { X X int rm = i1->src.areg; X int rn = i1->dst.areg; X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && (i2->src.disp == 2) && X (i2->dst.amode == REG) && X (i2->dst.areg == rm)) { X X while (i3 != NULL) { X if (sets(i3, RM(rm))) X goto end9; X X if (i3->src.amode==REGI && i3->src.areg==rn) { X if (i3->live & RM(rn)) X goto end9; X X if ((i3->flags & LENW) == 0) X goto end9; X X i3->src.amode |= INC; X i3->src.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X if (i3->dst.amode==REGI && i3->dst.areg==rn) { X if (i3->live & RM(rn)) X goto end9; X X if ((i3->flags & LENW) == 0) X goto end9; X X i3->dst.amode |= INC; X i3->dst.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X X if (i3->next == NULL) X goto end9; X else X i3 = i3->next; X X } X } X } Xend9: X X /* X * move.l Am, An X * addq.l #4, Am X * ... stuff ... X * ???.l ..(An).. => ???.l ..(Am)+.. X * X * An must be dead after the last instruction. Nothing in X * "stuff" can modify Am. X */ X if ((op1 == MOVE) && (i1->flags & LENL) && X (i1->src.amode == REG) && ISA(i1->src.areg) && X (i1->dst.amode == REG) && ISA(i1->dst.areg)) { X X int rm = i1->src.areg; X int rn = i1->dst.areg; X X if (((op2 == ADD) || (op2 == ADDQ)) && X (i2->flags & LENL) && X (i2->src.amode == IMM) && (i2->src.disp == 4) && X (i2->dst.amode == REG) && X (i2->dst.areg == rm)) { X X while (i3 != NULL) { X if (sets(i3, RM(rm))) X goto end11; X X if (i3->src.amode==REGI && i3->src.areg==rn) { X if (i3->live & RM(rn)) X goto end11; X X if ((i3->flags & LENL) == 0) X goto end11; X X i3->src.amode |= INC; X i3->src.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X if (i3->dst.amode==REGI && i3->dst.areg==rn) { X if (i3->live & RM(rn)) X goto end11; X X if ((i3->flags & LENL) == 0) X goto end11; X X i3->dst.amode |= INC; X i3->dst.areg = rm; X X delinst(bp, i1); X delinst(bp, i2); X DBG(printf("%d ", __LINE__)) X return TRUE; X } X X if (i3->next == NULL) X goto end11; X else X i3 = i3->next; X X } X } X } Xend11: X X return FALSE; X} X X/* X * peep3(bp) - scan blocks starting at 'bp' X */ Xbool Xpeep3(bp) Xregister BLOCK *bp; X{ X register INST *ip; X register bool changed = FALSE; X X DBG(printf("p3: ")) X for (; bp != NULL ;bp = bp->next) { X ip = bp->first; X while (ip!=NULL && ip->next != NULL && ip->next->next != NULL) { X if (ipeep3(bp, ip)) { X s_peep3++; X bprep(bp); X changed = TRUE; X /* X * If we had a match, then any instruction X * could have been deleted, so the safe thing X * to do is to go to the next block. X */ X break; X } else X ip = ip->next; X } X } X DBG(printf("\n"); fflush(stdout)) X return changed; X} END_OF_FILE if test 12352 -ne `wc -c <'top/PEEP3.C'`; then echo shar: \"'top/PEEP3.C'\" unpacked with wrong size! fi # end of 'top/PEEP3.C' fi echo shar: End of archive 6 \(of 9\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0