/* */ /* PARSERFP.C -- Part of FRACTINT fractal drawer. */ /* */ /* By Chuck Ebbert CompuServe [76306,1226] */ /* internet: 76306.1226@compuserve.com */ /* */ /* Fast floating-point parser code. The functions beginning with */ /* "fStk" are in PARSERA.ASM. PARSER.C calls this code after */ /* it has parsed the formula. */ /* */ /* Converts the function pointers/load pointers/store pointers */ /* built by parsestr() into an optimized array of function */ /* pointer/operand pointer pairs. */ /* */ /* ******************************************************************* */ /* */ /* Copyright (C) 1992, 1993 Chuck Ebbert. All rights reserved. */ /* */ /* This code may be freely distributed and used in non-commercial */ /* programs provided the author is credited either during program */ /* execution or in the documentation, and this copyright notice */ /* is left intact. Sale of this code, or its use in any commercial */ /* product requires permission from the author. Nominal */ /* distribution and handling fees may be charged by shareware and */ /* freeware distributors. */ /* */ /* Chuck Ebbert */ /* 1915 Blust Ln. */ /* Enola, PA 17025 */ /* */ /* ******************************************************************* */ /* */ /* Revised 12 July 1993 (for v18.1) by CAE to fix optimizer bug */ /* */ /* Revised 22 MAR 1993 (for Fractint v18.0) */ /* */ /* Uncomment the next line to enable debug. */ /* #define TESTFP 1 */ /* */ #include #include #include #include #include #include #include "mpmath.h" #include "prototyp.h" extern union Arg *Arg1, *Arg2; /* Some of these variables should be renamed for safety */ extern union Arg s[20], far * far *Store, far * far *Load; extern int StoPtr, LodPtr, OpPtr; extern int debugflag; extern unsigned vsp, LastOp; extern struct ConstArg far *v; extern int inside; /* "inside" color to use */ extern int outside; /* "outside" color to use */ extern int potflag; /* potential enabled? */ extern char useinitorbit; extern int InitLodPtr, InitStoPtr, InitOpPtr, LastInitOp; extern void (far * far *f)(void); struct fls { /* function, load, store pointers CAE fp */ void (near *function)(void); union Arg near *operand; } far *pfls = (struct fls far *)0; void StkLod(void); void StkClr(void); void dStkAdd(void); void dStkSub(void); void dStkMul(void); void dStkDiv(void); void StkSto(void); void dStkSqr(void); void EndInit(void); void dStkMod(void); void dStkLTE(void); void dStkSin(void); void dStkCos(void); void dStkSinh(void); void dStkCosh(void); void dStkCosXX(void); void dStkTan(void); void dStkTanh(void); void dStkCoTan(void); void dStkCoTanh(void); void dStkLog(void); void dStkExp(void); void dStkPwr(void); void dStkLT(void); void dStkFlip(void); void dStkReal(void); void dStkImag(void); void dStkConj(void); void dStkNeg(void); void dStkAbs(void); void dStkRecip(void); void StkIdent(void); void dStkGT(void); void dStkGTE(void); void dStkNE(void); void dStkEQ(void); void dStkAND(void); void dStkOR(void); #define fgf(x) pfls[(x)].function #define opp(x) pfls[(x)].operand #define NO_OPERAND (void near *)0 #define LastSqr v[4].a #define MAX_ARGS 100 #define MAX_STACK 8 #define TWO_FREE 6 #ifndef XFRACT void (near fStkPull2 )(void); /* pull up fpu stack from 2 to 4 */ void (near fStkPush2 )(void); /* push down fpu stack from 8 to 6 */ void (near fStkPush2a )(void); /* push down fpu stack from 6 to 4 */ void (near fStkPush4 )(void); /* push down fpu stack from 8 to 4 */ void (near fStkLodDup )(void); /* lod, dup */ void (near fStkLodSqr )(void); /* lod, sqr, dont save magnitude */ void (near fStkLodSqr2 )(void); /* lod, sqr, save magnitude */ void (near fStkStoDup )(void); /* store, duplicate */ void (near fStkStoSqr )(void); /* store, sqr, save lastsqr */ void (near fStkStoSqr0 )(void); /* store, sqr, dont save lastsqr */ void (near fStkLodDbl )(void); /* load, double */ void (near fStkStoDbl )(void); /* store, double */ void (near fStkReal2 )(void); /* fast ver. of real */ void (near fStkSqr )(void); /* sqr, save magnitude in lastsqr */ void (near fStkSqr0 )(void); /* sqr, no save magnitude */ void (near fStkClr1 )(void); /* clear fpu */ void (near fStkClr2 )(void); /* test stack top, clear fpu */ void (near fStkStoClr1 )(void); /* store, clr1 */ void (near fStkAdd )(void); void (near fStkSub )(void); void (near fStkSto )(void); void (near fStkSto2 )(void); /* fast ver. of sto */ void (near fStkLod )(void); void (near fStkEndInit )(void); void (near fStkMod )(void); void (near fStkMod2 )(void); void (near fStkLodMod2 )(void); void (near fStkStoMod2 )(void); void (near fStkLTE )(void); void (near fStkLodLTEMul )(void); void (near fStkLTE2 )(void); void (near fStkLodLTE )(void); void (near fStkLodLTE2 )(void); void (near fStkLodLTEAnd2 )(void); void (near fStkLT )(void); void (near fStkLodLTMul )(void); void (near fStkLT2 )(void); void (near fStkLodLT )(void); void (near fStkLodLT2 )(void); void (near fStkGTE )(void); void (near fStkLodGTE )(void); void (near fStkLodGTE2 )(void); void (near fStkGT )(void); void (near fStkGT2 )(void); void (near fStkLodGT )(void); void (near fStkLodGT2 )(void); void (near fStkEQ )(void); void (near fStkLodEQ )(void); void (near fStkNE )(void); void (near fStkLodNE )(void); void (near fStkAND )(void); void (near fStkANDClr2 )(void); void (near fStkOR )(void); void (near fStkSin )(void); void (near fStkSinh )(void); void (near fStkCos )(void); void (near fStkCosXX )(void); void (near fStkCosh )(void); void (near fStkTan )(void); void (near fStkTanh )(void); void (near fStkCoTan )(void); void (near fStkCoTanh )(void); void (near fStkLog )(void); void (near fStkExp )(void); void (near fStkPwr )(void); void (near fStkMul )(void); void (near fStkDiv )(void); void (near fStkFlip )(void); void (near fStkReal )(void); void (near fStkImag )(void); void (near fStkRealFlip )(void); void (near fStkImagFlip )(void); void (near fStkConj )(void); void (near fStkNeg )(void); void (near fStkAbs )(void); void (near fStkRecip )(void); void (near fStkLodReal )(void); void (near fStkLodRealC )(void); void (near fStkLodImag )(void); void (near fStkLodRealFlip )(void); void (near fStkLodRealAbs )(void); void (near fStkLodRealMul )(void); void (near fStkLodRealAdd )(void); void (near fStkLodRealSub )(void); void (near fStkLodImagFlip )(void); void (near fStkLodImagAbs )(void); void (near fStkLodConj )(void); void (near fStkLodAdd )(void); void (near fStkLodSub )(void); void (near fStkLodSubMod )(void); void (near fStkLodMul )(void); void (near fStkPLodAdd )(void); void (near fStkPLodSub )(void); void (near Img_Setup )(void); static void (near *prevfptr )(void); static int stkcnt, prevstkcnt, cvtptrx, prevlodptr, lastsqrused; static void CvtFptr(void (near * ffptr)(void), int MinStk, int MaxStk, int Delta ) /* (MinStk <= 4, MaxStk >= TWO_FREE) */ { char testconst = 0; if (stkcnt < MinStk ) { /* not enough operands on fpu stack */ #ifdef TESTFP stopmsg(0, "Inserted pull." ); #endif opp(cvtptrx) = NO_OPERAND; fgf(cvtptrx++) = fStkPull2; /* so adjust the stack, pull operand */ stkcnt += 2; } else if (stkcnt > MaxStk ) { /* too many operands */ #ifdef TESTFP stopmsg(0, "Inserted push." ); #endif opp(cvtptrx) = NO_OPERAND; fgf(cvtptrx++) = fStkPush2; /* push operand to adjust stack */ stkcnt -= 2; } /* set the operand pointer here */ if (ffptr == fStkSto ){ /* this must be before test for load */ opp(cvtptrx) = (void near *)(Store[StoPtr++]); } else if (ffptr == fStkLod && debugflag == 322 ){ /* if disabling optimizer, set load pointer here */ opp(cvtptrx) = (void near *)(Load[LodPtr++]); } else { opp(cvtptrx) = NO_OPERAND; } if (debugflag == 322 ){ goto SkipOptimizer; } /* -------------------------- begin optimizer -------------- */ /* For the following: */ /* * == cvtptrx points to this */ /* () == this is about to be added to the array */ if (ffptr == fStkLod) { /* we are about to add Lod to the array */ if (prevfptr == fStkLod && Load[LodPtr-1] == Load[LodPtr] ) { /* previous non-adjust operator was Lod of same operand */ /* i.e. found {? lodx ? (*lodx) } */ if (fgf(--cvtptrx) == fStkPush2 ){ /* prev fn was push */ /* {? lod *push (lod) } */ --cvtptrx; /* found {? *lod push (lod) } */ if (fgf(cvtptrx-1) == fStkPush2){ /* always more ops here */ #ifdef TESTFP stopmsg(0, "push *lod push (lod) -> push4 (*loddup)" ); #endif fgf(cvtptrx-1) = fStkPush4; } else { /* prev op not push */ #ifdef TESTFP stopmsg(0, "op *lod push (lod) -> op pusha(p=0) (*loddup)" ); #endif opp(cvtptrx) = NO_OPERAND; /* use 'alternate' push fn. */ fgf(cvtptrx++) = fStkPush2a; /* push with TWO_FREE on stack */ /* operand ptr will be set below */ } } else { /* never {push *lod (lod) } so must be */ #ifdef TESTFP stopmsg(0, "op *lod (lod) -> op (*loddup)" ); #endif } ffptr = fStkLodDup; } else if (prevfptr == fStkSto2 && Store[StoPtr-1] == Load[LodPtr] ){ /* store, load of same value */ /* only one operand on stack here when prev oper is Sto2 */ --cvtptrx; #ifdef TESTFP stopmsg(0, "*sto2 (lod) -> (*stodup)" ); #endif ffptr = fStkStoDup; } /* This may cause roundoff problems when later operators */ /* use the rounded value that was stored here, while the next */ /* operator uses the more accurate internal value. */ else if (prevfptr == fStkStoClr1 && prevstkcnt == 2 && Store[StoPtr-1] == Load[LodPtr] ){ /* store, clear, load same value found */ /* only one operand was on stack so this is safe */ --cvtptrx; #ifdef TESTFP stopmsg (0, "*StoClr1 (Lod) -> (*Sto2)" ); #endif ffptr = fStkSto2; /* use different Sto fn */ } else { /* the really awful hack below gets the first char of the name */ /* of the variable being loaded */ testconst = **(((char * far *)Load[LodPtr] ) - 2 ); if ( !isalpha(testconst) && Load[LodPtr]->d.y == 0.0 ){ /* if first character not alpha, the var is a constant */ #ifdef TESTFP stopmsg (0, "(*lod) -> (*lodrealc)" ); #endif ffptr = fStkLodRealC; /* a real const is being loaded */ } } /* set the operand ptr here */ opp(cvtptrx) = (void near *)(Load[LodPtr++]); } else if (ffptr == fStkAdd ){ if (prevfptr == fStkLodDup ){ /* there is never a push before add */ --cvtptrx; /* found {? *loddup (add) } */ if (cvtptrx>0 && fgf(cvtptrx-1) == fStkPush2a ){ /* because {push lod lod } impossible so is {push loddup } */ #ifdef TESTFP stopmsg (0, "pusha *loddup (add) -> (*loddbl),stk+=2" ); #endif --cvtptrx; opp(cvtptrx) = opp(cvtptrx+1); /* fix opptr */ stkcnt += 2; } else if (cvtptrx>0 && fgf(cvtptrx-1) == fStkPush4 ){ #ifdef TESTFP stopmsg (0, "push4 *loddup (add) -> push2 (*loddbl),stk+=2" ); #endif fgf(cvtptrx-1) = fStkPush2; stkcnt += 2; /* CAE added 12 July 1993 to fix bug */ } else { #ifdef TESTFP stopmsg (0, "op *loddup (add) -> {op (*loddbl)" ); #endif } ffptr = fStkLodDbl; } else if (prevfptr == fStkStoDup ){ #ifdef TESTFP stopmsg (0, "stodup (add) -> (stodbl)" ); #endif /* there are always exactly 4 on stack here */ --cvtptrx; ffptr = fStkStoDbl; } else if (prevfptr == fStkLod ){ /* have found {lod (*add) } */ --cvtptrx; /* {? *lod (add) } */ if (fgf(cvtptrx-1) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "*push load (add) -> (*plodadd),stk+=2" ); #endif --cvtptrx; stkcnt += 2; /* eliminated a push */ opp(cvtptrx) = opp(cvtptrx+1); /* fix opptrs */ ffptr = fStkPLodAdd; } else { #ifdef TESTFP stopmsg (0, "op *lod (add) -> op (*lodadd)" ); #endif ffptr = fStkLodAdd; } } else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ --cvtptrx; /* found {? *lodreal (add) } */ if (fgf(cvtptrx-1) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "*push lodreal (add) -> (*lodrealadd),stk+=2" ); #endif --cvtptrx; stkcnt += 2; /* push eliminated */ opp(cvtptrx) = opp(cvtptrx+1); /* fix opptrs */ } else { #ifdef TESTFP stopmsg (0, "*lodreal (add) -> (*lodrealadd)" ); #endif } ffptr = fStkLodRealAdd; } } else if (ffptr == fStkSub ){ if (prevfptr == fStkLod ){ /* found {lod (*sub) } */ --cvtptrx; /* {*lod (sub) } */ /* there is never a sequence (lod push sub ) */ if (fgf(cvtptrx-1) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "*push lod (sub) -> (*plodsub),stk+=2" ); #endif --cvtptrx; opp(cvtptrx) = opp(cvtptrx+1); /* fix opptrs */ stkcnt += 2; /* push was deleted so adj. stkcnt */ ffptr = fStkPLodSub; } else { #ifdef TESTFP stopmsg (0, "*lod (sub) -> (*lodsub)" ); #endif ffptr = fStkLodSub; } } else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ --cvtptrx; /* {? *lodreal (sub) } */ if (fgf(cvtptrx-1) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "*push lodreal (sub) -> (*lodrealsub),stk+=2" ); #endif --cvtptrx; stkcnt += 2; /* push eliminated */ opp(cvtptrx) = opp(cvtptrx+1); /* fix opptrs */ } else { #ifdef TESTFP stopmsg (0, "*lodreal (sub) -> (*lodrealsub)" ); #endif } ffptr = fStkLodRealSub; } } else if (ffptr == fStkMul ){ if (prevfptr == fStkLodDup ){ /* found {loddup ? (*mul) } */ if (fgf(--cvtptrx) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "loddup *push (mul) -> (*lodsqr),stk+=2" ); #endif stkcnt += 2; /* eliminate this push */ --cvtptrx; /* prev is a LodDup */ } else { #ifdef TESTFP stopmsg (0, "*loddup (mul) -> (*lodsqr)" ); #endif } ffptr = fStkLodSqr; } else if (prevfptr == fStkStoDup ){ /* no pushes here, 4 on stk. */ #ifdef TESTFP stopmsg (0, "stodup (mul) -> (*stosqr0)" ); #endif --cvtptrx; ffptr = fStkStoSqr0; /* dont save lastsqr here ever */ } else if (prevfptr == fStkLod ){ --cvtptrx; /* {lod *? (mul) } */ if (fgf(cvtptrx) == fStkPush2 ){ /* {lod *push (mul) } */ --cvtptrx; /* {? *lod push (mul) } */ if(fgf(cvtptrx-1) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "push *lod push (mul) -> push4 (*lodmul)" ); #endif fgf(cvtptrx-1) = fStkPush4; } else { #ifdef TESTFP stopmsg (0, "op *lod push (mul) -> op pusha (*lodmul)" ); #endif opp(cvtptrx+1) = opp(cvtptrx); /* fix operand ptr */ fgf(cvtptrx) = fStkPush2a; opp(cvtptrx++) = NO_OPERAND; } } else { #ifdef TESTFP stopmsg (0, "*lod (mul) -> (*lodmul)" ); #endif } ffptr = fStkLodMul; } else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ --cvtptrx; /* found {lodreal *? (mul) } */ if (fgf(cvtptrx) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "lodreal *push2 (mul) -> (*lodrealmul),stk+=2" ); #endif --cvtptrx; stkcnt += 2; /* stack ends with TWO_FREE, not 4 */ } else { #ifdef TESTFP stopmsg (0, "*lodreal (mul) }-> {(*lodrealmul)" ); #endif } ffptr = fStkLodRealMul; } else if (prevfptr == fStkLodLT && fgf(cvtptrx-1) != fStkPull2 ){ /* this shortcut fails if {Lod LT Pull Mul } found */ #ifdef TESTFP stopmsg (0, "LodLT (*Mul) -> (*LodLTMul)" ); #endif --cvtptrx; /* never { lod LT Push Mul } here */ ffptr = fStkLodLTMul; } else if (prevfptr == fStkLodLTE && fgf(cvtptrx-1) != fStkPull2 ){ #ifdef TESTFP stopmsg (0, "LodLTE (*mul) -> (*LodLTEmul)" ); #endif --cvtptrx; ffptr = fStkLodLTEMul; } } else if (ffptr == fStkClr1 && prevfptr == fStkSto ){ #ifdef TESTFP stopmsg (0, "sto (*clr1) -> (*stoclr1)" ); #endif --cvtptrx; ffptr = fStkStoClr1; } else if (ffptr == fStkDiv ){ if (prevfptr == fStkLodRealC && vsp < MAX_ARGS - 1 ){ /* have found a divide by a real constant */ /* and there is space to create a new one */ /* {lodrealc ? (*div) } */ --cvtptrx; /* change '/ const' to '* 1/const' */ if (fgf(cvtptrx) == fStkPush2 ){ #ifdef TESTFP stopmsg (0, "lodrealc *push (div) -> (*lodrealmul),stk+=2" ); #endif --cvtptrx; stkcnt += 2; } else { #ifdef TESTFP stopmsg (0, "*lodrealc (div) -> {(*lodrealmul)" ); #endif } v[vsp].s = (void near *)0; /* this constant has no name */ v[vsp].len = 0; v[vsp].a.d.x = 1.0 / Load[LodPtr-1]->d.x; v[vsp].a.d.y = 0.0; opp(cvtptrx) = (void near *)&v[vsp++].a; /* isn't C fun! */ ffptr = fStkLodRealMul; } } else if (ffptr == fStkReal ){ if (prevfptr == fStkLod ){ #ifdef TESTFP stopmsg (0, "lod (*real) -> (*lodreal)" ); #endif --cvtptrx; ffptr = fStkLodReal; } else if (stkcnt < MAX_STACK ){ #ifdef TESTFP stopmsg (0, "(*real) -> (*real2)" ); #endif ffptr = fStkReal2; } } else if (ffptr == fStkImag && prevfptr == fStkLod ){ #ifdef TESTFP stopmsg (0, "lod (*imag) -> lodimag" ); #endif --cvtptrx; ffptr = fStkLodImag; } else if (ffptr == fStkConj && prevfptr == fStkLod ){ #ifdef TESTFP stopmsg (0, "lod (*conj) -> (*lodconj)" ); #endif --cvtptrx; ffptr = fStkLodConj; } else if (ffptr == fStkMod && stkcnt < MAX_STACK ){ #ifdef TESTFP stopmsg (0, "(*mod) -> (*mod2)" ); #endif ffptr = fStkMod2; /* use faster version if room on stack */ if (prevfptr == fStkLod ){ #ifdef TESTFP stopmsg (0, "lod (*mod2) -> (*lodmod2)" ); #endif --cvtptrx; ffptr = fStkLodMod2; } else if (prevfptr == fStkSto || prevfptr == fStkSto2 ){ #ifdef TESTFP stopmsg (0, "sto (*mod2) -> (*stomod2)" ); #endif --cvtptrx; ffptr = fStkStoMod2; } else if (prevfptr == fStkLodSub ){ #ifdef TESTFP stopmsg (0, "lodsub (*mod2) -> (*lodsubmod)" ); #endif --cvtptrx; ffptr = fStkLodSubMod; } } else if (ffptr == fStkFlip ){ if (prevfptr == fStkReal || prevfptr == fStkReal2 ){ #ifdef TESTFP stopmsg (0, "real (*flip) -> (*realflip)" ); #endif --cvtptrx; ffptr = fStkRealFlip; } else if (prevfptr == fStkImag ){ #ifdef TESTFP stopmsg (0, "imag (*flip) -> (*imagflip)" ); #endif --cvtptrx; ffptr = fStkImagFlip; } else if (prevfptr == fStkLodReal ){ #ifdef TESTFP stopmsg (0, "lodreal (*flip) -> (*lodrealflip)" ); #endif --cvtptrx; ffptr = fStkLodRealFlip; } else if (prevfptr == fStkLodImag ){ #ifdef TESTFP stopmsg (0, "lodimag (*flip) -> (*lodimagflip)" ); #endif --cvtptrx; ffptr = fStkLodImagFlip; } } else if (ffptr == fStkAbs ){ if (prevfptr == fStkLodReal ){ #ifdef TESTFP stopmsg (0, "lodreal (*abs) -> (*lodrealabs)" ); #endif --cvtptrx; ffptr = fStkLodRealAbs; } else if (prevfptr == fStkLodImag ){ #ifdef TESTFP stopmsg (0, "lodimag (*abs) -> (*lodimagabs)" ); #endif --cvtptrx; ffptr = fStkLodImagAbs; } } else if (ffptr == fStkSqr ){ if (prevfptr == fStkLod && fgf(cvtptrx-1) != fStkPush2 ){ #ifdef TESTFP stopmsg (0, "lod (*sqr) -> (*lodsqr)" ); #endif --cvtptrx; ffptr = fStkLodSqr; /* assume no need to save lastsqr */ if (lastsqrused) { #ifdef TESTFP stopmsg (0, "(*lodsqr) -> (*lodsqr2)" ); #endif ffptr = fStkLodSqr2; /* lastsqr is being used */ } } else if (prevfptr == fStkSto2 ){ #ifdef TESTFP stopmsg (0, "sto2 (*sqr) -> (*stosqr0)" ); #endif --cvtptrx; ffptr = fStkStoSqr0; /* assume no need to save lastsqr */ if (lastsqrused) { #ifdef TESTFP stopmsg (0, "(*stosqr0) -> (*stosqr)" ); #endif ffptr = fStkStoSqr; /* save lastsqr */ } } else { if (!lastsqrused) { #ifdef TESTFP stopmsg (0, "(*sqr) -> (*sqr0)" ); #endif ffptr = fStkSqr0; /* don't save lastsqr */ } } } else if (ffptr == fStkLTE && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*LTE) -> (*LodLTE)" ); #endif --cvtptrx; ffptr = fStkLodLTE; } else if (ffptr == fStkLT && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*LT) -> (*LodLT)" ); #endif --cvtptrx; ffptr = fStkLodLT; } else if (ffptr == fStkGT && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*GT) -> (*LodGT)" ); #endif --cvtptrx; ffptr = fStkLodGT; } else if (ffptr == fStkGTE && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*GTE) -> (*LodGTE)" ); #endif --cvtptrx; ffptr = fStkLodGTE; } else if (ffptr == fStkNE && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*NE) -> (*LodNE)" ); #endif --cvtptrx; ffptr = fStkLodNE; } else if (ffptr == fStkEQ && ( prevfptr == fStkLod || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ) ){ #ifdef TESTFP stopmsg(0, "Lod (*EQ) -> (*LodEQ)" ); #endif --cvtptrx; ffptr = fStkLodEQ; } SkipOptimizer: /* ----------- end of optimizer code ------------ */ fgf(cvtptrx++) = prevfptr = ffptr; prevstkcnt = stkcnt; if (Delta == 999 ){ stkcnt = 0; } else { stkcnt += Delta; } return; } int CvtStk() { /* convert the array of ptrs */ extern int fform_per_pixel(void); /* these fns are in parsera.asm */ extern int fFormula(void); extern int BadFormula(void); extern char FormName[]; void (far *ftst)(void); void (near *ntst)(void); #ifdef TESTFP if (debugflag == 322) { stopmsg(0, "Skipping optimizer." ); } #endif for (OpPtr = LodPtr = lastsqrused = 0; OpPtr < LastOp; OpPtr++) { ftst = f[OpPtr]; if (ftst == StkLod && Load[LodPtr++] == &LastSqr ){ lastsqrused = 1; /* lastsqr is being used in the formula */ } if ( ftst != StkLod /* these are the supported parser fns */ && ftst != StkClr && ftst != dStkAdd && ftst != dStkSub && ftst != dStkMul && ftst != dStkDiv && ftst != StkSto && ftst != dStkSqr && ftst != EndInit && ftst != dStkMod && ftst != dStkLTE && ftst != dStkSin && ftst != dStkCos && ftst != dStkSinh && ftst != dStkCosh && ftst != dStkCosXX && ftst != dStkTan && ftst != dStkTanh && ftst != dStkCoTan && ftst != dStkCoTanh && ftst != dStkLog && ftst != dStkExp && ftst != dStkPwr && ftst != dStkLT && ftst != dStkFlip && ftst != dStkReal && ftst != dStkImag && ftst != dStkConj && ftst != dStkNeg && ftst != dStkAbs && ftst != dStkRecip && ftst != StkIdent && ftst != dStkGT && ftst != dStkGTE && ftst != dStkNE && ftst != dStkEQ && ftst != dStkAND && ftst != dStkOR ){ stopmsg(0, "Fast failure, using old code" ); return 1; /* Use old code */ } } #ifdef TESTFP if (lastsqrused) { stopmsg(0, "LastSqr used" ); } else { stopmsg(0, "LastSqr not used" ); } #endif if (f[LastOp-1] != StkClr ){ /* some formulas don't clear at the end! */ #ifdef TESTFP stopmsg (0, "clr added at end" ); #endif f[LastOp++] = StkClr; } prevfptr = (void (near *)(void))0; prevstkcnt = 999; /* there was not previous stk cnt */ stkcnt = cvtptrx = 0; for (OpPtr = LodPtr = StoPtr = 0; OpPtr < LastOp; OpPtr++) { ftst = f[OpPtr]; if (ftst == StkLod ) { #ifdef TESTFP stopmsg(0, "lod,0,TWO_FREE,2" ); #endif CvtFptr(fStkLod, 0, TWO_FREE, 2 ); continue; } if (ftst == StkClr ) { if (OpPtr == LastOp - 1 ){ #ifdef TESTFP stopmsg(0, "clr2,0,MAX_STACK,999" ); #endif CvtFptr(fStkClr2, 0, MAX_STACK, 999 ); } else { #ifdef TESTFP stopmsg(0, "clr1,0,MAX_STACK,999" ); #endif CvtFptr(fStkClr1, 0, MAX_STACK, 999 ); } continue; } if (ftst == dStkAdd ) { #ifdef TESTFP stopmsg(0, "add,4,MAX_STACK,-2" ); #endif CvtFptr(fStkAdd, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkSub ) { #ifdef TESTFP stopmsg(0, "sub,4,MAX_STACK,-2" ); #endif CvtFptr(fStkSub, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkDiv ) { #ifdef TESTFP stopmsg(0, "div,4,TWO_FREE,-2" ); #endif CvtFptr(fStkDiv, 4, TWO_FREE, -2 ); continue; } if (ftst == dStkMul ) { #ifdef TESTFP stopmsg(0, "mul,4,TWO_FREE,-2" ); #endif CvtFptr(fStkMul, 4, TWO_FREE, -2 ); continue; } if (ftst == StkSto ) { #ifdef TESTFP stopmsg(0, "sto,2,MAX_STACK,0" ); #endif CvtFptr(fStkSto, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkSqr ) { #ifdef TESTFP stopmsg(0, "sqr,2,TWO_FREE,0" ); #endif CvtFptr(fStkSqr, 2, TWO_FREE, 0 ); continue; } if (ftst == EndInit) { #ifdef TESTFP stopmsg(0, "endinit,0,MAX_STACK,999" ); #endif CvtFptr(fStkEndInit, 0, MAX_STACK, 999 ); continue; } if (ftst == dStkMod ) { #ifdef TESTFP stopmsg(0, "mod,2,MAX_STACK,0" ); #endif CvtFptr(fStkMod, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkLTE ) { #ifdef TESTFP stopmsg(0, "LTE,4,MAX_STACK,-2" ); #endif CvtFptr(fStkLTE, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkSin ) { #ifdef TESTFP stopmsg(0, "sin,2,TWO_FREE,0" ); #endif CvtFptr(fStkSin, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkCos ) { #ifdef TESTFP stopmsg(0, "cos,2,TWO_FREE,0" ); #endif CvtFptr(fStkCos, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkSinh ) { #ifdef TESTFP stopmsg(0, "sinh,2,TWO_FREE,0" ); #endif CvtFptr(fStkSinh, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkCosh ) { #ifdef TESTFP stopmsg(0, "cosh,2,TWO_FREE,0" ); #endif CvtFptr(fStkCosh, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkCosXX ) { #ifdef TESTFP stopmsg(0, "cosxx,2,TWO_FREE,0" ); #endif CvtFptr(fStkCosXX, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkTan ) { #ifdef TESTFP stopmsg(0, "tan,2,TWO_FREE,0" ); #endif CvtFptr(fStkTan, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkTanh ) { #ifdef TESTFP stopmsg(0, "tanh,2,TWO_FREE,0" ); #endif CvtFptr(fStkTanh, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkCoTan ) { #ifdef TESTFP stopmsg(0, "cotan,2,TWO_FREE,0" ); #endif CvtFptr(fStkCoTan, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkCoTanh ) { #ifdef TESTFP stopmsg(0, "cotanh,2,TWO_FREE,0" ); #endif CvtFptr(fStkCoTanh, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkExp ) { #ifdef TESTFP stopmsg(0, "exp,2,TWO_FREE,0" ); #endif CvtFptr(fStkExp, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkLog ) { #ifdef TESTFP stopmsg(0, "log,2,TWO_FREE,0" ); #endif CvtFptr(fStkLog, 2, TWO_FREE, 0 ); continue; } if (ftst == dStkPwr ) { #ifdef TESTFP stopmsg(0, "pwr,4,TWO_FREE,-2" ); #endif CvtFptr(fStkPwr, 4, TWO_FREE, -2 ); continue; } if (ftst == dStkLT ) { #ifdef TESTFP stopmsg(0, "LT,4,MAX_STACK,-2" ); #endif CvtFptr(fStkLT, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkFlip ) { #ifdef TESTFP stopmsg(0, "flip,2,MAX_STACK,0" ); #endif CvtFptr(fStkFlip, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkReal ) { #ifdef TESTFP stopmsg(0, "real,2,MAX_STACK,0" ); #endif CvtFptr(fStkReal, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkImag ) { #ifdef TESTFP stopmsg(0, "imag,2,MAX_STACK,0" ); #endif CvtFptr(fStkImag, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkConj ) { #ifdef TESTFP stopmsg(0, "conj,2,MAX_STACK,0" ); #endif CvtFptr(fStkConj, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkNeg ) { #ifdef TESTFP stopmsg(0, "neg,2,MAX_STACK,0" ); #endif CvtFptr(fStkNeg, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkAbs ) { #ifdef TESTFP stopmsg(0, "abs,2,MAX_STACK,0" ); #endif CvtFptr(fStkAbs, 2, MAX_STACK, 0 ); continue; } if (ftst == dStkRecip ) { #ifdef TESTFP stopmsg(0, "recip,2,TWO_FREE,0" ); #endif CvtFptr(fStkRecip, 2, TWO_FREE, 0 ); continue; } if (ftst == StkIdent ) { #ifdef TESTFP stopmsg(0, "ident skipped" ); #endif /* don't bother converting this one */ continue; } if (ftst == dStkGT ) { #ifdef TESTFP stopmsg(0, "GT,4,MAX_STACK,-2" ); #endif CvtFptr(fStkGT, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkGTE ) { #ifdef TESTFP stopmsg(0, "GTE,4,MAX_STACK,-2" ); #endif CvtFptr(fStkGTE, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkEQ ) { #ifdef TESTFP stopmsg(0, "EQ,4,MAX_STACK,-2" ); #endif CvtFptr(fStkEQ, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkNE ) { #ifdef TESTFP stopmsg(0, "NE,4,MAX_STACK,-2" ); #endif CvtFptr(fStkNE, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkOR ) { #ifdef TESTFP stopmsg(0, "OR,4,MAX_STACK,-2" ); #endif CvtFptr(fStkOR, 4, MAX_STACK, -2 ); continue; } if (ftst == dStkAND ) { #ifdef TESTFP stopmsg(0, "AND,4,MAX_STACK,-2" ); #endif CvtFptr(fStkAND, 4, MAX_STACK, -2 ); continue; } stopmsg(0, "Fast failure, using old code." ); return 1; /* this should never happen but is not fatal now */ } if (debugflag == 322 ){ /* skip these optimizations too */ goto skipfinalopt; } /* ---------------------------------- final optimizations ---- */ ntst = fgf(cvtptrx-2 ); /* cvtptrx -> one past last operator (clr2) */ if (ntst == fStkLT ){ #ifdef TESTFP stopmsg (0, "LT Clr2 -> LT2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLT2; } else if (ntst == fStkLodLT ){ #ifdef TESTFP stopmsg (0, "LodLT Clr2 -> LodLT2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLodLT2; } else if (ntst == fStkLTE ){ #ifdef TESTFP stopmsg (0, "LTE Clr2 -> LTE2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLTE2; } else if (ntst == fStkLodLTE ){ #ifdef TESTFP stopmsg (0, "LodLTE Clr2 -> LodLTE2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLodLTE2; } else if (ntst == fStkGT ){ #ifdef TESTFP stopmsg (0, "GT Clr2 -> GT2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkGT2; } else if (ntst == fStkLodGT ){ #ifdef TESTFP stopmsg (0, "LodGT Clr2 -> LodGT2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLodGT2; } else if (ntst == fStkLodGTE ){ #ifdef TESTFP stopmsg (0, "LodGTE Clr2 -> LodGTE2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLodGTE2; } else if (fgf(cvtptrx-2 ) == fStkAND ){ #ifdef TESTFP stopmsg (0, "AND Clr2 -> ANDClr2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkANDClr2; ntst = fgf(cvtptrx-2); if (ntst == fStkLodLTE ){ #ifdef TESTFP stopmsg (0, "LodLTE ANDClr2 -> LodLTEAnd2" ); #endif --cvtptrx; fgf(cvtptrx-1) = fStkLodLTEAnd2; } } skipfinalopt: /* ---------------- end of final optimizations ----- */ LastOp = cvtptrx; /* save the new operator count */ LastSqr.d.y = 0.0; /* do this once per image */ /* now change the pointers */ if (FormName[0] != 0 ){ /* but only if parse succeeded */ curfractalspecific->per_pixel = fform_per_pixel; curfractalspecific->orbitcalc = fFormula; } else { curfractalspecific->per_pixel = BadFormula; curfractalspecific->orbitcalc = BadFormula; } Img_Setup(); /* call assembler setup code */ return 1; } #endif /* XFRACT */