Title: [207004] trunk/Source/_javascript_Core
Revision
207004
Author
fpi...@apple.com
Date
2016-10-10 10:12:34 -0700 (Mon, 10 Oct 2016)

Log Message

Air should expose API for pinning registers
https://bugs.webkit.org/show_bug.cgi?id=163175

Reviewed by Keith Miller.
        
You can now call Procedure::pinRegister(), or Code::pinRegister(), and it will make this
register behave as follows:
        
- B3 and Air will emit no code that modifies the value in this register, except if that
  happens via a Patchpoint or stackmap constraint (i.e. the user explicitly asked for it).
- B3 and Air will allow others to modify the register. For example, if the register is not
  callee-save, then the compiler knows that the register's value will be trashed by any
  C-style call.
- Air will be happy to emit code that reads from this register, including coalescing tmps
  with it, so longer as there is no interference (i.e. no chance of the register's value
  changing). For example, if we went back to having pinned tag registers, we would tell B3
  to use them by (1) excluding them from any clobber set (easy, since they're callee save)
  and (2) emitting ArgumentReg to grab their value. There's a test that does this.
        
This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air 
already used this API when choosing registers in register allocation. Code now also vends a
mutableRegs() set, which is derived from regsInPriorityOrder(), that can quickly tell you if
a register can be mutated. Doing it this way means that most of this is a purely mechanical
change. The calls to mutableRegs() are the places where we had to change logic:
        
- The register allocators needs to know that coalescing with a precolored pinned tmp is free.
- The callee-save handler needs to know that we're not supposed to save/restore pinned
  registers.
        
Note that in this scheme, pinned registers are simply registers that do not appear in
regsInPriorityOrder(). This means, for example, that we will now say that FP is pinned. So,
this means that you can also pin registers by calling setRegsInPriorityOrder() and passing a
vector that excludes some registers. More generally, this means that clients can now tweak
the register allocator's register preferences, since the ordering in that list reflects the
order in which the allocator will try registers.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* b3/B3Procedure.cpp:
(JSC::B3::Procedure::pinRegister):
* b3/B3Procedure.h:
* b3/air/AirCode.cpp:
(JSC::B3::Air::Code::Code):
(JSC::B3::Air::Code::setRegsInPriorityOrder):
(JSC::B3::Air::Code::pinRegister):
* b3/air/AirCode.h:
(JSC::B3::Air::Code::regsInPriorityOrder):
(JSC::B3::Air::Code::mutableRegs):
(JSC::B3::Air::Code::isPinned):
(JSC::B3::Air::Code::regsInPriorityOrderImpl):
(JSC::B3::Air::Code::proc): Deleted.
* b3/air/AirEmitShuffle.cpp:
(JSC::B3::Air::emitShuffle):
* b3/air/AirEmitShuffle.h:
* b3/air/AirHandleCalleeSaves.cpp:
(JSC::B3::Air::handleCalleeSaves):
* b3/air/AirIteratedRegisterCoalescing.cpp:
* b3/air/AirLowerAfterRegAlloc.cpp:
(JSC::B3::Air::lowerAfterRegAlloc):
* b3/air/AirRegisterPriority.cpp: Removed.
* b3/air/AirRegisterPriority.h: Removed.
* b3/air/AirSpillEverything.cpp:
(JSC::B3::Air::spillEverything):
* b3/air/testair.cpp:
(JSC::B3::Air::testShuffleBroadcastAllRegs):
(JSC::B3::Air::testShuffleShiftAllRegs):
(JSC::B3::Air::testShuffleRotateAllRegs):
(JSC::B3::Air::testShuffleShiftMemoryAllRegs):
(JSC::B3::Air::testShuffleShiftMemoryAllRegs64):
(JSC::B3::Air::testShuffleShiftMemoryAllRegsMixedWidth):
(JSC::B3::Air::testShuffleRotateMemoryAllRegs64):
(JSC::B3::Air::testShuffleRotateMemoryAllRegsMixedWidth):
* b3/testb3.cpp:
(JSC::B3::testPinRegisters):
(JSC::B3::run):
* jit/RegisterSet.h:

Modified Paths

Removed Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (207003 => 207004)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-10 17:12:34 UTC (rev 207004)
@@ -96,7 +96,6 @@
     b3/air/AirLowerMacros.cpp
     b3/air/AirOptimizeBlockOrder.cpp
     b3/air/AirPhaseScope.cpp
-    b3/air/AirRegisterPriority.cpp
     b3/air/AirReportUsedRegisters.cpp
     b3/air/AirSimplifyCFG.cpp
     b3/air/AirSpecial.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (207003 => 207004)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-10 17:12:34 UTC (rev 207004)
@@ -1,3 +1,82 @@
+2016-10-09  Filip Pizlo  <fpi...@apple.com>
+
+        Air should expose API for pinning registers
+        https://bugs.webkit.org/show_bug.cgi?id=163175
+
+        Reviewed by Keith Miller.
+        
+        You can now call Procedure::pinRegister(), or Code::pinRegister(), and it will make this
+        register behave as follows:
+        
+        - B3 and Air will emit no code that modifies the value in this register, except if that
+          happens via a Patchpoint or stackmap constraint (i.e. the user explicitly asked for it).
+        - B3 and Air will allow others to modify the register. For example, if the register is not
+          callee-save, then the compiler knows that the register's value will be trashed by any
+          C-style call.
+        - Air will be happy to emit code that reads from this register, including coalescing tmps
+          with it, so longer as there is no interference (i.e. no chance of the register's value
+          changing). For example, if we went back to having pinned tag registers, we would tell B3
+          to use them by (1) excluding them from any clobber set (easy, since they're callee save)
+          and (2) emitting ArgumentReg to grab their value. There's a test that does this.
+        
+        This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air 
+        already used this API when choosing registers in register allocation. Code now also vends a
+        mutableRegs() set, which is derived from regsInPriorityOrder(), that can quickly tell you if
+        a register can be mutated. Doing it this way means that most of this is a purely mechanical
+        change. The calls to mutableRegs() are the places where we had to change logic:
+        
+        - The register allocators needs to know that coalescing with a precolored pinned tmp is free.
+        - The callee-save handler needs to know that we're not supposed to save/restore pinned
+          registers.
+        
+        Note that in this scheme, pinned registers are simply registers that do not appear in
+        regsInPriorityOrder(). This means, for example, that we will now say that FP is pinned. So,
+        this means that you can also pin registers by calling setRegsInPriorityOrder() and passing a
+        vector that excludes some registers. More generally, this means that clients can now tweak
+        the register allocator's register preferences, since the ordering in that list reflects the
+        order in which the allocator will try registers.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * b3/B3Procedure.cpp:
+        (JSC::B3::Procedure::pinRegister):
+        * b3/B3Procedure.h:
+        * b3/air/AirCode.cpp:
+        (JSC::B3::Air::Code::Code):
+        (JSC::B3::Air::Code::setRegsInPriorityOrder):
+        (JSC::B3::Air::Code::pinRegister):
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::regsInPriorityOrder):
+        (JSC::B3::Air::Code::mutableRegs):
+        (JSC::B3::Air::Code::isPinned):
+        (JSC::B3::Air::Code::regsInPriorityOrderImpl):
+        (JSC::B3::Air::Code::proc): Deleted.
+        * b3/air/AirEmitShuffle.cpp:
+        (JSC::B3::Air::emitShuffle):
+        * b3/air/AirEmitShuffle.h:
+        * b3/air/AirHandleCalleeSaves.cpp:
+        (JSC::B3::Air::handleCalleeSaves):
+        * b3/air/AirIteratedRegisterCoalescing.cpp:
+        * b3/air/AirLowerAfterRegAlloc.cpp:
+        (JSC::B3::Air::lowerAfterRegAlloc):
+        * b3/air/AirRegisterPriority.cpp: Removed.
+        * b3/air/AirRegisterPriority.h: Removed.
+        * b3/air/AirSpillEverything.cpp:
+        (JSC::B3::Air::spillEverything):
+        * b3/air/testair.cpp:
+        (JSC::B3::Air::testShuffleBroadcastAllRegs):
+        (JSC::B3::Air::testShuffleShiftAllRegs):
+        (JSC::B3::Air::testShuffleRotateAllRegs):
+        (JSC::B3::Air::testShuffleShiftMemoryAllRegs):
+        (JSC::B3::Air::testShuffleShiftMemoryAllRegs64):
+        (JSC::B3::Air::testShuffleShiftMemoryAllRegsMixedWidth):
+        (JSC::B3::Air::testShuffleRotateMemoryAllRegs64):
+        (JSC::B3::Air::testShuffleRotateMemoryAllRegsMixedWidth):
+        * b3/testb3.cpp:
+        (JSC::B3::testPinRegisters):
+        (JSC::B3::run):
+        * jit/RegisterSet.h:
+
 2016-10-08  Filip Pizlo  <fpi...@apple.com>
 
         B3 should know about mutable pinned registers

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (207003 => 207004)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-10 17:12:34 UTC (rev 207004)
@@ -875,8 +875,6 @@
 		0FEC85811BDACDC70080FF74 /* AirInstInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC855C1BDACDC70080FF74 /* AirInstInlines.h */; };
 		0FEC85831BDACDC70080FF74 /* AirPhaseScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC855E1BDACDC70080FF74 /* AirPhaseScope.cpp */; };
 		0FEC85841BDACDC70080FF74 /* AirPhaseScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC855F1BDACDC70080FF74 /* AirPhaseScope.h */; };
