diff -NaHudr fparser-jittest-1.3/Makefile fparser-jittest-1.4/Makefile
--- fparser-jittest-1.3/Makefile	2008-01-11 10:11:39.000000000 +0200
+++ fparser-jittest-1.4/Makefile	2008-01-15 01:11:30.000000000 +0200
@@ -1,12 +1,16 @@
 include Makefile.sets
 
 ARCHDIR=archives/
-ARCHNAME=fparser-jittest-1.3
-ARCHFILES=jittest.cc calculator.hh compiler.hh formula.hh \
-	interpreter.hh opcodes.hh \
-	Makefile.sets Makefile.sets.in configure
+ARCHNAME=fparser-jittest-1.4
+ARCHFILES=\
+		jittest.cc calculator.hh formula.hh \
+		interpreter.hh opcodes.hh \
+		compiler.hh \
+		compiler_trans.hh compiler_tree.hh compiler_synth.hh \
+		Makefile.sets Makefile.sets.in configure
 
 #OPTIM+=-fno-inline
+#OPTIM+=-inline-level=0
 
 jittest: jittest.o
 	$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
diff -NaHudr fparser-jittest-1.3/Makefile.sets fparser-jittest-1.4/Makefile.sets
--- fparser-jittest-1.3/Makefile.sets	2008-01-11 10:38:02.000000000 +0200
+++ fparser-jittest-1.4/Makefile.sets	2008-01-11 11:41:58.000000000 +0200
@@ -24,18 +24,18 @@
 
 #####
 # These options were set by ./configure
-# at Fri Jan 11 10:38:02 EET 2008
+# at Fri Jan 11 11:41:58 EET 2008
 # for Linux chii 2.6.23.1 #1 SMP Wed Oct 31 02:24:16 EET 2007 x86_64 GNU/Linux
 # To change, run ./configure again.
 #
-CC=gcc-4.2
-CPP=cpp-4.2
-CXX=g++-4.2
-OPTIM +=  -ftree-vectorize -ffast-math
-CPPFLAGS += 
-LDFLAGS += 
-WARNINGS +=  -Wall -Wundef -Wcast-qual -Wpointer-arith -Wconversion -Wwrite-strings -Wsign-compare -Wredundant-decls -Winit-self -Wextra -Wcast-align -Wformat
-CWARNINGS +=  -Waggregate-return -Wshadow -Winline -Wstrict-prototypes -Wmissing-prototypes
-CXXWARNINGS +=  -Woverloaded-virtual -Weffc++
+CC=icc
+CPP=icc
+CXX=icc
+OPTIM +=  -ipo
+CPPFLAGS +=  -w1 -inline-level=2
+LDFLAGS +=  -L/opt/intel/cce/10.1.008/bin/lib -lirc -lguide -lpthread -lstdc++
+WARNINGS += 
+CWARNINGS += 
+CXXWARNINGS += 
 
 
diff -NaHudr fparser-jittest-1.3/compiler.hh fparser-jittest-1.4/compiler.hh
--- fparser-jittest-1.3/compiler.hh	2008-01-11 11:40:48.000000000 +0200
+++ fparser-jittest-1.4/compiler.hh	2008-01-15 01:09:29.000000000 +0200
@@ -5,7 +5,7 @@
 #include <stdexcept>
 
 #ifdef unix
-# include <sys/mman.h>
+# include <sys/mman.h> /* for mprotect */
 #endif
 
 #ifndef PAGE_SIZE
@@ -14,39 +14,56 @@
 
 static const unsigned char SSE_NegPattern[16] = {0,0,0,0, 0,0,0,0x80, 0,0,0,0, 0,0,0,0};
 static const double FP_Constant_One = 1.0;
+static const double FP_Constant_Exp1 = 2.71828182845904523536028747135266249775724709369995;
 
-static int Log2up(unsigned long value)
-{
-    unsigned long res = 0;
-    while(value > (1LU << res)) ++res;
-    return res;
-}
-static int PopCount(unsigned long value) // population count
-{
-    static const int counts[16] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 };
-    int result = 0;
-    while(value > 0) { result += counts[value & 15]; value >>= 4; }
-    return result;
-}
+#include "compiler_tree.hh"
+#include "compiler_synth.hh"
+#include "compiler_trans.hh"
+
+/********
+
+  Here is what happens:
+  
+    Caller -> [bytecode] -> Compiler
+      caller passes bytecode to compiler.
+    
+    Compiler -> [bytecode] -> ByteCodeTranslator
+      compiler passes bytecode to bytecodetranslator.
+    
+    ByteCodeTranslator -> [codetree] -> CodeSynth
+      bytecodetranslator creates codetree and passes it to codesynth.
+    
+    CodeSynth -> [codebuffer] -> Compiler
+      codesynth creates codebuffer and compiler takes it.
+
+*********/
 
 class Compiler: public Calculator
 {
 public:
-    Compiler(const opcode* op, size_t n, bool UseSSE)
-        : CodeBuffer(), name("Compiler"), Code(0), CodePtr(0)
+    /* Constructor: constructs the JIT evaluator using
+     * the given bytecode, and a flag that indicates
+     * whether SSE should be used.
+     */
+    Compiler(const opcode* op, size_t n, bool UseSSE, bool RunCSE)
+        : name("Compiler"), CodeBuffer(), Code(0), CodePtr(0)
     {
         if(UseSSE)
         {
-            CodeSynth synth(true, *this);
-            SynthesizeCode_Generic(op, op+n, synth);
-            name = "Compiler (SSE)";
+            CodeSynth synth(true, CodeBuffer);
+            ByteCodeTranslator trans;
+            trans.SynthTo(synth, CodeBuffer, op, op+n, RunCSE);
+            name = "Compiler (SSE2)";
+            if(RunCSE) name += " + CSE";
         }
         else
         {
-            CodeSynth synth(false, *this);
-            SynthesizeCode_Generic(op, op+n, synth);
+            CodeSynth synth(false, CodeBuffer);
+            ByteCodeTranslator trans;
+            trans.SynthTo(synth, CodeBuffer, op, op+n, RunCSE);
             name = "Compiler (387)";
-        }        
+            if(RunCSE) name += " + CSE";
+        }
         
         Code = new unsigned char[ CodeBuffer.size() + PAGE_SIZE*3 ];
         
@@ -56,7 +73,10 @@
         
         std::memcpy(CodePtr, &CodeBuffer[0], CodeBuffer.size());
         
-        //fwrite(CodePtr, 1, CodeBuffer.size(), stdout);
+        /*
+        fwrite(CodePtr, 1, CodeBuffer.size(), stdout);
+        fflush(stdout);
+        */
         
     #ifdef unix
         mprotect(CodePtr, CodeBuffer.size(), PROT_EXEC|PROT_READ);
@@ -70,11 +90,13 @@
         delete[] Code;
     }
     
+    /* Identifies the calculator engine. */
     virtual std::string Identify() const
     {
         return name;
     }
     
+    /* Calculates the result. */
     virtual double Calc() const
     {
         typedef double (*JitCalc) ();
@@ -83,1069 +105,19 @@
     }
 
 private:
-    /*
-    
-    Synthesization algorithms:
-    
-        1) Just dummy translate code into asm, use FP
-        
-        2) Just dummy translate code into asm, use SSE
-        
-        3) Translate code into trees, combine identical
-           trees, allocate a register for each tree
-           and combine them in an arbitrary order
-           
-           i.e.    (3*x*x + 4*x*x) * y + x*x
-             ->   Z = x*x
-                  A = Z*3
-                  B = Z*4
-                  A = A+B
-                  A = A*y
-                  A = A+Z
-    */
-    
-    void SynthStackBegin(size_t stack_required)
-    {
-        #ifdef __x86_64
-            Synth(0x48, 0x81, 0xEC);
-            SynthI32(stack_required);  // sub rsp, n*8
-        #else
-            stack_required += 4; // improve aligning a bit                
-            Synth(0x81, 0xEC);
-            SynthI32(stack_required);  // sub esp, n*8
-        #endif
-    }
-    void SynthStackEnd(size_t stack_required)
-    {
-        #ifdef __x86_64
-            Synth(0x48, 0x81, 0xC4);
-            SynthI32(stack_required);  // add rsp, n*8
-        #else
-            Synth(0x81, 0xC4);
-            SynthI32(stack_required);  // add esp, n*8
-        #endif
-    }
-    
-    class CodeSynth
-    {
-    private:
-        bool SSE;
-        
-        struct Location
-        {
-            enum { ST, XMM, Mem, Stack } Loc;
-            //union {
-            int           st_no;
-            int           xmm_no;
-            int           stackoffs;
-            const double* memaddr;
-            bool          expected_reuse;
-            //};
-            
-            Location(): Loc(Mem), st_no(0),xmm_no(0),stackoffs(0),memaddr(0),
-                        expected_reuse(false) { }
-        };
-        std::vector<Location> stack; // calculator stack
-        std::set<int> Stack_Use;     // memory stack
-        int fpu_stack_depth;
-        int max_stack_use;
-        Compiler& com;
-        std::vector<const void*> basereg_use;
-        
-    public:
-        CodeSynth(bool sse, Compiler& comp)
-            : SSE(sse), stack(), Stack_Use(),
-              fpu_stack_depth(0),
-              max_stack_use(0),
-              com(comp),
-              basereg_use(16, (const void*)0)
-        {
-        }
-        
-        void GenBinaryOp(
-            int by_itself,
-            int sse1,int sse2,int sse3,
-            int fpu1self,int fpu2self,
-            int fpu1order,int fpu2order,
-            int fpu1swap,int fpu2swap,
-            int fpu1memorder,int fpu2memorder,
-            int fpu1memswap,int fpu2memswap)
-        {
-            Location& top = stack[stack.size()-1];
-            if(by_itself)
-            {
-                if(SSE && !(top.Loc == Location::ST && top.st_no == 0)
-                 && (sse1 || sse2 || sse3))
-                {
-                    if(by_itself == 2) // special: input->output
-                    {
-                        if(top.Loc == Location::Mem)
-                        {
-                            int xmm = GetFreeXMM();
-                            SynthXMM_Mem(sse1,(xmm&8)?0x44:0, sse2,sse3,(xmm&7)*8, top.memaddr, top.expected_reuse);
-                            top.Loc    = Location::XMM;
-                            top.xmm_no = xmm;
-                            return;
-                        }
-                        if(top.Loc == Location::Stack)
-                        {
-                            int xmm = GetFreeXMM();
-                            SynthXMM_Stack(sse1,(xmm&8)?0x44:0, sse2,sse3,(xmm&7)*8, top.stackoffs);
-                            Stack_Use.erase(top.stackoffs);
-                            top.Loc    = Location::XMM;
-                            top.xmm_no = xmm;
-                            return;
-                        }
-                    }
-                    int xmm = RequireXMM(0);
-                    SynthXMM_XMM(sse1,sse2,sse3, xmm, xmm);
-                }
-                else
-                {
-                    RequireST(0);
-                    com.Synth(fpu1self,fpu2self);
-                }
-            }
-            else
-            {
-                Location& prev= stack[stack.size()-2];
-
-                int whichpop = 0;
-                
-                if(SSE &&(!(top.Loc == Location::ST && top.st_no < 2)
-                       || !(prev.Loc== Location::ST && prev.st_no < 2))
-                 && (sse1 || sse2 || sse3))
-                {
-                    int cur = RequireXMM(1);
-                    if(top.Loc == Location::Mem)
-                        SynthXMM_Mem(sse1,(cur&8)?0x44:0, sse2,sse3,(cur&7)*8, top.memaddr, top.expected_reuse);
-                    else if(top.Loc == Location::Stack)
-                        SynthXMM_Stack(sse1,(cur&8)?0x44:0, sse2,sse3,(cur&7)*8, top.stackoffs);
-                    else // RequireXMM will spill if necessary 
-                        SynthXMM_XMM(sse1,sse2,sse3, cur, RequireXMM(0));
-                }
-                else
-                {
-                    /* Check for cases that one of the operands is in ST0
-                     * (or can be arranged there with little discomfort)
-                     * and the other is not in FPU stack
-                     */
-                    if(prev.Loc == Location::ST && top.Loc != Location::ST)
-                    {
-                        //When stack is:   stX
-                        //                 [mem]
-                        //Produce:
-                        //                 fxch stX    (if required)
-                        //                 fmul [mem]
-                        //Then pop top (0)
-                        Spill(top);
-                        switch(top.Loc)
-                        {
-                            case Location::Mem:
-                                MoveToST(prev, 0);
-                                SynthST_Mem(fpu1memorder,fpu2memorder, top.memaddr,top.expected_reuse);
-                                goto doneop;
-                            case Location::Stack:
-                                MoveToST(prev, 0);
-                                SynthST_Stack(fpu1memorder,fpu2memorder, top.stackoffs);
-                                goto doneop;
-                            default: break;
-                        }
-                    }
-                    if(prev.Loc != Location::ST)
-                    {
-                        //When stack is:   [mem]
-                        //                 stX
-                        //Produce:
-                        //                 fxch stX    (if required)
-                        //                 fmul [mem]
-                        //Then pop prev (1)
-                        Spill(prev);
-                        switch(prev.Loc)
-                        {
-                            case Location::Mem:
-                                MoveToST(top, 0);
-                                SynthST_Mem(fpu1memswap,fpu2memswap, prev.memaddr,prev.expected_reuse);
-                                whichpop = 1;
-                                goto doneop;
-                            case Location::Stack:
-                                MoveToST(top, 0);
-                                SynthST_Stack(fpu1memswap,fpu2memswap, prev.stackoffs);
-                                whichpop = 1;
-                                goto doneop;
-                            default: break;
-                        }
-                    }
-                    
-                  {
-                    bool order = RequireST10(false);
-                    com.Synth(order ? fpu1order : fpu1swap,
-                              order ? fpu2order : fpu2swap);
-                  }
-                doneop: ;
-                }
-                DidPop(whichpop);
-            }
-        }
-        
-        void GenAdd(bool by_itself)
-        {
-            StackDump(by_itself?"GenAddSelf":"GenAdd");
-            GenBinaryOp(by_itself,
-                0xF2,0x0F,0x58, // addsd
-                0xD8,0xC0, // fadd
-                0xDE,0xC1, // faddp
-                0xDE,0xC1, // faddp
-                0xDC,0x00, // fadd mem
-                0xDC,0x00); // fadd mem
-        }
-        void GenSub(bool by_itself)
-        {
-            StackDump(by_itself?"GenSubSelf":"GenSub");
-            GenBinaryOp(by_itself,
-                0xF2,0x0F,0x5C, // subsd
-                0xD8,0xE0, // fsub ?
-                0xDE,0xE9, // fsubp
-                0xDE,0xE1, // fsubrp
-                0xDC,0x20, // fsub mem
-                0xDC,0x28); // fsubr mem
-        }
-        void GenMul(bool by_itself)
-        {
-            StackDump(by_itself?"GenMulSelf":"GenMul");
-            GenBinaryOp(by_itself,
-                0xF2,0x0F,0x59, // mulsd
-                0xD8,0xC8, // fmul
-                0xDE,0xC9, // fmulp
-                0xDE,0xC9, // fmulp
-                0xDC,0x08, // fmul mem
-                0xDC,0x08); // fmul mem
-        }
-        void GenDiv(bool by_itself)
-        {
-            StackDump(by_itself?"GenDivSelf":"GenDiv");
-            GenBinaryOp(by_itself,
-                0xF2,0x0F,0x5E, // divsd
-                0xD8,0xF0, // fdiv ?
-                0xDE,0xF9, // fdivp
-                0xDE,0xF1, // fdivrp
-                0xDC,0x30, // fdiv mem
-                0xDC,0x38); // fdivr mem
-        }
-        void GenRDiv(bool by_itself)
-        {
-            StackDump(by_itself?"GenRDivSelf":"GenRDiv");
-            GenBinaryOp(by_itself,
-                0,0,0, // no rdivsd
-                0xD8,0xF8, // fdivr ?
-                0xDE,0xF1, // fdivrp
-                0xDE,0xF9, // fdivp
-                0xDC,0x38, // fdivr mem
-                0xDC,0x30); // fdiv mem
-        }
-        void GenSqrt()
-        {
-            StackDump("GenSqrtSelf");
-            GenBinaryOp(2, // special: input->output
-                0xF2,0x0F,0x51, // sqrtsd,
-                0xD9,0xFA, // fsqrt st0
-                0,0,
-                0,0,
-                0,0,
-                0,0);
-        }
-        void GenDup()
-        {
-            StackDump("GenDup");
-            if(SSE)
-            {
-                int newxmm = GetFreeXMM();
-                stack.push_back( CopyToXMM( stack[stack.size()-1], newxmm) );
-            }
-            else
-            {
-                RequireST(0);
-                RoomST(1);
-                com.Synth(0xD9, 0xC0); // fld st0
-                GotST();
-            }
-        }
-        void GenNeg()
-        {
-            StackDump("GenNegSelf");
-            Location& top = stack[stack.size()-1];
-            if(SSE && !(top.Loc == Location::ST && top.st_no == 0))
-            {
-                int xmm = RequireXMM(0);
-                SynthXMM_Mem(0x66, (xmm&8)?0x44:0, 0x0F,0x57,(xmm&7)*8, SSE_NegPattern, false);
-            }
-            else
-            {
-                RequireST(0);
-                com.Synth(0xD9, 0xE0); // fchs st0
-            }
-        }
-        void GenConstLoad(const double& immed)
-        {
-            StackDump("GenConstLoad");
-            if(SSE)
-            {
-                if(immed == 0.0)
-                    { int xmmno = GetFreeXMM();
-                      /* zero the register with xorps xmm,xmm */
-                      SynthXMM_XMM(0, 0x0F,0x57, xmmno, xmmno);
-                      Location loc;
-                      loc.Loc     = Location::XMM;
-                      loc.xmm_no  = xmmno;
-                      stack.push_back(loc);
-                      return;
-                    }
-                goto JustLoadFromMem;
-            }
-            if(immed == 1.0)
-                { com.Synth(0xD9, 0xE8); GotST(); } // fld1
-            else if(immed == 3.3219280948873623478)
-                { com.Synth(0xD9, 0xE9); GotST(); } // log2(10)
-            else if(immed == 1.4426950408889634074)
-                { com.Synth(0xD9, 0xEA); GotST(); } // log2(e)
-            else if(immed == 3.14159265358979323846)
-                { com.Synth(0xD9, 0xEB); GotST(); } // fldpi
-            else if(immed == 0.86858896380650365529)
-                { com.Synth(0xD9, 0xEC); GotST(); } // log10(2)
-            else if(immed == 0.69314718055994530943)
-                { com.Synth(0xD9, 0xED); GotST(); } // loge(2)
-            else if(immed == 0.0)
-                { com.Synth(0xD9, 0xEE); GotST(); } // fldz
-            else
-            {
-            JustLoadFromMem:
-                Location loc;
-                loc.Loc     = Location::Mem;
-                loc.memaddr = &immed;
-                loc.expected_reuse = false;
-                stack.push_back(loc);
-            }
-        }
-        void GenVarLoad(const double& value)
-        {
-            StackDump("GenVarLoad");
-            Location loc;
-            loc.Loc     = Location::Mem;
-            loc.memaddr = &value;
-            loc.expected_reuse = true;
-            stack.push_back(loc);
-        }
-        
-        void StackDump(const std::string& forwhom) const
-        {
-            return;
-            std::cerr << forwhom << ":";
-            for(size_t a=0, b=stack.size(); a<b; ++a)
-            {
-                std::cerr << " [";
-                const Location& loc = stack[a];
-                switch(loc.Loc)
-                {
-                    case Location::ST:
-                        std::cerr << "ST" << loc.st_no; break;
-                    case Location::XMM:
-                        std::cerr << "XMM" << loc.xmm_no; break;
-                    case Location::Mem:
-                        std::cerr << loc.memaddr; break;
-                    case Location::Stack:
-                        std::cerr << "SP" << loc.stackoffs; break;
-                }
-                std::cerr << "]";
-            }
-            std::cerr << "    (FPU depth " << fpu_stack_depth << ")";
-            std::cerr << std::endl;
-        }
-        
-        void RequireST(int stno)
-        {
-            // Generates the necessary statements to ensure
-            // that stack[last-stno] is ST(stno).
-            size_t lastitem = stack.size()-1 - stno;
-            MoveToST(stack[lastitem], stno);
-        }
-        bool RequireST10(bool order_strict)
-        {
-            // Return value: true = ST1 and ST0 are strictly ordered
-            //              false = ST1 and ST0 are swapped
-            
-            Location& top = stack[stack.size()-1];
-            Location& prev= stack[stack.size()-2];
-            
-            if(top.Loc  == Location::ST && top.st_no == 1
-            && prev.Loc == Location::ST && prev.st_no == 0)
-            {
-                // they're swapped!
-                if(!order_strict) return false;
-            }
-            RequireST(1);
-            RequireST(0);
-            return true;
-        }
-        int RequireXMM(int top_offs)
-        {
-            // Generates the necessary statements to ensure
-            // that stack[0] is in an XMM register
-            Location& top = stack[stack.size()-1 - top_offs];
-            if(top.Loc != Location::XMM)
-            {
-                int xmm = GetFreeXMM();
-                MoveToXMM(top, xmm);
-            }
-            return top.xmm_no;
-        }
-        void RoomST(int n) // Ensures there's room for at least n items of growth in ST
-        {
-            while(fpu_stack_depth+n > 8)
-            {
-                Spill(FindST(fpu_stack_depth-1));
-            }
-        }
-        Location& FindST(int stno)
-        {
-            for(size_t a=0; a<stack.size(); ++a)
-                if(stack[a].Loc == Location::ST
-                && stack[a].st_no == stno)
-                    return stack[a];
-            static Location dummy;
-            return dummy;
-        }
-        void GotST() // Informs that we've got a new value in st0
-        {
-            SimuSTpop(1);
-            Location loc;
-            loc.Loc   = Location::ST;
-            loc.st_no = 0;
-            stack.push_back(loc);
-        }
-        void GotXMM(int xmm)
-        {
-            Location loc;
-            loc.Loc    = Location::XMM;
-            loc.xmm_no = xmm;
-            stack.push_back(loc);
-        }
-        void SimuSTpop(int offset = -1)
-        {
-            // assumes that ST0 was just removed from stack
-            for(size_t a=0; a<stack.size(); ++a)
-                if(stack[a].Loc == Location::ST)
-                    stack[a].st_no += offset;
-            fpu_stack_depth += offset;
-        }
-        void DidPop(int which = 0)
-        {
-            Location& top = stack[stack.size()-1-which];
-            if(top.Loc == Location::Stack) Stack_Use.erase(top.stackoffs);
-            bool WasST0 = top.Loc == Location::ST && top.st_no == 0;
-            stack.erase(stack.begin() + stack.size() - 1 - which);
-            if(WasST0) SimuSTpop();
-        }
-        int GetFreeXMM()
-        {
-        #ifdef __x86_64
-            const int max_xmm = 16;
-        #else
-            const int max_xmm = 8;
-        #endif
-            bool XMM_Use[max_xmm] = {false};
-            for(size_t a=0; a<stack.size(); ++a)
-                if(stack[a].Loc == Location::XMM)
-                    XMM_Use[stack[a].xmm_no] = true;
-            for(int n=0; n<max_xmm; ++n)
-            {
-                if(!XMM_Use[n]) return n;
-            }
-            /* Spill one XMM register */
-            for(size_t a=0; a<stack.size(); ++a)
-                if(stack[a].Loc == Location::XMM)
-                {
-                    int xmm  = stack[a].xmm_no;
-                    Spill(stack[a]);
-                    return xmm;
-                }
-            /* Eh, what's the XMM registers being used for then?? */
-            throw std::logic_error("GetFreeXMM: Eh?");
-            return -1;
-        }
-        void Spill(Location& loc)
-        {
-            switch(loc.Loc)
-            {
-                case Location::XMM:
-                {
-                    int xmm  = loc.xmm_no;
-                    int slot = AllocStackSlot();
-                    loc.Loc       = Location::Stack;
-                    loc.stackoffs = slot;
-                    SynthXMM_Stack(0xF2, (xmm&8)?0x44:0, 0x0F,0x11,(xmm&7)*8, slot);
-                    break;
-                }
-                case Location::ST:
-                {
-                    int st   = loc.st_no;
-                    int slot = AllocStackSlot();
-                    loc.Loc       = Location::Stack;
-                    loc.stackoffs = slot;
-                    
-                    if(st == 7)
-                    {
-                        // spilling ST(7) is easy. Just fld st(7), and store it.
-                        SynthST_Stno(0xD9, 0xC0, st); // fld st7
-                        SynthST_Stack(0xDD,0x18, loc.stackoffs); // fstp addr
-                        // no renumbering needed.
-                        --fpu_stack_depth;
-                    }
-                    else
-                    {
-                        if(st != 0)
-                        {
-                            // Make it st0 by swapping it with whatever _is_ st0
-                            SynthST_Stno(0xD9, 0xC8, st); // fxch st#
-                            // Now it is st0.
-                            // But st0 is now st, so we have to update it to reflect the fact                        
-                            FindST(0).st_no = st;
-                        }
-                        SynthST_Stack(0xDD,0x18, loc.stackoffs); // fstp addr
-                        SimuSTpop(); // renumber each ST address.
-                    }
-                    break;
-                }
-                case Location::Mem:
-                case Location::Stack:
-                    break; // don't need spilling
-            }
-        }
-        Location CopyToXMM(Location& loc, int xmm, bool move = false)
-        {
-        retry:
-            switch(loc.Loc)
-            {
-                case Location::XMM:
-                    if(loc.xmm_no != xmm)
-                        SynthXMM_XMM(0xF2, 0x0F,0x10, xmm, loc.xmm_no);
-                    break;
-                case Location::ST:
-                    Spill(loc);
-                    goto retry;
-                case Location::Mem:
-                {
-                    SynthXMM_Mem(0xF2, (xmm&8)?0x44:0, 0x0F,0x10,(xmm&7)*8, loc.memaddr, loc.expected_reuse);
-                    break;
-                }
-                case Location::Stack:
-                    SynthXMM_Stack(0xF2, (xmm&8)?0x44:0, 0x0F,0x10,(xmm&7)*8, loc.stackoffs);
-                    if(move) Stack_Use.erase(loc.stackoffs);
-                    break;
-            }
-            
-            Location res;
-            res.Loc    = Location::XMM;
-            res.xmm_no = xmm;
-            
-            if(move) loc = res;
-            
-            return res;
-        }
-        void MoveToXMM(Location& loc, int xmm)
-        {
-            CopyToXMM(loc, xmm, true);
-        }
-        
-        void MoveToST(Location& loc, int stno)
-        {
-        retry:
-            switch(loc.Loc)
-            {
-                case Location::XMM:
-                    Spill(loc);
-                    goto retry;
-                case Location::ST:
-                    if(loc.st_no != stno)
-                    {
-                        if(loc.st_no != 0)
-                        {
-                            SynthST_Stno(0xD9, 0xC8, loc.st_no); // fxch st#
-                            // Whatever _was_ 0, change it to indicate where it's now
-                            FindST(0).st_no = loc.st_no;
-                        }
-                        if(stno != 0)
-                        {
-                            SynthST_Stno(0xD9, 0xC8, stno); // fxch st#
-                            // Whatever _was_ stno, change it to indicate that it's at 0 now
-                            FindST(stno).st_no = 0;
-                        }
-                    }
-                    break;
-                case Location::Mem:
-                {
-                    RoomST(1);
-                    if(loc.Loc != Location::Mem) goto retry;
-                    SynthST_Mem(0xDD, 0x00, loc.memaddr, loc.expected_reuse); // fld qword [...]
-                    SimuSTpop(1);
-                    break;
-                }
-                case Location::Stack:
-                    RoomST(1);
-                    if(loc.Loc != Location::Stack) goto retry;
-                    SynthST_Stack(0xDD, 0x00, loc.stackoffs); // fld qword [...]
-                    SimuSTpop(1);
-                    Stack_Use.erase(loc.stackoffs);
-                    break;
-            }
-            loc.Loc    = Location::ST;
-            loc.st_no  = stno;
-        }
-        int AllocStackSlot()
-        {
-            int n=0;
-            while(Stack_Use.find(n) != Stack_Use.end()) n -= 8;
-            Stack_Use.insert(n);
-            
-            int use = (-n) + 8;
-            if(use > max_stack_use) max_stack_use = use;
-            
-            return n;
-        }       
-        
-        void PullResult()
-        {
-            Location& loc = stack[stack.size()-1];
-        #ifdef __x86_64
-            /* Must transfer the value to xmm0 at end */
-            MoveToXMM(loc, 0);
-        #endif
-        #ifndef __x86_64
-            /* Must transfer the value to st0 at end */
-            MoveToST(loc, 0);
-        #endif
-        }
-        
-        void SynthXMM_XMM(int prefix, int b1, int b2, int reg1, int reg2)
-        {
-            if(prefix) com.Synth(prefix);
-            if(reg2 & 8)
-                com.Synth( (reg1 & 8) ? 0x45 : 0x41);
-            else if(reg1 & 8)
-                com.Synth(0x44);
-            com.Synth(b1, b2, 0xC0 + (reg1&7)*8 + (reg2&7));
-        }
-        void SynthXMM_Mem(int prefix, int code64, int b1, int b2, int b3, const void* addr, bool expected_reuse)
-        {
-            int basereg = SynthLoadAddr(addr, expected_reuse);
-            com.Synth(prefix);
-            if(basereg&8) code64 |= 0x41;
-            if(code64) com.Synth(code64);
-            com.Synth(b1, b2, b3 + (basereg&7));
-        }
-        void SynthXMM_Stack(int prefix, int code64, int b1, int b2, int b3, int stackoffs)
-        {
-            com.Synth(prefix);
-            if(code64) com.Synth(code64);
-            com.Synth(b1, b2);
-            SynthStackSIB(b3, stackoffs);
-        }
-        void SynthST_Mem(int b1,int b2, const void* addr, bool expected_reuse)
-        {
-            int basereg = SynthLoadAddr(addr, expected_reuse);
-            if(basereg&8) com.Synth(0x41);
-            com.Synth(b1, b2 + basereg);
-        }
-        void SynthST_Stno(int b1,int b2, int stno)
-        {
-            com.Synth(b1, (0xC0|b2) + stno);
-        }
-        void SynthST_Stack(int b1,int b2, int stackoffs)
-        {
-            com.Synth(b1);
-            SynthStackSIB(b2, stackoffs);
-        }
-        void SynthStackSIB(int b3,int stackoffs)
-        {
-            if(!stackoffs)
-                { com.Synth(b3 + 0x04, 0x24); }
-            else if(stackoffs >= -128 && stackoffs < 128)
-                { com.Synth(b3 + 0x44, 0x24); com.Synth( (int_least8_t) stackoffs ); }
-            else
-                { com.Synth(b3 + 0x84, 0x24); com.SynthI32( (int_least32_t) stackoffs ); }
-        }
-        int SynthLoadAddr(const void* addr, bool expected_reuse)
-        {
-            int basereg = 0, freereg = 0;
-            #ifdef __x86_64
-            int num_registers = 16;
-            #else
-            int num_registers = 8;
-            #endif
-            
-            if(!expected_reuse)
-                num_registers = 2; // eax or ecx for temporaries.
-            
-            for(basereg=num_registers; basereg-->0; )
-            {
-                // Registers ebx, ebp, r12, r13, r14 and r15 belong to the calling function.
-                // We can't clobber them.
-                if(basereg == 3
-                || basereg == 5
-                || (basereg >= 12 && basereg <= 15)) continue;
-
-                // Register esp cannot be used
-                if(basereg == 4) continue;
-                
-                // Give eax and ecx for temporaries.
-                if(expected_reuse && basereg < 2) continue;
-                
-                if(basereg_use[basereg] == addr) return basereg;
-                if(!basereg_use[basereg]) freereg = basereg;
-            }
-            basereg_use[basereg = freereg] = addr;
-            SynthLoadAddr(addr, basereg);
-            return basereg;
-        }
-        void SynthLoadAddr(const void* addr, int basereg)
-        {
-        #ifdef __x86_64
-            com.Synth((basereg&8) ? 0x49 : 0x48, 0xB8 + (basereg&7) );
-            com.SynthI64( (uint_fast64_t) addr);  // mov rax, qword ptr value
-        #else
-            com.Synth(0xB8+basereg);
-            com.SynthI32( (uint_fast32_t) addr);  // mov eax, dword ptr value
-        #endif
-        }
-        
-        int GetMaxStackUse() const { return max_stack_use; }
-    };
-
-    void SynthesizeCode_Generic(
-        const opcode* const op_begin,
-        const opcode* const op_end,
-        CodeSynth& synth,
-        size_t ImmedPtr = 0,
-        bool DoEntryExit = true)
-    {
-        size_t stack_required = 0;
-        
-        size_t begin_pos = CodeBuffer.size();
-        
-        for(const opcode* op = op_begin; op < op_end; )
-            switch(*op++)
-            {
-                case opPlus:  synth.GenAdd(false); break; // faddp st(1)
-                case opMinus: synth.GenSub(false); break; // fsubp st(1)
-                case opMul:   synth.GenMul(false); break; // fmulp st(1)
-                case opDiv:   synth.GenDiv(false); break; // fdivp st(1)
-                case opDup:
-                    if(*op == opMul) // opDup,opMul  x*x idiom?
-                    {
-                        // do a fmul without involving the stack
-                        ++op;
-                        synth.GenMul(true);
-                    }
-                    else if(*op == opPlus) // opDup,opPlus  x+x idiom?
-                    {
-                        // do a fadd without involving the stack
-                        ++op;
-                        synth.GenAdd(true);
-                    }
-                    else
-                    {
-                        synth.GenDup();
-                    }
-                    break;
-                case opNeg:   synth.GenNeg(); break;
-                case opSqrt:  synth.GenSqrt(); break;
-                case opSin:   synth.StackDump("opSin");
-                              synth.RequireST(0); Synth(0xD9, 0xFE); break; // fsin
-                case opCos:   synth.StackDump("opCos");
-                              synth.RequireST(0); Synth(0xD9, 0xFF); break; // fcos
-                case opExp:
-                {
-                    /* There is no natural exponent opcode on 387.
-                       To perform this operation, we use this formula:
-                         e^x = 2^(x * log2(e))
-                       But because FPU cannot do 2^x unless x is -1...+1,
-                       we have to do a trick involving rndint, subr and scale.
-                     */
-                    synth.StackDump("opExp");
-                    synth.RequireST(0);
-                    synth.RoomST(1);
-                    Synth(0xD9, 0xEA,  // fld2e
-                          0xDE, 0xC9); // fmulp st1
-                    Synth(0xD9, 0xC0,  // fld st0
-                          0xD9, 0xFC,  // frndint
-                          0xDC, 0xE9); // fsubr st1
-                    Synth(0xD9, 0xC9,  // fxch st1
-                          0xD9, 0xF0,  // f2xm1
-                          0xD9, 0xE8); // fld1
-                    Synth(0xDE, 0xC1,  // faddp  st1
-                          0xD9, 0xFD,  // fscale
-                          0xDD, 0xD9); // fstp st1
-                    break;
-                }
-                case opPow:
-                {
-                    /* There is no arbitrary exponent opcode on 387.
-                       To perform this operation, we need use this formula:
-                         exp(ln(a) * b)
-                       Or because the fpu does base-2 exponents:
-                         2^(log2(a) * b)
-                       The rndint/subr/scale trick is the same as in opExp.
-                     */
-                    synth.StackDump("opPow");
-                    synth.RequireST10(true);
-                    synth.RoomST(1);
-                    Synth(0xD9, 0xF1); // fyl2x: log2(a)*b
-                    Synth(0xD9, 0xC0,  // fld st0
-                          0xD9, 0xFC,  // frndint
-                          0xDC, 0xE9); // fsubr st1
-                    Synth(0xD9, 0xC9,  // fxch st1
-                          0xD9, 0xF0,  // f2xm1
-                          0xD9, 0xE8); // fld1
-                    Synth(0xDE, 0xC1,  // faddp  st1
-                          0xD9, 0xFD,  // fscale
-                          0xDD, 0xD9); // fstp st1
-                    synth.DidPop();
-                    break;
-                }
-
-                case opImmed: 
-                {
-                    const double& immed = immeds[ImmedPtr++];
-                    
-                    if(*op == opPow && immed != 0.0)
-                    {
-                        /* Check for special cases of integer exponents */
-                        for(int sqrtcount=0; sqrtcount < 30; ++sqrtcount)
-                        {
-                            const double immed_effected = immed * (1 << sqrtcount);
-                            if( (int)immed_effected == immed_effected)
-                            {
-                                int power = (int)immed_effected;
-                                if(power < 0) power = -power;
-                                
-                                /*
-                                  x ^ 11 translates like this:
-                                  
-                                  Algorithm:
-                                   (pow=11)  pow&1 ? make backup: x^1, zero low bit of pow
-                                   (pow=10)  pow&1 ? no, do Mul, shift low bit of pow
-                                   (pow=5)   pow&1 ? make backup: x^2, zero low bit
-                                   (pow=4)   pow&1 ? no, do Mul, shift low bit
-                                   (pow=2)   pow&1 ? no, do Mul, shift low bit
-                                   (pow=1)   flush backups.
-                                  
-                                  Result:
-                                    tmp1 = x  // backup of x^1
-                                    x *= x    // now x^2
-                                    tmp2 = x  // backup of x^2
-                                    x *= x    // now x^4
-                                    x *= x    // now x^8
-                                    x *= tmp2 // now x^10
-                                    x *= tmp1 // now x^11
-                                    
-                                  x ^ 10 translates like this:
-                                    x *= x    // now x^2
-                                    tmp1 = x  // backup of x^2
-                                    x *= x    // now x^4
-                                    x *= x    // now x^8
-                                    x *= tmp1 // now x^10
-                                    
-                                 This algorithm can still be improved,
-                                 for example:
-                                 
-                                  x ^ 15 is better as:
-                                    tmp1 = x  // backup of x^1
-                                    x *= x    // now x^2
-                                    x *= x    // now x^4
-                                    x *= x    // now x^8
-                                    x *= x    // now x^16
-                                    x /= tmp1 // now x^15
-                                  than:
-                                    tmp1 = x  // backup of x^1
-                                    x *= x    // now x^2
-                                    tmp2 = x  // backup of x^2
-                                    x *= x    // now x^4
-                                    tmp3 = x  // backup of x^4
-                                    x *= x    // now x^8
-                                    x *= tmp3 // now x^12
-                                    x *= tmp2 // now x^14
-                                    x *= tmp1 // now x^15
-                                  This is what gcc does, btw:
-                                    tmp1 = x  // backup of x^1
-                                    tmp1 *= x // now tmp1 is x^2
-                                    tmp1 *= x // now tmp1 is x^3
-                                    x = tmp1  // now x^3
-                                    x *= tmp1 // now x^6
-                                    tmp1 *= x // now tmp1 is x^9
-                                    x *= tmp1 // now x^15
-                                  
-                                  x ^ 27 could be x^32 - x^4 - x^1
-                                    tmp1 = x // backup of x^1
-                                    x *= x   // now x^2
-                                    x *= x   // now x^4
-                                    tmp2 = x // backup of x^4
-                                    x *= x   // now x^8
-                                    x *= x   // now x^16
-                                    x *= x   // now x^32
-                                    x /= tmp2 // now x^28
-                                    x /= tmp1 // now x^27
-                                  rather than:
-                                    tmp1 = x // backup of x^1  (26)
-                                    x *= x   // now x^2        (13)
-                                    tmp2 = x // backup of x^2  (12)
-                                    x *= x   // now x^4        (6)
-                                    x *= x   // now x^8        (3)
-                                    tmp3 = x // backup of x^8  (2)
-                                    x *= x   // now x^16       (1)
-                                    x *= tmp3 // now x^24
-                                    x *= tmp2 // now x^26
-                                    x *= tmp1 // now x^27
-                                    
-                                  However, exception is required because:
-                                  x^3:  normally  x^2 * x
-                                    tmp1 = x
-                                    x *= x
-                                    x *= tmp1 
-                                        modified  x^4 / x
-                                    tmp1 = x
-                                    x *= x
-                                    x *= x
-                                    x /= tmp1
-                                
-                                Done as described.
-                                */
-                                
-                                synth.StackDump("opPow (inlined)");
-                                
-                                std::list<bool/*true=mul,false=div*/> backuplist;
-                                bool polarity = true;
-                                while(power > 1)
-                                {
-                                    if(power & 1)
-                                    {
-                                        int next_power_of_2 = Log2up(power);
-                                        int popcount        = PopCount(power);
-                                        if(power != 3 && popcount > next_power_of_2 / 2)
-                                        {
-                                            power = (1 << next_power_of_2) - power;
-                                            polarity = !polarity;
-                                        }
-
-                                        synth.GenDup(); //  make dup
-                                        --power;
-                                        backuplist.push_back(polarity);
-                                        continue;
-                                    }
-                                    synth.GenMul(true); // mul self
-                                    power /= 2;
-                                }
-                                while(!backuplist.empty())
-                                {
-                                    bool val = backuplist.back(); backuplist.pop_back();
-                                    if(val)
-                                        synth.GenMul(false); // mul and pop
-                                    else
-                                        synth.GenDiv(false); // div and pop
-                                }
-
-                                if(immed < 0) // negative exponents are 1/x
-                                {
-                                    synth.GenConstLoad(FP_Constant_One);
-                                    synth.GenRDiv(false);
-                                }
-                                for(; sqrtcount > 0; --sqrtcount)
-                                    synth.GenSqrt();
-                                
-                                ++op; // skip pow
-                                goto DoneImmed;
-                            }
-                        }
-                    }
-                    
-                    synth.GenConstLoad(immed);
-                DoneImmed:
-                    break;
-                }
-                
-                case opVar:
-                {
-                    double& var = vars[ (size_t) *op++ ];
-                    synth.GenVarLoad(var);
-                    break;
-                }
-            }
-            
-          /*
-          modrm:
-            pprrrmmm
-            
-             rrr=reg
-             mmm=mem
-          */
-        
-        if(DoEntryExit)
-        {
-            /* Move result to the result register if needed */
-            synth.PullResult();
-            
-            /* Allocate and deallocate stack if needed */
-            size_t stack_required = synth.GetMaxStackUse();
-            if(stack_required)
-            {
-                #ifndef __x86_64
-                // add nice aligning
-                stack_required = ((stack_required + 4 + 15) & ~ 15) - 4;
-                #endif
-                
-                std::vector<unsigned char> tmp;
-                CodeBuffer.swap(tmp);
-                // Write the stack init code to a temporary buffer
-                SynthStackBegin(stack_required);
-                CodeBuffer.swap(tmp);
-                
-                // Insert the stack init code to the right place
-                CodeBuffer.insert(CodeBuffer.begin() + begin_pos, tmp.begin(), tmp.end());
-            
-                SynthStackEnd(stack_required);
-            }
-            Synth(0xC3); // ret
-        }
-    }
-    
-    inline void Synth(unsigned char c) { CodeBuffer.push_back(c); }
-    void Synth(unsigned char c1,unsigned char c2)
-        { CodeBuffer.reserve(CodeBuffer.size()+2);
-          Synth(c1); Synth(c2); }
-    void Synth(unsigned char c1,unsigned char c2,unsigned char c3)
-        { CodeBuffer.reserve(CodeBuffer.size()+3);
-          Synth(c1); Synth(c2); Synth(c3); }
-    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,unsigned char c4)
-        { CodeBuffer.reserve(CodeBuffer.size()+4);
-          Synth(c1); Synth(c2); Synth(c3); Synth(c4); }
-    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,unsigned char c4,unsigned char c5)
-        { CodeBuffer.reserve(CodeBuffer.size()+5);
-          Synth(c1); Synth(c2); Synth(c3); Synth(c4); Synth(c5); }
-    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,
-               unsigned char c4,unsigned char c5,unsigned char c6)
-        { CodeBuffer.reserve(CodeBuffer.size()+6);
-          Synth(c1); Synth(c2); Synth(c3); Synth(c4); Synth(c5); Synth(c6); }
-    void SynthI32(uint_fast32_t w)
-        { Synth(w & 0xFF, (w >> 8) & 0xFF,
-                (w >> 16) & 0xFF, (w >> 24) & 0xFF); }
-    void SynthI64(uint_fast64_t w)
-        { SynthI32(w); SynthI32(w >> 32); }
-
-private:
     Compiler(const Compiler&);
     void operator=(const Compiler&);
 
 private:
