1# This datafile documents all the possible optimizations that the optimizer can/should do.
2# It is parsed by the parser described in fpoptimizer_grammar_gen.y, which
3# is compiled into C++ code in fpoptimizer_grammar_gen.cc. The parser produces
4# a C++ file, fpoptimizer_grammar.cc , which lists the grammar rules in tabular
5# format. The grammar rules are utilized by fpoptimizer_optimize.cc , which
6# matches the function trees into the rules and performing those replacements
7# which can be performed.
8#
9# Copyright 2010 Joel Yliluoma, written specifically
10#               for Warp's Function Parser (fparser).
11#
12
13#   asinh: log(x + sqrt(x*x + 1))
14#   acosh: log(x + sqrt(x*x - 1))
15#   atanh: log( (1+x) / (1-x)) / 2
16#   asin: atan2(x, sqrt(1-x*x))     Complex: -i*log(i*x + sqrt(1 - x*x))
17#   acos: atan2(sqrt(1-x*x), x)     Complex: -i*log(x + i*sqrt(1 - x*x))
18#   atan:                           Complex: -0.5i * log( (1+i*x) / (1-i*x) )
19#   atan2: atan(y/x)
20#        = 2*atan(y/(sqrt(x^2+y^2) + x))
21#   sin:                            Complex: (exp(i*x) - exp(-i*x)) / (2i)
22#   cos:                            Complex: (exp(i*x) + exp(-i*x)) / (2)
23#   tan: sin/cos                    Complex: (i-i*exp(2i*x)) / (exp(2i*x)+1)
24#   sinh: (exp(x)-exp(-x)) / 2
25#       = exp(-x) * (exp(2*x)-1) / 2
26#   cosh: (exp(x)+exp(-x)) / 2
27#       = exp(-x) * (exp(2*x)+1) / 2
28#   tanh: sinh/cosh
29#       = (exp(2*x)-1) / (exp(2*x)+1)
30#   log10: log/CONSTANT_L10I
31#   log2: log/CONSTANT_L2I
32#   sqrt: pow(x, 0.5)
33#   exp: pow(CONSTANT_E, x)
34#   int: floor(x + 0.5)
35
36# Substitution rule syntax:
37#
38# %token NUMERIC_CONSTANT     # literals such as 0, 1, 1.5 or CONSTANT_DR, CONSTANT_L10I
39# %token NAMEDHOLDER_TOKEN    # placeholders such as x, y, a, b
40# %token RESTHOLDER_TOKEN     # placeholders such as <1>, <2>, <7>
41# %token IMMEDHOLDER_TOKEN    # placeholders % and &
42# %token BUILTIN_FUNC_NAME    # such as COS, CEIL, POW, +, *, MIN, MAX
43# %token OPCODE_TOKEN         # opcodes such as cCos, cMul
44# %token UNARY_TRANSFORMATION # /, -, !  # inverts/negates/inverts the param
45# %token PARAM_CONSTRAINT     # parameter constraint specifier:
46#                                 @E  = Even integer only
47#                                 @O  = Odd integer only
48#                                 @I  = Integer only
49#                                 @F  = (Float) non-integer only
50#                                 @L  = Logical operation (something that only yields 0 or 1)
51#                                 @P  = Positive only (also zero)
52#                                 @N  = Negative only
53#                                 @Q  = Only those where positive/negative not known
54#                                 @1  = value evaluating to +1 or -1 only
55#                                 @M  = (Multiple) value NOT evaluating to +1 or -1
56#                                 @C  = Const (x@C is similar to % and &)
57#                                 @V  = Explicitly non-const
58# %token CONST_CONSTRAINT     # constraint applicable to a numeric literal:
59#                                 @R  = Radians: Constant is tested after normalizing to -pi/2..pi/2 range
60#                             # they can be applied to IMMEDHOLDER_TOKENs and NAMEDHOLDER_TOKENs
61# %token RULE_CONSTRAINT          @L  = Logical context only
62#                                       i.e. when the result of the tree will only
63#                                       only be evaluated using fabs(value) >= 0.5.
64#                                 @I  = This rule applies for integer types only
65#                                 @F  = This rule applies for non-integer types only
66#                                 @C  = This rule applies to complex types only
67#                                 @R  = This rule applies to real (non-complex) types only
68# %token NEWLINE              # newline
69#
70# %%
71#     grammar:
72#       grammar substitution
73#     | grammar rule_constraints substitution
74#     | grammar NEWLINE
75#     | /* empty */
76#     ;
77#
78#     substitution:
79#       function '->' param NEWLINE
80#       /* Entire function is changed into the particular param */
81#
82#     | function '->' function NEWLINE
83#       /* Entire function changes, the param_notinv_list is rewritten */
84#       /* NOTE: "p x -> o y"  is a shortcut for "p x -> (o y)"  */
85#
86#     | function ':'  paramlist NEWLINE
87#       /* The params provided are replaced with the new param_maybeinv_list */
88#     ;
89#
90#     function:
91#        OPCODE_TOKEN '[' paramlist ']'
92#        /* Match a function with opcode=opcode,
93#         * and the exact parameter list as specified
94#         */
95#        OPCODE_TOKEN '{' paramlist '}'
96#        /* Match a function with opcode=opcode,
97#         * and the exact parameter list in any order
98#         */
99#     |  OPCODE_TOKEN paramlist
100#        /* Match a function with opcode=opcode and the given way of matching params */
101#        /* There may be more parameters, don't care about them */
102#     ;
103#
104#     paramlist: /* left-recursive list of 0-n params with no delimiter */
105#       | paramlist param             /* param */
106#       | paramlist RESTHOLDER_TOKEN  /* a placeholder for all remaining params */
107#       | /* empty */
108#     ;
109#
110#     param:
111#        NUMERIC_CONSTANT const_constraints   /* particular immed */
112#     |  IMMEDHOLDER_TOKEN param_constraints  /* a placeholder for some immed */
113#     |  BUILTIN_FUNC_NAME '(' paramlist ')'  /* literal logarithm/sin/etc. of the provided immed-type params -- also sum/product/minimum/maximum */
114#     |  NAMEDHOLDER_TOKEN param_constraints  /* any expression, indicated by "x", "a" etc. */
115#     |  (' function ')' param_constraints    /* a subtree */
116#     |  UNARY_TRANSFORMATION param           /* the negated/inverted literal value of the param */
117#     ;
118#
119#     param_constraints: /* List of possible constraints to the given param, eg. odd,int,etc */
120#        param_constraints PARAM_CONSTRAINT
121#     |  /* empty */
122#     ;
123#
124#     rule_constraints: /* List of possible constraints to the given rule */
125#        rule_constraints RULE_CONSTRAINT
126#     |  /* empty */
127#     ;
128#
129#     const_constraints: /* List of possible constraints to the given numeric value */
130#        const_constraints CONST_CONSTRAINT
131#     |  /* empty */
132#     ;
133
134[LOGICAL]
135
136# Change cLessOrEq into cLess for less rules to check
137# This way, the only comparison opcodes appearing in cIf
138# are cEqual,cNEqual,cLess.
139# cNEqual could be changed to cEqual, but we see no need.
140cIf [(cLessOrEq[x y]) z a] : (cLess[y x]) a z
141cIf [(cGreaterOrEq[x y]) z a] : (cGreater[y x]) a z
142#cIf [(cNEqual[x y]) z a]   : (cEqual[y x]) a z
143
144cIf [(cLess[x y]) x y] -> cMin x y             # TEST 20/cmp*_minmax
145cIf [(cLess[x y]) y x] -> cMax x y             # TEST 20/cmp*_minmax
146#cIf [(cLessOrEq[x y]) x y] -> cMin x y         # TEST 20/cmp*_minmax
147#cIf [(cLessOrEq[x y]) y x] -> cMax x y         # TEST 20/cmp*_minmax
148cIf [(cGreater[x y]) y x] -> cMin x y          # TEST 20/cmp*_minmax
149cIf [(cGreater[x y]) x y] -> cMax x y          # TEST 20/cmp*_minmax
150#cIf [(cGreaterOrEq[x y]) y x] -> cMin x y      # TEST 20/cmp*_minmax
151#cIf [(cGreaterOrEq[x y]) x y] -> cMax x y      # TEST 20/cmp*_minmax
152
153#  abs(x) = (x<0 ? -x : x)
154#  abs(x) = x * (x<0 ? -1 : 1)
155#           x * (x<0 ? -5 : 5) = abs(x)*5
156#           x * ((x<0 ? -5 : 5) + y) = abs(x)*5 + x*y
157
158#x<0 ? -x : x   POS
159#x>0 ?  x : -x  POS
160#x<0 ?  x : -x  NEG
161#x>0 ? -x : x   NEG
162
163@R cMul (cIf [(cLess[x 0])    % -%]) x : (cAbs[x]) -%      # TEST 20/ifabs
164@R cMul (cIf [(cGreater[x 0]) % -%]) x : (cAbs[x])  %      # TEST 20/ifabs
165
166@R cMul (cAdd (cIf [(cLess[x 0])    % -%]) <1>) x : (cAdd (cMul (cAbs[x]) -%) (cMul x (cAdd <1>)))  # TEST 20/ifabs
167@R cMul (cAdd (cIf [(cGreater[x 0]) % -%]) <1>) x : (cAdd (cMul (cAbs[x])  %) (cMul x (cAdd <1>)))  # TEST 20/ifabs
168
169cMul % (cIf [x & z@C]) : (cIf [x *(% &) *(% z@C)])       # TEST 20/if_join_mul2, ifabs
170cAdd % (cIf [x & z@C]) : (cIf [x +(% &) +(% z@C)])       # TEST 20/if_join_add2
171
172@R cIf [(cGreater[x 0])     (cFloor[x]) (cCeil[x])] -> cTrunc x  # TEST 20/trunc_from_if
173#@R cIf [(cGreaterOrEq[x 0]) (cFloor[x]) (cCeil[x])] -> cTrunc x # TEST 20/trunc_from_if
174@R cIf [(cLess[x 0])     (cCeil[x]) (cFloor[x])] -> cTrunc x     # TEST 20/trunc_from_if
175#@R cIf [(cLessOrEq[x 0]) (cCeil[x]) (cFloor[x])] -> cTrunc x    # TEST 20/trunc_from_if
176
177cAdd (cIf[x y z]) (cIf[x a b]) : (cIf [x (cAdd y a) (cAdd z b)]) # TEST 20/if_join_add
178cMul (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMul y a) (cMul z b)]) # TEST 20/if_join_mul
179cAnd (cIf[x y z]) (cIf[x a b]) : (cIf [x (cAnd y a) (cAnd z b)]) # TEST 20/if_join_and
180cOr  (cIf[x y z]) (cIf[x a b]) : (cIf [x (cOr  y a) (cOr  z b)]) # TEST 20/if_join_or
181@R cMin (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMin y a) (cMin z b)]) # TEST 20/if_join_min
182@R cMax (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMax y a) (cMax z b)]) # TEST 20/if_join_max
183
184@R cAnd (cNot[x]) (cNot[y]) : (cNot [(cOr  x y)]) # TEST 20/nor2, nor2plus, nor3
185@R cOr  (cNot[x]) (cNot[y]) : (cNot [(cAnd x y)]) # TEST 20/nand2, nand2plus, nand3
186
187@R cAnd (cNot[z]) (cIf[x (cNot[y]) %@L]) : (cNot [(cOr  z (cIf[x y (cNot[%])]))])
188@R cOr  (cNot[z]) (cIf[x (cNot[y]) %@L]) : (cNot [(cAnd z (cIf[x y (cNot[%])]))])
189
190@R cAnd (cNot[z]) (cIf[x %@L (cNot[y])]) : (cNot [(cOr  z (cIf[x (cNot[%]) y]))])
191@R cOr  (cNot[z]) (cIf[x %@L (cNot[y])]) : (cNot [(cAnd z (cIf[x (cNot[%]) y]))])
192
193# From logic, follows that...
194#   (a==b) & (b==c) & (a==c) -- one of these is redundant
195cAnd (cEqual[x y]) (cEqual[y z]) (cEqual[x z])  : (cEqual[x y]) (cEqual[y z])
196# Note: ^ Replacement function refers to y twice
197
198# !x = abs(x) < 0.5
199# Thus, !(x*2) = abs(x) < 0.5/2
200# Note: Due to range-based optimizations, % can never be 0 here. These are safe.
201@R @F cGreater  [% (cAbs[x])] -> cNot[(cMul x 0.5 /%)]      # TEST 20/absnzlt
202@R @F cLessOrEq [% (cAbs[x])] -> cNotNot[(cMul x 0.5 /%)]   # TEST 20/absnzge
203
204# abs(x) > 0  -->  abs(x) != 0  -->  x != 0
205@R cEqual    [0 (cAbs[x])] : x 0              # TEST 20/abseq0
206@R cNEqual   [0 (cAbs[x])] : x 0              # TEST 20/absneq0
207
208@I cEqual    [0 x]      -> cNot [x]        # TEST 20/eq0
209@I cNEqual   [0 x]      -> cNotNot [x]     # TEST 20/neq0
210@I cEqual    [1 x@L]    -> x               # TEST 20/eq1
211@I cNEqual   [1 x@L]  	-> cNot [x]        # TEST 20/neq1
212@I cNot    [(cAdd % <1>)] -> cEqual  -% (cAdd <1>)  # TEST 20/xaddnot
213@I cNotNot [(cAdd % <1>)] -> cNEqual -% (cAdd <1>)  # TEST 20/xaddnotnot
214@R @I cLess        [0 (cAbs[x])] -> cNotNot [x]     # TEST 20/gt0_abs
215@R @I cLessOrEq    [1 (cAbs[x])] -> cNotNot [x]     # TEST 20/ge1_abs
216@R @I cGreater     [1 (cAbs[x])] -> cNot [x]        # TEST 20/gt1_abs
217@R @I cGreaterOrEq [0 (cAbs[x])] -> cNot [x]        # TEST 20/ge0_abs
218
219cIf [x 1 0] -> cNotNot [x]         # TEST 20/if10 (factor 1)
220cIf [x 0 1] -> cNot [x]            # TEST 20/if10 (factor 10)
221cAbsIf [x 1 0] -> cAbsNotNot [x]   # TEST 20/if10 (factor 100)
222cAbsIf [x 0 1] -> cAbsNot [x]      # TEST 20/if10 (factor 1000)
223
224# In logical contexts:
225@R @L cMul %@N            : -%   # TEST 20/l_mulneg
226@R @L cMul (cAbs[x])      : x    # TEST 20/l_mulabs
227@R @L cNotNot [x]         -> x   # TEST 20/l_notnot
228@R @L cAbs [x]            -> x   # TEST 20/l_abs
229
230#@R @F cAnd    (cLess[% x]) (cAbsNot[x])           : (cNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5))))
231#@R @F cAnd    (cLess[% x]) (cGreater[& x])        : (cNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5))))
232#@R @F cAbsAnd (cLess[% x]) (cGreater[& x])        : (cNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5))))
233#@R @F cAbsAnd (cLess[% x]) (cAbsNot[x])           : (cNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5))))
234#@R @F cOr    (cGreaterOrEq[% x]) (cLessOrEq[& x]) : (cNotNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5))))
235#@R @F cOr    (cGreaterOrEq[% x]) (cAbsNotNot[x])  : (cNotNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5))))
236#@R @F cAbsOr (cGreaterOrEq[% x]) (cLessOrEq[& x]) : (cNotNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5))))
237#@R @F cAbsOr (cGreaterOrEq[% x]) (cAbsNotNot[x])  : (cNotNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5))))
238# ^ these rules only work if & > %, and currently there's no way to verify it
239
240#@R cOr    (cAbsNot[x]) (cAbsNot[(cMul{x -1})])  : (cNot[x])
241#@R cAbsOr (cAbsNot[x]) (cAbsNot[(cMul{x -1})])  : (cNot[x])
242#@R cOr    (cAbsNotNot[x]) (cAbsNotNot[(cMul{x -1})])  : (cNotNot[x])
243#@R cAbsOr (cAbsNotNot[x]) (cAbsNotNot[(cMul{x -1})])  : (cNotNot[x])
244
245@R @F cAbsNotNot (cMul %@P <1>) -> (cGreaterOrEq[(cMul <1>) *(0.5 /%)])
246@R @F cAbsNotNot (cMul %@N <1>) -> (cLessOrEq[(cMul <1>)    *(0.5 /%)])
247
248# min(x, max(x, ...)) = x
249# max(x, min(x, ...)) = x
250cMin x (cMax x <1>)  : x    # TEST 20/mixedminmax
251cMax x (cMin x <1>)  : x    # TEST 20/mixedminmax
252
253[SIMPLIFY_EQUATION]
254
255@R cLess        [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
256@R cLessOrEq    [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
257@R cGreater     [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
258@R cGreaterOrEq [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
259@R cEqual       [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
260@R cNEqual      [(cAdd % <1>) &]  : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm
261
262@R cLess        [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
263@R cLessOrEq    [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
264@R cGreater     [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
265@R cGreaterOrEq [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
266@R cEqual       [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
267@R cNEqual      [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>)  (cAdd <2> & -%) # TEST 20/cmp*_add_imm
268
269@R cLess        [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
270@R cLessOrEq    [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
271@R cGreater     [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
272@R cGreaterOrEq [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
273@R cEqual       [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
274@R cNEqual      [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce
275
276@R @F cLess        [(cMul %@P <1>) &]  : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos
277@R @F cLessOrEq    [(cMul %@P <1>) &]  : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos
278@R @F cGreater     [(cMul %@P <1>) &]  : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos
279@R @F cGreaterOrEq [(cMul %@P <1>) &]  : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos
280@R @F cLess        [(cMul %@N <1>) &]  : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
281@R @F cLessOrEq    [(cMul %@N <1>) &]  : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
282@R @F cGreater     [(cMul %@N <1>) &]  : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
283@R @F cGreaterOrEq [(cMul %@N <1>) &]  : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
284@R @F cEqual       [(cMul % <1>) &]  : (cMul <1>) DIV(& %)   # TEST 20/cmp*_mul_imm_pos
285@R @F cNEqual      [(cMul % <1>) &]  : (cMul <1>) DIV(& %)   # TEST 20/cmp*_mul_imm_pos
286
287@R @F cLess        [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
288@R @F cLessOrEq    [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
289@R @F cGreater     [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
290@R @F cGreaterOrEq [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
291@R @F cLess        [(cMul %@N <1>) (cMul & <2>)] :  (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
292@R @F cLessOrEq    [(cMul %@N <1>) (cMul & <2>)] :  (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
293@R @F cGreater     [(cMul %@N <1>) (cMul & <2>)] :  (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
294@R @F cGreaterOrEq [(cMul %@N <1>) (cMul & <2>)] :  (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg
295@R @F cEqual       [(cMul % <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
296@R @F cNEqual      [(cMul % <1>) (cMul & <2>)] : (cMul <1>)  (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos
297
298#cLess        [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
299#cLessOrEq    [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
300#cGreater     [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
301#cGreaterOrEq [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
302#cEqual       [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
303#cNEqual      [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>)
304# ^ Note: This fails when x=0
305
306# Instead of x, generate (x^%)^(1/%) to further
307# delegate the possible responsibility of adding an abs() call.
308@R @F cLess        [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
309@R @F cLessOrEq    [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
310@R @F cGreater     [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
311@R @F cGreaterOrEq [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
312@R @F cEqual       [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
313@R @F cNEqual      [(cPow [x %@P]) &]  : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_*
314
315#@R @F cLess        [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
316#@R @F cLessOrEq    [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
317#@R @F cGreater     [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
318#@R @F cGreaterOrEq [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
319#@R @F cEqual       [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
320#@R @F cNEqual      [(cPow [x %@P]) (cPow [y &@P])]  : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos
321# ^ Note: This fails in "pow(x,2) op pow(y,3)" when x=-5, y=-6"
322#         TODO: Figure out how to workaround
323
324@R @F cLess        [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
325@R @F cLessOrEq    [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
326@R @F cGreater     [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
327@R @F cGreaterOrEq [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
328@R @F cEqual       [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
329@R @F cNEqual      [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base
330#  ^Note: This fails on exp(x)=exp(y) because of epsilon
331
332@R @F cLess        [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
333@R @F cLessOrEq    [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
334@R @F cGreater     [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
335@R @F cGreaterOrEq [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
336@R @F cEqual       [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
337@R @F cNEqual      [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base
338
339[REMOVE_REDUNDANT]
340
341@R cMul (cAbs[x]) (cAbs[y]) : (cAbs[(cMul x y)])  # TEST 20/mergemultiabs
342
343[EXTRACT1]
344
345# ceil(-x) = -floor(x); floor(-x) = -ceil(x)
346@R @F cFloor[(cMul -1 <1>)] -> cMul -1 (cCeil[(cMul <1>)])  # TEST 20/negfloor
347@R @F cCeil[(cMul -1 <1>)] -> cMul -1 (cFloor[(cMul <1>)])  # TEST 20/negceil
348
349[LOGARITHM]
350
351#### Logarithm optimizations
352# log(x^y) = y*log(x)
353#@F cLog [(cPow [x y])] -> cMul y (cLog[(cPow [(cPow [x y]) (cPow [y -1])])])
354# ^makes an infinite loop
355#@F cLog [(cPow [x@P y])] -> cMul y (cLog[x])
356#@F cLog [(cPow [x y@E])] -> cMul y (cLog [(cAbs [x])])
357# ^ Done in ConstantFolding()
358
359# CONSTANT_E^log(x) = x
360# CONSTANT_E^(log(x)*y) = x^y
361# Generalized as:  p^ log(x)    = x^ log(p)
362#                  p^(log(x)*y) = x^(log(p)*y)
363#
364# Warning: This loses the information that x > 0,
365#          that could be utilized in further optimizations.
366#
367@F cPow [%       (cLog[x])     ]   :     x        LOG(%)      # TEST 20/powimmlog
368@F cPow [% (cMul (cLog[x]) <1>)]   :     x  (cMul LOG(%) <1>) # TEST 20/powimmlog
369
370# Because log(exp(6)*x) = log(x)+6, we can also do this:
371#                  y^(log(x)+z)
372#                = y^(log(x*exp(z)))
373#                = (x*exp(z))^log(y)
374#                = x^log(y) * y^z
375#cPow [y (cAdd {(cLog[x]) &})] -> cMul (cPow [y &]) (cPow [x (cLog [y])])
376#
377# Probably beneficial to do it only when y is const,
378# though. Otherwise we only trade + for *, which is bad.
379# Also z should be const, otherwise we get two pows instead of one.
380@F cPow [% (cAdd {(cLog[x]) &})] -> cMul POW(% &) (cPow [x LOG(%)]) # TEST 20/powimmaddimmlog
381
382# x^(y*z) = (x*y)^z - done by ConstantFolding
383
384# z^(log(x)/log(z)*y) = x^y
385# Note: This rule fails when z=0, because log(0)=-inf and 0^x = 1
386@F cPow [z (cMul (cPow [(cLog[z])  -1]) (cLog[x])  <1>)] : x (cMul <1>)
387@F cPow [% (cMul /LOG(%)                (cLog[x])  <1>)] : x (cMul <1>)
388
389# log(x) + log(y) = log(x*y)
390@F cAdd (cLog[x])  (cLog[y])  : (cLog  (cMul [x y]))   # TEST 20/addlog
391
392# When x is const, the reverse is more beneficial
393#  i.e.  log(2*x) = log(x) + log(2)
394@F cLog  [(cMul %@P <1>)] -> cAdd (cLog  [(cMul <1>)]) LOG(%) # TEST 20/mulimmlog
395
396# log(x * z^y) = (log(x) / log(z) + y) * log(z)
397#              = log(x) + log(z)*y
398# Only worthwhile when z is an immed, otherwise we trade cPow for cLog
399# Note that when z = CONSTANT_E, this reduces rather nicely into log(x) + y
400@F cLog  [(cMul (cPow [% y]) <1>)]  -> cAdd (cMul [LOG(%) y]) (cLog [(cMul <1>)])
401
402#cLog  [(cMul (cPow [% y]) <1>)] -> cMul LOG(%) (cAdd [y (cMul (cLog [(cMul <1>)]) /LOG(%))])
403# When y=1, the reverse is more useful:
404@F cMul {% (cAdd {1 (cMul {(cLog  [x]) /%})})} -> cAdd (cLog  [x]) %
405
406
407[POW_TRICKS]
408
409###### Note: Before adding new rules (especially those which handle constant values),
410######       verify that it is not already done in ConstantFolding().
411
412# (x*5) ^ 2 = x^2 * (5^2)
413# (x*5)^-1  = 0.2/x , shrug
414cPow [(cMul %@P <1>) &]    -> cMul POW(% &)   (cPow [(cMul <1>) &]) # TEST 20/powmulimm_*
415# ^Limited to positive values so that (-4*x)^3.3 won't be changed into nan*x^3.3
416
417cPow [(cMul %@N <1>) &@E]  -> cMul POW(% &)   (cPow [(cMul <1>) &]) # TEST 20/powmulimm_*
418# ^This changes (-5*x)^2 into x^2 * (-5)^2 = x^2 * 25, but only when & is an even integer.
419
420# z^(x+y/log(z)) = z^x * exp(y)
421# Note: This rule fails when z=0, because log(0)=-inf and 0^z = 1
422@F cPow [z (cAdd <1> (cMul <2> (cPow [(cLog [z]) -1])))] -> cMul (cPow [z (cAdd <1>)]) (cPow [CONSTANT_E (cMul <2>)])
423#@F cPow [% (cAdd <1> (cMul <2> /LOG(%)))]    -> cMul (cPow [% (cAdd <1>)]) (cPow [CONSTANT_E (cMul <2>)])
424@F cPow [z (cAdd <1> (cPow [(cLog [z]) -1]))] -> cMul CONSTANT_E (cPow [z (cAdd <1>)])
425cPow [% (cAdd <1> &@M)]                    -> cMul POW(% &)   (cPow [% (cAdd <1>)])
426
427# x*y / (x*z) = y/z
428cMul (cPow [(cMul x <2>) -1]) x : (cPow [(cMul <2>) -1])
429
430# (x^y)^z        -> x^(y*z)
431#  safe when y is odd or float, or z is an integer, or x is not negative
432cPow [ (cPow[x   y@O])  z ]       : x (cMul [y z])
433cPow [ (cPow[x   y@F])  z ]       : x (cMul [y z])
434cPow [ (cPow[x   y])  z@I ]       : x (cMul [y z])
435cPow [ (cPow[x@P y])    z ]       : x (cMul [y z])
436
437# (x^y)^z where (y*z) makes an even integer could also be changed safely
438#cPow [(cPow [x y@I]) z@E]        : x (cMul [y z])
439
440# If pow() makes a signless value into a positive value, guard that fact with abs()
441cPow [ (cPow[x@Q y])@P z ]     : (cAbs [x]) (cMul [y z])
442
443# abs(x)^e -> x^e when e=even integer
444# This removes the abs() generated by the above rule when needless
445cPow [(cAbs[x]) y@E]            : x y
446cPow [(cMul (cAbs[x]) <1>) y@E] : (cMul  x <1>) y
447#cPow [(cMul %@N      <1>) y@E] : (cMul -% <1>) y
448# ^ already done by constantfolding
449
450# x^y *  (n + x^z) = n*x^y + x^(y+z)
451cMul (cPow [x y]) (cAdd {%@1 (cPow [x z])}) : (cAdd (cMul (cPow[x y]) %) (cPow[x (cAdd y z)]))
452# x^y *  (n + a^z) = n*x^y + x^(y+z*log(a)/log(x))
453cMul (cPow [& y]) (cAdd { 1 (cPow [x@P z])}) : (cAdd       (cPow[& y])     (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))]))
454cMul (cPow [& y]) (cAdd {-1 (cPow [x@P z])}) : (cAdd (cMul (cPow[& y]) -1) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))]))
455# exp(-x)*(exp(2*n)+1)*4
456#   becomes
457# exp(1) ^ (-x) * (exp(2) ^ n * 4 + 4)
458#   so we detect that here as well.
459cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])})  %}) : % (cAdd       (cPow[& y])     (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))]))
460cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])}) -%}) : % (cAdd (cMul (cPow[& y]) -1) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))]))
461
462# exp(2*y) - 2*exp(y) = (exp(x)-1)^2 - 1
463# exp(2*y) - 6*exp(y) = (exp(x)-3)^2 - 9
464# exp(2*y) + 6*exp(y) = (exp(x)+3)^2 - 9
465# note: x^(2*y) = (x^2)^y      (especially: exp(2*y) = exp(2)^y)
466cAdd (cMul {% (cPow[x          y  ])}) (cPow[x (cMul {    2  y})]) : (cPow[(cAdd (cPow[x       y   ]) *(% 0.5)) 2]) -POW(*(% 0.5) 2)
467cAdd (cMul {% (cPow[x (cMul {& y})])}) (cPow[x (cMul {*(& 2) y})]) : (cPow[(cAdd (cPow[x (cMul y &)]) *(% 0.5)) 2]) -POW(*(% 0.5) 2)
468cAdd (cMul {% (cPow[&          y  ])}) (cPow[POW(& 2)        y  ]) : (cPow[(cAdd (cPow[&       y   ]) *(% 0.5)) 2]) -POW(*(% 0.5) 2)
469
470[BINOMIAL]
471
472# Opcodes we will NOT find in the intermediate stage:
473#  Done by bytecode parser:
474#   Meta opcodes: cDup, cNop, cFetch, cPopNMov, cJump
475#   Meta opcodes: cVar, cImmed
476#   Implemented through cMul: cDiv, cRDiv, cInv, cSqr
477#   Implemented through cAdd: cSub, cRSub, cNeg
478#   Implemented through constant-multiplying: cDeg, cRad
479#   Implemented through cSin, cCos: cCot, cCsc, cSec, cTan
480#   Implemented through cPow: cSqrt, cExp
481#   Implemented through cLog: cLog2, cLog10
482#  Done by entry rules:
483#   Extracted: cAsinh, cAcosh, cAtanh
484#   Extracted: cSinh, cCosh, cTanh
485
486#### CONTINUED: Flattening the topology of add/mul/min/max/and/or groups
487
488# a^2 + a*b*X/Z + b^2 = (a+b)^2 + (X/Z-2)*(a*b)
489#cAdd (cPow[x 2]) (cPow[y 2]) (cMul x y <1>) : (cPow [(cAdd [x y]) 2]) (cMul [x y (cAdd [(cMul <1>) -2])])
490# For optimizing x^2+2*x*y+y^2:
491#  With this rule,    eval=0.287154 us, optimized = 0.0758879 us
492#  Without this rule, eval=0.314538 us, optimized = 0.0831386 us
493# For optimizing x^2+3*x*y+y^2:
494#  With this rule,    eval=0.295956 us, optimized = 0.0781288 us
495#  Without this rule, eval=0.300723 us, optimized = 0.075689 us
496# The benchmark results seem too varying, so it is hard to tell
497# whether this rule had some advantage. It _looks_ like it did
498# though, so better keep it, I suppose. -Bisqwit
499#
500# How about this?
501# (a+b+c)^2 = c^2 + 2*b*c + 2*a*c + b^2 + 2*a*b + a^2
502# Seems that it becomes:
503# a^2 + b^2 + c^2 + 2*((a+b)*c + a*b)
504# Is it worth adding rule for making that into (a+b+c)^2?
505# Too specific, I suppose.
506
507# These are the same as above, but work also if pow() is expanded
508# Note: It would work even with y and z instead of % and &, but we
509# limit into numeric literals for simplicity.
510cAdd (cMul (cPow[x %@P@I]) <1>)  (cMul (cPow[x &@I]) <2>) : (cMul (cPow[x MIN(% &)]) (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% &))]))  (cMul <2> (cPow[x (cAdd & -MIN(% &))]))))
511
512# Note:
513#   x^4*a + b*x^9  -> (x^5 * b + a)*x^4:  Eval time goes 0.046 -> 0.056
514#   x^5*a + b*x^11 -> (x^6 * b + a)*x^5:  Eval time goes 0.060 -> 0.049
515#     srsly, what?
516
517# x^2 + N*y - y^2 = x^2 - (y + N* 0.5)^2 + (N/2)^2
518# x^2 + N*y + y^2 = x^2 + (y + N*-0.5)^2 - (N/2)^2
519@F cAdd (cMul {-1 (cPow[x 2])}) (cMul{% x}) : (cMul {-1 (cPow[(cAdd x *(% -0.5)) 2])})  POW(*(% 0.5) 2)
520@F cAdd           (cPow[x 2])   (cMul{% x}) :           (cPow[(cAdd x *(% 0.5)) 2])    -POW(*(% 0.5) 2)
521
522#cAdd (cMul (cPow[x %@P@I]) <1>)  (cMul x             <2>) : (cMul (cPow[x MIN(% 1)]) (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% 1))]))  (cMul <2> (cPow[x (cAdd 1 -MIN(% 1))]))))
523
524
525# N*x^2 + M*x^2 = (x*sqrt(N) + y*sqrt(M))^2 - (2*sqrt(N*M))*x*y
526# N*x^2 + M*x*y = (x*sqrt(N) + y*0.5*M/sqrt(N))^2 - 0.25*M^2/N*y^2
527cAdd (cMul {%@P (cPow[x 2])}) (cMul {& x y}) : (cPow[(cAdd (cMul x SQRT(%)) (cMul y *(0.5 *(& /SQRT(%)))) ) 2]) (cMul (cPow[y 2]) *(*(-0.25 /%) POW(& 2)))
528
529# N*(x^2 + y^2) + M*x*y = N*(x+y)^2 + (2*N-M)*x*y
530cAdd (cMul {%@P (cAdd {(cPow[x 2]) (cPow[y 2])})}) (cMul {&@P x y}) : (cMul % (cPow[(cAdd x          y ) 2])) (cMul +(& *(-2 %)) x y)
531cAdd (cMul {%@P (cAdd {(cPow[x 2]) (cPow[y 2])})}) (cMul {&@N x y}) : (cMul % (cPow[(cAdd x (cMul -1 y)) 2])) (cMul +(& *( 2 %)) x y)
532
533# The replacement expanded below:
534#  (cMul (cPow[x MIN(% 1)])
535#        (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% 1))]))
536#              (cMul <2> (cPow[x (cAdd 1 -MIN(% 1))]))))
537#
538# Example: x^2*y  + x*z -> x^1  * (y*x^1 + z*x^0)
539# Example: x^6*y  + x*z -> x^1  * (y*x^5 + z*x^0)
540# Example: x^-6*y + x*z -> x^-6 * (y*x^0 + z*x^7) -- not good, so restricted with @P
541#
542# Example: x*z + 2*x^0.7 -> x^0.7 * (x^0.3 * z+2) -- not good, so also restricted with @I
543#
544
545# Note: These two rules should be done in constantfolding, but it's complicated.
546# 5*x - 5*y = 5*(x-y)
547cAdd (cMul %@P <1>) (cMul -% <2>) : (cMul % (cAdd (cMul <1>) (cMul -1 <2>))) # TEST 20/addnegmulpos
548# 5 - 5*x   = -5*(x-1)
549#cAdd %@M            (cMul -% <2>) : (cMul -% (cAdd (cMul <2>) -1))
550cAdd %@M            (cMul -% <2>) : (cMul % (cAdd 1 (cMul <2> -1)))   # TEST 20/addnegmulneg
551
552#    (5.1*x +      4.1*y      + z+w)*2
553# -> (5.1*2*x + 2*(4.1*y      + z+w))
554# -> (5.1*2*x +   (4.1*2*y + 2*(z+w)))
555cMul (cAdd (cMul %@M <1>) <2>) &  :  (cAdd (cMul % & <1>) (cMul & (cAdd <2>))) # TEST 20/addmulconstmul
556
557#    (2+x+y)*4 = 2*4 + 4*(x+y)
558cMul (cAdd %@M <1>) &  : (cAdd *(% &) (cMul & (cAdd <1>)))     # TEST 20/addconstmul
559
560
561[TRIGONOMETRIC]
562
563# sin(-x) = -sin(x)
564@F cSin [(cMul -1 <1>)] -> cMul -1 (cSin [(cMul <1>)])   # TEST 20/negsin
565# However,  -sin(5*x) better expressed as sin(-5*x)
566@F cMul -1 (cSin [(cMul %@N <1>)]) : (cSin [(cMul -% <1>)])
567# cos(-x) = cos(x)
568@F cCos [(cMul -1 <1>)] : (cMul <1>)                     # TEST 20/negcos
569@R @F cCos [(cAbs [x])] : x                                 # TEST 20/abscos
570
571# cos(pi/2 - x) = sin(x)
572@F cCos [(cAdd {CONSTANT_PIHALF@R (cMul %@N <1>)})] -> cSin[(cMul -% <1>)]         # TEST 20/trig_modulo
573# sin(pi/2 - x) = cos(x)
574@F cSin [(cAdd {CONSTANT_PIHALF@R (cMul %@N <1>)})] -> cCos[(cMul -% <1>)]         # TEST 20/trig_modulo
575# cos(x - pi/2) = cos(pi/2 - x) = sin(x)
576@F cCos [(cAdd -CONSTANT_PIHALF@R <1>)]            -> cSin[(cAdd <1>)]             # TEST 20/trig_modulo
577# sin(x - pi/2) = -sin(pi/2 - x) = -cos(x)
578@F cSin [(cAdd -CONSTANT_PIHALF@R <1>)]            -> cMul -1 (cCos[(cAdd <1>)])   # TEST 20/trig_modulo
579# sin(x + pi/2) = cos(x)
580@F cSin [(cAdd  CONSTANT_PIHALF@R <1>)]            -> cCos[(cAdd <1>)]             # TEST 20/trig_modulo
581# cos(x + pi/2) = sin(-x)
582@F cCos [(cAdd  CONSTANT_PIHALF@R <1>)]            -> cSin[(cMul -1 (cAdd <1>))]   # TEST 20/trig_modulo
583# sin(x + pi) = -sin(x)
584@F cSin [(cAdd  CONSTANT_PI@R <1>)]                -> cMul -1 (cSin[(cAdd <1>)])   # TEST 20/trig_modulo
585# cos(x + pi) = -cos(x)
586@F cCos [(cAdd  CONSTANT_PI@R    <1>)]             -> cMul -1 (cCos[(cAdd <1>)])   # TEST 20/trig_modulo
587#
588@F cCos [(cAdd 0@R <1>)]             -> cCos[(cAdd <1>)]
589@F cSin [(cAdd 0@R <1>)]             -> cSin[(cAdd <1>)]
590
591
592# sin(x)^2 + cos(x)^2 = 1
593@F cAdd  (cPow[ (cSin[x]) 2]) (cPow [(cCos[x]) 2]) : 1  # TEST 20/addsin2cos2
594# y-sin(x)^2 = cos(x)^2+(y-1)
595# y-cos(x)^2 = sin(x)^2+(y-1)
596@F cAdd 1 (cMul { -1 (cPow[ (cSin[x]) 2]) }) : (cPow [(cCos[x]) 2])  # TEST 20/sub1sin2
597@F cAdd 1 (cMul { -1 (cPow[ (cCos[x]) 2]) }) : (cPow [(cSin[x]) 2])  # TEST 20/sub1cos2
598
599# sin(x)*cos(y) + cos(x)*sin(y) = sin(x+y)
600# sin(x)*cos(y) - cos(x)*sin(y) = sin(x-y)
601# cos(x)*cos(y) + sin(x)*sin(y) = cos(x+y)
602# cos(x)*cos(y) - sin(x)*sin(y) = cos(x-y)
603
604@F cAdd  (cMul {(cSin[x]) (cCos[y])}) (cMul {(cCos[x]) (cSin[y])   }) :  (cSin [(cAdd[x           y]  )])
605@F cAdd  (cMul {(cSin[x]) (cCos[y])}) (cMul {(cCos[x]) (cSin[y]) -1}) :  (cSin [(cAdd[x (cMul [-1 y])])])
606@F cAdd  (cMul {(cCos[x]) (cCos[y])}) (cMul {(cSin[x]) (cSin[y])   }) :  (cCos [(cAdd[x           y]  )])
607@F cAdd  (cMul {(cCos[x]) (cCos[y])}) (cMul {(cSin[x]) (cSin[y]) -1}) :  (cCos [(cAdd[x (cMul [-1 y])])])
608
609#@F cAdd  (cMul {(cSin[x]) (cCos[y]) -1}) (cMul {(cCos[x]) (cSin[y]) -1}) : (cMul [-1 (cSin [(cAdd[x           y]  )]) ])
610#@F cAdd  (cMul {(cCos[x]) (cCos[y]) -1}) (cMul {(cSin[x]) (cSin[y]) -1}) : (cMul [-1 (cCos [(cAdd[x           y]  )]) ])
611# ^This one is redundant, subexpression grouping already catches it
612@F cAdd  (cMul {(cCos[x]) (cCos[y]) -1}) (cMul {(cSin[x]) (cSin[y])   }) : (cMul [-1 (cCos [(cAdd[x (cMul [-1 y])])]) ])
613#@F cAdd (cMul {(cSin[x]) (cCos[y]) -1}) (cMul {(cCos[x]) (cSin[y])   }) : (cMul [-1 (cSin [(cAdd[x (cMul [-1 y])])]) ])
614# ^This one is redudant: It just reaffirms that sin(x) = -sin(-x).
615
616# sin(asin(x)) = x
617@F cSin [(cAsin [x])] -> x  # TEST 20/asinsin
618
619# cos(acos(x)) = x
620@F cCos [(cAcos [x])] -> x  # TEST 20/acoscos
621
622# Note: asin(sin(x)) must not be converted, because
623# even though asin(sin(1.1)) = 1.1, asin(sin(1500)) != 1500.
624
625# atan(x/y) = atan2(x,y) -- do this only when we don't know whether y is zero.
626#                           If we know that y is nonzero, ConstantFolding
627#                           will revert this optimization.
628@R @F cAtan [(cMul {x (cPow [y@Q %@N])})] -> cAtan2 [x (cPow [y -%])]
629
630@R @F cAtan2 [(cMul  x@P   <1>) (cMul  x@P   <2>)]   : (cMul    <1>) (cMul    <2>)
631@R @F cAtan2 [(cMul  x@N@V <1>) (cMul  x@N@V <2>)]   : (cMul -1 <1>) (cMul -1 <2>)
632
633#        asin(x): atan2(x, (1-x*x)^0.5)
634#        asin(x): atan(x * (1-x*x)^-0.5) - automatically converted to the above.
635@R @F cAtan2 [x (cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5])] -> cAsin[x]
636
637#        acos(x): atan2((1-x*x)^0.5, x)
638#        acos(x): atan((1-x*x)^0.5 * x^-1) - automatically converted to the above.
639@R @F cAtan2 [(cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5]) x] -> cAcos[x]
640
641
642[REGENERATE_TAN]
643
644# sin(x)/cos(x) = tan(x)
645@F cMul        (cSin[x])     (cPow [(cCos[x]) -1]) :        (cTan[x])
646@F cMul (cPow [(cSin[x]) -1])       (cCos[x])      : (cPow [(cTan[x]) -1])
647# tan(x)*cos(x) = sin(x)
648@F cMul        (cTan[x])            (cCos[x])      :        (cSin[x])
649# sin(x)/tan(x) = cos(x)
650@F cMul (cPow [(cTan[x]) -1])       (cSin[x])      :        (cCos[x])
651@F cMul        (cTan[x])     (cPow [(cSin[x]) -1]) : (cPow [(cCos[x]) -1])
652
653# cos(x)^(-2) * sin(x) = tan(x)/cos(x)
654# sin(x)^2    / cos(x) = tan(x)*sin(x)
655
656# sin(-5*x) / cos(5*x) = tan(-5*x)
657@F cMul (cSin  [(cMul % <1>)]) (cPow [(cCos  [(cMul -% <1>)]) -1]) : (cTan  [(cMul % <1>)])
658
659# tan(-x) = -tan(x)
660@F cTan [(cMul -1 <1>)] -> cMul [-1 (cTan [(cMul <1>)])]
661
662# However,  -tan(5*x) better expressed as tan(-5*x)
663@F cMul -1 (cTan [(cMul %@N <1>)]) : (cTan [(cMul -% <1>)])
664
665# asin(tan(x)) = x / (1-x^2)^0.5
666#@F cAsin [(cTan [x])] -> cMul x (cPow [(cAdd (cMul (cPow [x 2]) -1) 1) -0.5])
667#
668# ^Disabled: Incorrectly produces error when x = 1
669
670# acos(tan(x)) = (1-x^2)^0.5 / x
671#@F cAcos [(cTan [x])] -> cMul (cPow [x -1]) (cPow [(cAdd (cMul (cPow [x 2]) -1) 1) 0.5])
672#
673# ^Disabled: Incorrectly produces error when x = 0
674#            Incorrectly produces negative numbers when acos does no such thing
675
676# cot(pi/2 - x) = 1/tan(pi/2 - x) = tan(x)
677#                   tan(pi/2 - x) = 1/tan(x)
678#                      reverse is probably better
679#                      but cot() isn't exactly bad, so keep it
680#cPow [(cTan[x]) -1] -> cTan [(cAdd [CONSTANT_PIHALF@R (cMul [-1 x])])]
681
682@F cMul (cTan [(cAdd {CONSTANT_PIHALF@R (cMul {-1 x})})]) (cTan [x]) : 1
683@F cMul (cTan [(cAdd {CONSTANT_PIHALF@R (cMul -1 <1>)})]) (cTan [(cMul <1>)]) : 1
684
685# tan(atan(x)) = x
686@F cTan [(cAtan [x])] -> x
687
688@F cTan [(cAtan2 [x y])] -> cMul x (cPow [y -1])
689
690
691[REGENERATE_TANH]
692
693# sinh(x)/cosh(x) = tanh(x)
694@F cMul        (cSinh[x])     (cPow [(cCosh[x]) -1]) :        (cTanh[x])
695@F cMul (cPow [(cSinh[x]) -1])       (cCosh[x])      : (cPow [(cTanh[x]) -1])
696# tanh(x)*cosh(x) = sinh(x)
697@F cMul        (cTanh[x])            (cCosh[x])      :        (cSinh[x])
698# sinh(x)/tanh(x) = cosh(x)
699@F cMul (cPow [(cTanh[x]) -1])       (cSinh[x])      :        (cCosh[x])
700@F cMul        (cTanh[x])     (cPow [(cSinh[x]) -1]) : (cPow [(cCosh[x]) -1])
701
702# sinh(-5*x) / cosh(5*x) = tanh(-5*x)
703@F cMul (cSinh [(cMul {% x})]) (cPow [(cCosh [(cMul {-% x})]) -1]) : (cTanh [(cMul % x)])
704@F cMul (cSin  [(cMul {% x})]) (cPow [(cCos  [(cMul {-% x})]) -1]) : (cTan  [(cMul % x)])
705#^ Note: Should use (cMul % <1>) instead of (cMul {% x}),
706#        but cannot, due to repeated restholders
707
708# tanh(-x) = -tanh(x)
709@F cTanh [(cMul -1 <1>)] -> cMul [-1 (cTanh [(cMul <1>)])]
710
711# However,  -tanh(5*x) better expressed as tanh(-5*x)
712@F cMul -1 (cTanh [(cMul %@N <1>)]) : (cTanh [(cMul -% <1>)])
713
714
715#        tanh(x) = (exp(2*x)-1) / (exp(2*x)+1)
716#      1/tanh(x) = (exp(2*x)+1) / (exp(2*x)-1)
717#            exp(2*x) = exp(2)^x
718#            y^x = exp(log(y)*x)
719#        tanh(x*log(y)/2) = (y^x-1) / (y^x+1)
720@F cMul (cAdd {-1 (cPow [% x])}) (cPow [(cAdd { 1 (cPow [% x])}) -1]) : (cTanh [(cMul x LOG(%) 0.5)])
721@F cMul (cAdd { 1 (cPow [% x])}) (cPow [(cAdd {-1 (cPow [% x])}) -1]) : (cPow [(cTanh [(cMul x LOG(%) 0.5)]) -1])
722
723
724[SINH_COSH_EXP_TRANSFORMATIONS]
725
726# sinh(-x) = -sinh(x)
727@F cSinh [(cMul -1 <1>)] -> cMul [-1 (cSinh [(cMul <1>)])] # TEST 20/negsinh
728# However,  -sinh(5*x) better expressed as sinh(-5*x)
729@F cMul -1 (cSinh [(cMul %@N <1>)]) : (cSinh [(cMul -% <1>)])
730# cosh(-x) = cosh(x)
731@F cCosh [(cMul -1 <1>)] : (cMul <1>)                    # TEST 20/negcosh
732@R @F cCosh [(cAbs [x])] : x                             # TEST 20/abscosh
733
734# x - 1/x = sinh(log(x))*2. However, this alone is a pessimal conversion.
735#@F cAdd  x  (cMul {-1 (cPow [       x   -1])})  : (cMul (cSinh [(cLog [x])]) 2)
736#@F cAdd <1> (cMul {-1 (cPow [(cAdd <1>) -1])})  : (cMul (cSinh [(cLog [(cAdd <1>)])]) 2)
737# So we add the requirement of cPow to it.
738# cLog(cPow()) reduces into optimal opcodes.
739#
740# sinh(x)*2 = (exp(x)-exp(-x))    -- note: exp(-x) = 1/exp(x)
741# cosh(x)*2 = (exp(x)+exp(-x))
742@F cAdd (cPow [& x]) (cMul { -1 (cPow [/& x]) }) : (cMul (cSinh [(cLog [(cPow [& x])])]) 2)
743@F cAdd (cPow [& x])            (cPow [/& x])    : (cMul (cCosh [(cLog [(cPow [& x])])]) 2)
744#@F cAdd (cPow [y x]) (cMul { -1 (cPow [y (cMul {x -1})]) }) : (cMul (cSinh [(cLog [(cPow [y x])])]) 2)
745#@F cAdd (cPow [y x])            (cPow [y (cMul {x -1})])    : (cMul (cCosh [(cLog [(cPow [y x])])]) 2)
746#@F cAdd (cPow [y %]) (cMul { -1 (cPow [y -%]) }) : (cMul (cSinh [(cLog [(cPow [y %])])]) 2)
747#@F cAdd (cPow [y %])            (cPow [y -%])    : (cMul (cCosh [(cLog [(cPow [y %])])]) 2)
748
749# Because sinh(-x) = -sinh(x),
750# sinh(x)*-2 = (exp(-x)-exp(x))
751@F cAdd (cMul {-1 (cPow [& x])})            (cPow [/& x])   : (cMul (cSinh [(cMul x LOG(&))]) -2)
752@F cAdd (cMul {% (cPow [& x])})  (cMul { -% (cPow [/& x])}) : (cMul (cSinh [(cMul x LOG(&))]) 2 %)
753@F cAdd (cMul {% (cPow [& x])})  (cMul {  % (cPow [/& x])}) : (cMul (cCosh [(cMul x LOG(&))]) 2 %)
754
755
756# exp(x)  = cosh(x)+sinh(x)
757@F cAdd        (cCosh [x])             (cSinh [x])      :        (cPow [CONSTANT_E  x])
758# -cosh(x) = sinh(x)-exp(x)
759#  cosh(x) = exp(x)-sinh(x)
760# -sinh(x) = cosh(x)-exp(x)
761#  sinh(x) = exp(x)-cosh(x)
762@F cAdd        (cSinh [x])      (cMul {(cPow [CONSTANT_E  x]) -1}) : (cMul -1 (cCosh [x]))
763@F cAdd (cMul {(cSinh [x]) -1})        (cPow [CONSTANT_E  x])      :          (cCosh [x])
764@F cAdd        (cCosh [x])      (cMul {(cPow [CONSTANT_E  x]) -1}) : (cMul -1 (cSinh [x]))
765@F cAdd (cMul {(cCosh [x]) -1})        (cPow [CONSTANT_E  x])      :          (cSinh [x])
766# exp(-x) = cosh(x)-sinh(x)
767# -exp(-x) = sinh(x)-cosh(x)
768@F cAdd        (cCosh [x])      (cMul {(cSinh [x]) -1}) :        (cPow [CONSTANT_EI x])
769@F cAdd (cMul {(cCosh [x]) -1})        (cSinh [x])      : (cMul {(cPow [CONSTANT_EI x]) -1})
770#  sinh(x) = cosh(x)-exp(-x)
771# -sinh(x) = exp(-x)-cosh(x)
772#  cosh(x) = exp(-x)+sinh(x)
773@F cAdd        (cCosh [x])      (cMul {(cPow [CONSTANT_EI x]) -1}) :          (cSinh [x])
774@F cAdd (cMul {(cCosh [x]) -1})        (cPow [CONSTANT_EI x])      : (cMul -1 (cSinh [x]))
775@F cAdd        (cSinh [x])             (cPow [CONSTANT_EI x])      :          (cCosh [x])
776
777
778# sinh(x)   = ((((E^2) ^ x) + -1) * ((E^-1) ^ x) * 0.5)
779# sinh(3*x) = ((((E^6) ^ x) + -1) * ((E^-3) ^ x) * 0.5)
780
781# sinh(3*x)*2              = (((E^6) ^ x) + -1) * ((E^-3) ^ x)
782# sinh(3*x)*2 / (E^-3) ^x = (((E^6) ^ x) + -1)
783# sinh(3*x)*2 * (E^ 3) ^x = (((E^6) ^ x) + -1)
784
785#@F cAdd {-1 (cPow [% x])}  : (cMul (cSinh [(cMul x LOG(%) 0.5)]) 2 (cPow [% (cMul x 0.5)]))
786#@F cAdd { 1 (cPow [% x])}  : (cMul (cCosh [(cMul x LOG(%) 0.5)]) 2 (cPow [% (cMul x 0.5)]))
787
788#@F cMul (cAdd {-1 (cPow [% x])}) (cPow [POW(% -0.5) x]) : (cSinh [(cMul x LOG(%) 0.5)]) 2
789#@F cMul (cPow [% x]) (cAdd {-1 (cPow [POW(% -2) x])})   : (cSinh [(cMul x LOG(%) 0.5)]) 2
790
791#   tanh(x) / cosh(x)
792# = sinh(x) / cosh(x)^2
793@F cMul (cSinh[x]) (cPow[(cCosh[x]) %]) : (cTanh[x]) (cPow[(cCosh[x]) +(% 1)])
794
795# sinh(log(x)) = 0.5*(x - 1/x)   (valid only for x>0)
796#@F cSinh [(cLog [x])] -> cMul 0.5 (cAdd x (cMul -1 (cPow [x -1])))
797
798
799[ASINH_ACOSH_ATANH_TRANSFORMATIONS]
800
801# sinh(acosh(x)) = sqrt(x^2 - 1)  (not a typo)
802# cosh(asinh(x)) = sqrt(x^2 + 1)  (not a typo)
803#  Not sure whether these are faster. They are more opcodes, but
804#  simpler. The rationale is in allowing for further optimizations.
805@F cSinh [(cAcosh [x])] -> cPow [(cAdd [(cPow [x 2]) -1]) 0.5] # TEST 20/acoshsinh
806@F cCosh [(cAsinh [x])] -> cPow [(cAdd [(cPow [x 2])  1]) 0.5] # TEST 20/asinhcosh
807
808#        asinh: log(x + sqrt(x*x + 1))
809#        exp(asinh): x + sqrt(x*x + 1)#
810# Disabled: On x86_64, "asinh(x)" is slower than "log(sqrt(x^2+1)+x)"
811@F cAdd (cPow [(cAdd {1 (cPow [         x 2])})  0.5]) x   :  (cPow [CONSTANT_E (cAsinh [x])])
812@F cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])})  0.5]) <1> -> (cPow [CONSTANT_E (cAsinh [(cAdd <1>)])])
813@F cAdd (cPow [(cAdd {1 (cPow [         x 2])}) -0.5]) x   :  (cPow [CONSTANT_EI (cAsinh [x])])
814@F cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) -0.5]) <1> -> (cPow [CONSTANT_EI (cAsinh [(cAdd <1>)])])
815
816
817#        acosh: log(x + sqrt(x*x - 1))
818#        exp(acosh): x + sqrt(x*x - 1)
819# Disabled: On x86_64, "acosh(x)" is slower than "log(sqrt(x^2-1)+x)"
820@F cLog  [(cAdd {(cPow [(cAdd {-1 (cPow [x 2])}) 0.5]) x})] -> cAcosh [x]
821#cAdd {(cPow [(cAdd {(cPow [x 2]) -1}) 0.5]) x} -> cPow [CONSTANT_E (cAcosh [x])]
822
823#        atanh(x):   log( (1+x) / (1-x)) / 2
824#        2*atanh(x): log( (1+x) / (1-x))
825@F cLog  [(cMul {(cAdd {1 x}) (cPow [(cAdd {1 (cMul {-1 x})}) -1])})] -> cMul [(cAtanh [x]) 2]
826
827#        atanh(y*x):   log( (1+y*x) / (1+(-1*y*x))) / 2
828#        2*atanh(y*x): log( (1+y*x) / (1+(-1*y*x)))
829
830#        atanh(5*x):   log( (1+5*x) / (1+(-5*x))) / 2
831#        2*atanh(5*x): log( (1+5*x) / (1+(-5*x)))
832
833#        atanh(y+x):   log( (1+y+x) / (1+(-1*(y+x)))) / 2
834#        2*atanh(y+x): log( (1+y+x) / (1+(-1*(y+x))))
835
836#@F cLog [(cMul {(cAdd {1 (cMul {% x})}) (cPow [(cAdd {1 (cMul {-% x})}) -1])})] -> cMul [(cAtanh [(cMul % x)]) 2]
837
838# atanh(x)              = log2( ((x*-2)+1) / ((x*2)-1) ) * log(2)/2
839# atanh(x)*2/log(2)     = log2( ((x*-2)+1) / ((x*2)-1) )
840# y^(atanh(x)*2/log(y)) = ((x*-y)+1) / ((x*y)-1)
841
842#@F cMul (cAdd {1 (cMul {x %})}) (cPow [(cAdd {-1 (cMul {x -%})}) -1]) : (cPow [% (cMul (cAtanh[x]) 2 /LOG(%))])
843#@F cMul (cPow [(cAdd {(cMul {x %}) &}) -1]) (cAdd {(cMul {x -%}) 2 -&}) : (cPow [-% (cMul (cAtanh[(cAdd (cMul -% x) & -1)]) 2 /LOG(-%))])
844
845
846
847[REGENERATE_HIGHLEVEL_OPCODES]
848
849# x * CONSTANT_RD = cDeg(x)
850@F cMul  CONSTANT_RD <1> -> cDeg [(cMul <1>)]
851
852# x * CONSTANT_DR = cRad(x)
853@F cMul  CONSTANT_DR <1> -> cRad [(cMul <1>)]
854
855@F cFloor [(cAdd 0.5 <1>)] -> cInt [(cAdd <1>)]
856
857# log(x) / CONSTANT_L10  = log10(x)
858@F cMul        (cLog [x])      CONSTANT_L10I  :        (cLog10 [x])
859@F cMul (cPow [(cLog [x]) -1]) CONSTANT_L10   : (cPow [(cLog10 [x]) -1])
860
861# log(x) / CONSTANT_L2 = log2(x)
862@F cMul        (cLog [x])      CONSTANT_L2I  :        (cLog2 [x])
863@F cMul (cPow [(cLog [x]) -1]) CONSTANT_L2   : (cPow [(cLog2 [x]) -1])
864
865#@F cPow [ (cSin[x]) %@N ] : (cCsc[x]) -%
866#@F cPow [ (cCos[x]) %@N ] : (cSec[x]) -%
867#@F cPow [ (cTan[x]) %@N ] : (cCot[x]) -%
868#  ^ DONE BY MAKEBYTECODE
869
870@F cPow [ (cAdd [(           cPow [x %@E]  )  (           cPow [y &@E]  )] ) 0.5 ] -> (cHypot [(cPow [      x              *(% 0.5)]) (cPow [      y              *(& 0.5)])])
871@F cPow [ (cAdd {(           cPow [x %@E]  )  (cMul {z@C (cPow [y &@E])})} ) 0.5 ] -> (cHypot [(cPow [      x              *(% 0.5)]) (cPow [(cMul y POW(z@C /&)) *(& 0.5)])])
872@F cPow [ (cAdd {(cMul {a@C (cPow [x %@E])})  (cMul {z@C (cPow [y &@E])})} ) 0.5 ] -> (cHypot [(cPow [(cMul x POW(a@C /%)) *(% 0.5)]) (cPow [(cMul y POW(z@C /&)) *(& 0.5)])])
873
874@F cMul (cExp[x]) (cExp[y])   : (cExp[(cAdd x y)])  # TEST 20/expexp_a 20/expexp_b 20/expexp_c
875@F cMul (cExp2[x]) (cExp2[y]) : (cExp2[(cAdd x y)]) # TEST 20/expexp_a 20/expexp_b 20/expexp_c
876
877[ABS_LOGICAL]
878
879@R cNot    [x@P] -> cAbsNot [x]        # TEST 20/posnot
880@R cNotNot [x@P] -> cAbsNotNot [x]     # TEST 20/posnotnot
881@R cAnd x@P y@P   : (cAbsAnd x y)
882@R cOr x@P y@P    : (cAbsOr  x y)
883@R cIf [x@P y z]    -> cAbsIf x y z
884
885#@R @L cAbsNotNot [x]   -> x
886#@R @L cIf [x (cAbsNotNot[y]) z] : x y z
887#@R @L cIf [x y (cAbsNotNot[z])] : x y z
888# ^ These are mistakes; (x>=0.5 & y) is not same as (x & y)
889
890@R cAbsIf [(cLessOrEq[x y]) z a] : (cLess[y x]) a z
891@R cAbsIf [(cNotNot[x]) y z]     -> cIf x y z
892
893@R @F cLess        [x 0.5] -> cAbsNot[x]     # TEST 20/lthalf
894@R @F cGreaterOrEq [x 0.5] -> cAbsNotNot[x]  # TEST 20/gehalf
895
896[NON_SHORTCUT_LOGICAL_EVALUATION]
897
898@R cOr  x@L y@L          : (cNotNot (cAdd x y))
899@R cOr  x@L (cAdd <1>)@P : (cNotNot (cAdd x <1>))
900@R cAnd x@L <1>         -> (cNotNot (cMul x (cAnd <1>)))
901# ^Conflicts with "cMul x@L y@L"
902
903[SHORTCUT_LOGICAL_EVALUATION]
904
905@R cMul x@L y@L : (cAnd x y) # TEST 20/muland2, muland2plus, muland3, mulnor2, mulnor2plus, mulnor3, mulandlt
906# ^Conflicts with "cAnd x@L <1>"
907
908# @L cAdd x@L@M <1> -> cOr x (cAdd <1>)
909# cMul x@L   <1>    -> cAnd x (cMul <1>)
910
911#cAdd x@L@M <1>    -> cAbsIf [x (cAdd <1> 1) (cAdd <1>)]
912@R cMul x@L   <1>    -> cAbsIf [x (cMul <1>) 0]
913
914cAnd x <1>      -> cIf [x   (cNotNot[(cAnd <1>)]) 0]
915cOr  x <1>      -> cIf [x 1 (cNotNot[(cOr <1>)])   ]
916cAbsAnd x <1>   -> cAbsIf [x   (cNotNot[(cAbsAnd <1>)]) 0]
917cAbsOr  x <1>   -> cAbsIf [x 1 (cNotNot[(cAbsOr  <1>)])  ]
918
919[IGNORE_IF_SIDEEFFECTS]
920
921# These rules are the polar opposite of what
922# is done in SHORTCUT_LOGICAL_EVALUATION.
923# Do not include them in the same optimization set.
924
925cIf [x y@L 0] -> cAnd x y
926cIf [x 0 y@L] -> cAnd (cNot[x]) y
927cIf [x y 0] -> cMul (cNotNot[x]) y
928cIf [x 0 y] -> cMul (cNot[x])    y
929
930cIf [x 1 y@L] -> cOr x y
931cIf [x y@L 1] -> cOr (cNot[x]) y
932cIf [x y 0] -> cMul (cNotNot[x]) y
933cIf [x 0 y] -> cMul (cNot[x])    y
934
935# These cannot be done because y may have side
936# effects or just be computation-heavy.
937
938[BASE2_EXPAND_COMPONENTS]
939
940#@F cLog   [x] -> cMul (cLog2[x]) CONSTANT_L2
941#@F cLog10 [x] -> cMul (cLog2[x]) CONSTANT_L10B
942#@F cExp   [x] -> cExp2 [(cMul CONSTANT_L2I x)]
943#@F cMul (cLog2by [x y]) <1>    ->  cLog2by [x (cMul y <1>)]
944@F cAsin  [x] -> cAtan2 x (cSqrt (cSub 1 (cSqr x)))
945@F cAcos  [x] -> cAtan2 (cSqrt (cSub 1 (cSqr x))) x
946@F cSinh  [x] -> cMul 0.5 (cSub (cExp[x]) (cInv (cExp[x])))
947@F cCosh  [x] -> cMul 0.5 (cSub (cExp[x]) (cInv (cExp[x])))
948@F cTanh  [x] -> cDiv (cAdd (cExp [(cMul x 2)]) -1) (cAdd (cExp [(cMul x 2)]) 1)
949@F cAtanh [x] -> cMul 0.5 (cLog (cDiv (cAdd 1 x) (cSub 1 x)))
950@F cAsinh [x] -> cLog (cAdd x (cSqrt (cAdd  1 (cSqr x))))
951@F cAcosh [x] -> cLog (cAdd x (cSqrt (cAdd -1 (cSqr x))))
952
953#@F cLog2  [x] -> cLog2by x 1
954#@F cMul (cPow[(cLog2[x])     %]) & : (cPow[(cLog2by[x POW(& /%)]) %])
955@F cMul (cPow[(cLog2by[x 1]) %]) & : (cPow[(cLog2by[x POW(& /%)]) %])
956
957##### Now construct the rounds of optimization:
958
959$optimize_round1:
960LOGICAL
961REMOVE_REDUNDANT
962LOGARITHM
963POW_TRICKS
964BINOMIAL
965TRIGONOMETRIC
966EXTRACT1
967
968$optimize_round2:
969LOGICAL
970REMOVE_REDUNDANT
971POW_TRICKS
972SINH_COSH_EXP_TRANSFORMATIONS
973ASINH_ACOSH_ATANH_TRANSFORMATIONS
974
975$optimize_round3:
976SIMPLIFY_EQUATION
977REGENERATE_TAN
978REGENERATE_TANH
979
980$optimize_round4:
981REGENERATE_HIGHLEVEL_OPCODES
982
983$optimize_recreate:
984REGENERATE_HIGHLEVEL_OPCODES
985BINOMIAL
986
987$optimize_ignore_if_sideeffects
988IGNORE_IF_SIDEEFFECTS
989LOGICAL
990
991$optimize_shortcut_logical_evaluation
992#SHORTCUT_LOGICAL_EVALUATION
993LOGICAL
994
995$optimize_nonshortcut_logical_evaluation
996NON_SHORTCUT_LOGICAL_EVALUATION
997LOGICAL
998
999$optimize_abslogical
1000ABS_LOGICAL
1001
1002#$optimize_base2_expand
1003#BASE2_EXPAND_COMPONENTS
1004#BINOMIAL
1005#POW_TRICKS
1006