-		0FEC85851BDACDC70080FF74 /* AirRegisterPriority.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC85601BDACDC70080FF74 /* AirRegisterPriority.cpp */; };
-		0FEC85861BDACDC70080FF74 /* AirRegisterPriority.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85611BDACDC70080FF74 /* AirRegisterPriority.h */; };
 		0FEC85871BDACDC70080FF74 /* AirSpecial.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC85621BDACDC70080FF74 /* AirSpecial.cpp */; };
 		0FEC85881BDACDC70080FF74 /* AirSpecial.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85631BDACDC70080FF74 /* AirSpecial.h */; };
 		0FEC85891BDACDC70080FF74 /* AirSpillEverything.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEC85641BDACDC70080FF74 /* AirSpillEverything.cpp */; };
@@ -3151,8 +3149,6 @@
 		0FEC855C1BDACDC70080FF74 /* AirInstInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirInstInlines.h; path = b3/air/AirInstInlines.h; sourceTree = "<group>"; };
 		0FEC855E1BDACDC70080FF74 /* AirPhaseScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirPhaseScope.cpp; path = b3/air/AirPhaseScope.cpp; sourceTree = "<group>"; };
 		0FEC855F1BDACDC70080FF74 /* AirPhaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirPhaseScope.h; path = b3/air/AirPhaseScope.h; sourceTree = "<group>"; };
-		0FEC85601BDACDC70080FF74 /* AirRegisterPriority.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirRegisterPriority.cpp; path = b3/air/AirRegisterPriority.cpp; sourceTree = "<group>"; };
-		0FEC85611BDACDC70080FF74 /* AirRegisterPriority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirRegisterPriority.h; path = b3/air/AirRegisterPriority.h; sourceTree = "<group>"; };
 		0FEC85621BDACDC70080FF74 /* AirSpecial.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirSpecial.cpp; path = b3/air/AirSpecial.cpp; sourceTree = "<group>"; };
 		0FEC85631BDACDC70080FF74 /* AirSpecial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirSpecial.h; path = b3/air/AirSpecial.h; sourceTree = "<group>"; };
 		0FEC85641BDACDC70080FF74 /* AirSpillEverything.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirSpillEverything.cpp; path = b3/air/AirSpillEverything.cpp; sourceTree = "<group>"; };
@@ -5063,8 +5059,6 @@
 				0FB3878D1BFBC44D00E3AB1E /* AirOptimizeBlockOrder.h */,
 				0FEC855E1BDACDC70080FF74 /* AirPhaseScope.cpp */,
 				0FEC855F1BDACDC70080FF74 /* AirPhaseScope.h */,
