Bug 1077720 - IonMonkey: Optimize MPhi's addInput and addInputSlow r=nbp

This commit is contained in:
Dan Gohman 2014-10-08 15:04:12 -07:00
parent 1b3e647f56
commit 2180277e21
6 changed files with 91 additions and 94 deletions

View File

@ -78,6 +78,13 @@ class FixedList
MOZ_ASSERT(index < length_);
return list_[index];
}
T *begin() {
return list_;
}
T *end() {
return list_ + length_;
}
};
} // namespace jit

View File

@ -211,7 +211,26 @@ class InlineListNode : public InlineForwardListNode<T>
prev(p)
{ }
// Move constructor. Nodes may be moved without being removed from their
// containing lists. For example, this allows list nodes to be safely
// stored in a resizable Vector -- when the Vector resizes, the new storage
// is initialized by this move constructor. |other| is a reference to the
// old node which the |this| node here is replacing.
InlineListNode(InlineListNode<T> &&other)
: InlineForwardListNode<T>(other.next)
{
InlineListNode<T> *newNext = static_cast<InlineListNode<T> *>(other.next);
InlineListNode<T> *newPrev = other.prev;
prev = newPrev;
// Update the pointers in the adjacent nodes to point to this node's new
// location.
newNext->prev = this;
newPrev->next = this;
}
InlineListNode(const InlineListNode<T> &) MOZ_DELETE;
void operator=(const InlineListNode<T> &) MOZ_DELETE;
protected:
friend class InlineList<T>;

View File

@ -1361,19 +1361,6 @@ MPhi::congruentTo(const MDefinition *ins) const
return congruentIfOperandsEqual(ins);
}
bool
MPhi::reserveLength(size_t length)
{
// Initializes a new MPhi to have an Operand vector of at least the given
// capacity. This permits use of addInput() instead of addInputSlow(), the
// latter of which may call pod_realloc().
MOZ_ASSERT(numOperands() == 0);
#if DEBUG
capacity_ = length;
#endif
return inputs_.reserve(length);
}
static inline types::TemporaryTypeSet *
MakeMIRTypeSet(MIRType type)
{
@ -1502,65 +1489,20 @@ MPhi::typeIncludes(MDefinition *def)
return this->mightBeType(def->type());
}
void
MPhi::addInput(MDefinition *ins)
{
// This can only been done if the length was reserved through reserveLength,
// else the slower addInputSlow need to get called.
MOZ_ASSERT(inputs_.length() < capacity_);
inputs_.append(MUse());
inputs_.back().init(ins, this);
}
bool
MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
MPhi::checkForTypeChange(MDefinition *ins, bool *ptypeChange)
{
// The list of inputs to an MPhi is given as a vector of MUse nodes,
// each of which is in the list of the producer MDefinition.
// Because appending to a vector may reallocate the vector, it is possible
// that this operation may cause the producers' linked lists to reference
// invalid memory. Therefore, in the event of moving reallocation, each
// MUse must be removed and reinserted from/into its producer's use chain.
uint32_t index = inputs_.length();
bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
MIRType resultType = this->type();
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
// Remove all MUses from all use lists, in case pod_realloc() moves.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->removeUse(use);
}
}
// Insert the new input.
if (!inputs_.append(MUse()))
if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
return false;
inputs_.back().init(ins, this);
if (ptypeChange) {
MIRType resultType = this->type();
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
return false;
if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
*ptypeChange = true;
setResultType(resultType);
setResultTypeSet(resultTypeSet);
}
if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
*ptypeChange = true;
setResultType(resultType);
setResultTypeSet(resultTypeSet);
}
// Add all previously-removed MUses back.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->addUse(use);
}
}
return true;
}

View File

