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
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
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) );
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