1 /* Id: code.c,v 1.2 2014/11/11 07:43:07 ragge Exp */ 2 /* $NetBSD: code.c,v 1.1.1.1 2016/02/09 20:28:37 plunky Exp $ */ 3 /* 4 * Copyright (c) 2003 Anders Magnusson (ragge (at) 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 # include "pass1.h" 32 33 /* 34 * Print out assembler segment name. 35 */ 36 void 37 setseg(int seg, char *name) 38 { 39 switch (seg) { 40 case PROG: name = ".TEXT"; break; 41 case DATA: 42 case LDATA: name = ".DATA"; break; 43 case UDATA: break; 44 case STRNG: 45 case RDATA: name = ".DATA"; break; 46 case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; 47 case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; 48 case NMSEG: 49 printf("\t.section %s,\"a%c\",@progbits\n", name, 50 cftnsp ? 'x' : 'w'); 51 return; 52 } 53 printf("\t%s\n", name); 54 } 55 56 /* 57 * Define everything needed to print out some data (or text). 58 * This means segment, alignment, visibility, etc. 59 */ 60 void 61 defloc(struct symtab *sp) 62 { 63 char *name; 64 65 if ((name = sp->soname) == NULL) 66 name = exname(sp->sname); 67 if (sp->sclass == EXTDEF) { 68 printf(" .globl %s\n", name); 69 } 70 if (sp->slevel == 0) 71 printf("%s:\n", name); 72 else 73 printf(LABFMT ":\n", sp->soffset); 74 } 75 76 int structrettemp; 77 78 /* 79 * code for the end of a function 80 * deals with struct return here 81 */ 82 void 83 efcode(void) 84 { 85 extern int gotnr; 86 NODE *p, *q; 87 88 gotnr = 0; /* new number for next fun */ 89 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) 90 return; 91 /* Create struct assignment */ 92 q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap); 93 q = buildtree(UMUL, q, NIL); 94 p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); 95 p = buildtree(UMUL, p, NIL); 96 p = buildtree(ASSIGN, q, p); 97 ecomp(p); 98 99 /* put hidden arg in ax on return */ 100 q = tempnode(structrettemp, INT, 0, 0); 101 p = block(REG, NIL, NIL, INT, 0, 0); 102 regno(p) = AX; 103 ecomp(buildtree(ASSIGN, p, q)); 104 } 105 106 static TWORD longregs[] = { AXDX, DXCX }; 107 static TWORD regpregs[] = { AX, DX, CX }; 108 static TWORD charregs[] = { AL, DL, CL }; 109 110 /* 111 * code for the beginning of a function; a is an array of 112 * indices in symtab for the arguments; n is the number 113 * 114 * Classifying args on i386; not simple: 115 * - Args may be on stack or in registers (regparm) 116 * - There may be a hidden first arg, unless OpenBSD struct return. 117 * - Regparm syntax is not well documented. 118 * - There may be stdcall functions, where the called function pops stack 119 * - ...probably more 120 */ 121 void 122 bfcode(struct symtab **sp, int cnt) 123 { 124 extern int argstacksize; 125 #ifdef GCC_COMPAT 126 struct attr *ap; 127 #endif 128 struct symtab *sp2; 129 extern int gotnr; 130 NODE *n, *p; 131 int i, regparmarg; 132 int argbase, nrarg, sz; 133 134 argbase = ARGINIT; 135 nrarg = regparmarg = 0; 136 137 #ifdef GCC_COMPAT 138 if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL) 139 cftnsp->sflags |= SSTDCALL; 140 if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) 141 regparmarg = ap->iarg(0); 142 #endif 143 144 /* Function returns struct, create return arg node */ 145 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { 146 { 147 if (regparmarg) { 148 n = block(REG, 0, 0, INT, 0, 0); 149 regno(n) = regpregs[nrarg++]; 150 } else { 151 n = block(OREG, 0, 0, INT, 0, 0); 152 n->n_lval = argbase/SZCHAR; 153 argbase += SZINT; 154 regno(n) = FPREG; 155 } 156 p = tempnode(0, INT, 0, 0); 157 structrettemp = regno(p); 158 p = buildtree(ASSIGN, p, n); 159 ecomp(p); 160 } 161 } 162 163 /* 164 * Find where all params are so that they end up at the right place. 165 * At the same time recalculate their arg offset on stack. 166 * We also get the "pop size" for stdcall. 167 */ 168 for (i = 0; i < cnt; i++) { 169 sp2 = sp[i]; 170 sz = tsize(sp2->stype, sp2->sdf, sp2->sap); 171 172 SETOFF(sz, SZINT); 173 174 if (cisreg(sp2->stype) == 0 || 175 ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ 176 sp2->soffset = argbase; 177 argbase += sz; 178 nrarg = regparmarg; /* no more in reg either */ 179 } else { /* in reg */ 180 sp2->soffset = nrarg; 181 nrarg += sz/SZINT; 182 sp2->sclass = REGISTER; 183 } 184 } 185 186 /* 187 * Now (argbase - ARGINIT) is used space on stack. 188 * Move (if necessary) the args to something new. 189 */ 190 for (i = 0; i < cnt; i++) { 191 int reg, j; 192 193 sp2 = sp[i]; 194 195 if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) { 196 /* must move to stack */ 197 sz = tsize(sp2->stype, sp2->sdf, sp2->sap); 198 SETOFF(sz, SZINT); 199 SETOFF(autooff, SZINT); 200 reg = sp2->soffset; 201 sp2->sclass = AUTO; 202 sp2->soffset = NOOFFSET; 203 oalloc(sp2, &autooff); 204 for (j = 0; j < sz/SZCHAR; j += 4) { 205 p = block(OREG, 0, 0, INT, 0, 0); 206 p->n_lval = sp2->soffset/SZCHAR + j; 207 regno(p) = FPREG; 208 n = block(REG, 0, 0, INT, 0, 0); 209 regno(n) = regpregs[reg++]; 210 p = block(ASSIGN, p, n, INT, 0, 0); 211 ecomp(p); 212 } 213 } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && 214 ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) { 215 /* just put rest in temps */ 216 if (sp2->sclass == REGISTER) { 217 n = block(REG, 0, 0, sp2->stype, 218 sp2->sdf, sp2->sap); 219 if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG) 220 regno(n) = longregs[sp2->soffset]; 221 else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL) 222 regno(n) = charregs[sp2->soffset]; 223 else 224 regno(n) = regpregs[sp2->soffset]; 225 } else { 226 n = block(OREG, 0, 0, sp2->stype, 227 sp2->sdf, sp2->sap); 228 n->n_lval = sp2->soffset/SZCHAR; 229 regno(n) = FPREG; 230 } 231 p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); 232 sp2->soffset = regno(p); 233 sp2->sflags |= STNODE; 234 n = buildtree(ASSIGN, p, n); 235 ecomp(n); 236 } 237 } 238 239 argstacksize = 0; 240 if (cftnsp->sflags & SSTDCALL) { 241 argstacksize = (argbase - ARGINIT)/SZCHAR; 242 } 243 244 } 245 246 247 /* called just before final exit */ 248 /* flag is 1 if errors, 0 if none */ 249 void 250 ejobcode(int flag) 251 { 252 printf("\t.asciz \"PCC: %s\"\n", VERSSTR); 253 } 254 255 void 256 bjobcode(void) 257 { 258 astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; 259 } 260 261 /* 262 * Convert FUNARG to assign in case of regparm. 263 */ 264 static int regcvt, rparg; 265 static void 266 addreg(NODE *p) 267 { 268 TWORD t; 269 NODE *q; 270 int sz, r; 271 272 sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; 273 sz = (sz + 3) >> 2; /* sz in regs */ 274 if ((regcvt+sz) > rparg) { 275 regcvt = rparg; 276 return; 277 } 278 if (sz > 2) 279 uerror("cannot put struct in 3 regs (yet)"); 280 281 if (sz == 2) 282 r = regcvt == 0 ? AXDX : DXCX; 283 else 284 r = regcvt == 0 ? AX : regcvt == 1 ? DX : CX; 285 286 if (p->n_op == FUNARG) { 287 /* at most 2 regs */ 288 if (p->n_type < INT) { 289 p->n_left = ccast(p->n_left, INT, 0, 0, 0); 290 p->n_type = INT; 291 } 292 293 p->n_op = ASSIGN; 294 p->n_right = p->n_left; 295 } else if (p->n_op == STARG) { 296 /* convert to ptr, put in reg */ 297 q = p->n_left; 298 t = sz == 2 ? LONGLONG : INT; 299 q = cast(q, INCREF(t), 0); 300 q = buildtree(UMUL, q, NIL); 301 p->n_op = ASSIGN; 302 p->n_type = t; 303 p->n_right = q; 304 } else 305 cerror("addreg"); 306 p->n_left = block(REG, 0, 0, p->n_type, 0, 0); 307 regno(p->n_left) = r; 308 regcvt += sz; 309 } 310 311 /* 312 * Called with a function call with arguments as argument. 313 * This is done early in buildtree() and only done once. 314 * Returns p. 315 */ 316 NODE * 317 funcode(NODE *p) 318 { 319 extern int gotnr; 320 #ifdef GCC_COMPAT 321 struct attr *ap; 322 #endif 323 NODE *r, *l; 324 TWORD t = DECREF(DECREF(p->n_left->n_type)); 325 int stcall; 326 327 stcall = ISSOU(t); 328 /* 329 * We may have to prepend: 330 * - Hidden arg0 for struct return (in reg or on stack). 331 * - ebx in case of PIC code. 332 */ 333 334 /* Fix function call arguments. On x86, just add funarg */ 335 for (r = p->n_right; r->n_op == CM; r = r->n_left) { 336 if (r->n_right->n_op != STARG) { 337 r->n_right = intprom(r->n_right); 338 r->n_right = block(FUNARG, r->n_right, NIL, 339 r->n_right->n_type, r->n_right->n_df, 340 r->n_right->n_ap); 341 } 342 } 343 if (r->n_op != STARG) { 344 l = talloc(); 345 *l = *r; 346 r->n_op = FUNARG; 347 r->n_left = l; 348 r->n_left = intprom(r->n_left); 349 r->n_type = r->n_left->n_type; 350 } 351 if (stcall) { 352 /* Prepend a placeholder for struct address. */ 353 /* Use BP, can never show up under normal circumstances */ 354 l = talloc(); 355 *l = *r; 356 r->n_op = CM; 357 r->n_right = l; 358 r->n_type = INT; 359 l = block(REG, 0, 0, INCREF(VOID), 0, 0); 360 regno(l) = BP; 361 l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); 362 r->n_left = l; 363 } 364 365 #ifdef GCC_COMPAT 366 if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) 367 rparg = ap->iarg(0); 368 else 369 #endif 370 rparg = 0; 371 372 regcvt = 0; 373 if (rparg) 374 listf(p->n_right, addreg); 375 376 return p; 377 } 378 379 /* fix up type of field p */ 380 void 381 fldty(struct symtab *p) 382 { 383 } 384 385 /* 386 * XXX - fix genswitch. 387 */ 388 int 389 mygenswitch(int num, TWORD type, struct swents **p, int n) 390 { 391 return 0; 392 } 393 394 NODE * 395 builtin_return_address(const struct bitable *bt, NODE *a) 396 { 397 int nframes; 398 NODE *f; 399 400 if (a->n_op != ICON) 401 goto bad; 402 403 nframes = (int)a->n_lval; 404 405 tfree(a); 406 407 f = block(REG, NIL, NIL, PTR+VOID, 0, 0); 408 regno(f) = FPREG; 409 410 while (nframes--) 411 f = block(UMUL, f, NIL, PTR+VOID, 0, 0); 412 413 f = block(PLUS, f, bcon(2), INCREF(PTR+VOID), 0, 0); 414 f = buildtree(UMUL, f, NIL); 415 416 return f; 417 bad: 418 uerror("bad argument to __builtin_return_address"); 419 return bcon(0); 420 } 421 422 NODE * 423 builtin_frame_address(const struct bitable *bt, NODE *a) 424 { 425 int nframes; 426 NODE *f; 427 428 if (a->n_op != ICON) 429 goto bad; 430 431 nframes = (int)a->n_lval; 432 433 tfree(a); 434 435 f = block(REG, NIL, NIL, PTR+VOID, 0, 0); 436 regno(f) = FPREG; 437 438 while (nframes--) 439 f = block(UMUL, f, NIL, PTR+VOID, 0, 0); 440 441 return f; 442 bad: 443 uerror("bad argument to __builtin_frame_address"); 444 return bcon(0); 445 } 446 447 /* 448 * Return "canonical frame address". 449 */ 450 NODE * 451 builtin_cfa(const struct bitable *bt, NODE *a) 452 { 453 uerror("missing builtin_cfa"); 454 return bcon(0); 455 } 456 457