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 };