+    // Name of this JIT engine.
+    std::string name;
+    
+    // The synthesized binary code.
     std::vector<unsigned char> CodeBuffer;
-    const char* name;
+    
+    // A buffer aligned for holding the binary code and necessary padding
     unsigned char* Code;
+    
+    // A pointer to the binary code within the buffer, aligned properly.
     unsigned char* CodePtr;
 };
diff -NaHudr fparser-jittest-1.3/compiler_synth.hh fparser-jittest-1.4/compiler_synth.hh
--- fparser-jittest-1.3/compiler_synth.hh	1970-01-01 02:00:00.000000000 +0200
+++ fparser-jittest-1.4/compiler_synth.hh	2008-01-15 01:02:13.000000000 +0200
@@ -0,0 +1,1115 @@
+#include <map>
+#include <set>
+#include <vector>
+
+//#define DISASM_DEBUG
+//#define STACK_DEBUG
+
+#ifdef DISASM_DEBUG
+/* For disassembling (debug) */
+#include <unistd.h>
+#include <sys/wait.h>
+#endif
+
+class OpcodeMachine
+{
+public:
+    std::vector<unsigned char>& CodeBuffer;
+    std::vector<const void*> basereg_use;
+
+public:
+    OpcodeMachine(std::vector<unsigned char>& buf)
+        : CodeBuffer(buf),
+          basereg_use(16, (const void*)0)
+    { }
+
+public:
+    inline void Synth(unsigned char c) { CodeBuffer.push_back(c); }
+    void Synth(unsigned char c1,unsigned char c2)
+        { CodeBuffer.reserve(CodeBuffer.size()+2);
+          Synth(c1); Synth(c2); }
+    void Synth(unsigned char c1,unsigned char c2,unsigned char c3)
+        { CodeBuffer.reserve(CodeBuffer.size()+3);
+          Synth(c1); Synth(c2); Synth(c3); }
+    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,unsigned char c4)
+        { CodeBuffer.reserve(CodeBuffer.size()+4);
+          Synth(c1); Synth(c2); Synth(c3); Synth(c4); }
+    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,unsigned char c4,unsigned char c5)
+        { CodeBuffer.reserve(CodeBuffer.size()+5);
+          Synth(c1); Synth(c2); Synth(c3); Synth(c4); Synth(c5); }
+    void Synth(unsigned char c1,unsigned char c2,unsigned char c3,
+               unsigned char c4,unsigned char c5,unsigned char c6)
+        { CodeBuffer.reserve(CodeBuffer.size()+6);
+          Synth(c1); Synth(c2); Synth(c3); Synth(c4); Synth(c5); Synth(c6); }
+    void SynthI16BE(uint_fast16_t w)
+        { Synth((w >> 8) & 0xFF, w & 0xFF); }
+    void SynthI32(uint_fast32_t w)
+        { Synth(w & 0xFF, (w >> 8) & 0xFF,
+                (w >> 16) & 0xFF, (w >> 24) & 0xFF); }
+    void SynthI64(uint_fast64_t w)
+        { SynthI32(w); SynthI32(w >> 32); }
+public:
+    void SynthXMM_XMM(int prefix, int b1, int b2, int reg1, int reg2)
+    {
+        if(prefix) Synth(prefix);
+        if(reg2 & 8)
+            Synth( (reg1 & 8) ? 0x45 : 0x41);
+        else if(reg1 & 8)
+            Synth(0x44);
+        Synth(b1, b2, 0xC0 + (reg1&7)*8 + (reg2&7));
+    }
+    void SynthXMM_Mem(int prefix, int code64, int b1, int b2, int b3, const void* addr, bool expected_reuse)
+    {
+        int basereg = SynthLoadAddr(addr, expected_reuse);
+        Synth(prefix);
+        if(basereg&8) code64 |= 0x41;
+        if(code64) Synth(code64);
+        Synth(b1, b2, b3 + (basereg&7));
+    }
+    void SynthXMM_Stack(int prefix, int code64, int b1, int b2, int b3, int stackoffs)
+    {
+        Synth(prefix);
+        if(code64) Synth(code64);
+        Synth(b1, b2);
+        SynthStackSIB(b3, stackoffs);
+    }
+    void SynthST_Mem(unsigned short b, const void* addr, bool expected_reuse)
+    {
+        int basereg = SynthLoadAddr(addr, expected_reuse);
+        if(basereg&8) Synth(0x41);
+        SynthI16BE((b & 0xFF38) + basereg);
+    }
+    void SynthST_Stno(unsigned short b, int stno)
+    {
+        SynthI16BE((b | 0x00C0) + stno);
+    }
+    void SynthST_Stack(unsigned short b, int stackoffs)
+    {
+        Synth(b >> 8);
+        SynthStackSIB((b & 0xFF), stackoffs);
+    }
+    void SynthStackSIB(int b3,int stackoffs)
+    {
+        if(!stackoffs)
+            { Synth(b3 + 0x04, 0x24); }
+        else if(stackoffs >= -128 && stackoffs < 128)
+            { Synth(b3 + 0x44, 0x24); Synth( (int_least8_t) stackoffs ); }
+        else
+            { Synth(b3 + 0x84, 0x24); SynthI32( (int_least32_t) stackoffs ); }
+    }
+
+    void SynthLoadAddr(const void* addr, int basereg)
+    {
+    #ifdef __x86_64
+        Synth((basereg&8) ? 0x49 : 0x48, 0xB8 + (basereg&7) );
+        SynthI64( (uint_fast64_t) addr);  // mov rax, qword ptr value
+    #else
+        Synth(0xB8+basereg);
+        SynthI32( (uint_fast32_t) addr);  // mov eax, dword ptr value
+    #endif
+    }
+
+    int SynthLoadAddr(const void* addr, bool expected_reuse)
+    {
+        int basereg = 0, freereg = 0;
+        #ifdef __x86_64
+        int num_registers = 16;
+        #else
+        int num_registers = 8;
+        #endif
+        
+        if(!expected_reuse)
+            num_registers = 2; // eax or ecx for temporaries.
+        
+        for(basereg=num_registers; basereg-->0; )
+        {
+            // Registers ebx, ebp, r12, r13, r14 and r15 belong to the calling function.
+            // We can't clobber them.
+            if(basereg == 3
+            || basereg == 5
+            || (basereg >= 12 && basereg <= 15)) continue;
+
+            // Register esp cannot be used
+            if(basereg == 4) continue;
+            
+            // Give eax and ecx for temporaries.
+            if(expected_reuse && basereg < 2) continue;
+            
+            if(basereg_use[basereg] == addr) return basereg;
+            if(!basereg_use[basereg]) freereg = basereg;
+        }
+        basereg_use[basereg = freereg] = addr;
+        SynthLoadAddr(addr, basereg);
+        return basereg;
+    }
+};
+
+/* This is a code generator which generates both FPU and SSE
+ * code by simulating a stack. It also has traits of lazy
+ * evaluation.
+ */
+class CodeSynth
+{
+private:
+    bool SSE;
+    
+    struct Location
+    {
+        enum { ST, XMM, Mem, Stack, Copy, CopyDontMind } Loc;
+        int           st_no;
+        int           xmm_no;
+        int           stackoffs;
+        const double* memaddr;
+        bool          is_constant;
+        int           is_copyof;
+        
+        Location(): Loc(Mem), st_no(0),xmm_no(0),stackoffs(0),memaddr(0),
+                    is_constant(true),
+                    is_copyof(-1)
+        { }
+    };
+    std::vector<Location> stack; // calculator stack
+    std::set<int> Stack_Use;     // memory stack
+    int fpu_stack_depth;
+    int max_stack_use;
+    OpcodeMachine machine;
+    std::map<int, size_t> saved_exprs;
+private:
+    Location& GetShadow(Location& b)
+    {
+        if(b.Loc == Location::Copy
+        || b.Loc == Location::CopyDontMind) return GetShadow(stack[b.is_copyof]);
+        return b;
+    }
+    const Location& GetShadow(const Location& b) const
+    {
+        if(b.Loc == Location::Copy
+        || b.Loc == Location::CopyDontMind) return GetShadow(stack[b.is_copyof]);
+        return b;
+    }
+public:
+    CodeSynth(bool sse, std::vector<unsigned char>& target)
+        : SSE(sse), stack(), Stack_Use(),
+          fpu_stack_depth(0),
+          max_stack_use(0),
+          machine(target),
+          saved_exprs()
+    {
+    }
+    
+    bool SynthLeaves(const CodeTreeP& st1, const CodeTreeP& st0, bool check_self=true)
+    {
+        SynthCode(st1);
+        const bool identical = st1->expl == st0->expl;
+        if(check_self && identical)
+        {
+        #ifdef STACK_DEBUG
+            std::cerr << "Identical sibling omitted, next op will be unary\n";
+        #endif
+            return true;
+        }
+        if(identical) GenDup(); else SynthCode(st0);
+        return false;
+    }
+    
+    void SynthCode(const CodeTreeP& tree)
+    {
+        switch(tree->op)
+        {
+            case opPlus:
+            {
+                bool by_itself = SynthLeaves(tree->st1, tree->st0, true);
+                GenBinaryOp(by_itself,
+                    0xF20F58, // addsd
+                    0xD800,   // fadd (st0 = st0 + stX, no pop)
+                    0xDC00,   // fadd (stX = stX + st0, no pop)
+                    0xDC00,   // fadd (stX = st0 + stX, no pop)
+                    0xD800,   // fadd (st0 = stX + st0, no pop)
+                    0xDE00,   // faddp (stX = st0 + stX, pop)
+                    0xDE00,   // faddp (stX = stX + st0, pop)
+                    0xDC00,   // fadd (st0 = st0 + mem)
+                    0xDC00);  // fadd (st0 = mem + mem)
+                break;
+            }
+            
+            case opMinus:
+            {
+                bool by_itself = SynthLeaves(tree->st1, tree->st0, true);
+                GenBinaryOp(by_itself,
+                    0xF20F5C, // subsd
+                    0xD820,   // fsub   (st0 = st0 - stX, no pop)
+                    0xDC28,   // fsub   (stX = stX - st0, no pop)
+                    0xDC20,   // fsubr  (stX = st0 - stX, no pop)
+                    0xD828,   // fsubr  (st0 = stX - st0, no pop)
+                    0xDE20,   // fsubrp (stX = st0 - stX, pop)
+                    0xDE28,   // fsubp  (stX = stX - st0, pop)
+                    0xDC20,   // fsub   (st0 = st0 - mem)
+                    0xDC28);  // fsubr  (st0 = mem - st0)
+                break;
+            }
+            
+            case opMul:
+            {
+                bool by_itself = SynthLeaves(tree->st1, tree->st0, true);
+                GenBinaryOp(by_itself,
+                    0xF20F59, // mulsd
+                    0xD808,   // fmul (st0 = st0 * stX, no pop)
+                    0xDC08,   // fmul (stX = stX * st0, no pop)
+                    0xDC08,   // fmul (stX = st0 * stX, no pop)
+                    0xD808,   // fmul (st0 = stX * st0, no pop)
+                    0xDE08,   // fmulp (stX = st0 * stX, pop)
+                    0xDE08,   // fmulp (stX = stX * st0, pop)
+                    0xDC08,   // fmul (st0 = st0 * mem)
+                    0xDC08);  // fmul (st0 = mem * mem)
+                break;
+            }
+            
+            case opDiv:
+            {
+                bool by_itself = SynthLeaves(tree->st1, tree->st0, true);
+                GenBinaryOp(by_itself,
+                    0xF20F5E, // divsd
+                    0xD830,   // fdiv   (st0 = st0 / stX, no pop)
+                    0xDC38,   // fdiv   (stX = stX / st0, no pop)
+                    0xDC30,   // fdivr  (stX = st0 / stX, no pop)
+                    0xD838,   // fdivr  (st0 = stX / st0, no pop)
+                    0xDE30,   // fdivrp (stX = st0 / stX, pop)
+                    0xDE38,   // fdivp  (stX = stX / st0, pop)
+                    0xDC30,   // fdiv   (st0 = st0 / mem)
+                    0xDC38);  // fdivr  (st0 = mem / st0)
+                break;
+            }
+            
+            case opSqrt:
+            {
+                SynthCode(tree->st0);
+                GenBinaryOp(2, // special: input->output
+                    0xF20F51,  // sqrtsd,
+                    0xD9FA,    // fsqrt st0
+                    0,
+                    0,0,
+                    0,0,
+                    0,0);
+                break;
+            }
+            
+            case opSin:
+            {
+                SynthCode(tree->st0);
+                RequireST(0,0, true); machine.Synth(0xD9, 0xFE);
+                break;
+            }
+            
+            case opCos:
+            {
+                SynthCode(tree->st0);
+                RequireST(0,0, true); machine.Synth(0xD9, 0xFF);
+                break;
+            }
+            
+            case opNeg:
+            {
+                SynthCode(tree->st0);
+                Location& top = stack[stack.size()-1];
+                if(SSE && !(top.Loc == Location::ST && top.st_no == 0))
+                {
+                    int xmm = RequireXMM(0, true);
+                    machine.SynthXMM_Mem(0x66, (xmm&8)?0x44:0, 0x0F,0x57,(xmm&7)*8, SSE_NegPattern, false);
+                }
+                else
+                {
+                    RequireST(0,0, true);
+                    machine.Synth(0xD9, 0xE0); // fchs st0
+                }
+                break;
+            }
+            
+            case opPow:
+            {
+                SynthLeaves(tree->st1, tree->st0, false);
+                /* FIXME: This version does not support exponentation
+                 * of negative numbers. (-2)^2 will give NaN.
+                 */
+
+                /* There is no arbitrary exponent opcode on 387.
+                   To perform this operation, we need use this formula:
+                     exp(ln(a) * b)
+                   Or because the fpu does base-2 exponents:
+                     2^(log2(a) * b)
+                 */
+                
+                if(StackTopIsConst(1)
+                && GetStackTopConst(1) == 2.0)
+                {
+                    // 2^x is a bit simpler; we only need the exponent.
+                    DidPop(1); // forget the base
+                    RequireST(0,0,true); // ensure exponent is in ST0 and writable
+                    RoomST(1); // ensure there's room for ST to grow by 1
+                }
+                else if(StackTopIsConst(1)
+                     && GetStackTopConst(1) == FP_Constant_Exp1)
+                {
+                    // Uhhuh, we got exp()
+                    DidPop(1); // forget te base
+                    RequireST(0,0,true); // ensure exponent is in ST0 and writable
+                    RoomST(1); // ensure there's room for ST to grow by 1
+                    machine.Synth(0xD9, 0xEA,  // fld2e
+                                  0xDE, 0xC9); // fmulp st1
+                }
+                else
+                {
+                    // Ensure base is in ST1 and writable
+                    // Ensure exponent is in ST0
+                    RequireST(1,1, true);
+                    RequireST(0,0, false);
+                    RoomST(1);
+                    machine.Synth(0xD9, 0xF1); // fyl2x: log2(a)*b
+                    DidPop(0, true); // Exponent is gone now
+                }
+                
+                /*
+                   At this point, we are assumed to be performing 2^(x).
+                   Because FPU cannot do 2^x unless x is -1...+1,
+                   we have to do a trick involving rndint, subr and scale:
+                     result = 2^(frac(v))
+                            * 2^(int(v))
+                */
+                machine.Synth(0xD9, 0xC0,  // fld st0
+                              0xD9, 0xFC,  // frndint
+                              0xDC, 0xE9); // fsubr st1
+                machine.Synth(0xD9, 0xC9,  // fxch st1
+                              0xD9, 0xF0,  // f2xm1
+                              0xD9, 0xE8); // fld1
+                machine.Synth(0xDE, 0xC1,  // faddp  st1
+                              0xD9, 0xFD,  // fscale
+                              0xDD, 0xD9); // fstp st1
+                break;
+            }
+            
+            case opImmed:
+            {
+                Location loc;
+                loc.Loc     = Location::Mem;
+                loc.memaddr = tree->param;
+                loc.is_constant = true;
+                stack.push_back(loc);
+                break;
+            }
+            
+            case opStoreTemp:
+            {
+                // Remember where it is stored
+                saved_exprs[tree->expr_num] = stack.size();
+                
+                SynthCode(tree->st1); // this is to be stored
+                
+                StackDump("opStoreTemp");
+                
+                SynthCode(tree->st0); // this is where it affects
+                
+                // now the storage can be forgotten
+                DidPop(1, false);
+                saved_exprs.erase(tree->expr_num);
+                break;
+            }
+            case opRecallTempR:
+            case opRecallTempW:
+            {
+                std::map<int, size_t>::const_iterator i = saved_exprs.find(tree->expr_num);
+                if(i == saved_exprs.end())
+                    throw std::logic_error("opRecallTemp: saved expression not found");
+                size_t stackpos = i->second;
+                
+                bool writable = tree->op == opRecallTempW;// && SSE;
+                GenDup(stackpos, writable);
+                break;
+            }
+            
+            case opVarBegin:
+            {
+                Location loc;
+                loc.Loc     = Location::Mem;
+                loc.memaddr = tree->param;
+                loc.is_constant = false;
+                stack.push_back(loc);
+                break;
+            }
+        }
+        
+        #ifdef DISASM_DEBUG
+        static size_t genpos = 0;
+        const size_t newpos = machine.CodeBuffer.size();
+        if(newpos < genpos) genpos = 0;
+        std::cerr << "\33[0m";
+        #endif
+        StackDump(tree->NodeDump());
+        #ifdef DISASM_DEBUG
+        if(newpos > genpos)
+        {
+            std::cerr << "\33[0;32m" << std::flush; std::fflush(stderr);
+            char offsparam[64]; std::sprintf(offsparam, "-o%u", (unsigned)genpos);
+            int pip[2]; pipe(pip);
+            if(!fork())
+            {
+                close(pip[1]);
+                dup2(pip[0], 0);
+                dup2(2, 1);
+                execlp("ndisasm","ndisasm", "-", "-b64", offsparam, 0);
+                _exit(-1);
+            }
+            close(pip[0]);
+            write(pip[1], &machine.CodeBuffer[genpos], newpos-genpos);
+            close(pip[1]);
+            wait(0);
+            std::cerr << "\33[0m" << std::flush;
+            genpos = newpos;
+        }
+        #endif
+    }
+
+    void PullResult()
+    {
+        Location& loc = stack[stack.size()-1];
+    #ifdef __x86_64
+        /* Must transfer the value to xmm0 at end */
+        MoveToXMM(loc, 0);
+    #endif
+    #ifndef __x86_64
+        /* Must transfer the value to st0 at end */
+        MoveToST(loc, 0);
+    #endif
+    }
+
+    int GetMaxStackUse() const { return max_stack_use; }
+
+    void SynthStackBegin(int stack_required)
+    {
+        #ifdef __x86_64
+            machine.Synth(0x48, 0x81, 0xEC);
+            machine.SynthI32( stack_required);
+        #else
+            machine.Synth(0x81, 0xEC);
+            machine.SynthI32( stack_required);
+        #endif
+    }
+    void SynthStackEnd(int stack_required)
+    {
+    #if 0
+        #ifdef __x86_64
+            machine.Synth(0x48, 0x81, 0xC4);
+            machine.SynthI32( stack_required);
+        #else
+            machine.Synth(0x81, 0xC4);
+            machine.SynthI32( stack_required);
+        #endif
+    #else
+        // try to use LEA for less opcode bytes
+        #ifdef __x86_64
+            machine.Synth(0x48, 0x8D);
+        #else
+            machine.Synth(0x8D);
+        #endif
+        machine.SynthStackSIB(0x20, stack_required);
+    #endif
+    }
+
+private:
+    void StackDump(const std::string& forwhom) const
+    {
+        #ifdef STACK_DEBUG
+        int spaces = 21-forwhom.size(); if(spaces < 0) spaces = 0;
+        std::cerr << forwhom << std::string(spaces, ' ');
+        
+        std::cerr << ':';
+        for(size_t a=0, b=stack.size(); a<b; ++a)
+        {
+            std::cerr << " [";
+            const Location& loc = stack[a];
+            switch(loc.Loc)
+            {
+                case Location::ST:
+                    std::cerr << "ST" << loc.st_no; break;
+                case Location::XMM:
+                    std::cerr << "XMM" << loc.xmm_no; break;
+                case Location::Mem:
+                    std::cerr << loc.memaddr; break;
+                case Location::Stack:
+                    std::cerr << "SP" << loc.stackoffs; break;
+                case Location::Copy:
+                case Location::CopyDontMind:
+                    std::cerr << "=" << loc.is_copyof;
+                    if(loc.Loc == Location::CopyDontMind) std::cerr << '!';
+                    break;
+            }
+            std::cerr << "]";
+        }
+        std::cerr << "    (FPU depth " << fpu_stack_depth << ")";
+        std::cerr << std::endl;
+        #endif
+    }
+
+    void GenDup(int dupwhich, bool write_original_ok = false)
+    {
+        Location topcopy;
+        topcopy.Loc       = write_original_ok ? Location::CopyDontMind : Location::Copy;
+        topcopy.is_copyof = dupwhich;
+        stack.push_back(topcopy);
+    }
+    void GenDup()
+    {
+        GenDup(stack.size()-1);
+    }
+
+    void GenBinaryOp(
+        int by_itself,
+        uint_fast32_t sse,
+        unsigned short fpua,    // st0 = st0 - stX (aka. self)
+        unsigned short fpub,    // stX = stX - st0
+        unsigned short fpuc,    // stX = st0 - stX
+        unsigned short fpud,    // st0 = stX - st0
+        unsigned short fpupopa, // stX = st0 - stX, pop
+        unsigned short fpupopb, // stX = stX - st0, pop
+        unsigned short fpumema, // st0 = st0 - mem
+        unsigned short fpumemb) // st0 = mem - st0
+    {
+        if(by_itself)
+            GenBinaryOp_Self(
+                (sse >> 16) & 0xFF,
+                (sse >> 8) & 0xFF,
+                (sse) & 0xFF,
+                fpua,
+                by_itself == 2);
+        else
+            GenBinaryOp_Actual(
+                (sse >> 16) & 0xFF,
+                (sse >> 8) & 0xFF,
+                (sse) & 0xFF,
+                fpua, fpub, fpuc, fpud,
+                fpupopa, fpupopb,
+                fpumema, fpumemb);
+    }
+    
+    void GenBinaryOp_Self(
+        int sse1,int sse2,int sse3,
+        unsigned short fpuself,
+        bool special_kind)
+    {
+        Location& top = GetShadow(stack[stack.size()-1]);
+        
+        if(SSE && !(top.Loc == Location::ST && top.st_no == 0)
+         && (sse1 || sse2 || sse3))
+        {
+            if(special_kind) // special: input:read, output:write
+            {
+                if(top.Loc == Location::Mem)
+                {
+                    int xmm = GetFreeXMM();
+                    machine.SynthXMM_Mem(sse1,(xmm&8)?0x44:0, sse2,sse3,(xmm&7)*8, top.memaddr, !top.is_constant);
+                    top.Loc    = Location::XMM;
+                    top.xmm_no = xmm;
+                    return;
+                }
+                if(top.Loc == Location::Stack)
+                {
+                    int xmm = GetFreeXMM();
+                    machine.SynthXMM_Stack(sse1,(xmm&8)?0x44:0, sse2,sse3,(xmm&7)*8, top.stackoffs);
+                    Stack_Use.erase(top.stackoffs);
+                    top.Loc    = Location::XMM;
+                    top.xmm_no = xmm;
+                    return;
+                }
+            }
+            // parameter: read+write
+            int xmm = RequireXMM(0, true);
+            machine.SynthXMM_XMM(sse1,sse2,sse3, xmm, xmm);
+        }
+        else
+        {
+            RequireST(0,0, true);
+            machine.SynthST_Stno(fpuself, 0);
+        }
+    }
+    
+    void GenBinaryOp_Actual(
+        int sse1,int sse2,int sse3,
+        unsigned short fpua,    // st0 = st0 - stX (aka. self)
+        unsigned short fpub,    // stX = stX - st0
+        unsigned short fpuc,    // stX = st0 - stX
+        unsigned short fpud,    // st0 = stX - st0
+        unsigned short fpupopa, // stX = st0 - stX, pop
+        unsigned short fpupopb, // stX = stX - st0, pop
+        unsigned short fpumema, // st0 = st0 - mem
+        unsigned short fpumemb) // st0 = mem - st0
+    {
+        // prev:read+write, top:read
+
+        /*
+            Possible situations for FPU binary opcodes are:
+            
+                  Prev (1)     Top (0)     Opcode      Finish
+
+                  STx (W)      ST0 (W)     fpupopb     delete 0 and pop
+                  ST0 (W)      STx (W)     fpupopa     delete 1 and pop
+                  ST0 (W)      STx (R)     fpua        delete 0
+                  STx (R)      ST0 (W)     fpud        delete 1
+                  STx (W)      ST0 (R)     fpub        delete 0
+                  ST0 (R)      STx (W)     fpuc        delete 1
+                  ST0 (W)      other (*)   fpumema     delete 0
+                  other (*)    ST0 (W)     fpumemb     delete 1
+                  
+                  All of above take precedence over SSE.
+                  
+                  STx (*)      other (*)   RequireST(1,0,true) and retry
+                  other (*)    other (*)   RequireST(0,0,true) and retry
+        */
+    Retry: ;
+        Location& realtop = stack[stack.size()-1];
+        Location& top = GetShadow(realtop);
+        Location& realprev = stack[stack.size()-2];
+        Location& prev= GetShadow(realprev);
+
+        CleanupFPUstack();
+
+        bool PrevW = realprev.Loc != Location::Copy;
+        bool TopW  = realtop.Loc != Location::Copy;
+        int PrevST = prev.Loc == Location::ST ? prev.st_no : -1;
+        int TopST  = top.Loc == Location::ST ? top.st_no : -1;
+        
+        /*
+        std::cerr << "Prev(";
+        if(PrevST >= 0) std::cerr << "ST" << PrevST; else std::cerr << "other";
+        std::cerr << (PrevW ? ",W)" : ",R)");
+        std::cerr << "Top(";
+        if(TopST >= 0) std::cerr << "ST" << TopST; else std::cerr << "other";
+        std::cerr << (TopW ? ",W)\n" : ",R)\n");
+        */
+        
+        // See the table in above comment for explanations on what happens here        
+        if(PrevW && TopW && PrevST >= 0 && TopST == 0)
+        { machine.SynthST_Stno(fpupopb, PrevST); DidPop(0, true); return; }
+        if(PrevW && TopW && PrevST == 0 && TopST >= 0)
+        { machine.SynthST_Stno(fpupopa, TopST); DidPop(1, true); return; }
+        if(PrevW && !TopW && PrevST == 0 && TopST >= 0)
+        { machine.SynthST_Stno(fpua, TopST); DidPop(0); return; }
+        if(!PrevW && TopW && PrevST >= 0 && TopST == 0)
+        { machine.SynthST_Stno(fpud, PrevST); DidPop(1); return; }
+        if(PrevW && !TopW && PrevST >= 0 && TopST == 0)
+        { machine.SynthST_Stno(fpub, PrevST); DidPop(0); return; }
+        if(!PrevW && TopW && PrevST == 0 && TopST >= 0)
+        { machine.SynthST_Stno(fpuc, TopST); DidPop(1); return; }
+        if(PrevW && PrevST == 0)
+        { if(top.Loc == Location::Mem)
+            { machine.SynthST_Mem(fpumema, top.memaddr, !top.is_constant); DidPop(0); return; }
+          if(top.Loc == Location::Stack)
+            { machine.SynthST_Stack(fpumema, top.stackoffs); DidPop(0); return; }
+        }
+        if(TopW && TopST == 0)
+        { if(prev.Loc == Location::Mem)
+            { machine.SynthST_Mem(fpumemb, prev.memaddr, !prev.is_constant); DidPop(1); return; }
+          if(prev.Loc == Location::Stack)
+            { machine.SynthST_Stack(fpumemb, prev.stackoffs); DidPop(1); return; }
+        }
+        
+        // Now try SSE code, if SSE is enabled and an SSE opcode was given.
+
+        if(SSE && (sse1 || sse2 || sse3))
+        {
+            int cur = RequireXMM(1, true); // rw-register
+            
+            if(top.Loc == Location::Mem)
+                machine.SynthXMM_Mem(sse1,(cur&8)?0x44:0, sse2,sse3,(cur&7)*8, top.memaddr, !top.is_constant);
+            else if(top.Loc == Location::Stack)
+                machine.SynthXMM_Stack(sse1,(cur&8)?0x44:0, sse2,sse3,(cur&7)*8, top.stackoffs);
+            else // RequireXMM will spill if necessary 
+                machine.SynthXMM_XMM(sse1,sse2,sse3, cur, RequireXMM(0, false)); // read-register
+            
+            DidPop(0);
+            return;
+        }
+        
+        // Back to FPU possibilities
+        
+        if(PrevST >= 0)
+        {
+            RequireST(1,0, true);
+            StackDump("retry");
+            goto Retry;
+        }
+        RequireST(0,0,true);
+        StackDump("retry");
+        goto Retry;
+    }
+    
+    int RequireST_any(int top_offs, bool write)
+    {
+        // Generates the necessary statements to ensure
+        // that the given stack position is in some ST register
+        Location& realtop = stack[stack.size()-1 - top_offs];
+        if(write && realtop.Loc == Location::Copy)
+        {
+            // Must create a genuine duplicate
+            CopyToST(GetShadow(realtop), 0);
+            SimuSTpop(1);
+            realtop.Loc   = Location::ST;
+            realtop.st_no = 0;
+            return 0;
+        }
+        
+        // Just arrange the actual content to be in whatever ST is convenient
+        Location& top = GetShadow(realtop);
+        if(top.Loc == Location::ST) return top.st_no; // Nice, already in an ST
+        // Not in ST? Then I guess we get ST0.
+        MoveToST(top, 0);
+        return 0;
+    }
+    void RequireST(int top_offs, int stno, bool write)
+    {
+        int got_stno = RequireST_any(top_offs, write);
+        if(got_stno != stno) // If we didn't get what we wanted
+        {
+            Location& loc = GetShadow(stack[stack.size()-1 - top_offs]);
+            MoveToST(loc, stno);
+        }
+    }
+    int RequireXMM(int top_offs, bool write)
+    {
+        // Generates the necessary statements to ensure
+        // that the given stack position is in some XMM register
+        
+        Location& realtop = stack[stack.size()-1 - top_offs];
+        if(write && realtop.Loc == Location::Copy)
+        {
+            // Must create a genuine duplicate
+            int orig_xmm = RequireXMM(realtop.is_copyof, false);
+            int copy_xmm = GetFreeXMM();
+            Location newloc = CopyToXMM(stack[realtop.is_copyof], copy_xmm);
+            realtop = newloc;
+            return copy_xmm;
+        }
+        
+        // Load register for access.
+        Location& top = GetShadow(realtop);
+        if(top.Loc != Location::XMM)
+        {
+            int xmm = GetFreeXMM();
+            MoveToXMM(top, xmm);
+        }
+        return top.xmm_no;
+    }
+
+    void RoomST(int n) // Ensures there's room for at least n items of growth in ST
+    {
+        while(fpu_stack_depth+n > 8)
+        {
+            Location& st = FindST(fpu_stack_depth-1);
+            if(st.Loc != Location::ST)
+            {
+                std::cout << "RoomST(): No ST" << fpu_stack_depth-1 << " found\n";
+                break;
+            }
+            else
+                Spill(st);
+        }
+    }
+    Location& FindST(int stno)
+    {
+        for(size_t a=0; a<stack.size(); ++a)
+            if(stack[a].Loc == Location::ST
+            && stack[a].st_no == stno)
+                return stack[a];
+        static Location dummy;
+        return dummy;
+    }
+    void GotST() // Informs that we've got a new value in st0
+    {
+        SimuSTpop(1);
+        Location loc;
+        loc.Loc   = Location::ST;
+        loc.st_no = 0;
+        stack.push_back(loc);
+    }
+    void GotXMM(int xmm)
+    {
+        Location loc;
+        loc.Loc    = Location::XMM;
+        loc.xmm_no = xmm;
+        stack.push_back(loc);
+    }
+    void SimuSTpop(int offset = -1)
+    {
+        // assumes that ST0 was just removed from stack
+        for(size_t a=0; a<stack.size(); ++a)
+            if(stack[a].Loc == Location::ST)
+                stack[a].st_no += offset;
+        fpu_stack_depth += offset;
+    }
+    void DidPop(int which = 0, bool st0pop = false)
+    {
+        Location& top = stack[stack.size()-1-which];
+        
+        if(top.Loc == Location::Stack) Stack_Use.erase(top.stackoffs);
+        bool WasCopy = top.Loc == Location::Copy
+                    || top.Loc == Location::CopyDontMind;
+        
+        stack.erase(stack.begin() + stack.size() - 1 - which);
+        
+        if(st0pop && !WasCopy) SimuSTpop();
+    }
+    int GetFreeXMM()
+    {
+    #ifdef __x86_64
+        const int max_xmm = 16;
+    #else
+        const int max_xmm = 8;
+    #endif
+        bool XMM_Use[max_xmm] = {false};
+        for(size_t a=0; a<stack.size(); ++a)
+            if(stack[a].Loc == Location::XMM)
+                XMM_Use[stack[a].xmm_no] = true;
+        for(int n=0; n<max_xmm; ++n)
+        {
+            if(!XMM_Use[n]) return n;
+        }
+        /* Spill one XMM register */
+        for(size_t a=0; a<stack.size(); ++a)
+            if(stack[a].Loc == Location::XMM)
+            {
+                int xmm  = stack[a].xmm_no;
+                Spill(stack[a]);
+                return xmm;
+            }
+        /* Eh, what's the XMM registers being used for then?? */
+        throw std::logic_error("GetFreeXMM: Eh?");
+        return -1;
+    }
+    void Spill(Location& loc)
+    {
+        switch(loc.Loc)
+        {
+            case Location::XMM:
+            {
+                int xmm  = loc.xmm_no;
+                int slot = AllocStackSlot();
+                loc.Loc       = Location::Stack;
+                loc.stackoffs = slot;
+                machine.SynthXMM_Stack(0xF2, (xmm&8)?0x44:0, 0x0F,0x11,(xmm&7)*8, slot);
+                break;
+            }
+            case Location::ST:
+            {
+                int st   = loc.st_no;
+                int slot = AllocStackSlot();
+                loc.Loc       = Location::Stack;
+                loc.stackoffs = slot;
+                
+                if(st == 7)
+                {
+                    // spilling ST(7) is easy. Just fld st(7), and store it.
+                    machine.SynthST_Stno(0xD900, st); // fld st7
+                    machine.SynthST_Stack(0xDD18, loc.stackoffs); // fstp addr
+                    // no renumbering needed.
+                    --fpu_stack_depth;
+                }
+                else
+                {
+                    if(st != 0)
+                    {
+                        // Make it st0 by swapping it with whatever _is_ st0
+                        machine.SynthST_Stno(0xD908, st); // fxch st#
+                        // Now it is st0.
+                        // But st0 is now st, so we have to update it to reflect the fact                        
+                        FindST(0).st_no = st;
+                    }
+                    machine.SynthST_Stack(0xDD18, loc.stackoffs); // fstp addr
+                    SimuSTpop(); // renumber each ST address.
+                }
+                break;
+            }
+            case Location::Mem:
+            case Location::Stack:
+            case Location::Copy:
+            case Location::CopyDontMind:
+                break; // don't need spilling
+        }
+    }
+    Location CopyToXMM(Location& loc, int xmm, bool move = false)
+    {
+    retry:
+        switch(loc.Loc)
+        {
+            case Location::XMM:
+                if(loc.xmm_no != xmm)
+                    machine.SynthXMM_XMM(0xF2, 0x0F,0x10, xmm, loc.xmm_no);
+                break;
+            case Location::ST:
+                Spill(loc);
+                goto retry;
+            case Location::Mem:
+            {
+                if(loc.is_constant && *(const double*)loc.memaddr == 0.0)
+                    machine.SynthXMM_XMM(0, 0x0F,0x57, xmm, xmm); /* zero the register with xorps xmm,xmm */
+                else
+                    machine.SynthXMM_Mem(0xF2, (xmm&8)?0x44:0, 0x0F,0x10,(xmm&7)*8, loc.memaddr, !loc.is_constant);
+                break;
+            }
+            case Location::Stack:
+                machine.SynthXMM_Stack(0xF2, (xmm&8)?0x44:0, 0x0F,0x10,(xmm&7)*8, loc.stackoffs);
+                if(move) Stack_Use.erase(loc.stackoffs);
+                break;
+            case Location::Copy:
+            case Location::CopyDontMind:
+                throw std::logic_error("CopyToXMM called on a Copy");
+        }
+        
+        Location res;
+        res.Loc    = Location::XMM;
+        res.xmm_no = xmm;
+        
+        if(move) loc = res;
+        
+        return res;
+    }
+    void MoveToXMM(Location& loc, int xmm)
+    {
+        CopyToXMM(loc, xmm, true);
+    }
+    
+    Location CopyToST(Location& loc, int stno, bool move = false)
+    {
+    retry:
+        CleanupFPUstack();
+        
+        switch(loc.Loc)
+        {
+            case Location::XMM:
+                Spill(loc);
+                goto retry;
+            case Location::ST:
+            {
+                if(loc.st_no != stno || !move)
+                {
+                    if(!move)
+                    {
+                        RoomST(1); if(loc.Loc != Location::ST) goto retry;
+                        machine.SynthST_Stno(0xD900, loc.st_no); // fld st#
+                    }
+                    else
+                    {
+                        if(loc.st_no != 0)
+                        {
+                            machine.SynthST_Stno(0xD908, loc.st_no); // fxch st#
+                            // Whatever _was_ 0, change it to indicate where it's now
+                            FindST(0).st_no = loc.st_no;
+                        }
+                    }
+                    if(stno != 0)
+                    {
+                        machine.SynthST_Stno(0xD908, stno); // fxch st#
+                        // Whatever _was_ stno, change it to indicate that it's at 0 now
+                        FindST(stno).st_no = 0;
+                    }
+                }
+                break;
+            }
+            case Location::Mem:
+            {
+                RoomST(1); if(loc.Loc != Location::Mem) goto retry;
+                
+                if(loc.is_constant && *(const double*)loc.memaddr == 0.0)
+                    machine.Synth(0xD9, 0xEE); // fldz
+                else if(loc.is_constant && *(const double*)loc.memaddr == 1.0)
+                    machine.Synth(0xD9, 0xE8); // fld1
+                else if(loc.is_constant && *(const double*)loc.memaddr == 3.3219280948873623478)
+                    machine.Synth(0xD9, 0xE9); // log2(10)
+                else if(loc.is_constant && *(const double*)loc.memaddr == 1.4426950408889634074)
+                    machine.Synth(0xD9, 0xEA); // log2(e)
+                else if(loc.is_constant && *(const double*)loc.memaddr == 3.14159265358979323846)
+                    machine.Synth(0xD9, 0xEB); // fldpi
+                else if(loc.is_constant && *(const double*)loc.memaddr == 0.86858896380650365529)
+                    machine.Synth(0xD9, 0xEC); // log10(2)
+                else if(loc.is_constant && *(const double*)loc.memaddr == 0.69314718055994530943)
+                    machine.Synth(0xD9, 0xED); // loge(2)
+                else
+                    machine.SynthST_Mem(0xDD00, loc.memaddr, !loc.is_constant); // fld qword [...]
+                
+                if(move) SimuSTpop(1);
+                
+                if(stno != 0) { loc.Loc = Location::ST; loc.st_no = 0; goto retry; } //FIXME copy?
+                break;
+            }
+            case Location::Stack:
+                RoomST(1); if(loc.Loc != Location::Stack) goto retry;
+                
+                machine.SynthST_Stack(0xDD00, loc.stackoffs); // fld qword [...]
+                if(move) SimuSTpop(1);
+                if(move) Stack_Use.erase(loc.stackoffs);
+                if(stno != 0) { loc.Loc = Location::ST; loc.st_no = 0; goto retry; } //FIXME copy?
+                break;
+            case Location::Copy:
+            case Location::CopyDontMind:
+                throw std::logic_error("CopyToST called on a Copy");
+        }
+        
+        Location res;
+        res.Loc    = Location::ST;
+        res.st_no  = stno;
+        
+        if(move) loc = res;
+        
+        return res;
+    }
+
+    void MoveToST(Location& loc, int stno)
+    {
+        CopyToST(loc, stno, true);
+    }
+
+    int AllocStackSlot()
+    {
+        int n=0;
+        while(Stack_Use.find(n) != Stack_Use.end()) n -= 8;
+        Stack_Use.insert(n);
+        
+        int use = (-n) + 8;
+        if(use > max_stack_use) max_stack_use = use;
+        
+        return n;
+    }
+    
+    void CleanupFPUstack()
+    {
+    retry: ;
+        if(fpu_stack_depth <= 0) return;
+        
+        /* If we don't care what is in ST0, pop it
+         * so that we don't need to do fxch and stuff. */
+        Location& st = FindST(0);
+        if(st.Loc != Location::ST)
+        {
+            /* TODO: Is there a more efficient way of
+             * popping ST0 than storing it into a dummy
+             * memory address?
+             */
+            int slot = AllocStackSlot();
+            machine.SynthST_Stack(0xDD18, slot);
+            SimuSTpop();
+            Stack_Use.erase(slot);
+            goto retry;
+        }
+    }
+    
+    
+    bool InSSEmode() const { return SSE; }
+    bool StackTopIsConst(int offset=0) const
+    {
+        const Location& top = GetShadow(stack[stack.size()-1-offset]);
+        return top.Loc == Location::Mem
+            && top.is_constant;
+    }
+    const double& GetStackTopConst(int offset=0) const
+    {
+        const Location& top = GetShadow(stack[stack.size()-1-offset]);
+        return *(const double*) top.memaddr;
+    }
+};
+
diff -NaHudr fparser-jittest-1.3/compiler_trans.hh fparser-jittest-1.4/compiler_trans.hh
--- fparser-jittest-1.3/compiler_trans.hh	1970-01-01 02:00:00.000000000 +0200
+++ fparser-jittest-1.4/compiler_trans.hh	2008-01-15 01:04:39.000000000 +0200
@@ -0,0 +1,293 @@
+static int Log2up(unsigned long value)
+{
+    unsigned long res = 0;
+    while(value > (1LU << res)) ++res;
+    return res;
+}
+static int PopCount(unsigned long value) // population count
+{
+    static const int counts[16] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 };
+    int result = 0;
+    while(value > 0) { result += counts[value & 15]; value >>= 4; }
+    return result;
+}
+
+class ByteCodeTranslator
+{
+private:
+    static bool CreateTree_IntegerPow(const double& immed, CodeTree& tree)
+    {
+        /* Check for special cases of integer exponents */
+        for(int sqrtcount=0; sqrtcount < 30; ++sqrtcount)
+        {
+            const double immed_effected = immed * (1 << sqrtcount);
+            if( (int)immed_effected == immed_effected)
+            {
+                int power = (int)immed_effected;
+                if(power < 0) power = -power;
+                
+                /*
+                  x ^ 11 translates like this:
+                  
+                  Algorithm:
+                   (pow=11)  pow&1 ? make backup: x^1, zero low bit of pow
+                   (pow=10)  pow&1 ? no, do Mul, shift low bit of pow
+                   (pow=5)   pow&1 ? make backup: x^2, zero low bit
+                   (pow=4)   pow&1 ? no, do Mul, shift low bit
+                   (pow=2)   pow&1 ? no, do Mul, shift low bit
+                   (pow=1)   flush backups.
+                  
+                  Result:
+                    tmp1 = x  // backup of x^1
+                    x *= x    // now x^2
+                    tmp2 = x  // backup of x^2
+                    x *= x    // now x^4
+                    x *= x    // now x^8
+                    x *= tmp2 // now x^10
+                    x *= tmp1 // now x^11
+                    
+                  x ^ 10 translates like this:
+                    x *= x    // now x^2
+                    tmp1 = x  // backup of x^2
+                    x *= x    // now x^4
+                    x *= x    // now x^8
+                    x *= tmp1 // now x^10
+                    
+                 This algorithm can still be improved,
+                 for example:
+                 
+                  x ^ 15 is better as:
+                    tmp1 = x  // backup of x^1
+                    x *= x    // now x^2
+                    x *= x    // now x^4
+                    x *= x    // now x^8
+                    x *= x    // now x^16
+                    x /= tmp1 // now x^15
+                  than:
+                    tmp1 = x  // backup of x^1
+                    x *= x    // now x^2
+                    tmp2 = x  // backup of x^2
+                    x *= x    // now x^4
+                    tmp3 = x  // backup of x^4
+                    x *= x    // now x^8
+                    x *= tmp3 // now x^12
+                    x *= tmp2 // now x^14
+                    x *= tmp1 // now x^15
+                  This is what gcc does, btw:
+                    tmp1 = x  // backup of x^1
+                    tmp1 *= x // now tmp1 is x^2
+                    tmp1 *= x // now tmp1 is x^3
+                    x = tmp1  // now x^3
+                    x *= tmp1 // now x^6
+                    tmp1 *= x // now tmp1 is x^9
+                    x *= tmp1 // now x^15
+                  
+                  x ^ 27 could be x^32 - x^4 - x^1
+                    tmp1 = x // backup of x^1
+                    x *= x   // now x^2
+                    x *= x   // now x^4
+                    tmp2 = x // backup of x^4
+                    x *= x   // now x^8
+                    x *= x   // now x^16
+                    x *= x   // now x^32
+                    x /= tmp2 // now x^28
+                    x /= tmp1 // now x^27
+                  rather than:
+                    tmp1 = x // backup of x^1  (26)
+                    x *= x   // now x^2        (13)
+                    tmp2 = x // backup of x^2  (12)
+                    x *= x   // now x^4        (6)
+                    x *= x   // now x^8        (3)
+                    tmp3 = x // backup of x^8  (2)
+                    x *= x   // now x^16       (1)
+                    x *= tmp3 // now x^24
+                    x *= tmp2 // now x^26
+                    x *= tmp1 // now x^27
+                    
+                  However, exception is required because:
+                  x^3:  normally  x^2 * x
+                    tmp1 = x
+                    x *= x
+                    x *= tmp1 
+                        modified  x^4 / x
+                    tmp1 = x
+                    x *= x
+                    x *= x
+                    x /= tmp1
+                
+                Done as described.
+                */
+                
+                //synth.StackDump("opPow (inlined)");
+                
+                std::list<bool/*true=mul,false=div*/> backuplist;
+                bool polarity = true;
+                while(power > 1)
+                {
+                    if(power & 1)
+                    {
+                        int next_power_of_2 = Log2up(power);
+                        int popcount        = PopCount(power);
+                        if(power != 3 && popcount > next_power_of_2 / 2)
+                        {
+                            power = (1 << next_power_of_2) - power;
+                            polarity = !polarity;
+                        }
+
+                        tree.GenDup(); //  make dup
+                        --power;
+                        backuplist.push_back(polarity);
+                        continue;
+                    }
+                    tree.GenMul(true); // mul self
+                    power /= 2;
+                }
+                while(!backuplist.empty())
+                {
+                    bool val = backuplist.back(); backuplist.pop_back();
+                    if(val)
+                        tree.GenMul(false); // mul and pop
+                    else
+                        tree.GenDiv(false); // div and pop
+                }
+
+                if(immed < 0) // negative exponents are 1/x
+                {
+                    tree.GenConstLoad(FP_Constant_One);
+                    tree.SwapTop2();
+                    tree.GenDiv(false);
+                }
+                for(; sqrtcount > 0; --sqrtcount)
+                    tree.GenSqrt();
+                
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static void CreateTree(
+        const opcode* const op_begin,
+        const opcode* const op_end,
+        CodeTree& tree,
+        size_t ImmedPtr = 0)
+    {
+        for(const opcode* op = op_begin; op < op_end; )
+            switch(*op++)
+            {
+                case opPlus:  tree.GenAdd(false); break; // faddp st(1)
+                case opMinus: tree.GenSub(false); break; // fsubp st(1)
+                case opMul:   tree.GenMul(false); break; // fmulp st(1)
+                case opDiv:   tree.GenDiv(false); break; // fdivp st(1)
+                case opDup:
+                    if(*op == opMul) // opDup,opMul  x*x idiom?
+                    {
+                        // do a fmul without involving the stack
+                        ++op;
+                        tree.GenMul(true);
+                    }
+                    else if(*op == opPlus) // opDup,opPlus  x+x idiom?
+                    {
+                        // do a fadd without involving the stack
+                        ++op;
+                        tree.GenAdd(true);
+                    }
+                    else
+                    {
+                        tree.GenDup();
+                    }
+                    break;
+                case opNeg:   tree.GenNeg(); break;
+                case opSqrt:  tree.GenSqrt(); break;
+                case opSin:   tree.GenSin(); break;
+                case opCos:   tree.GenCos(); break;
+                case opExp:   tree.GenConstLoad(FP_Constant_Exp1);
+                              tree.SwapTop2(); // fallthrough to Pow
+                case opPow:   tree.GenPow(); break;
+
+                case opImmed: 
+                {
+                    const double& immed = immeds[ImmedPtr++];
+                    
+                    if(*op == opPow && immed != 0.0)
+                    {
+                        bool GotCode = CreateTree_IntegerPow(immed, tree);
+                        if(GotCode)
+                        {
+                            ++op; // skip pow
+                            goto DoneImmed;
+                        }
+                    }
+                    if(*op == opMul)
+                    {
+                        if(immed == 2.0)
+                        {
+                            ++op;
+                            tree.GenAdd(true); // Do x+x instead
+                            goto DoneImmed;
+                        }
+                    }
+                    tree.GenConstLoad(immed);
+                DoneImmed:
+                    break;
+                }
+                
+                default:
+                {
+                    double& var = vars[ (size_t) (op[-1] - opVarBegin) ];
+                    tree.GenVarLoad(var);
+                    break;
+                }
+            }
+    }
+        
+public:
+    void SynthTo(
+        CodeSynth& synth,
+        std::vector<unsigned char>& CodeBuffer,
+        const opcode* const op_begin,
+        const opcode* const op_end,
+        bool RunCSE,
+        size_t ImmedPtr = 0,
+        bool DoEntryExit = true)
+    {
+        size_t stack_required = 0;
+        
+        size_t begin_pos = CodeBuffer.size();
+        
+        CodeTree tree;
+        CreateTree(op_begin, op_end, tree, ImmedPtr);
+        if(RunCSE) tree.RunCSE();
+        //tree.TreeDump("After CSE");
+        
+        synth.SynthCode(tree.GetTree());
+        
+        if(DoEntryExit)
+        {
+            /* Move result to the result register if needed */
+            synth.PullResult();
+            
+            /* Allocate and deallocate stack if needed */
+            size_t stack_required = synth.GetMaxStackUse();
+            if(stack_required)
+            {
+                #ifndef __x86_64
+                // add nice aligning
+                stack_required = ((stack_required + 4 + 15) & ~ 15) - 4;
+                #endif
+                
+                std::vector<unsigned char> tmp;
+                CodeBuffer.swap(tmp);
+                // Write the stack init code to a temporary buffer
+                synth.SynthStackBegin(stack_required);
+                CodeBuffer.swap(tmp);
+                
+                // Insert the stack init code to the right place
+                CodeBuffer.insert(CodeBuffer.begin() + begin_pos, tmp.begin(), tmp.end());
+            
+                synth.SynthStackEnd(stack_required);
+            }
+            CodeBuffer.push_back(0xC3); // ret
+        }
+    }
+};
diff -NaHudr fparser-jittest-1.3/compiler_tree.hh fparser-jittest-1.4/compiler_tree.hh
--- fparser-jittest-1.3/compiler_tree.hh	1970-01-01 02:00:00.000000000 +0200
+++ fparser-jittest-1.4/compiler_tree.hh	2008-01-15 00:53:43.000000000 +0200
@@ -0,0 +1,420 @@
+#include <sstream>
+#include <list>
+#include "hash.hh"
+#include "autoptr"
+
+typedef autoptr<struct CodeTreeItem> CodeTreeP;
+
+static const bool DO_CONSTANT_FOLDING = true;
+
+struct CodeTreeItem: public ptrable
+{
+    std::string expl;
+    
+    opcode op;
+    int expr_num;
+    const double* param;
+    
+    CodeTreeP parent;
+    CodeTreeP st2, st1, st0;
+    
+public:
+    CodeTreeItem()
+        : expl(), op(), expr_num(), param(0), parent(), st2(), st1(), st0() { }
+    // constructors
+    CodeTreeItem(opcode o, CodeTreeP s0)
+        : expl(), op(o), expr_num(), param(0), parent(), st2(), st1(), st0(s0) { Fixup(); }
+    CodeTreeItem(opcode o, CodeTreeP s1, CodeTreeP s0)
+        : expl(), op(o), expr_num(), param(0), parent(), st2(), st1(s1), st0(s0) { Fixup(); }
+    CodeTreeItem(opcode o, CodeTreeP s2, CodeTreeP s1, CodeTreeP s0)
+        : expl(), op(o), expr_num(), param(0), parent(), st2(s2), st1(s1), st0(s0) { Fixup(); }
+    CodeTreeItem(opcode o, int en)
+        : expl(), op(o), expr_num(en), param(0), parent(), st2(), st1(), st0() { Fixup(); }
+    CodeTreeItem(opcode o, int en, CodeTreeP s1, CodeTreeP s0)
+        : expl(), op(o), expr_num(en), param(0), parent(), st2(), st1(s1), st0(s0) { Fixup(); }
+    CodeTreeItem(opcode o, const double* p)
+        : expl(), op(o), expr_num(), param(p), parent(), st2(), st1(), st0() { Fixup(); }
+    
+public:
+    // Complexity for determining which nodes should be CSEd
+    long Complexity() const
+    {
+        long res = 1;
+        switch(op)
+        {
+            case opImmed:    res = 2; break;
+            case opVarBegin: res = 2; break;
+            case opMul: case opDiv: res = 3; break;
+            case opSqrt: res = 6; break;
+            case opSin: case opCos: res = 40; break;
+            case opPow: res = 30; break;
+            default: break;
+        }
+        if(st0) res += st0->Complexity();
+        if(st1) res += st1->Complexity();
+        if(st2) res += st2->Complexity();
+        return res;
+    }
+    
+    bool IsCSEcandidate() const
+    {
+        if(op == opStoreTemp
+        || op == opRecallTempR
+        || op == opRecallTempW) return false;
+        return st2 || st1 || st0;
+    }
+    
+    std::string NodeDump() const
+    {
+        std::stringstream tmp;
+        #define p(p) case p: tmp << #p; break;
+        switch(op)
+        {
+            p(opPlus); p(opMinus); p(opMul); p(opDiv);
+            p(opDup); p(opNeg); p(opSqrt); p(opPow);
+            p(opSin); p(opCos); p(opExp); p(opImmed);
+            p(opStoreTemp); p(opRecallTempR); p(opRecallTempW);
+            p(opVarBegin);
+        }
+        if(op == opStoreTemp
+        || op == opRecallTempR
+        || op == opRecallTempW)
+            tmp << "(" << expr_num << ")";
+        if(op == opImmed)
+            tmp << "(" << *param << ")";
+        if(op == opVarBegin)
+            tmp << "(" << param << ")";
+        #undef p
+        return tmp.str();
+    }
+
+    void TreeDump(int n_indent) const
+    {
+        for(int n=0; n<n_indent; ++n)
+            std::cerr << "| ";
+        std::cerr << "[" << this << "] ";
+        
+        std::cerr << NodeDump();
+        
+        std::cerr << " [parent=" << &*parent << "]\n";
+        if(st2) st2->TreeDump(n_indent+1);
+        if(st1) st1->TreeDump(n_indent+1);
+        if(st0) st0->TreeDump(n_indent+1);
+    }
+private:
+    bool ConstParams() const
+    {
+        if(st2 && st2->op != opImmed) return false;
+        if(st1 && st1->op != opImmed) return false;
+        if(st0 && st0->op != opImmed) return false;
+        return true;
+    }
+    double GetConst() const { return *param; }
+    
+    void ReplaceWithConst(double value)
+    {
+        static std::list<double> values; // FIXME: Put somewhere else
+        values.push_back(value);
+        op = opImmed;
+        param = &values.back();
+        st2 = st1 = st0 = 0;
+    }
+      
+    void Fixup()
+    {
+        if(ConstParams())
+        {
+            switch(op)
+            {
+                case opPlus:  ReplaceWithConst(st1->GetConst() + st0->GetConst()); break;
+                case opMinus: ReplaceWithConst(st1->GetConst() - st0->GetConst()); break;
+                case opMul:   ReplaceWithConst(st1->GetConst() * st0->GetConst()); break;
+                case opDiv:   ReplaceWithConst(st1->GetConst() / st0->GetConst()); break;
+                case opNeg:   ReplaceWithConst(-st0->GetConst()); break;
+                case opSin:   ReplaceWithConst(std::sin(st0->GetConst())); break;
+                case opCos:   ReplaceWithConst(std::cos(st0->GetConst())); break;
+                case opSqrt:  ReplaceWithConst(std::sqrt(st0->GetConst())); break;
+                case opPow:   ReplaceWithConst(std::pow(st1->GetConst(), st0->GetConst())); break;
+                default: ;
+            }
+        }
+        
+        if(op == opPlus || op == opMinus)
+        {
+            bool negative = op == opMinus;
+            
+            // a + -b  = a-b;  a - -b = a+b
+            if(st0->op == opNeg) { negative = !negative; st0 = st0->st0; } // gobble!
+            
+            // -a + b = b - a
+            if(!negative && st1->op == opNeg)
+                { negative = !negative; std::swap(st0, st1); st0 = st0->st0; } // flip&gobble!
+            
+            // 5 + (a + 3) = 8 + a
+            // 5 - (a + 3) = 2 - a
+            // 5 + (a - 3) = 2 + a
+            // 5 - (a - 3) = 8 - a
+            // (a + 3) + 5 = a + 8
+            // (a + 3) - 5 = a - 2
+            // (a - 3) + 5 = a + 2
+            // (a - 3) - 5 = a - 8
+            
+         /* -- Nah this job is better left to the optimizer.
+            if(st1->op == opImmed && (st0->op == Plus || st0->op == Minus)
+                                  && st0->st0->op == opImmed)
+            {
+                st1->ReplaceWithConst( (negative ^ (st0->op == Minus))
+                                     ? st1->GetConst() - st0->st0->GetConst()
+                                     : st1->GetConst() + st0->st0->GetConst());
+                st0 = st0->st1;
+                goto reck;
+            }
+          */
+            op = negative ? opMinus : opPlus;
+        }
+        
+    
+        /* If the nodes could be in either order, reorder them so
+         * that identicality checking gets more positives */
+        if(op == opPlus || op == opMul)
+        {
+            if(st1->expl < st0->expl) std::swap(st0, st1);
+        }
+        expl = CreateExpl();
+    }
+    
+    // Creates the hash'able item for finding identical trees
+    std::string CreateExpl() const
+    {
+        std::stringstream tmp;
+        tmp << '[' << (int)op << ':' << expr_num;
+        if(param) { if(op == opVarBegin) tmp << param; // pointer
+                    else { const char* d = (const char*)param; // raw floating point value
+                           tmp << std::string(d, d+sizeof(param));
+                    }    }
+        if(st0) tmp << st0->CreateExpl();
+        if(st1) tmp << st1->CreateExpl();
+        if(st2) tmp << st2->CreateExpl();
+        tmp << ']';
+        return tmp.str();
+    }
+};
+
+template<typename P>
+struct Compare1st
+{
+    bool operator() (const P& a, const P& b) const
+    {
+        return a.first < b.first;
+    }
+};
+
+class CodeTree
+{
+    std::vector<CodeTreeP> stack;
+    typedef std::pair<long, std::vector<CodeTreeP > > node_info;
+    typedef hash_map<std::string, node_info> nodelist_t;
+    nodelist_t nodes;
+    size_t num_saved_exprs;
+    
+public:
+    CodeTree(): stack(), nodes(), num_saved_exprs(0)
+        { }
+
+    void GenAdd(bool by_itself) { GenBinary(opPlus, by_itself); }
+    void GenSub(bool by_itself) { GenBinary(opMinus, by_itself); }
+    void GenMul(bool by_itself) { GenBinary(opMul, by_itself); }
+    void GenDiv(bool by_itself) { GenBinary(opDiv, by_itself); }
+    void GenDup()  { stack.push_back(t()); }
+    void GenNeg()  { GenUnary(opNeg); }
+    void GenSin()  { GenUnary(opSin); }
+    void GenCos()  { GenUnary(opCos); }
+    void GenSqrt() { GenUnary(opSqrt); }
+    void GenConstLoad(const double& b) { stack.push_back(GenNode(new CodeTreeItem(opImmed, &b))); }
+    void GenVarLoad(const double& b)   { stack.push_back(GenNode(new CodeTreeItem(opVarBegin, &b))); }
+    void GenPow()  { GenBinary(opPow, false); }
+    void SwapTop2()
+    {
+        CodeTreeP &a = t(0), &b = t(1);
+        std::swap(a, b);
+    }
+    void RunCSE()
+    {
+    Redo: ;
+        /* Find identical nodes, and create opStoreTemp stuff from them. */
+        
+        /* Algorithm:
+         *   Find the leaf with worst behavior (but > 1 identical copies)
+         *   
+         *   Alter the tree such that the first common anchestor of all
+         *   of those copies gets an extra opStoreTemp node,
+         *   and then all the copies are replaced with opRecallTemp.
+         */
+        typedef nodelist_t::iterator node_it;
+        
+        std::vector<std::pair<long, node_it> > nodelist_byscore;
+        for(node_it i = nodes.begin(); i != nodes.end(); ++i)
+            nodelist_byscore.push_back( std::pair<long, node_it> (i->second.first, i));
+        
+        std::sort(nodelist_byscore.begin(), nodelist_byscore.end(),
+            Compare1st<std::pair<long, node_it> >() );
+        
+        for(size_t a=0, b=nodelist_byscore.size(); a<b; ++a)
+        {
+            node_it i = nodelist_byscore[a].second;
+            node_info& info = i->second;
+            if(info.second.size() <= 1 || !(info.second[0]->IsCSEcandidate())) continue;
+            
+            DoCSE(info);
+            nodes.erase(i); // no longer a concern
+            goto Redo;
+        }
+    }
+    
+    const CodeTreeP& GetTree() const
+    {
+        return stack[0];
+    }
+
+    void TreeDump(const std::string& when) const
+    {
+        std::cerr << when << ":\n";
+        for(size_t a=0, b=stack.size(); a<b; ++a)
+        {
+            std::cerr << "===" << a << "===\n";
+            stack[a]->TreeDump(0);
+        }
+    }
+    
+private:
+    CodeTreeP& t(int n=0) // loads item from stack top
+    {
+        return stack[stack.size()-1 - n];
+    }
+    void GenBinary(opcode op, bool by_itself) // creates a 2-parameter node
+    {
+        CodeTreeP b = t(0), a = by_itself ? b : t(1);
+        if(!by_itself) stack.erase(stack.end()-1);
+        t() = GenNode(new CodeTreeItem(op, a, b));
+        a->parent = t();
+        b->parent = t();
+    }
+    void GenUnary(opcode op) // creates an 1-parameter node
+    {
+        CodeTreeP c = t();
+        t() = GenNode(new CodeTreeItem(op, c));
+        c->parent = t();
+    }
+    
+    CodeTreeP GenNode(const CodeTreeP& b) // adds a new node to node list
+    {
+        node_info& info = nodes[b->expl];
+        
+        info.first -= b->Complexity();
+        info.second.push_back(b);
+        
+        return b;
+    }
+    
+    void DoCSE(node_info& info)
+    {
+        /*
+          Algorithm:
+          - Find the lowest common anchestor of all given nodes
+             - Find the depth of each node
+             - Iterate each node backwards until the depth has been reached
+             - Until the parent of each is identical,
+               iterate each node backwards by 1 simultaneously
+          - Insert a opStoreTemp node at the anchestor, and
+             put ONE of the children to that point
+          - Replace all references to the children by a opRecallTemp node.
+        */
+        std::vector<CodeTreeP>& twins = info.second;
+        size_t num_twins = twins.size();
+        
+        std::vector<std::pair<size_t, CodeTreeP> > depths(num_twins);
+        size_t min_depth = 0;
+        // Find the depth of each node
+        for(size_t a=0; a < num_twins; ++a)
+        {
+            CodeTreeP p = twins[a];
+            size_t depth = 0;
+            while(p) { p = p->parent; ++depth; }
+            depths[a].first  = depth;
+            if(a == 0 || depth < min_depth) min_depth = depth;
+        }
+        
+        // Iterate each node backwards until that depth has been reached
+        for(size_t a=0; a < num_twins; ++a)
+        {
+            CodeTreeP p = twins[a];
+            size_t depth = depths[a].first;
+            while(p && depth > min_depth) { p = p->parent; --depth; }
+            depths[a].second = p;
+        }
+        CodeTreeP LCA;
+        // Until the nodes are identical, iterate backwards by 1
+        for(;;)
+        {
+            LCA = depths[0].second;
+            for(size_t a=1; a < num_twins; ++a)
+                if(&*depths[a].second != &*LCA)
+                    goto LCA_not_found_yet;
+            break; // LCA found
+        LCA_not_found_yet:
+            bool progressed = false;
+            for(size_t a=0; a < num_twins; ++a)
+                if(depths[a].second && depths[a].second->parent)
+                {
+                    depths[a].second = depths[a].second->parent;
+                    progressed = true;
+                }
+            if(!progressed)
+            {
+                throw std::logic_error("Could not find LCA?");
+                return;
+            }
+        }
+        
+        // This is what we want to preserve
+        CodeTreeP preserved_child = twins[0];
+        
+        // Insert a opStoreTemp
+        CodeTreeP newnode = new CodeTreeItem(opStoreTemp, num_saved_exprs, preserved_child, LCA);
+        ReplaceNode(LCA, newnode);
+
+        // replace all children with opRecallTemp
+        for(size_t a=0; a < num_twins; ++a)
+        {
+            CodeTreeP child = twins[a];
+            if(!child) continue;
+            CodeTreeP parent = child->parent;
+            if(!parent) continue;
+            
+            bool last = (a+1) == num_twins;
+            
+            CodeTreeP recall = new CodeTreeItem(/*last ? opRecallTempW : */opRecallTempR, num_saved_exprs);
+            ReplaceNode(child, recall);
+        }
+        
+        preserved_child->parent = newnode;
+        LCA->parent = newnode;
+
+        ++num_saved_exprs;
+    }
+    
+    void ReplaceNode(CodeTreeP oldnode, CodeTreeP newnode)
+    {
+        if(!oldnode) return;
+        for(size_t a=0, b=stack.size(); a<b; ++a)
+            if(&*oldnode == &*stack[a])
+                stack[a] = newnode;
+        
+        CodeTreeP parent = oldnode->parent;
+        if(!parent) return;
+        if(&*parent->st0 == &*oldnode) parent->st0 = newnode;
+        if(&*parent->st1 == &*oldnode) parent->st1 = newnode;
+        if(&*parent->st2 == &*oldnode) parent->st2 = newnode;
+        newnode->parent = parent;
+    }
+};
diff -NaHudr fparser-jittest-1.3/configure fparser-jittest-1.4/configure
--- fparser-jittest-1.3/configure	2008-01-11 10:38:05.000000000 +0200
+++ fparser-jittest-1.4/configure	2008-01-14 11:31:18.000000000 +0200
@@ -98,6 +98,15 @@
   LDFLAGS="$LDFLAGS -L$ICC_PATH""/lib -lirc -lguide -lpthread -lstdc++"
 fi
 
+do_echo -n "Checking if your compiler supports hash_map... "
+if cc_check '"lib/hash.hh"' '-DHASH_MAP=1' 'hash_map<long,int>x; hash_set<long>y;'; then
+  do_echo Yes
+  CPPFLAGS="$CPPFLAGS -DHASH_MAP=1"
+else
+  do_echo No
+  CPPFLAGS="$CPPFLAGS -DHASH_MAP=0"
+fi
+
 WARNINGS=""
 CWARNINGS=""
 CXXWARNINGS=""
diff -NaHudr fparser-jittest-1.3/formula.hh fparser-jittest-1.4/formula.hh
--- fparser-jittest-1.3/formula.hh	2008-01-11 11:17:59.000000000 +0200
+++ fparser-jittest-1.4/formula.hh	2008-01-15 00:49:18.000000000 +0200
@@ -1,10 +1,3 @@
-/*
-Sample formula:
-exp((-x*x-y*y)/100)*sin(sqrt(x*x+y*y))/(10*2)
-     + sin(x^4-4*x^3+3*x^2-2*x+2*5-3)
-     - cos(-2*y^4+5*y^3-14*x^2+8*x-120/2+4)"
-*/
-
 static double vars[] =
 {
     15.0, /* x */
@@ -12,11 +5,12 @@
 };
 static const double immeds[] =
 {
-    100,
+    1024.0,
     10,2,
     4,
     3,4,
     3,
+    2,0.2,
     2,5,
     3,
     4,-2,
@@ -28,14 +22,16 @@
 };
 static const opcode opcodes[] =
 {
-      opVar, (opcode)0, opDup, opMul, opNeg, // -(x*x)
-      opVar, (opcode)1, opDup, opMul, // y*y
+   // opImmed, (opcode)(opVarBegin+0), opDup, opPlus, opPow, // 2^(x+x)
+    
+      (opcode)(opVarBegin+0), opDup, opMul, opNeg, // -(x*x)
+      (opcode)(opVarBegin+1), opDup, opMul, // y*y
      opMinus,
       opImmed, // 100.0
-     opDiv,
+     opMul,
     opExp,
-        opVar, (opcode)0, opDup, opMul, // x*x
-        opVar, (opcode)1, opDup, opMul, // y*y
+        (opcode)(opVarBegin+0), opDup, opMul, // x*x
+        (opcode)(opVarBegin+1), opDup, opMul, // y*y
        opPlus,
       opSqrt,
      opSin,
@@ -45,12 +41,12 @@
      opMul,
     opDiv,
     
-       opVar, (opcode)0, opImmed, opPow,                 // x^4
-       opVar, (opcode)0, opImmed, opPow, opImmed, opMul, // x^3 *4
+       (opcode)(opVarBegin+0), opImmed, opPow,                 // x^4
+       (opcode)(opVarBegin+0), opImmed, opPow, opImmed, opMul, // x^3 *4
       opMinus,
-       opVar, (opcode)0, opDup, opMul, opImmed, opMul,   // x*x *3
+       (opcode)(opVarBegin+0), opDup, opMul, opImmed, opMul,   // x*x *3
       opPlus,
-       opVar, (opcode)0, opDup, opPlus, // x+x
+       opImmed, opImmed, opPow, // 2^0.2
       opMinus,
         opImmed, // 2
         opImmed, // 5
@@ -60,12 +56,12 @@
       opMinus,
      opSin,
     opPlus,
-       opVar, (opcode)1, opImmed, opPow, opImmed, opMul, // y^4 * -2
-       opVar, (opcode)1, opImmed, opPow, opImmed, opMul, // y^3    * 5
+       (opcode)(opVarBegin+1), opImmed, opPow, opImmed, opMul, // y^4 * -2
+       (opcode)(opVarBegin+1), opImmed, opPow, opImmed, opMul, // y^3    * 5
       opPlus,
-       opVar, (opcode)0, opDup, opMul, opImmed, opMul, // x*x * 14
+       (opcode)(opVarBegin+0), opDup, opMul, opImmed, opMul, // x*x * 14
       opMinus,
-       opVar, (opcode)0, opImmed, opMul, // 8*x
+       (opcode)(opVarBegin+0), opImmed, opMul, // 8*x
       opPlus,
         opImmed, // 120
         opImmed, // 2
diff -NaHudr fparser-jittest-1.3/interpreter.hh fparser-jittest-1.4/interpreter.hh
--- fparser-jittest-1.3/interpreter.hh	2008-01-09 19:51:36.000000000 +0200
+++ fparser-jittest-1.4/interpreter.hh	2008-01-14 16:25:25.000000000 +0200
@@ -1,3 +1,5 @@
+#include <stdexcept>
+
 class Interpreter: public Calculator
 {
 public:
@@ -42,7 +44,12 @@
                 case opCos:   { Top() = std::cos(Top()); break; }
                 case opExp:   { Top() = std::exp(Top()); break; }
                 case opImmed: Push( immeds[ ImmedPtr++ ] ); break;
-                case opVar:   Push(   vars[ (size_t) *op++ ] ); break;
+                
+                case opStoreTemp:
+                case opRecallTempR:
+                case opRecallTempW: throw std::logic_error("unexpected opcodes");
+                
+                default:Push(   vars[ (size_t) (op[-1] - opVarBegin) ] ); break;
             }
         return Top();
         #undef FullCheck
diff -NaHudr fparser-jittest-1.3/jittest.cc fparser-jittest-1.4/jittest.cc
--- fparser-jittest-1.3/jittest.cc	2008-01-11 11:41:14.000000000 +0200
+++ fparser-jittest-1.4/jittest.cc	2008-01-15 01:09:39.000000000 +0200
@@ -20,17 +20,9 @@
     double& y = vars[1];
     
     return
-/*    
-    std::pow(x,11)
-   +std::pow(x,10)
-   +std::pow(x,15)
-   +std::pow(x,27)
-   +std::pow(x,120)
-   +std::pow(x,3)
-   +std::pow(x,6);*/
     
-std::exp((-(x*x)-y*y)/100.0)*std::sin(std::sqrt(x*x+y*y)) /(10*2.0)
-     + std::sin(x*x*x*x - 4*x*x*x + 3*x*x - (x+x) + 2*5.0 - 3)
+std::exp((-(x*x)-y*y)*100.0)*std::sin(std::sqrt(x*x+y*y)) /(10*2.0)
+     + std::sin(x*x*x*x - 4*x*x*x + 3*x*x - std::pow(2,0.2) + 2*5.0 - 3)
      - std::cos(-2*y*y*y*y + 5*y*y*y - 14*x*x + 8*x - 120/2.0 + 4)
     ;
 }
@@ -53,7 +45,10 @@
         
         if(valdiff > 1e-2)
         {
-            std::cout << calc.Identify() << ':' << std::flush;
+            std::string id = calc.Identify();
+            while(id.size() < 21) id += ' ';
+            
+            std::cout << id << ':' << std::flush;
             std::cout.precision(12);
             std::cout << val1 << " and " << val2 << " differ ";
             std::cout << "(x=" << x << ", y=" << y << ")";
@@ -71,7 +66,12 @@
     double& x = vars[0];
     double& y = vars[1];
     
-    std::cout << calc.Identify() << ':' << std::flush;
+    x = 15;
+    y = -7.3;
+    
+    std::string id = calc.Identify();
+    while(id.size() < 21) id += ' ';
+    std::cout << id << ':' << std::flush;
     
     clock_t iclock = std::clock();
     size_t counter = 0;
@@ -112,12 +112,18 @@
     Interpreter i(opcodes, sizeof(opcodes)/sizeof(*opcodes));
     DoTimingTests(i);
     
-    Compiler c_fp(opcodes, sizeof(opcodes)/sizeof(*opcodes), false);
+    Compiler c_fp(opcodes, sizeof(opcodes)/sizeof(*opcodes), false, false);
     DoTimingTests(c_fp);
 
+    Compiler c_fp_cse(opcodes, sizeof(opcodes)/sizeof(*opcodes), false, true);
+    DoTimingTests(c_fp_cse);
+
     if(has_sse2)
     {
-        Compiler c_sse(opcodes, sizeof(opcodes)/sizeof(*opcodes), true);
+        Compiler c_sse(opcodes, sizeof(opcodes)/sizeof(*opcodes), true, false);
         DoTimingTests(c_sse);
+
+        Compiler c_sse_cse(opcodes, sizeof(opcodes)/sizeof(*opcodes), true, true);
+        DoTimingTests(c_sse_cse);
     }
 }
diff -NaHudr fparser-jittest-1.3/opcodes.hh fparser-jittest-1.4/opcodes.hh
--- fparser-jittest-1.3/opcodes.hh	2008-01-09 14:40:11.000000000 +0200
+++ fparser-jittest-1.4/opcodes.hh	2008-01-14 20:29:15.000000000 +0200
@@ -1,5 +1,6 @@
 enum opcode
 {
+    // Standard opcodes
     opPlus,
     opMinus,
     opMul,
@@ -12,5 +13,12 @@
     opCos,
     opExp,
     opImmed,
-    opVar
+    
+    // JIT-specific:
+    opStoreTemp,  // store temp
+    opRecallTempR, // read temp
+    opRecallTempW,  // read temp (overwriting it is ok)
+    
+    // Also a standard opcode, must be last of the list
+    opVarBegin
 };
