/* EPC Imp to C Translation Release 4 Version Apr 95 */ #include "imptoc.h" /** 23Sep98 cprocs08.2*/ /** Extended DoLongIntop to cope with the unsigned ops via RTs */ /** 24Mar98 cprocs08.1.1*/ /** Corrections to Caddresscomplexopnd for case when real&imag are in */ /** 30Jan98 cprocs08.1 */ /** Changes to Ccall for Microsoft STDCALL (back compatible) */ /** Correction to Cpushbytes */ /** 30Sep97 cprocs08 */ /* Added Ctrampcall for KAI parallel support */ /** Incorporated updates from AK for Cdim,Cdividelongint & */ /** Cdividelongdouble */ /** Ameneded CCopyBytes to use subroutine if no unclaimed regs */ /** Improved Cinregbylit to use LEA if CC set */ /** 30Sep97 cprocs07.4.2*/ /* Changes to Cunasscheck to cope with 8 byte integer and Misaligneds */ /** 02Sep97 cprocs07.4.1*/ /* Changes to Cpushparam & ccall so params pushed always a */ /* a multiple of 8 bytes */ /** 02Au97 cprocs07.4 */ /* All the following from ANDY or CMCP slightly amended by pds */ /* When coercing an I*4 to I*8 in ConvertII, explicitly */ /* forget the contents of the source register (because */ /* the generated code corrupts it) */ /* ensure all stack temporaries created for i*8 are */ /* 8-byte aligned to avoid stack "memory" problems */ /* at BitWordShift in Cbitops call __ush64 rather */ /* than __ash64 */ /* in Caddress, set FRAMEADDRTAKEN when taking an */ /* address by means of a store into the stack frame */ /* in ConvertIR check for FregVal as well as RegVal */ /* when checking for I*8 operand in a register */ /* in Cdividelongint change lockreg call to lockregister */ /* in IndRegVal case since lockreg doesn't nest and add */ /* lockregister call to IndRegModVal-by-a-literal case */ /* in Cnoteresult for I*8 results, only unlock and */ /* forget the address register if it has been allocated */ /* Prepare i*8 parameters of __arem64() and __cshft64() */ /* by calling Csplitdouble rather than Cdividelongint */ /* in effort to avoid register locking confusion */ /* In ConvertIR when the operand is a RegVal move the */ /* claiming of the target freg to after the store into */ /* the temporary to avoid FP reg stack confusion. */ /** Correct the array FPcompares in DoLongIntOp */ /** 10Jun97 cprocs07.3 */ /** Merged in a number of corrections from AK for I*8 stuff */ /** 30May97 cprocs07.2 */ /** Call Mexpcall & Mspcall with enumeration types(pds) */ /** 26May97 cprocs07.1 */ /** Correct case of some Fortran entry points (ak) */ /** Correct faulty C syntax (ak) */ /** Additions to Cdividelongint and LoadRealGeneral to cope with */ /** misaligned ints, plus additions to Csign, Cdim, Cminmax and */ /** Cbitops for 64-bit ints. (CMcP) */ /** 01Apr97 cprocs07 */ /** Additions to support 64-bit signed integers (CMcP) */ /** Corrections to EISHFT (Fortran only) (pds) */ /** 02Apr97 cprocs06.2 */ /** Improved Cstbits to eliminate an AND when operating on */ /** the leftmost bits of a bitfield */ /** Made loadintgen try harder if claim reg fails */ /** 06Jan97 cprocs06.1 */ /** Made names consistent for tarnslation to C */ /** 29Nov96 cprocs06 */ /** Added the P6 only instructions when targetvariant=PPRO2 */ /** 24Oct96 cprocs05.3 */ /** Deferred some simple coercions as per GCC */ /** 16Oct96 cprocs05..2 */ /** Used eprocs version of PIC. Added support for qrndsngl (for DG) */ /** and code mininimisation option for GPT as well as further */ /** improvements to Pentium pro code */ /** 11July96 cprocs05.1 */ /** Corrected reg memory management for _cmval code */ /** 23Feb96 cprocs05 */ /** Added Cautostackop to support alloca(pds) */ /** Reactivated the _Cmval code in note index */ /** Changed code in Cswitch cos of Lynxos assembler */ /** 05Dec95 cprocs04.9 */ /** Further improvements to CLdbits & Cstbits */ /** 23Nov95 cprocs04.8 */ /** Improvements to C ldbits and Cstbits */ /** 23Aug95 cprocs04.7 */ /** Changes for swopped data to be loaded(&unswapped) */ /** Some infrastructure support for 64 bit ints */ /** 08Aug95 cprocs04.6 */ /** Added in Load quad & store quad (All FPops acually quad) */ /** 28Jly95 cprocs04.5 */ /** Forced in truncation for convert rr 8->4 bytes */ /* 31May95 cprocs04.4 */ /** Changed Generate Float consts to work with USLC also */ /** Changed _intval to _Intvalue & Creinitialise */ /* 18Apr95 cprocs04.3 */ /** Change to Cnoteindex not to set elevel on loaded index */ /* before the operation is complete */ /* Added cglabel code to reload GOTREG for C++ catchblocks */ /* 23Jan95 cprocs04.2 */ /** Changes to ensure shift by 32 is correct for F90 */ /** Hardware does shift modulo 31 so frigging about is needed */ /** but only 0-32 inclusive need to be correct */ /* 20Dec94 cprocs04.1 */ /** Corrections to C bitops and also assigning real*4 to real*8 */ /* 08Sep94 cprocs04 */ /** Changes to code sequences after reading Pentium Optimisatios */ /* 03Jun94 cprocs03 */ /** Changes to fix to avoid problems when IMP IO called from Ftran */ /** Corrections to Cincreg & Cdecreg */ /* 25Mar93 cprocs02 */ /** Changes for the latest Bprocs */ /** Nov93 cprocs01 */ /** Initial Pentium version base on mips cprocs7.3(qv) */ /***/ #define modulename ("cprocs") /***/ /**************************************************************************/ /** **/ /** Module includes **/ /** **/ /**************************************************************************/ /***/ /* **** for booting ****** %ENDOFLIST */ #include "cgtarget.h" /***/ #include "cgconsts.h" /***/ #include "boconsts.h" /***/ #include "ecodes.h" /***/ #include "archdefs.h" /***/ #include "archrvars.h" /***/ #include "prototypes.h" /**** for booting %LIST */ /***/ /**************************************************************************/ /** **/ /** Global data **/ /** **/ /**************************************************************************/ /***/ /***/ extern struct Stkfmt Stk [Stklimit+1]; extern int Elevel; extern int Labadjust; extern int FirstDisplayLevel; extern int MainFrameOffset; extern int TargetReg; extern int TargetFreg; extern int FirstTarget; extern int TargetDToS; static const struct Stkfmt ZeroStk = {0}; /* Physical register masks showing registers that have been allocated by */ /* the optimiser to register variables. All such registers have their */ /* corresponding bit in the mask set. */ int RegClaimMaskA; int RegClaimMaskB; /***/ static int ReturnInstr=0; /***/ static struct paramfmt *ParI; /*set via CsetParI whenever Call Level changes*/ /***/ struct Stkfmt LitZero; struct Stkfmt LitOne; /***/ int Report; int localca; int cgoptions; /*as determined by ftncomp*/ extern int currentFSP; extern int calllevel; /* Nesting level of proc calls */ #define CHKOFLOW (0x200000) /* option bit for soft overflow checks */ #define RNDSNGL (0x8000000) /* force extra rounding to single precision */ #define NOREG 0 /* Memory only instruction*/ #define DESTREG 1 /* Memory => reg instr */ #define DESTSTORE 2 /* Reg => store instrn */ #define SOURCELIT 3 /* Lit => Store Lit is in reg */ int Regvaropt; /*set by Cinitialise*/ int diagnostics; /*set by Cinitialise*/ int setdbx; /*set by Cinitialise*/ extern int Pic; /* 0 => defaults */ /**/ static int Contexts; static int FirstTime; /*set by Cinitialise*/ static int addrf387; static int /*set by C Setfputraps*/ areaf387; static int f387=0x12731273; static int f387pr64=0x13731373; static int fixPrecision = 1; static int ParIIsSet; /***/ /***/ int QCIResMask; int QCFResMask; /***/ /*%IF Language=CCOMP %THENSTART */ int QCDepth; /*%FINISH */ /***/ static char AuxstackName [12]="s#auxstdata"; static struct Stkfmt Auxstk; /***/ static int RegvarSpace; /*displacement of temporary space on stack to */ /*store FRegvars across function calls. */ static int convarea; /* Offset of 4 byte area for real truncation */ static int floatarea1; static int floatarea2; static int floatoffset1; static int floatoffset2 /*locations for fixed to flt convsn */; int ParamsSaved=-1; /*set by Cinitialise */ int saveparams; /*set by Cstartproc and Csideentry and */ /*read by Ccountparams */ /***/ int cmplxtemp; /*temp location for saving Complex*16 results */ /***/ static struct Stkfmt Stkunassigned; /*an Estack-like entry addressing the unassigned*/ /* pattern in GLA */ extern unsigned char StackStflags [256+1]; /* records stack frame access */ /***/ /**/ /* comparison of registers with zero (unsigned then signed) */ /**/ static const int jops [11+1] = { JA<<16,JB<<16,JE<<16, JNE<<16,JAE<<16,JBE<<16,JG<<16,JL<<16, JE<<16,JNE<<16,JGE<<16,JLE<<16}; static const int jopsr [11+1] = { JB<<16,JA<<16,JE<<16, JNE<<16,JBE<<16,JAE<<16,JL<<16,JG<<16, JE<<16,JNE<<16,JLE<<16,JGE<<16}; /**/ /* The next arrays are for building correct comparison sequences */ /* for Ecode compares from the (absurdly) restricted MIPS comparison */ /* operations. the 0 & 255 are mask fields for putting in the */ /* register nos into the operation. Signed and unsigned sequences */ /* are built the same way. Only the set operations is different */ /**/ static const unsigned char Inversejump [JG-(JO)+1] = { JNO, JO,JNB,JB,JNE,JE,JA,0, JBE,JNS,JS,JNP,JP,JGE,JL,JG, JLE}; static const unsigned char setjump [JG-(JO)+1] = { SETO, SETNO,SETB,SETNB,SETE,SETNEQ,SETBE,0, SETA,SETS,SETNS,SETP,SETNP,SETL,SETGE,SETLEQ, SETG}; static const unsigned char cmovcc [JG-(JO)+1] = { CMOVO, CMOVNO,CMOVB,CMOVNB,CMOVE,CMOVNEQ,CMOVBE,0, CMOVA,CMOVS,CMOVNS,CMOVP,CMOVNP,CMOVL,CMOVGE,CMOVLEQ, CMOVG}; static const unsigned char Invcc [ALWAYS-(GT)+1] = { LT, GT,EQ,NE,LE,GE,255,255, 255,255,255,255,255,255,ALWAYS,NEVER }; /***/ /* Equivalent CC values for unsigned compare with zero */ static const unsigned char UnsCC [ALWAYS-(GT)+1] = { NE, NEVER,EQ,NE,ALWAYS,EQ,255,255, 255,255,255,255,255,255,NEVER,ALWAYS }; /***/ /***/ /**************************************************************************/ /** **/ /** imports **/ /** **/ /**************************************************************************/ /***/ /***/ static struct procfmt *PI; /***/ /***/ /**************************************************************************/ /** **/ /** local specs **/ /** **/ /**************************************************************************/ /***/ extern void Cdiscard( struct Stkfmt *); void Cjump( int ,int ,int ); void Cnoteindex( int ,struct Stkfmt *,struct Stkfmt *); void Crefer( struct Stkfmt *,int ,int ); void Caddress( struct Stkfmt *); int Cstoreop( struct Stkfmt *,struct Stkfmt *,int ); void CIntBinaryOp( int ,struct Stkfmt *,struct Stkfmt *,int ); void CIntUnaryOp(int ,struct Stkfmt *); void CRealBinaryOp( int ,struct Stkfmt *,struct Stkfmt *); void ConvertIR( struct Stkfmt *,int ); void ConvertII( struct Stkfmt *,int ); void ConvertIU( struct Stkfmt *,int ); void ConvertUI( struct Stkfmt *,int ); void ConvertUU( struct Stkfmt *,int ); int LoadIntTgt( struct Stkfmt *); int LoadIntRO( struct Stkfmt *); int LoadIntRONoExt( struct Stkfmt *); int LoadIntRW( struct Stkfmt *,int ); int LoadIntRWNoExt( struct Stkfmt *,int ); int LoadIntGeneral( struct Stkfmt *,int ,int ,int ); int LoadRealTgt( struct Stkfmt *,int ); int LoadRealRO( struct Stkfmt *,int ); int LoadRealRW( struct Stkfmt *,int ,int ); int LoadRealGeneral( struct Stkfmt *,int ,int ,int ); void Ccopybytes( struct Stkfmt *,struct Stkfmt *,struct Stkfmt *,int ); void Cdiscardopnd( struct Stkfmt *); void ConvertRIR( struct Stkfmt *,int ); /***/ /***/ /***/ /**************************************************************************/ /** **/ /** management of register records on Estack **/ /** **/ /**************************************************************************/ /***/ void Cresetreguse(int Oldlevel,int Newlevel) { /****************************************************************/ /** Ensure that register properties associated with **/ /** Estk(Oldlevel) are redefined to be associated with **/ /** Estk(Newlevel) **/ /****************************************************************/ ResetReguse(Oldlevel,Newlevel); } /* Cresetreguse */ /***/ extern void Cstackfr(int, int); void Cstackr(int R,int size) { /****************************************************************/ /** create an Estack entry for value held in a general register**/ /** The register is presumed claimed(ie lock=1 Eitem unknown) **/ /****************************************************************/ struct Stkfmt *Lstk; if (size == 8) { Cstackfr(R, size); Lstk = &Stk [Elevel]; if (Lstk->Form == (FregVal|Regflag)) Lstk->Form = RegVal|Regflag; else Lstk->Form = Regvar|Regflag; Lstk->Type = IntType; return; } Elevel+=1; Lstk=&Stk [Elevel]; memset(Lstk,0,sizeof( struct Stkfmt)); /** A Regvar register cannot be refered to as RegVal at any time */ if ((RegClaimMaskA&(1<Form=Regvar|Regflag; } else { Lstk->Form=RegVal|Regflag; } Lstk->Type=IntType; Lstk->Reg=R; Lstk->Size=size; unlockreg(R); lockregister(R,Elevel,size); } /* Cstackr */ /***/ /**/ /* Copyright (c) 1987 Edinburgh Portable Compilers Ltd. All Rights Reserved.*/ /**/ /***/ void Cstackfr(int FR,int Bytes) { /****************************************************************/ /** create an Estack entry for value in a floating register **/ /****************************************************************/ struct Stkfmt *Lstk; Elevel+=1; Lstk=&Stk [Elevel]; memset(Lstk,0,sizeof( struct Stkfmt)); /** A Fregvar register cannot be refered to as a FregVal at any time */ if ((RegClaimMaskB&(1<<(FR-FRBASE)))!=0) { Lstk->Form=Fregvar|Regflag; } else { Lstk->Form=FregVal|Regflag; } Lstk->Type=RealType; Lstk->Reg=FR; Lstk->Size=Bytes; if (registerstatus(FR)>0) unlockreg(FR); currentFSP-=1; lockregister(FR,Elevel,Bytes); } /* Cstackfr */ /***/ /**/ /* Copyright (c) 1987 Edinburgh Portable Compilers Ltd. All Rights Reserved.*/ /**/ /***/ void Cpushoperand(struct Stkfmt *Operand) { /****************************************************************/ /** create an Estack entry for a prepared operand **/ /****************************************************************/ int Form,Size,Bytes; if (Elevel>=Stklimit) Mabort(17); Form=Operand->Form&31; /* %IF Form=RegVal %THEN Cstackr(operand_reg,operand_size) %AND %RETURN */ /* %IF Form=FregVal %THEN Cstackfr(operand_reg,operand_size) %AND %RETURN*/ Elevel+=1; Stk [Elevel]=*Operand; if (IsRegForm [Form]!=0) { if (IsIndRegForm [Form]==0) { Size=Operand->Size; Bytes=Size; #if(Directcomplex==1) if (((Target==SPARC)&&(Size==16))||((targetvariant==M88110)&&(Operand->Imagreg!=0))) Bytes=(unsigned)Size >>1; #endif } else { Size=4; Bytes=4; } lockregister(Operand->Reg,Elevel,Bytes); if ((Directcomplex==1)&&(Size!=Bytes)) { lockregister(Operand->Imagreg,Elevel,Bytes); } } if (IsModForm [Form]!=0) { if (IsRegForm [Operand->Modform&31]!=0) { lockregister(Operand->Modreg,Elevel,4); } } } /* Cpush operand */ /***/ void Cmakedouble(struct Stkfmt *MSH, struct Stkfmt *LSH) { /*********************************************************************/ /* Construct a 64-bit int from two 32-bit pieces and leave on Estack */ /*********************************************************************/ struct Stkfmt res = {0}; int Mform = MSH->Form&31; int Lform = LSH->Form&31; if (Mform == Lform) { if (Mform == LitVal) { res.Form = LitVal; res.Type = IntType; res.Size = 8; res.Intvalue = LSH->Intvalue; res.Modintval = MSH->Intvalue; Cpushoperand(&res); return; } else if ((Mform == TempVal || Mform == ConstVal || (Mform == DirVal && MSH->Base == LSH->Base)) && ((MSH->Offset - LSH->Offset) == 4)) { res = *LSH; res.Size = 8; res.Type = IntType; Cpushoperand(&res); return; } } StkTemp(&res, ARCH(tempspace(8, 8)), 8); res.Type = IntType; res.Size = 4; Cstoreop(&res, LSH, 0); res.Offset += 4; Cstoreop(&res, MSH, 0); res.Offset -= 4; res.Size = 8; Cpushoperand(&res); } /**/ int Cdividelongint(struct Stkfmt *Opnd,struct Stkfmt *Clsh,struct Stkfmt *Cmsh) { /************************************************************************/ /** Divide a 64 bit integer into two 32 bit integers **/ /************************************************************************/ /***/ int Form,Size,Areg,Type,Flags; Form=Opnd->Form&31; Size=(unsigned)Opnd->Size>>1; Type=Opnd->Type; /* caddress changes this to Int */ if (Type==MisIntType) Type = IntType; Flags=Opnd->Flags; Areg=-1; *Clsh=*Opnd; Clsh->Type=Type; Clsh->Size=Size; if ((Form==DirVal)||(Form==TempVal)||(Form==ConstVal)||(Form==DirAddr)) { /*******************************************************/ /** Load a Direct Reference to a Longint **/ /*******************************************************/ *Cmsh=*Clsh; Cmsh->Offset=Clsh->Offset+Size; } else if (Form==IndRegVal) { *Cmsh=*Clsh; Cmsh->Form=IndRegModVal; Cmsh->Modform=LitVal; Cmsh->Modintval=Size; lockregister(Clsh->Reg,0,4); /* lock address reg for two accesses */ Areg=-2; } else if ((Form==IndRegModVal)&&(Clsh->Modform==LitVal)) { *Cmsh=*Clsh; Cmsh->Modintval=Cmsh->Modintval+Size; lockregister(Clsh->Reg,0,4); /* lock address reg for two accesses */ Areg=-2; } else if (Form==LitVal) { *Cmsh=*Clsh; Cmsh->Intvalue=Cmsh->Modintval; } else { /*******************************************************/ /** Load an InDirect Reference to a Longint **/ /*******************************************************/ /**/ Caddress(Opnd); /* load address */ Areg=LoadIntRO(Opnd); /* into a register */ /**/ lockregister(Areg,0,4) /*avoid address reg being reused*/; /* until both parts have been accessed */ memset(Clsh,0,sizeof( struct Stkfmt)); Clsh->Form=IndRegVal; Clsh->Reg=Areg; Clsh->Size=Size; Clsh->Type=Type; Clsh->Flags=Flags; *Cmsh=*Clsh; Cmsh->Form=IndRegModVal; Cmsh->Modform=LitVal; Cmsh->Modintval=Size; } return Areg; } /* Cdivide longint */ /***/ void Csplitdouble(struct Stkfmt *Lstk) { /*************************************************************************/ /* Turn a 64 bit integer into two 32 bit ones (MSH on top) */ /*************************************************************************/ struct Stkfmt lsh, msh; int areg; areg=Cdividelongint(Lstk, &lsh, &msh); if (areg >= 0) { unlockreg(areg); unlockreg(areg); /* unlock once for the lock imposed by Cdividelongint and ** unlock again for the lock imposed by LoadIntRO called ** by Cdividelongint -- Cpushoperand below will reimpose ** a lock */ } else if (areg==-2) { unlockreg(lsh.Reg); unlockreg(lsh.Reg); } Cpushoperand(&lsh); Cpushoperand(&msh); } /***/ /**************************************************************************/ /** **/ /** Support for 'Optimiser' Ecodes **/ /** **/ /**************************************************************************/ /***/ /***/ int claimtgtreg() { /*************************************************************************/ /** Returns integer target register if one has been allocated, **/ /** otherwise returns a claimed register. **/ /*************************************************************************/ struct Stkfmt Tstk; if (TargetReg>=0) { if (Elevel>0) { Tstk.Form=RegVal; Tstk.Type=IntType; Tstk.Reg=TargetReg; Tstk.Size=4; MCurrentvalue(&Tstk,Elevel); } return claimnamedtgt(TargetReg); } else { return claimreg(); } } /* claim tgt reg */ /***/ int claimtgtfreg() { /************************************************************************/ /** Returns float register if one has been allocated, otherwise **/ /** returns a claimed float register. **/ /************************************************************************/ struct Stkfmt Tstk; if (TargetFreg>=0) { if (Elevel>0) { Tstk.Form=FregVal; Tstk.Type=RealType; Tstk.Reg=TargetFreg; Tstk.Size=4; MCurrentvalue(&Tstk,Elevel); } return claimnamedtgt(TargetFreg); } else { return claimfreg(); } } /* claim tgt freg */ /***/ /***/ void Cstkregvar(int Creg,int Size,int Offset) { /*****************************************************************************/ /** Create an Estack entry for a variable held in an FORTRAN or C optimiser **/ /** register **/ /*****************************************************************************/ int Reg; #if(Language==CCOMP) Reg=CRegVarMap [Creg]; #else Reg=CregMap [Creg]; #endif Cstackr(Reg,Size); /* Stk(Elevel)_Form=Regvar ! Regflag */ /* Done in cstackr */ if (Size>=4) { SetExtFlag(Reg,REGUNKNOWNEXT); } else { SetExtFlag(Reg,REGUNEXTENDED); } Stk [Elevel].Offset=Offset; /**/ } /* Cstkregvar */ /***/ void Cstkfregvar(int Cfreg,int Size) { /*****************************************************************************/ /** Create an Estack entry for a variable held in an FORTRAN or C optimiser **/ /** floating point register **/ /*****************************************************************************/ int Reg; #if(Language==CCOMP) Reg=CRegVarMap [Cfreg]; #else Reg=CfregMap [Cfreg]; #endif Cstackfr(Reg,Size); /* Stk(Elevel)_Form= Fregvar ! Regflag */ /* Done in cstackr */ /**/ } /* Cstkfregvar */ /***/ void CregSTop(int Op,int ECFlag,struct Stkfmt *LHS,struct Stkfmt *RHS) { /*************************************************************************/ /** Implement LHS(regvar) = LHS(regvar) Op RHS (IADDST,... etc) **/ /** We do this by setting the TargetReg to that of the RHS and then **/ /** calling C Int Binary Op. **/ /** If ECFlag is non-zero then we stack an E-stack entry giving the **/ /** result of the operation. **/ /*************************************************************************/ struct Stkfmt DestStk; int Junk; /** Do the given operation, targetting the LHS register */ DestStk=*LHS; TargetReg=LHS->Reg; TargetFreg=-1; FirstTarget=1; TargetDToS=0; CIntBinaryOp(Op,LHS,RHS,0); TargetReg=-1; /** Now store the result of the operation in the Regvar. This is */ /** normally a nop but serves to unlock the register(s) and is */ /** needed if OP calls a support procedure which disables the */ /** targetting. */ Elevel-=1; Junk=Cstoreop(&DestStk,&Stk [Elevel+1],ECFlag); } /* CregSTop */ /***/ void CFregSTop(int Op,int ECFlag,struct Stkfmt *LHS,struct Stkfmt *RHS) { /*************************************************************************/ /** Implement LHS(Regvar) = LHS(regvar) Op RHS (RADDST,... etc) **/ /** We do this by setting the TargetFreg to that of the RHS and then **/ /** calling C Real Binary Op. **/ /** If ECFlag is non-zero then we stack an E-stack entry giving the **/ /** result of the operation. **/ /*************************************************************************/ struct Stkfmt DestStk; int Junk; /** Do the given operation, targetting the LHS register */ DestStk=*LHS; TargetReg=-1; TargetFreg=LHS->Reg; FirstTarget=1; TargetDToS=0; CRealBinaryOp(Op,LHS,RHS); TargetFreg=-1; /** Now store the result of the operation in the Fregvar. This is */ /** normally a nop but serves to unlock regsister(s) and is */ /** needed if OP calls a support procedure which disables the */ /** targetting. */ Elevel-=1; Junk=Cstoreop(&DestStk,&Stk [Elevel+1],ECFlag); } /* CFregSTOp */ /***/ void CChangeContexts(int set,int unset) { /************************************************************************/ /* Generate a CXTCHANGE type instruction to record the contexts being **/ /* set and/or unset. Also set global flags to aid some code generator **/ /* decisions. **/ /************************************************************************/ struct instrfmt *instr; instr=(struct instrfmt*)(BNewInstr()); instr->group=CXTCHANGE; instr->u0.CXTset=set; instr->u1.CXTunset=unset; Contexts|=set; Contexts|=~unset; } /*CChangeContexts */ /***/ /**/ /* Copyright (c) 1989 Edinburgh Portable Compilers Ltd. All Rights Reserved.*/ /**/ /***/ /***/ /**************************************************************************/ /** **/ /** conversions **/ /** **/ /**************************************************************************/ /***/ static void GenerateFloatConstants() { /*************************************************************************/ /** Two 64 bit constants and a work word are set up in the GLA **/ /** The work word has the top part of 2**52 set the bottom empty **/ /*************************************************************************/ static const int aa [2+1] = { 0x127F1E7F,0x1A7F167F, 0x3F000000 }; Msetconst((int)&aa [0],8,&floatarea1,&floatoffset1); Msetconst((int)&aa [2],4,&floatarea2,&floatoffset2 /* make 0.5 poolable*/); /* works on USLC but consts become read only */ } /***/ static void Extendreg(int Oldreg,int Newreg,int Oldsize,int Newsize,int type) { /*************************************************************************/ /** Sign or zero extends the register as appropiate. Newsize can not **/ /** be greater than the register size **/ /*************************************************************************/ int mask,shift; if (type==UintType) { /* mask off top bite */ mask=-1; if ((Oldsize==2)||(Newsize==2)) mask=0xFFFF; if ((Oldsize==1)||(Newsize==1)) mask=255; if (mask==-1) return ; ARCH(oplit(AND,Oldreg,mask,Newreg)); SetExtFlag(Newreg,REGUNSIGNEDEXT); return ; } /* we need to sign extend */ if (Oldsize==2 && (MINCODESIZE!=0 || Oldreg!=Newreg)) { ARCH(rr(MOVSX,Oldreg,-1,Newreg)); SetExtFlag(Newreg,REGSIGNEDEXT); return ; } if (Oldsize==1 && Oldreg<=3 && (MINCODESIZE!=0 || Oldreg!=Newreg)) { ARCH(rr(LB,Oldreg,-1,Newreg)); SetExtFlag(Newreg,REGSIGNEDEXT); return ; } shift=8*(4-Oldsize); ARCH(rlit(SHL,Oldreg,shift,Newreg)); ARCH(rlit(SAR,Newreg,shift,Newreg)); SetExtFlag(Newreg,REGSIGNEDEXT); } /***/ void ConvertRR(struct Stkfmt *Stk,int Newsize) { /****************************************************************/ /** converts between real sizes **/ /** descriptor to result on Estack **/ /****************************************************************/ /**/ /**/ /* Warning the code in this convert routine appears to make the hidden */ /*assumption that the operand is also at ESTK(ELEVEL+1) !!! */ /**/ int form,freg1,bytes; struct Stkfmt Tstk; form=Stk->Form&31; bytes=Stk->Size; if ((Stk->Size==Newsize)&&((Newsize>4)||((cgoptions&RNDSNGL)==0)||(form!=FregVal))) { Elevel+=1; } else { if ((Stk->Form&31)!=FregVal) { freg1=LoadRealRO(Stk,bytes); unlockreg(freg1); Cstackfr(freg1,Newsize); } else { Elevel+=1; Stk->Size=Newsize; } if (Newsize==4) { /* %IF convarea=0 %THEN convarea=epermspace(4,4) */ /* Gladir(Tstk,convarea,4) */ convarea=ARCH(tempspace(4,4)); StkTemp(&Tstk,convarea,4); ARCH(oprx(FSTPm,currentFSP,&Tstk,DESTSTORE)); ARCH(modinstrprops(DESTROYABLE,0,0,PRECISIONREDN)); ARCH(oprx(FLDm,currentFSP,&Tstk,DESTREG)); ARCH(modinstrprops(DESTROYABLE,0,0,PRECISIONREDN)); } } } /* Convert RR */ /***/ void ConvertRI(struct Stkfmt *Lstk,int Newsize,int Mode) { /****************************************************************/ /** converts between real and integer **/ /** Mode = 0 TNC (ie truncate towards zero) **/ /** 1 RND (ie the nearest integer) **/ /** 2 FLOOR (ie Truncate towards minus infinity) **/ /** 3 CEIL (ie Truncate towards plus infinity) **/ /** descriptor to result on Estack **/ /****************************************************************/ /**/ /**/ /* Warning the code in this convert routine appears to make the hidden */ /*assumption that the operand is also at ESTK(ELEVEL+1) !!! */ /**/ int op,bytes,wreg3,j; struct instrfmt *curinstr; struct Stkfmt Tstk; bytes=Lstk->Size; if (floatarea1<=0) GenerateFloatConstants(); if ((bytes==4)&&((cgoptions&RNDSNGL)!=0)) { curinstr=BCurInstr(); if ((curinstr->privprops&PRECISIONREDN)==0) { ConvertRR(Lstk,4); Elevel-=1; } } if (Mode==1) { ConvertRIR(Lstk,1) /* Deal with exact halfs correctly */; wreg3=currentFSP; Elevel-=1; } else { ARCH(opr(PUSH,EAX)); /* make space */ ARCH(fopmem(FSTCW,ESP,0,2)); /* Save current mode */ wreg3=LoadRealRW(Lstk,-1,bytes); ARCH(fopfixmem(FLDCW,floatarea1,floatoffset1+(2*Mode),2)); /* Force right rounding mode*/ } op=FISTP; if (Newsize==8) { j=ARCH(tempspace(8,8)); op=FISTPd; } else { /* j=ARCH(tempspace(4,4)); */ /* last line commented out and two new lines added due to chip bug on P6 */ /* bug does dot affect the double store so store double but use lower 32 bits */ j=ARCH(tempspace(8,8)); op=FISTPd; } StkTemp(&Tstk,j,Newsize); ARCH(oprx(op,0,&Tstk,DESTSTORE)); CheckConflict(STACK,j,8); Tstk.Type=Intval; Cpushoperand(&Tstk); unlockreg(wreg3); if (Mode!=1) { ARCH(fopmem(FLDCW,ESP,0,2)); /* Back to original rounding */ ARCH(rlit(ADD,ESP,4,ESP)); } } /* Convert RI */ /***/ void ConvertRU(struct Stkfmt *SStk,int Newsize) { /*****************************************************************/ /** converts between real and unsigned integer **/ /** descriptor to result on Estack **/ /** On SPARC, works by using clib.a __ftou and __fdou. **/ /** These are envoked by the routine Mexpcall. **/ /*****************************************************************/ int reg,j; double Two63; /**/ /* Warning the code in this convert routine appears to make the hidden */ /*assumption that the operand is also at ESTK(ELEVEL+1) !!! */ /**/ struct Stkfmt Tstk; Two63=256.0*256.0*256.0*256.0*256.0*256.0*256.0*128.0; if (floatarea1<=0) GenerateFloatConstants(); TargetReg=-1; /* Ensure no more targetting as we may now be */ TargetFreg=-1; /* doing a nested call */ enotecc(-1); /* Notify EMachine that cond codes changed */ ARCH(opr(PUSH,EAX)); /* make space */ ARCH(fopmem(FSTCW,ESP,0,2)); /* Save current mode */ if (Newsize==8) { Elevel+=1; estkrconst(8,(int)&Two63); if (SStk->Size!=8) { estklit(SStk->Size); eop(CVTRR); } eop(RSUB); Elevel-=1; ARCH(fopfixmem(FLDCW,floatarea1,floatoffset1,2)) /* Force to rnd to zero */; } else { ARCH(fopfixmem(FLDCW,floatarea1,floatoffset1+4,2)) /* Force to rnd dowm to -inf */; } reg=LoadRealRW(SStk,-2,SStk->Size); j=ARCH(tempspace(8,8)); StkTemp(&Tstk,j,8); ARCH(oprx(FISTPd,0,&Tstk,DESTSTORE)); CheckConflict(STACK,j,8); unlockreg(currentFSP); StkTemp(&Tstk,j,Newsize) /*ls Newsize bytes */; Tstk.Type=UintType; if (Newsize==8) { reg=claimreg(); ARCH(loadri(LW,EBP,Tstk.Offset+4,reg)); ARCH(oplit(XOR,reg,0x80000000,reg)); ARCH(storeri(ST,reg,EBP,Tstk.Offset+4)); unlockreg(reg); } Cpushoperand(&Tstk); ARCH(fopmem(FLDCW,ESP,0,2)); /* Back to original rounding */ ARCH(rlit(ADD,ESP,4,ESP)); } /* Convert RU */ /***/ void ConvertRIR(struct Stkfmt *Rstk,int Mode) { /****************************************************************/ /** converts between real and integer leaving the result real **/ /** Mode = 0 TNCRR (ie truncate towards zero) **/ /** 1 RNDRR (ie the nearest integer) **/ /** descriptor to result on Estack **/ /****************************************************************/ int bytes,reg,regi,lab1,lab2,Index1,Index2; /**/ /* Warning the code in this convert routine appears to make the hidden */ /*assumption that the operand is also at ESTK(ELEVEL+1) !!! */ bytes=Rstk->Size; if (floatarea1<=0) GenerateFloatConstants(); ARCH(opr(PUSH,EAX)); /* make space */ ARCH(fopmem(FSTCW,ESP,0,2)); /* Save current mode */ ARCH(fopfixmem(FLDCW,floatarea1,floatoffset1,2)); /* Force round to zero mode*/ reg=LoadRealRW(Rstk,-1,bytes); if (Mode==1) { /* Round to nearest even does not deal with 0.5 */ /* correctly 50 of the time so must struggle */ ARCH(oponly(FTST,0,0)); regi=claimnamedreg(EAX); lab1=Mprivatelabel(); lab2=Mprivatelabel(); Index1=BLocateLabel(lab1+Labadjust,0); Index2=BLocateLabel(lab2+Labadjust,0); ARCH(oponly(FSTSW,1<