File: bytecoderules.dat

package info (click to toggle)
fparserc%2B%2B 4.5.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, sid, trixie
  • size: 6,132 kB
  • sloc: cpp: 23,297; pascal: 7,097; yacc: 1,650; ansic: 973; makefile: 307; php: 53; sh: 28
file content (513 lines) | stat: -rw-r--r-- 34,230 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# This documents all the optimizations that are done to bytecode
# by fparser.cc directly while parsing the input function
# (excluding powi).

# identifiers: lowercase=cImmeds, uppercase=opcodes
# [bracketed expression in condition]: constraints to input immeds or opcodes
# [bracketed expression in replacement]: function that produces an immed
# {braceted expression in replacement}: function that produces an opcode

#
# The comment tag "#TEST pathlet" indicates the test(s) that apply
# to this particular rule. Note that the tests only test that this
# rule does not _break_ anything (they try to invoke the rule),
# but they don't test whether the rule is actually applied
# and that the rule has the intended effect.
#

#y [isEvenInteger(y)&&!isEvenInteger(x*y)] cExp  x cPow -> cAbs [y*x] cExp
#y [isEvenInteger(y)&&!isEvenInteger(x*y)] cExp2 x cPow -> cAbs [y*x] cExp2
#  ^ y cExp never occurs (already optimized to literal)
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [isEvenInteger(y)&&!isEvenInteger(x*y)] cPow  x cPow -> cAbs [y*x] cPow  #TEST 10/absyxpow_neg, 10/absyxpow_pos
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr x [!isEvenInteger(x+x)] cPow -> cAbs [x+x] cPow
IF(FP_FLOAT_VERSION) cSqr cSqrt  -> cAbs         # TEST 10/sqrsqrt
#IF(FP_FLOAT_VERSION) cSqr cRSqrt -> cAbs cInv

 # (x^y)^1.5  is unacceptable,
 #            for y might be 2, resulting in x^3
 #              f(-2)  = 8
 #              f'(-2) = -8
 # (x^y)^5    is okay
 #            for y might be 1.2, resulting in x^6
 #              f(-2) = nan
 #              f'(-2) = 64
 # (x^y)^2    is okay,
 #            for y might be 1.5, resulting in x^3
 #              f(-2) = nan  <- ok because of this
 #              f'(-2) = -8
 #
#y [!isInteger(y)] cExp  x	[isInteger(x)] cPow -> [y*x] cExp
#y [!isInteger(y)] cExp2 x	[isInteger(x)] cPow -> [y*x] cExp2
#  ^ y cExp never occurs (already optimized to literal)
IF(FP_FLOAT_VERSION) y [!isInteger(y)] cPow  x	[isInteger(x)] cPow -> [y*x] cPow # TEST 10/ypowxpow
IF(FP_FLOAT_VERSION) cExp  x	[isInteger(x)] cPow -> [x] cMul cExp   # TEST 10/expxpow
IF(FP_FLOAT_VERSION) cExp2 x	[isInteger(x)] cPow -> [x] cMul cExp2  # TEST 10/exp2xpow
IF(FP_FLOAT_VERSION) cPow  x	[isInteger(x)] cPow -> [x] cMul cPow   # TEST 10/powxpow
IF(FP_FLOAT_VERSION) cSqr x cPow -> [x+x] cPow  #TEST 10/sqrxpow, 10/sqrxpow_nonint

# This rule does not speed up evaluation at all, but
# it greatly simplifies the optimization rule set, when
# we don't need to check for sequences of an immed and cSub.
x cSub -> [-x] cAdd    # TEST 10/immsub

###### REMOVING IDLE OPERATIONS :

x [x==Value_t(1)] cMul	->                  # TEST 10/mul1
x [x==Value_t(1)] cDiv	->                  # TEST 10/div1
x [x==Value_t()] cAdd	->                  # TEST 10/add0
x [x==Value_t()] cSub	->                  # TEST 10/sub0
cDup cMin ->				    # TEST 10/dupminmax
cDup cMax ->				    # TEST 10/dupminmax
cNeg cNeg ->                                # TEST 10/negneg
IF(FP_FLOAT_VERSION) cInv  cInv ->          # TEST 10/invinv
IF(FP_COMPLEX_VERSION) cConj cConj ->

B [B==A] cDup A [IsVarOpcode(A)] cMin -> B cDup # TEST 10/dupminmax2
B [B==A] cDup A [IsVarOpcode(A)] cMax -> B cDup # TEST 10/dupminmax2
B [B==A] cMin A [IsVarOpcode(A)] cMin -> B cMin # TEST 10/dupminmax3
B [B==A] cMax A [IsVarOpcode(A)] cMax -> B cMax # TEST 10/dupminmax3

y [y*x==Value_t(1)] cMul x cMul ->              # TEST 10/mul1b

###### OPERATIONS WHICH PRODUCE A CONSTANT VALUE:
###### An expression is turned into a constant value
###### by multiplying it with zero and adding the constant.

cDup cSub        -> [Value_t()] cMul                   # TEST 10/subxx
cDup cRSub       -> [Value_t()] cMul                   # TEST 10/subxx
cDup cDiv        -> [Value_t()] cMul [Value_t(1)] cAdd # TEST 10/divxx

