File: common\parserfp.c

    1 /* PARSERFP.C  -- Part of FRACTINT fractal drawer.  */
    2 
    3 /*   By Chuck Ebbert  CompuServe [76306,1226]  */
    4 /*                     internet: 76306.1226@compuserve.com  */
    5 
    6 /* Fast floating-point parser code.  The functions beginning with  */
    7 /*    "fStk" are in PARSERA.ASM.  PARSER.C calls this code after  */
    8 /*    it has parsed the formula.  */
    9 
   10 /*   Converts the function pointers/load pointers/store pointers  */
   11 /*       built by parsestr() into an optimized array of function  */
   12 /*       pointer/operand pointer pairs.  */
   13 
   14 /*   As of 31 Dec 93, also generates executable code in memory.  */
   15 /*       Define the varible COMPILER to generate executable code.  */
   16 /*       COMPILER must also be defined in PARSERA.ASM. */
   17 
   18 
   19 /* Revision history:  */
   20 
   21 /* 15 Mar 1997 TIW  */
   22 /*    Fixed if/else bug, replaced stopmsg with pstopmsg */
   23 
   24 /* 09 Mar 1997 TIW/GGM  */
   25 /*    Added support for if/else */
   26 
   27 /* 30 Jun 1996 TIW  */
   28 /*    Removed function names if TESTFP not defined to save memory      */
   29 /*    Function fStkFloor added to support new 'floor' function         */
   30 /*    Function fStkCeil  added to support new 'ceil'  function         */
   31 /*    Function fStkTrunc added to support new 'trunc' function         */
   32 /*    Function fStkRound added to support new 'round' function         */
   33 
   34 /* 15 Feb 1995 CAE  */
   35 /*    added safety tests to pointer conversion code  */
   36 /*    added the capability for functions to require 4 free regs  */
   37 
   38 /* 8 Feb 1995 CAE  */
   39 /*    Comments changed.  */
   40 
   41 /* 8 Jan 1995 JCO  */
   42 /*    Function fStkASin added to support new 'asin' function in v19    */
   43 /*    Function fStkASinh added to support new 'asinh' function in v19  */
   44 /*    Function fStkACos added to support new 'acos' function in v19    */
   45 /*    Function fStkACosh added to support new 'acosh' function in v19  */
   46 /*    Function fStkATan added to support new 'atan' function in v19    */
   47 /*    Function fStkATanh added to support new 'atanh' function in v19  */
   48 /*    Function fStkSqrt added to support new 'sqrt' function in v19    */
   49 /*    Function fStkCAbs added to support new 'cabs' function in v19    */
   50 /*    Added support for a third parameter p3    */
   51 
   52 /* 31 Dec 1993 CAE  */
   53 /*    Fixed optimizer bug discovered while testing compiler.  */
   54 
   55 /* 29 Dec 1993 CAE  */
   56 /*    Added compiler.  */
   57 
   58 /* 04 Dec 1993 CAE  */
   59 /*    Added optimizations for LodImagAdd/Sub/Mul.  */
   60 
   61 /* 06 Nov 1993 CAE  */
   62 /*    Added optimizer support for LodRealPwr and ORClr2 functions.  */
   63 /*    If stack top is a real, a simpler sqr() or mod() fn will be  */
   64 /*          called (fStkSqr3() was added.)  */
   65 /*    The identities x^0=1, x^1=x, and x^-1=recip(x) are now used by the  */
   66 /*          optimizer.  (fStkOne() was added for this.)  */
   67 
   68 /* 31 Oct 1993 CAE  */
   69 /*    Optimizer converts '2*x' and 'x*2' to 'x+x'. */
   70 /*        "     recognizes LastSqr as a real if not stored to.  */
   71 
   72 /* 9 Oct 1993 CAE  */
   73 /*    Functions are now converted via table search.                    */
   74 /*    Added "real" stack count variable and debug msgs for stack size. */
   75 /*    Added optimizer extension for commutative multiply.              */
   76 /*    P1, P2 will be treated as consts if they are never stored to.    */
   77 /*    Function fStkStoClr2 now emitted for sto,clr with 2 on stack.    */
   78 /*       "     fStkZero added to support new 'zero' function in v18    */
   79 /*    Added optimization for x^2 -> sqr(x).                            */
   80 /*    Changed "stopmsg" to "DBUGMSG" and made all macros upper case.   */
   81 /*       (debugflag=324 now needed for debug msgs to print.)           */
   82 
   83 /* 12 July 1993 (for v18.1) by CAE to fix optimizer bug  */
   84 
   85 /* 22 MAR 1993 (for Fractint v18.0)  */
   86 
   87 /* ******************************************************************* */
   88 /*                                                                     */
   89 /*  (c) Copyright 1992-1995 Chuck Ebbert.  All rights reserved.        */
   90 /*                                                                     */
   91 /*    This code may be freely distributed and used in non-commercial   */
   92 /*    programs provided the author is credited either during program   */
   93 /*    execution or in the documentation, and this copyright notice     */
   94 /*    is left intact.  Sale of this code, or its use in any commercial */
   95 /*    product requires permission from the author.  Nominal            */
   96 /*    distribution and handling fees may be charged by shareware and   */
   97 /*    freeware distributors.                                           */
   98 /*                                                                     */
   99 /* ******************************************************************* */
  100 
  101 /* Uncomment the next line to enable debug messages.  */
  102 /* #define TESTFP 1 */
  103 
  104 /* Use startup parameter "debugflag=324" to show debug messages after  */
  105 /*    compiling with above #define uncommented.  */
  106 
  107 #include <string.h>
  108 #include <ctype.h>
  109 #include <time.h>
  110 
  111   /* see Fractint.c for a description of the "include"  hierarchy */
  112 #include "port.h"
  113 #include "prototyp.h"
  114 
  115 /* global data  */
  116 struct fls far *pfls = (struct fls far *)0;
  117 
  118 #ifndef XFRACT /* --  */
  119 
  120 /* not moved to PROTOTYPE.H because these only communicate within
  121    PARSER.C and other parser modules */
  122 
  123 extern union Arg *Arg1, *Arg2;
  124 extern double _1_, _2_;
  125 extern union Arg s[20], far * far *Store, far * far *Load;
  126 extern int StoPtr, LodPtr, OpPtr;
  127 extern unsigned int vsp, LastOp;
  128 extern struct ConstArg far *v;
  129 extern int InitLodPtr, InitStoPtr, InitOpPtr, LastInitOp;
  130 extern void (far * far *f)(void);
  131 extern JUMP_CONTROL_ST far *jump_control;
  132 extern int uses_jump, jump_index;
  133 
  134 typedef void OLD_FN(void);  /* old C functions  */
  135 
  136 OLD_FN  StkLod, StkClr, StkSto, EndInit, StkJumpLabel;
  137 OLD_FN  dStkAdd, dStkSub, dStkMul, dStkDiv;
  138 OLD_FN  dStkSqr, dStkMod;
  139 OLD_FN  dStkSin, dStkCos, dStkSinh, dStkCosh, dStkCosXX;
  140 OLD_FN  dStkTan, dStkTanh, dStkCoTan, dStkCoTanh;
  141 OLD_FN  dStkLog, dStkExp, dStkPwr;
  142 OLD_FN  dStkLT, dStkLTE;
  143 OLD_FN  dStkFlip, dStkReal, dStkImag;
  144 OLD_FN  dStkConj, dStkNeg, dStkAbs;
  145 OLD_FN  dStkRecip, StkIdent;
  146 OLD_FN  dStkGT, dStkGTE, dStkNE, dStkEQ;
  147 OLD_FN  dStkAND, dStkOR;
  148 OLD_FN  dStkZero;
  149 OLD_FN  dStkSqrt;
  150 OLD_FN  dStkASin, dStkACos, dStkASinh, dStkACosh;
  151 OLD_FN  dStkATanh, dStkATan;
  152 OLD_FN  dStkCAbs;
  153 OLD_FN  dStkFloor;
  154 OLD_FN  dStkCeil;
  155 OLD_FN  dStkTrunc;
  156 OLD_FN  dStkRound;
  157 OLD_FN  StkJump, dStkJumpOnTrue, dStkJumpOnFalse;
  158 OLD_FN  dStkOne;
  159 
  160 typedef void (near NEW_FN)(void);  /* new 387-only ASM functions  */
  161 
  162 NEW_FN  fStkPull2;  /* pull up fpu stack from 2 to 4  */
  163 NEW_FN  fStkPush2;  /* push down fpu stack from 8 to 6  */
  164 NEW_FN  fStkPush2a;  /* push down fpu stack from 6 to 4  */
  165 NEW_FN  fStkPush4;  /* push down fpu stack from 8 to 4  */
  166 NEW_FN  fStkLodDup;  /* lod, dup  */
  167 NEW_FN  fStkLodSqr;  /* lod, sqr, dont save magnitude(i.e. lastsqr)  */
  168 NEW_FN  fStkLodSqr2;  /* lod, sqr, save lastsqr  */
  169 NEW_FN  fStkStoDup;  /* store, duplicate  */
  170 NEW_FN  fStkStoSqr;  /* store, sqr, save lastsqr  */
  171 NEW_FN  fStkStoSqr0;  /* store, sqr, dont save lastsqr  */
  172 NEW_FN  fStkLodDbl;  /* load, double  */
  173 NEW_FN  fStkStoDbl;  /* store, double  */
  174 NEW_FN  fStkReal2;  /* fast ver. of real  */
  175 NEW_FN  fStkSqr;  /* sqr, save magnitude in lastsqr  */
  176 NEW_FN  fStkSqr0;  /* sqr, no save magnitude  */
  177 NEW_FN  fStkClr1;  /* clear fpu  */
  178 NEW_FN  fStkClr2;  /* test stack top, clear fpu  */
  179 NEW_FN  fStkStoClr1;  /* store, clr1  */
  180 NEW_FN  fStkAdd, fStkSub;
  181 NEW_FN  fStkSto, fStkSto2;  /* fast ver. of sto  */
  182 NEW_FN  fStkLod, fStkEndInit;
  183 NEW_FN  fStkMod, fStkMod2;  /* faster mod  */
  184 NEW_FN  fStkLodMod2, fStkStoMod2;
  185 NEW_FN  fStkLTE, fStkLodLTEMul, fStkLTE2, fStkLodLTE;
  186 NEW_FN  fStkLodLTE2, fStkLodLTEAnd2;
  187 NEW_FN  fStkLT, fStkLodLTMul, fStkLT2, fStkLodLT;
  188 NEW_FN  fStkLodLT2;
  189 NEW_FN  fStkGTE, fStkLodGTE, fStkLodGTE2;
  190 NEW_FN  fStkGT, fStkGT2, fStkLodGT, fStkLodGT2;
  191 NEW_FN  fStkEQ, fStkLodEQ, fStkNE, fStkLodNE;
  192 NEW_FN  fStkAND, fStkANDClr2, fStkOR, fStkORClr2;
  193 NEW_FN  fStkSin, fStkSinh, fStkCos, fStkCosh, fStkCosXX;
  194 NEW_FN  fStkTan, fStkTanh, fStkCoTan, fStkCoTanh;
  195 NEW_FN  fStkLog, fStkExp, fStkPwr;
  196 NEW_FN  fStkMul, fStkDiv;
  197 NEW_FN  fStkFlip, fStkReal, fStkImag, fStkRealFlip, fStkImagFlip;
  198 NEW_FN  fStkConj, fStkNeg, fStkAbs, fStkRecip;
  199 NEW_FN  fStkLodReal, fStkLodRealC, fStkLodImag;
  200 NEW_FN  fStkLodRealFlip, fStkLodRealAbs;
  201 NEW_FN  fStkLodRealMul, fStkLodRealAdd, fStkLodRealSub, fStkLodRealPwr;
  202 NEW_FN  fStkLodImagMul, fStkLodImagAdd, fStkLodImagSub;  /* CAE 4Dec93  */
  203 NEW_FN  fStkLodImagFlip, fStkLodImagAbs;
  204 NEW_FN  fStkLodConj;
  205 NEW_FN  fStkLodAdd, fStkLodSub, fStkLodSubMod, fStkLodMul;
  206 NEW_FN  fStkPLodAdd, fStkPLodSub;  /* push-lod-add/sub  */
  207 NEW_FN  fStkIdent;
  208 NEW_FN  fStkStoClr2;  /* store, clear stack by popping  */
  209 NEW_FN  fStkZero;  /* to support new parser fn.  */
  210 NEW_FN  fStkDbl;  /* double the stack top  CAE 31OCT93  */
  211 NEW_FN  fStkOne, fStkSqr3;  /* sqr3 is sqr/mag of a real  CAE 09NOV93  */
  212 NEW_FN  fStkSqrt;
  213 NEW_FN  fStkASin, fStkACos, fStkASinh, fStkACosh;
  214 NEW_FN  fStkATanh, fStkATan;
  215 NEW_FN  fStkCAbs;
  216 NEW_FN  fStkFloor, fStkCeil, fStkTrunc, fStkRound; /* rounding functions */
  217 NEW_FN  fStkJump, fStkJumpOnTrue, fStkJumpOnFalse, fStkJumpLabel; /* flow */
  218 NEW_FN  fStkOne;   /* to support new parser fn.  */
  219 
  220 /* check to see if a const is being loaded  */
  221 /* the really awful hack below gets the first char of the name  */
  222 /*    of the variable being accessed  */
  223 /* if first char not alpha, or const p1, p2, or p3 are being accessed  */
  224 /*    then this is a const.  */
  225 #define IS_CONST(x) \
  226       (!isalpha(**(((char * far *)x ) - 2 ) ) \
  227       || (x==&PARM1 && p1const ) \
  228       || (x==&PARM2 && p2const ) \
  229       || (x==&PARM3 && p3const ) \
  230       || (x==&PARM4 && p4const ) \
  231       || (x==&PARM5 && p5const ) )
  232 
  233 /* is stack top a real?  */
  234 #define STACK_TOP_IS_REAL \
  235       ( prevfptr == fStkReal || prevfptr == fStkReal2 \
  236       || prevfptr == fStkLodReal || prevfptr == fStkLodRealC \
  237       || prevfptr == fStkLodRealAbs \
  238       || prevfptr == fStkImag || prevfptr == fStkLodImag )
  239 
  240 /* remove push operator from stack top  */
  241 #define REMOVE_PUSH --cvtptrx, stkcnt+=2
  242 
  243 #define CLEAR_STK 127
  244 #define FNPTR(x) pfls[(x)].function  /* function pointer */
  245 #define OPPTR(x) pfls[(x)].operand   /* operand pointer */
  246 #define NO_OPERAND (union Arg near *)0
  247 #define NO_FUNCTION (void (near *)(void))0
  248 #define LASTSQR v[4].a
  249 #define PARM1 v[1].a
  250 #define PARM2 v[2].a
  251 #define PARM3 v[8].a
  252 #define PARM4 v[17].a
  253 #define PARM5 v[18].a
  254 #define MAX_STACK 8   /* max # of stack register avail  */
  255 
  256 #ifdef TESTFP
