From bd8c2f431dc19aab00b59cb93c70998ce8bfa001 Mon Sep 17 00:00:00 2001 From: Anders Magnusson Date: Sun, 17 Sep 2023 19:01:56 +0000 Subject: [PATCH] Add support for common handling of function arguments. While here, have a common definition of the gotreg for future use. For now only x86 have this new handling. --- arch/i386/code.c | 167 +++++------------------------------------------------ arch/i386/local.c | 20 ++++--- arch/i386/local2.c | 10 +++- cc/ccom/params.c | 126 ++++++++++++++++++++++++++++++++++++---- cc/ccom/pass1.h | 35 ++++++----- cc/ccom/trees.c | 7 ++- 6 files changed, 176 insertions(+), 189 deletions(-) diff --git a/arch/i386/code.c b/arch/i386/code.c index 31c190f8..c1a7b85a 100644 --- a/arch/i386/code.c +++ b/arch/i386/code.c @@ -1,4 +1,4 @@ -/* $Id: code.c,v 1.109 2023/08/20 17:22:13 ragge Exp $ */ +/* $Id: code.c,v 1.110 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -159,9 +159,9 @@ mycallspec(struct callspec *cs) #ifdef GCC_COMPAT regpregs = reparegs; - if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) + if ((ap = attr_find(cs->rv.ap, GCC_ATYP_REGPARM))) regparmarg = ap->iarg(0); - if ((ap = attr_find(cftnsp->sap, GCC_ATYP_FASTCALL))) + if ((ap = attr_find(cs->rv.ap, GCC_ATYP_FASTCALL))) regparmarg = 2, regpregs = fastregs; if (regparmarg > 3) regparmarg = 3; @@ -271,10 +271,6 @@ int structrettemp; void efcode(void) { - extern int gotnr; - - gotnr = 0; /* new number for next fun */ - #ifdef LANG_CXX cerror("need return code"); #endif @@ -294,19 +290,20 @@ efcode(void) void bfcode(struct symtab **sp, int cnt) { - extern int gotnr; +#ifndef LANG_CXX NODE *p; /* Take care of PIC stuff first */ if (kflag) { NODE *q; p = tempnode(0, INT, 0, 0); - gotnr = regno(p); + gotreg = regno(p); q = block(REG, 0, 0, INT, 0, 0); regno(q) = EBX; p = buildtree(ASSIGN, p, q); ecomp(p); } +#endif } #if defined(MACHOABI) @@ -370,151 +367,6 @@ bjobcode(void) #endif } -/* - * Convert FUNARG to assign in case of regparm. - */ -static int regcvt, rparg, fcall; -static void -addreg(NODE *p) -{ - TWORD t; - NODE *q; - int sz, r; - - sz = (int)tsize(p->n_type, p->n_df, p->pss)/SZCHAR; - sz = (sz + 3) >> 2; /* sz in regs */ - if ((regcvt+sz) > rparg) { - regcvt = rparg; - return; - } - if (sz > 2) - uerror("cannot put struct in 3 regs (yet)"); - - if (sz == 2) - r = regcvt == 0 ? EAXEDX : EDXECX; - else if (fcall) - r = regcvt == 0 ? ECX : EDX; - else - r = regcvt == 0 ? EAX : regcvt == 1 ? EDX : ECX; - - if (p->n_op == FUNARG) { - /* at most 2 regs */ - if (p->n_type < INT) { - p->n_left = ccast(p->n_left, INT, 0, 0, 0); - p->n_type = INT; - } - - p->n_op = ASSIGN; - p->n_right = p->n_left; - } else if (p->n_op == STARG) { - /* convert to ptr, put in reg */ - q = p->n_left; - t = sz == 2 ? LONGLONG : INT; - q = cast(q, INCREF(t), 0); - q = buildtree(UMUL, q, NIL); - p->n_op = ASSIGN; - p->n_type = t; - p->n_right = q; - } else - cerror("addreg"); - p->n_left = block(REG, 0, 0, p->n_type, 0, 0); - regno(p->n_left) = r; - regcvt += sz; -} - -/* - * Called with a function call with arguments as argument. - * This is done early in buildtree() and only done once. - * Returns p. - */ -NODE * -funcode(NODE *p) -{ - extern int gotnr; - struct attr *ap; - NODE *r, *l; - TWORD t = DECREF(DECREF(p->n_left->n_type)); - int stcall; - - stcall = ISSOU(t); - /* - * We may have to prepend: - * - Hidden arg0 for struct return (in reg or on stack). - * - ebx in case of PIC code. - */ - - /* Fix function call arguments. On x86, just add funarg */ - for (r = p->n_right; r->n_op == CM; r = r->n_left) { - if (r->n_right->n_op != STARG) - r->n_right = block(FUNARG, r->n_right, NIL, - r->n_right->n_type, r->n_right->n_df, - r->n_right->pss); - } - if (r->n_op != STARG) { - l = talloc(); - *l = *r; - r->n_op = FUNARG; - r->n_left = l; - r->n_type = l->n_type; - } -#ifdef os_openbsd - if (stcall && strattr(p->n_left->n_td)->sz > SZLONGLONG) -#else - if (stcall && - (attr_find(p->n_left->n_ap, ATTR_COMPLEX) == 0 || -#ifdef LANG_CXX - ((ap = strattr(p->n_left->n_ap)) && ap->amsize > SZLONGLONG))) -#else - (p->n_left->n_td->ss && p->n_left->n_td->ss->sz > SZLONGLONG))) -#endif -#endif - { - /* Prepend a placeholder for struct address. */ - /* Use EBP, can never show up under normal circumstances */ - l = talloc(); - *l = *r; - r->n_op = CM; - r->n_right = l; - r->n_type = INT; - l = block(REG, 0, 0, INCREF(VOID), 0, 0); - regno(l) = EBP; - l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); - r->n_left = l; - } - -#ifdef GCC_COMPAT - fcall = 0; - if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) - rparg = ap->iarg(0); - else if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_FASTCALL))) - fcall = rparg = 2; - else -#endif - rparg = 0; - - regcvt = 0; - if (rparg) - p1listf(p->n_right, addreg); - - if (kflag == 0) - return p; - -#if defined(ELFABI) - /* Create an ASSIGN node for ebx */ - l = block(REG, NIL, NIL, INT, 0, 0); - l->n_rval = EBX; - l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); - if (p->n_right->n_op != CM) { - p->n_right = block(CM, l, p->n_right, INT, 0, 0); - } else { - for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) - ; - r->n_left = block(CM, l, r->n_left, INT, 0, 0); - } -#endif - return p; -} - /* fix up type of field p */ void fldty(struct symtab *p) @@ -593,3 +445,10 @@ builtin_cfa(const struct bitable *bt, NODE *a) return bcon(0); } +#ifdef LANG_CXX +NODE * +funcode(NODE *p) +{ + return p; +} +#endif diff --git a/arch/i386/local.c b/arch/i386/local.c index 0b35df8a..c9147ac1 100644 --- a/arch/i386/local.c +++ b/arch/i386/local.c @@ -1,4 +1,4 @@ -/* $Id: local.c,v 1.216 2023/08/20 17:22:13 ragge Exp $ */ +/* $Id: local.c,v 1.217 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -37,6 +37,7 @@ #define p1tcopy tcopy #define sss sap #define pss n_ap +int gotreg; #else #undef n_type #define n_type ptype @@ -154,7 +155,6 @@ import(P1ND *p) } #endif -int gotnr; /* tempnum for GOT register */ int argstacksize; /* @@ -172,7 +172,7 @@ char *name; P1ND *q, *r; struct symtab *sp; - q = tempnode(gotnr, PTR|VOID, 0, 0); + q = tempnode(gotreg, PTR|VOID, 0, 0); #ifdef GCC_COMPAT struct attr *ap; @@ -226,7 +226,7 @@ char *name; sp->stype = p->n_sp->stype; - q = tempnode(gotnr, PTR+VOID, 0, 0); + q = tempnode(gotreg, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); @@ -257,7 +257,7 @@ picstatic(P1ND *p) P1ND *q, *r; struct symtab *sp; - q = tempnode(gotnr, PTR|VOID, 0, 0); + q = tempnode(gotreg, PTR|VOID, 0, 0); if (p->n_sp->slevel > 0) { char buf[32]; if ((p->n_sp->sflags & SMASK) == SSTRING) @@ -296,7 +296,7 @@ picstatic(P1ND *p) } sp->sclass = STATIC; sp->stype = p->n_sp->stype; - q = tempnode(gotnr, PTR+VOID, 0, 0); + q = tempnode(gotreg, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->pss); @@ -330,7 +330,7 @@ tlspic(P1ND *p) */ /* calc address of var@TLSGD */ - q = tempnode(gotnr, PTR|VOID, 0, 0); + q = tempnode(gotreg, PTR|VOID, 0, 0); name = getsoname(p->n_sp); sp = picsymtab("", name, "@TLSGD"); r = xbcon(0, sp, INT); @@ -515,12 +515,13 @@ clocal(P1ND *p) p1nfree(l); break; +#if 0 case UCALL: if (kflag == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); l->n_rval = EBX; - p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + p->n_right = buildtree(ASSIGN, l, tempnode(gotreg, INT, 0, 0)); p->n_op -= (UCALL-CALL); break; @@ -562,7 +563,7 @@ clocal(P1ND *p) break; l = block(REG, NIL, NIL, INT, 0, 0); regno(l) = EBX; - r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + r = buildtree(ASSIGN, l, tempnode(gotreg, INT, 0, 0)); p->n_right = block(CM, r, p->n_right, INT, 0, 0); break; @@ -579,6 +580,7 @@ clocal(P1ND *p) #endif break; +#endif #ifdef notyet /* XXX breaks sometimes */ diff --git a/arch/i386/local2.c b/arch/i386/local2.c index 2a1b517e..7342c539 100644 --- a/arch/i386/local2.c +++ b/arch/i386/local2.c @@ -1,4 +1,4 @@ -/* $Id: local2.c,v 1.196 2023/09/07 19:02:20 ragge Exp $ */ +/* $Id: local2.c,v 1.197 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -386,6 +386,7 @@ ulltofp(NODE *p) printf(LABFMT ":\n", jmplab); } +#if 0 static int argsiz(NODE *p) { @@ -402,6 +403,7 @@ argsiz(NODE *p) comperr("argsiz"); return 0; } +#endif static void fcast(NODE *p) @@ -913,10 +915,11 @@ cbgen(int o, int lab) static void fixcalls(NODE *p, void *arg) { - struct attr *ap; +// struct attr *ap; /* Prepare for struct return by allocating bounce space on stack */ switch (p->n_op) { +#if 0 case STCALL: case USTCALL: ap = attr_find(p->n_ap, ATTR_P2STRUCT); @@ -925,6 +928,7 @@ fixcalls(NODE *p, void *arg) if (8+p2autooff > stkpos) stkpos = ap->iarg(0)+p2autooff; break; +#endif case LS: case RS: if (p->n_type != LONGLONG && p->n_type != ULONGLONG) @@ -1313,6 +1317,7 @@ gclass(TWORD t) void lastcall(NODE *p) { +#if 0 NODE *op = p; int nr = 0, size = 0; @@ -1347,6 +1352,7 @@ lastcall(NODE *p) #endif op->n_qual = size; /* XXX */ +#endif } /* diff --git a/cc/ccom/params.c b/cc/ccom/params.c index 2da85133..90807765 100644 --- a/cc/ccom/params.c +++ b/cc/ccom/params.c @@ -1,4 +1,4 @@ -/* $Id: params.c,v 1.7 2023/08/06 07:51:42 ragge Exp $ */ +/* $Id: params.c,v 1.8 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright (c) 2023 Anders Magnusson (ragge@ludd.ltu.se). * All rights reserved. @@ -38,6 +38,8 @@ #ifdef NEWPARAMS +int gotreg; + static struct callspec *cftns; static P1ND * @@ -189,18 +191,126 @@ fun_leave(void) ecomp(buildtree(ASSIGN, p, q)); } } + gotreg = 0; +} + +static P1ND * +prepend(P1ND *p, P1ND *q) +{ + P1ND *r; + + if (p == NULL) + return q; + if (p->n_op != CM) + return blk(CM, q, p, tdint); + for (r = p; r->n_left->n_op == CM; r = r->n_left) + ; + r->n_left = blk(CM, q, r->n_left, tdint); + return p; } -#if 0 /* * Put arguments at the right place for a function call. */ -fun_call() +P1ND * +fun_call(P1ND *p) { + struct callspec *cs; + struct rdef *rp; + int nargs = 0; + P1ND *q, *r, **np, *a; + int i, sz; + + if ((a = p->n_op == UCALL ? NULL : p->n_right)) { + nargs = 1; + for (q = a; q->n_op == CM; q = q->n_left) + nargs++; + } + + sz = sizeof(struct callspec) + nargs * sizeof(struct rdef); + memset(cs = stmtalloc(sz), 0, sz); + np = stmtalloc(nargs * sizeof (P1ND *)); + + cs->rv.type = p->ptype; + cs->rv.df = p->pdf; + cs->rv.ss = p->pss; + cs->rv.ap = p->n_ap; + cs->nargs = nargs; + /* cs->rv.flags = RV_CALLER; */ + + /* prepare parameter values */ + /* Put in an array instead of an CM-separated tree */ + if (nargs) { + i = nargs-1; + while (a->n_op == CM) { + np[i--] = a->n_right; + a = p1nfree(a); + } + np[i] = a; + } + for (i = 0; i < nargs; i++) { + q = np[i]; + cs->av[i].type = q->ptype; + cs->av[i].df = q->pdf; + cs->av[i].ss = q->pss; + cs->av[i].ap = q->n_ap; + } + + mycallspec(cs); + + /* setup formal parameter values */ + for (i = 0; i < nargs; i++) { + q = np[i]; + /* + * The ABI may declare that a parameter shall end up in + * multiple locations. + * XXX use COMOP. + */ + rp = &cs->av[i]; + if (rp->flags & AV_STK) { + if (rp->flags & AV_STK_PUSH) { + if (!ISSOU(q->ptype)) + q = blk(FUNARG, q, 0, q->n_td); + } else + cerror("FIXME fun_call"); + } + if (rp->flags & AV_REG) { /* in register */ + r = block(REG, 0, 0, rp->rtp, 0, 0); + regno(r) = rp->reg[0]; + q = buildtree(ASSIGN, r, q); + } + if (rp->flags & AV_REG2) + cerror("FIXME fun_call2"); + a = i ? blk(CM, a, q, tdint) : q; + } + + /* prepend struct return hidden arg, if available */ + if (cs->rv.flags & RV_STRET) { + /* allocate space on stack for struct*/ + struct symtab *spp; + + spp = getsymtab("RV_STRET", SSTMT); + spp->td[0] = p->n_td[0]; + spp->stype = DECREF(spp->stype); + spp->soffset = NOOFFSET; + spp->sclass = AUTO; + oalloc(spp, &autooff); + + q = buildtree(ADDROF, nametree(spp), 0); + if (cs->rv.flags & RV_ARG0_REG) { + cerror("FIXME RV_ARG0_REG"); + } else { + /* PUSH */ + q = blk(FUNARG, q, 0, q->n_td); + a = prepend(a, q); + } + } + if ((p->n_right = a)) + p->n_op = CALL; + return p; } #endif -#endif static FILE *pr_file; int arglistcnt; @@ -353,7 +463,7 @@ argeval(P1ND *p) int pr_hasell(int dsym) { - int i, t; + int t; if (pdebug) printf("pr_hasell: dsym %d\n", dsym); SEEKRD(dsym, t); @@ -362,7 +472,7 @@ if (pdebug) printf("pr_hasell: dsym %d\n", dsym); return 1; if (ISSOU(BTYPE(t))) (void)pr_rptr(); - for (i = 0; t > BTMASK; t = DECREF(t)) + for (; t > BTMASK; t = DECREF(t)) if (ISFTN(t) || ISARY(t)) (void)pr_rptr(); t = pr_rd(); @@ -486,12 +596,9 @@ done: ty = BTYPE(t1); if (ISSOU(ty)) { SEEKRDP(usym, u1); SEEKRDP(udef, u2); -//printf("ckproto: usym %d u1 %p\n", usym, u1); -//printf("ckproto: udef %d u2 %p\n", udef, u2); usym += sizeof(intptr_t), udef += sizeof(intptr_t); if (suemeq((struct ssdesc *)u1, (struct ssdesc *)u2) == 0) -// if (suemeq((struct tdef *)u1, (struct tdef *)u2) == 0) return 1; } @@ -576,7 +683,6 @@ protoarg(P1ND *p) } /* Get both types */ -// tn = p->n_type; tp = pr_rd(); /* handle varargs */ diff --git a/cc/ccom/pass1.h b/cc/ccom/pass1.h index 4a7fdf1c..f09de2d2 100644 --- a/cc/ccom/pass1.h +++ b/cc/ccom/pass1.h @@ -1,4 +1,4 @@ -/* $Id: pass1.h,v 1.330 2023/08/13 14:05:40 ragge Exp $ */ +/* $Id: pass1.h,v 1.331 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * @@ -403,7 +403,9 @@ int cdope(int); void myp2tree(P1ND *); void lcommprint(void), strprint(void); void lcommdel(struct symtab *); +#ifndef NEWPARAMS P1ND *funcode(P1ND *); +#endif struct symtab *enumhd(char *); P1ND *enumdcl(struct symtab *); P1ND *enumref(char *); @@ -803,17 +805,22 @@ void dwarf_end(void); * AV_REG2 - param spans over reg and reg2. * AV_STREG - struct in reg/reg2, reg type in rtp * AV_STK - param on stack, offset from fp in off. - * AV_STK_PUSH - param should be pushed on stack instead of written. + * AV_STK_PUSH - param should be pushed on stack instead of written to stack. + * AV_GOT_REG - set by target to tell GOT pointer is needed. * - * (typ, df, ap) are the type specification for this parameter. + * (typ, df, ss) are the type specification for this parameter. * (off, reg, reg2) are set by the target code for this parameter. + * p may be set by caller as extra hidden args. */ struct rdef { int flags; /* shared between common/target code */ int type; /* set by common code */ union dimfun *df; /* set by common code */ struct ssdesc *ss; /* set by common code */ - struct attr *ap; /* set by common code */ + union { + P1ND *p; /* set by target code */ + struct attr *ap; /* set by common code */ + }; int off, rtp, reg[2]; /* set by target code */ }; #define AV_REG 001 @@ -821,6 +828,7 @@ struct rdef { #define AV_STK 004 #define AV_STK_PUSH 010 #define AV_STREG 020 +#define AV_GOT_REG 040 /* * function call parameter definitions. @@ -847,13 +855,14 @@ void mycallspec(struct callspec *); void fun_enter(struct symtab *sp, struct symtab **spp, int nargs); void fun_leave(void); -//void fun_call(); +P1ND *fun_call(P1ND *); void setreg(struct rdef *rd, int reg, int tsz, TWORD typ); - - -#define RV_STRET 001 -#define RV_ARG0_REG 002 -#define RV_RETADDR 004 -#define RV_STREG 010 -#define RV_RETREG 020 -#define RV_CALLEE 040 +extern int gotreg; + +#define RV_STRET 0001 +#define RV_ARG0_REG 0002 +#define RV_ARG0_PUSH 0004 +#define RV_RETADDR 0010 +#define RV_STREG 0020 +#define RV_RETREG 0040 +#define RV_CALLEE 0100 diff --git a/cc/ccom/trees.c b/cc/ccom/trees.c index 7e4a9b36..39247d82 100644 --- a/cc/ccom/trees.c +++ b/cc/ccom/trees.c @@ -1,4 +1,4 @@ -/* $Id: trees.c,v 1.401 2023/09/07 08:52:39 ragge Exp $ */ +/* $Id: trees.c,v 1.402 2023/09/17 19:01:56 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -600,7 +600,9 @@ runtime: case CALL: p->n_right = r = strargs(p->n_right); +#ifndef NEWPARAMS p = funcode(p); +#endif /* FALLTHROUGH */ case UCALL: if (!ISPTR(l->n_type)) @@ -611,6 +613,9 @@ runtime: p->n_type = DECREF(p->n_type); p->n_df = l->n_df+1; /* add one for prototypes */ p->pss = l->pss; +#ifdef NEWPARAMS + p = fun_call(p); +#endif if (p->n_type == STRTY || p->n_type == UNIONTY) { /* function returning structure */ /* make function really return ptr to str., with * */ -- 2.11.4.GIT