-				0FEC85601BDACDC70080FF74 /* AirRegisterPriority.cpp */,
-				0FEC85611BDACDC70080FF74 /* AirRegisterPriority.h */,
 				0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */,
 				0F45703B1BE45F0A0062A629 /* AirReportUsedRegisters.h */,
 				0F338DFB1BED51270013C88F /* AirSimplifyCFG.cpp */,
@@ -7260,7 +7254,6 @@
 				0FEC85801BDACDC70080FF74 /* AirInst.h in Headers */,
 				0FEC85811BDACDC70080FF74 /* AirInstInlines.h in Headers */,
 				0FEC85841BDACDC70080FF74 /* AirPhaseScope.h in Headers */,
-				0FEC85861BDACDC70080FF74 /* AirRegisterPriority.h in Headers */,
 				0F45703D1BE45F0A0062A629 /* AirReportUsedRegisters.h in Headers */,
 				0FEC85881BDACDC70080FF74 /* AirSpecial.h in Headers */,
 				0FEC858A1BDACDC70080FF74 /* AirSpillEverything.h in Headers */,
@@ -9001,7 +8994,6 @@
 				0FEC857D1BDACDC70080FF74 /* AirInsertionSet.cpp in Sources */,
 				0FEC857F1BDACDC70080FF74 /* AirInst.cpp in Sources */,
 				0FEC85831BDACDC70080FF74 /* AirPhaseScope.cpp in Sources */,
