Diff
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (214407 => 214408)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2017-03-26 21:39:27 UTC (rev 214408)
@@ -101,6 +101,7 @@
b3/air/AirOptimizeBlockOrder.cpp
b3/air/AirPadInterference.cpp
b3/air/AirPhaseScope.cpp
+ b3/air/AirRegLiveness.cpp
b3/air/AirReportUsedRegisters.cpp
b3/air/AirSimplifyCFG.cpp
b3/air/AirSpecial.cpp
Modified: trunk/Source/_javascript_Core/ChangeLog (214407 => 214408)
--- trunk/Source/_javascript_Core/ChangeLog 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,3 +1,97 @@
+2017-03-26 Filip Pizlo <[email protected]>
+
+ Air should use RegisterSet for RegLiveness
+ https://bugs.webkit.org/show_bug.cgi?id=170108
+
+ Reviewed by Yusuke Suzuki.
+
+ The biggest change here is the introduction of the new RegLiveness class. This is a
+ drop-in replacement for the old RegLiveness, which was a specialization of
+ AbstractLiveness<>, but it's about 30% faster. It gets its speed boost from just using
+ sets everywhere, which is efficient for registers since RegisterSet is just two (on
+ x86-64) or three 32-bit (on ARM64) statically allocated words. This looks like a 1%
+ compile time progression on WasmBench.
+
+ * CMakeLists.txt:
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * b3/B3TimingScope.cpp: Records phase timing totals.
+ (JSC::B3::TimingScope::TimingScope):
+ (JSC::B3::TimingScope::~TimingScope):
+ * b3/B3TimingScope.h:
+ * b3/air/AirAllocateRegistersByGraphColoring.cpp:
+ (JSC::B3::Air::allocateRegistersByGraphColoring):
+ * b3/air/AirLiveness.h: Move code around and rename a bit to make it more like RegLiveness; in particular we want the `iterator` to be called `iterator` not `Iterator`, and we want it to be internal to its iterable. Also rename this template to Liveness, to match the header filename.
+ (JSC::B3::Air::Liveness::Liveness):
+ (JSC::B3::Air::Liveness::LocalCalc::LocalCalc):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::Iterable):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::iterator::iterator):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::iterator::operator++):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::iterator::operator*):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::iterator::operator==):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::iterator::operator!=):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::begin):
+ (JSC::B3::Air::Liveness::LocalCalc::Iterable::end):
+ (JSC::B3::Air::Liveness::Iterable::Iterable):
+ (JSC::B3::Air::Liveness::Iterable::iterator::iterator):
+ (JSC::B3::Air::RegLivenessAdapter::RegLivenessAdapter): Deleted.
+ (JSC::B3::Air::RegLivenessAdapter::numIndices): Deleted.
+ (JSC::B3::Air::RegLivenessAdapter::acceptsBank): Deleted.
+ (JSC::B3::Air::RegLivenessAdapter::acceptsRole): Deleted.
+ (JSC::B3::Air::RegLivenessAdapter::valueToIndex): Deleted.
+ (JSC::B3::Air::RegLivenessAdapter::indexToValue): Deleted.
+ (JSC::B3::Air::AbstractLiveness::AbstractLiveness): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::LocalCalc): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterator::Iterator): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterator::operator++): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterator::operator*): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterator::operator==): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterator::operator!=): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterable::Iterable): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterable::begin): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterable::end): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::Iterable::contains): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::live): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::isLive): Deleted.
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::execute): Deleted.
+ (JSC::B3::Air::AbstractLiveness::rawLiveAtHead): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::Iterable): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::iterator::iterator): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::iterator::operator*): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::iterator::operator++): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::iterator::operator==): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::iterator::operator!=): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::begin): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::end): Deleted.
+ (JSC::B3::Air::AbstractLiveness::Iterable::contains): Deleted.
+ (JSC::B3::Air::AbstractLiveness::liveAtHead): Deleted.
+ (JSC::B3::Air::AbstractLiveness::liveAtTail): Deleted.
+ (JSC::B3::Air::AbstractLiveness::workset): Deleted.
+ * b3/air/AirLogRegisterPressure.cpp:
+ * b3/air/AirLowerAfterRegAlloc.cpp:
+ * b3/air/AirRegLiveness.cpp: Added.
+ (JSC::B3::Air::RegLiveness::RegLiveness):
+ (JSC::B3::Air::RegLiveness::~RegLiveness):
+ (JSC::B3::Air::RegLiveness::LocalCalc::execute):
+ * b3/air/AirRegLiveness.h: Added.
+ (JSC::B3::Air::RegLiveness::LocalCalc::LocalCalc):
+ (JSC::B3::Air::RegLiveness::LocalCalc::live):
+ (JSC::B3::Air::RegLiveness::LocalCalc::isLive):
+ (JSC::B3::Air::RegLiveness::liveAtHead):
+ (JSC::B3::Air::RegLiveness::liveAtTail):
+ * b3/air/AirReportUsedRegisters.cpp:
+ * jit/RegisterSet.h:
+ (JSC::RegisterSet::add):
+ (JSC::RegisterSet::remove):
+ (JSC::RegisterSet::contains):
+ (JSC::RegisterSet::subsumes):
+ (JSC::RegisterSet::iterator::iterator):
+ (JSC::RegisterSet::iterator::operator*):
+ (JSC::RegisterSet::iterator::operator++):
+ (JSC::RegisterSet::iterator::operator==):
+ (JSC::RegisterSet::iterator::operator!=):
+ (JSC::RegisterSet::begin):
+ (JSC::RegisterSet::end):
+
2017-03-25 Filip Pizlo <[email protected]>
Fix wasm by returning after we do TLS.
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (214407 => 214408)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1005,6 +1005,8 @@
0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4275615914A20004CB9FF /* LinkBuffer.cpp */; };
0FF427641591A1CC004CB9FF /* DFGDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */; };
0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF427621591A1C9004CB9FF /* DFGDisassembler.h */; };
+ 0FF4B4BC1E88449700DBBE86 /* AirRegLiveness.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4B4BA1E88449500DBBE86 /* AirRegLiveness.cpp */; };
+ 0FF4B4BD1E88449A00DBBE86 /* AirRegLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4B4BB1E88449500DBBE86 /* AirRegLiveness.h */; };
0FF60AC216740F8300029779 /* ReduceWhitespace.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF60AC016740F8100029779 /* ReduceWhitespace.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF60ABF16740F8100029779 /* ReduceWhitespace.cpp */; };
0FF7168C15A3B235008F5DAA /* PropertyOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3520,6 +3522,8 @@
0FF4275615914A20004CB9FF /* LinkBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinkBuffer.cpp; sourceTree = "<group>"; };
0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDisassembler.cpp; path = dfg/DFGDisassembler.cpp; sourceTree = "<group>"; };
0FF427621591A1C9004CB9FF /* DFGDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDisassembler.h; path = dfg/DFGDisassembler.h; sourceTree = "<group>"; };
+ 0FF4B4BA1E88449500DBBE86 /* AirRegLiveness.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirRegLiveness.cpp; path = b3/air/AirRegLiveness.cpp; sourceTree = "<group>"; };
+ 0FF4B4BB1E88449500DBBE86 /* AirRegLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirRegLiveness.h; path = b3/air/AirRegLiveness.h; sourceTree = "<group>"; };
0FF60ABF16740F8100029779 /* ReduceWhitespace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReduceWhitespace.cpp; sourceTree = "<group>"; };
0FF60AC016740F8100029779 /* ReduceWhitespace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReduceWhitespace.h; sourceTree = "<group>"; };
0FF7168A15A3B231008F5DAA /* PropertyOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyOffset.h; sourceTree = "<group>"; };
@@ -5578,6 +5582,8 @@
0F9CABC71DB54A760008E83B /* AirPadInterference.h */,
0FEC855E1BDACDC70080FF74 /* AirPhaseScope.cpp */,
0FEC855F1BDACDC70080FF74 /* AirPhaseScope.h */,
+ 0FF4B4BA1E88449500DBBE86 /* AirRegLiveness.cpp */,
+ 0FF4B4BB1E88449500DBBE86 /* AirRegLiveness.h */,
0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */,
0F45703B1BE45F0A0062A629 /* AirReportUsedRegisters.h */,
0F338DFB1BED51270013C88F /* AirSimplifyCFG.cpp */,
@@ -8236,6 +8242,7 @@
0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */,
1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */,
62EC9BB71B7EB07C00303AD1 /* CallFrameShuffleData.h in Headers */,
+ 0FF4B4BD1E88449A00DBBE86 /* AirRegLiveness.h in Headers */,
62D755D71B84FB4A001801FA /* CallFrameShuffler.h in Headers */,
0F0B83B114BCF71800885B4F /* CallLinkInfo.h in Headers */,
0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */,
@@ -10625,6 +10632,7 @@
A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */,
14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */,
ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */,
+ 0FF4B4BC1E88449700DBBE86 /* AirRegLiveness.cpp in Sources */,
65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */,
1474C33C16AA2D9B0062F01D /* PrototypeMap.cpp in Sources */,
79B00CBC1C6AB07E0088C65D /* ProxyConstructor.cpp in Sources */,
Modified: trunk/Source/_javascript_Core/b3/B3TimingScope.cpp (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/B3TimingScope.cpp 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/B3TimingScope.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,23 +29,53 @@
#if ENABLE(B3_JIT)
#include "B3Common.h"
-#include <wtf/CurrentTime.h>
#include <wtf/DataLog.h>
+#include <wtf/HashMap.h>
+#include <wtf/Lock.h>
namespace JSC { namespace B3 {
+namespace {
+
+class State {
+ WTF_MAKE_NONCOPYABLE(State);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ State() { }
+
+ Seconds addToTotal(const char* name, Seconds duration)
+ {
+ auto locker = holdLock(lock);
+ return totals.add(name, Seconds(0)).iterator->value += duration;
+ }
+
+private:
+ HashMap<const char*, Seconds> totals;
+ Lock lock;
+};
+
+State& state()
+{
+ static Atomic<State*> s_state;
+ return ensurePointer(s_state, [] { return new State(); });
+}
+
+} // anonymous namespace
+
TimingScope::TimingScope(const char* name)
: m_name(name)
{
if (shouldMeasurePhaseTiming())
- m_before = monotonicallyIncreasingTimeMS();
+ m_before = MonotonicTime::now();
}
TimingScope::~TimingScope()
{
if (shouldMeasurePhaseTiming()) {
- double after = monotonicallyIncreasingTimeMS();
- dataLog("[B3] ", m_name, " took: ", after - m_before, " ms.\n");
+ Seconds duration = MonotonicTime::now() - m_before;
+ dataLog(
+ "[B3] ", m_name, " took: ", duration.milliseconds(), " ms ",
+ "(total: ", state().addToTotal(m_name, duration).milliseconds(), " ms).\n");
}
}
Modified: trunk/Source/_javascript_Core/b3/B3TimingScope.h (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/B3TimingScope.h 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/B3TimingScope.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
#if ENABLE(B3_JIT)
+#include <wtf/MonotonicTime.h>
#include <wtf/Noncopyable.h>
namespace JSC { namespace B3 {
@@ -39,7 +40,7 @@
private:
const char* m_name;
- double m_before;
+ MonotonicTime m_before;
};
} } // namespace JSC::B3
Modified: trunk/Source/_javascript_Core/b3/air/AirAllocateRegistersByGraphColoring.cpp (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirAllocateRegistersByGraphColoring.cpp 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/air/AirAllocateRegistersByGraphColoring.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -2257,7 +2257,7 @@
void allocateRegistersByGraphColoring(Code& code)
{
- PhaseScope phaseScope(code, "Air::allocateRegistersByGraphColoring");
+ PhaseScope phaseScope(code, "allocateRegistersByGraphColoring");
if (false)
dataLog("Code before graph coloring:\n", code);
Modified: trunk/Source/_javascript_Core/b3/air/AirLiveness.h (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirLiveness.h 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/air/AirLiveness.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -79,30 +79,14 @@
Code& m_code;
};
-struct RegLivenessAdapter {
- typedef Reg Thing;
- typedef BitVector IndexSet;
-
- RegLivenessAdapter(Code&) { }
-
- static unsigned numIndices(Code&)
- {
- return Reg::maxIndex() + 1;
- }
-
- static bool acceptsBank(Bank) { return true; }
- static bool acceptsRole(Arg::Role) { return true; }
- static unsigned valueToIndex(Reg reg) { return reg.index(); }
- Reg indexToValue(unsigned index) { return Reg::fromIndex(index); }
-};
-
+// HEADS UP: The algorithm here is duplicated in AirRegLiveness.h.
template<typename Adapter>
-class AbstractLiveness : public Adapter {
+class Liveness : public Adapter {
struct Workset;
public:
typedef typename Adapter::Thing Thing;
- AbstractLiveness(Code& code)
+ Liveness(Code& code)
: Adapter(code)
, m_workset(Adapter::numIndices(code))
, m_liveAtHead(code.size())
@@ -131,7 +115,7 @@
changed = false;
for (size_t blockIndex = code.size(); blockIndex--;) {
- BasicBlock* block = code.at(blockIndex);
+ BasicBlock* block = code[blockIndex];
if (!block)
continue;
@@ -187,7 +171,7 @@
// This calculator has to be run in reverse.
class LocalCalc {
public:
- LocalCalc(AbstractLiveness& liveness, BasicBlock* block)
+ LocalCalc(Liveness& liveness, BasicBlock* block)
: m_liveness(liveness)
, m_block(block)
{
@@ -198,40 +182,42 @@
workset.add(index);
}
- struct Iterator {
- Iterator(Adapter& adapter, IndexSparseSet<UnsafeVectorOverflow>::const_iterator sparceSetIterator)
- : m_adapter(adapter)
- , m_sparceSetIterator(sparceSetIterator)
+ class Iterable {
+ public:
+ Iterable(Liveness& liveness)
+ : m_liveness(liveness)
{
}
- Iterator& operator++()
- {
- ++m_sparceSetIterator;
- return *this;
- }
+ class iterator {
+ public:
+ iterator(Adapter& adapter, IndexSparseSet<UnsafeVectorOverflow>::const_iterator sparceSetIterator)
+ : m_adapter(adapter)
+ , m_sparceSetIterator(sparceSetIterator)
+ {
+ }
- typename Adapter::Thing operator*() const
- {
- return m_adapter.indexToValue(*m_sparceSetIterator);
- }
+ iterator& operator++()
+ {
+ ++m_sparceSetIterator;
+ return *this;
+ }
- bool operator==(const Iterator& other) { return m_sparceSetIterator == other.m_sparceSetIterator; }
- bool operator!=(const Iterator& other) { return m_sparceSetIterator != other.m_sparceSetIterator; }
+ typename Adapter::Thing operator*() const
+ {
+ return m_adapter.indexToValue(*m_sparceSetIterator);
+ }
- private:
- Adapter& m_adapter;
- IndexSparseSet<UnsafeVectorOverflow>::const_iterator m_sparceSetIterator;
- };
+ bool operator==(const iterator& other) { return m_sparceSetIterator == other.m_sparceSetIterator; }
+ bool operator!=(const iterator& other) { return m_sparceSetIterator != other.m_sparceSetIterator; }
- struct Iterable {
- Iterable(AbstractLiveness& liveness)
- : m_liveness(liveness)
- {
- }
+ private:
+ Adapter& m_adapter;
+ IndexSparseSet<UnsafeVectorOverflow>::const_iterator m_sparceSetIterator;
+ };
- Iterator begin() const { return Iterator(m_liveness, m_liveness.m_workset.begin()); }
- Iterator end() const { return Iterator(m_liveness, m_liveness.m_workset.end()); }
+ iterator begin() const { return iterator(m_liveness, m_liveness.m_workset.begin()); }
+ iterator end() const { return iterator(m_liveness, m_liveness.m_workset.end()); }
bool contains(const typename Adapter::Thing& thing) const
{
@@ -239,7 +225,7 @@
}
private:
- AbstractLiveness& m_liveness;
+ Liveness& m_liveness;
};
Iterable live() const
@@ -301,7 +287,7 @@
}
private:
- AbstractLiveness& m_liveness;
+ Liveness& m_liveness;
BasicBlock* m_block;
};
@@ -313,7 +299,7 @@
template<typename UnderlyingIterable>
class Iterable {
public:
- Iterable(AbstractLiveness& liveness, const UnderlyingIterable& iterable)
+ Iterable(Liveness& liveness, const UnderlyingIterable& iterable)
: m_liveness(liveness)
, m_iterable(iterable)
{
@@ -327,7 +313,7 @@
{
}
- iterator(AbstractLiveness& liveness, typename UnderlyingIterable::const_iterator iter)
+ iterator(Liveness& liveness, typename UnderlyingIterable::const_iterator iter)
: m_liveness(&liveness)
, m_iter(iter)
{
@@ -356,7 +342,7 @@
}
private:
- AbstractLiveness* m_liveness;
+ Liveness* m_liveness;
typename UnderlyingIterable::const_iterator m_iter;
};
@@ -369,7 +355,7 @@
}
private:
- AbstractLiveness& m_liveness;
+ Liveness& m_liveness;
const UnderlyingIterable& m_iterable;
};
@@ -387,7 +373,7 @@
private:
friend class LocalCalc;
- friend struct LocalCalc::Iterable;
+ friend class LocalCalc::Iterable;
IndexSparseSet<UnsafeVectorOverflow> m_workset;
IndexMap<BasicBlock, Vector<unsigned>> m_liveAtHead;
@@ -395,12 +381,11 @@
};
template<Bank bank, Arg::Temperature minimumTemperature = Arg::Cold>
-using TmpLiveness = AbstractLiveness<TmpLivenessAdapter<bank, minimumTemperature>>;
+using TmpLiveness = Liveness<TmpLivenessAdapter<bank, minimumTemperature>>;
-typedef AbstractLiveness<TmpLivenessAdapter<GP>> GPLiveness;
-typedef AbstractLiveness<TmpLivenessAdapter<FP>> FPLiveness;
-typedef AbstractLiveness<StackSlotLivenessAdapter> StackSlotLiveness;
-typedef AbstractLiveness<RegLivenessAdapter> RegLiveness;
+typedef Liveness<TmpLivenessAdapter<GP>> GPLiveness;
+typedef Liveness<TmpLivenessAdapter<FP>> FPLiveness;
+typedef Liveness<StackSlotLivenessAdapter> StackSlotLiveness;
} } } // namespace JSC::B3::Air
Modified: trunk/Source/_javascript_Core/b3/air/AirLogRegisterPressure.cpp (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirLogRegisterPressure.cpp 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/air/AirLogRegisterPressure.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -31,7 +31,7 @@
#include "AirArgInlines.h"
#include "AirCode.h"
#include "AirInstInlines.h"
-#include "AirLiveness.h"
+#include "AirRegLiveness.h"
namespace JSC { namespace B3 { namespace Air {
Modified: trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/air/AirLowerAfterRegAlloc.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -34,7 +34,7 @@
#include "AirEmitShuffle.h"
#include "AirInsertionSet.h"
#include "AirInstInlines.h"
-#include "AirLiveness.h"
+#include "AirRegLiveness.h"
#include "AirPhaseScope.h"
#include "B3CCallValue.h"
#include "B3ValueInlines.h"
Added: trunk/Source/_javascript_Core/b3/air/AirRegLiveness.cpp (0 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirRegLiveness.cpp (rev 0)
+++ trunk/Source/_javascript_Core/b3/air/AirRegLiveness.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 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 "AirRegLiveness.h"
+
+#if ENABLE(B3_JIT)
+
+#include "AirArgInlines.h"
+#include "AirInstInlines.h"
+
+namespace JSC { namespace B3 { namespace Air {
+
+RegLiveness::RegLiveness(Code& code)
+ : m_liveAtHead(code.size())
+ , m_liveAtTail(code.size())
+{
+ // The liveAtTail of each block automatically contains the LateUse's of the terminal.
+ for (BasicBlock* block : code) {
+ RegisterSet& liveAtTail = m_liveAtTail[block];
+
+ block->last().forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isLateUse(role))
+ liveAtTail.add(reg);
+ });
+ }
+
+ BitVector dirtyBlocks;
+ for (size_t blockIndex = code.size(); blockIndex--;)
+ dirtyBlocks.set(blockIndex);
+
+ bool changed;
+ do {
+ changed = false;
+
+ for (size_t blockIndex = code.size(); blockIndex--;) {
+ BasicBlock* block = code[blockIndex];
+ if (!block)
+ continue;
+
+ if (!dirtyBlocks.quickClear(blockIndex))
+ continue;
+
+ LocalCalc localCalc(*this, block);
+ for (size_t instIndex = block->size(); instIndex--;)
+ localCalc.execute(instIndex);
+
+ // Handle the early def's of the first instruction.
+ block->at(0).forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isEarlyDef(role))
+ localCalc.m_workset.remove(reg);
+ });
+
+ RegisterSet& liveAtHead = m_liveAtHead[block];
+ if (liveAtHead.subsumes(localCalc.m_workset))
+ continue;
+
+ liveAtHead.merge(localCalc.m_workset);
+
+ for (BasicBlock* predecessor : block->predecessors()) {
+ RegisterSet& liveAtTail = m_liveAtTail[predecessor];
+ if (liveAtTail.subsumes(localCalc.m_workset))
+ continue;
+
+ liveAtTail.merge(localCalc.m_workset);
+ dirtyBlocks.quickSet(predecessor->index());
+ changed = true;
+ }
+ }
+ } while (changed);
+}
+
+RegLiveness::~RegLiveness()
+{
+}
+
+void RegLiveness::LocalCalc::execute(unsigned instIndex)
+{
+ Inst& inst = m_block->at(instIndex);
+
+ // First handle the early def's of the next instruction.
+ if (instIndex + 1 < m_block->size()) {
+ Inst& nextInst = m_block->at(instIndex + 1);
+ nextInst.forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isEarlyDef(role))
+ m_workset.remove(reg);
+ });
+ }
+
+ // Then handle def's.
+ inst.forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isLateDef(role))
+ m_workset.remove(reg);
+ });
+
+ // Then handle use's.
+ inst.forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isEarlyUse(role))
+ m_workset.add(reg);
+ });
+
+ // And finally, handle the late use's of the previous instruction.
+ if (instIndex) {
+ Inst& prevInst = m_block->at(instIndex - 1);
+ prevInst.forEach<Reg>(
+ [&] (Reg& reg, Arg::Role role, Bank, Width) {
+ if (Arg::isLateUse(role))
+ m_workset.add(reg);
+ });
+ }
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
Added: trunk/Source/_javascript_Core/b3/air/AirRegLiveness.h (0 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirRegLiveness.h (rev 0)
+++ trunk/Source/_javascript_Core/b3/air/AirRegLiveness.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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 "AirBasicBlock.h"
+#include "AirCode.h"
+#include "AirInst.h"
+#include "RegisterSet.h"
+
+namespace JSC { namespace B3 { namespace Air {
+
+// Although we could trivially adapt Air::Liveness<> to work with Reg, this would not be so
+// efficient. There is a small number of registers, so it's much better to use bitvectors for
+// register liveness. This is a specialization of Liveness<> that uses bitvectors directly.
+// This makes the code sufficiently different that it didn't make sense to try to share code.
+class RegLiveness {
+public:
+ typedef Reg Thing;
+
+ RegLiveness(Code& code);
+ ~RegLiveness();
+
+ // This calculator has to be run in reverse.
+ class LocalCalc {
+ public:
+ LocalCalc(RegLiveness& liveness, BasicBlock* block)
+ : m_block(block)
+ , m_workset(liveness.m_liveAtTail[block])
+ {
+ }
+
+ const RegisterSet& live() const
+ {
+ return m_workset;
+ }
+
+ bool isLive(Reg reg) const
+ {
+ return m_workset.contains(reg);
+ }
+
+ void execute(unsigned instIndex);
+
+ private:
+ friend class RegLiveness;
+
+ BasicBlock* m_block;
+ RegisterSet m_workset;
+ };
+
+ const RegisterSet& liveAtHead(BasicBlock* block) const
+ {
+ return m_liveAtHead[block];
+ }
+
+ const RegisterSet& liveAtTail(BasicBlock* block) const
+ {
+ return m_liveAtTail[block];
+ }
+
+private:
+ IndexMap<BasicBlock, RegisterSet> m_liveAtHead;
+ IndexMap<BasicBlock, RegisterSet> m_liveAtTail;
+};
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
Modified: trunk/Source/_javascript_Core/b3/air/AirReportUsedRegisters.cpp (214407 => 214408)
--- trunk/Source/_javascript_Core/b3/air/AirReportUsedRegisters.cpp 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/b3/air/AirReportUsedRegisters.cpp 2017-03-26 21:39:27 UTC (rev 214408)
@@ -31,7 +31,7 @@
#include "AirArgInlines.h"
#include "AirCode.h"
#include "AirInstInlines.h"
-#include "AirLiveness.h"
+#include "AirRegLiveness.h"
#include "AirPhaseScope.h"
namespace JSC { namespace B3 { namespace Air {
Modified: trunk/Source/_javascript_Core/jit/RegisterSet.h (214407 => 214408)
--- trunk/Source/_javascript_Core/jit/RegisterSet.h 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/_javascript_Core/jit/RegisterSet.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,6 +36,8 @@
namespace JSC {
+typedef Bitmap<MacroAssembler::numGPRs + MacroAssembler::numFPRs + 1> RegisterBitmap;
+
class RegisterSet {
public:
template<typename... Regs>
@@ -99,10 +101,17 @@
set(reg);
}
+ // Also allow add/remove/contains terminology, which means the same thing as set/clear/get.
+ void add(Reg reg) { set(reg); }
+ void remove(Reg reg) { clear(reg); }
+ bool contains(Reg reg) const { return get(reg); }
+
void merge(const RegisterSet& other) { m_bits.merge(other.m_bits); }
void filter(const RegisterSet& other) { m_bits.filter(other.m_bits); }
void exclude(const RegisterSet& other) { m_bits.exclude(other.m_bits); }
+ bool subsumes(const RegisterSet& other) const { return m_bits.subsumes(other.m_bits); }
+
size_t numberOfSetGPRs() const;
size_t numberOfSetFPRs() const;
size_t numberOfSetRegisters() const { return m_bits.count(); }
@@ -149,6 +158,42 @@
});
}
+ class iterator {
+ public:
+ iterator()
+ {
+ }
+
+ iterator(const RegisterBitmap::iterator& iter)
+ : m_iter(iter)
+ {
+ }
+
+ Reg operator*() const { return Reg::fromIndex(*m_iter); }
+
+ iterator& operator++()
+ {
+ ++m_iter;
+ return *this;
+ }
+
+ bool operator==(const iterator& other)
+ {
+ return m_iter == other.m_iter;
+ }
+
+ bool operator!=(const iterator& other)
+ {
+ return !(*this == other);
+ }
+
+ private:
+ RegisterBitmap::iterator m_iter;
+ };
+
+ iterator begin() const { return iterator(m_bits.begin()); }
+ iterator end() const { return iterator(m_bits.end()); }
+
private:
void setAny(Reg reg) { set(reg); }
void setAny(const RegisterSet& set) { merge(set); }
@@ -166,7 +211,7 @@
static const unsigned hashSpecialBitIndex = fprOffset + MacroAssembler::numFPRs;
static const unsigned deletedBitIndex = 0;
- Bitmap<MacroAssembler::numGPRs + MacroAssembler::numFPRs + 1> m_bits;
+ RegisterBitmap m_bits;
};
struct RegisterSetHash {
Modified: trunk/Source/WTF/ChangeLog (214407 => 214408)
--- trunk/Source/WTF/ChangeLog 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/WTF/ChangeLog 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,3 +1,23 @@
+2017-03-26 Filip Pizlo <[email protected]>
+
+ Air should use RegisterSet for RegLiveness
+ https://bugs.webkit.org/show_bug.cgi?id=170108
+
+ Reviewed by Yusuke Suzuki.
+
+ * wtf/Atomics.h:
+ (WTF::ensurePointer): This is a useful replacement for std::once, which requires less fencing.
+ * wtf/Bitmap.h: Add more utilities.
+ (WTF::Bitmap::iterator::iterator): An iterator for set bits.
+ (WTF::Bitmap::iterator::operator*):
+ (WTF::Bitmap::iterator::operator++):
+ (WTF::Bitmap::iterator::operator==):
+ (WTF::Bitmap::iterator::operator!=):
+ (WTF::Bitmap::begin):
+ (WTF::Bitmap::end):
+ (WTF::WordType>::subsumes): a.subsumes(b) if all of b's set bits are set in a.
+ (WTF::WordType>::findBit): find next set or clear bit.
+
2017-03-24 JF Bastien <[email protected]>
WebAssembly: store state in TLS instead of on VM
Modified: trunk/Source/WTF/wtf/Atomics.h (214407 => 214408)
--- trunk/Source/WTF/wtf/Atomics.h 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/WTF/wtf/Atomics.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -519,6 +519,23 @@
#endif
}
+template<typename T, typename Func>
+ALWAYS_INLINE T& ensurePointer(Atomic<T*>& pointer, const Func& func)
+{
+ for (;;) {
+ T* oldValue = pointer.load(std::memory_order_relaxed);
+ if (oldValue) {
+ // On all sensible CPUs, we get an implicit dependency-based load-load barrier when
+ // loading this.
+ return *oldValue;
+ }
+ T* newValue = func();
+ if (pointer.compareExchangeWeak(oldValue, newValue))
+ return *newValue;
+ delete newValue;
+ }
+}
+
} // namespace WTF
using WTF::Atomic;
@@ -528,6 +545,7 @@
using WTF::consume;
using WTF::dependency;
using WTF::dependencyWith;
+using WTF::ensurePointer;
using WTF::nullDependency;
#endif // Atomics_h
Modified: trunk/Source/WTF/wtf/Bitmap.h (214407 => 214408)
--- trunk/Source/WTF/wtf/Bitmap.h 2017-03-26 03:52:40 UTC (rev 214407)
+++ trunk/Source/WTF/wtf/Bitmap.h 2017-03-26 21:39:27 UTC (rev 214408)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -59,9 +59,54 @@
void filter(const Bitmap&);
void exclude(const Bitmap&);
+ bool subsumes(const Bitmap&) const;
+
template<typename Func>
void forEachSetBit(const Func&) const;
+ size_t findBit(size_t startIndex, bool value) const;
+
+ class iterator {
+ public:
+ iterator()
+ : m_bitmap(nullptr)
+ , m_index(0)
+ {
+ }
+
+ iterator(const Bitmap& bitmap, size_t index)
+ : m_bitmap(&bitmap)
+ , m_index(index)
+ {
+ }
+
+ size_t operator*() const { return m_index; }
+
+ iterator& operator++()
+ {
+ m_index = m_bitmap->findBit(m_index + 1, true);
+ return *this;
+ }
+
+ bool operator==(const iterator& other) const
+ {
+ return m_index == other.m_index;
+ }
+
+ bool operator!=(const iterator& other) const
+ {
+ return !(*this == other);
+ }
+
+ private:
+ const Bitmap* m_bitmap;
+ size_t m_index;
+ };
+
+ // Use this to iterate over set bits.
+ iterator begin() const { return iterator(*this, findBit(0, true)); }
+ iterator end() const { return iterator(*this, bitmapSize); }
+
void mergeAndClear(Bitmap&);
void setAndClear(Bitmap&);
@@ -258,6 +303,18 @@
}
template<size_t bitmapSize, typename WordType>
+inline bool Bitmap<bitmapSize, WordType>::subsumes(const Bitmap& other) const
+{
+ for (size_t i = 0; i < words; ++i) {
+ WordType myBits = bits[i];
+ WordType otherBits = other.bits[i];
+ if ((myBits | otherBits) != myBits)
+ return false;
+ }
+ return true;
+}
+
+template<size_t bitmapSize, typename WordType>
template<typename Func>
inline void Bitmap<bitmapSize, WordType>::forEachSetBit(const Func& func) const
{
@@ -275,6 +332,28 @@
}
template<size_t bitmapSize, typename WordType>
+inline size_t Bitmap<bitmapSize, WordType>::findBit(size_t startIndex, bool value) const
+{
+ WordType skipValue = -(static_cast<WordType>(value) ^ 1);
+ size_t wordIndex = startIndex / wordSize;
+ size_t startIndexInWord = startIndex - wordIndex * wordSize;
+
+ while (wordIndex < words) {
+ WordType word = bits[wordIndex];
+ if (word != skipValue) {
+ size_t index = startIndexInWord;
+ if (findBitInWord(word, index, wordSize, value))
+ return wordIndex * wordSize + index;
+ }
+
+ wordIndex++;
+ startIndexInWord = 0;
+ }
+
+ return bitmapSize;
+}
+
+template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::mergeAndClear(Bitmap& other)
{
for (size_t i = 0; i < words; ++i) {