IF(FP_COMPLEX_VERSION) cReal cImag -> [Value_t()] cMul
IF(FP_COMPLEX_VERSION) cAbs  cImag -> [Value_t()] cMul

IF(FP_FLOAT_VERSION) x [x==Value_t()] cPow -> [Value_t()] cMul [Value_t(1)] cAdd
IF(FP_FLOAT_VERSION) cSinCos cHypot        -> [Value_t()] cMul [Value_t(1)] cAdd # TEST 99/59

# Multiplications by zero: Undo as many operands as possible by peeling.
# Some of these optimimizations can be disabled due to law of diminishing returns.
A [IsVarOpcode(A)]                                                                                      x [x==Value_t()] cMul ->        [x]          # TEST 10/mul_zero VERIFY
                                                 A [IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)]       x [x==Value_t()] cMul ->        [x] cMul     # TEST 10/mul_zero VERIFY
B [IsVarOpcode(B)]                               A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)]      x [x==Value_t()] cMul ->        [x] cMul     # TEST 10/mul_zero VERIFY
B [IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)]      x [x==Value_t()] cMul -> A      [x] cMul     # TEST 10/mul_zero VERIFY
y                                                A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)]      x [x==Value_t()] cMul ->        [x] cMul     # TEST 10/mul_zero VERIFY
A [IsVarOpcode(A)]                                                                                 cMul x [x==Value_t()] cMul ->        [x] cMul     # TEST 10/mul_zero VERIFY
C [IsVarOpcode(C)]                               B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul ->   A [x] cMul     # TEST 10/mul_zero VERIFY
C [IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> B A [x] cMul     # TEST 10/mul_zero VERIFY
y                                                B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul ->   A [x] cMul     # TEST 10/mul_zero VERIFY

###### INLINE EXPANSION OF BASIC OPERATORS :

x cNeg			-> [-x]             # TEST 10/neg
x [x!=Value_t()] cInv 	-> [Value_t(1)/x]
y x cMul		-> [y*x]            # TEST 10/mul
y x [x!=Value_t()] cDiv -> [y/x]           # TEST 10/div
y x [x!=Value_t()] cMod -> [fp_mod(y,x)]   # TEST 10/mod
y x cAdd		-> [y+x]            # TEST 10/add
y x cSub		-> [y-x]            # TEST 10/sub
x cNot			-> [fp_not(x)]      # TEST 10/not
#y [y!=Value_t()] x cRDiv -> [x/y]
#y x cRSub		-> [x-y]

y x cLess		-> [fp_less(y,x)]       # TEST 10/cmplt
y x cLessOrEq		-> [fp_lessOrEq(y,x)]   # TEST 10/cmple
y x cGreater		-> [fp_less(x,y)]       # TEST 10/cmpgt
y x cGreaterOrEq	-> [fp_lessOrEq(x,y)]   # TEST 10/cmpge
y x cEqual		-> [fp_equal(y,x)]      # TEST 10/cmpeq
y x cNEqual		-> [fp_nequal(y,x)]     # TEST 10/cmpne
y x cAnd		-> [fp_and(x,y)]        # TEST 10/and
y x cOr			-> [fp_or(x,y)]         # TEST 10/or
#y x cAbsAnd		-> [fp_absAnd(x,y)]
#y x cAbsOr		-> [fp_absOr(x,y)]

cNeg x cMul			-> [-x] cMul    # TEST 10/negmul
x cMul cNeg			-> [-x] cMul    # TEST 10/mulneg
x [x==Value_t(-1)] cMul		-> cNeg         # TEST 10/mulminus1
cNeg x [x!=Value_t()] cDiv	-> [-x] cDiv    # TEST 10/negdiv

y cAdd x cAdd		-> [y+x] cAdd           # TEST 11/42
y cMul x cMul		-> [y*x] cMul           # TEST 11/43

###### INLINE EXPANSION OF BASIC FUNCTIONS :

x cAbs	 		-> [fp_abs(x)]                                         # TEST 10/abs
IF(FP_FLOAT_VERSION) x cDeg	 		-> [RadiansToDegrees(x)]       # TEST 10/deg
IF(FP_FLOAT_VERSION) x cRad	 		-> [DegreesToRadians(x)]       # TEST 10/rad
IF(FP_FLOAT_VERSION) x cCeil	 		-> [fp_ceil(x)]                # TEST 10/ceil*
IF(FP_FLOAT_VERSION) x cFloor 			-> [fp_floor(x)]               # TEST 10/floor*
IF(FP_FLOAT_VERSION) x cInt	 		-> [fp_int(x)]                 # TEST 10/int
IF(FP_FLOAT_VERSION) x cTrunc 			-> [fp_trunc(x)]               # TEST 10/runc*
IF(FP_FLOAT_VERSION) y x cAtan2			-> [fp_atan2(y,x)]             # TEST 10/atan2*
y x cMin					-> [fp_min(x,y)]    # TEST 10/min
y x cMax					-> [fp_max(x,y)]    # TEST 10/max

##### REAL VERSIONS:

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x>=Value_t(1)]                 cAcosh -> [fp_acosh(x)] # TEST 10/acosh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x                                 cAsinh -> [fp_asinh(x)] # TEST 10/asinh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)< Value_t(1)] cAtanh -> [fp_atanh(x)] # TEST 10/atanh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)<=Value_t(1)] cAcos  -> [fp_acos(x)]  # TEST 10/acos*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)<=Value_t(1)] cAsin  -> [fp_asin(x)]  # TEST 10/asin*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAtan	 		-> [fp_atan(x)]                # TEST 10/atan*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCbrt	 		-> [fp_cbrt(x)]                # TEST 10/cbrt*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCos	 		-> [fp_cos(x)]                 # TEST 10/cos*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCosh	 		-> [fp_cosh(x)]                # TEST 10/cosh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp	 		-> [fp_exp(x)]                 # TEST 10/exp*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp2	 		-> [fp_exp2(x)]                # TEST 10/exp2*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog	-> [fp_log(x)]                 # TEST 10/log*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog10	-> [fp_log10(x)]               # TEST 10/log10*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog2	-> [fp_log2(x)]                # TEST 10/log2*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSin	 		-> [fp_sin(x)]                 # TEST 10/sin*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSinh	 		-> [fp_sinh(x)]                # TEST 10/sinh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x>=Value_t(0)] cSqrt	-> [fp_sqrt(x)]                # TEST 10/sqr*
#IF(FP_FLOAT_VERSION) x [x> Value_t()] cRSqrt	-> [Value_t(1)/fp_sqrt(x)]
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTan	 		-> [fp_tan(x)]                 # TEST 10/tan*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTanh	 		-> [fp_tanh(x)]                # TEST 10/tanh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [ y!=Value_t(0) || x>=Value_t(0)] x cPow -> [fp_pow(y,x)] # TEST 10/pow*