-				0FEC85851BDACDC70080FF74 /* AirRegisterPriority.cpp in Sources */,
 				0F45703C1BE45F0A0062A629 /* AirReportUsedRegisters.cpp in Sources */,
 				0FEC85871BDACDC70080FF74 /* AirSpecial.cpp in Sources */,
 				0FEC85891BDACDC70080FF74 /* AirSpillEverything.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/b3/B3Procedure.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -305,6 +305,11 @@
     code().requestCallArgAreaSizeInBytes(size);
 }
 
+void Procedure::pinRegister(Reg reg)
+{
+    code().pinRegister(reg);
+}
+
 unsigned Procedure::frameSize() const
 {
     return code().frameSize();

Modified: trunk/Source/_javascript_Core/b3/B3Procedure.h (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/B3Procedure.h	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.h	2016-10-10 17:12:34 UTC (rev 207004)
@@ -212,8 +212,11 @@
     unsigned callArgAreaSizeInBytes() const;
     void requestCallArgAreaSizeInBytes(unsigned size);
 
+    // This tells the register allocators to stay away from this register.
+    JS_EXPORT_PRIVATE void pinRegister(Reg);
+
     JS_EXPORT_PRIVATE unsigned frameSize() const;
-    const RegisterAtOffsetList& calleeSaveRegisters() const;
+    JS_EXPORT_PRIVATE const RegisterAtOffsetList& calleeSaveRegisters() const;
 
     PCToOriginMap& pcToOriginMap() { return m_pcToOriginMap; }
     PCToOriginMap releasePCToOriginMap() { return WTFMove(m_pcToOriginMap); }

Modified: trunk/Source/_javascript_Core/b3/air/AirCode.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirCode.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirCode.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -40,6 +40,26 @@
     : m_proc(proc)
     , m_lastPhaseName("initial")
 {
+    // Come up with initial orderings of registers. The user may replace this with something else.
+    Arg::forEachType(
+        [&] (Arg::Type type) {
+            Vector<Reg> result;
+            RegisterSet all = type == Arg::GP ? RegisterSet::allGPRs() : RegisterSet::allFPRs();
+            all.exclude(RegisterSet::stackRegisters());
+            all.exclude(RegisterSet::reservedHardwareRegisters());
+            RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
+            all.forEach(
+                [&] (Reg reg) {
+                    if (!calleeSave.get(reg))
+                        result.append(reg);
+                });
+            all.forEach(
+                [&] (Reg reg) {
+                    if (calleeSave.get(reg))
+                        result.append(reg);
+                });
+            setRegsInPriorityOrder(type, result);
+        });
 }
 
 Code::~Code()
@@ -46,6 +66,25 @@
 {
 }
 
+void Code::setRegsInPriorityOrder(Arg::Type type, const Vector<Reg>& regs)
+{
+    regsInPriorityOrderImpl(type) = regs;
+    m_mutableRegs = RegisterSet();
+    Arg::forEachType(
+        [&] (Arg::Type type) {
+            for (Reg reg : regsInPriorityOrder(type))
+                m_mutableRegs.set(reg);
+        });
+}
+
+void Code::pinRegister(Reg reg)
+{
+    Vector<Reg>& regs = regsInPriorityOrderImpl(Arg(Tmp(reg)).type());
+    regs.removeFirst(reg);
+    m_mutableRegs.clear(reg);
+    ASSERT(!regs.contains(reg));
+}
+
 BasicBlock* Code::addBlock(double frequency)
 {
     std::unique_ptr<BasicBlock> block(new BasicBlock(m_blocks.size(), frequency));

Modified: trunk/Source/_javascript_Core/b3/air/AirCode.h (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirCode.h	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirCode.h	2016-10-10 17:12:34 UTC (rev 207004)
@@ -63,6 +63,27 @@
     ~Code();
 
     Procedure& proc() { return m_proc; }
+    
+    const Vector<Reg>& regsInPriorityOrder(Arg::Type type) const
+    {
+        switch (type) {
+        case Arg::GP:
+            return m_gpRegsInPriorityOrder;
+        case Arg::FP:
+            return m_fpRegsInPriorityOrder;
+        }
+        ASSERT_NOT_REACHED();
+    }
+    
+    void setRegsInPriorityOrder(Arg::Type, const Vector<Reg>&);
+    
+    // This is the set of registers that Air is allowed to emit code to mutate. It's derived from
+    // regsInPriorityOrder. Any registers not in this set are said to be "pinned".
+    const RegisterSet& mutableRegs() const { return m_mutableRegs; }
+    
+    bool isPinned(Reg reg) const { return !mutableRegs().get(reg); }
+    
+    void pinRegister(Reg);
 
     JS_EXPORT_PRIVATE BasicBlock* addBlock(double frequency = 1);
 
@@ -250,7 +271,21 @@
     
     Code(Procedure&);
 
+    Vector<Reg>& regsInPriorityOrderImpl(Arg::Type type)
+    {
+        switch (type) {
+        case Arg::GP:
+            return m_gpRegsInPriorityOrder;
+        case Arg::FP:
+            return m_fpRegsInPriorityOrder;
+        }
+        ASSERT_NOT_REACHED();
+    }
+
     Procedure& m_proc; // Some meta-data, like byproducts, is stored in the Procedure.
+    Vector<Reg> m_gpRegsInPriorityOrder;
+    Vector<Reg> m_fpRegsInPriorityOrder;
+    RegisterSet m_mutableRegs;
     SparseCollection<StackSlot> m_stackSlots;
     Vector<std::unique_ptr<BasicBlock>> m_blocks;
     SparseCollection<Special> m_specials;

Modified: trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -28,8 +28,8 @@
 
 #if ENABLE(B3_JIT)
 
+#include "AirCode.h"
 #include "AirInstInlines.h"
-#include "AirRegisterPriority.h"
 #include <wtf/GraphNodeWorklist.h>
 #include <wtf/ListDump.h>
 
@@ -40,8 +40,8 @@
 bool verbose = false;
 
 template<typename Functor>
-Tmp findPossibleScratch(Arg::Type type, const Functor& functor) {
-    for (Reg reg : regsInPriorityOrder(type)) {
+Tmp findPossibleScratch(Code& code, Arg::Type type, const Functor& functor) {
+    for (Reg reg : code.regsInPriorityOrder(type)) {
         Tmp tmp(reg);
         if (functor(tmp))
             return tmp;
@@ -49,9 +49,9 @@
     return Tmp();
 }
 
-Tmp findPossibleScratch(Arg::Type type, const Arg& arg1, const Arg& arg2) {
+Tmp findPossibleScratch(Code& code, Arg::Type type, const Arg& arg1, const Arg& arg2) {
     return findPossibleScratch(
-        type,
+        code, type,
         [&] (Tmp tmp) -> bool {
             return !arg1.usesTmp(tmp) && !arg2.usesTmp(tmp);
         });
@@ -79,7 +79,8 @@
 }
 
 Vector<Inst> emitShuffle(
-    Vector<ShufflePair> pairs, std::array<Arg, 2> scratches, Arg::Type type, Value* origin)
+    Code& code, Vector<ShufflePair> pairs, std::array<Arg, 2> scratches, Arg::Type type,
+    Value* origin)
 {
     if (verbose) {
         dataLog(
@@ -303,7 +304,7 @@
         
         if (!isValidForm(move, pair.src().kind(), pair.dst().kind())) {
             Tmp scratch =
-                getScratch(scratchIndex, findPossibleScratch(type, pair.src(), pair.dst()));
+                getScratch(scratchIndex, findPossibleScratch(code, type, pair.src(), pair.dst()));
             RELEASE_ASSERT(scratch);
             if (isValidForm(move, pair.src().kind(), Arg::Tmp))
                 result.append(Inst(moveForWidth(pair.width()), origin, pair.src(), scratch));
@@ -435,7 +436,7 @@
                     // Moving data between two spills is rare. To get here a lot of rare stuff has to
                     // all happen at once.
                     
-                    Tmp scratch = getScratch(0, findPossibleScratch(type, left, right));
+                    Tmp scratch = getScratch(0, findPossibleScratch(code, type, left, right));
                     RELEASE_ASSERT(scratch);
                     result.append(Inst(moveForWidth(swapWidth), origin, left, scratch));
                     result.append(Inst(swap, origin, scratch, right));
@@ -469,7 +470,7 @@
             // available register file.
 
             Tmp scratch = findPossibleScratch(
-                type,
+                code, type,
                 [&] (Tmp tmp) -> bool {
                     for (ShufflePair pair : rotate.loop) {
                         if (pair.src().usesTmp(tmp))
@@ -512,7 +513,7 @@
 }
 
 Vector<Inst> emitShuffle(
-    const Vector<ShufflePair>& pairs,
+    Code& code, const Vector<ShufflePair>& pairs,
     const std::array<Arg, 2>& gpScratch, const std::array<Arg, 2>& fpScratch,
     Value* origin)
 {
@@ -531,8 +532,8 @@
     }
 
     Vector<Inst> result;
-    result.appendVector(emitShuffle(gpPairs, gpScratch, Arg::GP, origin));
-    result.appendVector(emitShuffle(fpPairs, fpScratch, Arg::FP, origin));
+    result.appendVector(emitShuffle(code, gpPairs, gpScratch, Arg::GP, origin));
+    result.appendVector(emitShuffle(code, fpPairs, fpScratch, Arg::FP, origin));
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.h (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.h	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirEmitShuffle.h	2016-10-10 17:12:34 UTC (rev 207004)
@@ -37,6 +37,8 @@
 
 namespace Air {
 
+class Code;
+
 class ShufflePair {
 public:
     ShufflePair()
@@ -100,12 +102,12 @@
 // NOTE: Use this method (and its friend below) to emit shuffles after register allocation. Before
 // register allocation it is much better to simply use the Shuffle instruction.
 Vector<Inst> emitShuffle(
-    Vector<ShufflePair>, std::array<Arg, 2> scratch, Arg::Type, Value* origin);
+    Code& code, Vector<ShufflePair>, std::array<Arg, 2> scratch, Arg::Type, Value* origin);
 
 // Perform a shuffle that involves any number of types. Pass scratch registers or memory locations
 // for each type according to the rules above.
 Vector<Inst> emitShuffle(
-    const Vector<ShufflePair>&,
+    Code& code, const Vector<ShufflePair>&,
     const std::array<Arg, 2>& gpScratch, const std::array<Arg, 2>& fpScratch,
     Value* origin);
 

Modified: trunk/Source/_javascript_Core/b3/air/AirHandleCalleeSaves.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirHandleCalleeSaves.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirHandleCalleeSaves.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -55,6 +55,7 @@
 
     // Now we filter to really get the callee saves.
     usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
+    usedCalleeSaves.filter(code.mutableRegs());
     usedCalleeSaves.exclude(RegisterSet::stackRegisters()); // We don't need to save FP here.
 
     if (!usedCalleeSaves.numberOfSetRegisters())

Modified: trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -33,7 +33,6 @@
 #include "AirInstInlines.h"
 #include "AirLiveness.h"
 #include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
 #include "AirTmpInlines.h"
 #include "AirTmpWidth.h"
 #include "AirUseCounts.h"
@@ -57,8 +56,11 @@
         , m_lastPrecoloredRegisterIndex(lastPrecoloredRegisterIndex)
         , m_unspillableTmps(unspillableTmp)
     {
+        for (Reg reg : m_regsInPriorityOrder)
+            m_mutableRegs.set(reg);
+        
         initializeDegrees(tmpArraySize);
-
+        
         m_adjacencyList.resize(tmpArraySize);
         m_moveList.resize(tmpArraySize);
         m_coalescedTmps.fill(0, tmpArraySize);
@@ -161,7 +163,7 @@
             std::swap(u, v);
 
         if (traceDebug)
-            dataLog("Coalescing move at index", moveIndex, " u = ", u, " v = ", v, "\n");
+            dataLog("Coalescing move at index ", moveIndex, " u = ", u, " v = ", v, "\n");
 
         if (u == v) {
             addWorkList(u);
@@ -461,8 +463,15 @@
 
     bool precoloredCoalescingHeuristic(IndexType u, IndexType v)
     {
+        if (traceDebug)
+            dataLog("    Checking precoloredCoalescingHeuristic\n");
         ASSERT(isPrecolored(u));
         ASSERT(!isPrecolored(v));
+        
+        // If u is a pinned register then it's always safe to coalesce. Note that when we call this,
+        // we have already proved that there is no interference between u and v.
+        if (!m_mutableRegs.get(m_coloredTmp[u]))
+            return true;
 
         // If any adjacent of the non-colored node is not an adjacent of the colored node AND has a degree >= K
         // there is a risk that this node needs to have the same color as our precolored node. If we coalesce such
@@ -549,6 +558,7 @@
     typedef SimpleClassHashTraits<InterferenceEdge> InterferenceEdgeHashTraits;
 
     const Vector<Reg>& m_regsInPriorityOrder;
+    RegisterSet m_mutableRegs;
     IndexType m_lastPrecoloredRegisterIndex { 0 };
 
     // The interference graph.
@@ -727,7 +737,7 @@
 class ColoringAllocator : public AbstractColoringAllocator<unsigned> {
 public:
     ColoringAllocator(Code& code, TmpWidth& tmpWidth, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp)
-        : AbstractColoringAllocator<unsigned>(regsInPriorityOrder(type), AbsoluteTmpMapper<type>::lastMachineRegisterIndex(), tmpArraySize(code), unspillableTmp)
+        : AbstractColoringAllocator<unsigned>(code.regsInPriorityOrder(type), AbsoluteTmpMapper<type>::lastMachineRegisterIndex(), tmpArraySize(code), unspillableTmp)
         , m_code(code)
         , m_tmpWidth(tmpWidth)
         , m_useCounts(useCounts)
@@ -839,7 +849,7 @@
         if (!reg) {
             // We only care about Tmps that interfere. A Tmp that never interfere with anything
             // can take any register.
-            reg = regsInPriorityOrder(type).first();
+            reg = m_code.regsInPriorityOrder(type).first();
         }
         return reg;
     }

Modified: trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -36,7 +36,6 @@
 #include "AirInstInlines.h"
 #include "AirLiveness.h"
 #include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
 #include "B3CCallValue.h"
 #include "B3ValueInlines.h"
 #include "RegisterSet.h"
@@ -86,7 +85,7 @@
         std::array<Arg, 2> result;
         for (unsigned i = 0; i < 2; ++i) {
             bool found = false;
-            for (Reg reg : regsInPriorityOrder(type)) {
+            for (Reg reg : code.regsInPriorityOrder(type)) {
                 if (!set.get(reg)) {
                     result[i] = Tmp(reg);
                     set.set(reg);
@@ -134,7 +133,7 @@
                 std::array<Arg, 2> gpScratch = getScratches(set, Arg::GP);
                 std::array<Arg, 2> fpScratch = getScratches(set, Arg::FP);
                 insertionSet.insertInsts(
-                    instIndex, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
+                    instIndex, emitShuffle(code, pairs, gpScratch, fpScratch, inst.origin));
                 inst = Inst();
                 break;
             }
@@ -193,7 +192,7 @@
                     dataLog("Pre-call pairs for ", inst, ": ", listDump(pairs), "\n");
                 
                 insertionSet.insertInsts(
-                    instIndex, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
+                    instIndex, emitShuffle(code, pairs, gpScratch, fpScratch, inst.origin));
 
                 inst = buildCCall(code, inst.origin, destinations);
                 if (oldKind.traps)
@@ -224,7 +223,7 @@
                 fpScratch = getScratches(liveRegs, Arg::FP);
                 
                 insertionSet.insertInsts(
-                    instIndex + 1, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
+                    instIndex + 1, emitShuffle(code, pairs, gpScratch, fpScratch, inst.origin));
                 break;
             }
 

Deleted: trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-#include "AirRegisterPriority.h"
-
-#if ENABLE(B3_JIT)
-
-#include "RegisterSet.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-const Vector<GPRReg>& gprsInPriorityOrder()
-{
-    static Vector<GPRReg>* result;
-    static std::once_flag once;
-    std::call_once(
-        once,
-        [] {
-            result = new Vector<GPRReg>();
-            RegisterSet all = RegisterSet::allGPRs();
-            all.exclude(RegisterSet::stackRegisters());
-            all.exclude(RegisterSet::reservedHardwareRegisters());
-            RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
-            all.forEach(
-                [&] (Reg reg) {
-                    if (!calleeSave.get(reg))
-                        result->append(reg.gpr());
-                });
-            all.forEach(
-                [&] (Reg reg) {
-                    if (calleeSave.get(reg))
-                        result->append(reg.gpr());
-                });
-        });
-    return *result;
-}
-
-const Vector<FPRReg>& fprsInPriorityOrder()
-{
-    static Vector<FPRReg>* result;
-    static std::once_flag once;
-    std::call_once(
-        once,
-        [] {
-            result = new Vector<FPRReg>();
-            RegisterSet all = RegisterSet::allFPRs();
-            RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
-            all.forEach(
-                [&] (Reg reg) {
-                    if (!calleeSave.get(reg))
-                        result->append(reg.fpr());
-                });
-            all.forEach(
-                [&] (Reg reg) {
-                    if (calleeSave.get(reg))
-                        result->append(reg.fpr());
-                });
-        });
-    return *result;
-}
-
-const Vector<Reg>& regsInPriorityOrder(Arg::Type type)
-{
-    static Vector<Reg>* result[Arg::numTypes];
-    static std::once_flag once;
-    std::call_once(
-        once,
-        [] {
-            result[Arg::GP] = new Vector<Reg>();
-            for (GPRReg reg : gprsInPriorityOrder())
-                result[Arg::GP]->append(Reg(reg));
-            result[Arg::FP] = new Vector<Reg>();
-            for (FPRReg reg : fprsInPriorityOrder())
-                result[Arg::FP]->append(Reg(reg));
-        });
-    return *result[type];
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)

Deleted: trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.h (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.h	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirRegisterPriority.h	2016-10-10 17:12:34 UTC (rev 207004)
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#pragma once
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "FPRInfo.h"
-#include "GPRInfo.h"
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-const Vector<GPRReg>& gprsInPriorityOrder();
-const Vector<FPRReg>& fprsInPriorityOrder();
-
-template<typename Bank> struct RegistersInPriorityOrder;
-template<> struct RegistersInPriorityOrder<GPRInfo> {
-    const Vector<GPRReg>& inPriorityOrder() { return gprsInPriorityOrder(); }
-};
-template<> struct RegistersInPriorityOrder<FPRInfo> {
-    const Vector<FPRReg>& inPriorityOrder() { return fprsInPriorityOrder(); }
-};
-
-template<typename Bank>
-const Vector<typename Bank::RegisterType>& regsInPriorityOrder()
-{
-    return RegistersInPriorityOrder<Bank>::inPriorityOrder();
-}
-
-JS_EXPORT_PRIVATE const Vector<Reg>& regsInPriorityOrder(Arg::Type);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -34,7 +34,6 @@
 #include "AirInstInlines.h"
 #include "AirLiveness.h"
 #include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
 #include <wtf/IndexMap.h>
 
 namespace JSC { namespace B3 { namespace Air {
@@ -129,7 +128,7 @@
                     switch (role) {
                     case Arg::Use:
                     case Arg::ColdUse:
-                        for (Reg reg : regsInPriorityOrder(type)) {
+                        for (Reg reg : code.regsInPriorityOrder(type)) {
                             if (!setBefore.get(reg)) {
                                 setBefore.set(reg);
                                 chosenReg = reg;
@@ -139,7 +138,7 @@
                         break;
                     case Arg::Def:
                     case Arg::ZDef:
-                        for (Reg reg : regsInPriorityOrder(type)) {
+                        for (Reg reg : code.regsInPriorityOrder(type)) {
                             if (!setAfter.get(reg)) {
                                 setAfter.set(reg);
                                 chosenReg = reg;
@@ -153,7 +152,7 @@
                     case Arg::LateColdUse:
                     case Arg::Scratch:
                     case Arg::EarlyDef:
-                        for (Reg reg : regsInPriorityOrder(type)) {
+                        for (Reg reg : code.regsInPriorityOrder(type)) {
                             if (!setBefore.get(reg) && !setAfter.get(reg)) {
                                 setAfter.set(reg);
                                 setBefore.set(reg);

Modified: trunk/Source/_javascript_Core/b3/air/testair.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/air/testair.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/air/testair.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -28,7 +28,6 @@
 #include "AirCode.h"
 #include "AirGenerate.h"
 #include "AirInstInlines.h"
-#include "AirRegisterPriority.h"
 #include "AllowMacroScratchRegisterUsage.h"
 #include "B3Compilation.h"
 #include "B3Procedure.h"
@@ -393,7 +392,7 @@
     B3::Procedure proc;
     Code& code = proc.code();
 
-    const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
+    const Vector<Reg>& regs = code.regsInPriorityOrder(Arg::GP);
 
     BasicBlock* root = code.addBlock();
     root->append(Move, nullptr, Arg::imm(35), Tmp(GPRInfo::regT0));
@@ -860,7 +859,7 @@
     B3::Procedure proc;
     Code& code = proc.code();
 
-    const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
+    const Vector<Reg>& regs = code.regsInPriorityOrder(Arg::GP);
 
     BasicBlock* root = code.addBlock();
     for (unsigned i = 0; i < regs.size(); ++i)
@@ -896,7 +895,7 @@
     B3::Procedure proc;
     Code& code = proc.code();
 
-    const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
+    const Vector<Reg>& regs = code.regsInPriorityOrder(Arg::GP);
 
     BasicBlock* root = code.addBlock();
     for (unsigned i = 0; i < regs.size(); ++i)
@@ -1168,7 +1167,7 @@
     memory[0] = 35;
     memory[1] = 36;
 
-    Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
+    Vector<Reg> regs = code.regsInPriorityOrder(Arg::GP);
     regs.removeFirst(Reg(GPRInfo::regT0));
 
     BasicBlock* root = code.addBlock();
@@ -1218,7 +1217,7 @@
     memory[0] = 35000000000000ll;
     memory[1] = 36000000000000ll;
 
-    Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
+    Vector<Reg> regs = code.regsInPriorityOrder(Arg::GP);
     regs.removeFirst(Reg(GPRInfo::regT0));
 
     BasicBlock* root = code.addBlock();
@@ -1279,7 +1278,7 @@
     memory[0] = 35000000000000ll;
     memory[1] = 36000000000000ll;
 
-    Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
+    Vector<Reg> regs = code.regsInPriorityOrder(Arg::GP);
     regs.removeFirst(Reg(GPRInfo::regT0));
 
     BasicBlock* root = code.addBlock();
@@ -1469,7 +1468,7 @@
     memory[0] = 35000000000000ll;
     memory[1] = 36000000000000ll;
 
-    Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
+    Vector<Reg> regs = code.regsInPriorityOrder(Arg::GP);
     regs.removeFirst(Reg(GPRInfo::regT0));
 
     BasicBlock* root = code.addBlock();
@@ -1521,7 +1520,7 @@
     memory[0] = 35000000000000ll;
     memory[1] = 36000000000000ll;
 
-    Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
+    Vector<Reg> regs = code.regsInPriorityOrder(Arg::GP);
     regs.removeFirst(Reg(GPRInfo::regT0));
 
     BasicBlock* root = code.addBlock();

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (207003 => 207004)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2016-10-10 17:12:34 UTC (rev 207004)
@@ -13327,6 +13327,60 @@
     compile(proc);
 }
 
+void testPinRegisters()
+{
+    auto go = [&] (bool pin) {
+        Procedure proc;
+        RegisterSet csrs;
+        csrs.merge(RegisterSet::calleeSaveRegisters());
+        csrs.exclude(RegisterSet::stackRegisters());
+        if (pin) {
+            csrs.forEach(
+                [&] (Reg reg) {
+                    proc.pinRegister(reg);
+                });
+        }
+        BasicBlock* root = proc.addBlock();
+        Value* a = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* b = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* c = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
+        Value* d = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::regCS0);
+        root->appendNew<CCallValue>(
+            proc, Void, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<intptr_t>(0x1234)));
+        root->appendNew<CCallValue>(
+            proc, Void, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<intptr_t>(0x1235)),
+            a, b, c);
+        PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        patchpoint->appendSomeRegister(d);
+        patchpoint->setGenerator(
+            [&] (CCallHelpers&, const StackmapGenerationParams& params) {
+                CHECK_EQ(params[0].gpr(), GPRInfo::regCS0);
+            });
+        root->appendNew<Value>(proc, Return, Origin());
+        auto code = compile(proc);
+        bool usesCSRs = false;
+        for (Air::BasicBlock* block : proc.code()) {
+            for (Air::Inst& inst : *block) {
+                if (inst.kind.opcode == Air::Patch && inst.origin == patchpoint)
+                    continue;
+                inst.forEachTmpFast(
+                    [&] (Air::Tmp tmp) {
+                        if (tmp.isReg())
+                            usesCSRs |= csrs.get(tmp.reg());
+                    });
+            }
+        }
+        for (const RegisterAtOffset& regAtOffset : proc.calleeSaveRegisters())
+            usesCSRs |= csrs.get(regAtOffset.reg());
+        CHECK_EQ(usesCSRs, !pin);
+    };
+    
+    go(true);
+    go(false);
+}
+
 // Make sure the compiler does not try to optimize anything out.
 NEVER_INLINE double zero()
 {
@@ -14774,6 +14828,7 @@
     RUN(testTrappingStoreElimination());
     RUN(testMoveConstants());
     RUN(testPCOriginMapDoesntInsertNops());
+    RUN(testPinRegisters());
     
     if (tasks.isEmpty())
         usage();

Modified: trunk/Source/_javascript_Core/jit/RegisterSet.h (207003 => 207004)


--- trunk/Source/_javascript_Core/jit/RegisterSet.h	2016-10-10 17:11:42 UTC (rev 207003)
+++ trunk/Source/_javascript_Core/jit/RegisterSet.h	2016-10-10 17:12:34 UTC (rev 207004)
@@ -48,7 +48,7 @@
     JS_EXPORT_PRIVATE static RegisterSet reservedHardwareRegisters();
     static RegisterSet runtimeRegisters();
     static RegisterSet specialRegisters(); // The union of stack, reserved hardware, and runtime registers.
-    static RegisterSet calleeSaveRegisters();
+    JS_EXPORT_PRIVATE static RegisterSet calleeSaveRegisters();
     static RegisterSet vmCalleeSaveRegisters(); // Callee save registers that might be saved and used by any tier.
     static RegisterSet llintBaselineCalleeSaveRegisters(); // Registers saved and used by the LLInt.
     static RegisterSet dfgCalleeSaveRegisters(); // Registers saved and used by the DFG JIT.
@@ -107,7 +107,7 @@
     size_t numberOfSetFPRs() const;
     size_t numberOfSetRegisters() const { return m_bits.count(); }
     
-    void dump(PrintStream&) const;
+    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
     
     enum EmptyValueTag { EmptyValue };
     enum DeletedValueTag { DeletedValue };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to