// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/compiler/representation-change.h" #include <sstream> #include "src/base/bits.h" #include "src/code-factory.h" #include "src/compiler/machine-operator.h" namespace v8 { namespace internal { namespace compiler { const char* Truncation::description() const { 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; } // Partial order for truncations: // // kWord64 kAny // ^ ^ // \ | // \ kFloat64 <--+ // \ ^ ^ | // \ / | | // kWord32 kFloat32 kBool // ^ ^ ^ // \ | / // \ | / // \ | / // \ | / // \ | / // kNone // static Truncation::TruncationKind Truncation::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 truncations"); return TruncationKind::kNone; } // static bool Truncation::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; } namespace { bool IsWord(MachineRepresentation rep) { return rep == MachineRepresentation::kWord8 || rep == MachineRepresentation::kWord16 || rep == MachineRepresentation::kWord32; } } // 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, 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_info.representation()); } // 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_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, use_info.truncation()); case MachineRepresentation::kFloat64: return GetFloat64RepresentationFor(node, output_rep, output_type, 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, 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. break; case MachineRepresentation::kNone: return node; } UNREACHABLE(); return nullptr; } Node* RepresentationChanger::GetTaggedRepresentationFor( Node* node, MachineRepresentation output_rep, Type* output_type) { // Eagerly fold representation changes for constants. switch (node->opcode()) { case IrOpcode::kNumberConstant: case IrOpcode::kHeapConstant: return node; // No change necessary. case IrOpcode::kInt32Constant: if (output_type->Is(Type::Signed32())) { int32_t value = OpParameter<int32_t>(node); return jsgraph()->Constant(value); } else if (output_type->Is(Type::Unsigned32())) { uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); return jsgraph()->Constant(static_cast<double>(value)); } else if (output_rep == MachineRepresentation::kBit) { return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant() : jsgraph()->TrueConstant(); } else { return TypeError(node, output_rep, output_type, MachineRepresentation::kTagged); } case IrOpcode::kFloat64Constant: return jsgraph()->Constant(OpParameter<double>(node)); case IrOpcode::kFloat32Constant: return jsgraph()->Constant(OpParameter<float>(node)); default: break; } // Select the correct X -> Tagged operator. const Operator* op; if (output_rep == MachineRepresentation::kBit) { op = simplified()->ChangeBitToTagged(); } else if (IsWord(output_rep)) { if (output_type->Is(Type::Signed31())) { op = simplified()->ChangeInt31ToTaggedSigned(); } else if (output_type->Is(Type::Signed32())) { op = simplified()->ChangeInt32ToTagged(); } else if (output_type->Is(Type::Unsigned32())) { op = simplified()->ChangeUint32ToTagged(); } else { return TypeError(node, output_rep, output_type, MachineRepresentation::kTagged); } } else if (output_rep == MachineRepresentation::kFloat32) { // float32 -> float64 -> tagged node = InsertChangeFloat32ToFloat64(node); // TODO(bmeurer): Pass -0 hint to ChangeFloat64ToTagged. op = simplified()->ChangeFloat64ToTagged(); } else if (output_rep == MachineRepresentation::kFloat64) { if (output_type->Is(Type::Signed31())) { // float64 -> int32 -> tagged node = InsertChangeFloat64ToInt32(node); op = simplified()->ChangeInt31ToTaggedSigned(); } else if (output_type->Is( Type::Signed32())) { // float64 -> int32 -> tagged node = InsertChangeFloat64ToInt32(node); op = simplified()->ChangeInt32ToTagged(); } else if (output_type->Is( Type::Unsigned32())) { // float64 -> uint32 -> tagged node = InsertChangeFloat64ToUint32(node); op = simplified()->ChangeUint32ToTagged(); } else { // TODO(bmeurer): Pass -0 hint to ChangeFloat64ToTagged. op = simplified()->ChangeFloat64ToTagged(); } } else { return TypeError(node, output_rep, output_type, MachineRepresentation::kTagged); } return jsgraph()->graph()->NewNode(op, node); } Node* RepresentationChanger::GetFloat32RepresentationFor( Node* node, MachineRepresentation output_rep, Type* output_type, Truncation truncation) { // Eagerly fold representation changes for constants. switch (node->opcode()) { case IrOpcode::kFloat64Constant: case IrOpcode::kNumberConstant: return jsgraph()->Float32Constant( DoubleToFloat32(OpParameter<double>(node))); case IrOpcode::kInt32Constant: if (output_type->Is(Type::Unsigned32())) { uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); return jsgraph()->Float32Constant(static_cast<float>(value)); } else { int32_t value = OpParameter<int32_t>(node); return jsgraph()->Float32Constant(static_cast<float>(value)); } case IrOpcode::kFloat32Constant: return node; // No change necessary. default: break; } // Select the correct X -> Float32 operator. const Operator* op = nullptr; if (IsWord(output_rep)) { if (output_type->Is(Type::Signed32())) { // int32 -> float64 -> float32 op = machine()->ChangeInt32ToFloat64(); node = jsgraph()->graph()->NewNode(op, node); op = machine()->TruncateFloat64ToFloat32(); } else if (output_type->Is(Type::Unsigned32()) || truncation.TruncatesToWord32()) { // Either the output is uint32 or the uses only care about the // low 32 bits (so we can pick uint32 safely). // uint32 -> float64 -> float32 op = machine()->ChangeUint32ToFloat64(); node = jsgraph()->graph()->NewNode(op, node); op = machine()->TruncateFloat64ToFloat32(); } } else if (output_rep == MachineRepresentation::kTagged) { if (output_type->Is(Type::NumberOrUndefined())) { // tagged -> float64 -> float32 if (output_type->Is(Type::Number())) { op = simplified()->ChangeTaggedToFloat64(); } else { op = simplified()->TruncateTaggedToFloat64(); } node = jsgraph()->graph()->NewNode(op, node); op = machine()->TruncateFloat64ToFloat32(); } } else if (output_rep == MachineRepresentation::kFloat64) { op = machine()->TruncateFloat64ToFloat32(); } if (op == nullptr) { return TypeError(node, output_rep, output_type, MachineRepresentation::kFloat32); } return jsgraph()->graph()->NewNode(op, node); } Node* RepresentationChanger::GetFloat64RepresentationFor( Node* node, MachineRepresentation output_rep, Type* output_type, Node* use_node, UseInfo use_info) { // Eagerly fold representation changes for constants. 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; if (IsWord(output_rep)) { if (output_type->Is(Type::Signed32())) { op = machine()->ChangeInt32ToFloat64(); } else if (output_type->Is(Type::Unsigned32()) || 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(); } } else if (output_rep == MachineRepresentation::kTagged) { if (output_type->Is(Type::Undefined())) { return jsgraph()->Float64Constant( std::numeric_limits<double>::quiet_NaN()); } else if (output_type->Is(Type::TaggedSigned())) { node = InsertChangeTaggedSignedToInt32(node); op = machine()->ChangeInt32ToFloat64(); } 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(); } if (op == nullptr) { return TypeError(node, output_rep, output_type, MachineRepresentation::kFloat64); } 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, 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: { float const fv = OpParameter<float>(node); if (use_info.type_check() == TypeCheckKind::kNone || (use_info.type_check() == TypeCheckKind::kSigned32 && IsInt32Double(fv))) { return MakeTruncatedInt32Constant(fv); } break; } case IrOpcode::kNumberConstant: case IrOpcode::kFloat64Constant: { double const fv = OpParameter<double>(node); if (use_info.type_check() == TypeCheckKind::kNone || (use_info.type_check() == TypeCheckKind::kSigned32 && IsInt32Double(fv))) { return MakeTruncatedInt32Constant(fv); } break; } default: break; } // Select the correct X -> Word32 operator. const Operator* op = nullptr; 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 (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 if (output_type->Is(Type::Unsigned32())) { op = machine()->ChangeFloat64ToUint32(); } else if (output_type->Is(Type::Signed32())) { op = machine()->ChangeFloat64ToInt32(); } 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())) { 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 (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. Node* effect = NodeProperties::GetEffectInput(use_node); Node* control = NodeProperties::GetControlInput(use_node); Node* conversion = jsgraph()->graph()->NewNode(op, node, effect, control); NodeProperties::ReplaceEffectInput(use_node, conversion); return conversion; } return jsgraph()->graph()->NewNode(op, node); } Node* RepresentationChanger::GetBitRepresentationFor( Node* node, MachineRepresentation output_rep, Type* output_type) { // Eagerly fold representation changes for constants. switch (node->opcode()) { case IrOpcode::kHeapConstant: { Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node); DCHECK(value.is_identical_to(factory()->true_value()) || value.is_identical_to(factory()->false_value())); return jsgraph()->Int32Constant( value.is_identical_to(factory()->true_value()) ? 1 : 0); } default: break; } // Select the correct X -> Bit operator. const Operator* op; if (output_rep == MachineRepresentation::kTagged) { op = simplified()->ChangeTaggedToBit(); } else { return TypeError(node, output_rep, output_type, MachineRepresentation::kBit); } return jsgraph()->graph()->NewNode(op, node); } Node* RepresentationChanger::GetWord64RepresentationFor( Node* node, MachineRepresentation output_rep, Type* output_type) { if (output_rep == MachineRepresentation::kBit) { return node; // Sloppy comparison -> word64 } // Can't really convert Word64 to anything else. Purported to be internal. return TypeError(node, output_rep, output_type, 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. 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::kSpeculativeNumberMultiply: case IrOpcode::kNumberMultiply: return machine()->Int32Mul(); case IrOpcode::kSpeculativeNumberDivide: case IrOpcode::kNumberDivide: return machine()->Int32Div(); case IrOpcode::kSpeculativeNumberModulus: case IrOpcode::kNumberModulus: return machine()->Int32Mod(); case IrOpcode::kNumberBitwiseOr: return machine()->Word32Or(); case IrOpcode::kNumberBitwiseXor: return machine()->Word32Xor(); case IrOpcode::kNumberBitwiseAnd: return machine()->Word32And(); case IrOpcode::kNumberEqual: case IrOpcode::kSpeculativeNumberEqual: return machine()->Word32Equal(); case IrOpcode::kNumberLessThan: case IrOpcode::kSpeculativeNumberLessThan: return machine()->Int32LessThan(); case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kSpeculativeNumberLessThanOrEqual: return machine()->Int32LessThanOrEqual(); default: UNREACHABLE(); return nullptr; } } const Operator* RepresentationChanger::Int32OverflowOperatorFor( IrOpcode::Value opcode) { switch (opcode) { case IrOpcode::kSpeculativeNumberAdd: // Fall through. return simplified()->CheckedInt32Add(); case IrOpcode::kSpeculativeNumberSubtract: // Fall through. return simplified()->CheckedInt32Sub(); default: UNREACHABLE(); return nullptr; } } const Operator* RepresentationChanger::Uint32OperatorFor( IrOpcode::Value opcode) { switch (opcode) { case IrOpcode::kNumberAdd: return machine()->Int32Add(); case IrOpcode::kNumberSubtract: return machine()->Int32Sub(); case IrOpcode::kSpeculativeNumberMultiply: case IrOpcode::kNumberMultiply: return machine()->Int32Mul(); case IrOpcode::kSpeculativeNumberDivide: case IrOpcode::kNumberDivide: return machine()->Uint32Div(); case IrOpcode::kSpeculativeNumberModulus: case IrOpcode::kNumberModulus: return machine()->Uint32Mod(); case IrOpcode::kNumberEqual: case IrOpcode::kSpeculativeNumberEqual: return machine()->Word32Equal(); case IrOpcode::kNumberLessThan: case IrOpcode::kSpeculativeNumberLessThan: return machine()->Uint32LessThan(); case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kSpeculativeNumberLessThanOrEqual: return machine()->Uint32LessThanOrEqual(); case IrOpcode::kNumberClz32: return machine()->Word32Clz(); case IrOpcode::kNumberImul: return machine()->Int32Mul(); default: UNREACHABLE(); return nullptr; } } 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::kSpeculativeNumberMultiply: case IrOpcode::kNumberMultiply: return machine()->Float64Mul(); case IrOpcode::kSpeculativeNumberDivide: case IrOpcode::kNumberDivide: return machine()->Float64Div(); case IrOpcode::kSpeculativeNumberModulus: case IrOpcode::kNumberModulus: return machine()->Float64Mod(); case IrOpcode::kNumberEqual: case IrOpcode::kSpeculativeNumberEqual: return machine()->Float64Equal(); case IrOpcode::kNumberLessThan: case IrOpcode::kSpeculativeNumberLessThan: return machine()->Float64LessThan(); case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kSpeculativeNumberLessThanOrEqual: return machine()->Float64LessThanOrEqual(); case IrOpcode::kNumberAbs: return machine()->Float64Abs(); case IrOpcode::kNumberAtan: return machine()->Float64Atan(); case IrOpcode::kNumberAtan2: return machine()->Float64Atan2(); case IrOpcode::kNumberCos: return machine()->Float64Cos(); case IrOpcode::kNumberExp: return machine()->Float64Exp(); case IrOpcode::kNumberFround: return machine()->TruncateFloat64ToFloat32(); case IrOpcode::kNumberAtanh: return machine()->Float64Atanh(); case IrOpcode::kNumberLog: return machine()->Float64Log(); case IrOpcode::kNumberLog1p: return machine()->Float64Log1p(); case IrOpcode::kNumberLog2: return machine()->Float64Log2(); case IrOpcode::kNumberLog10: return machine()->Float64Log10(); case IrOpcode::kNumberSin: return machine()->Float64Sin(); case IrOpcode::kNumberTan: return machine()->Float64Tan(); case IrOpcode::kNumberSqrt: return machine()->Float64Sqrt(); case IrOpcode::kNumberCbrt: return machine()->Float64Cbrt(); case IrOpcode::kNumberExpm1: return machine()->Float64Expm1(); case IrOpcode::kNumberSilenceNaN: return machine()->Float64SilenceNaN(); default: UNREACHABLE(); return nullptr; } } Node* RepresentationChanger::TypeError(Node* node, MachineRepresentation output_rep, Type* output_type, MachineRepresentation use) { type_error_ = true; if (!testing_type_errors_) { std::ostringstream out_str; out_str << output_rep << " ("; output_type->PrintTo(out_str, Type::SEMANTIC_DIM); out_str << ")"; std::ostringstream use_str; use_str << use; V8_Fatal(__FILE__, __LINE__, "RepresentationChangerError: node #%d:%s of " "%s cannot be changed to %s", node->id(), node->op()->mnemonic(), out_str.str().c_str(), use_str.str().c_str()); } return node; } Node* RepresentationChanger::InsertChangeFloat32ToFloat64(Node* node) { return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node); } Node* RepresentationChanger::InsertChangeFloat64ToUint32(Node* node) { return jsgraph()->graph()->NewNode(machine()->ChangeFloat64ToUint32(), node); } Node* RepresentationChanger::InsertChangeFloat64ToInt32(Node* node) { return jsgraph()->graph()->NewNode(machine()->ChangeFloat64ToInt32(), node); } Node* RepresentationChanger::InsertChangeTaggedSignedToInt32(Node* node) { return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), node); } Node* RepresentationChanger::InsertChangeTaggedToFloat64(Node* node) { return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(), node); } } // namespace compiler } // namespace internal } // namespace v8