| 1 | /* $Id: code.c,v 1.21 2009/02/08 16:07:52 ragge Exp $ */
|
|---|
| 2 | /*
|
|---|
| 3 | * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
|
|---|
| 4 | * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
|
|---|
| 5 | * All rights reserved.
|
|---|
| 6 | *
|
|---|
| 7 | * Redistribution and use in source and binary forms, with or without
|
|---|
| 8 | * modification, are permitted provided that the following conditions
|
|---|
| 9 | * are met:
|
|---|
| 10 | * 1. Redistributions of source code must retain the above copyright
|
|---|
| 11 | * notice, this list of conditions and the following disclaimer.
|
|---|
| 12 | * 2. Redistributions in binary form must reproduce the above copyright
|
|---|
| 13 | * notice, this list of conditions and the following disclaimer in the
|
|---|
| 14 | * documentation and/or other materials provided with the distribution.
|
|---|
| 15 | * 3. The name of the author may not be used to endorse or promote products
|
|---|
| 16 | * derived from this software without specific prior written permission
|
|---|
| 17 | *
|
|---|
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|---|
| 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|---|
| 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|---|
| 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|---|
| 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|---|
| 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|---|
| 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|---|
| 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|---|
| 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|---|
| 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|---|
| 28 | */
|
|---|
| 29 |
|
|---|
| 30 | /*
|
|---|
| 31 | * Stuff for pass1.
|
|---|
| 32 | */
|
|---|
| 33 |
|
|---|
| 34 | #include <assert.h>
|
|---|
| 35 |
|
|---|
| 36 | #include "pass1.h"
|
|---|
| 37 | #include "pass2.h"
|
|---|
| 38 |
|
|---|
| 39 | int lastloc = -1;
|
|---|
| 40 | static int rvnr;
|
|---|
| 41 |
|
|---|
| 42 | /*
|
|---|
| 43 | * Define everything needed to print out some data (or text).
|
|---|
| 44 | * This means segment, alignment, visibility, etc.
|
|---|
| 45 | */
|
|---|
| 46 | void
|
|---|
| 47 | defloc(struct symtab *sp)
|
|---|
| 48 | {
|
|---|
| 49 | extern char *nextsect;
|
|---|
| 50 | static char *loctbl[] = { "text", "data", "section .rodata" };
|
|---|
| 51 | char *n;
|
|---|
| 52 | TWORD t;
|
|---|
| 53 | int s;
|
|---|
| 54 |
|
|---|
| 55 | if (sp == NULL) {
|
|---|
| 56 | lastloc = -1;
|
|---|
| 57 | return;
|
|---|
| 58 | }
|
|---|
| 59 | t = sp->stype;
|
|---|
| 60 | s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? PROG : DATA;
|
|---|
| 61 | if (nextsect) {
|
|---|
| 62 | printf("\t.section %s\n", nextsect);
|
|---|
| 63 | nextsect = NULL;
|
|---|
| 64 | s = -1;
|
|---|
| 65 | } else if (s != lastloc)
|
|---|
| 66 | printf("\t.%s\n", loctbl[s]);
|
|---|
| 67 | lastloc = s;
|
|---|
| 68 | while (ISARY(t))
|
|---|
| 69 | t = DECREF(t);
|
|---|
| 70 | if (t > UCHAR)
|
|---|
| 71 | printf("\t.align %d\n", t > USHORT ? 4 : 2);
|
|---|
| 72 | n = sp->soname ? sp->soname : exname(sp->sname);
|
|---|
| 73 | #ifdef USE_GAS
|
|---|
| 74 | if (ISFTN(t))
|
|---|
| 75 | printf("\t.type %s,%%function\n", n);
|
|---|
| 76 | #endif
|
|---|
| 77 | if (sp->sclass == EXTDEF)
|
|---|
| 78 | printf("\t.global %s\n", n);
|
|---|
| 79 | if (ISFTN(t))
|
|---|
| 80 | return;
|
|---|
| 81 | if (sp->slevel == 0)
|
|---|
| 82 | printf("%s:\n", n);
|
|---|
| 83 | else
|
|---|
| 84 | printf(LABFMT ":\n", sp->soffset);
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | /* Put a symbol in a temporary
|
|---|
| 88 | * used by bfcode() and its helpers
|
|---|
| 89 | */
|
|---|
| 90 | static void
|
|---|
| 91 | putintemp(struct symtab *sym)
|
|---|
| 92 | {
|
|---|
| 93 | NODE *p;
|
|---|
| 94 |
|
|---|
| 95 | p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 96 | p = buildtree(ASSIGN, p, nametree(sym));
|
|---|
| 97 | sym->soffset = regno(p->n_left);
|
|---|
| 98 | sym->sflags |= STNODE;
|
|---|
| 99 | ecomp(p);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | /* setup a 64-bit parameter (double/ldouble/longlong)
|
|---|
| 103 | * used by bfcode() */
|
|---|
| 104 | static void
|
|---|
| 105 | param_64bit(struct symtab *sym, int *argofsp, int dotemps)
|
|---|
| 106 | {
|
|---|
| 107 | int argofs = *argofsp;
|
|---|
| 108 | NODE *p, *q;
|
|---|
| 109 | int navail;
|
|---|
| 110 |
|
|---|
| 111 | #if ALLONGLONG == 64
|
|---|
| 112 | /* alignment */
|
|---|
| 113 | ++argofs;
|
|---|
| 114 | argofs &= ~1;
|
|---|
| 115 | *argofsp = argofs;
|
|---|
| 116 | #endif
|
|---|
| 117 |
|
|---|
| 118 | navail = NARGREGS - argofs;
|
|---|
| 119 |
|
|---|
| 120 | if (navail < 2) {
|
|---|
| 121 | /* half in and half out of the registers */
|
|---|
| 122 | if (features(FEATURE_BIGENDIAN)) {
|
|---|
| 123 | cerror("param_64bit");
|
|---|
| 124 | p = q = NULL;
|
|---|
| 125 | } else {
|
|---|
| 126 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 127 | regno(q) = R0 + argofs;
|
|---|
| 128 | if (dotemps) {
|
|---|
| 129 | q = block(SCONV, q, NIL,
|
|---|
| 130 | ULONGLONG, 0, MKSUE(ULONGLONG));
|
|---|
| 131 | p = nametree(sym);
|
|---|
| 132 | p->n_type = ULONGLONG;
|
|---|
| 133 | p->n_df = 0;
|
|---|
| 134 | p->n_sue = MKSUE(ULONGLONG);
|
|---|
| 135 | p = block(LS, p, bcon(32), ULONGLONG,
|
|---|
| 136 | 0, MKSUE(ULONGLONG));
|
|---|
| 137 | q = block(PLUS, p, q, ULONGLONG,
|
|---|
| 138 | 0, MKSUE(ULONGLONG));
|
|---|
| 139 | p = tempnode(0, ULONGLONG,
|
|---|
| 140 | 0, MKSUE(ULONGLONG));
|
|---|
| 141 | sym->soffset = regno(p);
|
|---|
| 142 | sym->sflags |= STNODE;
|
|---|
| 143 | } else {
|
|---|
| 144 | p = nametree(sym);
|
|---|
| 145 | regno(p) = sym->soffset;
|
|---|
| 146 | p->n_type = INT;
|
|---|
| 147 | p->n_df = 0;
|
|---|
| 148 | p->n_sue = MKSUE(INT);
|
|---|
| 149 | }
|
|---|
| 150 | }
|
|---|
| 151 | p = buildtree(ASSIGN, p, q);
|
|---|
| 152 | ecomp(p);
|
|---|
| 153 | *argofsp = argofs + 2;
|
|---|
| 154 | return;
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 158 | regno(q) = R0R1 + argofs;
|
|---|
| 159 | if (dotemps) {
|
|---|
| 160 | p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 161 | sym->soffset = regno(p);
|
|---|
| 162 | sym->sflags |= STNODE;
|
|---|
| 163 | } else {
|
|---|
| 164 | p = nametree(sym);
|
|---|
| 165 | }
|
|---|
| 166 | p = buildtree(ASSIGN, p, q);
|
|---|
| 167 | ecomp(p);
|
|---|
| 168 | *argofsp = argofs + 2;
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | /* setup a 32-bit param on the stack
|
|---|
| 172 | * used by bfcode() */
|
|---|
| 173 | static void
|
|---|
| 174 | param_32bit(struct symtab *sym, int *argofsp, int dotemps)
|
|---|
| 175 | {
|
|---|
| 176 | NODE *p, *q;
|
|---|
| 177 |
|
|---|
| 178 | q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 179 | regno(q) = R0 + (*argofsp)++;
|
|---|
| 180 | if (dotemps) {
|
|---|
| 181 | p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 182 | sym->soffset = regno(p);
|
|---|
| 183 | sym->sflags |= STNODE;
|
|---|
| 184 | } else {
|
|---|
| 185 | p = nametree(sym);
|
|---|
| 186 | }
|
|---|
| 187 | p = buildtree(ASSIGN, p, q);
|
|---|
| 188 | ecomp(p);
|
|---|
| 189 | }
|
|---|
| 190 |
|
|---|
| 191 | /* setup a double param on the stack
|
|---|
| 192 | * used by bfcode() */
|
|---|
| 193 | static void
|
|---|
| 194 | param_double(struct symtab *sym, int *argofsp, int dotemps)
|
|---|
| 195 | {
|
|---|
| 196 | NODE *p, *q, *t;
|
|---|
| 197 | int tmpnr;
|
|---|
| 198 |
|
|---|
| 199 | /*
|
|---|
| 200 | * we have to dump the float from the general register
|
|---|
| 201 | * into a temp, since the register allocator doesn't like
|
|---|
| 202 | * floats to be in CLASSA. This may not work for -xtemps.
|
|---|
| 203 | */
|
|---|
| 204 |
|
|---|
| 205 | t = tempnode(0, ULONGLONG, 0, MKSUE(ULONGLONG));
|
|---|
| 206 | tmpnr = regno(t);
|
|---|
| 207 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 208 | q->n_rval = R0R1 + (*argofsp)++;
|
|---|
| 209 | p = buildtree(ASSIGN, t, q);
|
|---|
| 210 | ecomp(p);
|
|---|
| 211 |
|
|---|
| 212 | if (dotemps) {
|
|---|
| 213 | sym->soffset = tmpnr;
|
|---|
| 214 | sym->sflags |= STNODE;
|
|---|
| 215 | } else {
|
|---|
| 216 | q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 217 | p = nametree(sym);
|
|---|
| 218 | p = buildtree(ASSIGN, p, q);
|
|---|
| 219 | ecomp(p);
|
|---|
| 220 | }
|
|---|
| 221 | }
|
|---|
| 222 |
|
|---|
| 223 | /* setup a float param on the stack
|
|---|
| 224 | * used by bfcode() */
|
|---|
| 225 | static void
|
|---|
| 226 | param_float(struct symtab *sym, int *argofsp, int dotemps)
|
|---|
| 227 | {
|
|---|
| 228 | NODE *p, *q, *t;
|
|---|
| 229 | int tmpnr;
|
|---|
| 230 |
|
|---|
| 231 | /*
|
|---|
| 232 | * we have to dump the float from the general register
|
|---|
| 233 | * into a temp, since the register allocator doesn't like
|
|---|
| 234 | * floats to be in CLASSA. This may not work for -xtemps.
|
|---|
| 235 | */
|
|---|
| 236 |
|
|---|
| 237 | t = tempnode(0, INT, 0, MKSUE(INT));
|
|---|
| 238 | tmpnr = regno(t);
|
|---|
| 239 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 240 | q->n_rval = R0 + (*argofsp)++;
|
|---|
| 241 | p = buildtree(ASSIGN, t, q);
|
|---|
| 242 | ecomp(p);
|
|---|
| 243 |
|
|---|
| 244 | if (dotemps) {
|
|---|
| 245 | sym->soffset = tmpnr;
|
|---|
| 246 | sym->sflags |= STNODE;
|
|---|
| 247 | } else {
|
|---|
| 248 | q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
|
|---|
| 249 | p = nametree(sym);
|
|---|
| 250 | p = buildtree(ASSIGN, p, q);
|
|---|
| 251 | ecomp(p);
|
|---|
| 252 | }
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | /* setup the hidden pointer to struct return parameter
|
|---|
| 256 | * used by bfcode() */
|
|---|
| 257 | static void
|
|---|
| 258 | param_retstruct(void)
|
|---|
| 259 | {
|
|---|
| 260 | NODE *p, *q;
|
|---|
| 261 |
|
|---|
| 262 | p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->ssue);
|
|---|
| 263 | rvnr = regno(p);
|
|---|
| 264 | q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
|
|---|
| 265 | regno(q) = R0;
|
|---|
| 266 | p = buildtree(ASSIGN, p, q);
|
|---|
| 267 | ecomp(p);
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 |
|
|---|
| 271 | /* setup struct parameter
|
|---|
| 272 | * push the registers out to memory
|
|---|
| 273 | * used by bfcode() */
|
|---|
| 274 | static void
|
|---|
| 275 | param_struct(struct symtab *sym, int *argofsp)
|
|---|
| 276 | {
|
|---|
| 277 | int argofs = *argofsp;
|
|---|
| 278 | NODE *p, *q;
|
|---|
| 279 | int navail;
|
|---|
| 280 | int sz;
|
|---|
| 281 | int off;
|
|---|
| 282 | int num;
|
|---|
| 283 | int i;
|
|---|
| 284 |
|
|---|
| 285 | navail = NARGREGS - argofs;
|
|---|
| 286 | sz = tsize(sym->stype, sym->sdf, sym->ssue) / SZINT;
|
|---|
| 287 | off = ARGINIT/SZINT + argofs;
|
|---|
| 288 | num = sz > navail ? navail : sz;
|
|---|
| 289 | for (i = 0; i < num; i++) {
|
|---|
| 290 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 291 | regno(q) = R0 + argofs++;
|
|---|
| 292 | p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 293 | regno(p) = SP;
|
|---|
| 294 | p = block(PLUS, p, bcon(4*off++), INT, 0, MKSUE(INT));
|
|---|
| 295 | p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
|
|---|
| 296 | p = buildtree(ASSIGN, p, q);
|
|---|
| 297 | ecomp(p);
|
|---|
| 298 | }
|
|---|
| 299 |
|
|---|
| 300 | *argofsp = argofs;
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 | /*
|
|---|
| 305 | * Beginning-of-function code:
|
|---|
| 306 | *
|
|---|
| 307 | * 'sp' is an array of indices in symtab for the arguments
|
|---|
| 308 | * 'cnt' is the number of arguments
|
|---|
| 309 | */
|
|---|
| 310 | void
|
|---|
| 311 | bfcode(struct symtab **sp, int cnt)
|
|---|
| 312 | {
|
|---|
| 313 | union arglist *usym;
|
|---|
| 314 | int saveallargs = 0;
|
|---|
| 315 | int i, argofs = 0;
|
|---|
| 316 |
|
|---|
| 317 | /*
|
|---|
| 318 | * Detect if this function has ellipses and save all
|
|---|
| 319 | * argument registers onto stack.
|
|---|
| 320 | */
|
|---|
| 321 | usym = cftnsp->sdf->dfun;
|
|---|
| 322 | while (usym && usym->type != TNULL) {
|
|---|
| 323 | if (usym->type == TELLIPSIS) {
|
|---|
| 324 | saveallargs = 1;
|
|---|
| 325 | break;
|
|---|
| 326 | }
|
|---|
| 327 | ++usym;
|
|---|
| 328 | }
|
|---|
| 329 |
|
|---|
| 330 | /* if returning a structure, move the hidden argument into a TEMP */
|
|---|
| 331 | if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
|
|---|
| 332 | param_retstruct();
|
|---|
| 333 | ++argofs;
|
|---|
| 334 | }
|
|---|
| 335 |
|
|---|
| 336 | /* recalculate the arg offset and create TEMP moves */
|
|---|
| 337 | for (i = 0; i < cnt; i++) {
|
|---|
| 338 |
|
|---|
| 339 | if (sp[i] == NULL)
|
|---|
| 340 | continue;
|
|---|
| 341 |
|
|---|
| 342 | if ((argofs >= NARGREGS) && !xtemps)
|
|---|
| 343 | break;
|
|---|
| 344 |
|
|---|
| 345 | if (argofs > NARGREGS) {
|
|---|
| 346 | putintemp(sp[i]);
|
|---|
| 347 | } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
|
|---|
| 348 | param_struct(sp[i], &argofs);
|
|---|
| 349 | } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
|
|---|
| 350 | param_64bit(sp[i], &argofs, xtemps && !saveallargs);
|
|---|
| 351 | } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
|
|---|
| 352 | if (features(FEATURE_HARDFLOAT))
|
|---|
| 353 | param_double(sp[i], &argofs,
|
|---|
| 354 | xtemps && !saveallargs);
|
|---|
| 355 | else
|
|---|
| 356 | param_64bit(sp[i], &argofs,
|
|---|
| 357 | xtemps && !saveallargs);
|
|---|
| 358 | } else if (sp[i]->stype == FLOAT) {
|
|---|
| 359 | if (features(FEATURE_HARDFLOAT))
|
|---|
| 360 | param_float(sp[i], &argofs,
|
|---|
| 361 | xtemps && !saveallargs);
|
|---|
| 362 | else
|
|---|
| 363 | param_32bit(sp[i], &argofs,
|
|---|
| 364 | xtemps && !saveallargs);
|
|---|
| 365 | } else {
|
|---|
| 366 | param_32bit(sp[i], &argofs, xtemps && !saveallargs);
|
|---|
| 367 | }
|
|---|
| 368 | }
|
|---|
| 369 |
|
|---|
| 370 | /* if saveallargs, save the rest of the args onto the stack */
|
|---|
| 371 | while (saveallargs && argofs < NARGREGS) {
|
|---|
| 372 | NODE *p, *q;
|
|---|
| 373 | int off = ARGINIT/SZINT + argofs;
|
|---|
| 374 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 375 | regno(q) = R0 + argofs++;
|
|---|
| 376 | p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 377 | regno(p) = FPREG;
|
|---|
| 378 | p = block(PLUS, p, bcon(4*off), INT, 0, MKSUE(INT));
|
|---|
| 379 | p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
|
|---|
| 380 | p = buildtree(ASSIGN, p, q);
|
|---|
| 381 | ecomp(p);
|
|---|
| 382 | }
|
|---|
| 383 |
|
|---|
| 384 | }
|
|---|
| 385 |
|
|---|
| 386 | /*
|
|---|
| 387 | * End-of-Function code:
|
|---|
| 388 | */
|
|---|
| 389 | void
|
|---|
| 390 | efcode()
|
|---|
| 391 | {
|
|---|
| 392 | NODE *p, *q;
|
|---|
| 393 | int tempnr;
|
|---|
| 394 |
|
|---|
| 395 | if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
|
|---|
| 396 | return;
|
|---|
| 397 |
|
|---|
| 398 | /*
|
|---|
| 399 | * At this point, the address of the return structure on
|
|---|
| 400 | * has been FORCEd to RETREG, which is R0.
|
|---|
| 401 | * We want to copy the contents from there to the address
|
|---|
| 402 | * we placed into the tempnode "rvnr".
|
|---|
| 403 | */
|
|---|
| 404 |
|
|---|
| 405 | /* move the pointer out of R0 to a tempnode */
|
|---|
| 406 | q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
|
|---|
| 407 | q->n_rval = R0;
|
|---|
| 408 | p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
|
|---|
| 409 | tempnr = regno(p);
|
|---|
| 410 | p = buildtree(ASSIGN, p, q);
|
|---|
| 411 | ecomp(p);
|
|---|
| 412 |
|
|---|
| 413 | /* get the address from the tempnode */
|
|---|
| 414 | q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->ssue);
|
|---|
| 415 | q = buildtree(UMUL, q, NIL);
|
|---|
| 416 |
|
|---|
| 417 | /* now, get the structure destination */
|
|---|
| 418 | p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->ssue);
|
|---|
| 419 | p = buildtree(UMUL, p, NIL);
|
|---|
| 420 |
|
|---|
| 421 | /* struct assignment */
|
|---|
| 422 | p = buildtree(ASSIGN, p, q);
|
|---|
| 423 | ecomp(p);
|
|---|
| 424 | }
|
|---|
| 425 |
|
|---|
| 426 | /*
|
|---|
| 427 | * Beginning-of-code: finished generating function prologue
|
|---|
| 428 | *
|
|---|
| 429 | * by now, the automatics and register variables are allocated
|
|---|
| 430 | */
|
|---|
| 431 | void
|
|---|
| 432 | bccode()
|
|---|
| 433 | {
|
|---|
| 434 | SETOFF(autooff, SZINT);
|
|---|
| 435 | }
|
|---|
| 436 |
|
|---|
| 437 | /*
|
|---|
| 438 | * End-of-job: called just before final exit.
|
|---|
| 439 | */
|
|---|
| 440 | void
|
|---|
| 441 | ejobcode(int flag )
|
|---|
| 442 | {
|
|---|
| 443 | #define _MKSTR(x) #x
|
|---|
| 444 | #define MKSTR(x) _MKSTR(x)
|
|---|
| 445 | #define OS MKSTR(TARGOS)
|
|---|
| 446 | printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | /*
|
|---|
| 450 | * Beginning-of-job: called before compilation starts
|
|---|
| 451 | *
|
|---|
| 452 | * Initialise data structures specific for the local machine.
|
|---|
| 453 | */
|
|---|
| 454 | void
|
|---|
| 455 | bjobcode()
|
|---|
| 456 | {
|
|---|
| 457 | }
|
|---|
| 458 |
|
|---|
| 459 | /*
|
|---|
| 460 | * Compute the alignment of object with type 't'.
|
|---|
| 461 | */
|
|---|
| 462 | int
|
|---|
| 463 | fldal(unsigned int t)
|
|---|
| 464 | {
|
|---|
| 465 | uerror("illegal field type");
|
|---|
| 466 | return(ALINT);
|
|---|
| 467 | }
|
|---|
| 468 |
|
|---|
| 469 | /*
|
|---|
| 470 | * fix up type of field p
|
|---|
| 471 | */
|
|---|
| 472 | void
|
|---|
| 473 | fldty(struct symtab *p)
|
|---|
| 474 | {
|
|---|
| 475 | }
|
|---|
| 476 |
|
|---|
| 477 | /*
|
|---|
| 478 | * Build target-dependent switch tree/table.
|
|---|
| 479 | *
|
|---|
| 480 | * Return 1 if successfull, otherwise return 0 and the
|
|---|
| 481 | * target-independent tree will be used.
|
|---|
| 482 | */
|
|---|
| 483 | int
|
|---|
| 484 | mygenswitch(int num, TWORD type, struct swents **p, int n)
|
|---|
| 485 | {
|
|---|
| 486 | return 0;
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 |
|
|---|
| 490 | /*
|
|---|
| 491 | * Straighten a chain of CM ops so that the CM nodes
|
|---|
| 492 | * only appear on the left node.
|
|---|
| 493 | *
|
|---|
| 494 | * CM CM
|
|---|
| 495 | * CM CM CM b
|
|---|
| 496 | * x y a b CM a
|
|---|
| 497 | * x y
|
|---|
| 498 | */
|
|---|
| 499 | static NODE *
|
|---|
| 500 | straighten(NODE *p)
|
|---|
| 501 | {
|
|---|
| 502 | NODE *r = p->n_right;
|
|---|
| 503 |
|
|---|
| 504 | if (p->n_op != CM || r->n_op != CM)
|
|---|
| 505 | return p;
|
|---|
| 506 |
|
|---|
| 507 | p->n_right = r->n_left;
|
|---|
| 508 | r->n_left = p;
|
|---|
| 509 |
|
|---|
| 510 | return r;
|
|---|
| 511 | }
|
|---|
| 512 |
|
|---|
| 513 | static NODE *
|
|---|
| 514 | reverse1(NODE *p, NODE *a)
|
|---|
| 515 | {
|
|---|
| 516 | NODE *l = p->n_left;
|
|---|
| 517 | NODE *r = p->n_right;
|
|---|
| 518 |
|
|---|
| 519 | a->n_right = r;
|
|---|
| 520 | p->n_left = a;
|
|---|
| 521 |
|
|---|
| 522 | if (l->n_op == CM) {
|
|---|
| 523 | return reverse1(l, p);
|
|---|
| 524 | } else {
|
|---|
| 525 | p->n_right = l;
|
|---|
| 526 | return p;
|
|---|
| 527 | }
|
|---|
| 528 | }
|
|---|
| 529 |
|
|---|
| 530 | /*
|
|---|
| 531 | * Reverse a chain of CM ops
|
|---|
| 532 | */
|
|---|
| 533 | static NODE *
|
|---|
| 534 | reverse(NODE *p)
|
|---|
| 535 | {
|
|---|
| 536 | NODE *l = p->n_left;
|
|---|
| 537 | NODE *r = p->n_right;
|
|---|
| 538 |
|
|---|
| 539 | p->n_left = r;
|
|---|
| 540 |
|
|---|
| 541 | if (l->n_op == CM)
|
|---|
| 542 | return reverse1(l, p);
|
|---|
| 543 |
|
|---|
| 544 | p->n_right = l;
|
|---|
| 545 |
|
|---|
| 546 | return p;
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 |
|
|---|
| 550 | /* push arg onto the stack */
|
|---|
| 551 | /* called by moveargs() */
|
|---|
| 552 | static NODE *
|
|---|
| 553 | pusharg(NODE *p, int *regp)
|
|---|
| 554 | {
|
|---|
| 555 | NODE *q;
|
|---|
| 556 | int sz;
|
|---|
| 557 |
|
|---|
| 558 | /* convert to register size, if smaller */
|
|---|
| 559 | sz = tsize(p->n_type, p->n_df, p->n_sue);
|
|---|
| 560 | if (sz < SZINT)
|
|---|
| 561 | p = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
|
|---|
| 562 |
|
|---|
| 563 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 564 | regno(q) = SP;
|
|---|
| 565 |
|
|---|
| 566 | if (szty(p->n_type) == 1) {
|
|---|
| 567 | ++(*regp);
|
|---|
| 568 | q = block(MINUSEQ, q, bcon(4), INT, 0, MKSUE(INT));
|
|---|
| 569 | } else {
|
|---|
| 570 | (*regp) += 2;
|
|---|
| 571 | q = block(MINUSEQ, q, bcon(8), INT, 0, MKSUE(INT));
|
|---|
| 572 | }
|
|---|
| 573 |
|
|---|
| 574 | q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_sue);
|
|---|
| 575 |
|
|---|
| 576 | return buildtree(ASSIGN, q, p);
|
|---|
| 577 | }
|
|---|
| 578 |
|
|---|
| 579 | /* setup call stack with 32-bit argument */
|
|---|
| 580 | /* called from moveargs() */
|
|---|
| 581 | static NODE *
|
|---|
| 582 | movearg_32bit(NODE *p, int *regp)
|
|---|
| 583 | {
|
|---|
| 584 | int reg = *regp;
|
|---|
| 585 | NODE *q;
|
|---|
| 586 |
|
|---|
| 587 | q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
|
|---|
| 588 | regno(q) = reg++;
|
|---|
| 589 | q = buildtree(ASSIGN, q, p);
|
|---|
| 590 |
|
|---|
| 591 | *regp = reg;
|
|---|
| 592 | return q;
|
|---|
| 593 | }
|
|---|
| 594 |
|
|---|
| 595 | /* setup call stack with 64-bit argument */
|
|---|
| 596 | /* called from moveargs() */
|
|---|
| 597 | static NODE *
|
|---|
| 598 | movearg_64bit(NODE *p, int *regp)
|
|---|
| 599 | {
|
|---|
| 600 | int reg = *regp;
|
|---|
| 601 | NODE *q, *r;
|
|---|
| 602 |
|
|---|
| 603 | #if ALLONGLONG == 64
|
|---|
| 604 | /* alignment */
|
|---|
| 605 | ++reg;
|
|---|
| 606 | reg &= ~1;
|
|---|
| 607 | *regp = reg;
|
|---|
| 608 | #endif
|
|---|
| 609 |
|
|---|
| 610 | if (reg > R3) {
|
|---|
| 611 | q = pusharg(p, regp);
|
|---|
| 612 | } else if (reg == R3) {
|
|---|
| 613 | /* half in and half out of the registers */
|
|---|
| 614 | r = tcopy(p);
|
|---|
| 615 | if (!features(FEATURE_BIGENDIAN)) {
|
|---|
| 616 | q = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
|
|---|
| 617 | q = movearg_32bit(q, regp); /* little-endian */
|
|---|
| 618 | r = buildtree(RS, r, bcon(32));
|
|---|
| 619 | r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
|
|---|
| 620 | r = pusharg(r, regp); /* little-endian */
|
|---|
| 621 | } else {
|
|---|
| 622 | q = buildtree(RS, p, bcon(32));
|
|---|
| 623 | q = block(SCONV, q, NIL, INT, 0, MKSUE(INT));
|
|---|
| 624 | q = movearg_32bit(q, regp); /* big-endian */
|
|---|
| 625 | r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
|
|---|
| 626 | r = pusharg(r, regp); /* big-endian */
|
|---|
| 627 | }
|
|---|
| 628 | q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_sue));
|
|---|
| 629 | } else {
|
|---|
| 630 | q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
|
|---|
| 631 | regno(q) = R0R1 + (reg - R0);
|
|---|
| 632 | q = buildtree(ASSIGN, q, p);
|
|---|
| 633 | *regp = reg + 2;
|
|---|
| 634 | }
|
|---|
| 635 |
|
|---|
| 636 | return q;
|
|---|
| 637 | }
|
|---|
| 638 |
|
|---|
| 639 | /* setup call stack with float/double argument */
|
|---|
| 640 | /* called from moveargs() */
|
|---|
| 641 | static NODE *
|
|---|
| 642 | movearg_float(NODE *p, int *regp)
|
|---|
| 643 | {
|
|---|
| 644 | NODE *q, *r;
|
|---|
| 645 | TWORD ty = INCREF(p->n_type);
|
|---|
| 646 | int tmpnr;
|
|---|
| 647 |
|
|---|
| 648 | /*
|
|---|
| 649 | * Floats are passed in the general registers for
|
|---|
| 650 | * compatibily with libraries compiled to handle soft-float.
|
|---|
| 651 | */
|
|---|
| 652 |
|
|---|
| 653 | if (xtemps) {
|
|---|
| 654 | /* bounce on TOS */
|
|---|
| 655 | r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
|
|---|
| 656 | regno(r) = SP;
|
|---|
| 657 | r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_sue);
|
|---|
| 658 | r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
|
|---|
| 659 | r = buildtree(ASSIGN, r, p);
|
|---|
| 660 | ecomp(r);
|
|---|
| 661 |
|
|---|
| 662 | /* bounce into temp */
|
|---|
| 663 | r = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT));
|
|---|
| 664 | regno(r) = SP;
|
|---|
| 665 | r = block(PLUS, r, bcon(-8), PTR+INT, 0, MKSUE(INT));
|
|---|
| 666 | r = block(UMUL, r, NIL, INT, 0, MKSUE(INT));
|
|---|
| 667 | q = tempnode(0, INT, 0, MKSUE(INT));
|
|---|
| 668 | tmpnr = regno(q);
|
|---|
| 669 | r = buildtree(ASSIGN, q, r);
|
|---|
| 670 | ecomp(r);
|
|---|
| 671 | } else {
|
|---|
| 672 | /* copy directly into temp */
|
|---|
| 673 | q = tempnode(0, p->n_type, p->n_df, p->n_sue);
|
|---|
| 674 | tmpnr = regno(q);
|
|---|
| 675 | r = buildtree(ASSIGN, q, p);
|
|---|
| 676 | ecomp(r);
|
|---|
| 677 | }
|
|---|
| 678 |
|
|---|
| 679 | /* copy from temp to register parameter */
|
|---|
| 680 | r = tempnode(tmpnr, INT, 0, MKSUE(INT));
|
|---|
| 681 | q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 682 | regno(q) = (*regp)++;
|
|---|
| 683 | p = buildtree(ASSIGN, q, r);
|
|---|
| 684 |
|
|---|
| 685 | return p;
|
|---|
| 686 | }
|
|---|
| 687 |
|
|---|
| 688 | /* setup call stack with float/double argument */
|
|---|
| 689 | /* called from moveargs() */
|
|---|
| 690 | static NODE *
|
|---|
| 691 | movearg_double(NODE *p, int *regp)
|
|---|
| 692 | {
|
|---|
| 693 | NODE *q, *r;
|
|---|
| 694 | TWORD ty = INCREF(p->n_type);
|
|---|
| 695 | int tmpnr;
|
|---|
| 696 |
|
|---|
| 697 | if (xtemps) {
|
|---|
| 698 | /* bounce on TOS */
|
|---|
| 699 | r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
|
|---|
| 700 | regno(r) = SP;
|
|---|
| 701 | r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_sue);
|
|---|
| 702 | r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
|
|---|
| 703 | r = buildtree(ASSIGN, r, p);
|
|---|
| 704 | ecomp(r);
|
|---|
| 705 |
|
|---|
| 706 | /* bounce into temp */
|
|---|
| 707 | r = block(REG, NIL, NIL, PTR+LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 708 | regno(r) = SP;
|
|---|
| 709 | r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 710 | r = block(UMUL, r, NIL, LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 711 | q = tempnode(0, LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 712 | tmpnr = regno(q);
|
|---|
| 713 | r = buildtree(ASSIGN, q, r);
|
|---|
| 714 | ecomp(r);
|
|---|
| 715 | } else {
|
|---|
| 716 | /* copy directly into temp */
|
|---|
| 717 | q = tempnode(0, p->n_type, p->n_df, p->n_sue);
|
|---|
| 718 | tmpnr = regno(q);
|
|---|
| 719 | r = buildtree(ASSIGN, q, p);
|
|---|
| 720 | ecomp(r);
|
|---|
| 721 | }
|
|---|
| 722 |
|
|---|
| 723 | /* copy from temp to register parameter */
|
|---|
| 724 | r = tempnode(tmpnr, LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 725 | q = block(REG, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG));
|
|---|
| 726 | regno(q) = R0R1 - R0 + (*regp);
|
|---|
| 727 | p = buildtree(ASSIGN, q, r);
|
|---|
| 728 |
|
|---|
| 729 | (*regp) += 2;
|
|---|
| 730 |
|
|---|
| 731 | return p;
|
|---|
| 732 | }
|
|---|
| 733 |
|
|---|
| 734 |
|
|---|
| 735 | /* setup call stack with a structure */
|
|---|
| 736 | /* called from moveargs() */
|
|---|
| 737 | static NODE *
|
|---|
| 738 | movearg_struct(NODE *p, int *regp)
|
|---|
| 739 | {
|
|---|
| 740 | int reg = *regp;
|
|---|
| 741 | NODE *l, *q, *t, *r;
|
|---|
| 742 | int tmpnr;
|
|---|
| 743 | int navail;
|
|---|
| 744 | int num;
|
|---|
| 745 | int sz;
|
|---|
| 746 | int ty;
|
|---|
| 747 | int i;
|
|---|
| 748 |
|
|---|
| 749 | assert(p->n_op == STARG);
|
|---|
| 750 |
|
|---|
| 751 | navail = NARGREGS - (reg - R0);
|
|---|
| 752 | navail = navail < 0 ? 0 : navail;
|
|---|
| 753 | sz = tsize(p->n_type, p->n_df, p->n_sue) / SZINT;
|
|---|
| 754 | num = sz > navail ? navail : sz;
|
|---|
| 755 |
|
|---|
| 756 | /* remove STARG node */
|
|---|
| 757 | l = p->n_left;
|
|---|
| 758 | nfree(p);
|
|---|
| 759 | ty = l->n_type;
|
|---|
| 760 |
|
|---|
| 761 | /*
|
|---|
| 762 | * put it into a TEMP, rather than tcopy(), since the tree
|
|---|
| 763 | * in p may have side-affects
|
|---|
| 764 | */
|
|---|
| 765 | t = tempnode(0, ty, l->n_df, l->n_sue);
|
|---|
| 766 | tmpnr = regno(t);
|
|---|
| 767 | q = buildtree(ASSIGN, t, l);
|
|---|
| 768 |
|
|---|
| 769 | /* copy structure into registers */
|
|---|
| 770 | for (i = 0; i < num; i++) {
|
|---|
| 771 | t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
|
|---|
| 772 | t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
|
|---|
| 773 | t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
|
|---|
| 774 | t = buildtree(UMUL, t, NIL);
|
|---|
| 775 |
|
|---|
| 776 | r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
|
|---|
| 777 | regno(r) = reg++;
|
|---|
| 778 | r = buildtree(ASSIGN, r, t);
|
|---|
| 779 |
|
|---|
| 780 | q = block(CM, q, r, INT, 0, MKSUE(INT));
|
|---|
| 781 | }
|
|---|
| 782 |
|
|---|
| 783 | /* put the rest of the structure on the stack */
|
|---|
| 784 | for (i = num; i < sz; i++) {
|
|---|
| 785 | t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
|
|---|
| 786 | t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
|
|---|
| 787 | t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
|
|---|
| 788 | t = buildtree(UMUL, t, NIL);
|
|---|
| 789 | r = pusharg(t, ®);
|
|---|
| 790 | q = block(CM, q, r, INT, 0, MKSUE(INT));
|
|---|
| 791 | }
|
|---|
| 792 |
|
|---|
| 793 | q = reverse(q);
|
|---|
| 794 |
|
|---|
| 795 | *regp = reg;
|
|---|
| 796 | return q;
|
|---|
| 797 | }
|
|---|
| 798 |
|
|---|
| 799 |
|
|---|
| 800 | static NODE *
|
|---|
| 801 | moveargs(NODE *p, int *regp)
|
|---|
| 802 | {
|
|---|
| 803 | NODE *r, **rp;
|
|---|
| 804 | int reg;
|
|---|
| 805 |
|
|---|
| 806 | if (p->n_op == CM) {
|
|---|
| 807 | p->n_left = moveargs(p->n_left, regp);
|
|---|
| 808 | r = p->n_right;
|
|---|
| 809 | rp = &p->n_right;
|
|---|
| 810 | } else {
|
|---|
| 811 | r = p;
|
|---|
| 812 | rp = &p;
|
|---|
| 813 | }
|
|---|
| 814 |
|
|---|
| 815 | reg = *regp;
|
|---|
| 816 |
|
|---|
| 817 | if (reg > R3 && r->n_op != STARG) {
|
|---|
| 818 | *rp = pusharg(r, regp);
|
|---|
| 819 | } else if (r->n_op == STARG) {
|
|---|
| 820 | *rp = movearg_struct(r, regp);
|
|---|
| 821 | } else if (DEUNSIGN(r->n_type) == LONGLONG) {
|
|---|
| 822 | *rp = movearg_64bit(r, regp);
|
|---|
| 823 | } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
|
|---|
| 824 | *rp = movearg_double(r, regp);
|
|---|
| 825 | } else if (r->n_type == FLOAT) {
|
|---|
| 826 | *rp = movearg_float(r, regp);
|
|---|
| 827 | } else {
|
|---|
| 828 | *rp = movearg_32bit(r, regp);
|
|---|
| 829 | }
|
|---|
| 830 |
|
|---|
| 831 | return straighten(p);
|
|---|
| 832 | }
|
|---|
| 833 |
|
|---|
| 834 | /*
|
|---|
| 835 | * Fixup arguments to pass pointer-to-struct as first argument.
|
|---|
| 836 | *
|
|---|
| 837 | * called from funcode().
|
|---|
| 838 | */
|
|---|
| 839 | static NODE *
|
|---|
| 840 | retstruct(NODE *p)
|
|---|
| 841 | {
|
|---|
| 842 | NODE *l, *r, *t, *q;
|
|---|
| 843 | TWORD ty;
|
|---|
| 844 |
|
|---|
| 845 | l = p->n_left;
|
|---|
| 846 | r = p->n_right;
|
|---|
| 847 |
|
|---|
| 848 | ty = DECREF(l->n_type) - FTN;
|
|---|
| 849 |
|
|---|
| 850 | // assert(tsize(ty, l->n_df, l->n_sue) == SZINT);
|
|---|
| 851 |
|
|---|
| 852 | /* structure assign */
|
|---|
| 853 | q = tempnode(0, ty, l->n_df, l->n_sue);
|
|---|
| 854 | q = buildtree(ADDROF, q, NIL);
|
|---|
| 855 |
|
|---|
| 856 | /* insert hidden assignment at beginning of list */
|
|---|
| 857 | if (r->n_op != CM) {
|
|---|
| 858 | p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_sue);
|
|---|
| 859 | } else {
|
|---|
| 860 | for (t = r; t->n_left->n_op == CM; t = t->n_left)
|
|---|
| 861 | ;
|
|---|
| 862 | t->n_left = block(CM, q, t->n_left, INCREF(ty),
|
|---|
| 863 | l->n_df, l->n_sue);
|
|---|
| 864 | }
|
|---|
| 865 |
|
|---|
| 866 | return p;
|
|---|
| 867 | }
|
|---|
| 868 |
|
|---|
| 869 | /*
|
|---|
| 870 | * Called with a function call with arguments as argument.
|
|---|
| 871 | * This is done early in buildtree() and only done once.
|
|---|
| 872 | */
|
|---|
| 873 | NODE *
|
|---|
| 874 | funcode(NODE *p)
|
|---|
| 875 | {
|
|---|
| 876 | int reg = R0;
|
|---|
| 877 |
|
|---|
| 878 | if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) {
|
|---|
| 879 | p = retstruct(p);
|
|---|
| 880 | reg = R1;
|
|---|
| 881 | }
|
|---|
| 882 |
|
|---|
| 883 | p->n_right = moveargs(p->n_right, ®);
|
|---|
| 884 |
|
|---|
| 885 | if (p->n_right == NULL)
|
|---|
| 886 | p->n_op += (UCALL - CALL);
|
|---|
| 887 |
|
|---|
| 888 | return p;
|
|---|
| 889 | }
|
|---|