static char *sccsid
="@(#)local.c 1.2 (Berkeley) %G%";
/* this file contains code which is dependent on the target machine */
cast( p
, t
) register NODE
*p
; TWORD t
; {
/* cast node p to type t */
p
= buildtree( CAST
, block( NAME
, NIL
, NIL
, t
, 0, (int)t
), p
);
p
->in
.left
->in
.op
= FREE
;
/* 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;
/* 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
;
m
= (p
->in
.type
== FLOAT
|| p
->in
.type
== DOUBLE
);
ml
= (p
->in
.left
->in
.type
== FLOAT
|| p
->in
.left
->in
.type
== DOUBLE
);
/* now, look for conversions downwards */
ml
= p
->in
.left
->in
.type
;
if( p
->in
.left
->in
.op
== 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
;
/* meaningful ones are conversion of int to char, int to short,
and short to char, and unsigned version of them */
if( m
==CHAR
|| m
==UCHAR
){
if( ml
!=CHAR
&& ml
!= UCHAR
) break;
else if( m
==SHORT
|| m
==USHORT
){
if( ml
!=CHAR
&& ml
!=UCHAR
&& ml
!=SHORT
&& ml
!=USHORT
) break;
if( tlen(p
) == tlen(p
->in
.left
) ) goto inherit
;
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;
p
->in
.right
= buildtree( UNARY MINUS
, p
->in
.right
, NIL
);
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 H'well */
static inwd
/* current bit offsed in word */;
static 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%x\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
; {
/* arrange for the initialization of p into a space of
/* 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%x\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
){ /* map types which are not defined on the local machine */
noinit( t
) { /* 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
);
isitlong( cb
, ce
){ /* is lastcon to be long or short */
/* cb is the first character of the representation, ce the last */
if( ce
== 'l' || ce
== 'L' ||
lastcon
>= (1L << (SZINT
-1) ) ) return (1);
isitfloat( s
) char *s
; {
/* walk the tree and write out the nodes.. */