static char *sccsid
="@(#)local.c 1.17 (Berkeley) 5/11/88";
/* this file contains code which is dependent on the target machine */
clocal(p
) register NODE
*p
; {
/* this is called to do local transformations on
an expression tree preparitory to its being
written out in intermediate code.
/* the major essential job is rewriting the
automatic variables and arguments in terms of
/* conversion ops which are not necessary are also clobbered here */
/* in addition, any special features (such as rewriting
exclusive or) are easily handled here as well */
register struct symtab
*q
;
if( p
->tn
.rval
< 0 ) { /* already processed; ignore... */
/* fake up a structure reference */
r
= block( REG
, NIL
, NIL
, PTR
+STRTY
, 0, 0 );
r
->tn
.rval
= (q
->sclass
==AUTO
?STKREG
:ARGREG
);
p
= stref( block( STREF
, r
, p
, 0, 0, 0 ) );
if( q
->slevel
== 0 ) break;
if( ISPTR( p
->in
.left
->in
.type
) || ISPTR( p
->in
.right
->in
.type
) ){
/* do pointer conversions for char and longs */
ml
= p
->in
.left
->in
.type
;
if( ( ml
==CHAR
|| ml
==UCHAR
|| ml
==SHORT
|| ml
==USHORT
) && p
->in
.left
->in
.op
!= ICON
) break;
/* pointers all have the same representation; the type is inherited */
p
->in
.left
->in
.type
= p
->in
.type
;
p
->in
.left
->fn
.cdim
= p
->fn
.cdim
;
p
->in
.left
->fn
.csiz
= p
->fn
.csiz
;
ml
= p
->in
.left
->in
.type
;
if(m
== FLOAT
|| m
== DOUBLE
) {
p
->in
.left
->in
.left
->in
.type
==m
) {
p
->in
.op
= p
->in
.left
->in
.op
= FREE
;
return(p
->in
.left
->in
.left
);
/* see makety() for constant conversions */
if(ml
== FLOAT
|| ml
== DOUBLE
){
if(o
!= FCON
&& o
!= DCON
)
ml
= ISUNSIGNED(m
) ? UNSIGNED
: INT
; /* LONG? */
r
= block( ICON
, (NODE
*)NULL
, (NODE
*)NULL
, ml
, 0, 0 );
(int) p
->in
.left
->fpn
.fval
:
(unsigned) p
->in
.left
->fpn
.fval
;
(int) p
->in
.left
->dpn
.dval
:
(unsigned) p
->in
.left
->dpn
.dval
;
p
->in
.left
->in
.op
= FREE
;
/* now, look for conversions downwards */
if( o
== ICON
){ /* simulate the conversion here */
val
= p
->in
.left
->tn
.lval
;
p
->in
.left
->tn
.lval
= (char) val
;
p
->in
.left
->tn
.lval
= val
& 0XFF;
p
->in
.left
->tn
.lval
= val
& 0XFFFFL
;
p
->in
.left
->tn
.lval
= (short)val
;
p
->in
.left
->tn
.lval
= val
& 0xFFFFFFFFL
;
p
->in
.left
->tn
.lval
= (int)val
;
return( p
->in
.left
); /* conversion gets clobbered */
if( p
->in
.right
->in
.op
!= ICON
) cerror( "bad conversion", 0);
return( buildtree( o
==PMCONV
?MUL
:DIV
, p
->in
.left
, p
->in
.right
) );
/* convert >> to << with negative shift count */
/* only if type of left operand is not unsigned */
if( ISUNSIGNED(p
->in
.left
->in
.type
) ) break;
if( p
->in
.right
->in
.op
!= UNARY MINUS
)
p
->in
.right
= buildtree( UNARY MINUS
, p
->in
.right
, NIL
);
p
->in
.right
= p
->in
.right
->in
.left
;
if( p
->in
.op
== RS
) p
->in
.op
= LS
;
/* make sure that the second pass does not make the
descendant of a FLD operator into a doubly indexed OREG */
if( p
->in
.left
->in
.op
== UNARY MUL
&& (r
=p
->in
.left
->in
.left
)->in
.op
== PCONV
)
if( r
->in
.left
->in
.op
== PLUS
|| r
->in
.left
->in
.op
== MINUS
)
if( ISPTR(r
->in
.type
) ) {
if( ISUNSIGNED(p
->in
.left
->in
.type
) )
p
->in
.left
->in
.type
= UCHAR
;
p
->in
.left
->in
.type
= CHAR
;
return(1); /* all names can have & taken on them */
cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */
cisreg( t
) TWORD t
; { /* is an automatic variable of type t OK for a register variable */
#ifdef TRUST_REG_CHAR_AND_REG_SHORT
if( t
==INT
|| t
==UNSIGNED
|| t
==LONG
|| t
==ULONG
/* tbl */
|| t
==CHAR
|| t
==UCHAR
|| t
==SHORT
/* tbl */
|| t
==USHORT
|| ISPTR(t
)) return(1); /* tbl */
if( t
==INT
|| t
==UNSIGNED
|| t
==LONG
|| t
==ULONG
/* wnj */
|| ISPTR(t
)) return (1); /* wnj */
offcon( off
, t
, d
, s
) OFFSZ off
; TWORD t
; {
/* return a node, for structure references, which is suitable for
being added to a pointer of type t, in order to be off bits offset
/* t, d, and s are the type, dimension offset, and sizeoffset */
/* in general they are necessary for offcon, but not on VAX */
static inwd
/* current bit offsed in word */;
static CONSZ word
/* word being built from fields */;
incode( p
, sz
) register NODE
*p
; {
/* generate initialization code for assigning a constant c
to a field of width sz */
/* we assume that the proper alignment has been obtained */
/* inoff is updated to have the proper final value */
/* we also assume sz < SZINT */
if((sz
+inwd
) > SZINT
) cerror("incode: field > int");
word
|= ((unsigned)(p
->tn
.lval
<<(32-sz
))) >> (32-sz
-inwd
);
printf( " .long 0x%lx\n", word
);
fincode( d
, sz
) double d
; {
/* output code to initialize space of size sz to the value d */
/* the proper alignment has been obtained */
/* inoff is updated to have the proper final value */
/* on the target machine, write it out in octal! */
printf(" %s 0%c%.20e\n", sz
== SZDOUBLE
? ".double" : ".float",
sz
== SZDOUBLE
? 'd' : 'f', d
);
cinit( p
, sz
) NODE
*p
; {
* as a favor (?) to people who want to write
* we will, under the proper circumstances, do
(l
->in
.left
->tn
.op
!= DCON
&& l
->in
.left
->tn
.op
!= FCON
))
l
->tn
.lval
= l
->tn
.op
== DCON
? (long)(l
->dpn
.dval
) :
/* arrange for the initialization of p into a space of size sz */
/* the proper alignment has been opbtained */
/* inoff is updated to have the proper final value */
vfdzero( n
){ /* define n bits of zeros in a vfd */
printf( " .long 0x%lx\n", word
);
/* make a name look like an external name in the local machine */
static char text
[NCHNAM
+1];
static char text
[BUFSIZ
+1];
for( i
=1; *p
&&i
<NCHNAM
; ++i
)
text
[NCHNAM
] = '\0'; /* truncate */
ctype( type
) TWORD type
;
{ /* map types which are not defined on the local machine */
noinit() { /* curid is a variable which is defined but
is not initialized (and not a function );
This routine returns the stroage class for an uninitialized declaration */
commdec( id
){ /* make a common declaration for id, if reasonable */
register struct symtab
*q
;
printf( " .comm %s,", exname( q
->sname
) );
off
= tsize( q
->stype
, q
->dimoff
, q
->sizoff
);
printf( CONFMT
, off
/SZCHAR
);
register int o
= p
->in
.op
;
if (o
!= DCON
&& o
!= FCON
)
* Clobber constants of value zero so
* we can generate more efficient code.
if ((o
== DCON
&& p
->dpn
.dval
== 0) ||
(o
== FCON
&& p
->fpn
.fval
== 0)) {
defalign(o
== DCON
? ALDOUBLE
: ALFLOAT
);
fincode(p
->fpn
.fval
, SZFLOAT
);
fincode(p
->dpn
.dval
, SZDOUBLE
);
p
->in
.type
= (o
== DCON
? DOUBLE
: FLOAT
);
/* walk the tree and write out the nodes.. */