GenerateAndAllocateRegisters can trivially elide self moves at end of liveness
https://bugs.webkit.org/show_bug.cgi?id=202833

Reviewed by Saam Barati.

This also fixes a bug where if a tmp is moved to itself at the end of its lifetime
we would mess up the accounting for the tmp.

In order to catch these bugs earlier during generation I added a
checkConsistency function that if a tmp is in a reg that reg is
not available and that reg thinks the tmp is also allocated in it.

* b3/B3Bank.h:
(JSC::B3::bankForReg):
* b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp:
(JSC::B3::Air::GenerateAndAllocateRegisters::checkConsistency):
(JSC::B3::Air::GenerateAndAllocateRegisters::generate):
* b3/air/AirAllocateRegistersAndStackAndGenerateCode.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@250999 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2d6d32e..836845a 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,24 @@
+2019-10-10  Keith Miller  <keith_miller@apple.com>
+
+        GenerateAndAllocateRegisters can trivially elide self moves at end of liveness
+        https://bugs.webkit.org/show_bug.cgi?id=202833
+
+        Reviewed by Saam Barati.
+
+        This also fixes a bug where if a tmp is moved to itself at the end of its lifetime
+        we would mess up the accounting for the tmp.
+
+        In order to catch these bugs earlier during generation I added a
+        checkConsistency function that if a tmp is in a reg that reg is
+        not available and that reg thinks the tmp is also allocated in it.
+
+        * b3/B3Bank.h:
+        (JSC::B3::bankForReg):
+        * b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp:
+        (JSC::B3::Air::GenerateAndAllocateRegisters::checkConsistency):
+        (JSC::B3::Air::GenerateAndAllocateRegisters::generate):
+        * b3/air/AirAllocateRegistersAndStackAndGenerateCode.h:
+
 2019-10-10  Yury Semikhatsky  <yurys@chromium.org>
 
         Web Inspector: use more C++ keywords for defining agents
diff --git a/Source/JavaScriptCore/b3/B3Bank.h b/Source/JavaScriptCore/b3/B3Bank.h
index 1e93bad..5bebf26 100644
--- a/Source/JavaScriptCore/b3/B3Bank.h
+++ b/Source/JavaScriptCore/b3/B3Bank.h
@@ -28,6 +28,7 @@
 #if ENABLE(B3_JIT)
 
 #include "B3Type.h"
+#include "Reg.h"
 
 namespace JSC { namespace B3 {
 
@@ -63,6 +64,11 @@
     return GP;
 }
 
+inline Bank bankForReg(Reg reg)
+{
+    return reg.isGPR() ? GP : FP;
+}
+
 } } // namespace JSC::B3
 
 namespace WTF {
diff --git a/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp b/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp
index 3f9c79c..ea2c7cc 100644
--- a/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp
+++ b/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp
@@ -45,6 +45,34 @@
     , m_map(code)
 { }
 
+ALWAYS_INLINE void GenerateAndAllocateRegisters::checkConsistency()
+{
+#if !ASSERT_DISABLED
+    m_code.forEachTmp([&] (Tmp tmp) {
+        Reg reg = m_map[tmp].reg;
+        if (!reg)
+            return;
+
+        ASSERT(!m_availableRegs[tmp.bank()].contains(reg));
+        ASSERT(m_currentAllocation->at(reg) == tmp);
+    });
+
+    for (Reg reg : RegisterSet::allRegisters()) {
+        if (isDisallowedRegister(reg))
+            continue;
+
+        Tmp tmp = m_currentAllocation->at(reg);
+        if (!tmp) {
+            ASSERT(m_availableRegs[bankForReg(reg)].contains(reg));
+            continue;
+        }
+
+        ASSERT(!m_availableRegs[tmp.bank()].contains(reg));
+        ASSERT(m_map[tmp].reg == reg);
+    }
+#endif
+}
+
 void GenerateAndAllocateRegisters::buildLiveRanges(UnifiedTmpLiveness& liveness)
 {
     m_liveRangeEnd = TmpMap<size_t>(m_code, 0);
@@ -416,6 +444,8 @@
 
         bool isReplayingSameInst = false;
         for (size_t instIndex = 0; instIndex < block->size(); ++instIndex) {
+            checkConsistency();
+
             if (instIndex && !isReplayingSameInst)
                 startLabel = m_jit->labelIgnoringWatchpoints();
 
@@ -444,6 +474,10 @@
                 if (source.isReg() || m_liveRangeEnd[source.tmp()] != m_globalInstIndex)
                     return true;
 
+                // If we are doing a self move at the end of the temps liveness we can trivially elide the move.
+                if (source == dest)
+                    return false;
+
                 Reg sourceReg = m_map[source.tmp()].reg;
                 // If the value is not already materialized into a register we may still move it into one so let the normal generation code run.
                 if (!sourceReg)
@@ -462,6 +496,7 @@
                 m_map[source.tmp()].reg = Reg();
                 return false;
             })();
+            checkConsistency();
 
             inst.forEachArg([&] (Arg& arg, Arg::Role role, Bank, Width) {
                 if (!arg.isTmp())
diff --git a/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.h b/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.h
index df7a3ff..ac3cebf 100644
--- a/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.h
+++ b/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.h
@@ -64,6 +64,8 @@
     void buildLiveRanges(UnifiedTmpLiveness&);
     bool isDisallowedRegister(Reg);
 
+    void checkConsistency();
+
     Code& m_code;
     CCallHelpers* m_jit { nullptr };