Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

846 lines
19 KiB
Groff

/*
Copyright 1982
Alcyon Corporation
8716 Production Ave.
San Diego, Ca. 92121
@(#)codegen.c 1.13 12/30/83
*/
#include "cgen.h"
#include "cskel.h"
char null[];
char *opname[];
/* scodegen - over-all code generation for expression*/
/* Picks off post-fix ++, --.*/
scodegen(tp,cookie,reg) /* returns register result is in*/
struct tnode *tp;
int cookie;
int reg;
{
struct tnode *clist[20];
struct tnode **clp;
register struct tnode **cp;
register short r, ccflag;
short lconst;
register struct tnode *rtp;
if( tp->t_op == COMMA ) {
scodegen(tp->t_left,FOREFF,reg);
return(scodegen(tp->t_right,cookie,reg));
}
ccflag = 0;
clp = clist;
tp = addptree(tp,&clp);
if( clp > clist ) {
/*
* post ++, -- in tree. We need to compile the tree post operators
* then generate code to do the post operators, then do any fix up of
* condition codes since the Stupid 68000 architect was a nimnul.
*/
if( cookie == FORCC ) {
/*
* here we make the observation that if we are comparing something with
* zero OR the top operator of the tree is not a comparison operator,
* we can compile the tree to a register, and then set the condition
* codes OK with a tst instruction at the end.
*/
if( RELOP(tp->t_op) ) {
if( (rtp=constant(tp->t_right,&lconst)) &&
CONSTZERO(lconst,rtp)) { /* [vlh] */
ccflag = 1;
tp = tp->t_left;
cookie = FORREG;
}
else
ccflag = 2;
}
else {
ccflag = 1;
cookie = FORREG;
}
}
}
r = codegen(tp,cookie,reg);
if( clp > clist ) {
if( ccflag == 2 ) {
if (!m68010) /* [vlh] 4.2, added differentiation */
OUTSRSAVE(r);
else
OUTCCSAVE(r);
}
for( cp = clist; cp < clp; cp++ )
codegen(*cp,FOREFF,r+1);
if( ccflag == 1 )
outcmp0(r,tp);
else if( ccflag == 2 )
OUTCCRESTORE(r);
}
return(r);
}
/* addptree - prune off postfix ++, -- from expression tree*/
/* This prunes off ++, -- and collects those expressions for*/
/* scodegen.*/
char *
addptree(tp,clp) /* returns pointer to pruned tree*/
struct tnode *tp;
struct tnode ***clp;
{
register short op;
register struct tnode *stp;
op = tp->t_op;
if( LEAFOP(op) || op == QMARK || op == LAND || op == LOR ) /* [mac] 4.2 */
return(tp);
if( op == POSTINC || op == POSTDEC ) {
stp = tcopy(tp->t_left,A_DOPRE);/* [mac] 4.2 c[i=+1]++ & c[*p++]++ */
*(*clp)++ = tcopy(tp,A_DOPOST);
return( stp );
}
if( BINOP(op) )
tp->t_right = addptree(tp->t_right,clp);
tp->t_left = addptree(tp->t_left,clp);
return(tp);
}
/**
* codegen - generate code for expression
* This calls up rcodegen, which prunes off any special register
* optimization code, then calls ucodegen (unrecursive) code
* generation.
**/
codegen(tp,cookie,reg) /* returns reg result is in*/
struct tnode *tp; /* tree pointer*/
int cookie; /* code generation goals*/
int reg; /* first available register*/
{
register short savestk, ssize, r, i;
register struct tnode *rtp;
#ifdef DEBUG
if( cflag )
printf("codegen op=%d cookie=%d reg=%d\n",tp->t_op,cookie,reg);
#endif
switch( tp->t_op ) {
case CALL:
case NACALL:
ssize = 0;
savestk = stacksize;
if( tp->t_left->t_op != SYMBOL )
stacksize++;
if( tp->t_op == CALL ) {
rtp = tp->t_right;
while( rtp->t_op == COMMA ) {
ssize += dofarg(rtp->t_right);
rtp = rtp->t_left;
}
ssize += dofarg(rtp);
}
tp->t_op = FJSR; /*generate JSR (unary op)*/
codegen(tp,FORREG,reg);
popstack(ssize);
stacksize = savestk;
fixresult(tp,cookie,0);
return(0); /*result in R0*/
case COMMA:
codegen(tp->t_left,FOREFF,reg);
return(codegen(tp->t_right,cookie,reg));
case AND:
if( cookie == FORCC && (i=isonebit(tp->t_right)) >= 0 &&
(i=dobitadd(tp->t_left,i)) >= 0 ) {
if( CONVOP(tp->t_right->t_op) )
tp->t_right = tp->t_right->t_left;
tp->t_right->t_value = i;
tp->t_right->t_op = CINT; /* [vlh] 4.1 */
tp->t_right->t_type = INT; /* [vlh] 4.1 */
tp->t_op = BTST;
tp = canon(tp);
sucomp(tp,reg,1);
}
break;
}
if( rcodegen(&tp,cookie,reg) ) {
if( cookie == FORCC && tp->t_op == SYMBOL && tp->t_sc == REGISTER
&& ISDREG(tp->t_reg))
return(reg);
}
r = ucodegen(tp,cookie,reg);
return(r);
}
/* fixresult - fix result of code generation*/
fixresult(tp,cookie,reg) /* returns - none*/
struct tnode *tp;
int cookie; /* wanted this cookie*/
int reg;
{
#ifdef DEBUG
if (cflag)
printf("fixresult cookie=%d reg=%d op=%d\n",cookie,reg,tp->t_op);
#endif
switch( cookie ) {
case FORCC:
outcmp0(reg,tp);
break;
case FORSP:
case FORSTACK:
stacksize++;
outrpush(reg,tp,cookie==FORSTACK);
break;
}
return(reg);
}
/**
* ucodegen - generate code for tree given cookie and starting register
* Handles the matching of the expression tree node with the
* corresponding code generation table. When a match is found,
* expand is called to expand the code skeleton macro.
**/
ucodegen(tp,cookie,reg) /* returns reg result is in*/
struct tnode *tp; /* pointer to expression tree*/
int cookie; /* (FORCC,FOREFF,FORREG,FORSTACK)*/
int reg; /* first available register*/
{
register short r;
register char *p;
register struct tnode *ltp;
short lconst;
PUTEXPR(cflag,"ucodegen",tp);
switch( tp->t_op ) {
case ADDR: /* 4.2 */
ltp = tp->t_left;
if(cookie==FORCC && ltp->t_op==SYMBOL &&
(ltp->t_sc==EXTERNAL || ltp->t_sc==STATIC)) {
warning("function existence test");
printf("move.l #");
outaexpr(ltp,A_NOIMMED);
printf(",-(sp)\ntst.l (sp)+\n");
return(reg);
}
break;
case ASSIGN: /* 4.3 [mac] */
if ((BASETYPE(tp->t_left->t_type) == CHAR) && cookie == FORREG &&
ISAREG(reg))
reg = DREG(reg);
break;
case STASSIGN: /*[vlh]*/
outstrcpy(codegen(tp->t_left,FORREG,AREG(reg)),
codegen(tp->t_right,FORREG,AREG(reg+1)),tp->t_type);
return(reg);
break;
case SYMBOL:
if( cookie == FOREFF )
return(reg);
break;
case LSH:
if( (ISAREG(reg)) && (p=constant(tp->t_right,&lconst)) &&
!(UNSIGN(tp->t_left->t_type)) &&
((!lconst && (p->t_value == 1 || p->t_value == 2) ) ||
(lconst && (p->t_lvalue == 1 || p->t_lvalue == 2) ))) {
r = codegen(tp->t_left,FORREG,reg);
outmovr(r,reg,tp->t_left);
if( p->t_value == 2 )
OUTADDR(reg,reg,tp);
OUTADDR(reg,reg,tp);
fixresult(tp,cookie,reg);
return(reg);
}
break;
case EQMULT:
case EQDIV:
case LEQMULT:
case LEQDIV:
case EQMOD:
case LEQMOD:
case EQRSH:
case EQLSH:
case EQAND:
case EQOR:
case EQXOR:
if( indexreg(tp->t_left) ) {
reg = DREG(reg);
outmovr(r=tp->t_left->t_reg,reg,tp);
tp->t_left->t_reg = reg;
codegen(tp,cookie,reg+1);
outmovr(reg,r,tp);
return(reg);
}
if (cookie == FORREG && ISAREG(reg)) { /* 4.3 [mac] */
reg = DREG(reg);
codegen(tp,cookie,reg);
return(reg);
}
break;
case ADD:
case EQADD:
if( (p=constant(tp->t_right,&lconst)))
if (!lconst && (p->t_value < 0 && p->t_value >= -QUICKVAL)) {
p->t_value = - p->t_value;
tp->t_op += (SUB-ADD);
}
else if (lconst && p->t_lvalue<0 && p->t_lvalue >= -QUICKVAL) {
p->t_lvalue = -p->t_lvalue;
tp->t_op += (SUB-ADD);
}
break;
} /* end of case statement..... */
sucomp(tp,reg,1);
if( (r=loadexpr(tp,cookie,reg)) >= 0 )
return(r);
if( (r=cqmark(tp,cookie,reg)) >= 0 )
return(r);
if( (r=hardrel(tp,cookie,reg)) >= 0 )
return(r);
if( cookie == FORCC && (p=match(tp,FOREFF,reg)) != 0 ) {
r = expand(tp,FOREFF,reg,p);
if( ISASGOP(tp->t_op) && indexreg(tp->t_left) )
outcmp0(tp->t_left->t_reg,tp->t_left);
}
else if( p = match(tp,cookie,reg) )
r = expand(tp,cookie,reg,p);
else if( cookie != FORREG )
r = fixresult(tp,cookie,ucodegen(tp,FORREG,reg));
else {
if(tp->t_type != STRUCT) /* [vlh] 4.3 */
error("no code table for %s",opname[tp->t_op]);
else
error("illegal structure operation");
}
return(r);
}
/* outstrcpy - output structure copy */
outstrcpy(lr,rr,size) /*[vlh]*/
int lr, rr; /* left register, right register */
int size; /* structure size to copy */
{
register short lab;
#ifdef DEBUG
if (cflag) printf("size is %d\n",size);
#endif
if (ISDREG(lr)) {
printf("move.l r%d,r%d\n",lr,AREG(lr));
lr = AREG(lr);
}
if (ISDREG(rr)) {
printf("move.l r%d,r%d\n",rr,AREG(rr));
rr = AREG(rr);
}
lab = nextlabel++;
printf("move #%d,r%d\n",(size/INTSIZE)-1,DREG(lr));
OUTLAB(lab);
printf("move (r%d)+,(r%d)+\ndbra r%d,L%d\n",rr,lr,DREG(lr),lab);
}
/**
* loadexpr - load an addressable expression into a register
* This checks for any possible usage of the register indexed
* addressing mode. Note that this relies on the good graces of the
* load code skeletons not to muck up the compiler registers before
* loading an addressable expression...
**/
loadexpr(tp,cookie,reg) /* returns register loaded or -1*/
struct tnode *tp; /* pointer to expression tree*/
int reg; /* register to load*/
{
register struct tnode *rtp, *ltp, *xtp, *atp;
register short off, r, type, nr, ar, xr, xt;
if( tp->t_op == INDR || LOADABLE(tp) ) {
PUTEXPR((cflag>1),"loadexpr",tp);
type = tp->t_type;
if( tp->t_op == INDR && (ltp=tp->t_left)->t_op == ADD ) {
rtp = ltp->t_right;
ltp = ltp->t_left;
off = 0;
if( rtp->t_op == CINT && ((off=rtp->t_value) < -128 ||
off > 127 || ltp->t_op != ADD ) ) {
tp = snalloc(type,AUTO,(long)off,0,0);
if( indexreg(ltp) )
tp->t_reg = ltp->t_reg;
else {
r = codegen(ltp,FORREG,AREG(reg));
if( ISDREG(r) )
outmovr(r,AREG(r),ltp);
tp->t_reg = AREG(r);
}
}
else {
if( rtp->t_op == CINT ) {
rtp = ltp->t_right;
ltp = ltp->t_left;
}
if(indexreg(rtp) || (!(indexreg(ltp)) && (ISREG(rtp)))) {
xtp = ltp;
ltp = rtp;
rtp = xtp;
}
xtp = atp = 0;
if( indexreg(ltp) ) {
ar = ltp->t_reg;
if( (ISREG(rtp)) && rtp->t_type != CHAR ) {
xr = rtp->t_reg;
xt = rtp->t_type;
}
else
xtp = rtp;
}
else if( (ISREG(ltp)) && ltp->t_type != CHAR &&
(lflag || rtp->t_op != ADDR) ) {
xr = ltp->t_reg;
xt = ltp->t_type;
atp = rtp;
}
else if( rtp->t_op == ADDR ) {
atp = ltp;
xtp = rtp;
}
else {
atp = rtp;
xtp = ltp;
}
nr = 0;
if( atp )
nr++;
if( xtp && (xtp->t_op != ADDR || lflag ) )
nr++;
if( DREG(nr+reg) <= HICREG ) {
r = reg;
if( atp ) {
ar = codegen(atp,FORREG,AREG(r));
if( ISDREG(ar) ) {
outmovr(ar,AREG(ar),atp);
ar = AREG(ar);
}
r++;
}
if( xtp && xtp->t_op == ADDR && !lflag ) {
tp = xtp->t_left;
tp->t_sc += (EXTOFF-EXTERNAL);
tp->t_offset += off;
tp->t_reg = ar;
}
else {
if( xtp ) {
xr = codegen(xtp,FORREG,AREG(r));
xt = xtp->t_type;
}
tp = xnalloc(type,ar,(long)off,xr,xt);
}
}
}
}
if( (ISAREG(reg)) && tp->t_type == CHAR )
reg = DREG(reg);
tp = tnalloc(LOAD,tp->t_type,SU_EASY,0,tp,null);
PUTEXPR((cflag>1),"loadexpr final",tp);
return( codegen(tp,cookie,reg) );
}
return(-1);
}
/* coffset - check offset for addressable node*/
char *coffset(tp) /* returns ptr to const off node*/
struct tnode *tp; /* pointer to node*/
{
register struct tnode *rtp;
if( tp->t_op == ADD ) {
rtp = tp->t_right;
if( rtp->t_op == CINT )
return(rtp);
if(!lflag) {
if( rtp->t_op == ADDR )
return(rtp->t_left);
rtp = tp->t_left;
if( rtp->t_op == ADDR ) {
tp->t_left = tp->t_right;
tp->t_right = rtp;
return(rtp->t_left);
}
}
}
return(0);
}
/* hardrel - do relationals returning a value*/
hardrel(tp,cookie,reg) /* returns reg or -1*/
struct tnode *tp; /* pointer to tree*/
int cookie; /* cookie for code generation*/
int reg; /* low register*/
{
register char *p;
register short op, lab1, lab2;
short islong;
#ifdef DEBUG
if (cflag)
printf("hardrel: cookie=%d op=%d reg=%d\n",cookie,tp->t_op,reg);
#endif
op = tp->t_op;
if (RELOP(op) && tp->t_left->t_type == CHAR &&
(p=constant(tp->t_right,&islong))) {
if (islong)
tp->t_left = tnalloc(LOAD,LONG,SU_EASY,0,tp->t_left,null);
else if (p->t_value > 255 || p->t_value < -128)
tp->t_left = tnalloc(LOAD,INT,SU_EASY,0,tp->t_left,null);
} /* [vlh] 4.3, if char compared to large constant.... */
if (cookie != FORCC && (RELOP(op) || op==LOR || op==LAND || op==NOT)) {
lab1 = nextlabel++;
condbr(tp,TRUE,lab1,reg);
p = canon(cnalloc(INT,0));
codegen(p,cookie,reg);
lab2 = nextlabel++;
OUTGOTO(lab2);
OUTLAB(lab1);
p = canon(cnalloc(INT,1));
codegen(p,cookie,reg);
OUTLAB(lab2);
return(reg);
}
return(-1);
}
/* cqmark - compile question mark operator*/
/* This does the compilation of the question mark operator.*/
cqmark(tp,cookie,reg) /* returns reg or -1*/
struct tnode *tp;
int cookie;
int reg;
{
register short lab1, lab2, savestk, r;
if( tp->t_op == QMARK && cookie != FORCC ) {
lab1 = nextlabel++;
condbr(tp->t_left,FALSE,lab1,reg);
savestk = stacksize;
r = scodegen(tp->t_right->t_left,cookie,reg); /* [mc] 4.0 */
outmovr(r,reg,tp);
stacksize = savestk;
OUTGOTO(lab2=nextlabel++);
OUTLAB(lab1);
r = scodegen(tp->t_right->t_right,cookie,reg); /* [mc] 4.0 */
outmovr(r,reg,tp);
OUTLAB(lab2);
return(reg);
}
return(-1);
}
/**
* condbr - handle conditional branch code generation
* This handles the conditional branch code generation, handling
* the special cases for constants, ||, &&, ! and generating the
* correct conditional branch instruction.
**/
condbr(tp,dir,lab,reg)
struct tnode *tp;
int dir;
int lab;
int reg;
{
register struct tnode *ltp, *rtp;
register short lab1, optype, op, subdir;
ltp = tp->t_left;
if( BINOP(op=tp->t_op) )
rtp = tp->t_right;
subdir = dir; /*set up for LOR*/
#ifdef DEBUG
if (cflag)
printf("condbr: dir = %d, lab = %d, reg = %d\n",dir,lab,reg);
#endif
switch( op ) {
case CINT:
if( !tp->t_value ) {
if( dir == FALSE )
OUTGOTO(lab);
}
else if( dir != FALSE )
OUTGOTO(lab);
break;
case NOT:
condbr(ltp,!dir,lab,reg);
break;
case LAND:
dir = !dir;
case LOR:
if( dir == FALSE ) {
lab1 = nextlabel++;
condbr(ltp,!subdir,lab1,reg);
condbr(rtp,subdir,lab,reg);
OUTLAB(lab1);
}
else {
condbr(ltp,subdir,lab,reg);
condbr(rtp,subdir,lab,reg);
}
break;
case COMMA:
scodegen(tp->t_left,FOREFF,reg);
condbr(tp->t_right,dir,lab,reg);
break;
default: /* [mc] 4.2.b */
if(outdbra(dir,op,ltp,rtp,lab))
break;
if( RELOP(op) && ltp->t_op == AUTOINC && rtp->t_op == AUTOINC &&
ltp->t_type == rtp->t_type )
outcmpm(tp);
else
scodegen(tp,FORCC,reg);
optype = 0;
if( RELOP(op) ) {
if( UNORPTR(ltp->t_type) || UNORPTR(rtp->t_type) )
optype++;
}
else
op = NEQUALS;
if(!dir)
op = invrel[op-EQUALS];
optype = brtab[op-EQUALS][optype];
printf("%s L%d\n",mnemonics[optype],lab);
break;
}
}
rcodegen(tpp,cookie,reg) /* returns changed flag*/
struct tnode **tpp; /* pointer to tree*/
int cookie; /* code generation cookie*/
int reg; /* register to use for code*/
{
register short change, op;
register struct tnode *tp;
tp = *tpp;
op = tp->t_op;
change = 0;
if (NOTLEAFOP(op) && op!=COMMA && op!=QMARK && op!=LAND && op!=LOR &&
op!=LESS && op!=LESSEQ && op!=GREAT && op!=GREATEQ) {
change += rcodegen(&tp->t_left,cookie,reg);
if( BINOP(op) )
change += rcodegen(&tp->t_right,cookie,reg);
change += rcgen(tpp,cookie,reg);
} /* [vlh] 4.2 stop getting to this code on <, >, <=, >= */
if( change )
*tpp = canon(*tpp);
return(change);
}
rcgen(tpp,cookie,reg) /* returns changed flag*/
struct tnode **tpp; /* pointer to tree*/
int cookie; /* code generation goals*/
int reg; /* register to use*/
{
register struct tnode *tp, *p, *ltp, *rtp;
register short op, change;
change = 0;
for( tp = *tpp ; BINOP(op=tp->t_op); *tpp=tp=canon(tp), change++ ) {
ltp = tp->t_left;
if( ltp->t_op != SYMBOL )
break;
rtp = tp->t_right;
switch( op ) {
case ASSIGN:
if( ltp->t_sc != REGISTER )
return(change);
switch( rtp->t_op ) {
case DIV:
case MOD:
if( rtp->t_left->t_type==LONG && ltp->t_type==INT )
return(change); /* [vlh]4.3, ri = rl / 10 */
case MULT:
if( (rtp->t_left->t_type==INT || rtp->t_left->t_op==INT2L)
&& (rtp->t_right->t_type==INT || rtp->t_right->t_op==INT2L)
&& ltp->t_type==LONG)
return(change); /* [vlh]4.3, rl = i * i */
case AND:
case OR:
case XOR:
case LSH:
case RSH:
if( ISAREG(ltp->t_reg) )
return(change);
case ADD:
case SUB:
p = rtp->t_right;
if(NOTADDRESSABLE(ltp) || !noref(rtp->t_right,ltp->t_reg))
return(change);
p = rtp->t_left;
if( p->t_op != SYMBOL || p->t_sc != REGISTER ||
p->t_reg != ltp->t_reg ) {
tp->t_right = p;
PUTEXPR((cflag>1),"rcgen",tp);
codegen(tp,FOREFF,reg);
}
tp->t_right = rtp->t_right;
tp->t_op = rtp->t_op + (EQADD-ADD);
continue;
}
case EQLSH:
case EQRSH:
if( ltp->t_sc != REGISTER )
return(change);
case EQADD:
case EQSUB:
case EQAND:
case EQOR:
case EQXOR:
PUTEXPR((cflag>1),"rcgen EQOP",tp);
if( ltp->t_type == CHAR ) {
#ifdef DEBUG
if (cflag>1) printf("exiting rcgen with ltp type CHAR change %d\n",change);
#endif
return(change);
}
ucodegen(tp,FOREFF,reg);
tp = ltp;
continue;
case PREDEC:
case PREINC:
if(cookie==FORCC || ltp->t_type==CHAR)
return(change);
ucodegen(tp,FOREFF,reg);
tp = ltp;
continue;
}
break;
}
return(change);
}
noref(tp,reg) /* 4.0 change */
struct tnode *tp; /* returns 1 if no reference in tree to reg */
int reg;
{
if ( LEAFOP(tp->t_op) ) {
if (tp->t_op == SYMBOL && tp->t_sc == REGISTER && tp->t_reg == reg)
return(0);
return(1);
}
if ( !noref(tp->t_left,reg) )
return(0);
if (BINOP(tp->t_op))
return( noref(tp->t_right,reg) );
return(1);
}
/* cdsize - compute size of data item*/
cdsize(tp) /* returns data size in bytes*/
struct tnode *tp;
{
register short type;
type = tp->t_type;
if( SUPTYPE(type) )
return(PTRSIZE);
switch( type ) {
case INT:
case CHAR:
case UCHAR: /* [vlh] 4.2 */
case UNSIGNED:
return(INTSIZE);
case LONG:
case ULONG: /* [vlh] 4.2 */
case FLOAT: /* [vlh] 3.4 */
return(LONGSIZE);
}
error("cdsize: invalid type %d",type);
return(0);
}
dofarg(tp) /* returns number of bytes pushed*/
struct tnode *tp; /* pointer to expression tree*/
{
register short nb;
nb = 0;
if( tp->t_op == SYMBOL && tp->t_sc == STRUCT )
error("structure operation not implemented");
else if( stacksize ) {
codegen(tp,FORSTACK,0);
nb = cdsize(tp);
}
else
codegen(tp,FORSP,0);
return( nb );
}
/* dobitadd - do bit operation address checking and fixup*/
dobitadd(tp,bitno) /* returns -1 if can't or bitno*/
struct tnode *tp;
int bitno;
{
register short offset;
if( tp->t_type == CHAR )
offset = 0;
else
offset = cdsize(tp) - (bitno/BITSPBYTE) - 1;
if( tp->t_op == SYMBOL ) {
switch( tp->t_sc ) {
case REGISTER:
if( ISDREG(tp->t_reg) )
return(bitno);
default:
return(-1);
case EXTERNAL:
case STATIC:
case REGOFF:
case STATOFF:
case EXTOFF:
tp->t_offset += offset;
return( bitno % BITSPBYTE );
}
}
else if( tp->t_op == INDR ) {
tp->t_left = tnalloc(ADD,tp->t_left->t_type,0,0,tp->t_left,
cnalloc(INT,offset));
return( bitno % BITSPBYTE );
}
return(-1);
}
isonebit(tp) /* returns -1 if not 1 bit, else bitno*/
struct tnode *tp; /* pointer to tree*/
{
short lconst;
long bvalue;
if (!(tp = constant(tp,&lconst))) /* [vlh] 4.1 added long... */
return(-1);
bvalue = (lconst) ? tp->t_lvalue : (long) tp->t_value;
return(onebit(bvalue));