1 /* $Id: local.c,v 1.72 2011/01/21 21:47:58 ragge Exp $ */
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 /* this file contains code which is dependent on the target machine */
34 static int pointp(TWORD t
);
35 static struct symtab
*newfun(char *name
, TWORD type
);
40 static int xptype(TWORD t
);
45 /* this is called to do local transformations on
46 an expression tree preparitory to its being
47 written out in intermediate code.
50 /* the major essential job is rewriting the
51 automatic variables and arguments in terms of
53 /* conversion ops which are not necessary are also clobbered here */
54 /* in addition, any special features (such as rewriting
55 exclusive or) are easily handled here as well */
57 register struct symtab
*q
;
58 register NODE
*r
, *l
, *oop
;
65 printf("clocal: %p\n", p
);
70 switch( o
= p
->n_op
){
73 if ((q
= p
->n_sp
) == NULL
)
74 return p
; /* Nothing to care about */
79 /* First 7 parameters are in registers */
80 /* XXX last may be double */
81 if (q
->soffset
/SZINT
< 7) {
83 p
->n_rval
= q
->soffset
/SZINT
;
86 q
->soffset
-= 7*SZINT
;
89 /* fake up a structure reference */
90 if (q
->stype
== CHAR
|| q
->stype
== UCHAR
||
91 q
->stype
== SHORT
|| q
->stype
== USHORT
)
92 r
= block(REG
, NIL
, NIL
, PTR
+q
->stype
, 0, 0);
94 r
= block(REG
, NIL
, NIL
, PTR
+STRTY
, 0, 0);
97 p
= stref(block(STREF
, r
, p
, 0, 0, 0));
109 p
->n_rval
= q
->soffset
;
116 /* avoid recursive calls */
117 r
= tempnode(0, p
->n_type
, p
->n_df
, p
->n_sue
);
118 l
= tempnode(regno(r
), p
->n_type
, p
->n_df
, p
->n_sue
);
119 ecomp(buildtree(ASSIGN
, r
, p
));
126 * Handle frame pointer directly without conversion,
129 if (l
->n_op
== REG
&& l
->n_rval
== 0) {
130 rmpc
: l
->n_type
= p
->n_type
;
136 /* Convert ICON with name to new type */
137 if (l
->n_op
== ICON
&& l
->n_sp
!= NULL
&&
138 l
->n_type
== INCREF(STRTY
) &&
139 (p
->n_type
== INCREF(CHAR
) ||
140 p
->n_type
== INCREF(UCHAR
) ||
141 p
->n_type
== INCREF(SHORT
) ||
142 p
->n_type
== INCREF(USHORT
))) {
143 l
->n_lval
*= (BTYPE(p
->n_type
) == CHAR
||
144 BTYPE(p
->n_type
) == UCHAR
? 4 : 2);
147 /* Convert only address constants, never convert other */
148 if (l
->n_op
== ICON
) {
151 if (p
->n_type
== INCREF(CHAR
) ||
152 p
->n_type
== INCREF(UCHAR
) ||
153 p
->n_type
== INCREF(VOID
))
154 l
->n_lval
= (l
->n_lval
& 07777777777) |
156 else if (p
->n_type
== INCREF(SHORT
) ||
157 p
->n_type
== INCREF(USHORT
))
158 l
->n_lval
= (l
->n_lval
& 07777777777) |
161 l
->n_lval
= l
->n_lval
& 07777777777;
165 /* Remove more conversions of identical pointers */
166 /* Be careful! optim() may do bad things */
167 if (ISPTR(DECREF(p
->n_type
))) {
168 if (ISPTR(DECREF(l
->n_type
))) {
169 if ((coptype(l
->n_op
) == UTYPE
||
170 coptype(l
->n_op
) == BITYPE
) &&
171 (l
->n_left
->n_op
== REG
))
172 l
->n_left
->n_type
= p
->n_type
;
177 /* Change PCONV from int to double pointer to right shift */
178 if (ISPTR(p
->n_type
) && ISPTR(DECREF(p
->n_type
)) &&
179 (l
->n_type
== INT
|| l
->n_type
== UNSIGNED
)) {
181 p
->n_right
= bcon(2);
185 /* Check for cast integral -> pointer */
186 if (BTYPE(l
->n_type
) == l
->n_type
)
189 /* Remove conversions to identical pointers */
190 switch (xptype(p
->n_type
)) {
192 if (xptype(l
->n_type
) == PTRNORMAL
)
197 if (xptype(l
->n_type
) == PTRSHORT
)
202 if (xptype(l
->n_type
) == PTRCHAR
)
212 if ((p
->n_type
& TMASK
) == 0 && (l
->n_type
& TMASK
) == 0 &&
213 btdims
[p
->n_type
].suesize
== btdims
[l
->n_type
].suesize
) {
214 if (p
->n_type
!= FLOAT
&& p
->n_type
!= DOUBLE
&&
215 l
->n_type
!= FLOAT
&& l
->n_type
!= DOUBLE
) {
220 /* cast to (void) XXX should be removed in MI code */
221 if (p
->n_type
== VOID
) {
232 if (ml
== FLOAT
|| ml
== DOUBLE
) {
235 ml
= ISUNSIGNED(m
) ? UNSIGNED
: INT
; /* LONG? */
236 r
= xbcon(ml
== INT
? (int)p
->n_left
->n_dcon
:
237 (unsigned)p
->n_left
->n_dcon
,
249 CONSZ val
= l
->n_lval
;
253 l
->n_lval
= val
& 0777;
255 l
->n_lval
|= ~((CONSZ
)0777);
258 l
->n_lval
= val
& 0777;
261 l
->n_lval
= val
& 0777777;
264 l
->n_lval
= val
& 0777777;
266 l
->n_lval
|= ~((CONSZ
)0777777);
269 l
->n_lval
= val
& 0777777777777LL;
272 l
->n_lval
= val
& 0777777777777LL;
273 if (val
& 0400000000000LL)
274 l
->n_lval
|= ~(0777777777777LL);
276 case LONGLONG
: /* XXX */
288 cerror("unknown type %d", m
);
299 /* if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); */
301 return(buildtree(o
==PMCONV
?MUL
:DIV
, p
->n_left
, p
->n_right
));
305 /* convert >> to << with negative shift count */
306 /* Beware! constant shifts will be converted back in optim() */
308 if (p
->n_right
->n_op
!= UMINUS
) {
309 p
->n_right
= buildtree(UMINUS
, p
->n_right
, NIL
);
312 p
->n_right
= p
->n_right
->n_left
;
321 case UMUL
: /* Convert structure assignment to memcpy() */
322 if (p
->n_left
->n_op
== PLUS
&&
323 p
->n_left
->n_left
->n_op
== PCONV
&&
324 p
->n_left
->n_right
->n_op
== ICON
&&
325 (p
->n_type
== CHAR
|| p
->n_type
== UCHAR
||
326 p
->n_type
== SHORT
|| p
->n_type
== USHORT
)) {
327 /* Can remove the left SCONV */
328 l
= p
->n_left
->n_left
;
329 p
->n_left
->n_left
= l
->n_left
;
334 if (p
->n_left
->n_op
!= STASG
)
338 siz
= p
->n_sue
->suesize
/SZCHAR
;
341 if (l
->n_type
== STRTY
|| l
->n_type
== UNIONTY
) {
342 if (l
->n_op
== UMUL
) {
343 p
->n_left
= l
->n_left
;
347 l
= block(ADDROF
, l
, NIL
, INCREF(l
->n_type
),
351 if ((l
->n_type
!= (STRTY
+PTR
) && l
->n_type
!= (UNIONTY
+PTR
)) ||
352 (r
->n_type
!= (STRTY
+PTR
) && r
->n_type
!= (UNIONTY
+PTR
)))
353 cerror("bad stasg, l = %o, r = %o", l
->n_type
, r
->n_type
);
354 q
= newfun("__structcpy", p
->n_type
);
356 /* structure pointer block */
357 l
= block(CM
, l
, r
, INT
, 0, MKSUE(INT
));
359 r
= block(CM
, l
, bcon(siz
), INT
, 0, MKSUE(INT
));
361 l
= xbcon(0, q
, q
->stype
);
370 p
->n_right
= p
->n_left
;
371 p
->n_left
= block(REG
, NIL
, NIL
, p
->n_type
, 0, MKSUE(INT
));
372 p
->n_left
->n_rval
= RETREG(p
->n_type
);
386 case ULT
: /* exor sign bit to avoid unsigned comparitions */
390 if (ISLONGLONG(p
->n_left
->n_type
)) {
392 r
= xbcon(0x8000000000000000ULL
, NULL
, LONGLONG
);
394 r
= xbcon(0400000000000LL, NULL
, INT
);
395 p
->n_left
= buildtree(ER
, p
->n_left
, r
);
396 if (ISUNSIGNED(p
->n_left
->n_type
))
397 p
->n_left
->n_type
= DEUNSIGN(p
->n_left
->n_type
);
399 if (ISLONGLONG(p
->n_right
->n_type
)) {
401 r
= xbcon(0x8000000000000000ULL
, NULL
, LONGLONG
);
403 r
= xbcon(0400000000000LL, NULL
, INT
);
404 p
->n_right
= buildtree(ER
, p
->n_right
, r
);
405 if (ISUNSIGNED(p
->n_right
->n_type
))
406 p
->n_right
->n_type
= DEUNSIGN(p
->n_right
->n_type
);
411 cerror("fix float constants");
417 newfun(char *name
, TWORD type
)
421 sp
= lookup(name
, 0);
422 if (sp
->stype
== VOID
) {
423 sp
->stype
= INCREF(type
| FTN
);
428 else if (!ISFTN(DECREF(sp
->stype
)))
429 uerror("reserved name '%s' used illegally", name
);
438 return(1); /* all names can have & taken on them */
442 * at the end of the arguments of a ftn, set the automatic offset
451 * is an automatic variable of type t OK for a register variable
452 * Everything is trusted to be in register here.
467 cerror("not a pointer");
495 if (DECREF(t
) == tt
|| ISARY(rv
))
500 if (DECREF(t
) == tt
|| ISARY(rv
))
506 cerror("unknown type");
507 return PTRNORMAL
; /* XXX */
511 * Help routine to the one below; return true if it's not a word pointer.
518 if (ISPTR(t
) && ((t
& TMASK1
) == 0))
530 * return a node, for structure references, which is suitable for
531 * being added to a pointer of type t, in order to be off bits offset
533 * t, d, and s are the type, dimension offset, and sizeoffset
534 * For pdp10, return the type-specific index number which calculation
535 * is based on its size. For example, short a[3] would return 3.
536 * Be careful about only handling first-level pointers, the following
537 * indirections must be fullword.
540 offcon(OFFSZ off
, TWORD t
, union dimfun
*d
, struct suedef
*sue
)
545 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
546 off
, t
, d
, sue
->suesize
);
549 p
->n_lval
= off
/SZINT
; /* Default */
550 if (ISPTR(DECREF(t
)))
551 return p
; /* Pointer/pointer reference */
552 switch (BTMASK
& t
) {
568 p
->n_lval
= off
/SZSHORT
;
571 case VOID
: /* void pointers */
575 p
->n_lval
= off
/SZCHAR
;
579 cerror("offcon, off %llo size %d type %x", off
, sue
->suesize
, t
);
582 printf("offcon return 0%llo\n", p
->n_lval
);
587 * Allocate off bits on the stack. p is a tree that when evaluated
588 * is the multiply count for off, t is a NAME node where to write
589 * the allocated address.
590 * Be aware that a pointer conversion may be needed when saving
594 spalloc(NODE
*t
, NODE
*p
, OFFSZ off
)
598 if ((off
% SZINT
) == 0)
599 p
= buildtree(MUL
, p
, bcon(off
/SZINT
));
600 else if ((off
% SZSHORT
) == 0) {
601 p
= buildtree(MUL
, p
, bcon(off
/SZSHORT
));
602 p
= buildtree(PLUS
, p
, bcon(1));
603 p
= buildtree(RS
, p
, bcon(1));
604 } else if ((off
% SZCHAR
) == 0) {
605 p
= buildtree(MUL
, p
, bcon(off
/SZCHAR
));
606 p
= buildtree(PLUS
, p
, bcon(3));
607 p
= buildtree(RS
, p
, bcon(2));
611 /* save the address of sp */
612 sp
= block(REG
, NIL
, NIL
, PTR
+INT
, t
->n_df
, t
->n_sue
);
615 /* Cast sp to destination type (may be redundant) */
617 block(NAME
, NIL
, NIL
, t
->n_type
, t
->n_df
, t
->n_sue
), sp
);
621 ecomp(buildtree(ASSIGN
, t
, sp
)); /* Emit! */
623 /* add the size to sp */
624 sp
= block(REG
, NIL
, NIL
, p
->n_type
, 0, 0);
627 ecomp(buildtree(PLUSEQ
, sp
, p
));
631 static int inwd
; /* current bit offsed in word */
632 static CONSZ word
; /* word being built from fields */
635 * Generate initialization code for assigning a constant c
636 * to a field of width sz
637 * we assume that the proper alignment has been obtained
638 * inoff is updated to have the proper final value
639 * we also assume sz < SZINT
642 incode(NODE
*p
, int sz
)
647 if ((sz
+ inwd
) > SZINT
)
648 cerror("incode: field > int");
650 word
|= ((p
->n_lval
& ((1 << sz
) - 1)) << (36 - inwd
- sz
));
653 if (inoff
% SZINT
== 0) {
654 s
= isinlining
? permalloc(30) : tmpalloc(30);
655 sprintf(s
, " .long 0%llo", word
);
656 send_passt(IP_ASM
, s
);
662 /* output code to initialize space of size sz to the value d */
663 /* the proper alignment has been obtained */
664 /* inoff is updated to have the proper final value */
665 /* on the target machine, write it out in octal! */
667 fincode(NODE
*p
, int sz
)
669 double d
= p
->n_dcon
;
672 printf(" %s 0%c%.20e\n",
673 sz
== SZDOUBLE
? ".double" : ".float",
674 sz
== SZDOUBLE
? 'd' : 'f', d
);
679 cinit(NODE
*p
, int sz
)
684 * as a favor (?) to people who want to write
685 * int i = 9600/134.5;
686 * we will, under the proper circumstances, do
693 if (l
->n_op
!= SCONV
|| l
->n_left
->n_op
!= FCON
)
697 l
->n_lval
= (long)(l
->n_dcon
);
704 /* arrange for the initialization of p into a space of size sz */
705 /* the proper alignment has been opbtained */
706 /* inoff is updated to have the proper final value */
712 * define n bits of zeros in a vfd
721 if (inoff
%ALINT
==0) {
722 s
= isinlining
? permalloc(30) : tmpalloc(30);
723 sprintf(s
, " .long 0%llo", word
);
724 send_passt(IP_ASM
, s
);
730 /* make a name look like an external name in the local machine */
740 * map types which are not defined on the local machine
745 switch (BTYPE(type
)) {
750 MODTYPE(type
,UNSIGNED
);
753 MODTYPE(type
,DOUBLE
);
760 * Print out a string of characters.
761 * Assume that the assembler understands C-style escape
765 instring(struct symtab
*sp
)
772 /* be kind to assemblers and avoid long strings */
773 printf("\t.ascii \"");
774 for (s
= str
; *s
!= 0; ) {
779 fwrite(str
, 1, s
- str
, stdout
);
780 printf("\"\n\t.ascii \"");
784 fwrite(str
, 1, s
- str
, stdout
);
788 /* curid is a variable which is defined but
789 * is not initialized (and not a function );
790 * This routine returns the stroage class for an uninitialized declaration
799 calldec(NODE
*p
, NODE
*q
)
804 extdec(struct symtab
*q
)
808 /* make a common declaration for id, if reasonable */
810 defzero(struct symtab
*sp
)
814 off
= tsize(sp
->stype
, sp
->sdf
, sp
->ssue
);
815 off
= (off
+(SZINT
-1))/SZINT
;
816 printf(" .%scomm ", sp
->sclass
== STATIC
? "l" : "");
818 printf("%s,0%o\n", exname(sp
->soname
), off
);
820 printf(LABFMT
",0%o\n", sp
->soffset
, off
);
824 * set fsz bits in sequence to zero.
827 zbits(OFFSZ off
, int fsz
)
833 * Initialize a bitfield.
836 infld(CONSZ off
, int fsz
, CONSZ val
)
839 // printf("infld off %lld, fsz %d, val %lld inbits %d\n",
840 // off, fsz, val, inbits);
845 * print out a constant node, may be associated with a label.
846 * Do not free the node after use.
847 * off is bit offset from the beginning of the aggregate
848 * fsz is the number of bits this is referring to
851 ninval(CONSZ off
, int fsz
, NODE
*p
)
858 * Give target the opportunity of handling pragmas.
867 * Called when a identifier has been declared, to give target last word.
870 fixdef(struct symtab
*sp
)
875 pass1_lastchance(struct interpass
*ip
)