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