##### COMPLEX VERSIONS:

IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAcosh	 		-> [fp_acosh(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAsinh	 		-> [fp_asinh(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh -> [fp_atanh(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAcos	 		-> [fp_acos(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAsin	 		-> [fp_asin(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan	-> [fp_atan(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCbrt	 		-> [fp_cbrt(x)]                # TEST 10/cbrt*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCos	 		-> [fp_cos(x)]                 # TEST 10/cos*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCosh	 		-> [fp_cosh(x)]                # TEST 10/cosh*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp	 		-> [fp_exp(x)]                 # TEST 10/exp*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp2	 		-> [fp_exp2(x)]                # TEST 10/exp2*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog	-> [fp_log(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog10	-> [fp_log10(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog2	-> [fp_log2(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSin	 		-> [fp_sin(x)]                 # TEST 10/sin*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSinh	 		-> [fp_sinh(x)]                # TEST 10/sinh*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSqrt			-> [fp_sqrt(x)]
#IF(FP_FLOAT_VERSION) x [x> Value_t(0)] cRSqrt	-> [Value_t(1)/fp_sqrt(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTan	 		-> [fp_tan(x)]                 # TEST 10/tan*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTanh	 		-> [fp_tanh(x)]                # TEST 10/tanh*
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y x cPow			-> [fp_pow(y,x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cArg                       -> [fp_arg(x)]
IF(FP_COMPLEX_VERSION)                     x cReal                      -> [fp_real(x)]
IF(FP_COMPLEX_VERSION)                     x cImag                      -> [fp_imag(x)]
IF(FP_COMPLEX_VERSION)                     x cConj                      -> [fp_conj(x)]
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x y cPolar                   -> [fp_polar(x,y)]

###### SIMPLIFYING SOME OPCODE SEQUENCES :

x [x==Value_t(2)] cMul -> cDup cAdd                        # TEST 10/mul2
cNeg cAdd -> cSub                                          # TEST 10/negadd
cNeg cSub -> cAdd                                          # TEST 10/negsub
cNeg cAbs -> cAbs                                          # TEST 10/negabs
cDup cMul -> cSqr                                          # TEST 10/sqr_xx
cNeg cSqr -> cSqr                                          # TEST 10/negsqr
cAbs cSqr -> cSqr                                          # TEST 10/abssqr

IF(FP_FLOAT_VERSION) cSqrt cInv -> cRSqrt                        # TEST 10/rsqrt
IF(FP_FLOAT_VERSION) x [x==fp_const_rad_to_deg<Value_t>()] cMul -> cDeg #TEST 10/deg
IF(FP_FLOAT_VERSION) x [x==fp_const_deg_to_rad<Value_t>()] cMul -> cRad #TEST 10/rad
IF(FP_FLOAT_VERSION) cDeg x cMul -> [RadiansToDegrees(x)] cMul # TEST 10/degxmul
IF(FP_FLOAT_VERSION) cRad x cMul -> [DegreesToRadians(x)] cMul # TEST 10/radxmul VERIFY
IF(FP_FLOAT_VERSION) x cMul cRad -> [DegreesToRadians(x)] cMul # TEST 10/xmulrad

IF(FP_FLOAT_VERSION) cInv cDiv -> cMul  # TEST 10/invdiv
IF(FP_FLOAT_VERSION) cInv cMul -> cDiv  # TEST 10/invmul (float-only, because: y*(1/x) vs y/x)

cLess        cNot -> cGreaterOrEq  # TEST 10/not_lt
cLessOrEq    cNot -> cGreater      # TEST 10/not_le
cGreater     cNot -> cLessOrEq     # TEST 10/not_gt
cGreaterOrEq cNot -> cLess         # TEST 10/not_ge
cEqual       cNot -> cNEqual       # TEST 10/not_eq
cNEqual      cNot -> cEqual        # TEST 10/not_ne

cDup cOr   -> cNotNot  # TEST 99/3
cDup cAnd  -> cNotNot  # TEST 99/3

IF(!FP_COMPLEX_VERSION) cNeg  cNot -> cNot         # TEST 10/negnot
IF(!FP_COMPLEX_VERSION) cAbs  cNot -> cNot         # TEST 10/absnot

cNot  cNot -> cNotNot      # TEST 10/notnot
cNotNot cNot    -> cNot    # TEST 10/notnotnot
cAbsNotNot cNot -> cAbsNot # TEST 10/absnotnotnot
cNot cNotNot    -> cNot    # TEST 10/notnotnot2
# ^ Impossible as it seems, it is triggered by (!x & !x) -> !!(!x)

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cCos  -> cCos  # TEST 10/abscos
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cCosh -> cCosh # TEST 10/abscosh

IF(FP_FLOAT_VERSION) cNeg cCos  -> cCos                   # TEST 10/negcos
IF(FP_FLOAT_VERSION) cNeg cCosh -> cCosh                  # TEST 10/negcosh
IF(FP_FLOAT_VERSION) cNeg cSin  -> cSin cNeg              # TEST 10/negsin
IF(FP_FLOAT_VERSION) cNeg cSinh -> cSinh cNeg             # TEST 10/negsinh
IF(FP_FLOAT_VERSION) cNeg cTan  -> cTan cNeg              # TEST 10/negtan
IF(FP_FLOAT_VERSION) cNeg cTanh -> cTanh cNeg             # TEST 10/negtanh
IF(FP_FLOAT_VERSION) x cMul cSin  cNeg -> [-x] cMul cSin  # TEST 10/xmulsinneg
IF(FP_FLOAT_VERSION) x cMul cSinh cNeg -> [-x] cMul cSinh # TEST 10/xmulsinhneg
IF(FP_FLOAT_VERSION) x cMul cTan  cNeg -> [-x] cMul cTan  # TEST 10/xmultanneg
IF(FP_FLOAT_VERSION) x cMul cTanh cNeg -> [-x] cMul cTanh # TEST 10/xmultanhneg

IF(FP_FLOAT_VERSION) cSin cDiv -> cCsc cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCos cDiv -> cSec cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cTan cDiv -> cCot cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCsc cDiv -> cSin cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cSec cDiv -> cCos cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCot cDiv -> cTan cMul   # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cSin cInv -> cCsc        # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCos cInv -> cSec        # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cTan cInv -> cCot        # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCsc cInv -> cSin        # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cSec cInv -> cCos        # TEST 10/invsincostan
IF(FP_FLOAT_VERSION) cCot cInv -> cTan        # TEST 10/invsincostan

###################

# rdiv(x,y)/z --> rdiv(x*z,y)   (y/x/z = y/(x*z))
IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cRDiv A [IsVarOpcode(A)] cDiv -> A cMul  B cRDiv #TEST 11/23
IF(FP_FLOAT_VERSION) x                  cRDiv A [IsVarOpcode(A)] cDiv -> A cMul [x] cRDiv #TEST 11/24
IF(FP_FLOAT_VERSION) x                  cRDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1] A [x] cMul cRDiv #TEST 11/25
x [x==Value_t(1)] cRDiv -> cInv

# a/b/c = a/(b*c)
IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cDiv A [IsVarOpcode(A)] cDiv -> [DO_STACKPLUS1] B A cMul cDiv #TEST 11/26

# a/b*c = a*b/c  (increases chances of doing the div grouping if more divs come later)
IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1]   A cMul B cDiv #TEST 11/27
# The three rules below: same as above, but with immed instead of var A
# (do only when there is an explicit optimization; otherwise we get an infinite loop)
IF(FP_FLOAT_VERSION) y      B [IsVarOpcode(B)] cDiv x cMul -> [y*x]      B cDiv
IF(FP_FLOAT_VERSION) y cMul B [IsVarOpcode(B)] cDiv x cMul -> [y*x] cMul B cDiv
IF(FP_FLOAT_VERSION) cNeg   B [IsVarOpcode(B)] cDiv x cMul ->  [-x] cMul B cDiv #TEST 11/28

IF(FP_FLOAT_VERSION) cRDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1]   A cMul cRDiv #TEST 11/29
# The three rules below: same as above, but with immed instead of var A
# (do only when there is an explicit optimization; otherwise we get an infinite loop)
IF(FP_FLOAT_VERSION) y      cRDiv x cMul -> [y*x]      cRDiv #TEST 11/30
IF(FP_FLOAT_VERSION) y cMul cRDiv x cMul -> [y*x] cMul cRDiv
IF(FP_FLOAT_VERSION) cNeg   cRDiv x cMul ->  [-x] cMul cRDiv #TEST 11/31

# These below are just Add/Sub analogies of the above rules.
x cRSub A [IsVarOpcode(A)] cSub -> A cAdd [x] cRSub #TEST 11/32
x cRSub A [IsVarOpcode(A)] cAdd -> [DO_STACKPLUS1] A [x] cAdd cRSub #TEST 11/33
y       B [IsVarOpcode(B)] cSub x cAdd -> [ y+x]      B cSub
y cAdd  B [IsVarOpcode(B)] cSub x cAdd -> [ y+x] cAdd B cSub #TEST 11/34
cNeg    B [IsVarOpcode(B)] cSub x cAdd ->   [-x] cAdd B cSub #TEST 11/35

cRSub A [IsVarOpcode(A)] cAdd -> [DO_STACKPLUS1]   A cAdd cRSub #TEST 11/32 (DUP)
cRSub A [IsVarOpcode(A)] cSub -> [DO_STACKPLUS1]   A cSub cRSub #TEST 11/33 (DUP)
y      cRSub x cAdd -> [ y+x]      cRSub #TEST 11/36
y cAdd cRSub x cAdd -> [ y+x] cAdd cRSub #TEST 11/37
cNeg   cRSub x cAdd ->  [-x] cAdd cRSub

A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cLess -> A [x] cMul # TEST 10/lt0

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog   -> cAbs cLog   cDup cAdd  # TEST 10/sqrlog
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog2  -> cAbs cLog2  cDup cAdd  # TEST 10/sqrlog2
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog10 -> cAbs cLog10 cDup cAdd  # TEST 10/sqrlog10

IF(FP_FLOAT_VERSION) y [(y*x)==fp_const_rad_to_deg<Value_t>()] cMul x cMul -> cDeg
IF(FP_FLOAT_VERSION) y [(y*x)==fp_const_deg_to_rad<Value_t>()] cMul x cMul -> cRad

cDup cAdd      cDup cAdd -> [Value_t(4)] cMul       # TEST 10/mul4
cDup cAdd cMul cDup cAdd -> cMul [Value_t(4)] cMul  # TEST 10/mul4

cDup x cMul cAdd -> [x+Value_t(1)] cMul         # TEST 10/dupxmuladd
cDup x cPow cMul -> [x+Value_t(1)] cPow         # TEST 10/dupxpowmul

IF(FP_FLOAT_VERSION) cDup [x+x==Value_t(1)] cAdd      x cMul ->                  # TEST 10/dupaddmulh
                     cDup                   cAdd      x cMul ->      [x+x] cMul  # TEST 10/dupaddmul7
IF(FP_FLOAT_VERSION) cDup [x+x==Value_t(1)] cAdd cMul x cMul -> cMul             # TEST 10/dupaddmulmulh
                     cDup                   cAdd cMul x cMul -> cMul [x+x] cMul  # TEST 10/dupaddmulmul7

IF(FP_FLOAT_VERSION) y [(y/x)==fp_const_rad_to_deg<Value_t>()] cMul x [x!=Value_t(0)] cDiv -> cDeg
IF(FP_FLOAT_VERSION) y [(y/x)==fp_const_deg_to_rad<Value_t>()] cMul x [x!=Value_t(0)] cDiv -> cRad
IF(FP_FLOAT_VERSION) y cMul x [x!=Value_t(0)] cDiv 	-> [y/x] cMul

IF(FP_FLOAT_VERSION) x [x!=Value_t(0)] cDiv		-> [Value_t(1)/x] cMul  # TEST 10/multodiv

#IF(FP_FLOAT_VERSION) y cExp  x cPow -> [y*x] cExp
#IF(FP_FLOAT_VERSION) y cExp2 x cPow -> [y*x] cExp2
#  ^ y cExp never occurs (already optimized to literal)
IF(FP_FLOAT_VERSION) y cPow  x cPow -> [y*x] cPow                      # TEST 10/ypowxpow (maybe?)

IF(FP_FLOAT_VERSION) x [x==Value_t(0.5)]      cPow -> cSqrt            # TEST 10/powhalf
IF(FP_FLOAT_VERSION) x [x==Value_t(1)/Value_t(3)]  cPow -> cCbrt       # TEST 10/powthird
IF(FP_FLOAT_VERSION) x [x==Value_t(1)/Value_t(-3)] cPow -> cCbrt cInv  # TEST 10/powminusthird
IF(FP_FLOAT_VERSION) x [x==Value_t(-0.5)]     cPow -> cRSqrt           # TEST 10/powminushalf
IF(FP_FLOAT_VERSION) x [x==Value_t(-1)]     cPow -> cInv               # TEST 10/powminusone

IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cSqrt cSqr  -> A # TEST 10/sqrtsqr1, 10/sqrtsqr2
# ^ Doable only if lhs > 0.
IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cLog  cExp  -> A # TEST 10/logexp1, 10/logexp2
IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cLog2 cExp2 -> A # TEST 10/log2exp1, 10/log2exp2
# ^ Doable only if lhs > 0.
IF(FP_FLOAT_VERSION) cExp  cLog  -> # TEST 10/explog
IF(FP_FLOAT_VERSION) cExp2 cLog2 -> # TEST 12/exp2log2
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAsin cSin ->
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAcos cCos ->
# ^ For real values, doable only if abs(x) <= 1
#IF(FP_FLOAT_VERSION) cAtan cTan ->
IF(FP_FLOAT_VERSION) cAsinh cSinh -> # TEST 10/asinhsinh
#IF(FP_FLOAT_VERSION) cAcosh cCosh -> # TEST 10/acoshcosh
# ^ Doable only if x >= 1
IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAtanh cTanh ->
# ^ For real values, doable only if abs(x) < 1
IF(FP_FLOAT_VERSION) cAtan2 cTan -> cDiv # TEST 10/atan2tan
IF(FP_FLOAT_VERSION) cPow  cInv -> cNeg cPow # TEST 10/powinv

#IF(FP_FLOAT_VERSION) x [x<0] cPow cMul -> [-x] cPow cDiv

cAbs x [x==Value_t(0)] cEqual  -> [x] cEqual   # TEST 10/abseq0
cAbs x [x==Value_t(0)] cNEqual -> [x] cNEqual  # TEST 10/absneq0
cSqr x [x==Value_t(0)] cEqual  -> [x] cEqual   # TEST 10/sqreq0
cSqr x [x==Value_t(0)] cNEqual -> [x] cNEqual  # TEST 10/sqrneq0

IF(!FP_COMPLEX_VERSION)                     y                 cAdd x A [IsComparisonOpcode(A)] -> [x-y] A                              # TEST 10/cmp_add
IF(!FP_COMPLEX_VERSION)                                       cNeg x A [IsComparisonOpcode(A)] -> [-x] {OppositeComparisonOpcode(A)}   # TEST 10/cmp_neg
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y>Value_t(0)]  cMul x A [IsComparisonOpcode(A)] -> [x/y] A                              # TEST 10/cmp_mulpos
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y<Value_t(0)]  cMul x A [IsComparisonOpcode(A)] -> [x/y] {OppositeComparisonOpcode(A)}  # TEST 10/cmp_mulneg
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y>Value_t(0)]  cPow [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_pow(x,Value_t(1)/y)] A     # TEST 10/cmp_powy_*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                   cSqr [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> cAbs [fp_sqrt(x)] A   # TEST 10/cmp_sqr, 10/cmp_sqr_neg
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                  cExp [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_log(x)] A          # TEST 10/cmp_exp, 10/cmp_exp_neg
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                 cExp2 [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_log2(x)] A         # TEST 10/cmp_exp2, 10/cmp_exp2_neg
# ^ Always doable
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)  B [IsNeverNegativeValueOpcode(B)]   cLog x A [IsComparisonOpcode(A)] -> B [fp_exp(x)] A             # TEST 10/cmp_log_*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)  B [IsNeverNegativeValueOpcode(B)]  cLog2 x A [IsComparisonOpcode(A)] -> B [fp_exp2(x)] A            # TEST 10/cmp_log2_*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)  B [IsNeverNegativeValueOpcode(B)] cLog10 x A [IsComparisonOpcode(A)] -> B [fp_pow(Value_t(10),x)] A # TEST 10/cmp_log10_*
# ^ Doable only if lhs > 0.
#IF(FP_FLOAT_VERSION)                 cAsin [fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)] x A [IsComparisonOpcode(A)] -> [fp_sin(x)] A  # TEST 10/cmp_asin*
#IF(FP_FLOAT_VERSION)                 cAcos [x>=Value_t(0)&&fp_abs(x)<fp_const_pi<Value_t>()] x A [IsComparisonOpcode(A)] -> [fp_cos(x)] {OppositeComparisonOpcode(A)}  # TEST 10/cmp_acos*
# ^ Doable only if abs(x) <= 1
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                 cAtan [fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)] x A [IsComparisonOpcode(A)] -> [fp_tan(x)] A # TEST 10/cmp_atan*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                 cSinh x A [IsComparisonOpcode(A)] -> [fp_asinh(x)] A                          # TEST 10/cmp_sinh*
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION)                 cTanh [fp_abs(x)<Value_t(1)] x A [IsComparisonOpcode(A)] -> [fp_atanh(x)] A   # TEST 10/cmp_tanh*

# (x+3)*4 -> x*4 + 12
                       y      cAdd x cMul -> [x] cMul   [y*x]      cAdd #TEST 11/39
A [IsVarOpcode(A)] y cMul cAdd x cMul -> [x] cMul A [y*x] cMul cAdd #TEST 11/40
A [IsVarOpcode(A)] y cMul cSub x cMul -> [x] cMul A [y*x] cMul cSub #TEST 11/41

IF(!FP_COMPLEX_VERSION) A [IsLogicalOpcode(A)]            cAbsNot cNot -> A              # TEST 10/absnot3
IF(!FP_COMPLEX_VERSION) A [A!=cImmed]                     cAbsNot cNot -> A cAbsNotNot   # TEST 10/absnot4
IF(!FP_COMPLEX_VERSION) A [IsNeverNegativeValueOpcode(A)] cNot -> A cAbsNot              # TEST 10/absnot2

IF(!FP_COMPLEX_VERSION) A [IsNeverNegativeValueOpcode(A)] cAbs   -> A                    # TEST 10/absneverneg
IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)]    cTrunc-> A  # TEST 10/inttrunc
IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)]    cFloor-> A  # TEST 10/intfloor
IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)]    cCeil -> A  # TEST 10/intceil
IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)]    cInt  -> A  # TEST 10/intint

