1 /* $Id: local.c,v 1.16 2014/06/03 20:19:50 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27
28 # include "pass1.h"
29
30 /* this file contains code which is dependent on the target machine */
31
32 NODE *
clocal(NODE * p)33 clocal(NODE *p)
34 {
35 struct symtab *q;
36 NODE *r, *l;
37 TWORD t;
38 int o;
39
40 #ifdef PCC_DEBUG
41 if (xdebug) {
42 printf("clocal\n");
43 fwalk(p, eprint, 0);
44 }
45 #endif
46
47 switch( o = p->n_op ){
48 case NAME:
49 /* handle variables */
50 if ((q = p->n_sp) == NULL)
51 return p; /* Nothing to care about */
52 switch (q->sclass) {
53 case PARAM:
54 case AUTO:
55 if (0 && q->soffset < MAXZP * SZINT &&
56 q->sclass != PARAM) {
57 p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2;
58 p->n_sp = NULL;
59 } else {
60 /* fake up a structure reference */
61 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
62 r->n_lval = 0;
63 r->n_rval = FPREG;
64 p = stref(block(STREF, r, p, 0, 0, 0));
65 }
66 break;
67 default:
68 break;
69 }
70 break;
71
72 case PMCONV:
73 case PVCONV:
74 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
75 nfree(p);
76 p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
77 break;
78
79 case PCONV:
80 t = p->n_type;
81 if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
82 t == INCREF(BOOL) || t == INCREF(VOID))
83 break;
84 l = p->n_left;
85 t = l->n_type;
86 if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
87 t == INCREF(BOOL) || t == INCREF(VOID))
88 break;
89 if (p->n_type <= UCHAR || l->n_type <= UCHAR)
90 break; /* must do runtime ptr conv */
91 /* if conversion to another pointer type, just remove */
92 if (p->n_type > BTMASK && l->n_type > BTMASK)
93 goto delp;
94 if (l->n_op == ICON && l->n_sp == NULL)
95 goto delp;
96 break;
97
98 delp: l->n_type = p->n_type;
99 l->n_qual = p->n_qual;
100 l->n_df = p->n_df;
101 l->n_ap = p->n_ap;
102 p = nfree(p);
103 break;
104 }
105
106 #ifdef PCC_DEBUG
107 if (xdebug) {
108 printf("clocal end\n");
109 fwalk(p, eprint, 0);
110 }
111 #endif
112
113 #if 0
114 register struct symtab *q;
115 register NODE *r, *l;
116 register int o;
117 register int m;
118 TWORD t;
119
120 //printf("in:\n");
121 //fwalk(p, eprint, 0);
122 switch( o = p->n_op ){
123
124 case NAME:
125 if ((q = p->n_sp) == NULL)
126 return p; /* Nothing to care about */
127
128 switch (q->sclass) {
129
130 case PARAM:
131 case AUTO:
132 /* fake up a structure reference */
133 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
134 r->n_lval = 0;
135 r->n_rval = FPREG;
136 p = stref(block(STREF, r, p, 0, 0, 0));
137 break;
138
139 case STATIC:
140 if (q->slevel == 0)
141 break;
142 p->n_lval = 0;
143 p->n_sp = q;
144 break;
145
146 case REGISTER:
147 p->n_op = REG;
148 p->n_lval = 0;
149 p->n_rval = q->soffset;
150 break;
151
152 }
153 break;
154
155 case STCALL:
156 case CALL:
157 /* Fix function call arguments. On x86, just add funarg */
158 for (r = p->n_right; r->n_op == CM; r = r->n_left) {
159 if (r->n_right->n_op != STARG &&
160 r->n_right->n_op != FUNARG)
161 r->n_right = block(FUNARG, r->n_right, NIL,
162 r->n_right->n_type, r->n_right->n_df,
163 r->n_right->n_sue);
164 }
165 if (r->n_op != STARG && r->n_op != FUNARG) {
166 l = talloc();
167 *l = *r;
168 r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
169 }
170 break;
171
172 case CBRANCH:
173 l = p->n_left;
174
175 /*
176 * Remove unnecessary conversion ops.
177 */
178 if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
179 if (coptype(l->n_op) != BITYPE)
180 break;
181 if (l->n_right->n_op == ICON) {
182 r = l->n_left->n_left;
183 if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
184 break;
185 /* Type must be correct */
186 t = r->n_type;
187 nfree(l->n_left);
188 l->n_left = r;
189 l->n_type = t;
190 l->n_right->n_type = t;
191 }
192 }
193 break;
194
195 case PCONV:
196 /* Remove redundant PCONV's. Be careful */
197 l = p->n_left;
198 if (l->n_op == ICON) {
199 l->n_lval = (unsigned)l->n_lval;
200 goto delp;
201 }
202 if (l->n_type < INT || l->n_type == LONGLONG ||
203 l->n_type == ULONGLONG) {
204 /* float etc? */
205 p->n_left = block(SCONV, l, NIL,
206 UNSIGNED, 0, 0);
207 break;
208 }
209 /* if left is SCONV, cannot remove */
210 if (l->n_op == SCONV)
211 break;
212 /* if conversion to another pointer type, just remove */
213 if (p->n_type > BTMASK && l->n_type > BTMASK)
214 goto delp;
215 break;
216
217 delp: l->n_type = p->n_type;
218 l->n_qual = p->n_qual;
219 l->n_df = p->n_df;
220 l->n_sue = p->n_sue;
221 nfree(p);
222 p = l;
223 break;
224
225 case SCONV:
226 l = p->n_left;
227
228 if (p->n_type == l->n_type) {
229 nfree(p);
230 return l;
231 }
232
233 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
234 btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
235 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
236 l->n_type != FLOAT && l->n_type != DOUBLE &&
237 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
238 if (l->n_op == NAME || l->n_op == UMUL ||
239 l->n_op == TEMP) {
240 l->n_type = p->n_type;
241 nfree(p);
242 return l;
243 }
244 }
245 }
246
247 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
248 coptype(l->n_op) == BITYPE) {
249 l->n_type = p->n_type;
250 nfree(p);
251 return l;
252 }
253
254 o = l->n_op;
255 m = p->n_type;
256
257 if (o == ICON) {
258 CONSZ val = l->n_lval;
259
260 if (!ISPTR(m)) /* Pointers don't need to be conv'd */
261 switch (m) {
262 case CHAR:
263 l->n_lval = (char)val;
264 break;
265 case UCHAR:
266 l->n_lval = val & 0377;
267 break;
268 case SHORT:
269 l->n_lval = (short)val;
270 break;
271 case USHORT:
272 l->n_lval = val & 0177777;
273 break;
274 case ULONG:
275 case UNSIGNED:
276 l->n_lval = val & 0xffffffff;
277 break;
278 case LONG:
279 case INT:
280 l->n_lval = (int)val;
281 break;
282 case LONGLONG:
283 l->n_lval = (long long)val;
284 break;
285 case ULONGLONG:
286 l->n_lval = val;
287 break;
288 case VOID:
289 break;
290 case LDOUBLE:
291 case DOUBLE:
292 case FLOAT:
293 l->n_op = FCON;
294 l->n_dcon = val;
295 break;
296 default:
297 cerror("unknown type %d", m);
298 }
299 l->n_type = m;
300 l->n_sue = 0;
301 nfree(p);
302 return l;
303 }
304 if (DEUNSIGN(p->n_type) == SHORT &&
305 DEUNSIGN(l->n_type) == SHORT) {
306 nfree(p);
307 p = l;
308 }
309 if ((p->n_type == CHAR || p->n_type == UCHAR ||
310 p->n_type == SHORT || p->n_type == USHORT) &&
311 (l->n_type == FLOAT || l->n_type == DOUBLE ||
312 l->n_type == LDOUBLE)) {
313 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
314 p->n_left->n_type = INT;
315 return p;
316 }
317 break;
318
319 case MOD:
320 case DIV:
321 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
322 break;
323 if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
324 break;
325 /* make it an int division by inserting conversions */
326 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
327 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
328 p = block(SCONV, p, NIL, p->n_type, 0, 0);
329 p->n_left->n_type = INT;
330 break;
331
332 case PMCONV:
333 case PVCONV:
334 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
335 nfree(p);
336 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
337
338 case FORCE:
339 /* put return value in return reg */
340 p->n_op = ASSIGN;
341 p->n_right = p->n_left;
342 p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
343 p->n_left->n_rval = RETREG(p->n_type);
344 break;
345
346 case LS:
347 case RS:
348 /* shift count must be in a char
349 * unless longlong, where it must be int */
350 if (p->n_right->n_op == ICON)
351 break; /* do not do anything */
352 if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
353 if (p->n_right->n_type != INT)
354 p->n_right = block(SCONV, p->n_right, NIL,
355 INT, 0, 0);
356 break;
357 }
358 if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
359 break;
360 p->n_right = block(SCONV, p->n_right, NIL,
361 CHAR, 0, 0);
362 break;
363 }
364 //printf("ut:\n");
365 //fwalk(p, eprint, 0);
366
367 #endif
368
369 return(p);
370 }
371
372 void
myp2tree(NODE * p)373 myp2tree(NODE *p)
374 {
375 struct symtab *sp;
376 NODE *l, *r;
377 int o = p->n_op;
378
379 switch (o) {
380 case NAME: /* reading from a name must be done with a subroutine */
381 if (p->n_type != CHAR && p->n_type != UCHAR)
382 break;
383 l = buildtree(ADDROF, ccopy(p), NIL);
384 r = block(NAME, NIL, NIL, INT, 0, 0);
385
386 r->n_sp = lookup(addname("__nova_rbyte"), SNORMAL);
387 if (r->n_sp->sclass == SNULL) {
388 r->n_sp->sclass = EXTERN;
389 r->n_sp->stype = INCREF(p->n_type)+(FTN-PTR);
390 }
391 r->n_type = r->n_sp->stype;
392 r = clocal(r);
393 r = optim(buildtree(CALL, r, l));
394 *p = *r;
395 nfree(r);
396 break;
397
398 case FCON:
399 sp = inlalloc(sizeof(struct symtab));
400 sp->sclass = STATIC;
401 sp->sap = 0;
402 sp->slevel = 1; /* fake numeric label */
403 sp->soffset = getlab();
404 sp->sflags = 0;
405 sp->stype = p->n_type;
406 sp->squal = (CON >> TSHIFT);
407
408 defloc(sp);
409 ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
410
411 p->n_op = NAME;
412 p->n_lval = 0;
413 p->n_sp = sp;
414 }
415 }
416
417 /*ARGSUSED*/
418 int
andable(NODE * p)419 andable(NODE *p)
420 {
421 return(1); /* all names can have & taken on them */
422 }
423
424 /*
425 * Return 1 if a variable of type type is OK to put in register.
426 */
427 int
cisreg(TWORD t)428 cisreg(TWORD t)
429 {
430 return 1; /* try to put anything in a register */
431 }
432
433 /*
434 * return a node, for structure references, which is suitable for
435 * being added to a pointer of type t, in order to be off bits offset
436 * into a structure
437 * t, d, and s are the type, dimension offset, and sizeoffset
438 * For nova, return the type-specific index number which calculation
439 * is based on its size. For example, char a[3] would return 3.
440 * Be careful about only handling first-level pointers, the following
441 * indirections must be fullword.
442 */
443 NODE *
offcon(OFFSZ off,TWORD t,union dimfun * d,struct attr * ap)444 offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
445 {
446 register NODE *p;
447
448 if (xdebug)
449 printf("offcon: OFFSZ %ld type %x dim %p siz %ld\n",
450 off, t, d, tsize(t, d, ap));
451
452 p = bcon(off/SZINT);
453 if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(VOID))
454 p->n_lval = off/SZCHAR; /* pointer to char */
455 return(p);
456 }
457
458 /*
459 * Allocate off bits on the stack. p is a tree that when evaluated
460 * is the multiply count for off, t is a NAME node where to write
461 * the allocated address.
462 */
463 void
spalloc(NODE * t,NODE * p,OFFSZ off)464 spalloc(NODE *t, NODE *p, OFFSZ off)
465 {
466 NODE *sp;
467
468 cerror("spalloc");
469 if ((off % SZINT) == 0)
470 p = buildtree(MUL, p, bcon(off/SZINT));
471 else if ((off % SZSHORT) == 0) {
472 p = buildtree(MUL, p, bcon(off/SZSHORT));
473 p = buildtree(PLUS, p, bcon(1));
474 p = buildtree(RS, p, bcon(1));
475 } else if ((off % SZCHAR) == 0) {
476 p = buildtree(MUL, p, bcon(off/SZCHAR));
477 p = buildtree(PLUS, p, bcon(3));
478 p = buildtree(RS, p, bcon(2));
479 } else
480 cerror("roundsp");
481
482 /* save the address of sp */
483 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
484 sp->n_lval = 0;
485 sp->n_rval = STKREG;
486 t->n_type = sp->n_type;
487 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
488
489 /* add the size to sp */
490 sp = block(REG, NIL, NIL, p->n_type, 0, 0);
491 sp->n_lval = 0;
492 sp->n_rval = STKREG;
493 ecomp(buildtree(PLUSEQ, sp, p));
494 }
495
496 /*
497 * print out a constant node
498 * mat be associated with a label
499 */
500 int
ninval(CONSZ off,int fsz,NODE * p)501 ninval(CONSZ off, int fsz, NODE *p)
502 {
503 switch (p->n_type) {
504 case FLOAT:
505 case DOUBLE:
506 case LDOUBLE:
507 cerror("ninval");
508 }
509 return 1;
510 }
511
512 /* make a name look like an external name in the local machine */
513 char *
exname(char * p)514 exname(char *p)
515 {
516 if (p == NULL)
517 return "";
518 return p;
519 }
520
521 /*
522 * map types which are not defined on the local machine
523 */
524 TWORD
ctype(TWORD type)525 ctype(TWORD type)
526 {
527 switch (BTYPE(type)) {
528 case LONGLONG:
529 MODTYPE(type,LONG);
530 break;
531
532 case ULONGLONG:
533 MODTYPE(type,ULONG);
534 break;
535 case SHORT:
536 MODTYPE(type,INT);
537 break;
538 case USHORT:
539 MODTYPE(type,UNSIGNED);
540 break;
541 }
542 return (type);
543 }
544
545 #if 0
546 /* curid is a variable which is defined but
547 * is not initialized (and not a function );
548 * This routine returns the storage class for an uninitialized declaration
549 */
550 int
551 noinit()
552 {
553 return(EXTERN);
554 }
555 #endif
556
557 void
calldec(NODE * p,NODE * q)558 calldec(NODE *p, NODE *q)
559 {
560 }
561
562 void
extdec(struct symtab * q)563 extdec(struct symtab *q)
564 {
565 }
566
567 #if 0
568 /* make a common declaration for id, if reasonable */
569 void
570 commdec(struct symtab *q)
571 {
572 int off;
573
574 off = tsize(q->stype, q->sdf, q->ssue);
575 off = (off+(SZCHAR-1))/SZCHAR;
576 printf(" .comm %s,0%o\n", exname(q->soname), off);
577 }
578
579 /* make a local common declaration for id, if reasonable */
580 void
581 lcommdec(struct symtab *q)
582 {
583 int off;
584
585 off = tsize(q->stype, q->sdf, q->ssue);
586 off = (off+(SZCHAR-1))/SZCHAR;
587 if (q->slevel == 0)
588 printf(" .lcomm %s,0%o\n", exname(q->soname), off);
589 else
590 printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off);
591 }
592
593 /*
594 * print a (non-prog) label.
595 */
596 void
597 deflab1(int label)
598 {
599 printf(LABFMT ":\n", label);
600 }
601
602 static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
603
604 void
605 setloc1(int locc)
606 {
607 if (locc == lastloc)
608 return;
609 lastloc = locc;
610 printf(" .%s\n", loctbl[locc]);
611 }
612 #endif
613
614 /*
615 * Give target the opportunity of handling pragmas.
616 */
617 int
mypragma(char * str)618 mypragma(char *str)
619 {
620 return 0;
621 }
622
623 /*
624 * Called when a identifier has been declared, to give target last word.
625 * On Nova we put symbols over the size of an int above 24 bytes in
626 * offset and leave zeropage for small vars.
627 */
628 void
fixdef(struct symtab * sp)629 fixdef(struct symtab *sp)
630 {
631 #if 0
632 if (sp->sclass != AUTO)
633 return; /* not our business */
634 if (ISPTR(sp->stype) || sp->stype < LONG)
635 return;
636 if (sp->soffset >= (MAXZP * SZINT))
637 return; /* already above */
638 /* have to move */
639 /* XXX remember old autooff for reorg of smaller vars */
640 if (autooff < MAXZP * SZINT)
641 autooff = MAXZP * SZINT;
642 oalloc(sp, &autooff);
643 #endif
644 }
645
646 void
pass1_lastchance(struct interpass * ip)647 pass1_lastchance(struct interpass *ip)
648 {
649 }
650