summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/hppa/local2.c
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-11-16 08:36:24 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-11-16 08:36:24 +0000
commitf7d7a39b9fa388ad3592ca630db976b95437e570 (patch)
tree396b761b2dbee37ca4c53f3ce3859774263ada8f /usr.bin/pcc/hppa/local2.c
parent2811f223c5884b622e45a2352c89b8654da77b35 (diff)
sync with repo and brink in hppa backend from mickey. afaik, it needs
some changes in the mi parts that are not yet committed
Diffstat (limited to 'usr.bin/pcc/hppa/local2.c')
-rw-r--r--usr.bin/pcc/hppa/local2.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/usr.bin/pcc/hppa/local2.c b/usr.bin/pcc/hppa/local2.c
new file mode 100644
index 00000000000..c3800e493f6
--- /dev/null
+++ b/usr.bin/pcc/hppa/local2.c
@@ -0,0 +1,709 @@
+/* $OpenBSD: local2.c,v 1.1 2007/11/16 08:36:23 otto Exp $ */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+
+static int stkpos;
+
+static const int rl[] =
+ { R1, R5, R7, R9, R11, R13, R15, R17, T4, T2, ARG3, ARG1, RET1 };
+static const int rh[] =
+ { R31, R4, R6, R8, R10, R12, R14, R16, T3, T1, ARG2, ARG0, RET0 };
+
+void
+deflab(int label)
+{
+ printf("\t.label\t" LABFMT "\n", label);
+}
+
+static int regoff[MAXREGS];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+ int i;
+
+ printf("\tcopy\t%%r3,%%r1\n"
+ "\tcopy\t%%sp,%%r3\n"
+ "\tstw,ma\t%%r1,%d(%%sp)\n", addto);
+ for (i = 0; i < MAXREGS; i++)
+ if (TESTBIT(ipp->ipp_regs, i)) {
+ if (i <= R31)
+ printf("\tstw\t%s,%d(%s)\n",
+ rnames[i], regoff[i], rnames[FPREG]);
+ else if (i < RETD0)
+ printf("\tstw\t%s,%d(%s)\n\tstw\t%s,%d(%s)\n",
+ rnames[rl[i - RD0]], regoff[i] + 0, rnames[FPREG],
+ rnames[rh[i - RD0]], regoff[i] + 4, rnames[FPREG]);
+ else if (i <= FR31)
+ ;
+ else
+ ;
+ }
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+ int i, addto;
+
+ addto = 32;
+ for (i = 0; i < MAXREGS; i++)
+ if (TESTBIT(ipp->ipp_regs, i)) {
+ regoff[i] = addto;
+ addto += SZINT/SZCHAR;
+ }
+ addto += p2maxautooff;
+ return (addto + 63) & ~63;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ int addto;
+
+ ftype = ipp->ipp_type;
+ printf("\t.align\t4\n");
+ if (ipp->ipp_vis)
+ printf("\t.export\t%s, code\n", ipp->ipp_name);
+ printf("\t.label\t%s\n\t.proc\n", ipp->ipp_name);
+
+ /*
+ * We here know what register to save and how much to
+ * add to the stack.
+ */
+ addto = offcalc(ipp);
+ printf("\t.callinfo frame=%d, save_rp, save_sp\n\t.entry\n", addto);
+ prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+ int i;
+
+ if (ipp->ipp_ip.ip_lbl == 0)
+ return; /* no code needs to be generated */
+
+ /* return from function code */
+ for (i = 0; i < MAXREGS; i++)
+ if (TESTBIT(ipp->ipp_regs, i))
+ printf("\tldw\t%d(%s),%s\n",
+ regoff[i], rnames[FPREG], rnames[i]);
+
+ /* TODO restore sp,rp */
+ printf("\tbv\t%%r0(%%rp)\n\tnop\n"
+ "\t.exit\n\t.procend\n\t.size\t%s, .-%s\n",
+ ipp->ipp_name, ipp->ipp_name);
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str;
+
+ switch (o) {
+ case PLUS:
+ str = "add";
+ break;
+ case MINUS:
+ str = "sub";
+ break;
+ case AND:
+ str = "and";
+ break;
+ case OR:
+ str = "or";
+ break;
+ case ER:
+ str = "xor";
+ break;
+ case EQ:
+ str = "=";
+ break;
+ case NE:
+ str = "<>";
+ break;
+ case LE:
+ str = "<";
+ break;
+ case LT:
+ str = "<=";
+ break;
+ case GE:
+ str = ">";
+ break;
+ case GT:
+ str = ">=";
+ break;
+ case ULE:
+ str = "<<";
+ break;
+ case ULT:
+ str = "<<=";
+ break;
+ case UGE:
+ str = ">>";
+ break;
+ case UGT:
+ str = ">>=";
+ break;
+ default:
+ comperr("hopcode2: %d", o);
+ str = 0; /* XXX gcc */
+ }
+ printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes. Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+ switch(p->n_type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case SHORT:
+ case USHORT:
+ return(SZSHORT/SZCHAR);
+
+ case FLOAT:
+ return(SZFLOAT/SZCHAR);
+
+ case DOUBLE:
+ return(SZDOUBLE/SZCHAR);
+
+ case INT:
+ case UNSIGNED:
+ case LONG:
+ case ULONG:
+ return(SZINT/SZCHAR);
+
+ case LONGLONG:
+ case ULONGLONG:
+ return SZLONGLONG/SZCHAR;
+
+ default:
+ if (!ISPTR(p->n_type))
+ comperr("tlen type %d not pointer");
+ return SZPOINT(p->n_type)/SZCHAR;
+ }
+}
+
+static int
+argsiz(NODE *p)
+{
+ TWORD t = p->n_type;
+
+ if (t < LONGLONG || t == FLOAT || t > BTMASK)
+ return 4;
+ if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+ return 8;
+ if (t == LDOUBLE)
+ return 8; /* quad is 16 */
+ if (t == STRTY || t == UNIONTY)
+ return p->n_stsize;
+ comperr("argsiz");
+ return 0;
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+ int n;
+
+ switch (c) {
+
+ case 'C': /* after-call fixup */
+ n = p->n_qual;
+ if (n)
+ printf("\tldo\t-%d(%%sp),%%sp\n", n);
+ break;
+
+ case 'P': /* returning struct-call setup */
+ n = p->n_qual;
+ if (n)
+ printf("\tldo\t%d(%%sp),%%sp\n", n);
+ break;
+
+ case 'F': /* output extr/dep offset/len parts for bitfields */
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o == NAME || o == REG || o == ICON || o == OREG ||
+ (o == UMUL && shumul(p->n_left)))
+ return(1);
+ return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+ int o = p->n_op;
+
+ if (isreg(p))
+ return SRDIR; /* Direct match */
+
+ return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+ return 0;
+#if 0
+ int r;
+
+ if (p->n_op == STARG )
+ p = p->n_left;
+
+ switch (p->n_op) {
+ case REG:
+ return (!istreg(p->n_rval));
+
+ case OREG:
+ r = p->n_rval;
+ if (R2TEST(r)) {
+ if (istreg(R2UPK1(r)))
+ return(0);
+ r = R2UPK2(r);
+ }
+ return (!istreg(r));
+
+ case UMUL:
+ p = p->n_left;
+ return (p->n_op != UMUL && shtemp(p));
+ }
+
+ if (optype(p->n_op) != LTYPE)
+ return(0);
+ return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+ /* fix for L% and R% */
+ printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+ int val = p->n_lval;
+
+ switch (p->n_op) {
+ case ICON:
+ if (p->n_name[0] != '\0') {
+ fprintf(fp, "RR'%s", p->n_name);
+ if (val)
+ fprintf(fp, "+%d", val);
+ fprintf(fp, "-$global$");
+ } else
+ fprintf(fp, "%d", val);
+ return;
+
+ default:
+ comperr("illegal conput, p %p", p);
+ }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+ comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+ size /= SZCHAR;
+ switch (p->n_op) {
+ case REG:
+ printf("%s", rnames[rh[p->n_rval - RD0]]);
+ break;
+
+ case OREG:
+ p->n_lval += size;
+ adrput(stdout, p);
+ p->n_lval -= size;
+ break;
+
+ case ICON:
+ case NAME:
+ if (p->n_name[0] != '\0') {
+ printf("LL'%s", p->n_name);
+ if (p->n_lval != 0)
+ printf("+" CONFMT, p->n_lval);
+ printf("-$global$");
+ } else
+ printf("L%%" CONFMT, p->n_lval >> 32);
+ break;
+ default:
+ comperr("upput bad op %d size %d", p->n_op, size);
+ }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+ int r;
+ /* output an address, with offsets, from p */
+
+ if (p->n_op == FLD)
+ p = p->n_left;
+
+ switch (p->n_op) {
+
+ case ICON:
+ case NAME:
+ if (p->n_name[0] != '\0') {
+ fprintf(io, "RR'%s", p->n_name);
+ if (p->n_lval != 0)
+ fprintf(io, "+" CONFMT, p->n_lval);
+ fprintf(io, "-$global$");
+ } else
+ fprintf(io, "R%%" CONFMT, p->n_lval);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+ if (p->n_name[0] != '\0') {
+ fprintf(io, "RR'%s", p->n_name);
+ if (p->n_lval != 0)
+ fprintf(io, "+" CONFMT, p->n_lval);
+ fprintf(io, "-$global$");
+ } else if (p->n_lval)
+ fprintf(io, "%d", (int)p->n_lval);
+ if (R2TEST(r)) {
+ fprintf(io, "%s(%s)", rnames[R2UPK1(r)],
+ rnames[R2UPK2(r)]);
+ } else
+ fprintf(io, "(%s)", rnames[p->n_rval]);
+ return;
+ case MOVE:
+ case REG:
+ if (RD0 <= p->n_rval && p->n_rval <= RETD0)
+ fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]);
+ else
+ fprintf(io, "%s", rnames[p->n_rval]);
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+/* not used */
+void
+cbgen(int o, int lab)
+{
+}
+
+static void
+fixcalls(NODE *p)
+{
+ /* Prepare for struct return by allocating bounce space on stack */
+ switch (p->n_op) {
+ case STCALL:
+ case USTCALL:
+ if (p->n_stsize+p2autooff > stkpos)
+ stkpos = p->n_stsize+p2autooff;
+ break;
+ }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+ struct interpass *ip;
+
+ stkpos = p2autooff;
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, fixcalls);
+ }
+ if (stkpos > p2autooff)
+ p2autooff = stkpos;
+ if (stkpos > p2maxautooff)
+ p2maxautooff = stkpos;
+ if (x2debug)
+ printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p)
+{
+ NODE *q;
+
+ if (p->n_op == PLUS) {
+ if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+ if (p->n_right->n_op != ICON)
+ return;
+ if (p->n_left->n_op != PCONV)
+ return;
+ if (p->n_left->n_left->n_op != OREG)
+ return;
+ q = p->n_left->n_left;
+ nfree(p->n_left);
+ p->n_left = q;
+ /*
+ * This will be converted to another OREG later.
+ */
+ }
+ }
+}
+
+void
+mycanon(NODE *p)
+{
+ walkf(p, pconv2);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+ int sl, sh, dl, dh;
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+ sl = rl[s-RD0];
+ sh = rh[s-RD0];
+ dl = rl[d-RD0];
+ dh = rh[d-RD0];
+
+ /* sanity checks, remove when satisfied */
+ if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
+ memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
+ comperr("rmove source error");
+ if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
+ memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
+ comperr("rmove dest error");
+#define SW(x,y) { int i = x; x = y; y = i; }
+ if (sl == dh || sh == dl) {
+ /* Swap if moving to itself */
+ SW(sl, sh);
+ SW(dl, dh);
+ }
+ if (sl != dl)
+ printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]);
+ if (sh != dh)
+ printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]);
+ break;
+ case FLOAT:
+ printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]);
+ break;
+ case DOUBLE:
+ case LDOUBLE:
+ printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]);
+ break;
+ default:
+ printf("\tcopy\t%s,%s\n", rnames[s], rnames[d]);
+ }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+ int num;
+
+ switch (c) {
+ case CLASSA:
+ num = 2 * r[CLASSB];
+ num += r[CLASSA];
+ return num < 28;
+ case CLASSB:
+ num = r[CLASSA];
+ num += r[CLASSB] * 2;
+ return num < 28;
+ case CLASSC:
+ num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2;
+ num += r[CLASSC];
+ return num < 28;
+ case CLASSD:
+ num = (r[CLASSC] + 1) / 2;
+ num += r[CLASSD];
+ return num < 28;
+ }
+ return 0; /* XXX gcc */
+}
+
+const char * const rnames[MAXREGS] = {
+ "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9",
+ "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18",
+ "%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp",
+ "%ret0", "%ret1", "%sp", "%r31",
+ "%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7",
+ "%td2", "%td1", "%ad1", "%ad0", "%retd0",
+ "%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10",
+ "%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18",
+ "%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26",
+ "%fr27", "%fr28", "%fr29", "%fr30", "%fr31",
+ "%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r",
+ "%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r",
+ "%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r",
+ "%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r",
+ "%fr16l", "%fr16r", "%fr17l", "%fr17r",
+#ifdef __hppa64__
+ "%fr18l", "%fr18r", "%fr19l", "%fr19r",
+ "%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r",
+ "%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r",
+ "%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r",
+ "%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r",
+#endif
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+ return CLASSB;
+ case FLOAT:
+ return CLASSC;
+ case DOUBLE:
+ case LDOUBLE:
+ return CLASSD;
+ default:
+ return CLASSA;
+ }
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+ NODE *op = p;
+ int size = 64;
+
+ p->n_qual = size;
+ if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+ return;
+ for (p = p->n_right; p->n_op == CM; p = p->n_left)
+ size += argsiz(p->n_right);
+ size += argsiz(p);
+ op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+ int o = p->n_op;
+
+ switch (shape) {
+ case SFUNCALL:
+ if (o == STCALL || o == USTCALL)
+ return SRREG;
+ break;
+ case SPICON:
+ if (o != ICON || p->n_name[0] ||
+ p->n_lval < -1024 || p->n_lval >= 1024)
+ break;
+ return SRDIR;
+ case SPCON:
+ if (o != ICON || p->n_name[0] ||
+ p->n_lval < -8192 || p->n_lval >= 8192)
+ break;
+ return SRDIR;
+ case SPNAME:
+ if (o != ICON || !p->n_name[0])
+ break;
+ return SRDIR;
+ }
+ return SRNOPE;
+}