#IF(FP_FLOAT_VERSION) x cMul cFloor cNeg -> [-x] cMul cCeil
#IF(FP_FLOAT_VERSION) x cMul cCeil  cNeg -> [-x] cMul cFloor
IF(FP_FLOAT_VERSION) cNeg cFloor -> cCeil cNeg     # TEST 10/negfloor, 10/floorneg
IF(FP_FLOAT_VERSION) cNeg cCeil  -> cFloor cNeg    # TEST 10/negceil, 10/ceilneg

IF(FP_FLOAT_VERSION) x cAdd cExp  -> cExp  [fp_exp(x)]  cMul # TEST 10/addexp
IF(FP_FLOAT_VERSION) x cAdd cExp2 -> cExp2 [fp_exp2(x)] cMul # TEST 10/addexp2

IF(FP_FLOAT_VERSION) cPow  cDiv -> cNeg cPow  cMul  # TEST 10/powdiv
IF(FP_FLOAT_VERSION) cExp  cDiv -> cNeg cExp  cMul  # TEST 10/expdiv
IF(FP_FLOAT_VERSION) cExp2 cDiv -> cNeg cExp2 cMul  # TEST 10/exp2div

IF(!FP_FLOAT_VERSION) x [x==Value_t(0)] cEqual  -> cNot              # TEST 10/eq0
IF(!FP_FLOAT_VERSION) x [x==Value_t(0)] cNEqual -> cNotNot           # TEST 10/neq0
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(0)] cGreater     -> cNotNot # TEST 10/gt0_abs
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(1)] cGreaterOrEq -> cNotNot # TEST 10/ge1_abs
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(1)] cLess     -> cNot       # TEST 10/gt1_abs
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(0)] cLessOrEq -> cNot       # TEST 10/ge0_abs
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cGreater     -> A cNotNot # TEST 10/gt0_pos, 10/gt0_neg
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(1)] cGreaterOrEq -> A cNotNot # TEST 10/ge1_pos, 10/ge1_neg
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(1)] cLess     -> A cNot       # TEST 10/gt1_pos, 10/gt1_neg
IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cLessOrEq -> A cNot       # TEST 10/ge0_pos, 10/ge0_neg
IF(!FP_FLOAT_VERSION) A [IsLogicalOpcode(A)] x [x==Value_t(1)] cEqual  -> A      # TEST 10/eq1
IF(!FP_FLOAT_VERSION) A [IsLogicalOpcode(A)] x [x==Value_t(1)] cNEqual -> A cNot # TEST 10/neq1
IF(!FP_FLOAT_VERSION) x cAdd cNotNot -> [-x] cNEqual # TEST 10/xaddnotnot
IF(!FP_FLOAT_VERSION) x cAdd cNot    -> [-x] cEqual  # TEST 10/xaddnot

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs x [x!=Value_t(0)] cLess         -> [Value_t(0.5)/x] cMul cNot    # TEST 10/absnzlt
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs x [x!=Value_t(0)] cGreaterOrEq  -> [Value_t(0.5)/x] cMul cNotNot # TEST 10/absnzge

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(0.5)] cLess         -> cAbsNot       # TEST 10/lthalf
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(0.5)] cGreaterOrEq  -> cAbsNotNot    # TEST 10/gehalf
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(-0.5)] cGreater   -> cNeg cAbsNot    # TEST 10/gtminushalf
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(-0.5)] cLessOrEq  -> cNeg cAbsNotNot # TEST 10/leminushalf

IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs      x [isEvenInteger(x)] cPow ->      [x] cPow # TEST 10/absevenconstpow
IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cMul x [isEvenInteger(x)] cPow -> cMul [x] cPow # TEST 10/absmulevenconstpow

IF(FP_FLOAT_VERSION) cAcosh cSinh -> [DO_STACKPLUS1] cSqr [Value_t(-1)] cAdd cSqrt # TEST 10/acoshsinh
# sinh(x) =  0.5 * (exp(x) - exp(-x))
# acosh(x) = log(x + sqrt(x*x - 1))
# Thus,
# sinh(acosh(x)) = 0.5 * (exp(log(x + sqrt(x*x - 1))) - exp(-log(x + sqrt(x*x - 1))))
# sinh(acosh(x)) = 0.5 * (   (   (x + sqrt(x*x - 1))) -     1 / (x + sqrt(x*x - 1)) )
# sinh(acosh(x)) = 0.5 * (x + sqrt(x*x - 1) - 1 / (x + sqrt(x*x - 1)))
# sinh(acosh(x)) = 0.5*x + 0.5*sqrt(x*x - 1) - 0.5/(x + sqrt(x*x - 1))
# Maxima gets a step further and says that:
# sinh(acosh(x)) = sqrt(x-1)*sqrt(x+1)
# Furthermore, Wikipedia gives us this:
# sinh(acosh(x)) = sqrt(x*x-1)  IF abs(x) > 1 or complex version

