[turbofan] Replace information about uses by explicit truncation in representation selection.
This change replaces the bitwise masking of uses by storing the most general truncation for all uses. Review URL: https://codereview.chromium.org/1464763003 Cr-Commit-Position: refs/heads/master@{#32248}
This commit is contained in:
parent
47e1ab78d7
commit
9564ffe9c1
@ -16,10 +16,137 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
|
class Truncation final {
|
||||||
|
public:
|
||||||
|
// Constructors.
|
||||||
|
static Truncation None() { return Truncation(TruncationKind::kNone); }
|
||||||
|
static Truncation Bool() { return Truncation(TruncationKind::kBool); }
|
||||||
|
static Truncation Word32() { return Truncation(TruncationKind::kWord32); }
|
||||||
|
static Truncation Word64() { return Truncation(TruncationKind::kWord64); }
|
||||||
|
static Truncation Float32() { return Truncation(TruncationKind::kFloat32); }
|
||||||
|
static Truncation Float64() { return Truncation(TruncationKind::kFloat64); }
|
||||||
|
static Truncation Any() { return Truncation(TruncationKind::kAny); }
|
||||||
|
|
||||||
|
static Truncation Generalize(Truncation t1, Truncation t2) {
|
||||||
|
return Truncation(Generalize(t1.kind(), t2.kind()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queries.
|
||||||
|
bool TruncatesToWord32() const {
|
||||||
|
return LessGeneral(kind_, TruncationKind::kWord32);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TruncatesNaNToZero() {
|
||||||
|
return LessGeneral(kind_, TruncationKind::kWord32) ||
|
||||||
|
LessGeneral(kind_, TruncationKind::kBool);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TruncatesUndefinedToZeroOrNaN() {
|
||||||
|
return LessGeneral(kind_, TruncationKind::kFloat64) ||
|
||||||
|
LessGeneral(kind_, TruncationKind::kWord64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operators.
|
||||||
|
bool operator==(Truncation other) const { return kind() == other.kind(); }
|
||||||
|
bool operator!=(Truncation other) const { return !(*this == other); }
|
||||||
|
|
||||||
|
// Debug utilities.
|
||||||
|
const char* description() {
|
||||||
|
switch (kind()) {
|
||||||
|
case TruncationKind::kNone:
|
||||||
|
return "no-value-use";
|
||||||
|
case TruncationKind::kBool:
|
||||||
|
return "truncate-to-bool";
|
||||||
|
case TruncationKind::kWord32:
|
||||||
|
return "truncate-to-word32";
|
||||||
|
case TruncationKind::kWord64:
|
||||||
|
return "truncate-to-word64";
|
||||||
|
case TruncationKind::kFloat32:
|
||||||
|
return "truncate-to-float32";
|
||||||
|
case TruncationKind::kFloat64:
|
||||||
|
return "truncate-to-float64";
|
||||||
|
case TruncationKind::kAny:
|
||||||
|
return "no-truncation";
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class TruncationKind : uint8_t {
|
||||||
|
kNone,
|
||||||
|
kBool,
|
||||||
|
kWord32,
|
||||||
|
kWord64,
|
||||||
|
kFloat32,
|
||||||
|
kFloat64,
|
||||||
|
kAny
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Truncation(TruncationKind kind) : kind_(kind) {}
|
||||||
|
TruncationKind kind() const { return kind_; }
|
||||||
|
|
||||||
|
TruncationKind kind_;
|
||||||
|
|
||||||
|
// Partial order for truncations:
|
||||||
|
//
|
||||||
|
// kWord64 kAny
|
||||||
|
// ^ ^
|
||||||
|
// \ |
|
||||||
|
// \ kFloat64 <--+
|
||||||
|
// \ ^ ^ |
|
||||||
|
// \ / | |
|
||||||
|
// kWord32 kFloat32 kBool
|
||||||
|
// ^ ^ ^
|
||||||
|
// \ | /
|
||||||
|
// \ | /
|
||||||
|
// \ | /
|
||||||
|
// \ | /
|
||||||
|
// \ | /
|
||||||
|
// kNone
|
||||||
|
static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2) {
|
||||||
|
if (LessGeneral(rep1, rep2)) return rep2;
|
||||||
|
if (LessGeneral(rep2, rep1)) return rep1;
|
||||||
|
// Handle the generalization of float64-representable values.
|
||||||
|
if (LessGeneral(rep1, TruncationKind::kFloat64) &&
|
||||||
|
LessGeneral(rep2, TruncationKind::kFloat64)) {
|
||||||
|
return TruncationKind::kFloat64;
|
||||||
|
}
|
||||||
|
// All other combinations are illegal.
|
||||||
|
FATAL("Tried to combine incompatible representations");
|
||||||
|
return TruncationKind::kNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LessGeneral(TruncationKind rep1, TruncationKind rep2) {
|
||||||
|
switch (rep1) {
|
||||||
|
case TruncationKind::kNone:
|
||||||
|
return true;
|
||||||
|
case TruncationKind::kBool:
|
||||||
|
return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny;
|
||||||
|
case TruncationKind::kWord32:
|
||||||
|
return rep2 == TruncationKind::kWord32 ||
|
||||||
|
rep2 == TruncationKind::kWord64 ||
|
||||||
|
rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
|
||||||
|
case TruncationKind::kWord64:
|
||||||
|
return rep2 == TruncationKind::kWord64;
|
||||||
|
case TruncationKind::kFloat32:
|
||||||
|
return rep2 == TruncationKind::kFloat32 ||
|
||||||
|
rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
|
||||||
|
case TruncationKind::kFloat64:
|
||||||
|
return rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
|
||||||
|
case TruncationKind::kAny:
|
||||||
|
return rep2 == TruncationKind::kAny;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Contains logic related to changing the representation of values for constants
|
// Contains logic related to changing the representation of values for constants
|
||||||
// and other nodes, as well as lowering Simplified->Machine operators.
|
// and other nodes, as well as lowering Simplified->Machine operators.
|
||||||
// Eagerly folds any representation changes for constants.
|
// Eagerly folds any representation changes for constants.
|
||||||
class RepresentationChanger {
|
class RepresentationChanger final {
|
||||||
public:
|
public:
|
||||||
RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
|
RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
|
||||||
: jsgraph_(jsgraph),
|
: jsgraph_(jsgraph),
|
||||||
@ -32,34 +159,40 @@ class RepresentationChanger {
|
|||||||
return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0;
|
return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changes representation from {output_type} to {use_rep}. The {truncation}
|
||||||
|
// parameter is only used for sanity checking - if the changer cannot figure
|
||||||
|
// out signedness for the word32->float64 conversion, then we check that the
|
||||||
|
// uses truncate to word32 (so they do not care about signedness).
|
||||||
Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
|
Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
|
||||||
MachineTypeUnion use_type) {
|
MachineTypeUnion use_rep,
|
||||||
|
Truncation truncation = Truncation::None()) {
|
||||||
|
DCHECK((use_rep & kRepMask) == use_rep);
|
||||||
if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
|
if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
|
||||||
// There should be only one output representation.
|
// There should be only one output representation.
|
||||||
return TypeError(node, output_type, use_type);
|
return TypeError(node, output_type, use_rep);
|
||||||
}
|
}
|
||||||
if ((use_type & kRepMask) == (output_type & kRepMask)) {
|
if (use_rep == (output_type & kRepMask)) {
|
||||||
// Representations are the same. That's a no-op.
|
// Representations are the same. That's a no-op.
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (IsWord(use_type) && IsWord(output_type)) {
|
if (IsWord(use_rep) && IsWord(output_type)) {
|
||||||
// Both are words less than or equal to 32-bits.
|
// Both are words less than or equal to 32-bits.
|
||||||
// Since loads of integers from memory implicitly sign or zero extend the
|
// Since loads of integers from memory implicitly sign or zero extend the
|
||||||
// value to the full machine word size and stores implicitly truncate,
|
// value to the full machine word size and stores implicitly truncate,
|
||||||
// no representation change is necessary.
|
// no representation change is necessary.
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (use_type & kRepTagged) {
|
if (use_rep & kRepTagged) {
|
||||||
return GetTaggedRepresentationFor(node, output_type);
|
return GetTaggedRepresentationFor(node, output_type);
|
||||||
} else if (use_type & kRepFloat32) {
|
} else if (use_rep & kRepFloat32) {
|
||||||
return GetFloat32RepresentationFor(node, output_type, use_type);
|
return GetFloat32RepresentationFor(node, output_type, truncation);
|
||||||
} else if (use_type & kRepFloat64) {
|
} else if (use_rep & kRepFloat64) {
|
||||||
return GetFloat64RepresentationFor(node, output_type, use_type);
|
return GetFloat64RepresentationFor(node, output_type, truncation);
|
||||||
} else if (use_type & kRepBit) {
|
} else if (use_rep & kRepBit) {
|
||||||
return GetBitRepresentationFor(node, output_type);
|
return GetBitRepresentationFor(node, output_type);
|
||||||
} else if (IsWord(use_type)) {
|
} else if (IsWord(use_rep)) {
|
||||||
return GetWord32RepresentationFor(node, output_type);
|
return GetWord32RepresentationFor(node, output_type);
|
||||||
} else if (use_type & kRepWord64) {
|
} else if (use_rep & kRepWord64) {
|
||||||
return GetWord64RepresentationFor(node, output_type);
|
return GetWord64RepresentationFor(node, output_type);
|
||||||
} else {
|
} else {
|
||||||
return node;
|
return node;
|
||||||
@ -116,7 +249,7 @@ class RepresentationChanger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type,
|
Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type,
|
||||||
MachineTypeUnion truncation) {
|
Truncation truncation) {
|
||||||
// Eagerly fold representation changes for constants.
|
// Eagerly fold representation changes for constants.
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
case IrOpcode::kFloat64Constant:
|
case IrOpcode::kFloat64Constant:
|
||||||
@ -146,8 +279,7 @@ class RepresentationChanger {
|
|||||||
} else {
|
} else {
|
||||||
// Either the output is int32 or the uses only care about the
|
// Either the output is int32 or the uses only care about the
|
||||||
// low 32 bits (so we can pick int32 safely).
|
// low 32 bits (so we can pick int32 safely).
|
||||||
DCHECK(output_type & kTypeInt32 ||
|
DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32());
|
||||||
!(truncation & ~(kTypeInt32 | kTypeUint32 | kRepMask)));
|
|
||||||
op = machine()->ChangeInt32ToFloat64();
|
op = machine()->ChangeInt32ToFloat64();
|
||||||
}
|
}
|
||||||
// int32 -> float64 -> float32
|
// int32 -> float64 -> float32
|
||||||
@ -167,7 +299,7 @@ class RepresentationChanger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type,
|
Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type,
|
||||||
MachineTypeUnion use_type) {
|
Truncation truncation) {
|
||||||
// Eagerly fold representation changes for constants.
|
// Eagerly fold representation changes for constants.
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
case IrOpcode::kNumberConstant:
|
case IrOpcode::kNumberConstant:
|
||||||
@ -197,8 +329,7 @@ class RepresentationChanger {
|
|||||||
} else {
|
} else {
|
||||||
// Either the output is int32 or the uses only care about the
|
// Either the output is int32 or the uses only care about the
|
||||||
// low 32 bits (so we can pick int32 safely).
|
// low 32 bits (so we can pick int32 safely).
|
||||||
DCHECK(output_type & kTypeInt32 ||
|
DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32());
|
||||||
!(use_type & ~(kTypeInt32 | kTypeUint32 | kRepMask)));
|
|
||||||
op = machine()->ChangeInt32ToFloat64();
|
op = machine()->ChangeInt32ToFloat64();
|
||||||
}
|
}
|
||||||
} else if (output_type & kRepTagged) {
|
} else if (output_type & kRepTagged) {
|
||||||
|
@ -72,67 +72,57 @@ namespace {
|
|||||||
// need the signedness information to produce the correct value.
|
// need the signedness information to produce the correct value.
|
||||||
class UseInfo {
|
class UseInfo {
|
||||||
public:
|
public:
|
||||||
// Constructors
|
UseInfo(MachineType preferred, Truncation truncation)
|
||||||
// ================================================================
|
: preferred_(preferred), truncation_(truncation) {
|
||||||
|
DCHECK(preferred == (preferred & kRepMask));
|
||||||
// Uses truncating to the preferred representation.
|
}
|
||||||
static UseInfo TruncatingWord32() {
|
static UseInfo TruncatingWord32() {
|
||||||
return UseInfo(kTypeInt32 | kTypeUint32 | kRepWord32);
|
return UseInfo(kRepWord32, Truncation::Word32());
|
||||||
}
|
}
|
||||||
static UseInfo TruncatingWord64() {
|
static UseInfo TruncatingWord64() {
|
||||||
return UseInfo(kTypeInt64 | kTypeUint64 | kRepWord64);
|
return UseInfo(kRepWord64, Truncation::Word64());
|
||||||
|
}
|
||||||
|
static UseInfo Bool() { return UseInfo(kRepBit, Truncation::Bool()); }
|
||||||
|
static UseInfo Float32() {
|
||||||
|
return UseInfo(kRepFloat32, Truncation::Float32());
|
||||||
|
}
|
||||||
|
static UseInfo Float64() {
|
||||||
|
return UseInfo(kRepFloat64, Truncation::Float64());
|
||||||
}
|
}
|
||||||
static UseInfo Bool() { return UseInfo(kMachBool); }
|
|
||||||
static UseInfo Float32() { return UseInfo(kMachFloat32); }
|
|
||||||
static UseInfo Float64() { return UseInfo(kMachFloat64); }
|
|
||||||
static UseInfo PointerInt() {
|
static UseInfo PointerInt() {
|
||||||
return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
|
return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
|
||||||
}
|
}
|
||||||
|
static UseInfo AnyTagged() { return UseInfo(kRepTagged, Truncation::Any()); }
|
||||||
|
|
||||||
// Non-truncating uses.
|
// Undetermined representation.
|
||||||
static UseInfo AnyTagged() { return UseInfo(kMachAnyTagged); }
|
static UseInfo Any() { return UseInfo(kMachNone, Truncation::Any()); }
|
||||||
static UseInfo Any() { return UseInfo(kTypeAny); }
|
static UseInfo None() { return UseInfo(kMachNone, Truncation::None()); }
|
||||||
|
|
||||||
// Ignored-value 'use'.
|
// Truncation to a representation that is smaller than the preferred
|
||||||
static UseInfo None() { return UseInfo(kMachNone); }
|
|
||||||
|
|
||||||
// Truncating to a representation that is smaller than the preferred
|
|
||||||
// one.
|
// one.
|
||||||
static UseInfo Float64TruncatingToWord32() {
|
static UseInfo Float64TruncatingToWord32() {
|
||||||
return UseInfo(kRepFloat64 | kTypeInt32 | kTypeUint32);
|
return UseInfo(kRepFloat64, Truncation::Word32());
|
||||||
}
|
}
|
||||||
static UseInfo Word64TruncatingToWord32() {
|
static UseInfo Word64TruncatingToWord32() {
|
||||||
return UseInfo(kRepWord64 | kTypeInt32 | kTypeUint32);
|
return UseInfo(kRepWord64, Truncation::Word32());
|
||||||
}
|
}
|
||||||
static UseInfo AnyTruncatingToBool() { return UseInfo(kTypeBool); }
|
static UseInfo AnyTruncatingToBool() {
|
||||||
|
return UseInfo(kMachNone, Truncation::Bool());
|
||||||
UseInfo(MachineTypeUnion representation, MachineTypeUnion truncation)
|
|
||||||
: type_(representation | truncation) {
|
|
||||||
DCHECK(base::bits::CountPopulation32(representation & kRepMask) == 1);
|
|
||||||
DCHECK((representation & kTypeMask) == 0);
|
|
||||||
DCHECK((truncation & kRepMask) == 0);
|
|
||||||
// TODO(jarin) Check/normalize truncation?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queries
|
MachineType preferred() const { return preferred_; }
|
||||||
// ================================================================
|
Truncation truncation() const { return truncation_; }
|
||||||
MachineType GetRepresentation() const {
|
|
||||||
return static_cast<MachineType>(type_ & kRepMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should only be used by the Enqueue method.
|
|
||||||
MachineTypeUnion machine_type() const { return type_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit UseInfo(MachineTypeUnion type) : type_(type) {}
|
MachineType preferred_;
|
||||||
|
Truncation truncation_;
|
||||||
MachineTypeUnion type_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
UseInfo UseInfoFromMachineType(MachineType type) {
|
UseInfo UseInfoFromMachineType(MachineType type) {
|
||||||
MachineTypeUnion rep = RepresentationOf(type);
|
MachineTypeUnion rep = RepresentationOf(type);
|
||||||
DCHECK((rep & kTypeMask) == 0);
|
DCHECK((rep & kTypeMask) == 0);
|
||||||
|
|
||||||
if (rep & kRepTagged) return UseInfo::AnyTagged();
|
if (rep & kRepTagged) return UseInfo::AnyTagged();
|
||||||
if (rep & kRepFloat64) {
|
if (rep & kRepFloat64) {
|
||||||
DCHECK((rep & kRepWord64) == 0);
|
DCHECK((rep & kRepWord64) == 0);
|
||||||
@ -169,11 +159,29 @@ UseInfo UseInfoForBasePointer(const ElementAccess& access) {
|
|||||||
class RepresentationSelector {
|
class RepresentationSelector {
|
||||||
public:
|
public:
|
||||||
// Information for each node tracked during the fixpoint.
|
// Information for each node tracked during the fixpoint.
|
||||||
struct NodeInfo {
|
class NodeInfo {
|
||||||
MachineTypeUnion use : 15; // Union of all usages for the node.
|
public:
|
||||||
bool queued : 1; // Bookkeeping for the traversal.
|
// Adds new use to the node. Returns true if something has changed
|
||||||
bool visited : 1; // Bookkeeping for the traversal.
|
// and the node has to be requeued.
|
||||||
MachineTypeUnion output : 15; // Output type of the node.
|
bool AddUse(UseInfo info) {
|
||||||
|
Truncation old_truncation = truncation_;
|
||||||
|
truncation_ = Truncation::Generalize(truncation_, info.truncation());
|
||||||
|
return truncation_ != old_truncation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_queued(bool value) { queued_ = value; }
|
||||||
|
bool queued() const { return queued_; }
|
||||||
|
void set_visited() { visited_ = true; }
|
||||||
|
bool visited() const { return visited_; }
|
||||||
|
Truncation truncation() const { return truncation_; }
|
||||||
|
void set_output_type(MachineTypeUnion type) { output_ = type; }
|
||||||
|
MachineTypeUnion output_type() const { return output_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool queued_ = false; // Bookkeeping for the traversal.
|
||||||
|
bool visited_ = false; // Bookkeeping for the traversal.
|
||||||
|
MachineTypeUnion output_ = kMachNone; // Output type of the node.
|
||||||
|
Truncation truncation_ = Truncation::None(); // Information about uses.
|
||||||
};
|
};
|
||||||
|
|
||||||
RepresentationSelector(JSGraph* jsgraph, Zone* zone,
|
RepresentationSelector(JSGraph* jsgraph, Zone* zone,
|
||||||
@ -181,15 +189,13 @@ class RepresentationSelector {
|
|||||||
SourcePositionTable* source_positions)
|
SourcePositionTable* source_positions)
|
||||||
: jsgraph_(jsgraph),
|
: jsgraph_(jsgraph),
|
||||||
count_(jsgraph->graph()->NodeCount()),
|
count_(jsgraph->graph()->NodeCount()),
|
||||||
info_(zone->NewArray<NodeInfo>(count_)),
|
info_(count_, zone),
|
||||||
nodes_(zone),
|
nodes_(zone),
|
||||||
replacements_(zone),
|
replacements_(zone),
|
||||||
phase_(PROPAGATE),
|
phase_(PROPAGATE),
|
||||||
changer_(changer),
|
changer_(changer),
|
||||||
queue_(zone),
|
queue_(zone),
|
||||||
source_positions_(source_positions) {
|
source_positions_(source_positions) {
|
||||||
memset(info_, 0, sizeof(NodeInfo) * count_);
|
|
||||||
|
|
||||||
safe_int_additive_range_ =
|
safe_int_additive_range_ =
|
||||||
Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone);
|
Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone);
|
||||||
}
|
}
|
||||||
@ -204,11 +210,11 @@ class RepresentationSelector {
|
|||||||
Node* node = queue_.front();
|
Node* node = queue_.front();
|
||||||
NodeInfo* info = GetInfo(node);
|
NodeInfo* info = GetInfo(node);
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
info->queued = false;
|
info->set_queued(false);
|
||||||
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
|
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
|
||||||
VisitNode(node, info->use, NULL);
|
VisitNode(node, info->truncation(), NULL);
|
||||||
TRACE(" ==> output ");
|
TRACE(" ==> output ");
|
||||||
PrintInfo(info->output);
|
PrintInfo(info->output_type());
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,11 +224,12 @@ class RepresentationSelector {
|
|||||||
// Process nodes from the collected {nodes_} vector.
|
// Process nodes from the collected {nodes_} vector.
|
||||||
for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
|
for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
|
||||||
Node* node = *i;
|
Node* node = *i;
|
||||||
|
NodeInfo* info = GetInfo(node);
|
||||||
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
|
TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
|
||||||
// Reuse {VisitNode()} so the representation rules are in one place.
|
// Reuse {VisitNode()} so the representation rules are in one place.
|
||||||
SourcePositionTable::Scope scope(
|
SourcePositionTable::Scope scope(
|
||||||
source_positions_, source_positions_->GetSourcePosition(node));
|
source_positions_, source_positions_->GetSourcePosition(node));
|
||||||
VisitNode(node, GetUseInfo(node), lowering);
|
VisitNode(node, info->truncation(), lowering);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the final replacements.
|
// Perform the final replacements.
|
||||||
@ -242,34 +249,31 @@ class RepresentationSelector {
|
|||||||
// Enqueue {node} if the {use} contains new information for that node.
|
// Enqueue {node} if the {use} contains new information for that node.
|
||||||
// Add {node} to {nodes_} if this is the first time it's been visited.
|
// Add {node} to {nodes_} if this is the first time it's been visited.
|
||||||
void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) {
|
void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) {
|
||||||
MachineTypeUnion use = use_info.machine_type();
|
|
||||||
|
|
||||||
if (phase_ != PROPAGATE) return;
|
if (phase_ != PROPAGATE) return;
|
||||||
NodeInfo* info = GetInfo(node);
|
NodeInfo* info = GetInfo(node);
|
||||||
if (!info->visited) {
|
if (!info->visited()) {
|
||||||
// First visit of this node.
|
// First visit of this node.
|
||||||
info->visited = true;
|
info->set_visited();
|
||||||
info->queued = true;
|
info->set_queued(true);
|
||||||
nodes_.push_back(node);
|
nodes_.push_back(node);
|
||||||
queue_.push(node);
|
queue_.push(node);
|
||||||
TRACE(" initial: ");
|
TRACE(" initial: ");
|
||||||
info->use |= use;
|
info->AddUse(use_info);
|
||||||
PrintUseInfo(node);
|
PrintTruncation(info->truncation());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TRACE(" queue?: ");
|
TRACE(" queue?: ");
|
||||||
PrintUseInfo(node);
|
PrintTruncation(info->truncation());
|
||||||
if ((info->use & use) != use) {
|
if (info->AddUse(use_info)) {
|
||||||
// New usage information for the node is available.
|
// New usage information for the node is available.
|
||||||
if (!info->queued) {
|
if (!info->queued()) {
|
||||||
queue_.push(node);
|
queue_.push(node);
|
||||||
info->queued = true;
|
info->set_queued(true);
|
||||||
TRACE(" added: ");
|
TRACE(" added: ");
|
||||||
} else {
|
} else {
|
||||||
TRACE(" inqueue: ");
|
TRACE(" inqueue: ");
|
||||||
}
|
}
|
||||||
info->use |= use;
|
PrintTruncation(info->truncation());
|
||||||
PrintUseInfo(node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +285,7 @@ class RepresentationSelector {
|
|||||||
// instruction.
|
// instruction.
|
||||||
DCHECK((output & kRepMask) == 0 ||
|
DCHECK((output & kRepMask) == 0 ||
|
||||||
base::bits::IsPowerOfTwo32(output & kRepMask));
|
base::bits::IsPowerOfTwo32(output & kRepMask));
|
||||||
GetInfo(node)->output = output;
|
GetInfo(node)->set_output_type(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BothInputsAre(Node* node, Type* type) {
|
bool BothInputsAre(Node* node, Type* type) {
|
||||||
@ -297,7 +301,7 @@ class RepresentationSelector {
|
|||||||
Enqueue(input, UseInfo::TruncatingWord32());
|
Enqueue(input, UseInfo::TruncatingWord32());
|
||||||
} else {
|
} else {
|
||||||
// In the change phase, insert a change before the use if necessary.
|
// In the change phase, insert a change before the use if necessary.
|
||||||
MachineTypeUnion output = GetInfo(input)->output;
|
MachineTypeUnion output = GetInfo(input)->output_type();
|
||||||
if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
|
if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
|
||||||
// Output representation doesn't match usage.
|
// Output representation doesn't match usage.
|
||||||
TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
|
TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
|
||||||
@ -319,10 +323,10 @@ class RepresentationSelector {
|
|||||||
void ConvertInput(Node* node, int index, UseInfo use) {
|
void ConvertInput(Node* node, int index, UseInfo use) {
|
||||||
Node* input = node->InputAt(index);
|
Node* input = node->InputAt(index);
|
||||||
// In the change phase, insert a change before the use if necessary.
|
// In the change phase, insert a change before the use if necessary.
|
||||||
if (use.GetRepresentation() == kMachNone)
|
if (use.preferred() == kMachNone)
|
||||||
return; // No input requirement on the use.
|
return; // No input requirement on the use.
|
||||||
MachineTypeUnion output = GetInfo(input)->output;
|
MachineTypeUnion output = GetInfo(input)->output_type();
|
||||||
if ((output & kRepMask) != use.GetRepresentation()) {
|
if ((output & kRepMask) != use.preferred()) {
|
||||||
// Output representation doesn't match usage.
|
// Output representation doesn't match usage.
|
||||||
TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
|
TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
|
||||||
index, input->id(), input->op()->mnemonic());
|
index, input->id(), input->op()->mnemonic());
|
||||||
@ -331,8 +335,8 @@ class RepresentationSelector {
|
|||||||
TRACE(" to ");
|
TRACE(" to ");
|
||||||
PrintUseInfo(use);
|
PrintUseInfo(use);
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
Node* n =
|
Node* n = changer_->GetRepresentationFor(input, output, use.preferred(),
|
||||||
changer_->GetRepresentationFor(input, output, use.machine_type());
|
use.truncation());
|
||||||
node->ReplaceInput(index, n);
|
node->ReplaceInput(index, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -440,13 +444,13 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Infer representation for phi-like nodes.
|
// Infer representation for phi-like nodes.
|
||||||
static MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
|
static MachineType GetRepresentationForPhi(Node* node, Truncation use) {
|
||||||
// Phis adapt to the output representation their uses demand.
|
// Phis adapt to the output representation their uses demand.
|
||||||
Type* upper = NodeProperties::GetType(node);
|
Type* upper = NodeProperties::GetType(node);
|
||||||
if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
|
if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
|
||||||
// We are within 32 bits range => pick kRepWord32.
|
// We are within 32 bits range => pick kRepWord32.
|
||||||
return kRepWord32;
|
return kRepWord32;
|
||||||
} else if (!CanObserveNonWord32(use)) {
|
} else if (use.TruncatesToWord32()) {
|
||||||
// We only use 32 bits.
|
// We only use 32 bits.
|
||||||
return kRepWord32;
|
return kRepWord32;
|
||||||
} else if (upper->Is(Type::Boolean())) {
|
} else if (upper->Is(Type::Boolean())) {
|
||||||
@ -462,10 +466,10 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for handling selects.
|
// Helper for handling selects.
|
||||||
void VisitSelect(Node* node, MachineTypeUnion use,
|
void VisitSelect(Node* node, Truncation truncation,
|
||||||
SimplifiedLowering* lowering) {
|
SimplifiedLowering* lowering) {
|
||||||
ProcessInput(node, 0, UseInfo::Bool());
|
ProcessInput(node, 0, UseInfo::Bool());
|
||||||
MachineType output = GetRepresentationForPhi(node, use);
|
MachineType output = GetRepresentationForPhi(node, truncation);
|
||||||
|
|
||||||
Type* upper = NodeProperties::GetType(node);
|
Type* upper = NodeProperties::GetType(node);
|
||||||
MachineType output_type =
|
MachineType output_type =
|
||||||
@ -482,16 +486,16 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Convert inputs to the output representation of this phi, pass the
|
// Convert inputs to the output representation of this phi, pass the
|
||||||
// use truncation along.
|
// truncation truncation along.
|
||||||
UseInfo input_use(output, use & kTypeMask);
|
UseInfo input_use(output, truncation);
|
||||||
ProcessInput(node, 1, input_use);
|
ProcessInput(node, 1, input_use);
|
||||||
ProcessInput(node, 2, input_use);
|
ProcessInput(node, 2, input_use);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for handling phis.
|
// Helper for handling phis.
|
||||||
void VisitPhi(Node* node, MachineTypeUnion use,
|
void VisitPhi(Node* node, Truncation truncation,
|
||||||
SimplifiedLowering* lowering) {
|
SimplifiedLowering* lowering) {
|
||||||
MachineType output = GetRepresentationForPhi(node, use);
|
MachineType output = GetRepresentationForPhi(node, truncation);
|
||||||
|
|
||||||
Type* upper = NodeProperties::GetType(node);
|
Type* upper = NodeProperties::GetType(node);
|
||||||
MachineType output_type =
|
MachineType output_type =
|
||||||
@ -509,8 +513,8 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert inputs to the output representation of this phi, pass the
|
// Convert inputs to the output representation of this phi, pass the
|
||||||
// use truncation along.
|
// truncation truncation along.
|
||||||
UseInfo input_use(output, use & kTypeMask);
|
UseInfo input_use(output, truncation);
|
||||||
for (int i = 0; i < node->InputCount(); i++) {
|
for (int i = 0; i < node->InputCount(); i++) {
|
||||||
ProcessInput(node, i, i < values ? input_use : UseInfo::None());
|
ProcessInput(node, i, i < values ? input_use : UseInfo::None());
|
||||||
}
|
}
|
||||||
@ -550,7 +554,7 @@ class RepresentationSelector {
|
|||||||
new (zone->New(sizeof(ZoneVector<MachineType>)))
|
new (zone->New(sizeof(ZoneVector<MachineType>)))
|
||||||
ZoneVector<MachineType>(node->InputCount(), zone);
|
ZoneVector<MachineType>(node->InputCount(), zone);
|
||||||
for (int i = 0; i < node->InputCount(); i++) {
|
for (int i = 0; i < node->InputCount(); i++) {
|
||||||
MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output;
|
MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output_type();
|
||||||
(*types)[i] = static_cast<MachineType>(input_type);
|
(*types)[i] = static_cast<MachineType>(input_type);
|
||||||
}
|
}
|
||||||
NodeProperties::ChangeOp(node,
|
NodeProperties::ChangeOp(node,
|
||||||
@ -571,34 +575,20 @@ class RepresentationSelector {
|
|||||||
return changer_->Float64OperatorFor(node->opcode());
|
return changer_->Float64OperatorFor(node->opcode());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
|
bool CanLowerToInt32Binop(Node* node, Truncation use) {
|
||||||
return BothInputsAre(node, Type::Signed32()) &&
|
return BothInputsAre(node, Type::Signed32()) &&
|
||||||
(!CanObserveNonWord32(use) ||
|
(use.TruncatesToWord32() ||
|
||||||
NodeProperties::GetType(node)->Is(Type::Signed32()));
|
NodeProperties::GetType(node)->Is(Type::Signed32()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanLowerToWord32AdditiveBinop(Node* node, MachineTypeUnion use) {
|
bool CanLowerToWord32AdditiveBinop(Node* node, Truncation use) {
|
||||||
return BothInputsAre(node, safe_int_additive_range_) &&
|
return BothInputsAre(node, safe_int_additive_range_) &&
|
||||||
!CanObserveNonWord32(use);
|
use.TruncatesToWord32();
|
||||||
}
|
|
||||||
|
|
||||||
bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
|
|
||||||
return BothInputsAre(node, Type::Unsigned32()) &&
|
|
||||||
(!CanObserveNonWord32(use) ||
|
|
||||||
NodeProperties::GetType(node)->Is(Type::Unsigned32()));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CanObserveNonWord32(MachineTypeUnion use) {
|
|
||||||
return (use & kTypeMask & ~(kTypeInt32 | kTypeUint32)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CanObserveNaN(MachineTypeUnion use) {
|
|
||||||
return (use & (kTypeNumber | kTypeAny)) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatching routine for visiting the node {node} with the usage {use}.
|
// Dispatching routine for visiting the node {node} with the usage {use}.
|
||||||
// Depending on the operator, propagate new usage info to the inputs.
|
// Depending on the operator, propagate new usage info to the inputs.
|
||||||
void VisitNode(Node* node, MachineTypeUnion use,
|
void VisitNode(Node* node, Truncation truncation,
|
||||||
SimplifiedLowering* lowering) {
|
SimplifiedLowering* lowering) {
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
@ -638,9 +628,9 @@ class RepresentationSelector {
|
|||||||
Enqueue(NodeProperties::GetControlInput(node, 0));
|
Enqueue(NodeProperties::GetControlInput(node, 0));
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kSelect:
|
case IrOpcode::kSelect:
|
||||||
return VisitSelect(node, use, lowering);
|
return VisitSelect(node, truncation, lowering);
|
||||||
case IrOpcode::kPhi:
|
case IrOpcode::kPhi:
|
||||||
return VisitPhi(node, use, lowering);
|
return VisitPhi(node, truncation, lowering);
|
||||||
case IrOpcode::kCall:
|
case IrOpcode::kCall:
|
||||||
return VisitCall(node, lowering);
|
return VisitCall(node, lowering);
|
||||||
|
|
||||||
@ -663,7 +653,7 @@ class RepresentationSelector {
|
|||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
case IrOpcode::kBooleanNot: {
|
case IrOpcode::kBooleanNot: {
|
||||||
if (lower()) {
|
if (lower()) {
|
||||||
MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
|
MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type();
|
||||||
if (input & kRepBit) {
|
if (input & kRepBit) {
|
||||||
// BooleanNot(x: kRepBit) => Word32Equal(x, #0)
|
// BooleanNot(x: kRepBit) => Word32Equal(x, #0)
|
||||||
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
|
node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
|
||||||
@ -682,7 +672,7 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
case IrOpcode::kBooleanToNumber: {
|
case IrOpcode::kBooleanToNumber: {
|
||||||
if (lower()) {
|
if (lower()) {
|
||||||
MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
|
MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type();
|
||||||
if (input & kRepBit) {
|
if (input & kRepBit) {
|
||||||
// BooleanToNumber(x: kRepBit) => x
|
// BooleanToNumber(x: kRepBit) => x
|
||||||
DeferReplacement(node, node->InputAt(0));
|
DeferReplacement(node, node->InputAt(0));
|
||||||
@ -721,7 +711,7 @@ class RepresentationSelector {
|
|||||||
case IrOpcode::kNumberSubtract: {
|
case IrOpcode::kNumberSubtract: {
|
||||||
// Add and subtract reduce to Int32Add/Sub if the inputs
|
// Add and subtract reduce to Int32Add/Sub if the inputs
|
||||||
// are already integers and all uses are truncating.
|
// are already integers and all uses are truncating.
|
||||||
if (CanLowerToWord32AdditiveBinop(node, use)) {
|
if (CanLowerToWord32AdditiveBinop(node, truncation)) {
|
||||||
// => signed Int32Add/Sub
|
// => signed Int32Add/Sub
|
||||||
VisitInt32Binop(node);
|
VisitInt32Binop(node);
|
||||||
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
|
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
|
||||||
@ -735,7 +725,7 @@ class RepresentationSelector {
|
|||||||
case IrOpcode::kNumberMultiply: {
|
case IrOpcode::kNumberMultiply: {
|
||||||
NumberMatcher right(node->InputAt(1));
|
NumberMatcher right(node->InputAt(1));
|
||||||
if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
|
if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
|
||||||
if (CanLowerToInt32Binop(node, use)) {
|
if (CanLowerToInt32Binop(node, truncation)) {
|
||||||
// => signed Int32Mul
|
// => signed Int32Mul
|
||||||
VisitInt32Binop(node);
|
VisitInt32Binop(node);
|
||||||
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
|
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
|
||||||
@ -748,13 +738,14 @@ class RepresentationSelector {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kNumberDivide: {
|
case IrOpcode::kNumberDivide: {
|
||||||
if (CanLowerToInt32Binop(node, use)) {
|
if (CanLowerToInt32Binop(node, truncation)) {
|
||||||
// => signed Int32Div
|
// => signed Int32Div
|
||||||
VisitInt32Binop(node);
|
VisitInt32Binop(node);
|
||||||
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
|
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
|
if (BothInputsAre(node, Type::Unsigned32()) &&
|
||||||
|
truncation.TruncatesNaNToZero()) {
|
||||||
// => unsigned Uint32Div
|
// => unsigned Uint32Div
|
||||||
VisitUint32Binop(node);
|
VisitUint32Binop(node);
|
||||||
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
|
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
|
||||||
@ -766,13 +757,14 @@ class RepresentationSelector {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kNumberModulus: {
|
case IrOpcode::kNumberModulus: {
|
||||||
if (CanLowerToInt32Binop(node, use)) {
|
if (CanLowerToInt32Binop(node, truncation)) {
|
||||||
// => signed Int32Mod
|
// => signed Int32Mod
|
||||||
VisitInt32Binop(node);
|
VisitInt32Binop(node);
|
||||||
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
|
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
|
if (BothInputsAre(node, Type::Unsigned32()) &&
|
||||||
|
truncation.TruncatesNaNToZero()) {
|
||||||
// => unsigned Uint32Mod
|
// => unsigned Uint32Mod
|
||||||
VisitUint32Binop(node);
|
VisitUint32Binop(node);
|
||||||
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
|
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
|
||||||
@ -901,21 +893,27 @@ class RepresentationSelector {
|
|||||||
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
|
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
|
||||||
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
|
ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
|
||||||
ProcessRemainingInputs(node, 3);
|
ProcessRemainingInputs(node, 3);
|
||||||
// Tagged overrides everything if we have to do a typed array bounds
|
|
||||||
// check, because we may need to return undefined then.
|
|
||||||
MachineType output_type;
|
MachineType output_type;
|
||||||
if (use & kRepTagged) {
|
if (truncation.TruncatesUndefinedToZeroOrNaN()) {
|
||||||
output_type = kMachAnyTagged;
|
if (truncation.TruncatesNaNToZero()) {
|
||||||
} else if (use & kRepFloat64) {
|
// If undefined is truncated to a non-NaN number, we can use
|
||||||
if (access.machine_type() & kRepFloat32) {
|
// the load's representation.
|
||||||
output_type = access.machine_type();
|
output_type = access.machine_type();
|
||||||
} else {
|
} else {
|
||||||
output_type = kMachFloat64;
|
// If undefined is truncated to a number, but the use can
|
||||||
|
// observe NaN, we need to output at least the float32
|
||||||
|
// representation.
|
||||||
|
if (access.machine_type() & kRepFloat32) {
|
||||||
|
output_type = access.machine_type();
|
||||||
|
} else {
|
||||||
|
output_type = kMachFloat64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (use & kRepFloat32) {
|
|
||||||
output_type = kMachFloat32;
|
|
||||||
} else {
|
} else {
|
||||||
output_type = access.machine_type();
|
// If undefined is not truncated away, we need to have the tagged
|
||||||
|
// representation.
|
||||||
|
output_type = kMachAnyTagged;
|
||||||
}
|
}
|
||||||
SetOutput(node, output_type);
|
SetOutput(node, output_type);
|
||||||
if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
|
if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
|
||||||
@ -1125,7 +1123,7 @@ class RepresentationSelector {
|
|||||||
replacement->op()->mnemonic());
|
replacement->op()->mnemonic());
|
||||||
|
|
||||||
if (replacement->id() < count_ &&
|
if (replacement->id() < count_ &&
|
||||||
GetInfo(replacement)->output == GetInfo(node)->output) {
|
GetInfo(replacement)->output_type() == GetInfo(node)->output_type()) {
|
||||||
// Replace with a previously existing node eagerly only if the type is the
|
// Replace with a previously existing node eagerly only if the type is the
|
||||||
// same.
|
// same.
|
||||||
node->ReplaceUses(replacement);
|
node->ReplaceUses(replacement);
|
||||||
@ -1140,12 +1138,6 @@ class RepresentationSelector {
|
|||||||
node->NullAllInputs(); // Node is now dead.
|
node->NullAllInputs(); // Node is now dead.
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintUseInfo(Node* node) {
|
|
||||||
TRACE("#%d:%-20s ", node->id(), node->op()->mnemonic());
|
|
||||||
PrintInfo(GetUseInfo(node));
|
|
||||||
TRACE("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintInfo(MachineTypeUnion info) {
|
void PrintInfo(MachineTypeUnion info) {
|
||||||
if (FLAG_trace_representation) {
|
if (FLAG_trace_representation) {
|
||||||
OFStream os(stdout);
|
OFStream os(stdout);
|
||||||
@ -1153,17 +1145,24 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintTruncation(Truncation truncation) {
|
||||||
|
if (FLAG_trace_representation) {
|
||||||
|
OFStream os(stdout);
|
||||||
|
os << truncation.description();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PrintUseInfo(UseInfo info) {
|
void PrintUseInfo(UseInfo info) {
|
||||||
if (FLAG_trace_representation) {
|
if (FLAG_trace_representation) {
|
||||||
OFStream os(stdout);
|
OFStream os(stdout);
|
||||||
os << static_cast<MachineType>(info.machine_type());
|
os << info.preferred() << ":" << info.truncation().description();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSGraph* jsgraph_;
|
JSGraph* jsgraph_;
|
||||||
size_t const count_; // number of nodes in the graph
|
size_t const count_; // number of nodes in the graph
|
||||||
NodeInfo* info_; // node id -> usage information
|
ZoneVector<NodeInfo> info_; // node id -> usage information
|
||||||
NodeVector nodes_; // collected nodes
|
NodeVector nodes_; // collected nodes
|
||||||
NodeVector replacements_; // replacements to be done after lowering
|
NodeVector replacements_; // replacements to be done after lowering
|
||||||
Phase phase_; // current phase of algorithm
|
Phase phase_; // current phase of algorithm
|
||||||
@ -1182,8 +1181,6 @@ class RepresentationSelector {
|
|||||||
DCHECK(node->id() < count_);
|
DCHECK(node->id() < count_);
|
||||||
return &info_[node->id()];
|
return &info_[node->id()];
|
||||||
}
|
}
|
||||||
|
|
||||||
MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1226,7 +1223,8 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
|
|||||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||||
Node* etrue =
|
Node* etrue =
|
||||||
graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
|
graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
|
||||||
Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
|
Node* vtrue = changer->GetRepresentationFor(
|
||||||
|
etrue, type, RepresentationOf(output_type), Truncation::None());
|
||||||
|
|
||||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||||
Node* efalse = effect;
|
Node* efalse = effect;
|
||||||
|
@ -452,11 +452,10 @@ TEST(SingleChanges) {
|
|||||||
TEST(SignednessInWord32) {
|
TEST(SignednessInWord32) {
|
||||||
RepresentationChangerTester r;
|
RepresentationChangerTester r;
|
||||||
|
|
||||||
// TODO(titzer): assume that uses of a word32 without a sign mean kTypeInt32.
|
|
||||||
CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged | kTypeInt32,
|
CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged | kTypeInt32,
|
||||||
kRepWord32 | kTypeInt32);
|
kRepWord32);
|
||||||
CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged | kTypeUint32,
|
CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged | kTypeUint32,
|
||||||
kRepWord32 | kTypeUint32);
|
kRepWord32);
|
||||||
CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
|
CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
|
||||||
CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64 | kTypeInt32,
|
CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64 | kTypeInt32,
|
||||||
kRepWord32);
|
kRepWord32);
|
||||||
@ -480,7 +479,6 @@ TEST(Nops) {
|
|||||||
// 32-bit floats.
|
// 32-bit floats.
|
||||||
r.CheckNop(kRepFloat32, kRepFloat32);
|
r.CheckNop(kRepFloat32, kRepFloat32);
|
||||||
r.CheckNop(kRepFloat32 | kTypeNumber, kRepFloat32);
|
r.CheckNop(kRepFloat32 | kTypeNumber, kRepFloat32);
|
||||||
r.CheckNop(kRepFloat32, kRepFloat32 | kTypeNumber);
|
|
||||||
|
|
||||||
// 32-bit words can be used as smaller word sizes and vice versa, because
|
// 32-bit words can be used as smaller word sizes and vice versa, because
|
||||||
// loads from memory implicitly sign or zero extend the value to the
|
// loads from memory implicitly sign or zero extend the value to the
|
||||||
@ -508,39 +506,29 @@ TEST(TypeErrors) {
|
|||||||
|
|
||||||
// Wordish cannot be implicitly converted to/from comparison conditions.
|
// Wordish cannot be implicitly converted to/from comparison conditions.
|
||||||
r.CheckTypeError(kRepWord8, kRepBit);
|
r.CheckTypeError(kRepWord8, kRepBit);
|
||||||
r.CheckTypeError(kRepWord8, kRepBit | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepWord16, kRepBit);
|
r.CheckTypeError(kRepWord16, kRepBit);
|
||||||
r.CheckTypeError(kRepWord16, kRepBit | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepWord32, kRepBit);
|
r.CheckTypeError(kRepWord32, kRepBit);
|
||||||
r.CheckTypeError(kRepWord32, kRepBit | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepWord64, kRepBit);
|
r.CheckTypeError(kRepWord64, kRepBit);
|
||||||
r.CheckTypeError(kRepWord64, kRepBit | kTypeBool);
|
|
||||||
|
|
||||||
// Floats cannot be implicitly converted to/from comparison conditions.
|
// Floats cannot be implicitly converted to/from comparison conditions.
|
||||||
r.CheckTypeError(kRepFloat64, kRepBit);
|
r.CheckTypeError(kRepFloat64, kRepBit);
|
||||||
r.CheckTypeError(kRepFloat64, kRepBit | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepBit, kRepFloat64);
|
r.CheckTypeError(kRepBit, kRepFloat64);
|
||||||
r.CheckTypeError(kRepBit | kTypeBool, kRepFloat64);
|
r.CheckTypeError(kRepBit | kTypeBool, kRepFloat64);
|
||||||
|
|
||||||
// Floats cannot be implicitly converted to/from comparison conditions.
|
// Floats cannot be implicitly converted to/from comparison conditions.
|
||||||
r.CheckTypeError(kRepFloat32, kRepBit);
|
r.CheckTypeError(kRepFloat32, kRepBit);
|
||||||
r.CheckTypeError(kRepFloat32, kRepBit | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepBit, kRepFloat32);
|
r.CheckTypeError(kRepBit, kRepFloat32);
|
||||||
r.CheckTypeError(kRepBit | kTypeBool, kRepFloat32);
|
r.CheckTypeError(kRepBit | kTypeBool, kRepFloat32);
|
||||||
|
|
||||||
// Word64 is internal and shouldn't be implicitly converted.
|
// Word64 is internal and shouldn't be implicitly converted.
|
||||||
r.CheckTypeError(kRepWord64, kRepTagged | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepWord64, kRepTagged);
|
r.CheckTypeError(kRepWord64, kRepTagged);
|
||||||
r.CheckTypeError(kRepWord64, kRepTagged | kTypeBool);
|
|
||||||
r.CheckTypeError(kRepTagged, kRepWord64);
|
r.CheckTypeError(kRepTagged, kRepWord64);
|
||||||
r.CheckTypeError(kRepTagged | kTypeBool, kRepWord64);
|
r.CheckTypeError(kRepTagged | kTypeBool, kRepWord64);
|
||||||
|
|
||||||
// Word64 / Word32 shouldn't be implicitly converted.
|
// Word64 / Word32 shouldn't be implicitly converted.
|
||||||
r.CheckTypeError(kRepWord64, kRepWord32);
|
r.CheckTypeError(kRepWord64, kRepWord32);
|
||||||
r.CheckTypeError(kRepWord32, kRepWord64);
|
r.CheckTypeError(kRepWord32, kRepWord64);
|
||||||
r.CheckTypeError(kRepWord64, kRepWord32 | kTypeInt32);
|
|
||||||
r.CheckTypeError(kRepWord32 | kTypeInt32, kRepWord64);
|
r.CheckTypeError(kRepWord32 | kTypeInt32, kRepWord64);
|
||||||
r.CheckTypeError(kRepWord64, kRepWord32 | kTypeUint32);
|
|
||||||
r.CheckTypeError(kRepWord32 | kTypeUint32, kRepWord64);
|
r.CheckTypeError(kRepWord32 | kTypeUint32, kRepWord64);
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(all_reps); i++) {
|
for (size_t i = 0; i < arraysize(all_reps); i++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user