Chromium Code Reviews| Index: src/compiler/representation-change.cc |
| diff --git a/src/compiler/representation-change.cc b/src/compiler/representation-change.cc |
| index 180355d294c0fdfe8211f3c0754fe0fe4e2fb89c..dca976e484de9a0cc9d42c9530082c77d552d72e 100644 |
| --- a/src/compiler/representation-change.cc |
| +++ b/src/compiler/representation-change.cc |
| @@ -105,46 +105,55 @@ bool IsWord(MachineRepresentation rep) { |
| } // namespace |
| - |
| // Changes representation from {output_rep} 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* RepresentationChanger::GetRepresentationFor( |
| Node* node, MachineRepresentation output_rep, Type* output_type, |
| - MachineRepresentation use_rep, Truncation truncation) { |
| + Node* use_node, UseInfo use_info) { |
| if (output_rep == MachineRepresentation::kNone) { |
| // The output representation should be set. |
| - return TypeError(node, output_rep, output_type, use_rep); |
| - } |
| - if (use_rep == output_rep) { |
| - // Representations are the same. That's a no-op. |
| - return node; |
| + return TypeError(node, output_rep, output_type, use_info.representation()); |
| } |
| - if (IsWord(use_rep) && IsWord(output_rep)) { |
| - // 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; |
| + |
| + // Handle the no-op shortcuts when no checking is necessary. |
| + if (use_info.type_check() == TypeCheckKind::kNone || |
| + output_rep != MachineRepresentation::kWord32) { |
| + if (use_info.representation() == output_rep) { |
| + // Representations are the same. That's a no-op. |
| + return node; |
| + } |
| + if (IsWord(use_info.representation()) && IsWord(output_rep)) { |
| + // 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; |
| + } |
| } |
| - switch (use_rep) { |
| + |
| + switch (use_info.representation()) { |
| case MachineRepresentation::kTagged: |
| + DCHECK(use_info.type_check() == TypeCheckKind::kNone); |
| return GetTaggedRepresentationFor(node, output_rep, output_type); |
| case MachineRepresentation::kFloat32: |
| + DCHECK(use_info.type_check() == TypeCheckKind::kNone); |
| return GetFloat32RepresentationFor(node, output_rep, output_type, |
| - truncation); |
| + use_info.truncation()); |
| case MachineRepresentation::kFloat64: |
| return GetFloat64RepresentationFor(node, output_rep, output_type, |
| - truncation); |
| + use_node, use_info); |
| case MachineRepresentation::kBit: |
| + DCHECK(use_info.type_check() == TypeCheckKind::kNone); |
| return GetBitRepresentationFor(node, output_rep, output_type); |
| case MachineRepresentation::kWord8: |
| case MachineRepresentation::kWord16: |
| case MachineRepresentation::kWord32: |
| - return GetWord32RepresentationFor(node, output_rep, output_type, |
| - truncation); |
| + return GetWord32RepresentationFor(node, output_rep, output_type, use_node, |
| + use_info); |
| case MachineRepresentation::kWord64: |
| + DCHECK(use_info.type_check() == TypeCheckKind::kNone); |
| return GetWord64RepresentationFor(node, output_rep, output_type); |
| case MachineRepresentation::kSimd128: // Fall through. |
| // TODO(bbudge) Handle conversions between tagged and untagged. |
| @@ -156,7 +165,6 @@ Node* RepresentationChanger::GetRepresentationFor( |
| return nullptr; |
| } |
| - |
| Node* RepresentationChanger::GetTaggedRepresentationFor( |
| Node* node, MachineRepresentation output_rep, Type* output_type) { |
| // Eagerly fold representation changes for constants. |
| @@ -286,29 +294,31 @@ Node* RepresentationChanger::GetFloat32RepresentationFor( |
| return jsgraph()->graph()->NewNode(op, node); |
| } |
| - |
| Node* RepresentationChanger::GetFloat64RepresentationFor( |
| Node* node, MachineRepresentation output_rep, Type* output_type, |
| - Truncation truncation) { |
| + Node* use_node, UseInfo use_info) { |
| // Eagerly fold representation changes for constants. |
| - switch (node->opcode()) { |
| - case IrOpcode::kNumberConstant: |
| - return jsgraph()->Float64Constant(OpParameter<double>(node)); |
| - case IrOpcode::kInt32Constant: |
| - if (output_type->Is(Type::Signed32())) { |
| - int32_t value = OpParameter<int32_t>(node); |
| - return jsgraph()->Float64Constant(value); |
| - } else { |
| - DCHECK(output_type->Is(Type::Unsigned32())); |
| - uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
| - return jsgraph()->Float64Constant(static_cast<double>(value)); |
| - } |
| - case IrOpcode::kFloat64Constant: |
| - return node; // No change necessary. |
| - case IrOpcode::kFloat32Constant: |
| - return jsgraph()->Float64Constant(OpParameter<float>(node)); |
| - default: |
| - break; |
| + if ((use_info.type_check() == TypeCheckKind::kNone)) { |
| + // TODO(jarin) Handle checked constant conversions. |
| + switch (node->opcode()) { |
| + case IrOpcode::kNumberConstant: |
| + return jsgraph()->Float64Constant(OpParameter<double>(node)); |
| + case IrOpcode::kInt32Constant: |
| + if (output_type->Is(Type::Signed32())) { |
| + int32_t value = OpParameter<int32_t>(node); |
| + return jsgraph()->Float64Constant(value); |
| + } else { |
| + DCHECK(output_type->Is(Type::Unsigned32())); |
| + uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
| + return jsgraph()->Float64Constant(static_cast<double>(value)); |
| + } |
| + case IrOpcode::kFloat64Constant: |
| + return node; // No change necessary. |
| + case IrOpcode::kFloat32Constant: |
| + return jsgraph()->Float64Constant(OpParameter<float>(node)); |
| + default: |
| + break; |
| + } |
| } |
| // Select the correct X -> Float64 operator. |
| const Operator* op = nullptr; |
| @@ -316,7 +326,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( |
| if (output_type->Is(Type::Signed32())) { |
| op = machine()->ChangeInt32ToFloat64(); |
| } else if (output_type->Is(Type::Unsigned32()) || |
| - truncation.TruncatesToWord32()) { |
| + use_info.truncation().TruncatesToWord32()) { |
| // Either the output is uint32 or the uses only care about the |
| // low 32 bits (so we can pick uint32 safely). |
| op = machine()->ChangeUint32ToFloat64(); |
| @@ -329,7 +339,10 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( |
| node = InsertChangeTaggedSignedToInt32(node); |
| op = machine()->ChangeInt32ToFloat64(); |
| } else if (output_type->Is(Type::NumberOrUndefined())) { |
| + // TODO(jarin) Here we should check that truncation is Number. |
| op = simplified()->ChangeTaggedToFloat64(); |
|
Benedikt Meurer
2016/05/30 18:39:50
This should probably be TruncateTaggedToFloat64
Jarin
2016/05/31 20:28:53
Done in https://codereview.chromium.org/2027593002
|
| + } else if (use_info.type_check() == TypeCheckKind::kNumberOrUndefined) { |
| + op = simplified()->CheckedTaggedToFloat64(); |
| } |
| } else if (output_rep == MachineRepresentation::kFloat32) { |
| op = machine()->ChangeFloat32ToFloat64(); |
| @@ -338,29 +351,32 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( |
| return TypeError(node, output_rep, output_type, |
| MachineRepresentation::kFloat64); |
| } |
| - return jsgraph()->graph()->NewNode(op, node); |
| + return InsertConversion(node, op, use_node); |
| } |
| - |
| Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) { |
| return jsgraph()->Int32Constant(DoubleToInt32(value)); |
| } |
| Node* RepresentationChanger::GetWord32RepresentationFor( |
| Node* node, MachineRepresentation output_rep, Type* output_type, |
| - Truncation truncation) { |
| + Node* use_node, UseInfo use_info) { |
| // Eagerly fold representation changes for constants. |
| - switch (node->opcode()) { |
| - case IrOpcode::kInt32Constant: |
| - return node; // No change necessary. |
| - case IrOpcode::kFloat32Constant: |
| - return MakeTruncatedInt32Constant(OpParameter<float>(node)); |
| - case IrOpcode::kNumberConstant: |
| - case IrOpcode::kFloat64Constant: |
| - return MakeTruncatedInt32Constant(OpParameter<double>(node)); |
| - default: |
| - break; |
| + // TODO(jarin) Properly fold constants in presence of type check. |
| + if (use_info.type_check() == TypeCheckKind::kNone) { |
| + switch (node->opcode()) { |
| + case IrOpcode::kInt32Constant: |
| + return node; // No change necessary. |
| + case IrOpcode::kFloat32Constant: |
| + return MakeTruncatedInt32Constant(OpParameter<float>(node)); |
| + case IrOpcode::kNumberConstant: |
| + case IrOpcode::kFloat64Constant: |
| + return MakeTruncatedInt32Constant(OpParameter<double>(node)); |
| + default: |
| + break; |
| + } |
| } |
| + |
| // Select the correct X -> Word32 operator. |
| const Operator* op = nullptr; |
| if (output_rep == MachineRepresentation::kBit) { |
| @@ -370,8 +386,10 @@ Node* RepresentationChanger::GetWord32RepresentationFor( |
| op = machine()->ChangeFloat64ToUint32(); |
| } else if (output_type->Is(Type::Signed32())) { |
| op = machine()->ChangeFloat64ToInt32(); |
| - } else if (truncation.TruncatesToWord32()) { |
| + } else if (use_info.truncation().TruncatesToWord32()) { |
| op = machine()->TruncateFloat64ToWord32(); |
| + } else if (use_info.type_check() == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedFloat64ToInt32(); |
| } |
| } else if (output_rep == MachineRepresentation::kFloat32) { |
| node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 |
| @@ -379,8 +397,10 @@ Node* RepresentationChanger::GetWord32RepresentationFor( |
| op = machine()->ChangeFloat64ToUint32(); |
| } else if (output_type->Is(Type::Signed32())) { |
| op = machine()->ChangeFloat64ToInt32(); |
| - } else if (truncation.TruncatesToWord32()) { |
| + } else if (use_info.truncation().TruncatesToWord32()) { |
| op = machine()->TruncateFloat64ToWord32(); |
| + } else if (use_info.type_check() == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedFloat64ToInt32(); |
| } |
| } else if (output_rep == MachineRepresentation::kTagged) { |
| if (output_type->Is(Type::TaggedSigned())) { |
| @@ -389,14 +409,49 @@ Node* RepresentationChanger::GetWord32RepresentationFor( |
| op = simplified()->ChangeTaggedToUint32(); |
| } else if (output_type->Is(Type::Signed32())) { |
| op = simplified()->ChangeTaggedToInt32(); |
| - } else if (truncation.TruncatesToWord32()) { |
| + } else if (use_info.truncation().TruncatesToWord32()) { |
| op = simplified()->TruncateTaggedToWord32(); |
| + } else if (use_info.type_check() == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedTaggedToInt32(); |
| } |
| + } else if (output_rep == MachineRepresentation::kWord32) { |
| + // Only the checked case should get here, the non-checked case is |
| + // handled in GetRepresentationFor. |
| + DCHECK(use_info.type_check() == TypeCheckKind::kSigned32); |
| + if (output_type->Is(Type::Signed32())) { |
| + return node; |
| + } else if (output_type->Is(Type::Unsigned32())) { |
| + op = simplified()->CheckedUint32ToInt32(); |
| + } |
| + } else if (output_rep == MachineRepresentation::kWord8 || |
| + output_rep == MachineRepresentation::kWord16) { |
| + DCHECK(use_info.representation() == MachineRepresentation::kWord32); |
| + DCHECK(use_info.type_check() == TypeCheckKind::kSigned32); |
| + return node; |
| } |
| + |
| if (op == nullptr) { |
| return TypeError(node, output_rep, output_type, |
| MachineRepresentation::kWord32); |
| } |
| + return InsertConversion(node, op, use_node); |
| +} |
| + |
| +Node* RepresentationChanger::InsertConversion(Node* node, const Operator* op, |
| + Node* use_node) { |
| + if (op->ControlInputCount() > 0) { |
| + // If the operator can deoptimize (which means it has control |
| + // input), we need to connect it to the effect and control chains |
| + // and also provide it with a frame state. |
| + Node* effect = NodeProperties::GetEffectInput(use_node); |
| + Node* control = NodeProperties::GetControlInput(use_node); |
| + Node* frame_state = NodeProperties::GetFrameStateInput(use_node, 0); |
| + Node* conversion = |
| + jsgraph()->graph()->NewNode(op, node, frame_state, effect, control); |
| + NodeProperties::ReplaceControlInput(use_node, control); |
| + NodeProperties::ReplaceEffectInput(use_node, effect); |
| + return conversion; |
| + } |
| return jsgraph()->graph()->NewNode(op, node); |
| } |
| @@ -426,7 +481,6 @@ Node* RepresentationChanger::GetBitRepresentationFor( |
| return jsgraph()->graph()->NewNode(op, node); |
| } |
| - |
| Node* RepresentationChanger::GetWord64RepresentationFor( |
| Node* node, MachineRepresentation output_rep, Type* output_type) { |
| if (output_rep == MachineRepresentation::kBit) { |
| @@ -437,12 +491,82 @@ Node* RepresentationChanger::GetWord64RepresentationFor( |
| MachineRepresentation::kWord64); |
| } |
| +Node* RepresentationChanger::GetCheckedWord32RepresentationFor( |
| + Node* node, MachineRepresentation output_rep, Type* output_type, |
| + Node* use_node, Truncation truncation, TypeCheckKind check) { |
| + // TODO(jarin) Eagerly fold constants (or insert hard deopt if the constant |
| + // does not pass the check). |
| + |
| + // If the input is already Signed32 in Word32 representation, we do not |
| + // have to do anything. (We could fold this into the big if below, but |
| + // it feels nicer to have the shortcut return first). |
| + if (output_rep == MachineRepresentation::kWord32 || |
| + output_type->Is(Type::Signed32())) { |
| + return node; |
| + } |
| + |
| + // Select the correct X -> Word32 operator. |
| + const Operator* op = nullptr; |
| + if (output_rep == MachineRepresentation::kWord32) { |
| + if (output_type->Is(Type::Unsigned32())) { |
| + op = simplified()->CheckedUint32ToInt32(); |
| + } |
| + } else if (output_rep == MachineRepresentation::kBit) { |
| + return node; // Sloppy comparison -> word32 |
| + } else if (output_rep == MachineRepresentation::kFloat64) { |
| + if (output_type->Is(Type::Unsigned32())) { |
| + op = machine()->ChangeFloat64ToUint32(); |
| + } else if (output_type->Is(Type::Signed32())) { |
| + op = machine()->ChangeFloat64ToInt32(); |
| + } else if (truncation.TruncatesToWord32()) { |
| + op = machine()->TruncateFloat64ToWord32(); |
| + } else if (check == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedFloat64ToInt32(); |
| + } |
| + } else if (output_rep == MachineRepresentation::kFloat32) { |
| + node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 |
| + if (output_type->Is(Type::Unsigned32())) { |
| + op = machine()->ChangeFloat64ToUint32(); |
| + } else if (output_type->Is(Type::Signed32())) { |
| + op = machine()->ChangeFloat64ToInt32(); |
| + } else if (truncation.TruncatesToWord32()) { |
| + op = machine()->TruncateFloat64ToWord32(); |
| + } else if (check == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedFloat64ToInt32(); |
| + } |
| + } else if (output_rep == MachineRepresentation::kTagged) { |
| + if (output_type->Is(Type::TaggedSigned())) { |
| + op = simplified()->ChangeTaggedSignedToInt32(); |
| + } else if (output_type->Is(Type::Unsigned32())) { |
| + op = simplified()->ChangeTaggedToUint32(); |
| + } else if (output_type->Is(Type::Signed32())) { |
| + op = simplified()->ChangeTaggedToInt32(); |
| + } else if (truncation.TruncatesToWord32()) { |
| + op = simplified()->TruncateTaggedToWord32(); |
| + } else if (check == TypeCheckKind::kSigned32) { |
| + op = simplified()->CheckedTaggedToInt32(); |
| + } |
| + } |
| + if (op == nullptr) { |
| + return TypeError(node, output_rep, output_type, |
| + MachineRepresentation::kWord32); |
| + } |
| + if (op->ControlInputCount() > 0) { |
| + // If the operator can deoptimize (which means it has control |
| + // input), we need to connect it to the effect and control chains |
| + // and also provide it with a frame state. |
| + UNIMPLEMENTED(); |
| + } |
| + return jsgraph()->graph()->NewNode(op, node); |
| +} |
| const Operator* RepresentationChanger::Int32OperatorFor( |
| IrOpcode::Value opcode) { |
| switch (opcode) { |
| + case IrOpcode::kSpeculativeNumberAdd: // Fall through. |
| case IrOpcode::kNumberAdd: |
| return machine()->Int32Add(); |
| + case IrOpcode::kSpeculativeNumberSubtract: // Fall through. |
| case IrOpcode::kNumberSubtract: |
| return machine()->Int32Sub(); |
| case IrOpcode::kNumberMultiply: |
| @@ -469,6 +593,18 @@ const Operator* RepresentationChanger::Int32OperatorFor( |
| } |
| } |
| +const Operator* RepresentationChanger::Int32OverflowOperatorFor( |
| + IrOpcode::Value opcode) { |
| + switch (opcode) { |
| + case IrOpcode::kSpeculativeNumberAdd: // Fall through. |
| + return machine()->Int32AddWithOverflow(); |
| + case IrOpcode::kSpeculativeNumberSubtract: // Fall through. |
| + return machine()->Int32SubWithOverflow(); |
| + default: |
| + UNREACHABLE(); |
| + return nullptr; |
| + } |
| +} |
| const Operator* RepresentationChanger::Uint32OperatorFor( |
| IrOpcode::Value opcode) { |
| @@ -503,8 +639,10 @@ const Operator* RepresentationChanger::Uint32OperatorFor( |
| const Operator* RepresentationChanger::Float64OperatorFor( |
| IrOpcode::Value opcode) { |
| switch (opcode) { |
| + case IrOpcode::kSpeculativeNumberAdd: |
| case IrOpcode::kNumberAdd: |
| return machine()->Float64Add(); |
| + case IrOpcode::kSpeculativeNumberSubtract: |
| case IrOpcode::kNumberSubtract: |
| return machine()->Float64Sub(); |
| case IrOpcode::kNumberMultiply: |