IF(FP_FLOAT_VERSION) cAsinh cCosh -> [DO_STACKPLUS1] cSqr  [Value_t(1)] cAdd cSqrt # TEST 10/asinhcosh
# cosh(asinh(x)) = sqrt(x^2+1)

# Hardcoded optimizations that are too complex or
# impossible to convey using this rule file:
IF(FP_FLOAT_VERSION) x cPow -> [DO_POWI]

# x*x = x^2
B [B==A]           A [IsVarOpcode(A)] cMul  -> B cSqr           # TEST 10/sqr_xx

# ...*x*x = ...*x^2
B [B==A]      cMul A [IsVarOpcode(A)] cMul  -> B cSqr cMul      # TEST 10/sqr_yxx

# -x*x = -(x^2)
B [B==A] cNeg      A [IsVarOpcode(A)] cMul  -> B cSqr      cNeg # TEST 10/sqr_nxx

# x*-x = -(x^2)
cDup cNeg cMul                              ->   cSqr      cNeg # TEST 10/sqr_xnx

# ...*-x*x = ...*-(x^2)
B [B==A] cNeg cMul A [IsVarOpcode(A)] cMul  -> B cSqr cMul cNeg # TEST 10/sqr_ynxx

# ...*x*-x = ...*-(x^2)
B [B==A] cMul A [IsVarOpcode(A)] cNeg cMul  -> B cSqr cMul cNeg # TEST 10/sqr_yxnx