@ -127,11 +127,6 @@ class MUse : public TempObject, public InlineListNode<MUse>
MDefinition *producer_; // MDefinition that is being used.
MNode *consumer_; // The node that is using this operand.
MUse(MDefinition *producer, MNode *consumer)
: producer_(producer),
consumer_(consumer)
{ }
// Low-level unchecked edit method for replaceAllUsesWith and
// MPhi::removeOperand. This doesn't update use lists!
// replaceAllUsesWith and MPhi::removeOperand do that manually.
@ -148,11 +143,17 @@ class MUse : public TempObject, public InlineListNode<MUse>
: producer_(nullptr), consumer_(nullptr)
{ }
// MUses can only be copied when they are not in a use list.
explicit MUse(const MUse &other)
: producer_(other.producer_), consumer_(other.consumer_)
// Move constructor for use in vectors. When an MUse is moved, it stays
// in its containing use list.
MUse(MUse &&other)
: InlineListNode<MUse>(mozilla::Move(other)),
producer_(other.producer_), consumer_(other.consumer_)
{ }
// Construct an MUse initialized with |producer| and |consumer|.
MUse(MDefinition *producer, MNode *consumer)
{
MOZ_ASSERT(!other.next && !other.prev);
initUnchecked(producer, consumer);
}
// Set this use, which was previously clear.
@ -5904,7 +5905,6 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
#if DEBUG
bool specialized_;
uint32_t capacity_;
#endif
protected:
@ -5933,7 +5933,6 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
canConsumeFloat32_(false)
#if DEBUG
, specialized_(false)
, capacity_(0)
#endif
{
setResultType(resultType);
@ -6003,14 +6002,36 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
// Initializes the operands vector to the given capacity,
// permitting use of addInput() instead of addInputSlow().
bool reserveLength(size_t length);
bool reserveLength(size_t length) {
return inputs_.reserve(length);
}
// Use only if capacity has been reserved by reserveLength
void addInput(MDefinition *ins);
void addInput(MDefinition *ins) {
// Use infallibleGrowByUninitialized and placement-new instead of just
// infallibleAppend to avoid creating a temporary MUse which will get
// linked into |ins|'s use list and then unlinked in favor of the
// MUse in the Vector. We'd ideally like to use an emplace method here,
// once Vector supports that.
inputs_.infallibleGrowByUninitialized(1);
new (&inputs_.back()) MUse(ins, this);
}
// Appends a new input to the input vector. May call pod_realloc().
// Appends a new input to the input vector. May perform reallocation.
// Prefer reserveLength() and addInput() instead, where possible.
bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
bool addInputSlow(MDefinition *ins) {
// Use growByUninitialized and placement-new instead of just append,
// similar to what addInput does.
if (!inputs_.growByUninitialized(1))
return false;
new (&inputs_.back()) MUse(ins, this);
return true;
}
// Update the type of this phi after adding |ins| as an input. Set
// |*ptypeChange| to true if the type changed.
bool checkForTypeChange(MDefinition *ins, bool *ptypeChange);
MDefinition *foldsTo(TempAllocator &alloc);
MDefinition *foldsTernary();

View File

@ -335,7 +335,6 @@ MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kin
MOZ_ASSERT(predSlot->type() != MIRType_Value);
MPhi *phi = new(phis + i) MPhi(alloc, predSlot->type());
JS_ALWAYS_TRUE(phi->reserveLength(2));
phi->addInput(predSlot);
// Add append Phis in the block.
@ -407,8 +406,10 @@ MBasicBlock::copySlots(MBasicBlock *from)
{
MOZ_ASSERT(stackPosition_ <= from->stackPosition_);
for (uint32_t i = 0; i < stackPosition_; i++)
slots_[i] = from->slots_[i];
MDefinition **thisSlots = slots_.begin();
MDefinition **fromSlots = from->slots_.begin();
for (size_t i = 0, e = stackPosition_; i < e; ++i)
thisSlots[i] = fromSlots[i];
}
bool
@ -447,8 +448,7 @@ MBasicBlock::inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlo
size_t i = 0;
for (i = 0; i < info().firstStackSlot(); i++) {
MPhi *phi = MPhi::New(alloc);
if (!phi->addInputSlow(pred->getSlot(i)))
return false;
phi->addInput(pred->getSlot(i));
addPhi(phi);
setSlot(i, phi);
entryResumePoint()->initOperand(i, phi);
@ -468,8 +468,7 @@ MBasicBlock::inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlo
for (; i < stackDepth(); i++) {
MPhi *phi = MPhi::New(alloc);
if (!phi->addInputSlow(pred->getSlot(i)))
return false;
phi->addInput(pred->getSlot(i));
addPhi(phi);
setSlot(i, phi);
entryResumePoint()->initOperand(i, phi);
@ -1025,7 +1024,7 @@ MBasicBlock::addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_
MOZ_ASSERT(pred->hasLastIns());
MOZ_ASSERT(pred->stackPosition_ == stackPosition_ + popped);
for (uint32_t i = 0; i < stackPosition_; i++) {
for (uint32_t i = 0, e = stackPosition_; i < e; ++i) {
MDefinition *mine = getSlot(i);
MDefinition *other = pred->getSlot(i);
@ -1051,7 +1050,7 @@ MBasicBlock::addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_
if (!phi->reserveLength(predecessors_.length() + 1))
return false;
for (size_t j = 0; j < predecessors_.length(); j++) {
for (size_t j = 0, numPreds = predecessors_.length(); j < numPreds; ++j) {
MOZ_ASSERT(predecessors_[j]->getSlot(i) == mine);
phi->addInput(mine);
}
@ -1197,7 +1196,7 @@ MBasicBlock::setBackedgeAsmJS(MBasicBlock *pred)
exitDef = entryDef->getOperand(0);
}
// MBasicBlock::NewAsmJS calls reserveLength(2) for loop header phis.
// Phis always have room for 2 operands, so we can use addInput.
entryDef->addInput(exitDef);
MOZ_ASSERT(slot < pred->stackDepth());
@ -1436,9 +1435,10 @@ MBasicBlock::inheritPhisFromBackedge(MBasicBlock *backedge, bool *hadTypeChange)
bool typeChange = false;
if (!entryDef->addInputSlow(exitDef, &typeChange))
if (!entryDef->addInputSlow(exitDef))
return false;
if (!entryDef->checkForTypeChange(exitDef, &typeChange))
return false;
*hadTypeChange |= typeChange;
setSlot(slot, entryDef);
}

View File

@ -472,6 +472,7 @@ public:
* -- leave them as uninitialized memory.
*/
bool growByUninitialized(size_t aIncr);
void infallibleGrowByUninitialized(size_t aIncr);
bool resizeUninitialized(size_t aNewLength);
/** Shorthand for shrinkBy(length()). */
@ -879,6 +880,14 @@ VectorBase<T, N, AP, TV>::growByUninitialized(size_t aIncr)
if (aIncr > mCapacity - mLength && !growStorageBy(aIncr)) {
return false;
}
infallibleGrowByUninitialized(aIncr);
return true;
}
template<typename T, size_t N, class AP, class TV>
MOZ_ALWAYS_INLINE void
VectorBase<T, N, AP, TV>::infallibleGrowByUninitialized(size_t aIncr)
{
MOZ_ASSERT(mLength + aIncr <= mCapacity);
mLength += aIncr;
#ifdef DEBUG
@ -886,7 +895,6 @@ VectorBase<T, N, AP, TV>::growByUninitialized(size_t aIncr)
mReserved = mLength;
}
#endif
return true;
}
template<typename T, size_t N, class AP, class TV>