Demote floating point comparisons even if one side is constant (bug in nanojit, filed as #443884 against tamarin). Also demote add/sub/mul using the integer overflow detection side exit code that Ed adopted upstream. Tight loops (bitwise) are not emitted completely as integer code after the initial compilation using doubles triggered a speculative demotion of the context slots.
authorAndreas Gal <gal@mozilla.com>
Mon, 07 Jul 2008 00:43:40 -0700
changeset 17481 0f7c4afcd5c83af511ec58c8798e0a4716524f96
parent 17480 a051c0844e1ba0b0127db7aeccebebd09222e781
child 17482 d88a5e56ec9382799f89b9a87d8b4f9a561ff1af
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherderautoland@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs443884
milestone1.9.1a1pre
Demote floating point comparisons even if one side is constant (bug in nanojit, filed as #443884 against tamarin). Also demote add/sub/mul using the integer overflow detection side exit code that Ed adopted upstream. Tight loops (bitwise) are not emitted completely as integer code after the initial compilation using doubles triggered a speculative demotion of the context slots.
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -195,34 +195,35 @@ static LIns* demote(LirWriter *out, LIns
     AvmAssert(i->isconstq());
     double cf = i->constvalf();
     int32_t ci = cf > 0x7fffffff ? uint32_t(cf) : int32_t(cf);
     return out->insImm(ci);
 }
 
 static bool isPromoteInt(LIns *i)
 {
-    return i->isop(LIR_i2f);
+    return i->isop(LIR_i2f) || i->isconstq();
 }
 
 static bool isPromoteUint(LIns *i)
 {
-    return i->isop(LIR_u2f);
+    return i->isop(LIR_u2f) || i->isconstq();
 }
 
 static bool isPromote(LIns *i)
 {
     return isPromoteInt(i) || isPromoteUint(i);;
 }
 
 class FuncFilter: public LirWriter
 {
+    TraceRecorder& recorder;
 public:
-    FuncFilter(LirWriter *out):
-        LirWriter(out)
+    FuncFilter(LirWriter *out, TraceRecorder& _recorder):
+        LirWriter(out), recorder(_recorder)
     {
     }
     
     LInsp ins1(LOpcode v, LInsp s0)
     {
         switch (v) {
         case LIR_i2f:
             if (s0->oprnd1()->isCall() && s0->imm8() == F_doubleToInt32) 
@@ -259,16 +260,24 @@ public:
                 return out->ins2(v, demote(out, s1), demote(out, s0));
             } else if (isPromoteUint(s0) && isPromoteUint(s1)) {
                 // uint compare
                 v = LOpcode(v + (LIR_eq - LIR_feq));
                 if (v != LIR_eq)
                     v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp
                 return out->ins2(v, demote(out, s1), demote(out, s0));
             }
+        } else if (v == LIR_fadd || v == LIR_fsub || v == LIR_fmul) {
+            if (isPromoteInt(s0) && isPromoteInt(s1)) {
+                // demote fop to op
+                v = (LOpcode)((int)v & ~LIR64);
+                LIns* result = out->ins2(v, demote(out, s1), demote(out, s0));
+                out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
+                return out->ins1(LIR_i2f, result);
+            }
         }
         return out->ins2(v, s1, s0);
     }
 
     LInsp insCall(int32_t fid, LInsp args[])
     {
         LInsp s0 = args[0];
         switch (fid) {
@@ -396,17 +405,17 @@ TraceRecorder::TraceRecorder(JSContext* 
     lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf);
 #ifdef DEBUG
     lirbuf->names = new (&gc) LirNameMap(&gc, builtins, fragmento->labels);
     lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);
 #endif
     lir = cse_filter = new (&gc) CseFilter(lir, &gc);
     lir = expr_filter = new (&gc) ExprFilter(lir);
     lir = exit_filter = new (&gc) ExitFilter(lir, *this);
-    lir = func_filter = new (&gc) FuncFilter(lir);
+    lir = func_filter = new (&gc) FuncFilter(lir, *this);
     lir->ins0(LIR_trace);
     if (fragment->vmprivate == NULL) {
         /* generate the entry map and stash it in the trace */
         unsigned entryNativeFrameSlots = nativeFrameSlots(entryFrame, entryRegs);
         LIns* data = lir_buf_writer->skip(sizeof(VMFragmentInfo) + 
                 entryNativeFrameSlots * sizeof(char));
         fragmentInfo = (VMFragmentInfo*)data->payload();
         fragmentInfo->entryNativeFrameSlots = entryNativeFrameSlots;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -128,17 +128,16 @@ class TraceRecorder {
     
     JSStackFrame* findFrame(void* p) const;
     bool onFrame(void* p) const;
     unsigned nativeFrameSlots(JSStackFrame* fp, JSFrameRegs& regs) const;
     size_t nativeFrameOffset(void* p) const;
     void import(jsval*, uint8& t, char *prefix, int index);
     void trackNativeFrameUse(unsigned slots);
     
-    nanojit::SideExit* snapshot();
     unsigned getCallDepth() const;
     void guard(bool expected, nanojit::LIns* cond);
 
     void set(void* p, nanojit::LIns* l);
 
     bool checkType(jsval& v, uint8& type);
     bool verifyTypeStability(JSStackFrame* fp, JSFrameRegs& regs, uint8* m);
     void closeLoop(nanojit::Fragmento* fragmento);
@@ -189,16 +188,17 @@ class TraceRecorder {
 public:
     TraceRecorder(JSContext* cx, nanojit::Fragmento*, nanojit::Fragment*);
     ~TraceRecorder();
 
     JSStackFrame* getEntryFrame() const;
     JSStackFrame* getFp() const;
     JSFrameRegs& getRegs() const;
     nanojit::Fragment* getFragment() const;
+    nanojit::SideExit* snapshot();
 
     nanojit::LIns* get(void* p);
     
     bool loopEdge();
     void stop();
     
     bool JSOP_INTERRUPT();
     bool JSOP_PUSH();