Bug 600127 - nanojit: do implicit constant propagation after guards. r=edwsmith.
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 28 Sep 2010 21:07:43 -0700
changeset 54760 566ddadcedcd889515dee84506ca87e53d8700e8
parent 54759 a45738e63c6ca5be704f7915196395420b337c30
child 54761 5047f619d154840bd29a46bf9046f4b2b747d054
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersedwsmith
bugs600127
milestone2.0b7pre
Bug 600127 - nanojit: do implicit constant propagation after guards. r=edwsmith.
js/src/nanojit/LIR.cpp
js/src/nanojit/LIR.h
--- a/js/src/nanojit/LIR.cpp
+++ b/js/src/nanojit/LIR.cpp
@@ -1954,16 +1954,17 @@ namespace nanojit
     CseFilter::CseFilter(LirWriter *out, uint8_t embNumUsedAccs, Allocator& alloc)
         : LirWriter(out),
           EMB_NUM_USED_ACCS(embNumUsedAccs),
           CSE_NUM_USED_ACCS(EMB_NUM_USED_ACCS + 2),
           CSE_ACC_CONST(    EMB_NUM_USED_ACCS + 0),
           CSE_ACC_MULTIPLE( EMB_NUM_USED_ACCS + 1),
           storesSinceLastLoad(ACCSET_NONE),
           alloc(alloc),
+          knownCmpValues(alloc),
           suspended(false)
     {
 
         m_findNL[LInsImmI] = &CseFilter::findImmI;
         m_findNL[LInsImmQ] = PTR_SIZE(NULL, &CseFilter::findImmQ);
         m_findNL[LInsImmD] = &CseFilter::findImmD;
         m_findNL[LIns1]    = &CseFilter::find1;
         m_findNL[LIns2]    = &CseFilter::find2;
@@ -2055,16 +2056,18 @@ namespace nanojit
 
     void CseFilter::clearAll() {
         for (NLKind nlkind = LInsFirst; nlkind <= LInsLast; nlkind = nextNLKind(nlkind))
             clearNL(nlkind);
 
         // Note that this clears the CONST and MULTIPLE load tables as well.
         for (CseAcc a = 0; a < CSE_NUM_USED_ACCS; a++)
             clearL(a);
+
+        knownCmpValues.clear();
     }
 
     inline uint32_t CseFilter::hashImmI(int32_t a) {
         return hashfinish(hash32(0, a));
     }
 
     inline uint32_t CseFilter::hashImmQorD(uint64_t a) {
         uint32_t hash = hash32(0, uint32_t(a >> 32));
@@ -2458,16 +2461,25 @@ namespace nanojit
     {
         LIns* ins;
         NanoAssert(isCseOpcode(op));
         uint32_t k;
         ins = find2(op, a, b, k);
         if (!ins) {
             ins = out->ins2(op, a, b);
             addNL(LIns2, ins, k);
+        } else if (ins->isCmp()) {
+            if (knownCmpValues.containsKey(ins)) {
+                // We've seen this comparison before, and it was previously
+                // used in a guard, so we know what its value must be at this
+                // point.  Replace it with a constant.
+                NanoAssert(ins->isCmp());
+                bool cmpValue = knownCmpValues.get(ins);
+                return insImmI(cmpValue ? 1 : 0);
+            }
         }
         NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b);
         return ins;
     }
 
     LIns* CseFilter::ins3(LOpcode op, LIns* a, LIns* b, LIns* c)
     {
         NanoAssert(isCseOpcode(op));
@@ -2572,16 +2584,23 @@ namespace nanojit
         if (isCseOpcode(op)) {
             // conditional guard
             uint32_t k;
             ins = find1(op, c, k);
             if (!ins) {
                 ins = out->insGuard(op, c, gr);
                 addNL(LIns1, ins, k);
             }
+            // After this guard, we know that 'c's result was true (if
+            // op==LIR_xf) or false (if op==LIR_xt), else we would have
+            // exited.  Record this fact in case 'c' occurs again.
+            if (!suspended) {
+                bool c_value = (op == LIR_xt ? false : true);
+                knownCmpValues.put(c, c_value);
+            }
         } else {
             ins = out->insGuard(op, c, gr);
         }
         NanoAssert(ins->isop(op) && ins->oprnd1() == c);
         return ins;
     }
 
     LIns* CseFilter::insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr)
--- a/js/src/nanojit/LIR.h
+++ b/js/src/nanojit/LIR.h
@@ -1959,16 +1959,22 @@ namespace nanojit
         LIns**      m_listL[CSE_NUM_ACCS];
         uint32_t    m_capL[ CSE_NUM_ACCS];
         uint32_t    m_usedL[CSE_NUM_ACCS];
 
         AccSet      storesSinceLastLoad;    // regions stored to since the last load
 
         Allocator& alloc;
 
+        // After a conditional guard such as "xf cmp", we know that 'cmp' must
+        // be true, else we would have side-exited.  So if we see 'cmp' again
+        // we can treat it like a constant.  This table records such
+        // comparisons.
+        HashMap <LIns*, bool> knownCmpValues;
+
         // If true, we will not add new instructions to the CSE tables, but we
         // will continue to CSE instructions that match existing table
         // entries.  Load instructions will still be removed if aliasing
         // stores are encountered.
         bool suspended;
 
         CseAcc miniAccSetToCseAcc(MiniAccSet miniAccSet, LoadQual loadQual) {
             NanoAssert(miniAccSet.val < NUM_ACCS || miniAccSet.val == MINI_ACCSET_MULTIPLE.val);