1 #include <cmath> 2 #include <cassert> 3 4 #include "codetree.hh" 5 #include "optimize.hh" 6 #include "opcodename.hh" 7 #include "grammar.hh" 8 #include "extrasrc/fptypes.hh" 9 10 #include "consts.hh" 11 #include "fparser.hh" 12 13 // There are several case statements in this file where we 14 // intentionally want to fall through, so let's not get warned about 15 // each one. 16 #ifdef __GNUC__ 17 #if (__GNUC__ > 6) 18 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" 19 #endif 20 #endif 21 22 #ifdef FP_SUPPORT_OPTIMIZER 23 24 using namespace FUNCTIONPARSERTYPES; 25 //using namespace FPoptimizer_Grammar; 26 27 namespace 28 { 29 using namespace FPoptimizer_CodeTree; 30 31 #define FactorStack std::vector /* typedef*/ 32 33 const struct PowiMuliType 34 { 35 unsigned opcode_square; 36 unsigned opcode_cumulate; 37 unsigned opcode_invert; 38 unsigned opcode_half; 39 unsigned opcode_invhalf; 40 } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt}, 41 iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) }; 42 43 template<typename Value_t> ParsePowiMuli(const PowiMuliType & opcodes,const std::vector<unsigned> & ByteCode,size_t & IP,size_t limit,size_t factor_stack_base,FactorStack<Value_t> & stack)44 Value_t ParsePowiMuli( 45 const PowiMuliType& opcodes, 46 const std::vector<unsigned>& ByteCode, size_t& IP, 47 size_t limit, 48 size_t factor_stack_base, 49 FactorStack<Value_t>& stack) 50 { 51 Value_t result(1); 52 while(IP < limit) 53 { 54 if(ByteCode[IP] == opcodes.opcode_square) 55 { 56 if(!isInteger(result)) break; 57 result *= 2; 58 ++IP; 59 continue; 60 } 61 if(ByteCode[IP] == opcodes.opcode_invert) 62 { 63 result = -result; 64 ++IP; 65 continue; 66 } 67 if(ByteCode[IP] == opcodes.opcode_half) 68 { 69 if(result > Value_t(0) && isEvenInteger(result)) 70 break; 71 result *= Value_t(0.5); 72 ++IP; 73 continue; 74 } 75 if(ByteCode[IP] == opcodes.opcode_invhalf) 76 { 77 if(result > Value_t(0) && isEvenInteger(result)) 78 break; 79 result *= Value_t(-0.5); 80 ++IP; 81 continue; 82 } 83 84 size_t dup_fetch_pos = IP; 85 Value_t lhs(1); 86 87 if(ByteCode[IP] == cFetch) 88 { 89 unsigned index = ByteCode[++IP]; 90 if(index < factor_stack_base 91 || size_t(index-factor_stack_base) >= stack.size()) 92 { 93 // It wasn't a powi-fetch after all 94 IP = dup_fetch_pos; 95 break; 96 } 97 lhs = stack[index - factor_stack_base]; 98 // Note: ^This assumes that cFetch of recentmost 99 // is always converted into cDup. 100 goto dup_or_fetch; 101 } 102 if(ByteCode[IP] == cDup) 103 { 104 lhs = result; 105 goto dup_or_fetch; 106 107 dup_or_fetch: 108 stack.push_back(result); 109 ++IP; 110 Value_t subexponent = ParsePowiMuli 111 (opcodes, 112 ByteCode, IP, limit, 113 factor_stack_base, stack); 114 if(IP >= limit || ByteCode[IP] != opcodes.opcode_cumulate) 115 { 116 // It wasn't a powi-dup after all 117 IP = dup_fetch_pos; 118 break; 119 } 120 ++IP; // skip opcode_cumulate 121 stack.pop_back(); 122 result += lhs*subexponent; 123 continue; 124 } 125 break; 126 } 127 return result; 128 } 129 130 template<typename Value_t> ParsePowiSequence(const std::vector<unsigned> & ByteCode,size_t & IP,size_t limit,size_t factor_stack_base)131 Value_t ParsePowiSequence 132 (const std::vector<unsigned>& ByteCode, size_t& IP, 133 size_t limit, size_t factor_stack_base) 134 { 135 FactorStack<Value_t> stack; 136 stack.push_back( Value_t(1) ); 137 return ParsePowiMuli(iseq_powi, ByteCode, IP, limit, factor_stack_base, stack); 138 } 139 140 template<typename Value_t> ParseMuliSequence(const std::vector<unsigned> & ByteCode,size_t & IP,size_t limit,size_t factor_stack_base)141 Value_t ParseMuliSequence 142 (const std::vector<unsigned>& ByteCode, size_t& IP, 143 size_t limit, size_t factor_stack_base) 144 { 145 FactorStack<Value_t> stack; 146 stack.push_back( Value_t(1) ); 147 return ParsePowiMuli(iseq_muli, ByteCode, IP, limit, factor_stack_base, stack); 148 } 149 150 template<typename Value_t> 151 class CodeTreeParserData 152 { 153 public: CodeTreeParserData(bool k_powi)154 explicit CodeTreeParserData(bool k_powi) 155 : stack(), clones(), keep_powi(k_powi) { } 156 Eat(size_t nparams,OPCODE opcode)157 void Eat(size_t nparams, OPCODE opcode) 158 { 159 CodeTree<Value_t> newnode; 160 newnode.SetOpcode(opcode); 161 162 std::vector<CodeTree<Value_t> > params = Pop(nparams); 163 newnode.SetParamsMove(params); 164 165 if(!keep_powi) 166 switch(opcode) 167 { 168 // asinh: log(x + sqrt(x*x + 1)) 169 //cAsinh [x] -> cLog (cAdd x (cPow (cAdd (cPow x 2) 1) 0.5)) 170 // Note: ^ Replacement function refers to x twice 171 172 // acosh: log(x + sqrt(x*x - 1)) 173 //cAcosh [x] -> cLog (cAdd x (cPow (cAdd (cPow x 2) -1) 0.5)) 174 175 // atanh: log( (1+x) / (1-x)) / 2 176 //cAtanh [x] -> cMul (cLog (cMul (cAdd 1 x) (cPow (cAdd 1 (cMul -1 x)) -1))) 0.5 177 178 // asin: atan2(x, sqrt(1-x*x)) 179 //cAsin[x] -> cAtan2 [x (cPow [(cAdd 1 (cMul (cPow [x 2] -1)) 0.5])] 180 181 // acos: atan2(sqrt(1-x*x), x) 182 //cAcos[x] -> cAtan2 [(cPow [(cAdd 1 (cMul (cPow [x 2] -1)) 0.5]) x] 183 184 // The hyperbolic functions themselves are: 185 // sinh: (exp(x)-exp(-x)) / 2 = exp(-x) * (exp(2*x)-1) / 2 186 //cSinh [x] -> cMul 0.5 (cPow [CONSTANT_EI x]) (cAdd [-1 (cPow [CONSTANT_2E x])]) 187 188 // cosh: (exp(x)+exp(-x)) / 2 = exp(-x) * (exp(2*x)+1) / 2 189 // cosh(-x) = cosh(x) 190 //cCosh [x] -> cMul 0.5 (cPow [CONSTANT_EI x]) (cAdd [ 1 (cPow [CONSTANT_2E x])]) 191 192 // tanh: sinh/cosh = (exp(2*x)-1) / (exp(2*x)+1) 193 //cTanh [x] -> (cMul (cAdd {(cPow [CONSTANT_2E x]) -1}) (cPow [(cAdd {(cPow [CONSTANT_2E x]) 1}) -1])) 194 case cTanh: 195 { 196 CodeTree<Value_t> sinh, cosh; 197 sinh.SetOpcode(cSinh); sinh.AddParam(newnode.GetParam(0)); sinh.Rehash(); 198 cosh.SetOpcode(cCosh); cosh.AddParamMove(newnode.GetParam(0)); cosh.Rehash(); 199 CodeTree<Value_t> pow; 200 pow.SetOpcode(cPow); 201 pow.AddParamMove(cosh); 202 pow.AddParam(CodeTreeImmed(Value_t(-1))); 203 pow.Rehash(); 204 newnode.SetOpcode(cMul); 205 newnode.SetParamMove(0, sinh); 206 newnode.AddParamMove(pow); 207 break; 208 } 209 210 // tan: sin/cos 211 //cTan [x] -> (cMul (cSin [x]) (cPow [(cCos [x]) -1])) 212 case cTan: 213 { 214 CodeTree<Value_t> sin, cos; 215 sin.SetOpcode(cSin); sin.AddParam(newnode.GetParam(0)); sin.Rehash(); 216 cos.SetOpcode(cCos); cos.AddParamMove(newnode.GetParam(0)); cos.Rehash(); 217 CodeTree<Value_t> pow; 218 pow.SetOpcode(cPow); 219 pow.AddParamMove(cos); 220 pow.AddParam(CodeTreeImmed(Value_t(-1))); 221 pow.Rehash(); 222 newnode.SetOpcode(cMul); 223 newnode.SetParamMove(0, sin); 224 newnode.AddParamMove(pow); 225 break; 226 } 227 228 case cPow: 229 { 230 const CodeTree<Value_t>& p0 = newnode.GetParam(0); 231 const CodeTree<Value_t>& p1 = newnode.GetParam(1); 232 if(p1.GetOpcode() == cAdd) 233 { 234 // convert x^(a + b) into x^a * x^b just so that 235 // some optimizations can be run on it. 236 // For instance, exp(log(x)*-61.1 + log(z)*-59.1) 237 // won't be changed into exp(log(x*z)*-61.1)*z^2 238 // unless we do this. 239 std::vector<CodeTree<Value_t> > mulgroup(p1.GetParamCount()); 240 for(size_t a=0; a<p1.GetParamCount(); ++a) 241 { 242 CodeTree<Value_t> pow; 243 pow.SetOpcode(cPow); 244 pow.AddParam(p0); 245 pow.AddParam(p1.GetParam(a)); 246 pow.Rehash(); 247 mulgroup[a].swap(pow); 248 } 249 newnode.SetOpcode(cMul); 250 newnode.SetParamsMove(mulgroup); 251 } 252 break; 253 } 254 255 // Should we change sin(x) into cos(pi/2-x) 256 // or cos(x) into sin(pi/2-x)? 257 // note: cos(x-pi/2) = cos(pi/2-x) = sin(x) 258 // note: sin(x-pi/2) = -sin(pi/2-x) = -cos(x) 259 default: break; 260 } 261 262 newnode.Rehash(!keep_powi); 263 /* 264 using namespace FPoptimizer_Grammar; 265 bool recurse = false; 266 while(ApplyGrammar(pack.glist[0], newnode, recurse)) // intermediate 267 { //std::cout << "Rerunning 1\n"; 268 newnode.FixIncompleteHashes(); 269 recurse = true; 270 } 271 */ 272 FindClone(newnode, false); 273 #ifdef DEBUG_SUBSTITUTIONS 274 std::cout << "POP " << nparams << ", " << FP_GetOpcodeName(opcode) 275 << "->" << FP_GetOpcodeName(newnode.GetOpcode()) 276 << ": PUSH "; 277 DumpTree(newnode); 278 std::cout <<std::endl; 279 DumpHashes(newnode); 280 #endif 281 stack.push_back(newnode); 282 } 283 EatFunc(size_t nparams,OPCODE opcode,unsigned funcno)284 void EatFunc(size_t nparams, OPCODE opcode, unsigned funcno) 285 { 286 CodeTree<Value_t> newnode = CodeTreeFuncOp<Value_t> (opcode, funcno); 287 std::vector<CodeTree<Value_t> > params = Pop(nparams); 288 newnode.SetParamsMove(params); 289 newnode.Rehash(false); 290 #ifdef DEBUG_SUBSTITUTIONS 291 std::cout << "POP " << nparams << ", PUSH "; 292 DumpTree(newnode); 293 std::cout << std::endl; 294 DumpHashes(newnode); 295 #endif 296 FindClone(newnode); 297 stack.push_back(newnode); 298 } 299 AddConst(const Value_t & value)300 void AddConst(const Value_t& value) 301 { 302 CodeTree<Value_t> newnode = CodeTreeImmed(value); 303 FindClone(newnode); 304 Push(newnode); 305 } 306 AddVar(unsigned varno)307 void AddVar(unsigned varno) 308 { 309 CodeTree<Value_t> newnode = CodeTreeVar<Value_t>(varno); 310 FindClone(newnode); 311 Push(newnode); 312 } 313 SwapLastTwoInStack()314 void SwapLastTwoInStack() 315 { 316 stack[stack.size()-1].swap( stack[stack.size()-2] ); 317 } 318 Dup()319 void Dup() 320 { 321 Fetch(stack.size()-1); 322 } 323 Fetch(size_t which)324 void Fetch(size_t which) 325 { 326 Push(stack[which]); 327 } 328 329 template<typename T> Push(T tree)330 void Push(T tree) 331 { 332 #ifdef DEBUG_SUBSTITUTIONS 333 std::cout << "PUSH "; 334 DumpTree(tree); 335 std::cout << std::endl; 336 DumpHashes(tree); 337 #endif 338 stack.push_back(tree); 339 } 340 PopNMov(size_t target,size_t source)341 void PopNMov(size_t target, size_t source) 342 { 343 stack[target] = stack[source]; 344 stack.resize(target+1); 345 } 346 PullResult()347 CodeTree<Value_t> PullResult() 348 { 349 clones.clear(); 350 CodeTree<Value_t> result(stack.back()); 351 stack.resize(stack.size()-1); 352 return result; 353 } Pop(size_t n_pop)354 std::vector<CodeTree<Value_t> > Pop(size_t n_pop) 355 { 356 std::vector<CodeTree<Value_t> > result(n_pop); 357 for(unsigned n=0; n<n_pop; ++n) 358 result[n].swap(stack[stack.size()-n_pop+n]); 359 #ifdef DEBUG_SUBSTITUTIONS 360 for(size_t n=n_pop; n-- > 0; ) 361 { 362 std::cout << "POP "; 363 DumpTree(result[n]); 364 std::cout << std::endl; 365 DumpHashes(result[n]); 366 } 367 #endif 368 stack.resize(stack.size()-n_pop); 369 return result; 370 } 371 GetStackTop() const372 size_t GetStackTop() const { return stack.size(); } 373 private: FindClone(CodeTree<Value_t> &,bool=true)374 void FindClone(CodeTree<Value_t> & /*tree*/, bool /*recurse*/ = true) 375 { 376 // Disabled: Causes problems in optimization when 377 // the same subtree is included in logical and non-logical 378 // contexts: optimizations applied to the logical one will 379 // mess up the non-logical one. 380 return; 381 /* 382 std::multimap<fphash_t, CodeTree>::const_iterator 383 i = clones.lower_bound(tree.GetHash()); 384 for(; i != clones.end() && i->first == tree.GetHash(); ++i) 385 { 386 if(i->second.IsIdenticalTo(tree)) 387 tree.Become(i->second); 388 } 389 if(recurse) 390 for(size_t a=0; a<tree.GetParamCount(); ++a) 391 FindClone(tree.GetParam(a)); 392 clones.insert(std::make_pair(tree.GetHash(), tree)); 393 */ 394 } 395 private: 396 std::vector<CodeTree<Value_t> > stack; 397 std::multimap<fphash_t, CodeTree<Value_t> > clones; 398 399 bool keep_powi; 400 401 private: 402 CodeTreeParserData(const CodeTreeParserData&); 403 CodeTreeParserData& operator=(const CodeTreeParserData&); 404 }; 405 406 template<typename Value_t> 407 struct IfInfo 408 { 409 CodeTree<Value_t> condition; 410 CodeTree<Value_t> thenbranch; 411 size_t endif_location; 412 IfInfo__anonbb570fb40111::IfInfo413 IfInfo(): condition(), thenbranch(), endif_location() { } 414 }; 415 } 416 417 namespace FPoptimizer_CodeTree 418 { 419 template<typename Value_t> GenerateFrom(const typename FunctionParserBase<Value_t>::Data & fpdata,bool keep_powi)420 void CodeTree<Value_t>::GenerateFrom( 421 const typename FunctionParserBase<Value_t>::Data& fpdata, 422 bool keep_powi) 423 { 424 std::vector<CodeTree<Value_t> > var_trees; 425 var_trees.reserve(fpdata.mVariablesAmount); 426 for(unsigned n=0; n<fpdata.mVariablesAmount; ++n) 427 { 428 var_trees.push_back( CodeTreeVar<Value_t> (n+VarBegin) ); 429 } 430 GenerateFrom(fpdata,var_trees,keep_powi); 431 } 432 433 template<typename Value_t> GenerateFrom(const typename FunctionParserBase<Value_t>::Data & fpdata,const std::vector<CodeTree> & var_trees,bool keep_powi)434 void CodeTree<Value_t>::GenerateFrom( 435 const typename FunctionParserBase<Value_t>::Data& fpdata, 436 const std::vector<CodeTree>& var_trees, 437 bool keep_powi) 438 { 439 const std::vector<unsigned>& ByteCode = fpdata.mByteCode; 440 const std::vector<Value_t>& Immed = fpdata.mImmed; 441 442 /*for(unsigned i=0; i<ByteCode.size(); ++i) 443 fprintf(stderr, "by[%u/%u]=%u\n", i, (unsigned)ByteCode.size(), (unsigned) ByteCode[i]);*/ 444 445 #ifdef DEBUG_SUBSTITUTIONS 446 std::cout << "ENTERS GenerateFrom()\n"; 447 #endif 448 CodeTreeParserData<Value_t> sim(keep_powi); 449 std::vector<IfInfo<Value_t> > if_stack; 450 451 for(size_t IP=0, DP=0; ; ++IP) 452 { 453 after_powi: 454 while(!if_stack.empty() && 455 ( // Normal If termination rule: 456 if_stack.back().endif_location == IP 457 // This rule matches when cJumps are threaded: 458 || (IP < ByteCode.size() && ByteCode[IP] == cJump 459 && if_stack.back().thenbranch.IsDefined()) 460 )) 461 { 462 // The "else" of an "if" ends here 463 CodeTree elsebranch = sim.PullResult(); 464 sim.Push(if_stack.back().condition); 465 sim.Push(if_stack.back().thenbranch); 466 sim.Push(elsebranch); 467 sim.Eat(3, cIf); 468 if_stack.pop_back(); 469 } 470 if(IP >= ByteCode.size()) break; 471 472 unsigned opcode = ByteCode[IP]; 473 if((opcode == cSqr || opcode == cDup 474 || (opcode == cInv && !IsIntType<Value_t>::result) 475 || opcode == cNeg 476 || opcode == cSqrt || opcode == cRSqrt 477 || opcode == cFetch)) 478 { 479 // Parse a powi sequence 480 size_t was_ip = IP; 481 Value_t exponent = ParsePowiSequence<Value_t>( 482 ByteCode, IP, if_stack.empty() ? ByteCode.size() : if_stack.back().endif_location, 483 sim.GetStackTop()-1); 484 if(exponent != Value_t(1.0)) 485 { 486 //std::cout << "Found exponent at " << was_ip << ": " << exponent << "\n"; 487 sim.AddConst(exponent); 488 sim.Eat(2, cPow); 489 goto after_powi; 490 } 491 if(opcode == cDup 492 || opcode == cFetch 493 || opcode == cNeg) 494 { 495 Value_t factor = ParseMuliSequence<Value_t>( 496 ByteCode, IP, if_stack.empty() ? ByteCode.size() : if_stack.back().endif_location, 497 sim.GetStackTop()-1); 498 if(factor != Value_t(1.0)) 499 { 500 //std::cout << "Found factor at " << was_ip << ": " << factor << "\n"; 501 sim.AddConst(factor); 502 sim.Eat(2, cMul); 503 goto after_powi; 504 } 505 } 506 IP = was_ip; 507 } 508 if(OPCODE(opcode) >= VarBegin) 509 { 510 unsigned index = opcode-VarBegin; 511 /*std::fprintf(stderr, "IP=%u, opcode=%u, VarBegin=%u, ind=%u\n", 512 (unsigned)IP,(unsigned)opcode,(unsigned)VarBegin, (unsigned)index);*/ 513 sim.Push(var_trees[index]); 514 } 515 else 516 { 517 switch( OPCODE(opcode) ) 518 { 519 // Specials 520 case cIf: 521 case cAbsIf: 522 { 523 if_stack.resize(if_stack.size() + 1); 524 CodeTree res( sim.PullResult() ); 525 if_stack.back().condition.swap( res ); 526 if_stack.back().endif_location = ByteCode.size(); 527 IP += 2; // dp,sp for elsebranch are irrelevant. 528 continue; 529 } 530 case cJump: 531 { 532 CodeTree res( sim.PullResult() ); 533 if_stack.back().thenbranch.swap( res ); 534 if_stack.back().endif_location = ByteCode[IP+1]+1; 535 IP += 2; 536 continue; 537 } 538 case cImmed: 539 sim.AddConst(Immed[DP++]); 540 break; 541 case cDup: 542 sim.Dup(); 543 break; 544 case cNop: 545 break; 546 case cFCall: 547 { 548 unsigned funcno = ByteCode[++IP]; 549 assert(funcno < fpdata.mFuncPtrs.size()); 550 unsigned params = fpdata.mFuncPtrs[funcno].mParams; 551 sim.EatFunc(params, OPCODE(opcode), funcno); 552 break; 553 } 554 case cPCall: 555 { 556 unsigned funcno = ByteCode[++IP]; 557 assert(funcno < fpdata.mFuncParsers.size()); 558 const FunctionParserBase<Value_t>& p = 559 *fpdata.mFuncParsers[funcno].mParserPtr; 560 unsigned params = fpdata.mFuncParsers[funcno].mParams; 561 562 /* Inline the procedure call */ 563 /* Works because cPCalls can never recurse */ 564 std::vector<CodeTree> paramlist = sim.Pop(params); 565 CodeTree pcall_tree; 566 pcall_tree.GenerateFrom(*p.mData, paramlist); 567 sim.Push(pcall_tree); 568 break; 569 } 570 // Unary operators requiring special attention 571 case cInv: // already handled by powi_opt 572 //sim.Eat(1, cInv); 573 //break; 574 sim.AddConst(1); 575 sim.SwapLastTwoInStack(); 576 sim.Eat(2, cDiv); 577 break; 578 case cNeg: // already handled by powi_opt 579 sim.Eat(1, cNeg); 580 break; 581 sim.AddConst(0); 582 sim.SwapLastTwoInStack(); 583 sim.Eat(2, cSub); 584 break; 585 case cSqr: // already handled by powi_opt 586 //sim.Eat(1, cSqr); 587 //break; 588 sim.AddConst(2); 589 sim.Eat(2, cPow); 590 break; 591 // Unary functions requiring special attention 592 case cSqrt: // already handled by powi_opt 593 sim.AddConst( Value_t(0.5) ); 594 sim.Eat(2, cPow); 595 break; 596 case cRSqrt: // already handled by powi_opt 597 sim.AddConst( Value_t(-0.5) ); 598 sim.Eat(2, cPow); 599 break; 600 case cCbrt: 601 sim.AddConst(Value_t(1) / Value_t(3)); 602 sim.Eat(2, cPow); 603 break; 604 case cDeg: 605 sim.AddConst(fp_const_rad_to_deg<Value_t>()); 606 sim.Eat(2, cMul); 607 break; 608 case cRad: 609 sim.AddConst(fp_const_deg_to_rad<Value_t>()); 610 sim.Eat(2, cMul); 611 break; 612 case cExp: 613 if(keep_powi) goto default_function_handling; 614 sim.AddConst(fp_const_e<Value_t>()); 615 sim.SwapLastTwoInStack(); 616 sim.Eat(2, cPow); 617 break; 618 case cExp2: // from fpoptimizer 619 if(keep_powi) goto default_function_handling; 620 sim.AddConst(2.0); 621 sim.SwapLastTwoInStack(); 622 sim.Eat(2, cPow); 623 break; 624 case cCot: 625 sim.Eat(1, cTan); 626 if(keep_powi) { sim.Eat(1, cInv); break; } 627 sim.AddConst(-1); 628 sim.Eat(2, cPow); 629 break; 630 case cCsc: 631 sim.Eat(1, cSin); 632 if(keep_powi) { sim.Eat(1, cInv); break; } 633 sim.AddConst(-1); 634 sim.Eat(2, cPow); 635 break; 636 case cSec: 637 sim.Eat(1, cCos); 638 if(keep_powi) { sim.Eat(1, cInv); break; } 639 sim.AddConst(-1); 640 sim.Eat(2, cPow); 641 break; 642 case cInt: // int(x) = floor(x + 0.5) 643 #ifndef __x86_64 644 if(keep_powi) { sim.Eat(1, cInt); break; } 645 #endif 646 sim.AddConst( Value_t(0.5) ); 647 sim.Eat(2, cAdd); 648 sim.Eat(1, cFloor); 649 break; 650 case cLog10: 651 sim.Eat(1, cLog); 652 sim.AddConst(fp_const_log10inv<Value_t>()); 653 sim.Eat(2, cMul); 654 break; 655 case cLog2: 656 sim.Eat(1, cLog); 657 sim.AddConst(fp_const_log2inv<Value_t>()); 658 sim.Eat(2, cMul); 659 break; 660 case cLog2by: // x y -> log(x)*CONSTANT_L2I*y 661 sim.SwapLastTwoInStack(); // y x 662 sim.Eat(1, cLog); // y log(x) 663 sim.AddConst(fp_const_log2inv<Value_t>()); // y log(x) CONSTANT_L2I 664 sim.Eat(3, cMul); // y*log(x)*CONSTANT_L2I 665 break; 666 case cHypot: // x y -> sqrt(x*x + y*y) 667 sim.AddConst(2); 668 sim.Eat(2, cPow); // x y^2 669 sim.SwapLastTwoInStack(); 670 sim.AddConst(2); 671 sim.Eat(2, cPow); // y^2 x^2 672 sim.Eat(2, cAdd); // y^2 + x^2 673 sim.AddConst( Value_t(0.5) ); 674 sim.Eat(2, cPow); // (y^2 + x^2)^0.5 675 break; 676 case cSinCos: 677 sim.Dup(); 678 sim.Eat(1, cSin); 679 sim.SwapLastTwoInStack(); 680 sim.Eat(1, cCos); 681 break; 682 case cSinhCosh: 683 sim.Dup(); 684 sim.Eat(1, cSinh); 685 sim.SwapLastTwoInStack(); 686 sim.Eat(1, cCosh); 687 break; 688 //case cLog: 689 // sim.Eat(1, cLog2); 690 // sim.AddConst(fp_const_log2<Value_t>()); 691 // sim.Eat(2, cMul); 692 // break; 693 // Binary operators requiring special attention 694 case cRSub: // from fpoptimizer 695 sim.SwapLastTwoInStack(); 696 // Passthru to cSub 697 case cSub: 698 if(keep_powi) { sim.Eat(2, cSub); break; } 699 sim.AddConst(-1); 700 sim.Eat(2, cMul); // -x is x*-1 701 sim.Eat(2, cAdd); // Minus is negative adding 702 break; 703 case cRDiv: // from fpoptimizer 704 sim.SwapLastTwoInStack(); 705 // Passthru to cDiv 706 case cDiv: 707 if(keep_powi || IsIntType<Value_t>::result) 708 { 709 sim.Eat(2, cDiv); 710 break; 711 } 712 sim.AddConst(-1); 713 sim.Eat(2, cPow); // 1/x is x^-1 714 sim.Eat(2, cMul); // Divide is inverse multiply 715 break; 716 // Binary operators not requiring special attention 717 case cAdd: case cMul: 718 case cMod: case cPow: 719 case cEqual: case cLess: case cGreater: 720 case cNEqual: case cLessOrEq: case cGreaterOrEq: 721 case cAnd: case cOr: 722 case cAbsAnd: case cAbsOr: 723 sim.Eat(2, OPCODE(opcode)); 724 break; 725 // Unary operators not requiring special attention 726 case cNot: 727 case cNotNot: // from fpoptimizer 728 case cAbsNot: 729 case cAbsNotNot: 730 sim.Eat(1, OPCODE(opcode)); 731 break; 732 // Special opcodes generated by fpoptimizer itself 733 case cFetch: 734 sim.Fetch(ByteCode[++IP]); 735 break; 736 case cPopNMov: 737 { 738 unsigned stackOffs_target = ByteCode[++IP]; 739 unsigned stackOffs_source = ByteCode[++IP]; 740 sim.PopNMov(stackOffs_target, stackOffs_source); 741 break; 742 } 743 744 default: 745 default_function_handling:; 746 unsigned funcno = opcode-cAbs; 747 assert(funcno < FUNC_AMOUNT); 748 const FuncDefinition& func = Functions[funcno]; 749 sim.Eat(func.params, OPCODE(opcode)); 750 break; 751 } 752 } 753 } 754 Become(sim.PullResult()); 755 #ifdef DEBUG_SUBSTITUTIONS 756 std::cout << "Produced tree:\n"; 757 DumpTreeWithIndent(*this); 758 #endif 759 } 760 } 761 762 /* BEGIN_EXPLICIT_INSTANTATION */ 763 #include "instantiate.hh" 764 namespace FPoptimizer_CodeTree 765 { 766 #define FP_INSTANTIATE(type) \ 767 template \ 768 void CodeTree<type>::GenerateFrom( \ 769 const FunctionParserBase<type>::Data& fpdata, \ 770 bool keep_powi); 771 FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) 772 #undef FP_INSTANTIATE 773 } 774 /* END_EXPLICIT_INSTANTATION */ 775 776 #endif 777