257 int pstopmsg(int x,char far *msg) 258 { 259 static FILE *fp = NULL; 260 if(fp == NULL) 261 fp = fopen("fpdebug.txt","w"); 262 if(fp) 263 { 264 #ifndef XFRACT 265 fprintf(fp,"%Fs\n",msg); 266 #else 267 fprintf(fp,"%s\n",msg); 268 #endif 269 fflush(fp); 270 } 271 return(x); /* just to quiet warnings */ 272 } 273 274 #define stopmsg pstopmsg 275 276 #define DBUGMSG(x,y) if (debugflag==324 || debugflag==322 ) stopmsg((x), (y)) 277 #define DBUGMSG1(x,y,p) \ 278 if (debugflag==324 || debugflag==322 ){ \ 279 sprintf(cDbgMsg, (y), (p) ); \ 280 stopmsg((x), cDbgMsg ); \ 281 } 282 #define DBUGMSG2(x,y,p,q) \ 283 if (debugflag==324 || debugflag==322 ){ \ 284 sprintf(cDbgMsg, (y), (p), (q) ); \ 285 stopmsg((x), cDbgMsg ); \ 286 } 287 #define DBUGMSG3(x,y,p,q,r) \ 288 if (debugflag==324 || debugflag==322 ){ \ 289 sprintf(cDbgMsg, (y), (p), (q), (r) ); \ 290 stopmsg((x), cDbgMsg ); \ 291 } 292 #define DBUGMSG4(x,y,p,q,r,s) \ 293 if (debugflag==324 || debugflag==322 ){ \ 294 sprintf(cDbgMsg, (y), (p), (q), (r), (s) ); \ 295 stopmsg((x), cDbgMsg ); \ 296 } 297 #define FNAME(a,b,c,d,e,f) a,b,c,d,e,f /* use the function name string */
298 #else 299 300 #define DBUGMSG(x,y) 301 #define DBUGMSG1(x,y,p) 302 #define DBUGMSG2(x,y,p,q) 303 #define DBUGMSG3(x,y,p,q,r) 304 #define DBUGMSG4(x,y,p,q,r,s) 305 #define FNAME(a,b,c,d,e,f) b,c,d,e,f /* don't use the function name string */ 306 #endif /* TESTFP */ 307 308 #define FN_LOD 0 309 #define FN_CLR 1 310 #define FN_ADD 2 311 #define FN_SUB 3 312 #define FN_MUL 4 313 #define FN_DIV 5 314 #define FN_STO 6 315 #define FN_SQR 7 316 #define FN_ENDINIT 8 317 #define FN_MOD 9 318 #define FN_LTE 10 319 #define FN_SIN 11 320 #define FN_COS 12 321 #define FN_SINH 13 322 #define FN_COSH 14 323 #define FN_COSXX 15 324 #define FN_TAN 16 325 #define FN_TANH 17 326 #define FN_COTAN 18 327 #define FN_COTANH 19 328 #define FN_LOG 20 329 #define FN_EXP 21 330 #define FN_PWR 22 331 #define FN_LT 23 332 #define FN_FLIP 24 333 #define FN_REAL 25 334 #define FN_IMAG 26 335 #define FN_CONJ 27 336 #define FN_NEG 28 337 #define FN_ABS 29 338 #define FN_RECIP 30 339 #define FN_IDENT 31 340 #define FN_GT 32 341 #define FN_GTE 33 342 #define FN_NE 34 343 #define FN_EQ 35 344 #define FN_AND 36 345 #define FN_OR 37 346 #define FN_ZERO 38 347 #define FN_SQRT 39 348 #define FN_ASIN 40 349 #define FN_ACOS 41 350 #define FN_ASINH 42 351 #define FN_ACOSH 43 352 #define FN_ATANH 44 353 #define FN_ATAN 45 354 #define FN_CABS 46 355 #define FN_FLOOR 47 356 #define FN_CEIL 48 357 #define FN_TRUNC 49 358 #define FN_ROUND 50 359 #define FN_JUMP 51 360 #define FN_JUMP_ON_TRUE 52 361 #define FN_JUMP_ON_FALSE 53 362 #define FN_JUMP_LABEL 54 363 #define FN_ONE 55 364 365 366 /* number of "old" functions in the table. */ 367 /* these are the ones that the parser outputs */ 368 369 #define LAST_OLD_FN FN_ONE 370 #define NUM_OLD_FNS LAST_OLD_FN + 1 371 372 /* total number of functions in the table. */ 373 374 #define LAST_FN FN_ONE 375 #define NUM_FNS LAST_FN + 1 376 377 static unsigned char 378 realstkcnt, /* how many scalars are really on stack */ 379 stkcnt, /* # scalars on FPU stack */ 380 lastsqrused, /* was lastsqr loaded in the formula? */ 381 lastsqrreal, /* was lastsqr stored explicitly in the formula? */ 382 p1const, /* is p1 a constant? */ 383 p2const, /* ...and p2? */ 384 p3const, /* ...and p3? */ 385 p4const, /* ...and p4? */ 386 p5const; /* ...and p5? */ 387 388 static unsigned int 389 cvtptrx; /* subscript of next free entry in pfls */ 390 391 static void (near *prevfptr )(void); /* previous function pointer */ 392 393 /* the entries in this table must be in the same order as */ 394 /* the #defines above */ 395 /* this table is searched sequentially */ 396 struct fn_entry { 397 398 #ifdef TESTFP
399 char far *fname; /* function name */
400 #endif 401 void (far *infn)(void); /* 'old' function pointer */ 402 /* (infn points to an operator fn in parser.c) */ 403 404 void (near *outfn)(void); /* pointer to equiv. fast fn. */ 405 406 char min_regs; /* min regs needed on stack by this fn. */ 407 /* (legal values are 0, 2, 4) */ 408 409 char free_regs; /* free regs required by this fn */ 410 /* (legal values are 0, 2, 4) */ 411 412 char delta; /* net change to # of values on the fp stack */ 413 /* (legal values are -2, 0, +2) */ 414 415 } static far afe[NUM_OLD_FNS] = { /* array of function entries */ 416 417 {FNAME("Lod", StkLod, fStkLod, 0, 2, +2) }, /* 0 */ 418 {FNAME("Clr", StkClr, fStkClr1, 0, 0, CLEAR_STK) }, /* 1 */ 419 {FNAME("+", dStkAdd, fStkAdd, 4, 0, -2) }, /* 2 */ 420 {FNAME("-", dStkSub, fStkSub, 4, 0, -2) }, /* 3 */ 421 {FNAME("*", dStkMul, fStkMul, 4, 2, -2) }, /* 4 */ 422 {FNAME("/", dStkDiv, fStkDiv, 4, 2, -2) }, /* 5 */ 423 {FNAME("Sto", StkSto, fStkSto, 2, 0, 0) }, /* 6 */ 424 {FNAME("Sqr", dStkSqr, fStkSqr, 2, 2, 0) }, /* 7 */ 425 {FNAME(":", EndInit, fStkEndInit,0, 0, CLEAR_STK) }, /* 8 */ 426 {FNAME("Mod", dStkMod, fStkMod, 2, 0, 0) }, /* 9 */ 427 {FNAME("<=", dStkLTE, fStkLTE, 4, 0, -2) }, /* 10 */ 428 {FNAME("Sin", dStkSin, fStkSin, 2, 2, 0) }, /* 11 */ 429 {FNAME("Cos", dStkCos, fStkCos, 2, 2, 0) }, /* 12 */ 430 {FNAME("Sinh", dStkSinh, fStkSinh, 2, 2, 0) }, /* 13 */ 431 {FNAME("Cosh", dStkCosh, fStkCosh, 2, 2, 0) }, /* 14 */ 432 {FNAME("Cosxx", dStkCosXX, fStkCosXX, 2, 2, 0) }, /* 15 */ 433 {FNAME("Tan", dStkTan, fStkTan, 2, 2, 0) }, /* 16 */ 434 {FNAME("Tanh", dStkTanh, fStkTanh, 2, 2, 0) }, /* 17 */ 435 {FNAME("CoTan", dStkCoTan, fStkCoTan, 2, 2, 0) }, /* 18 */ 436 {FNAME("CoTanh", dStkCoTanh, fStkCoTanh, 2, 2, 0) }, /* 19 */ 437 {FNAME("Log", dStkLog, fStkLog, 2, 2, 0) }, /* 20 */ 438 {FNAME("Exp", dStkExp, fStkExp, 2, 2, 0) }, /* 21 */ 439 {FNAME("^", dStkPwr, fStkPwr, 4, 2, -2) }, /* 22 */ 440 {FNAME("<", dStkLT, fStkLT, 4, 0, -2) }, /* 23 */ 441 {FNAME("Flip", dStkFlip, fStkFlip, 2, 0, 0) }, /* 24 */ 442 {FNAME("Real", dStkReal, fStkReal, 2, 0, 0) }, /* 25 */ 443 {FNAME("Imag", dStkImag, fStkImag, 2, 0, 0) }, /* 26 */ 444 {FNAME("Conj", dStkConj, fStkConj, 2, 0, 0) }, /* 27 */ 445 {FNAME("Neg", dStkNeg, fStkNeg, 2, 0, 0) }, /* 28 */ 446 {FNAME("Abs", dStkAbs, fStkAbs, 2, 0, 0) }, /* 29 */ 447 {FNAME("Recip", dStkRecip, fStkRecip, 2, 2, 0) }, /* 30 */ 448 {FNAME("Ident", StkIdent, fStkIdent, 2, 0, 0) }, /* 31 */ 449 {FNAME(">", dStkGT, fStkGT, 4, 0, -2) }, /* 32 */ 450 {FNAME(">=", dStkGTE, fStkGTE, 4, 0, -2) }, /* 33 */ 451 {FNAME("!=", dStkNE, fStkNE, 4, 0, -2) }, /* 34 */ 452 {FNAME("==", dStkEQ, fStkEQ, 4, 0, -2) }, /* 35 */ 453 {FNAME("&&", dStkAND, fStkAND, 4, 0, -2) }, /* 36 */ 454 {FNAME("||", dStkOR, fStkOR, 4, 0, -2) }, /* 37 */ 455 {FNAME("Zero", dStkZero, fStkZero, 2, 0, 0) }, /* 38 */ 456 {FNAME("Sqrt", dStkSqrt, fStkSqrt, 2, 2, 0) }, /* 39 */ 457 {FNAME("ASin", dStkASin, fStkASin, 2, 4, 0) }, /* 40 */ 458 {FNAME("ACos", dStkACos, fStkACos, 2, 4, 0) }, /* 41 */ 459 {FNAME("ASinh", dStkASinh, fStkASinh, 2, 4, 0) }, /* 42 */ 460 {FNAME("ACosh", dStkACosh, fStkACosh, 2, 4, 0) }, /* 43 */ 461 {FNAME("ATanh", dStkATanh, fStkATanh, 2, 4, 0) }, /* 44 */ 462 {FNAME("ATan", dStkATan, fStkATan, 2, 4, 0) }, /* 45 */ 463 {FNAME("CAbs", dStkCAbs, fStkCAbs, 2, 0, 0) }, /* 46 */ 464 {FNAME("Floor", dStkFloor, fStkFloor, 2, 0, 0) }, /* 47 */ 465 {FNAME("Ceil", dStkCeil, fStkCeil, 2, 0, 0) }, /* 48 */ 466 {FNAME("Trunc", dStkTrunc, fStkTrunc, 2, 0, 0) }, /* 49 */ 467 {FNAME("Round", dStkRound, fStkRound, 2, 0, 0) }, /* 50 */ 468 {FNAME("Jump", StkJump, fStkJump, 0, 0, 0)},/* 51 */ 469 {FNAME("JumpOnTrue", dStkJumpOnTrue, fStkJumpOnTrue, 2, 0, 0)},/* 52 */ 470 {FNAME("JumpOnFalse", dStkJumpOnFalse, fStkJumpOnFalse,2, 0, 0)},/* 53 */ 471 {FNAME("JumpLabel", StkJumpLabel, fStkJumpLabel, 0, 0, 0)},/* 54 */ 472 {FNAME("One", dStkOne, fStkOne, 2, 0, 0) } /* 55 */ 473 }; 474 475 #ifdef TESTFP
476 static char cDbgMsg[255];
477 #endif /* TESTFP */ 478 479 static int CvtFptr(void (near * ffptr)(void), int MinStk, int FreeStk, 480 int Delta ) 481 { 482 union Arg near *otemp; /* temp operand ptr */ 483 union Arg far *testload; 484 #ifdef TESTFP
485 int prevstkcnt;
486 #endif 487 double dTemp; 488 489 int Max_On_Stack = MAX_STACK - FreeStk; /* max regs allowed on stack */ 490 int Num_To_Push; /* number of regs to push */ 491 492 /* first do some sanity checks */ /* CAE 15Feb95 */ 493 if ( (Delta != -2 && Delta != 0 && Delta != 2 && Delta != CLEAR_STK) 494 || (FreeStk != 0 && FreeStk != 2 && FreeStk != 4) 495 || (MinStk != 0 && MinStk != 2 && MinStk != 4) ){ 496 awful_error: 497 stopmsg (0,"FATAL INTERNAL PARSER ERROR!"); 498 return 0; /* put out dire message and revert to old parser */ 499 } 500 501 /* this if statement inserts a stack push or pull into the token array */ 502 /* it would be much better to do this *after* optimization */ 503 if ((int)stkcnt < MinStk ) { /* not enough operands on fpu stack */ 504 DBUGMSG2(0, "Inserted pull. Stack: %2d --> %2d", stkcnt, stkcnt+2 ); 505 OPPTR(cvtptrx) = NO_OPERAND; 506 FNPTR(cvtptrx++) = fStkPull2; /* so adjust the stack, pull operand */ 507 stkcnt += 2; 508 } 509 else if ((int)stkcnt > Max_On_Stack ) { /* too many operands */ 510 511 Num_To_Push = stkcnt - Max_On_Stack; 512 if (Num_To_Push == 2 ){ 513 if (stkcnt == MAX_STACK ){ 514 /* push stack down from max to max-2 */ 515 FNPTR(cvtptrx) = fStkPush2; 516 } 517 else if (stkcnt == MAX_STACK - 2 ){ 518 /* push stack down from max-2 to max-4 */ 519 FNPTR(cvtptrx) = fStkPush2a; 520 } 521 else { 522 goto awful_error; 523 } 524 DBUGMSG2(0, 525 "Inserted push. Stack: %2d --> %2d", stkcnt, stkcnt-2 ); 526 OPPTR(cvtptrx++) = NO_OPERAND; 527 stkcnt -= 2; 528 } 529 else if (Num_To_Push == 4 ){ 530 /* push down from max to max-4 */ 531 FNPTR(cvtptrx) = fStkPush4; 532 DBUGMSG2(0, 533 "Inserted push. Stack: %2d --> %2d", stkcnt, stkcnt-4 ); 534 OPPTR(cvtptrx++) = NO_OPERAND; 535 stkcnt -= 4; 536 } 537 else { 538 goto awful_error; 539 } 540 } 541 542 /* set the operand pointer here for store function */ 543 if (ffptr == fStkSto ){ 544 OPPTR(cvtptrx) = (void near *)FP_OFF((Store[StoPtr++])); 545 } 546 else if (ffptr == fStkLod && debugflag == 322 ){ 547 /* when disabling optimizer, set load pointer here */ 548 OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++])); 549 } 550 else { /* the optimizer will set the pointer for load fn. */ 551 OPPTR(cvtptrx) = NO_OPERAND; 552 } 553 554 if (debugflag == 322 ){ 555 goto SkipOptimizer; 556 } /* -------------------------- begin optimizer --------------------- */ 557 558 /* This optimizer grew from a simple if statement into a monster. */ 559 560 /* Most of the bugs in the optimizer have been in the code that */ 561 /* juggles the overflow stack. */ 562 563 /* For the following: */ 564 /* * == cvtptrx points to this */ 565 /* () == this is about to be added to the array */ 566 567 /* ******************************************************************** */ 568 if (ffptr == fStkLod) { /* about to add Lod to the array */ 569 570 if (prevfptr == fStkLod && Load[LodPtr-1] == Load[LodPtr] ) { 571 /* previous non-adjust operator was Lod of same operand */ 572 /* ? lodx ? (*lodx) */ 573 if (FNPTR(--cvtptrx) == fStkPush2 ){ /* prev fn was push */ 574 /* ? lod *push (lod) */ 575 --cvtptrx; /* found *lod push (lod) */ 576 if (FNPTR(cvtptrx-1) == fStkPush2){ /* always more ops here */ 577 DBUGMSG(0, "push *lod push (lod) -> push4 (*loddup)" ); 578 FNPTR(cvtptrx-1) = fStkPush4; 579 } 580 else { /* prev op not push */ 581 DBUGMSG(0, "op *lod push (lod) -> op pusha(p=0) (*loddup)" ); 582 OPPTR(cvtptrx) = NO_OPERAND; /* use 'alternate' push fn. */ 583 FNPTR(cvtptrx++) = fStkPush2a; /* push w/2 free on stack */ 584 /* operand ptr will be set below */ 585 } 586 } 587 else { /* never push *lod (lod) so must be */ 588 DBUGMSG(0, "op *lod (lod) -> op (*loddup)" ); 589 } 590 ffptr = fStkLodDup; 591 } 592 else if (prevfptr == fStkSto2 593 && Store[StoPtr-1] == Load[LodPtr] ){ 594 /* store, load of same value */ 595 /* only one operand on stack here when prev oper is Sto2 */ 596 DBUGMSG(0, "*sto2 (lod) -> (*stodup)" ); 597 --cvtptrx; 598 ffptr = fStkStoDup; 599 } 600 /* This may cause roundoff problems when later operators */ 601 /* use the rounded value that was stored here, while the next */ 602 /* operator uses the more accurate internal value. */ 603 else if (prevfptr == fStkStoClr2 604 && Store[StoPtr-1] == Load[LodPtr] ){ 605 /* store, clear, load same value found */ 606 /* only one operand was on stack so this is safe */ 607 DBUGMSG (0, "*StoClr2 (Lod) -> (*Sto2)" ); 608 --cvtptrx; 609 ffptr = fStkSto2; /* use different Sto fn */ 610 } 611 else { 612 testload = Load[LodPtr]; 613 if (testload == &LASTSQR && lastsqrreal ){ 614 /* -- LastSqr is a real. CAE 31OCT93 */ 615 DBUGMSG(0, "(*lod[lastsqr]) -> (*lodreal)" ); 616 ffptr = fStkLodReal; 617 } 618 else if (IS_CONST(testload) && testload->d.y == 0.0 ){ 619 DBUGMSG(0, "(*lod) -> (*lodrealc)" ); 620 ffptr = fStkLodRealC; /* a real const is being loaded */ 621 } 622 } 623 /* set the operand ptr here */ 624 OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++])); 625 } 626 /* ******************************************************************** */ 627 else if (ffptr == fStkAdd ){ 628 629 if (prevfptr == fStkLodDup ){ /* there is never a push before add */ 630 --cvtptrx; /* found ? *loddup (add) */ 631 if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush2a ){ 632 /* because push lod lod is impossible so is push loddup */ 633 DBUGMSG(0, "pusha *loddup (add) -> (*loddbl),stk+=2" ); 634 REMOVE_PUSH; 635 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptr */ 636 } 637 else if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush4 ){ 638 DBUGMSG(0, "push4 *loddup (add) -> push2 (*loddbl),stk+=2" ); 639 FNPTR(cvtptrx-1) = fStkPush2; 640 stkcnt += 2; /* CAE added 12 July 1993 to fix bug */ 641 } 642 else { 643 DBUGMSG(0, "op *loddup (add) -> op (*loddbl)" ); 644 } 645 ffptr = fStkLodDbl; 646 } 647 else if (prevfptr == fStkStoDup ){ 648 DBUGMSG(0, "stodup (*add) -> (*stodbl)" ); 649 /* there are always exactly 4 on stack here */ 650 --cvtptrx; 651 ffptr = fStkStoDbl; 652 } 653 else if (prevfptr == fStkLod ){ /* have found lod (*add) */ 654 --cvtptrx; /* ? *lod (add) */ 655 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 656 DBUGMSG(0, "*push load (add) -> (*plodadd),stk+=2" ); 657 REMOVE_PUSH; 658 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 659 ffptr = fStkPLodAdd; 660 } 661 else { 662 DBUGMSG(0, "op *lod (add) -> op (*lodadd)" ); 663 ffptr = fStkLodAdd; 664 } 665 } 666 else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 667 --cvtptrx; /* found ? *lodreal (add) */ 668 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 669 DBUGMSG(0, "*push lodreal (add) -> (*lodrealadd),stk+=2" ); 670 REMOVE_PUSH; 671 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 672 } 673 else { 674 DBUGMSG(0, "*lodreal (add) -> (*lodrealadd)" ); 675 } 676 ffptr = fStkLodRealAdd; 677 } 678 else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */ 679 --cvtptrx; /* found ? *lodimag (add) */ 680 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 681 DBUGMSG(0, "*push lodimag (add) -> (*lodimagadd),stk+=2" ); 682 REMOVE_PUSH; 683 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 684 } 685 else { 686 DBUGMSG(0, "*lodimag (add) -> (*lodimagadd)" ); 687 } 688 ffptr = fStkLodImagAdd; 689 } 690 } 691 /* ******************************************************************** */ 692 else if (ffptr == fStkSub ){ 693 694 if (prevfptr == fStkLod ){ 695 /* found lod (*sub) */ 696 --cvtptrx; /* *lod (sub) */ 697 /* there is never a sequence (lod push sub ) */ 698 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 699 DBUGMSG(0, "*push lod (sub) -> (*plodsub),stk+=2" ); 700 REMOVE_PUSH; 701 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 702 ffptr = fStkPLodSub; 703 } 704 else { 705 DBUGMSG(0, "*lod (sub) -> (*lodsub)" ); 706 ffptr = fStkLodSub; 707 } 708 } 709 else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 710 --cvtptrx; /* ? *lodreal (sub) */ 711 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 712 DBUGMSG(0, "*push lodreal (sub) -> (*lodrealsub),stk+=2" ); 713 REMOVE_PUSH; 714 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 715 } 716 else { 717 DBUGMSG(0, "*lodreal (sub) -> (*lodrealsub)" ); 718 } 719 ffptr = fStkLodRealSub; 720 } 721 else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */ 722 --cvtptrx; /* ? *lodimag (sub) */ 723 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 724 DBUGMSG(0, "*push lodimag (sub) -> (*lodimagsub),stk+=2" ); 725 REMOVE_PUSH; 726 OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */ 727 } 728 else { 729 DBUGMSG(0, "*lodimag (sub) -> (*lodimagsub)" ); 730 } 731 ffptr = fStkLodImagSub; 732 } 733 } 734 /* ******************************************************************** */ 735 else if (ffptr == fStkMul ){ 736 737 if (prevfptr == fStkLodDup ){ 738 /* found loddup ? (*mul) */ 739 if (FNPTR(--cvtptrx) == fStkPush2 ){ 740 DBUGMSG(0, "loddup *push (mul) -> (*lodsqr),stk+=2" ); 741 REMOVE_PUSH; 742 } 743 else { 744 DBUGMSG(0, "*loddup (mul) -> (*lodsqr)" ); 745 } 746 ffptr = fStkLodSqr; 747 } 748 else if (prevfptr == fStkStoDup ){ /* no pushes here, 4 on stk. */ 749 DBUGMSG(0, "stodup (mul) -> (*stosqr0)" ); 750 --cvtptrx; 751 ffptr = fStkStoSqr0; /* dont save lastsqr here ever */ 752 } 753 else if (prevfptr == fStkLod ){ 754 --cvtptrx; /* lod *? (mul) */ 755 if (FNPTR(cvtptrx) == fStkPush2 ){ /* lod *push (mul) */ 756 --cvtptrx; /* ? *lod push (mul) */ 757 if(FNPTR(cvtptrx-1) == fStkPush2 ){ 758 DBUGMSG(0, "push *lod push (mul) -> push4 (*lodmul)" ); 759 FNPTR(cvtptrx-1) = fStkPush4; 760 } 761 else { 762 DBUGMSG(0, "op *lod push (mul) -> op pusha (*lodmul)" ); 763 OPPTR(cvtptrx+1) = OPPTR(cvtptrx); /* fix operand ptr */ 764 FNPTR(cvtptrx) = fStkPush2a; 765 OPPTR(cvtptrx) = NO_OPERAND; 766 cvtptrx++; 767 } 768 } 769 else { 770 DBUGMSG(0, "*lod (mul) -> (*lodmul)" ); 771 } 772 ffptr = fStkLodMul; 773 774 /********************** begin extension *** CAE 9 Oct 93 ****/ 775 /* change loadreal a, lodmul b --> lod b, lodrealmul a */ 776 777 FNPTR(cvtptrx) = NO_FUNCTION; /* mark the pending fn as null */ 778 if (FNPTR(cvtptrx-1) == fStkPush4 779 || FNPTR(cvtptrx-1) == fStkPush2a ){ 780 --cvtptrx; /* look back past this push */ 781 } 782 783 if (FNPTR(cvtptrx-1) == fStkLodRealC 784 && Load[LodPtr-2]->d.x == _2_ ){ 785 /* -- Convert '2*a' into 'a+a'. CAE 31OCT93 */ 786 if (FNPTR(cvtptrx) == NO_FUNCTION ){ 787 DBUGMSG(0, "lodreal[2] (*lodmul[b])" 788 " -> (*loddbl[b])" ); 789 OPPTR(cvtptrx-1) = OPPTR(cvtptrx); 790 } 791 else if (FNPTR(cvtptrx) == fStkPush2a ){ 792 DBUGMSG(0, "lodreal[2] *pusha (lodmul[b])" 793 " -> loddbl[b],stk+=2" ); 794 OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1); 795 stkcnt += 2; 796 } 797 else if (FNPTR(cvtptrx) == fStkPush4 ){ 798 DBUGMSG(0, "lodreal[2] *push4 (lodmul[b])" 799 " -> loddbl[b],stk+=4" ); 800 OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1); 801 stkcnt += 4; 802 } 803 FNPTR(--cvtptrx) = NO_FUNCTION; /* so no increment later */ 804 ffptr = fStkLodDbl; 805 } 806 else if (FNPTR(cvtptrx-1) == fStkLodReal 807 || FNPTR(cvtptrx-1) == fStkLodRealC ){ 808 /* lodreal *?push?? (*?lodmul) */ 809 otemp = OPPTR(cvtptrx-1); /* save previous fn's operand */ 810 FNPTR(cvtptrx-1) = fStkLod; /* prev fn = lod */ 811 /* Moved setting of prev lodptr to below CAE 31DEC93 */ 812 /* This was a bug causing a bad loadptr to be set here */ 813 /* 3 lines marked 'prev lodptr=this' below replace this line */ 814 if (FNPTR(cvtptrx) == NO_FUNCTION ){ 815 DBUGMSG(0, "lodreal[a] (*lodmul[b])" 816 " -> lod[b] (*lodrealmul[a])" ); 817 OPPTR(cvtptrx-1) = OPPTR(cvtptrx); /* prev lodptr=this */ 818 } 819 else if (FNPTR(cvtptrx) == fStkPush2a ){ 820 DBUGMSG(0, "lodreal[a] *pusha (lodmul[b])" 821 " -> lod[b] (*lodrealmul[a]),stk+=2" ); 822 /* set this fn ptr to null so cvtptrx won't be incr later */ 823 FNPTR(cvtptrx) = NO_FUNCTION; 824 OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1); /* prev lodptr=this */ 825 stkcnt += 2; 826 } 827 else if (FNPTR(cvtptrx) == fStkPush4 ){ 828 DBUGMSG(0, "lodreal[a] *push4 (lodmul[b])" 829 " -> lod[b] push2 (*lodrealmul[a]),stk+=2" ); 830 FNPTR(cvtptrx++) = fStkPush2; 831 OPPTR(cvtptrx-2) = OPPTR(cvtptrx); /* prev lodptr=this */ 832 /* we know cvtptrx points to a null function now */ 833 stkcnt += 2; 834 } 835 OPPTR(cvtptrx) = otemp; /* switch the operands */ 836 ffptr = fStkLodRealMul; /* next fn is now lodrealmul */ 837 } 838 839 if (FNPTR(cvtptrx) != NO_FUNCTION ){ 840 cvtptrx++; /* adjust cvtptrx back to normal if needed */ 841 } 842 /* ********************** end extension *********************** */ 843 } 844 else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 845 846 --cvtptrx; /* found lodreal *? (mul) */ 847 if (FNPTR(cvtptrx) == fStkPush2 ){ 848 DBUGMSG(0, "lodreal *push2 (mul) -> (*lodrealmul),stk+=2" ); 849 REMOVE_PUSH; 850 } 851 else { 852 DBUGMSG(0, "*lodreal (mul) -> (*lodrealmul)" ); 853 } 854 ffptr = fStkLodRealMul; 855 856 /********************** begin extension *** CAE 31OCT93 ****/ 857 if (prevfptr == fStkLodRealC /* use prevfptr here */ 858 && Load[LodPtr-1]->d.x == _2_ ){ 859 if (FNPTR(cvtptrx) == fStkPush2 ){ 860 DBUGMSG(0, "push (*lodrealmul[2]) -> (*dbl),stk+=2" ); 861 REMOVE_PUSH; 862 } 863 else { 864 DBUGMSG(0, "*lodrealmul[2] -> (*dbl)" ); 865 } 866 OPPTR(cvtptrx) = NO_OPERAND; 867 ffptr = fStkDbl; 868 869 if (FNPTR(cvtptrx-1) == fStkLod ){ 870 DBUGMSG(0, "lod (*dbl) -> (*loddbl)" ); 871 --cvtptrx; 872 ffptr = fStkLodDbl; 873 } 874 else if (FNPTR(cvtptrx-1) == fStkSto2 ){ 875 DBUGMSG(0, "sto2 (*dbl) -> (*stodbl)" ); 876 --cvtptrx; 877 ffptr = fStkStoDbl; 878 } 879 } 880 /************************ end extension *** CAE 31OCT93 ****/ 881 } 882 else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */ 883 884 --cvtptrx; /* found lodimag *? (mul) */ 885 if (FNPTR(cvtptrx) == fStkPush2 ){ 886 DBUGMSG(0, "lodimag *push2 (mul) -> (*lodimagmul),stk+=2" ); 887 REMOVE_PUSH; 888 } 889 else { 890 DBUGMSG(0, "*lodimag (mul) -> (*lodimagmul)" ); 891 } 892 ffptr = fStkLodImagMul; 893 } 894 else if (prevfptr == fStkLodLT && FNPTR(cvtptrx-1) != fStkPull2 ){ 895 /* this shortcut fails if Lod LT Pull Mul found */ 896 DBUGMSG(0, "LodLT (*Mul) -> (*LodLTMul)" ); 897 --cvtptrx; /* never lod LT Push Mul here */ 898 ffptr = fStkLodLTMul; 899 } 900 else if (prevfptr == fStkLodLTE && FNPTR(cvtptrx-1) != fStkPull2 ){ 901 DBUGMSG(0, "LodLTE (*mul) -> (*LodLTEmul)" ); 902 --cvtptrx; 903 ffptr = fStkLodLTEMul; 904 } 905 } 906 /* ******************************************************************** */ 907 else if (ffptr == fStkClr1 && prevfptr == fStkSto ){ 908 909 --cvtptrx; 910 if (stkcnt == 2 ){ 911 DBUGMSG(0, "sto (*clr1) -> (*stoclr2)" ); 912 ffptr = fStkStoClr2; 913 } 914 else { 915 DBUGMSG(0, "sto (*clr1) -> (*stoclr1)" ); 916 ffptr = fStkStoClr1; 917 } 918 } 919 /* ******************************************************************** */ 920 else if (ffptr == fStkDiv ){ 921 922 if (prevfptr == fStkLodRealC && vsp < Max_Args - 1 ){ 923 /* have found a divide by a real constant */ 924 /* and there is space to create a new one */ 925 /* lodrealc ? (*div) */ 926 if (FNPTR(--cvtptrx) == fStkPush2 ){ 927 DBUGMSG(0, "lodrealc *push (div) -> (*lodrealmul),stk+=2" ); 928 REMOVE_PUSH; 929 } 930 else { 931 DBUGMSG(0, "*lodrealc (div) -> (*lodrealmul)" ); 932 } 933 v[vsp].s = (void near *)0; /* this constant has no name */ 934 v[vsp].len = 0; 935 v[vsp].a.d.x = _1_ / Load[LodPtr-1]->d.x; 936 v[vsp].a.d.y = 0.0; 937 { 938 void far *p = &v[vsp++].a; 939 OPPTR(cvtptrx) = (void near *)FP_OFF(p); /* isn't C fun! */ 940 } 941 ffptr = fStkLodRealMul; 942 } 943 } 944 /* ******************************************************************** */ 945 else if (ffptr == fStkReal ){ 946 947 if (prevfptr == fStkLod ){ 948 DBUGMSG(0, "lod (*real) -> (*lodreal)" ); 949 --cvtptrx; 950 ffptr = fStkLodReal; 951 } 952 else if (stkcnt < MAX_STACK ){ 953 DBUGMSG(0, "(*real) -> (*real2)" ); 954 ffptr = fStkReal2; 955 } 956 } 957 /* ******************************************************************** */ 958 else if (ffptr == fStkImag && prevfptr == fStkLod ){ 959 960 DBUGMSG(0, "lod (*imag) -> lodimag" ); 961 --cvtptrx; 962 ffptr = fStkLodImag; 963 } 964 /* ******************************************************************** */ 965 else if (ffptr == fStkConj && prevfptr == fStkLod ){ 966 967 DBUGMSG(0, "lod (*conj) -> (*lodconj)" ); 968 --cvtptrx; 969 ffptr = fStkLodConj; 970 } 971 /* ******************************************************************** */ 972 else if (ffptr == fStkMod && stkcnt < MAX_STACK ){ 973 974 DBUGMSG(0, "(*mod) -> (*mod2)" ); 975 ffptr = fStkMod2; /* use faster version if room on stack */ 976 if (prevfptr == fStkLod ){ 977 DBUGMSG(0, "lod (*mod2) -> (*lodmod2)" ); 978 --cvtptrx; 979 ffptr = fStkLodMod2; 980 } 981 else if (prevfptr == fStkSto || prevfptr == fStkSto2 ){ 982 DBUGMSG(0, "sto (*mod2) -> (*stomod2)" ); 983 --cvtptrx; 984 ffptr = fStkStoMod2; 985 } 986 else if (prevfptr == fStkLodSub ){ 987 DBUGMSG(0, "lodsub (*mod2) -> (*lodsubmod)" ); 988 --cvtptrx; 989 ffptr = fStkLodSubMod; 990 } 991 else if (STACK_TOP_IS_REAL){ /* CAE 06NOV93 */ 992 DBUGMSG(0, "(*mod2[st real]) -> (*sqr3)" ); 993 ffptr = fStkSqr3; 994 } 995 } 996 /* ******************************************************************** */ 997 else if (ffptr == fStkFlip ){ 998 999 if (prevfptr == fStkReal || prevfptr == fStkReal2 ){ 1000 DBUGMSG(0, "real (*flip) -> (*realflip)" ); 1001 --cvtptrx; 1002 ffptr = fStkRealFlip; 1003 } 1004 else if (prevfptr == fStkImag ){ 1005 DBUGMSG(0, "imag (*flip) -> (*imagflip)" ); 1006 --cvtptrx; 1007 ffptr = fStkImagFlip; 1008 } 1009 else if (prevfptr == fStkLodReal ){ 1010 DBUGMSG(0, "lodreal (*flip) -> (*lodrealflip)" ); 1011 --cvtptrx; 1012 ffptr = fStkLodRealFlip; 1013 } 1014 else if (prevfptr == fStkLodImag ){ 1015 DBUGMSG(0, "lodimag (*flip) -> (*lodimagflip)" ); 1016 --cvtptrx; 1017 ffptr = fStkLodImagFlip; 1018 } 1019 } 1020 /* ******************************************************************** */ 1021 else if (ffptr == fStkAbs ){ 1022 1023 if (prevfptr == fStkLodReal ){ 1024 DBUGMSG(0, "lodreal (*abs) -> (*lodrealabs)" ); 1025 --cvtptrx; 1026 ffptr = fStkLodRealAbs; 1027 } 1028 else if (prevfptr == fStkLodImag ){ 1029 DBUGMSG(0, "lodimag (*abs) -> (*lodimagabs)" ); 1030 --cvtptrx; 1031 ffptr = fStkLodImagAbs; 1032 } 1033 } 1034 /* ******************************************************************** */ 1035 else if (ffptr == fStkSqr ){ 1036 1037 if (prevfptr == fStkLod && FNPTR(cvtptrx-1) != fStkPush2 ){ 1038 DBUGMSG(0, "lod (*sqr) -> (*lodsqr)" ); 1039 --cvtptrx; 1040 ffptr = fStkLodSqr; /* assume no need to save lastsqr */ 1041 if (lastsqrused){ 1042 DBUGMSG(0, "(*lodsqr) -> (*lodsqr2)" ); 1043 ffptr = fStkLodSqr2; /* lastsqr is being used */ 1044 } 1045 } 1046 else if (prevfptr == fStkSto2 ){ 1047 DBUGMSG(0, "sto2 (*sqr) -> (*stosqr0)" ); 1048 --cvtptrx; 1049 ffptr = fStkStoSqr0; /* assume no need to save lastsqr */ 1050 if (lastsqrused) { 1051 DBUGMSG(0, "(*stosqr0) -> (*stosqr)" ); 1052 ffptr = fStkStoSqr; /* save lastsqr */ 1053 } 1054 } 1055 else { 1056 if (!lastsqrused) { 1057 DBUGMSG(0, "(*sqr) -> (*sqr0)" ); 1058 ffptr = fStkSqr0; /* don't save lastsqr */ 1059 if (STACK_TOP_IS_REAL){ /* CAE 06NOV93 */ 1060 DBUGMSG(0, "(*sqr0[st real]) -> (*sqr3)" ); 1061 ffptr = fStkSqr3; 1062 } 1063 } 1064 } 1065 } 1066 /* ******************************************************************** */ 1067 else if (ffptr == fStkPwr ){ 1068 1069 if (prevfptr == fStkLodRealC ){ 1070 dTemp = Load[LodPtr-1]->d.x; 1071 if (dTemp == _2_ || dTemp == _1_ || dTemp == -1.0 || dTemp == 0.0 ){ 1072 /* change ^[-1,0,1,or 2] to recip,one,ident,sqr CAE 06NOV93 */ 1073 if (FNPTR(cvtptrx-1) == fStkPush2 ){ 1074 DBUGMSG(0, "LodRealC[-1,0,1,2] Push (*Pwr)" 1075 " -> (*[recip,1,ident,Sqr0]), stk+=2" ); 1076 REMOVE_PUSH; /* lod[?] (push) *pwr */ 1077 } 1078 else { 1079 DBUGMSG(0, "LodRealC[-1,0,1,2] (*Pwr)" 1080 " -> (*[recip,1,ident,sqr0])" ); 1081 } 1082 --cvtptrx; 1083 OPPTR(cvtptrx) = NO_OPERAND; 1084 if (dTemp == _2_ ){ 1085 DBUGMSG(0, "[]=Sqr0" ); 1086 ffptr = fStkSqr0; /* no need to compute lastsqr here */ 1087 if (FNPTR(cvtptrx-1) == fStkLod ){ 1088 DBUGMSG(0, "Lod (*Sqr0) -> (*LodSqr)" ); 1089 --cvtptrx; 1090 ffptr = fStkLodSqr; /* dont save lastsqr */ 1091 } 1092 else if (FNPTR(cvtptrx-1) == fStkSto2 ){ 1093 DBUGMSG(0, "Sto2 (*Sqr0) -> (*StoSqr0)" ); 1094 --cvtptrx; 1095 ffptr = fStkStoSqr0; /* dont save lastsqr */ 1096 } 1097 } 1098 else if (dTemp == _1_ ){ 1099 DBUGMSG(0, "[]=Ident" ); 1100 ffptr = fStkIdent; 1101 } 1102 else if (dTemp == 0.0 ){ 1103 DBUGMSG(0, "[]=One" ); 1104 ffptr = fStkOne; 1105 } 1106 else if (dTemp == -1.0 ){ 1107 DBUGMSG(0, "[]=Recip" ); 1108 ffptr = fStkRecip; 1109 } 1110 } 1111 else if (FNPTR(cvtptrx-1) == prevfptr ){ 1112 --cvtptrx; 1113 ffptr = fStkLodRealPwr; /* see comments below */ 1114 } 1115 } 1116 else if (prevfptr == fStkLodReal && FNPTR(cvtptrx-1) == prevfptr ){ 1117 /* CAE 6NOV93 */ 1118 /* don't handle pushes here, lodrealpwr needs 4 free */ 1119 DBUGMSG(0, "LodReal (*Pwr) -> (*LodRealPwr)" ); 1120 --cvtptrx; 1121 ffptr = fStkLodRealPwr; 1122 } 1123 } 1124 /* ******************************************************************** */ 1125 else if (ffptr == fStkLTE ){ 1126 1127 if (prevfptr == fStkLod 1128 || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 1129 DBUGMSG(0, "Lod (*LTE) -> (*LodLTE)" ); 1130 --cvtptrx; 1131 ffptr = fStkLodLTE; 1132 } 1133 } 1134 /* ******************************************************************** */ 1135 else if (ffptr == fStkLT ){ 1136 1137 if (prevfptr == fStkLod || prevfptr == fStkLodReal 1138 || prevfptr == fStkLodRealC ){ 1139 DBUGMSG(0, "Lod (*LT) -> (*LodLT)" ); 1140 --cvtptrx; 1141 ffptr = fStkLodLT; 1142 } 1143 } 1144 /* ******************************************************************** */ 1145 else if (ffptr == fStkGT ){ 1146 1147 if (prevfptr == fStkLod 1148 || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 1149 DBUGMSG(0, "Lod (*GT) -> (*LodGT)" ); 1150 --cvtptrx; 1151 ffptr = fStkLodGT; 1152 } 1153 } 1154 /* ******************************************************************** */ 1155 else if (ffptr == fStkGTE ){ 1156 1157 if (prevfptr == fStkLod 1158 || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 1159 DBUGMSG(0, "Lod (*GTE) -> (*LodGTE)" ); 1160 --cvtptrx; 1161 ffptr = fStkLodGTE; 1162 } 1163 } 1164 /* ******************************************************************** */ 1165 else if (ffptr == fStkNE ){ 1166 1167 if (prevfptr == fStkLod 1168 || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 1169 DBUGMSG(0, "Lod (*NE) -> (*LodNE)" ); 1170 --cvtptrx; 1171 ffptr = fStkLodNE; 1172 } 1173 } 1174 /* ******************************************************************** */ 1175 else if (ffptr == fStkEQ ){ 1176 1177 if (prevfptr == fStkLod 1178 || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){ 1179 DBUGMSG(0, "Lod (*EQ) -> (*LodEQ)" ); 1180 --cvtptrx; 1181 ffptr = fStkLodEQ; 1182 } 1183 } 1184 /* ******************************************************************** */ 1185 SkipOptimizer: /* ------------- end of optimizer ----------------------- */ 1186 1187 FNPTR(cvtptrx++) = prevfptr = ffptr; 1188 #ifdef TESTFP
1189 prevstkcnt = stkcnt;
1190 #endif 1191 if (Delta == CLEAR_STK ){ 1192 realstkcnt = stkcnt = 0; 1193 } 1194 else { 1195 stkcnt = (unsigned char)(stkcnt + Delta); 1196 realstkcnt = (unsigned char)(realstkcnt + Delta); 1197 } 1198 1199 DBUGMSG3(0, "Stack: %2d --> %2d, Real stack: %2d", 1200 prevstkcnt, stkcnt, realstkcnt ); 1201 1202 return 1; /* return 1 for success */ 1203 } 1204 1205 int fpfill_jump_struct(void) 1206 { /* Completes all entries in jump structure. Returns 1 on error) */ 1207 /* On entry, jump_index is the number of jump functions in the formula*/ 1208 int i = 0; 1209 int checkforelse = 0; 1210 NEW_FN near * JumpFunc = NULL; 1211 int find_new_func = 1; 1212 JUMP_PTRS_ST jump_data[MAX_JUMPS]; 1213 1214 for (OpPtr = 0; OpPtr < (int) LastOp; OpPtr++) { 1215 if(find_new_func) { 1216 switch (jump_control[i].type) { 1217 case 1: 1218 JumpFunc = fStkJumpOnFalse; 1219 break; 1220 case 2: 1221 checkforelse = !checkforelse; 1222 if(checkforelse) 1223 JumpFunc = fStkJump; 1224 else 1225 JumpFunc = fStkJumpOnFalse; 1226 break; 1227 case 3: 1228 JumpFunc = fStkJump; 1229 break; 1230 case 4: 1231 JumpFunc = fStkJumpLabel; 1232 break; 1233 default: 1234 break; 1235 } 1236 find_new_func = 0; 1237 } 1238 if(pfls[OpPtr].function == JumpFunc) { 1239 jump_data[i].JumpOpPtr = OpPtr*4; 1240 i++; 1241 find_new_func = 1; 1242 } 1243 } 1244 1245 /* Following for safety only; all should always be false */ 1246 if(i != jump_index || jump_control[i - 1].type != 4 1247 || jump_control[0].type != 1) { 1248 return 1; 1249 } 1250 1251 while(i > 0) { 1252 i--; 1253 i = fill_if_group(i, jump_data); 1254 } 1255 return i < 0 ? 1 : 0; 1256 } 1257 1258 extern int fform_per_pixel(void); /* these fns are in parsera.asm */ 1259 extern int BadFormula(void); 1260 extern void (far Img_Setup )(void); 1261 1262 int CvtStk() { /* convert the array of ptrs */ 1263 extern char FormName[]; 1264 void (far *ftst)(void); 1265 void (near *ntst)(void); 1266 union Arg far *testoperand; 1267 struct fn_entry far *pfe; 1268 int fnfound; 1269 1270 lastsqrreal = 1; /* assume lastsqr is real (not stored explicitly) */ 1271 p1const = p2const = p3const = (unsigned char)1; /* . . . p1, p2, p3 const */ 1272 p4const = p5const = (unsigned char)1; /* . . . p4, p5 const */ 1273 lastsqrused = 0; /* ... and LastSqr is not used */ 1274 1275 /* now see if the above assumptions are true */ 1276 for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++ ){ 1277 ftst = f[OpPtr]; 1278 if (ftst == StkLod ){ 1279 if (Load[LodPtr++] == &LASTSQR ){ 1280 lastsqrused = 1; 1281 } 1282 } 1283 else if (ftst == StkSto ){ 1284 testoperand = Store[StoPtr++]; 1285 if (testoperand == &PARM1 ){ 1286 p1const = 0; 1287 } 1288 else if (testoperand == &PARM2 ){ 1289 p2const = 0; 1290 } 1291 else if (testoperand == &PARM3 ){ 1292 p3const = 0; 1293 } 1294 else if (testoperand == &PARM4 ){ 1295 p4const = 0; 1296 } 1297 else if (testoperand == &PARM5 ){ 1298 p5const = 0; 1299 } 1300 else if (testoperand == &LASTSQR ){ 1301 lastsqrreal = 0; 1302 } 1303 } 1304 } 1305 1306 if (!p1const) { 1307 DBUGMSG(0, "p1 not constant" ); 1308 } 1309 if (!p2const) { 1310 DBUGMSG(0, "p2 not constant" ); 1311 } 1312 if (!p3const) { 1313 DBUGMSG(0, "p3 not constant" ); 1314 } 1315 if (!p4const) { 1316 DBUGMSG(0, "p4 not constant" ); 1317 } 1318 if (!p5const) { 1319 DBUGMSG(0, "p5 not constant" ); 1320 } 1321 if (lastsqrused) { 1322 DBUGMSG(0, "LastSqr loaded" ); 1323 if (!lastsqrreal) { 1324 DBUGMSG(0, "LastSqr stored" ); 1325 } 1326 } 1327 1328 if (f[LastOp-1] != StkClr ){ 1329 DBUGMSG(0, "Missing clr added at end" ); 1330 /* should be safe to modify this */ 1331 f[LastOp++] = StkClr; 1332 } 1333 1334 prevfptr = (void (near *)(void))0; 1335 cvtptrx = realstkcnt = stkcnt = 0; 1336 1337 for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++) { 1338 ftst = f[OpPtr]; 1339 fnfound = 0; 1340 for (pfe = &afe[0]; pfe <= &afe[LAST_OLD_FN]; pfe++ ){ 1341 if (ftst == pfe->infn ){ 1342 fnfound = 1; 1343 ntst = pfe->outfn; 1344 if (ntst == fStkClr1 && OpPtr == (int)(LastOp-1) ){ 1345 ntst = fStkClr2; /* convert the last clear to a clr2 */ 1346 DBUGMSG(0, "Last fn (CLR) --> (is really CLR2)" ); 1347 } 1348 if (ntst == fStkIdent && debugflag != 322 ){ 1349 /* ident will be skipped here */ 1350 /* this is really part of the optimizer */ 1351 DBUGMSG(0, "IDENT was skipped" ); 1352 } 1353 else { 1354 #ifndef XFRACT 1355 DBUGMSG4(0, "fn=%Fs, minstk=%1i, freestk=%1i, delta=%3i", 1356 pfe->fname, 1357 (int)(pfe->min_regs), 1358 (int)(pfe->free_regs), 1359 (int)(pfe->delta) );
1360 #else 1361 DBUGMSG4(0, "fn=%s, minstk=%1i, freestk=%1i, delta=%3i", 1362 pfe->fname, 1363 (int)(pfe->min_regs), 1364 (int)(pfe->free_regs), 1365 (int)(pfe->delta) );
1366 #endif 1367 if (!CvtFptr(ntst, 1368 pfe->min_regs, 1369 pfe->free_regs, 1370 pfe->delta) ){ 1371 return 1; 1372 } 1373 } 1374 } 1375 } 1376 if (!fnfound ){ 1377 /* return success so old code will be used */ 1378 /* stopmsg(0, "Fast 387 parser failed, reverting to slower code." );*/ 1379 return 1; /* this should only happen if random numbers are used */ 1380 } 1381 } /* end for */ 1382 1383 if (debugflag == 322 ){ 1384 goto skipfinalopt; 1385 } /* ------------------------------ final optimizations ---------- */ 1386 1387 /* cvtptrx -> one past last operator (always clr2) */ 1388 --cvtptrx; /* now it points to the last operator */ 1389 ntst = FNPTR(cvtptrx-1); 1390 /* ntst is the next-to-last operator */ 1391 1392 if (ntst == fStkLT ){ 1393 DBUGMSG(0, "LT Clr2 -> LT2" ); 1394 FNPTR(cvtptrx-1) = fStkLT2; 1395 } 1396 else if (ntst == fStkLodLT ){ 1397 DBUGMSG(0, "LodLT Clr2 -> LodLT2" ); 1398 FNPTR(cvtptrx-1) = fStkLodLT2; 1399 } 1400 else if (ntst == fStkLTE ){ 1401 DBUGMSG(0, "LTE Clr2 -> LTE2" ); 1402 FNPTR(cvtptrx-1) = fStkLTE2; 1403 } 1404 else if (ntst == fStkLodLTE ){ 1405 DBUGMSG(0, "LodLTE Clr2 -> LodLTE2" ); 1406 FNPTR(cvtptrx-1) = fStkLodLTE2; 1407 } 1408 else if (ntst == fStkGT ){ 1409 DBUGMSG(0, "GT Clr2 -> GT2" ); 1410 FNPTR(cvtptrx-1) = fStkGT2; 1411 } 1412 else if (ntst == fStkLodGT ){ 1413 DBUGMSG(0, "LodGT Clr2 -> LodGT2" ); 1414 FNPTR(cvtptrx-1) = fStkLodGT2; 1415 } 1416 else if (ntst == fStkLodGTE ){ 1417 DBUGMSG(0, "LodGTE Clr2 -> LodGTE2" ); 1418 FNPTR(cvtptrx-1) = fStkLodGTE2; 1419 } 1420 else if (ntst == fStkAND ){ 1421 DBUGMSG(0, "AND Clr2 -> ANDClr2" ); 1422 FNPTR(cvtptrx-1) = fStkANDClr2; 1423 ntst = FNPTR(cvtptrx-2); 1424 if (ntst == fStkLodLTE ){ 1425 DBUGMSG(0, "LodLTE ANDClr2 -> LodLTEAnd2" ); 1426 --cvtptrx; 1427 FNPTR(cvtptrx-1) = fStkLodLTEAnd2; 1428 } 1429 } 1430 else if (ntst == fStkOR ){ /* CAE 06NOV93 */ 1431 DBUGMSG(0, "OR Clr2 -> ORClr2" ); 1432 FNPTR(cvtptrx-1) = fStkORClr2; 1433 } 1434 else { 1435 ++cvtptrx; /* adjust this back since no optimization was found */ 1436 } 1437 1438 skipfinalopt: /* -------------- end of final optimizations ------------ */ 1439 1440 LastOp = cvtptrx; /* save the new operator count */ 1441 LASTSQR.d.y = 0.0; /* do this once per image */ 1442 1443 /* now change the pointers */ 1444 if (FormName[0] != 0 && 1445 (uses_jump == 0 || fpfill_jump_struct() == 0)){ /* but only if parse succeeded */ 1446 curfractalspecific->per_pixel = fform_per_pixel; 1447 curfractalspecific->orbitcalc = fFormula; 1448 } 1449 else { 1450 curfractalspecific->per_pixel = BadFormula; 1451 curfractalspecific->orbitcalc = BadFormula; 1452 } 1453 1454 Img_Setup(); /* call assembler setup code */ 1455 return 1; 1456 } 1457 1458 #endif /* XFRACT */ 1459