| Index: src/compiler/representation-change.h
|
| diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h
|
| index 2eff131f26550bda84c4a81caa2709d897e198d5..dfb82960a02317431005d6190d5a8a7eb443abc5 100644
|
| --- a/src/compiler/representation-change.h
|
| +++ b/src/compiler/representation-change.h
|
| @@ -16,10 +16,137 @@ namespace v8 {
|
| namespace internal {
|
| 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
|
| // and other nodes, as well as lowering Simplified->Machine operators.
|
| // Eagerly folds any representation changes for constants.
|
| -class RepresentationChanger {
|
| +class RepresentationChanger final {
|
| public:
|
| RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
|
| : jsgraph_(jsgraph),
|
| @@ -32,34 +159,40 @@ class RepresentationChanger {
|
| 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,
|
| - MachineTypeUnion use_type) {
|
| + MachineTypeUnion use_rep,
|
| + Truncation truncation = Truncation::None()) {
|
| + DCHECK((use_rep & kRepMask) == use_rep);
|
| if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
|
| // 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.
|
| 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.
|
| // Since loads of integers from memory implicitly sign or zero extend the
|
| // value to the full machine word size and stores implicitly truncate,
|
| // no representation change is necessary.
|
| return node;
|
| }
|
| - if (use_type & kRepTagged) {
|
| + if (use_rep & kRepTagged) {
|
| return GetTaggedRepresentationFor(node, output_type);
|
| - } else if (use_type & kRepFloat32) {
|
| - return GetFloat32RepresentationFor(node, output_type, use_type);
|
| - } else if (use_type & kRepFloat64) {
|
| - return GetFloat64RepresentationFor(node, output_type, use_type);
|
| - } else if (use_type & kRepBit) {
|
| + } else if (use_rep & kRepFloat32) {
|
| + return GetFloat32RepresentationFor(node, output_type, truncation);
|
| + } else if (use_rep & kRepFloat64) {
|
| + return GetFloat64RepresentationFor(node, output_type, truncation);
|
| + } else if (use_rep & kRepBit) {
|
| return GetBitRepresentationFor(node, output_type);
|
| - } else if (IsWord(use_type)) {
|
| + } else if (IsWord(use_rep)) {
|
| return GetWord32RepresentationFor(node, output_type);
|
| - } else if (use_type & kRepWord64) {
|
| + } else if (use_rep & kRepWord64) {
|
| return GetWord64RepresentationFor(node, output_type);
|
| } else {
|
| return node;
|
| @@ -116,7 +249,7 @@ class RepresentationChanger {
|
| }
|
|
|
| Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type,
|
| - MachineTypeUnion truncation) {
|
| + Truncation truncation) {
|
| // Eagerly fold representation changes for constants.
|
| switch (node->opcode()) {
|
| case IrOpcode::kFloat64Constant:
|
| @@ -146,8 +279,7 @@ class RepresentationChanger {
|
| } else {
|
| // Either the output is int32 or the uses only care about the
|
| // low 32 bits (so we can pick int32 safely).
|
| - DCHECK(output_type & kTypeInt32 ||
|
| - !(truncation & ~(kTypeInt32 | kTypeUint32 | kRepMask)));
|
| + DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32());
|
| op = machine()->ChangeInt32ToFloat64();
|
| }
|
| // int32 -> float64 -> float32
|
| @@ -167,7 +299,7 @@ class RepresentationChanger {
|
| }
|
|
|
| Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type,
|
| - MachineTypeUnion use_type) {
|
| + Truncation truncation) {
|
| // Eagerly fold representation changes for constants.
|
| switch (node->opcode()) {
|
| case IrOpcode::kNumberConstant:
|
| @@ -197,8 +329,7 @@ class RepresentationChanger {
|
| } else {
|
| // Either the output is int32 or the uses only care about the
|
| // low 32 bits (so we can pick int32 safely).
|
| - DCHECK(output_type & kTypeInt32 ||
|
| - !(use_type & ~(kTypeInt32 | kTypeUint32 | kRepMask)));
|
| + DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32());
|
| op = machine()->ChangeInt32ToFloat64();
|
| }
|
| } else if (output_type & kRepTagged) {
|
|
|