Index: src/compiler/representation-change.cc |
diff --git a/src/compiler/representation-change.cc b/src/compiler/representation-change.cc |
index 45915f65fba1c616b0605458c9150268ac7e4039..0ebb74fb5cc16135254b613eeb22e8a600a5959a 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. |
@@ -290,29 +298,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; |
@@ -320,7 +330,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(); |
@@ -335,7 +345,10 @@ Node* RepresentationChanger::GetFloat64RepresentationFor( |
} else if (output_type->Is(Type::Number())) { |
op = simplified()->ChangeTaggedToFloat64(); |
} else if (output_type->Is(Type::NumberOrUndefined())) { |
+ // TODO(jarin) Here we should check that truncation is Number. |
op = simplified()->TruncateTaggedToFloat64(); |
+ } else if (use_info.type_check() == TypeCheckKind::kNumberOrUndefined) { |
+ op = simplified()->CheckedTaggedToFloat64(); |
} |
} else if (output_rep == MachineRepresentation::kFloat32) { |
op = machine()->ChangeFloat32ToFloat64(); |
@@ -344,29 +357,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) { |
@@ -376,8 +392,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 |
@@ -385,8 +403,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())) { |
@@ -395,14 +415,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); |
} |
@@ -432,7 +487,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) { |
@@ -443,12 +497,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: |
@@ -475,6 +599,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) { |
@@ -509,8 +645,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: |