B [B==A] A [IsVarOpcode(A) && mData->mByteCode.size() > 0] -> B cDup                                                  # TEST 10/xxdup
D [D==B] C [C==A]      B [IsVarOpcode(B) && mData->mByteCode.size() > 1] A [IsUnaryOpcode(A)]      -> D C cDup        # TEST 10/xxfdup
D [D==B] C [C==A] cMul B [IsVarOpcode(B) && mData->mByteCode.size() > 1] A [IsUnaryOpcode(A)] cMul -> D C cSqr cMul   # TEST 10/xxsqrdup

IF(FP_FLOAT_VERSION) cExp2	 -> [DO_STACKPLUS1] [fp_log(Value_t(2))] cMul cExp         # TEST 02/exp2
IF(FP_FLOAT_VERSION) cExp cLog2	 -> [DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())] cMul  # TEST 10/explog2
IF(FP_FLOAT_VERSION) cExp cLog10 -> [DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())] cMul # TEST 10/explog10

#    expr0 expr1 cExp cMul cLog
# -> expr0 cLog expr1 cAdd
# could be done if expr1 is a var. Too special case. Not doing...
#    expr0 cLog expr1 cLog
# -> expr0 expr1 cMul cLog
# similar.

IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog2  -> cLog2  [fp_log2(x)]  cAdd # TEST 10/logmul2
IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog   -> cLog   [fp_log(x)]   cAdd # TEST 10/logmul
IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog10 -> cLog10 [fp_log10(x)] cAdd # TEST 10/logmul10

IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCos -> B cSinCos         # TEST 10/sincos_sc
IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSec -> B cSinCos cInv    # TEST 10/sincos_sci
IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCsc -> B cSin cDup cInv  # TEST 10/sincos_ssi
IF(FP_FLOAT_VERSION) B [B==A] cCos A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSec -> B cCos cDup cInv  # TEST 10/sincos_cci
IF(FP_FLOAT_VERSION) B [B==A] cTan A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCot -> B cTan cDup cInv  # TEST 10/sincos_tti
IF(FP_FLOAT_VERSION) B [B==A] cCsc A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSin -> B cCsc cDup cInv  # TEST 10/sincos_sis
IF(FP_FLOAT_VERSION) B [B==A] cSec A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCos -> B cSec cDup cInv  # TEST 10/sincos_cic
IF(FP_FLOAT_VERSION) B [B==A] cCot A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cTan -> B cCot cDup cInv  # TEST 10/sincos_tit
IF(FP_FLOAT_VERSION) cSinCos cDiv  -> cTan  # TEST 10/sincos_tan
IF(FP_FLOAT_VERSION) cSinCos cRDiv -> cCot

IF(FP_FLOAT_VERSION) B [B==A] cCos  A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cSin  C [IsCommutativeOrParamSwappableBinaryOpcode(C)] -> B cSinCos {GetParamSwappedBinaryOpcode(C)}   # TEST 99/59
IF(FP_FLOAT_VERSION) B [B==A] cCosh A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cSinh C [IsCommutativeOrParamSwappableBinaryOpcode(C)] -> B cSinhCosh {GetParamSwappedBinaryOpcode(C)} # TEST 99/59
IF(FP_FLOAT_VERSION) B [B==A] cSinh A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCosh -> B cSinhCosh
IF(FP_FLOAT_VERSION) B [B==A] cCos  A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cCsc cMul -> B cCot
IF(FP_FLOAT_VERSION) cSinhCosh cDiv   -> cTanh
IF(FP_FLOAT_VERSION) cSinhCosh cRDiv  -> cTanh cInv

IF(FP_FLOAT_VERSION) cSqr A [IsVarOpcode(A)]                      cSqr cAdd cSqrt -> A   cHypot  # TEST 10/xsqrysqrhypot
IF(FP_FLOAT_VERSION) cSqr A [IsVarOpcode(A)] B [IsUnaryOpcode(B)] cSqr cAdd cSqrt -> A B cHypot  # TEST 10/xsqryfsqrhypot