mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1004363 - IonMonkey: A new value-numbering implementation based on a dom-tree DFS. r=nbp
This commit is contained in:
parent
8ae670ea14
commit
243266ba02
@ -479,6 +479,13 @@ class HashSet
|
||||
impl.rekeyAndMaybeRehash(p, new_lookup, new_value);
|
||||
}
|
||||
|
||||
// Infallibly rekey one entry with a new key that is equivalent.
|
||||
void rekeyInPlace(Ptr p, const T &new_value)
|
||||
{
|
||||
MOZ_ASSERT(HashPolicy::match(*p, new_value));
|
||||
impl.rekeyInPlace(p, new_value);
|
||||
}
|
||||
|
||||
// HashSet is movable
|
||||
HashSet(HashSet &&rhs) : impl(mozilla::Move(rhs.impl)) {}
|
||||
void operator=(HashSet &&rhs) {
|
||||
@ -1629,6 +1636,14 @@ class HashTable : private AllocPolicy
|
||||
checkOverRemoved();
|
||||
}
|
||||
|
||||
void rekeyInPlace(Ptr p, const Key &k)
|
||||
{
|
||||
MOZ_ASSERT(table);
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
MOZ_ASSERT(p.found());
|
||||
HashPolicy::rekey(const_cast<Key &>(*p), const_cast<Key &>(k));
|
||||
}
|
||||
|
||||
#undef METER
|
||||
};
|
||||
|
||||
|
@ -177,8 +177,7 @@ AliasAnalysis::analyze()
|
||||
|
||||
// Type analysis may have inserted new instructions. Since this pass depends
|
||||
// on the instruction number ordering, all instructions are renumbered.
|
||||
// We start with 1 because some passes use 0 to denote failure.
|
||||
uint32_t newId = 1;
|
||||
uint32_t newId = 0;
|
||||
|
||||
for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
|
||||
if (mir->shouldCancel("Alias Analysis (main loop)"))
|
||||
|
@ -21,7 +21,7 @@ bool
|
||||
EdgeCaseAnalysis::analyzeLate()
|
||||
{
|
||||
// Renumber definitions for NeedNegativeZeroCheck under analyzeEdgeCasesBackward.
|
||||
uint32_t nextId = 1;
|
||||
uint32_t nextId = 0;
|
||||
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
if (mir->shouldCancel("Analyze Late (first loop)"))
|
||||
|
@ -1395,8 +1395,8 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
|
||||
if (mir->optimizationInfo().gvnEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::GVN);
|
||||
ValueNumberer gvn(mir, graph, mir->optimizationInfo().gvnKind() == GVN_Optimistic);
|
||||
if (!gvn.analyze())
|
||||
ValueNumberer gvn(mir, graph);
|
||||
if (!gvn.run(ValueNumberer::UpdateAliasAnalysis))
|
||||
return false;
|
||||
IonSpewPass("GVN");
|
||||
AssertExtendedGraphCoherency(graph);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "jit/IonAnalysis.h"
|
||||
|
||||
#include "jit/AliasAnalysis.h"
|
||||
#include "jit/BaselineInspector.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Ion.h"
|
||||
@ -1091,6 +1092,59 @@ jit::RenumberBlocks(MIRGraph &graph)
|
||||
return true;
|
||||
}
|
||||
|
||||
// A utility for code which deletes blocks. Renumber the remaining blocks,
|
||||
// recompute dominators, and optionally recompute AliasAnalysis dependencies.
|
||||
bool
|
||||
jit::AccountForCFGChanges(MIRGenerator *mir, MIRGraph &graph, bool updateAliasAnalysis)
|
||||
{
|
||||
// Renumber the blocks and clear out the old dominator info.
|
||||
size_t id = 0;
|
||||
for (ReversePostorderIterator i(graph.rpoBegin()), e(graph.rpoEnd()); i != e; ++i) {
|
||||
i->clearDominatorInfo();
|
||||
i->setId(id++);
|
||||
}
|
||||
|
||||
// Recompute dominator info.
|
||||
if (!BuildDominatorTree(graph))
|
||||
return false;
|
||||
|
||||
// If needed, update alias analysis dependencies.
|
||||
if (updateAliasAnalysis) {
|
||||
if (!AliasAnalysis(mir, graph).analyze())
|
||||
return false;
|
||||
}
|
||||
|
||||
AssertExtendedGraphCoherency(graph);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove all blocks not marked with isMarked(). Unmark all remaining blocks.
|
||||
// Alias analysis dependencies may be invalid after calling this function.
|
||||
bool
|
||||
jit::RemoveUnmarkedBlocks(MIRGenerator *mir, MIRGraph &graph, uint32_t numMarkedBlocks)
|
||||
{
|
||||
// If all blocks are marked, the CFG is unmodified. Just clear the marks.
|
||||
if (numMarkedBlocks == graph.numBlocks()) {
|
||||
graph.unmarkBlocks();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (ReversePostorderIterator iter(graph.rpoBegin()); iter != graph.rpoEnd();) {
|
||||
MBasicBlock *block = *iter++;
|
||||
|
||||
if (block->isMarked()) {
|
||||
block->unmark();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0, e = block->numSuccessors(); i != e; ++i)
|
||||
block->getSuccessor(i)->removePredecessor(block);
|
||||
graph.removeBlockIncludingPhis(block);
|
||||
}
|
||||
|
||||
return AccountForCFGChanges(mir, graph, /*updateAliasAnalysis=*/false);
|
||||
}
|
||||
|
||||
// A Simple, Fast Dominance Algorithm by Cooper et al.
|
||||
// Modified to support empty intersections for OSR, and in RPO.
|
||||
static MBasicBlock *
|
||||
@ -1559,7 +1613,13 @@ BoundsCheckHashIgnoreOffset(MBoundsCheck *check)
|
||||
static MBoundsCheck *
|
||||
FindDominatingBoundsCheck(BoundsCheckMap &checks, MBoundsCheck *check, size_t index)
|
||||
{
|
||||
// See the comment in ValueNumberer::findDominatingDef.
|
||||
// Since we are traversing the dominator tree in pre-order, when we
|
||||
// are looking at the |index|-th block, the next numDominated() blocks
|
||||
// we traverse are precisely the set of blocks that are dominated.
|
||||
//
|
||||
// So, this value is visible in all blocks if:
|
||||
// index <= index + ins->block->numDominated()
|
||||
// and becomes invalid after that.
|
||||
HashNumber hash = BoundsCheckHashIgnoreOffset(check);
|
||||
BoundsCheckMap::Ptr p = checks.lookup(hash);
|
||||
if (!p || index >= p->value().validEnd) {
|
||||
|
@ -55,6 +55,12 @@ MakeMRegExpHoistable(MIRGraph &graph);
|
||||
bool
|
||||
RenumberBlocks(MIRGraph &graph);
|
||||
|
||||
bool
|
||||
AccountForCFGChanges(MIRGenerator *mir, MIRGraph &graph, bool updateAliasAnalysis);
|
||||
|
||||
bool
|
||||
RemoveUnmarkedBlocks(MIRGenerator *mir, MIRGraph &graph, uint32_t numMarkedBlocks);
|
||||
|
||||
bool
|
||||
BuildDominatorTree(MIRGraph &graph);
|
||||
|
||||
|
@ -29,7 +29,6 @@ OptimizationInfo::initNormalOptimizationInfo()
|
||||
inlineInterpreted_ = true;
|
||||
inlineNative_ = true;
|
||||
gvn_ = true;
|
||||
gvnKind_ = GVN_Optimistic;
|
||||
licm_ = true;
|
||||
uce_ = true;
|
||||
rangeAnalysis_ = true;
|
||||
|
@ -66,9 +66,6 @@ class OptimizationInfo
|
||||
// Toggles whether global value numbering is used.
|
||||
bool gvn_;
|
||||
|
||||
// Toggles whether global value numbering is optimistic or pessimistic.
|
||||
IonGvnKind gvnKind_;
|
||||
|
||||
// Toggles whether loop invariant code motion is performed.
|
||||
bool licm_;
|
||||
|
||||
@ -162,12 +159,6 @@ class OptimizationInfo
|
||||
return eliminateRedundantChecks_;
|
||||
}
|
||||
|
||||
IonGvnKind gvnKind() const {
|
||||
if (!js_JitOptions.forceGvnKind)
|
||||
return gvnKind_;
|
||||
return js_JitOptions.forcedGvnKind;
|
||||
}
|
||||
|
||||
IonRegisterAllocator registerAllocator() const {
|
||||
if (!js_JitOptions.forceRegisterAllocator)
|
||||
return registerAllocator_;
|
||||
|
@ -66,11 +66,6 @@ JitOptions::JitOptions()
|
||||
forceDefaultIonUsesBeforeCompile = false;
|
||||
forcedDefaultIonUsesBeforeCompile = 1000;
|
||||
|
||||
// Force the GVN kind to be optimistic or pessimistic instead of letting
|
||||
// the optimization pass decide.
|
||||
forceGvnKind = false;
|
||||
forcedGvnKind = GVN_Optimistic;
|
||||
|
||||
// Force the used register allocator instead of letting the
|
||||
// optimization pass decide.
|
||||
forceRegisterAllocator = false;
|
||||
|
@ -28,11 +28,6 @@ enum IonRegisterAllocator {
|
||||
RegisterAllocator_Stupid
|
||||
};
|
||||
|
||||
enum IonGvnKind {
|
||||
GVN_Optimistic,
|
||||
GVN_Pessimistic
|
||||
};
|
||||
|
||||
struct JitOptions
|
||||
{
|
||||
bool checkGraphConsistency;
|
||||
@ -51,8 +46,6 @@ struct JitOptions
|
||||
bool eagerCompilation;
|
||||
bool forceDefaultIonUsesBeforeCompile;
|
||||
uint32_t forcedDefaultIonUsesBeforeCompile;
|
||||
bool forceGvnKind;
|
||||
IonGvnKind forcedGvnKind;
|
||||
bool forceRegisterAllocator;
|
||||
IonRegisterAllocator forcedRegisterAllocator;
|
||||
bool limitScriptSize;
|
||||
|
@ -69,15 +69,6 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
|
||||
fprintf(fp, "%c", tolower(name[i]));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
EqualValues(bool useGVN, MDefinition *left, MDefinition *right)
|
||||
{
|
||||
if (useGVN)
|
||||
return left->valueNumber() == right->valueNumber();
|
||||
|
||||
return left == right;
|
||||
}
|
||||
|
||||
static MConstant *
|
||||
EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr)
|
||||
{
|
||||
@ -148,9 +139,6 @@ MDefinition::printName(FILE *fp) const
|
||||
{
|
||||
PrintOpcodeName(fp, op());
|
||||
fprintf(fp, "%u", id());
|
||||
|
||||
if (valueNumber() != 0)
|
||||
fprintf(fp, "-vn%u", valueNumber());
|
||||
}
|
||||
|
||||
HashNumber
|
||||
@ -158,7 +146,7 @@ MDefinition::valueHash() const
|
||||
{
|
||||
HashNumber out = op();
|
||||
for (size_t i = 0, e = numOperands(); i < e; i++) {
|
||||
uint32_t valueNumber = getOperand(i)->valueNumber();
|
||||
uint32_t valueNumber = getOperand(i)->id();
|
||||
out = valueNumber + (out << 6) + (out << 16) - out;
|
||||
}
|
||||
return out;
|
||||
@ -180,7 +168,7 @@ MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
|
||||
return false;
|
||||
|
||||
for (size_t i = 0, e = numOperands(); i < e; i++) {
|
||||
if (getOperand(i)->valueNumber() != ins->getOperand(i)->valueNumber())
|
||||
if (getOperand(i) != ins->getOperand(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -188,7 +176,7 @@ MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MDefinition::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MDefinition::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
// In the default case, there are no constants to fold.
|
||||
return this;
|
||||
@ -246,7 +234,7 @@ MTest::cacheOperandMightEmulateUndefined()
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MTest::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MTest::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *op = getOperand(0);
|
||||
|
||||
@ -808,7 +796,7 @@ MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDef
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MStringLength::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if ((type() == MIRType_Int32) && (string()->isConstant())) {
|
||||
Value value = string()->toConstant()->value();
|
||||
@ -949,22 +937,31 @@ MPhi::removeAllOperands()
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MPhi::operandIfRedundant()
|
||||
{
|
||||
JS_ASSERT(!inputs_.empty());
|
||||
JS_ASSERT(inputs_.length() != 0);
|
||||
|
||||
// If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
|
||||
// returns the operand that it will always be equal to (a, in
|
||||
// those two cases).
|
||||
MDefinition *first = getOperand(0);
|
||||
|
||||
for (size_t i = 1; i < inputs_.length(); i++) {
|
||||
// Phis need dominator information to fold based on value numbers. For
|
||||
// simplicity, we only compare SSA names right now (bug 714727).
|
||||
if (!EqualValues(false, getOperand(i), first))
|
||||
return this;
|
||||
for (size_t i = 1, e = numOperands(); i < e; i++) {
|
||||
MDefinition *op = getOperand(i);
|
||||
if (op != first && op != this)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MPhi::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (MDefinition *def = operandIfRedundant())
|
||||
return def;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool
|
||||
MPhi::congruentTo(const MDefinition *ins) const
|
||||
{
|
||||
@ -1224,7 +1221,7 @@ IsConstant(MDefinition *def, double v)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (specialization_ != MIRType_Int32)
|
||||
return this;
|
||||
@ -1259,7 +1256,7 @@ MBinaryBitwiseInstruction::foldUnnecessaryBitop()
|
||||
if (IsConstant(rhs, -1))
|
||||
return foldIfNegOne(1);
|
||||
|
||||
if (EqualValues(false, lhs, rhs))
|
||||
if (lhs == rhs)
|
||||
return foldIfEqual();
|
||||
|
||||
return this;
|
||||
@ -1416,7 +1413,7 @@ NeedNegativeZeroCheck(MDefinition *def)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MBinaryArithInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MBinaryArithInstruction::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (specialization_ == MIRType_None)
|
||||
return this;
|
||||
@ -1483,7 +1480,7 @@ MAbs::trySpecializeFloat32(TempAllocator &alloc)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MDiv::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MDiv::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (specialization_ == MIRType_None)
|
||||
return this;
|
||||
@ -1540,7 +1537,7 @@ MDiv::fallible() const
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MMod::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MMod::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (specialization_ == MIRType_None)
|
||||
return this;
|
||||
@ -1612,16 +1609,16 @@ MSub::fallible() const
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MMul::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MMul::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *out = MBinaryArithInstruction::foldsTo(alloc, useValueNumbers);
|
||||
MDefinition *out = MBinaryArithInstruction::foldsTo(alloc);
|
||||
if (out != this)
|
||||
return out;
|
||||
|
||||
if (specialization() != MIRType_Int32)
|
||||
return this;
|
||||
|
||||
if (EqualValues(useValueNumbers, lhs(), rhs()))
|
||||
if (lhs() == rhs())
|
||||
setCanBeNegativeZero(false);
|
||||
|
||||
return this;
|
||||
@ -2086,7 +2083,7 @@ MBitNot::NewAsmJS(TempAllocator &alloc, MDefinition *input)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MBitNot::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (specialization_ != MIRType_Int32)
|
||||
return this;
|
||||
@ -2107,7 +2104,7 @@ MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MTypeOf::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
// Note: we can't use input->type() here, type analysis has
|
||||
// boxed the input.
|
||||
@ -2335,7 +2332,7 @@ MResumePoint::isObservableOperand(size_t index) const
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MToInt32::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *input = getOperand(0);
|
||||
if (input->type() == MIRType_Int32)
|
||||
@ -2351,7 +2348,7 @@ MToInt32::analyzeEdgeCasesBackward()
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MTruncateToInt32::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *input = getOperand(0);
|
||||
if (input->type() == MIRType_Int32)
|
||||
@ -2367,7 +2364,7 @@ MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MToDouble::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *in = input();
|
||||
if (in->type() == MIRType_Double)
|
||||
@ -2385,7 +2382,7 @@ MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MToFloat32::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (input()->type() == MIRType_Float32)
|
||||
return input();
|
||||
@ -2407,7 +2404,7 @@ MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MToString::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
MDefinition *in = input();
|
||||
if (in->type() == MIRType_String)
|
||||
@ -2416,7 +2413,7 @@ MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MClampToUint8::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MClampToUint8::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (input()->isConstant()) {
|
||||
const Value &v = input()->toConstant()->value();
|
||||
@ -2637,7 +2634,7 @@ MCompare::evaluateConstantOperands(bool *result)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MCompare::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MCompare::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
bool result;
|
||||
|
||||
@ -2709,7 +2706,7 @@ MNot::cacheOperandMightEmulateUndefined()
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MNot::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
// Fold if the input is constant
|
||||
if (operand()->isConstant()) {
|
||||
@ -3007,7 +3004,7 @@ MGetPropertyCache::updateForReplacement(MDefinition *ins) {
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (input()->isConstant()) {
|
||||
const Value &v = input()->toConstant()->value();
|
||||
@ -3019,7 +3016,7 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (input()->isConstant()) {
|
||||
const Value &v = input()->toConstant()->value();
|
||||
|
@ -32,7 +32,6 @@ class StringObject;
|
||||
namespace jit {
|
||||
|
||||
class BaselineInspector;
|
||||
class ValueNumberData;
|
||||
class Range;
|
||||
|
||||
static inline
|
||||
@ -323,7 +322,6 @@ class MDefinition : public MNode
|
||||
InlineList<MUse> uses_; // Use chain.
|
||||
uint32_t id_; // Instruction ID, which after block re-ordering
|
||||
// is sorted within a basic block.
|
||||
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
|
||||
Range *range_; // Any computed range for this def.
|
||||
MIRType resultType_; // Representation of result type.
|
||||
types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type.
|
||||
@ -365,7 +363,6 @@ class MDefinition : public MNode
|
||||
public:
|
||||
MDefinition()
|
||||
: id_(0),
|
||||
valueNumber_(nullptr),
|
||||
range_(nullptr),
|
||||
resultType_(MIRType_None),
|
||||
resultTypeSet_(nullptr),
|
||||
@ -448,7 +445,7 @@ class MDefinition : public MNode
|
||||
return false;
|
||||
}
|
||||
bool congruentIfOperandsEqual(const MDefinition *ins) const;
|
||||
virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
virtual MDefinition *foldsTo(TempAllocator &alloc);
|
||||
virtual void analyzeEdgeCasesForward();
|
||||
virtual void analyzeEdgeCasesBackward();
|
||||
|
||||
@ -511,18 +508,6 @@ class MDefinition : public MNode
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
uint32_t valueNumber() const;
|
||||
void setValueNumber(uint32_t vn);
|
||||
ValueNumberData *valueNumberData() {
|
||||
return valueNumber_;
|
||||
}
|
||||
void clearValueNumberData() {
|
||||
valueNumber_ = nullptr;
|
||||
}
|
||||
void setValueNumberData(ValueNumberData *vn) {
|
||||
JS_ASSERT(valueNumber_ == nullptr);
|
||||
valueNumber_ = vn;
|
||||
}
|
||||
#define FLAG_ACCESSOR(flag) \
|
||||
bool is##flag() const {\
|
||||
return hasFlags(1 << flag);\
|
||||
@ -537,6 +522,9 @@ class MDefinition : public MNode
|
||||
}\
|
||||
void set##flag##Unchecked() {\
|
||||
setFlags(1 << flag);\
|
||||
} \
|
||||
void setNot##flag##Unchecked() {\
|
||||
removeFlags(1 << flag);\
|
||||
}
|
||||
|
||||
MIR_FLAG_LIST(FLAG_ACCESSOR)
|
||||
@ -869,7 +857,7 @@ class MBinaryInstruction : public MAryInstruction<2>
|
||||
MDefinition *lhs = getOperand(0);
|
||||
MDefinition *rhs = getOperand(1);
|
||||
|
||||
return op() + lhs->valueNumber() + rhs->valueNumber();
|
||||
return op() + lhs->id() + rhs->id();
|
||||
}
|
||||
void swapOperands() {
|
||||
MDefinition *temp = getOperand(0);
|
||||
@ -892,7 +880,7 @@ class MBinaryInstruction : public MAryInstruction<2>
|
||||
const MDefinition *right = getOperand(1);
|
||||
const MDefinition *tmp;
|
||||
|
||||
if (isCommutative() && left->valueNumber() > right->valueNumber()) {
|
||||
if (isCommutative() && left->id() > right->id()) {
|
||||
tmp = right;
|
||||
right = left;
|
||||
left = tmp;
|
||||
@ -901,14 +889,14 @@ class MBinaryInstruction : public MAryInstruction<2>
|
||||
const MBinaryInstruction *bi = static_cast<const MBinaryInstruction *>(ins);
|
||||
const MDefinition *insLeft = bi->getOperand(0);
|
||||
const MDefinition *insRight = bi->getOperand(1);
|
||||
if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
|
||||
if (isCommutative() && insLeft->id() > insRight->id()) {
|
||||
tmp = insRight;
|
||||
insRight = insLeft;
|
||||
insLeft = tmp;
|
||||
}
|
||||
|
||||
return (left->valueNumber() == insLeft->valueNumber()) &&
|
||||
(right->valueNumber() == insRight->valueNumber());
|
||||
return left == insLeft &&
|
||||
right == insRight;
|
||||
}
|
||||
|
||||
// Return true if the operands to this instruction are both unsigned,
|
||||
@ -934,7 +922,7 @@ class MTernaryInstruction : public MAryInstruction<3>
|
||||
MDefinition *second = getOperand(1);
|
||||
MDefinition *third = getOperand(2);
|
||||
|
||||
return op() + first->valueNumber() + second->valueNumber() + third->valueNumber();
|
||||
return op() + first->id() + second->id() + third->id();
|
||||
}
|
||||
};
|
||||
|
||||
@ -958,8 +946,8 @@ class MQuaternaryInstruction : public MAryInstruction<4>
|
||||
MDefinition *third = getOperand(2);
|
||||
MDefinition *fourth = getOperand(3);
|
||||
|
||||
return op() + first->valueNumber() + second->valueNumber() +
|
||||
third->valueNumber() + fourth->valueNumber();
|
||||
return op() + first->id() + second->id() +
|
||||
third->id() + fourth->id();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1479,7 +1467,7 @@ class MTest
|
||||
// to check whether the operand might do this. If this method is never
|
||||
// called, we'll assume our operand can emulate undefined.
|
||||
void cacheOperandMightEmulateUndefined();
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
|
||||
bool *filtersNull);
|
||||
|
||||
@ -2557,7 +2545,7 @@ class MCompare
|
||||
|
||||
bool tryFold(bool *result);
|
||||
bool evaluateConstantOperands(bool *result);
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
|
||||
bool *filtersNull);
|
||||
|
||||
@ -3203,7 +3191,7 @@ class MToDouble
|
||||
return this;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
|
||||
return false;
|
||||
@ -3276,7 +3264,7 @@ class MToFloat32
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
virtual MDefinition *foldsTo(TempAllocator &alloc);
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion())
|
||||
return false;
|
||||
@ -3309,7 +3297,7 @@ class MAsmJSUnsignedToDouble
|
||||
return new(alloc) MAsmJSUnsignedToDouble(def);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
@ -3335,7 +3323,7 @@ class MAsmJSUnsignedToFloat32
|
||||
return new(alloc) MAsmJSUnsignedToFloat32(def);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
@ -3378,7 +3366,7 @@ class MToInt32
|
||||
return new(alloc) MToInt32(def, conversion);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
// this only has backwards information flow.
|
||||
void analyzeEdgeCasesBackward();
|
||||
@ -3437,7 +3425,7 @@ class MTruncateToInt32 : public MUnaryInstruction
|
||||
return new(alloc) MTruncateToInt32(def);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
@ -3474,7 +3462,7 @@ class MToString :
|
||||
return new(alloc) MToString(def);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
@ -3514,7 +3502,7 @@ class MBitNot
|
||||
return this;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void infer();
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
@ -3562,7 +3550,7 @@ class MTypeOf
|
||||
return inputType_;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void cacheInputMaybeCallableOrEmulatesUndefined();
|
||||
|
||||
bool inputMaybeCallableOrEmulatesUndefined() const {
|
||||
@ -3631,7 +3619,7 @@ class MBinaryBitwiseInstruction
|
||||
return this;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
MDefinition *foldUnnecessaryBitop();
|
||||
virtual MDefinition *foldIfZero(size_t operand) = 0;
|
||||
virtual MDefinition *foldIfNegOne(size_t operand) = 0;
|
||||
@ -3869,7 +3857,7 @@ class MBinaryArithInstruction
|
||||
return specialization_;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
virtual double getIdentity() = 0;
|
||||
|
||||
@ -4467,7 +4455,7 @@ class MMul : public MBinaryArithInstruction
|
||||
return new(alloc) MMul(left, right, type, mode);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void analyzeEdgeCasesForward();
|
||||
void analyzeEdgeCasesBackward();
|
||||
void collectRangeInfoPreTrunc();
|
||||
@ -4562,7 +4550,7 @@ class MDiv : public MBinaryArithInstruction
|
||||
return div;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void analyzeEdgeCasesForward();
|
||||
void analyzeEdgeCasesBackward();
|
||||
|
||||
@ -4658,7 +4646,7 @@ class MMod : public MBinaryArithInstruction
|
||||
return mod;
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
double getIdentity() {
|
||||
MOZ_ASSUME_UNREACHABLE("not used");
|
||||
@ -4959,7 +4947,7 @@ class MLoadArrowThis
|
||||
}
|
||||
};
|
||||
|
||||
class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
|
||||
class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
|
||||
{
|
||||
js::Vector<MUse, 2, IonAllocPolicy> inputs_;
|
||||
|
||||
@ -5056,7 +5044,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
|
||||
// Prefer reserveLength() and addInput() instead, where possible.
|
||||
bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const;
|
||||
|
||||
@ -5072,17 +5060,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
|
||||
}
|
||||
void computeRange(TempAllocator &alloc);
|
||||
|
||||
MDefinition *operandIfRedundant() {
|
||||
// If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
|
||||
// returns the operand that it will always be equal to (a, in
|
||||
// those two cases).
|
||||
MDefinition *first = getOperand(0);
|
||||
for (size_t i = 1, e = numOperands(); i < e; i++) {
|
||||
if (getOperand(i) != first && getOperand(i) != this)
|
||||
return nullptr;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
MDefinition *operandIfRedundant();
|
||||
|
||||
bool canProduceFloat32() const {
|
||||
return canProduceFloat32_;
|
||||
@ -6210,7 +6188,7 @@ class MNot
|
||||
INSTRUCTION_HEADER(Not);
|
||||
|
||||
void cacheOperandMightEmulateUndefined();
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
void markOperandCantEmulateUndefined() {
|
||||
operandMightEmulateUndefined_ = false;
|
||||
@ -7153,7 +7131,7 @@ class MClampToUint8
|
||||
return new(alloc) MClampToUint8(input);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
@ -8900,7 +8878,7 @@ class MStringLength
|
||||
return new(alloc) MStringLength(string);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
|
@ -118,6 +118,15 @@ MIRGraph::removeBlock(MBasicBlock *block)
|
||||
numBlocks_--;
|
||||
}
|
||||
|
||||
void
|
||||
MIRGraph::removeBlockIncludingPhis(MBasicBlock *block)
|
||||
{
|
||||
// removeBlock doesn't clear phis because of IonBuilder constraints. Here,
|
||||
// we want to totally clear everything.
|
||||
removeBlock(block);
|
||||
block->discardAllPhis();
|
||||
}
|
||||
|
||||
void
|
||||
MIRGraph::unmarkBlocks()
|
||||
{
|
||||
@ -930,6 +939,20 @@ MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock *child)
|
||||
return immediatelyDominated_.append(child);
|
||||
}
|
||||
|
||||
void
|
||||
MBasicBlock::removeImmediatelyDominatedBlock(MBasicBlock *child)
|
||||
{
|
||||
for (size_t i = 0; ; ++i) {
|
||||
MOZ_ASSERT(i < immediatelyDominated_.length(),
|
||||
"Dominated block to remove not present");
|
||||
if (immediatelyDominated_[i] == child) {
|
||||
immediatelyDominated_[i] = immediatelyDominated_.back();
|
||||
immediatelyDominated_.popBack();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ class MDefinitionIterator;
|
||||
|
||||
typedef InlineListIterator<MInstruction> MInstructionIterator;
|
||||
typedef InlineListReverseIterator<MInstruction> MInstructionReverseIterator;
|
||||
typedef InlineForwardListIterator<MPhi> MPhiIterator;
|
||||
typedef InlineListIterator<MPhi> MPhiIterator;
|
||||
typedef InlineForwardListIterator<MResumePoint> MResumePointIterator;
|
||||
|
||||
class LBlock;
|
||||
@ -189,9 +189,8 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
void replacePredecessor(MBasicBlock *old, MBasicBlock *split);
|
||||
void replaceSuccessor(size_t pos, MBasicBlock *split);
|
||||
|
||||
// Removes `pred` from the predecessor list. `pred` should not be
|
||||
// the final predecessor. If this block defines phis, removes the
|
||||
// entry for `pred` and updates the indices of later entries.
|
||||
// Removes `pred` from the predecessor list. If this block defines phis,
|
||||
// removes the entry for `pred` and updates the indices of later entries.
|
||||
// This may introduce redundant phis if the new block has fewer
|
||||
// than two predecessors.
|
||||
void removePredecessor(MBasicBlock *pred);
|
||||
@ -292,6 +291,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
MPhiIterator phisBegin() const {
|
||||
return phis_.begin();
|
||||
}
|
||||
MPhiIterator phisBegin(MPhi *at) const {
|
||||
return phis_.begin(at);
|
||||
}
|
||||
MPhiIterator phisEnd() const {
|
||||
return phis_.end();
|
||||
}
|
||||
@ -420,8 +422,12 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
numDominated_ += n;
|
||||
}
|
||||
|
||||
// Add |child| to this block's immediately-dominated set.
|
||||
bool addImmediatelyDominatedBlock(MBasicBlock *child);
|
||||
|
||||
// Remove |child| from this block's immediately-dominated set.
|
||||
void removeImmediatelyDominatedBlock(MBasicBlock *child);
|
||||
|
||||
// This function retrieves the internal instruction associated with a
|
||||
// slot, and should not be used for normal stack operations. It is an
|
||||
// internal helper that is also used to enhance spew.
|
||||
@ -506,7 +512,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
CompileInfo &info_; // Each block originates from a particular script.
|
||||
InlineList<MInstruction> instructions_;
|
||||
Vector<MBasicBlock *, 1, IonAllocPolicy> predecessors_;
|
||||
InlineForwardList<MPhi> phis_;
|
||||
InlineList<MPhi> phis_;
|
||||
InlineForwardList<MResumePoint> resumePoints_;
|
||||
FixedList<MDefinition *> slots_;
|
||||
uint32_t stackPosition_;
|
||||
@ -565,7 +571,7 @@ class MIRGraph
|
||||
: alloc_(alloc),
|
||||
returnAccumulator_(nullptr),
|
||||
blockIdGen_(0),
|
||||
idGen_(1),
|
||||
idGen_(0),
|
||||
osrBlock_(nullptr),
|
||||
osrStart_(nullptr),
|
||||
numBlocks_(0),
|
||||
@ -627,6 +633,7 @@ class MIRGraph
|
||||
}
|
||||
void removeBlocksAfter(MBasicBlock *block);
|
||||
void removeBlock(MBasicBlock *block);
|
||||
void removeBlockIncludingPhis(MBasicBlock *block);
|
||||
void moveBlockToEnd(MBasicBlock *block) {
|
||||
JS_ASSERT(block->id());
|
||||
blocks_.remove(block);
|
||||
|
@ -83,8 +83,10 @@ UnreachableCodeElimination::removeUnmarkedBlocksAndCleanup()
|
||||
// Pass 5: It's important for optimizations to re-run GVN (and in
|
||||
// turn alias analysis) after UCE if we eliminated branches.
|
||||
if (rerunAliasAnalysis_ && mir_->optimizationInfo().gvnEnabled()) {
|
||||
ValueNumberer gvn(mir_, graph_, mir_->optimizationInfo().gvnKind() == GVN_Optimistic);
|
||||
if (!gvn.clear() || !gvn.analyze())
|
||||
ValueNumberer gvn(mir_, graph_);
|
||||
if (!gvn.run(rerunAliasAnalysis_
|
||||
? ValueNumberer::UpdateAliasAnalysis
|
||||
: ValueNumberer::DontUpdateAliasAnalysis))
|
||||
return false;
|
||||
IonSpewPass("GVN-after-UCE");
|
||||
AssertExtendedGraphCoherency(graph_);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,131 +7,101 @@
|
||||
#ifndef jit_ValueNumbering_h
|
||||
#define jit_ValueNumbering_h
|
||||
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/IonAllocPolicy.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class MDefinition;
|
||||
class MBasicBlock;
|
||||
class MIRGraph;
|
||||
class MPhi;
|
||||
class MInstruction;
|
||||
class MIRGenerator;
|
||||
|
||||
class ValueNumberer
|
||||
{
|
||||
protected:
|
||||
struct ValueHasher
|
||||
// Value numbering data.
|
||||
class VisibleValues
|
||||
{
|
||||
typedef MDefinition * Lookup;
|
||||
typedef MDefinition * Key;
|
||||
static HashNumber hash(const Lookup &ins) {
|
||||
return ins->valueHash();
|
||||
}
|
||||
// Hash policy for ValueSet.
|
||||
struct ValueHasher
|
||||
{
|
||||
typedef const MDefinition *Lookup;
|
||||
typedef MDefinition *Key;
|
||||
static HashNumber hash(Lookup ins);
|
||||
static bool match(Key k, Lookup l);
|
||||
static void rekey(Key &k, Key newKey);
|
||||
};
|
||||
|
||||
static bool match(const Key &k, const Lookup &l) {
|
||||
// If one of the instructions depends on a store, and the
|
||||
// other instruction does not depend on the same store,
|
||||
// the instructions are not congruent.
|
||||
if (k->dependency() != l->dependency())
|
||||
return false;
|
||||
return k->congruentTo(l);
|
||||
}
|
||||
typedef HashSet<MDefinition *, ValueHasher, IonAllocPolicy> ValueSet;
|
||||
|
||||
ValueSet set_; // Set of visible values
|
||||
|
||||
public:
|
||||
explicit VisibleValues(TempAllocator &alloc);
|
||||
bool init();
|
||||
|
||||
typedef ValueSet::Ptr Ptr;
|
||||
typedef ValueSet::AddPtr AddPtr;
|
||||
|
||||
Ptr findLeader(const MDefinition *def) const;
|
||||
AddPtr findLeaderForAdd(MDefinition *def);
|
||||
bool insert(AddPtr p, MDefinition *def);
|
||||
void overwrite(AddPtr p, MDefinition *def);
|
||||
void forget(const MDefinition *def);
|
||||
void clear();
|
||||
};
|
||||
|
||||
typedef HashMap<MDefinition *,
|
||||
uint32_t,
|
||||
ValueHasher,
|
||||
IonAllocPolicy> ValueMap;
|
||||
typedef Vector<MBasicBlock *, 4, IonAllocPolicy> BlockWorklist;
|
||||
typedef Vector<MDefinition *, 4, IonAllocPolicy> DefWorklist;
|
||||
|
||||
struct DominatingValue
|
||||
{
|
||||
MDefinition *def;
|
||||
uint32_t validEnd;
|
||||
};
|
||||
|
||||
typedef HashMap<uint32_t,
|
||||
DominatingValue,
|
||||
DefaultHasher<uint32_t>,
|
||||
IonAllocPolicy> InstructionMap;
|
||||
|
||||
protected:
|
||||
TempAllocator &alloc() const;
|
||||
uint32_t lookupValue(MDefinition *ins);
|
||||
MDefinition *findDominatingDef(InstructionMap &defs, MDefinition *ins, size_t index);
|
||||
|
||||
MDefinition *simplify(MDefinition *def, bool useValueNumbers);
|
||||
MControlInstruction *simplifyControlInstruction(MControlInstruction *def);
|
||||
bool eliminateRedundancies();
|
||||
|
||||
bool computeValueNumbers();
|
||||
|
||||
inline bool isMarked(MDefinition *def) {
|
||||
return pessimisticPass_ || def->isInWorklist();
|
||||
}
|
||||
|
||||
void markDefinition(MDefinition *def);
|
||||
void unmarkDefinition(MDefinition *def);
|
||||
|
||||
void markConsumers(MDefinition *def);
|
||||
void markBlock(MBasicBlock *block);
|
||||
void setClass(MDefinition *toSet, MDefinition *representative);
|
||||
|
||||
public:
|
||||
static MDefinition *findSplit(MDefinition *);
|
||||
void breakClass(MDefinition*);
|
||||
|
||||
protected:
|
||||
MIRGenerator *mir;
|
||||
MIRGenerator *const mir_;
|
||||
MIRGraph &graph_;
|
||||
ValueMap values;
|
||||
bool pessimisticPass_;
|
||||
size_t count_;
|
||||
VisibleValues values_; // Numbered values
|
||||
DefWorklist deadDefs_; // Worklist for deleting values
|
||||
BlockWorklist unreachableBlocks_; // Worklist for unreachable blocks
|
||||
BlockWorklist remainingBlocks_; // Blocks remaining with fewer preds
|
||||
size_t numBlocksDeleted_; // Num deleted blocks in current tree
|
||||
bool rerun_; // Should we run another GVN iteration?
|
||||
bool blocksRemoved_; // Have any blocks been removed?
|
||||
bool updateAliasAnalysis_; // Do we care about AliasAnalysis?
|
||||
bool dependenciesBroken_; // Have we broken AliasAnalysis?
|
||||
|
||||
bool deleteDefsRecursively(MDefinition *def);
|
||||
bool pushDeadPhiOperands(MPhi *phi, const MBasicBlock *phiBlock);
|
||||
bool pushDeadInsOperands(MInstruction *ins);
|
||||
bool processDeadDefs();
|
||||
|
||||
bool removePredecessor(MBasicBlock *block, MBasicBlock *pred);
|
||||
bool removeBlocksRecursively(MBasicBlock *block, const MBasicBlock *root);
|
||||
|
||||
MDefinition *simplified(MDefinition *def) const;
|
||||
MDefinition *leader(MDefinition *def);
|
||||
bool hasLeader(const MPhi *phi, const MBasicBlock *phiBlock) const;
|
||||
bool loopHasOptimizablePhi(MBasicBlock *backedge) const;
|
||||
|
||||
bool visitDefinition(MDefinition *def);
|
||||
bool visitControlInstruction(MBasicBlock *block, const MBasicBlock *root);
|
||||
bool visitBlock(MBasicBlock *block, const MBasicBlock *root);
|
||||
bool visitDominatorTree(MBasicBlock *root, size_t *totalNumVisited);
|
||||
bool visitGraph();
|
||||
|
||||
public:
|
||||
ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic);
|
||||
bool analyze();
|
||||
bool clear();
|
||||
ValueNumberer(MIRGenerator *mir, MIRGraph &graph);
|
||||
|
||||
enum UpdateAliasAnalysisFlag {
|
||||
DontUpdateAliasAnalysis,
|
||||
UpdateAliasAnalysis,
|
||||
};
|
||||
|
||||
// Optimize the graph, performing expression simplification and
|
||||
// canonicalization, eliminating statically fully-redundant expressions,
|
||||
// deleting dead instructions, and removing unreachable blocks.
|
||||
bool run(UpdateAliasAnalysisFlag updateAliasAnalysis);
|
||||
};
|
||||
|
||||
class ValueNumberData : public TempObject {
|
||||
|
||||
friend void ValueNumberer::breakClass(MDefinition*);
|
||||
friend MDefinition *ValueNumberer::findSplit(MDefinition*);
|
||||
uint32_t number;
|
||||
MDefinition *classNext;
|
||||
MDefinition *classPrev;
|
||||
|
||||
public:
|
||||
ValueNumberData() : number(0), classNext(nullptr), classPrev(nullptr) {}
|
||||
|
||||
void setValueNumber(uint32_t number_) {
|
||||
number = number_;
|
||||
}
|
||||
|
||||
uint32_t valueNumber() {
|
||||
return number;
|
||||
}
|
||||
// Set the class of this to the given representative value.
|
||||
void setClass(MDefinition *thisDef, MDefinition *rep) {
|
||||
JS_ASSERT(thisDef->valueNumberData() == this);
|
||||
// If we are attempting to insert ourself, then nothing needs to be done.
|
||||
// However, if the definition to be inserted already has the correct value number,
|
||||
// it still needs to be inserted, since the value number needs to be updated lazily.
|
||||
// this updating tactic can leave the world in a state where thisDef is not in the
|
||||
// equivalence class of rep, but it has the same value number. Defs in this state
|
||||
// need to be re-processed.
|
||||
if (this == rep->valueNumberData())
|
||||
return;
|
||||
|
||||
if (classNext)
|
||||
classNext->valueNumberData()->classPrev = classPrev;
|
||||
if (classPrev)
|
||||
classPrev->valueNumberData()->classNext = classNext;
|
||||
|
||||
|
||||
classPrev = rep;
|
||||
classNext = rep->valueNumberData()->classNext;
|
||||
|
||||
if (rep->valueNumberData()->classNext)
|
||||
rep->valueNumberData()->classNext->valueNumberData()->classPrev = thisDef;
|
||||
rep->valueNumberData()->classNext = thisDef;
|
||||
}
|
||||
};
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
@ -5980,13 +5980,12 @@ SetRuntimeOptions(JSRuntime *rt, const OptionParser &op)
|
||||
if (const char *str = op.getStringOption("ion-gvn")) {
|
||||
if (strcmp(str, "off") == 0) {
|
||||
jit::js_JitOptions.disableGvn = true;
|
||||
} else if (strcmp(str, "pessimistic") == 0) {
|
||||
jit::js_JitOptions.forceGvnKind = true;
|
||||
jit::js_JitOptions.forcedGvnKind = jit::GVN_Pessimistic;
|
||||
} else if (strcmp(str, "optimistic") == 0) {
|
||||
jit::js_JitOptions.forceGvnKind = true;
|
||||
jit::js_JitOptions.forcedGvnKind = jit::GVN_Optimistic;
|
||||
} else {
|
||||
} else if (strcmp(str, "on") != 0 &&
|
||||
strcmp(str, "optimistic") != 0 &&
|
||||
strcmp(str, "pessimistic") != 0)
|
||||
{
|
||||
// We accept "pessimistic" and "optimistic" as synonyms for "on"
|
||||
// for backwards compatibility.
|
||||
return OptionFailure("ion-gvn", str);
|
||||
}
|
||||
}
|
||||
@ -6269,8 +6268,7 @@ main(int argc, char **argv, char **envp)
|
||||
|| !op.addStringOption('\0', "ion-gvn", "[mode]",
|
||||
"Specify Ion global value numbering:\n"
|
||||
" off: disable GVN\n"
|
||||
" pessimistic: use pessimistic GVN\n"
|
||||
" optimistic: (default) use optimistic GVN")
|
||||
" on: enable GVN (default)\n")
|
||||
|| !op.addStringOption('\0', "ion-licm", "on/off",
|
||||
"Loop invariant code motion (default: on, off to disable)")
|
||||
|| !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
|
||||
|
Loading…
Reference in New Issue
Block a user