1 /* Id: local.c,v 1.15 2008/12/14 21:16:58 ragge Exp */ 2 /* $NetBSD: local.c,v 1.1.1.3 2010/06/03 18:57:17 plunky Exp $ */ 3 /* 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 # include "pass1.h" 32 33 /* this file contains code which is dependent on the target machine */ 34 35 NODE * 36 clocal(NODE *p) 37 { 38 /* this is called to do local transformations on 39 an expression tree preparitory to its being 40 written out in intermediate code. 41 */ 42 43 /* the major essential job is rewriting the 44 automatic variables and arguments in terms of 45 REG and OREG nodes */ 46 /* conversion ops which are not necessary are also clobbered here */ 47 /* in addition, any special features (such as rewriting 48 exclusive or) are easily handled here as well */ 49 50 struct symtab *q; 51 NODE *l, *r; 52 int o; 53 TWORD ml; 54 55 switch( o = p->n_op ){ 56 57 case NAME: 58 if ((q = p->n_sp) == NULL) 59 return p; /* Nothing to care about */ 60 61 switch (q->sclass) { 62 63 case PARAM: 64 case AUTO: 65 /* fake up a structure reference */ 66 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); 67 r->n_lval = 0; 68 r->n_rval = FPREG; 69 p = stref(block(STREF, r, p, 0, 0, 0)); 70 break; 71 72 case STATIC: 73 if (q->slevel == 0) 74 break; 75 p->n_lval = 0; 76 p->n_sp = q; 77 break; 78 79 case REGISTER: 80 p->n_op = REG; 81 p->n_lval = 0; 82 p->n_rval = q->soffset; 83 break; 84 85 } 86 break; 87 88 case PMCONV: 89 case PVCONV: 90 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); 91 nfree(p); 92 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); 93 94 case PCONV: 95 ml = p->n_left->n_type; 96 l = p->n_left; 97 if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON) 98 break; 99 l->n_type = p->n_type; 100 l->n_qual = p->n_qual; 101 l->n_df = p->n_df; 102 l->n_sue = p->n_sue; 103 nfree(p); 104 p = l; 105 break; 106 107 case SCONV: 108 l = p->n_left; 109 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) { 110 nfree(p); 111 return l; 112 } 113 if (l->n_op == ICON) { 114 CONSZ val = l->n_lval; 115 switch (p->n_type) { 116 case CHAR: 117 l->n_lval = (char)val; 118 break; 119 case UCHAR: 120 l->n_lval = val & 0377; 121 break; 122 case SHORT: 123 case INT: 124 l->n_lval = (short)val; 125 break; 126 case USHORT: 127 case UNSIGNED: 128 l->n_lval = val & 0177777; 129 break; 130 case ULONG: 131 case ULONGLONG: 132 l->n_lval = val & 0xffffffff; 133 break; 134 case LONG: 135 case LONGLONG: 136 l->n_lval = (int)val; 137 break; 138 case VOID: 139 break; 140 case LDOUBLE: 141 case DOUBLE: 142 case FLOAT: 143 l->n_op = FCON; 144 l->n_dcon = val; 145 break; 146 default: 147 cerror("unknown type %d", p->n_type); 148 } 149 l->n_type = p->n_type; 150 nfree(p); 151 return l; 152 } 153 break; 154 155 156 } 157 158 return(p); 159 } 160 161 /*ARGSUSED*/ 162 int 163 andable(NODE *p) 164 { 165 return(1); /* all names can have & taken on them */ 166 } 167 168 /* 169 * at the end of the arguments of a ftn, set the automatic offset 170 */ 171 void 172 cendarg() 173 { 174 autooff = AUTOINIT; 175 } 176 177 /* 178 * is an automatic variable of type t OK for a register variable 179 */ 180 int 181 cisreg(TWORD t) 182 { 183 if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR || 184 ISPTR(t)) 185 return(1); 186 return 0; /* XXX - fix reg assignment in pftn.c */ 187 } 188 189 /* 190 * return a node, for structure references, which is suitable for 191 * being added to a pointer of type t, in order to be off bits offset 192 * into a structure 193 * t, d, and s are the type, dimension offset, and sizeoffset 194 * For pdp10, return the type-specific index number which calculation 195 * is based on its size. For example, short a[3] would return 3. 196 * Be careful about only handling first-level pointers, the following 197 * indirections must be fullword. 198 */ 199 NODE * 200 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) 201 { 202 register NODE *p; 203 204 if (xdebug) 205 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", 206 off, t, d, sue->suesize); 207 208 p = bcon(0); 209 p->n_lval = off/SZCHAR; /* Default */ 210 return(p); 211 } 212 213 /* 214 * Allocate off bits on the stack. p is a tree that when evaluated 215 * is the multiply count for off, t is a NAME node where to write 216 * the allocated address. 217 */ 218 void 219 spalloc(NODE *t, NODE *p, OFFSZ off) 220 { 221 NODE *sp; 222 223 if ((off % SZINT) == 0) 224 p = buildtree(MUL, p, bcon(off/SZINT)); 225 else if ((off % SZSHORT) == 0) { 226 p = buildtree(MUL, p, bcon(off/SZSHORT)); 227 p = buildtree(PLUS, p, bcon(1)); 228 p = buildtree(RS, p, bcon(1)); 229 } else if ((off % SZCHAR) == 0) { 230 p = buildtree(MUL, p, bcon(off/SZCHAR)); 231 p = buildtree(PLUS, p, bcon(3)); 232 p = buildtree(RS, p, bcon(2)); 233 } else 234 cerror("roundsp"); 235 236 /* save the address of sp */ 237 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); 238 sp->n_lval = 0; 239 sp->n_rval = STKREG; 240 t->n_type = sp->n_type; 241 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ 242 243 /* add the size to sp */ 244 sp = block(REG, NIL, NIL, p->n_type, 0, 0); 245 sp->n_lval = 0; 246 sp->n_rval = STKREG; 247 ecomp(buildtree(PLUSEQ, sp, p)); 248 } 249 250 /* 251 * print out a constant node 252 * mat be associated with a label 253 */ 254 void 255 ninval(NODE *p) 256 { 257 struct symtab *q; 258 TWORD t; 259 260 p = p->n_left; 261 t = p->n_type; 262 if (t > BTMASK) 263 t = INT; /* pointer */ 264 265 switch (t) { 266 case LONGLONG: 267 case ULONGLONG: 268 inval(p->n_lval & 0xffffffff); 269 inval(p->n_lval >> 32); 270 break; 271 case LONG: 272 case ULONG: 273 case INT: 274 case UNSIGNED: 275 printf("\t.long 0x%x", (int)p->n_lval); 276 if ((q = p->n_sp) != NULL) { 277 if ((q->sclass == STATIC && q->slevel > 0)) { 278 printf("+" LABFMT, q->soffset); 279 } else 280 printf("+%s", exname(q->soname)); 281 } 282 printf("\n"); 283 break; 284 default: 285 fwalk(p, eprint, 0); 286 cerror("ninval"); 287 } 288 } 289 290 /* 291 * print out an integer. 292 */ 293 void 294 inval(CONSZ word) 295 { 296 word &= 0xffffffff; 297 printf(" .long 0x%llx\n", word); 298 } 299 300 /* output code to initialize a floating point value */ 301 /* the proper alignment has been obtained */ 302 void 303 finval(NODE *p) 304 { 305 switch (p->n_type) { 306 case LDOUBLE: 307 printf("\t.tfloat\t0t%.20Le\n", p->n_dcon); 308 break; 309 case DOUBLE: 310 printf("\t.dfloat\t0d%.20e\n", (double)p->n_dcon); 311 break; 312 case FLOAT: 313 printf("\t.ffloat\t0f%.20e\n", (float)p->n_dcon); 314 break; 315 } 316 } 317 318 /* make a name look like an external name in the local machine */ 319 char * 320 exname(char *p) 321 { 322 if (p == NULL) 323 return ""; 324 return p; 325 } 326 327 /* 328 * map types which are not defined on the local machine 329 */ 330 TWORD 331 ctype(TWORD type) 332 { 333 switch (BTYPE(type)) { 334 case SHORT: 335 MODTYPE(type,INT); 336 break; 337 338 case USHORT: 339 MODTYPE(type,UNSIGNED); 340 break; 341 342 case LONGLONG: 343 MODTYPE(type,LONG); 344 break; 345 346 case ULONGLONG: 347 MODTYPE(type,ULONG); 348 break; 349 350 case LDOUBLE: 351 MODTYPE(type,DOUBLE); 352 break; 353 } 354 return (type); 355 } 356 357 /* curid is a variable which is defined but 358 * is not initialized (and not a function ); 359 * This routine returns the storage class for an uninitialized declaration 360 */ 361 int 362 noinit() 363 { 364 return(EXTERN); 365 } 366 367 /* 368 * Extern variable not necessary common. 369 */ 370 void 371 extdec(struct symtab *q) 372 { 373 extern void addsym(struct symtab *); 374 addsym(q); 375 } 376 377 /* 378 * Call to a function 379 */ 380 void 381 calldec(NODE *p, NODE *r) 382 { 383 struct symtab *q = p->n_sp; 384 extern void addsym(struct symtab *); 385 addsym(q); 386 } 387 388 /* make a common declaration for id, if reasonable */ 389 void 390 commdec(struct symtab *q) 391 { 392 int off; 393 char *c = q->soname; 394 395 off = tsize(q->stype, q->sdf, q->ssue); 396 off = (off+(SZCHAR-1))/SZCHAR; 397 398 printf(" PUBLIC %s\n", c); 399 /* XXX - NOROOT??? */ 400 printf(" RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n"); 401 printf("%s:\n", c); 402 printf(" DS8 %d\n", off); 403 printf(" REQUIRE __data16_zero\n"); 404 } 405 406 /* make a local common declaration for id, if reasonable */ 407 void 408 lcommdec(struct symtab *q) 409 { 410 int off; 411 412 off = tsize(q->stype, q->sdf, q->ssue); 413 off = (off+(SZCHAR-1))/SZCHAR; 414 if (q->slevel == 0) 415 printf(" .lcomm %s,0%o\n", exname(q->soname), off); 416 else 417 printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); 418 } 419 420 /* 421 * print a (non-prog) label. 422 */ 423 void 424 deflab1(int label) 425 { 426 printf(LABFMT ":\n", label); 427 } 428 429 void 430 setloc1(int locc) 431 { 432 if (locc == lastloc) 433 return; 434 lastloc = locc; 435 } 436 437 /* 438 * special handling before tree is written out. 439 */ 440 void 441 myp2tree(NODE *p) 442 { 443 struct symtab *sp; 444 union dimfun *df; 445 union arglist *al; 446 NODE *q; 447 int i; 448 449 switch (p->n_op) { 450 case MOD: 451 case DIV: 452 if (p->n_type == LONG || p->n_type == ULONG) { 453 /* Swap arguments for hardops() later */ 454 q = p->n_left; 455 p->n_left = p->n_right; 456 p->n_right = q; 457 } 458 break; 459 460 case CALL: 461 case STCALL: 462 /* 463 * inform pass2 about varargs. 464 * store first variadic argument number in n_stalign 465 * in the CM node. 466 */ 467 if (p->n_right->n_op != CM) 468 break; /* nothing to care about */ 469 df = p->n_left->n_df; 470 if (df && (al = df->dfun)) { 471 for (i = 0; i < 6; i++, al++) { 472 if (al->type == TELLIPSIS || al->type == TNULL) 473 break; 474 } 475 p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0; 476 } else 477 p->n_right->n_stalign = 0; 478 break; 479 480 case FCON: 481 /* Write float constants to memory */ 482 sp = inlalloc(sizeof(struct symtab)); 483 sp->sclass = STATIC; 484 sp->ssue = MKSUE(p->n_type); 485 sp->slevel = 1; /* fake numeric label */ 486 sp->soffset = getlab(); 487 sp->sflags = 0; 488 sp->stype = p->n_type; 489 sp->squal = (CON >> TSHIFT); 490 491 defloc(sp); 492 ninval(0, sp->ssue->suesize, p); 493 494 p->n_op = NAME; 495 p->n_lval = 0; 496 p->n_sp = sp; 497 break; 498 } 499 500 } 501 /* 502 * Give target the opportunity of handling pragmas. 503 */ 504 int 505 mypragma(char **ary) 506 { 507 return 0; } 508 509 /* 510 * Called when a identifier has been declared, to give target last word. 511 */ 512 void 513 fixdef(struct symtab *sp) 514 { 515 } 516 517 void 518 pass1_lastchance(struct interpass *ip) 519 { 520 } 521