[turbofan] Add TruncationMode for TruncateFloat64ToInt32.
We actually need round to zero truncation to implement the counterpart of LDoubleToI in TurboFan, which tries to convert a double to an integer as required for keyed load/store optimizations. Drive-by-cleanup: Reduce some code duplication in the InstructionSelector implementations. R=jarin@chromium.org Review URL: https://codereview.chromium.org/1225993002 Cr-Commit-Position: refs/heads/master@{#29527}
This commit is contained in:
parent
3973642c98
commit
4b38c15817
@ -914,6 +914,17 @@ void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, kArchTruncateDoubleToI, node);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRR(this, kArmVcvtS32F64, node);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Add(Node* node) {
|
void InstructionSelector::VisitFloat32Add(Node* node) {
|
||||||
ArmOperandGenerator g(this);
|
ArmOperandGenerator g(this);
|
||||||
Float32BinopMatcher m(node);
|
Float32BinopMatcher m(node);
|
||||||
|
@ -1237,9 +1237,18 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
||||||
Arm64OperandGenerator g(this);
|
VisitRR(this, kArm64Float64ToFloat32, node);
|
||||||
Emit(kArm64Float64ToFloat32, g.DefineAsRegister(node),
|
}
|
||||||
g.UseRegister(node->InputAt(0)));
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, kArchTruncateDoubleToI, node);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRR(this, kArm64Float64ToInt32, node);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,14 +127,13 @@ class IA32OperandGenerator final : public OperandGenerator {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void VisitROFloat(InstructionSelector* selector, Node* node,
|
void VisitRO(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
|
||||||
ArchOpcode opcode) {
|
|
||||||
IA32OperandGenerator g(selector);
|
IA32OperandGenerator g(selector);
|
||||||
selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VisitRRFloat(InstructionSelector* selector, Node* node,
|
void VisitRR(InstructionSelector* selector, Node* node,
|
||||||
InstructionCode opcode) {
|
InstructionCode opcode) {
|
||||||
IA32OperandGenerator g(selector);
|
IA32OperandGenerator g(selector);
|
||||||
selector->Emit(opcode, g.DefineAsRegister(node),
|
selector->Emit(opcode, g.DefineAsRegister(node),
|
||||||
@ -648,38 +647,43 @@ void InstructionSelector::VisitUint32Mod(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
|
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat32ToFloat64);
|
||||||
Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
|
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEInt32ToFloat64);
|
||||||
Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEUint32ToFloat64);
|
||||||
Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat64ToInt32);
|
||||||
Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat64ToUint32);
|
||||||
Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat64ToFloat32);
|
||||||
Emit(kSSEFloat64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, node, kArchTruncateDoubleToI);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRO(this, node, kSSEFloat64ToInt32);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -791,22 +795,22 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||||
VisitROFloat(this, node, kSSEFloat32Sqrt);
|
VisitRO(this, node, kSSEFloat32Sqrt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
|
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
|
||||||
VisitROFloat(this, node, kSSEFloat64Sqrt);
|
VisitRO(this, node, kSSEFloat64Sqrt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64RoundDown(Node* node) {
|
void InstructionSelector::VisitFloat64RoundDown(Node* node) {
|
||||||
VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
|
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
|
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
|
||||||
VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
|
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -779,13 +779,6 @@ void InstructionSelector::VisitNode(Node* node) {
|
|||||||
|
|
||||||
#if V8_TURBOFAN_BACKEND
|
#if V8_TURBOFAN_BACKEND
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
|
||||||
OperandGenerator g(this);
|
|
||||||
Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node),
|
|
||||||
g.UseRegister(node->InputAt(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitLoadStackPointer(Node* node) {
|
void InstructionSelector::VisitLoadStackPointer(Node* node) {
|
||||||
OperandGenerator g(this);
|
OperandGenerator g(this);
|
||||||
Emit(kArchStackPointer, g.DefineAsRegister(node));
|
Emit(kArchStackPointer, g.DefineAsRegister(node));
|
||||||
|
@ -646,14 +646,13 @@ Reduction MachineOperatorReducer::ReduceTruncateFloat64ToInt32(Node* node) {
|
|||||||
Node* const phi = m.node();
|
Node* const phi = m.node();
|
||||||
DCHECK_EQ(kRepFloat64, RepresentationOf(OpParameter<MachineType>(phi)));
|
DCHECK_EQ(kRepFloat64, RepresentationOf(OpParameter<MachineType>(phi)));
|
||||||
if (phi->OwnedBy(node)) {
|
if (phi->OwnedBy(node)) {
|
||||||
// TruncateFloat64ToInt32(Phi[Float64](x1,...,xn))
|
// TruncateFloat64ToInt32[mode](Phi[Float64](x1,...,xn))
|
||||||
// => Phi[Int32](TruncateFloat64ToInt32(x1),
|
// => Phi[Int32](TruncateFloat64ToInt32[mode](x1),
|
||||||
// ...,
|
// ...,
|
||||||
// TruncateFloat64ToInt32(xn))
|
// TruncateFloat64ToInt32[mode](xn))
|
||||||
const int value_input_count = phi->InputCount() - 1;
|
const int value_input_count = phi->InputCount() - 1;
|
||||||
for (int i = 0; i < value_input_count; ++i) {
|
for (int i = 0; i < value_input_count; ++i) {
|
||||||
Node* input = graph()->NewNode(machine()->TruncateFloat64ToInt32(),
|
Node* input = graph()->NewNode(node->op(), phi->InputAt(i));
|
||||||
phi->InputAt(i));
|
|
||||||
// TODO(bmeurer): Reschedule input for reduction once we have Revisit()
|
// TODO(bmeurer): Reschedule input for reduction once we have Revisit()
|
||||||
// instead of recursing into ReduceTruncateFloat64ToInt32() here.
|
// instead of recursing into ReduceTruncateFloat64ToInt32() here.
|
||||||
Reduction reduction = ReduceTruncateFloat64ToInt32(input);
|
Reduction reduction = ReduceTruncateFloat64ToInt32(input);
|
||||||
|
@ -12,6 +12,24 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, TruncationMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return os << "JavaScript";
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return os << "RoundToZero";
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TruncationMode TruncationModeOf(Operator const* op) {
|
||||||
|
DCHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, op->opcode());
|
||||||
|
return OpParameter<TruncationMode>(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) {
|
std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case kNoWriteBarrier:
|
case kNoWriteBarrier:
|
||||||
@ -117,7 +135,6 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
|
|||||||
V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 0, 1) \
|
V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
|
V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(TruncateFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
|
|
||||||
V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1) \
|
V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(Float32Abs, Operator::kNoProperties, 1, 0, 1) \
|
V(Float32Abs, Operator::kNoProperties, 1, 0, 1) \
|
||||||
V(Float32Add, Operator::kCommutative, 2, 0, 1) \
|
V(Float32Add, Operator::kCommutative, 2, 0, 1) \
|
||||||
@ -191,6 +208,19 @@ struct MachineOperatorGlobalCache {
|
|||||||
PURE_OPTIONAL_OP_LIST(PURE)
|
PURE_OPTIONAL_OP_LIST(PURE)
|
||||||
#undef PURE
|
#undef PURE
|
||||||
|
|
||||||
|
template <TruncationMode kMode>
|
||||||
|
struct TruncateFloat64ToInt32Operator final
|
||||||
|
: public Operator1<TruncationMode> {
|
||||||
|
TruncateFloat64ToInt32Operator()
|
||||||
|
: Operator1<TruncationMode>(IrOpcode::kTruncateFloat64ToInt32,
|
||||||
|
Operator::kPure, "TruncateFloat64ToInt32",
|
||||||
|
1, 0, 0, 1, 0, 0, kMode) {}
|
||||||
|
};
|
||||||
|
TruncateFloat64ToInt32Operator<TruncationMode::kJavaScript>
|
||||||
|
kTruncateFloat64ToInt32JavaScript;
|
||||||
|
TruncateFloat64ToInt32Operator<TruncationMode::kRoundToZero>
|
||||||
|
kTruncateFloat64ToInt32RoundToZero;
|
||||||
|
|
||||||
#define LOAD(Type) \
|
#define LOAD(Type) \
|
||||||
struct Load##Type##Operator final : public Operator1<LoadRepresentation> { \
|
struct Load##Type##Operator final : public Operator1<LoadRepresentation> { \
|
||||||
Load##Type##Operator() \
|
Load##Type##Operator() \
|
||||||
@ -268,6 +298,20 @@ PURE_OP_LIST(PURE)
|
|||||||
PURE_OPTIONAL_OP_LIST(PURE)
|
PURE_OPTIONAL_OP_LIST(PURE)
|
||||||
#undef PURE
|
#undef PURE
|
||||||
|
|
||||||
|
|
||||||
|
const Operator* MachineOperatorBuilder::TruncateFloat64ToInt32(
|
||||||
|
TruncationMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return &cache_.kTruncateFloat64ToInt32JavaScript;
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return &cache_.kTruncateFloat64ToInt32RoundToZero;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const Operator* MachineOperatorBuilder::Load(LoadRepresentation rep) {
|
const Operator* MachineOperatorBuilder::Load(LoadRepresentation rep) {
|
||||||
switch (rep) {
|
switch (rep) {
|
||||||
#define LOAD(Type) \
|
#define LOAD(Type) \
|
||||||
|
@ -16,8 +16,9 @@ namespace compiler {
|
|||||||
struct MachineOperatorGlobalCache;
|
struct MachineOperatorGlobalCache;
|
||||||
class Operator;
|
class Operator;
|
||||||
|
|
||||||
|
|
||||||
// For operators that are not supported on all platforms.
|
// For operators that are not supported on all platforms.
|
||||||
class OptionalOperator {
|
class OptionalOperator final {
|
||||||
public:
|
public:
|
||||||
explicit OptionalOperator(const Operator* op) : op_(op) {}
|
explicit OptionalOperator(const Operator* op) : op_(op) {}
|
||||||
|
|
||||||
@ -28,9 +29,25 @@ class OptionalOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Operator* op_;
|
const Operator* const op_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Supported float64 to int32 truncation modes.
|
||||||
|
enum class TruncationMode : uint8_t {
|
||||||
|
kJavaScript, // ES6 section 7.1.5
|
||||||
|
kRoundToZero // Round towards zero. Implementation defined for NaN and ovf.
|
||||||
|
};
|
||||||
|
|
||||||
|
V8_INLINE size_t hash_value(TruncationMode mode) {
|
||||||
|
return static_cast<uint8_t>(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream&, TruncationMode);
|
||||||
|
|
||||||
|
TruncationMode TruncationModeOf(Operator const*);
|
||||||
|
|
||||||
|
|
||||||
// Supported write barrier modes.
|
// Supported write barrier modes.
|
||||||
enum WriteBarrierKind { kNoWriteBarrier, kFullWriteBarrier };
|
enum WriteBarrierKind { kNoWriteBarrier, kFullWriteBarrier };
|
||||||
|
|
||||||
@ -175,7 +192,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
|||||||
// These operators truncate numbers, both changing the representation of
|
// These operators truncate numbers, both changing the representation of
|
||||||
// the number and mapping multiple input values onto the same output value.
|
// the number and mapping multiple input values onto the same output value.
|
||||||
const Operator* TruncateFloat64ToFloat32();
|
const Operator* TruncateFloat64ToFloat32();
|
||||||
const Operator* TruncateFloat64ToInt32(); // JavaScript semantics.
|
const Operator* TruncateFloat64ToInt32(TruncationMode);
|
||||||
const Operator* TruncateInt64ToInt32();
|
const Operator* TruncateInt64ToInt32();
|
||||||
|
|
||||||
// Floating point operators always operate with IEEE 754 round-to-nearest
|
// Floating point operators always operate with IEEE 754 round-to-nearest
|
||||||
|
@ -391,6 +391,17 @@ void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, kArchTruncateDoubleToI, node);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRR(this, kMipsTruncWD, node);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Add(Node* node) {
|
void InstructionSelector::VisitFloat32Add(Node* node) {
|
||||||
VisitRRR(this, kMipsAddS, node);
|
VisitRRR(this, kMipsAddS, node);
|
||||||
}
|
}
|
||||||
|
@ -539,6 +539,17 @@ void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, kArchTruncateDoubleToI, node);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRR(this, kMips64TruncWD, node);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Add(Node* node) {
|
void InstructionSelector::VisitFloat32Add(Node* node) {
|
||||||
VisitRRR(this, kMips64AddS, node);
|
VisitRRR(this, kMips64AddS, node);
|
||||||
}
|
}
|
||||||
|
@ -412,8 +412,8 @@ class RawMachineAssembler : public GraphBuilder {
|
|||||||
Node* TruncateFloat64ToFloat32(Node* a) {
|
Node* TruncateFloat64ToFloat32(Node* a) {
|
||||||
return NewNode(machine()->TruncateFloat64ToFloat32(), a);
|
return NewNode(machine()->TruncateFloat64ToFloat32(), a);
|
||||||
}
|
}
|
||||||
Node* TruncateFloat64ToInt32(Node* a) {
|
Node* TruncateFloat64ToInt32(TruncationMode mode, Node* a) {
|
||||||
return NewNode(machine()->TruncateFloat64ToInt32(), a);
|
return NewNode(machine()->TruncateFloat64ToInt32(mode), a);
|
||||||
}
|
}
|
||||||
Node* TruncateInt64ToInt32(Node* a) {
|
Node* TruncateInt64ToInt32(Node* a) {
|
||||||
return NewNode(machine()->TruncateInt64ToInt32(), a);
|
return NewNode(machine()->TruncateInt64ToInt32(), a);
|
||||||
|
@ -232,13 +232,13 @@ class RepresentationChanger {
|
|||||||
// Select the correct X -> Word32 truncation operator.
|
// Select the correct X -> Word32 truncation operator.
|
||||||
const Operator* op = NULL;
|
const Operator* op = NULL;
|
||||||
if (output_type & kRepFloat64) {
|
if (output_type & kRepFloat64) {
|
||||||
op = machine()->TruncateFloat64ToInt32();
|
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
|
||||||
} else if (output_type & kRepFloat32) {
|
} else if (output_type & kRepFloat32) {
|
||||||
node = InsertChangeFloat32ToFloat64(node);
|
node = InsertChangeFloat32ToFloat64(node);
|
||||||
op = machine()->TruncateFloat64ToInt32();
|
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
|
||||||
} else if (output_type & kRepTagged) {
|
} else if (output_type & kRepTagged) {
|
||||||
node = InsertChangeTaggedToFloat64(node);
|
node = InsertChangeTaggedToFloat64(node);
|
||||||
op = machine()->TruncateFloat64ToInt32();
|
op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
|
||||||
} else {
|
} else {
|
||||||
return TypeError(node, output_type, kRepWord32);
|
return TypeError(node, output_type, kRepWord32);
|
||||||
}
|
}
|
||||||
|
@ -727,8 +727,10 @@ class RepresentationSelector {
|
|||||||
// Require the input in float64 format and perform truncation.
|
// Require the input in float64 format and perform truncation.
|
||||||
// TODO(turbofan): avoid a truncation with a smi check.
|
// TODO(turbofan): avoid a truncation with a smi check.
|
||||||
VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
|
VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
|
||||||
if (lower())
|
if (lower()) {
|
||||||
node->set_op(lowering->machine()->TruncateFloat64ToInt32());
|
node->set_op(lowering->machine()->TruncateFloat64ToInt32(
|
||||||
|
TruncationMode::kJavaScript));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -755,8 +757,10 @@ class RepresentationSelector {
|
|||||||
// Require the input in float64 format and perform truncation.
|
// Require the input in float64 format and perform truncation.
|
||||||
// TODO(turbofan): avoid a truncation with a smi check.
|
// TODO(turbofan): avoid a truncation with a smi check.
|
||||||
VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
|
VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
|
||||||
if (lower())
|
if (lower()) {
|
||||||
node->set_op(lowering->machine()->TruncateFloat64ToInt32());
|
node->set_op(lowering->machine()->TruncateFloat64ToInt32(
|
||||||
|
TruncationMode::kJavaScript));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1008,6 +1012,9 @@ class RepresentationSelector {
|
|||||||
case IrOpcode::kTruncateFloat64ToFloat32:
|
case IrOpcode::kTruncateFloat64ToFloat32:
|
||||||
return VisitUnop(node, kTypeNumber | kRepFloat64,
|
return VisitUnop(node, kTypeNumber | kRepFloat64,
|
||||||
kTypeNumber | kRepFloat32);
|
kTypeNumber | kRepFloat32);
|
||||||
|
case IrOpcode::kTruncateFloat64ToInt32:
|
||||||
|
return VisitUnop(node, kTypeNumber | kRepFloat64,
|
||||||
|
kTypeInt32 | kRepWord32);
|
||||||
case IrOpcode::kTruncateInt64ToInt32:
|
case IrOpcode::kTruncateInt64ToInt32:
|
||||||
// TODO(titzer): Is kTypeInt32 correct here?
|
// TODO(titzer): Is kTypeInt32 correct here?
|
||||||
return VisitUnop(node, kTypeInt32 | kRepWord64,
|
return VisitUnop(node, kTypeInt32 | kRepWord64,
|
||||||
|
@ -818,37 +818,23 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
|
||||||
X64OperandGenerator g(this);
|
|
||||||
Emit(kSSEFloat64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
|
|
||||||
X64OperandGenerator g(this);
|
|
||||||
Node* value = node->InputAt(0);
|
|
||||||
if (CanCover(node, value)) {
|
|
||||||
switch (value->opcode()) {
|
|
||||||
case IrOpcode::kWord64Sar:
|
|
||||||
case IrOpcode::kWord64Shr: {
|
|
||||||
Int64BinopMatcher m(value);
|
|
||||||
if (m.right().Is(32)) {
|
|
||||||
Emit(kX64Shr, g.DefineSameAsFirst(node),
|
|
||||||
g.UseRegister(m.left().node()), g.TempImmediate(32));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void VisitRO(InstructionSelector* selector, Node* node,
|
||||||
|
InstructionCode opcode) {
|
||||||
|
X64OperandGenerator g(selector);
|
||||||
|
selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VisitRR(InstructionSelector* selector, Node* node,
|
||||||
|
InstructionCode opcode) {
|
||||||
|
X64OperandGenerator g(selector);
|
||||||
|
selector->Emit(opcode, g.DefineAsRegister(node),
|
||||||
|
g.UseRegister(node->InputAt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VisitFloatBinop(InstructionSelector* selector, Node* node,
|
void VisitFloatBinop(InstructionSelector* selector, Node* node,
|
||||||
ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
|
ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
|
||||||
X64OperandGenerator g(selector);
|
X64OperandGenerator g(selector);
|
||||||
@ -872,10 +858,48 @@ void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
|
||||||
|
VisitRO(this, node, kSSEFloat64ToFloat32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
|
||||||
|
switch (TruncationModeOf(node->op())) {
|
||||||
|
case TruncationMode::kJavaScript:
|
||||||
|
return VisitRR(this, node, kArchTruncateDoubleToI);
|
||||||
|
case TruncationMode::kRoundToZero:
|
||||||
|
return VisitRO(this, node, kSSEFloat64ToInt32);
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
|
||||||
|
X64OperandGenerator g(this);
|
||||||
|
Node* value = node->InputAt(0);
|
||||||
|
if (CanCover(node, value)) {
|
||||||
|
switch (value->opcode()) {
|
||||||
|
case IrOpcode::kWord64Sar:
|
||||||
|
case IrOpcode::kWord64Shr: {
|
||||||
|
Int64BinopMatcher m(value);
|
||||||
|
if (m.right().Is(32)) {
|
||||||
|
Emit(kX64Shr, g.DefineSameAsFirst(node),
|
||||||
|
g.UseRegister(m.left().node()), g.TempImmediate(32));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Add(Node* node) {
|
void InstructionSelector::VisitFloat32Add(Node* node) {
|
||||||
VisitFloatBinop(this, node, kAVXFloat32Add, kSSEFloat32Add);
|
VisitFloatBinop(this, node, kAVXFloat32Add, kSSEFloat32Add);
|
||||||
}
|
}
|
||||||
@ -914,14 +938,12 @@ void InstructionSelector::VisitFloat32Min(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Abs(Node* node) {
|
void InstructionSelector::VisitFloat32Abs(Node* node) {
|
||||||
X64OperandGenerator g(this);
|
|
||||||
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
|
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||||
X64OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat32Sqrt);
|
||||||
Emit(kSSEFloat32Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -984,37 +1006,22 @@ void InstructionSelector::VisitFloat64Min(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64Abs(Node* node) {
|
void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||||
X64OperandGenerator g(this);
|
|
||||||
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
|
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
|
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
|
||||||
X64OperandGenerator g(this);
|
VisitRO(this, node, kSSEFloat64Sqrt);
|
||||||
Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void VisitRRFloat64(InstructionSelector* selector, InstructionCode opcode,
|
|
||||||
Node* node) {
|
|
||||||
X64OperandGenerator g(selector);
|
|
||||||
selector->Emit(opcode, g.DefineAsRegister(node),
|
|
||||||
g.UseRegister(node->InputAt(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64RoundDown(Node* node) {
|
void InstructionSelector::VisitFloat64RoundDown(Node* node) {
|
||||||
VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundDown), node);
|
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
|
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
|
||||||
VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundToZero),
|
VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
|
||||||
node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4840,7 +4840,8 @@ TEST(RunTruncateFloat64ToInt32P) {
|
|||||||
{-1.7976931348623157e+308, 0}};
|
{-1.7976931348623157e+308, 0}};
|
||||||
double input = -1.0;
|
double input = -1.0;
|
||||||
RawMachineAssemblerTester<int32_t> m;
|
RawMachineAssemblerTester<int32_t> m;
|
||||||
m.Return(m.TruncateFloat64ToInt32(m.LoadFromPointer(&input, kMachFloat64)));
|
m.Return(m.TruncateFloat64ToInt32(TruncationMode::kJavaScript,
|
||||||
|
m.LoadFromPointer(&input, kMachFloat64)));
|
||||||
for (size_t i = 0; i < arraysize(kValues); ++i) {
|
for (size_t i = 0; i < arraysize(kValues); ++i) {
|
||||||
input = kValues[i].from;
|
input = kValues[i].from;
|
||||||
uint64_t expected = static_cast<int64_t>(kValues[i].raw);
|
uint64_t expected = static_cast<int64_t>(kValues[i].raw);
|
||||||
|
@ -207,7 +207,8 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
|
|||||||
|
|
||||||
TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
|
TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
|
||||||
StreamBuilder m(this, kMachInt32, kMachFloat64);
|
StreamBuilder m(this, kMachInt32, kMachFloat64);
|
||||||
m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
|
m.Return(
|
||||||
|
m.TruncateFloat64ToInt32(TruncationMode::kJavaScript, m.Parameter(0)));
|
||||||
Stream s = m.Build(kAllInstructions);
|
Stream s = m.Build(kAllInstructions);
|
||||||
ASSERT_EQ(4U, s.size());
|
ASSERT_EQ(4U, s.size());
|
||||||
EXPECT_EQ(kArchNop, s[0]->arch_opcode());
|
EXPECT_EQ(kArchNop, s[0]->arch_opcode());
|
||||||
|
@ -234,6 +234,10 @@ const uint32_t kUint32Values[] = {
|
|||||||
0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
|
0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
|
||||||
|
|
||||||
|
|
||||||
|
const TruncationMode kTruncationModes[] = {TruncationMode::kJavaScript,
|
||||||
|
TruncationMode::kRoundToZero};
|
||||||
|
|
||||||
|
|
||||||
struct ComparisonBinaryOperator {
|
struct ComparisonBinaryOperator {
|
||||||
const Operator* (MachineOperatorBuilder::*constructor)();
|
const Operator* (MachineOperatorBuilder::*constructor)();
|
||||||
const char* constructor_name;
|
const char* constructor_name;
|
||||||
@ -257,53 +261,6 @@ const ComparisonBinaryOperator kComparisonBinaryOperators[] = {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Unary operators
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct UnaryOperator {
|
|
||||||
const Operator* (MachineOperatorBuilder::*constructor)();
|
|
||||||
const char* constructor_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
|
|
||||||
return os << unop.constructor_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const UnaryOperator kUnaryOperators[] = {
|
|
||||||
{&MachineOperatorBuilder::ChangeInt32ToFloat64, "ChangeInt32ToFloat64"},
|
|
||||||
{&MachineOperatorBuilder::ChangeUint32ToFloat64, "ChangeUint32ToFloat64"},
|
|
||||||
{&MachineOperatorBuilder::ChangeFloat64ToInt32, "ChangeFloat64ToInt32"},
|
|
||||||
{&MachineOperatorBuilder::ChangeFloat64ToUint32, "ChangeFloat64ToUint32"},
|
|
||||||
{&MachineOperatorBuilder::ChangeInt32ToInt64, "ChangeInt32ToInt64"},
|
|
||||||
{&MachineOperatorBuilder::ChangeUint32ToUint64, "ChangeUint32ToUint64"},
|
|
||||||
{&MachineOperatorBuilder::TruncateFloat64ToInt32, "TruncateFloat64ToInt32"},
|
|
||||||
{&MachineOperatorBuilder::TruncateInt64ToInt32, "TruncateInt64ToInt32"}};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
|
|
||||||
typedef MachineOperatorReducerTestWithParam<UnaryOperator>
|
|
||||||
MachineUnaryOperatorReducerTest;
|
|
||||||
|
|
||||||
|
|
||||||
TEST_P(MachineUnaryOperatorReducerTest, Parameter) {
|
|
||||||
const UnaryOperator unop = GetParam();
|
|
||||||
Reduction reduction =
|
|
||||||
Reduce(graph()->NewNode((machine()->*unop.constructor)(), Parameter(0)));
|
|
||||||
EXPECT_FALSE(reduction.Changed());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest,
|
|
||||||
MachineUnaryOperatorReducerTest,
|
|
||||||
::testing::ValuesIn(kUnaryOperators));
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// ChangeFloat64ToFloat32
|
// ChangeFloat64ToFloat32
|
||||||
|
|
||||||
@ -459,19 +416,22 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
|
|||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest,
|
TEST_F(MachineOperatorReducerTest,
|
||||||
TruncateFloat64ToInt32WithChangeInt32ToFloat64) {
|
TruncateFloat64ToInt32WithChangeInt32ToFloat64) {
|
||||||
|
TRACED_FOREACH(TruncationMode, mode, kTruncationModes) {
|
||||||
Node* value = Parameter(0);
|
Node* value = Parameter(0);
|
||||||
Reduction reduction = Reduce(graph()->NewNode(
|
Reduction reduction = Reduce(graph()->NewNode(
|
||||||
machine()->TruncateFloat64ToInt32(),
|
machine()->TruncateFloat64ToInt32(mode),
|
||||||
graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
|
graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
|
||||||
ASSERT_TRUE(reduction.Changed());
|
ASSERT_TRUE(reduction.Changed());
|
||||||
EXPECT_EQ(value, reduction.replacement());
|
EXPECT_EQ(value, reduction.replacement());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) {
|
TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) {
|
||||||
TRACED_FOREACH(double, x, kFloat64Values) {
|
TRACED_FOREACH(double, x, kFloat64Values) {
|
||||||
Reduction reduction = Reduce(graph()->NewNode(
|
Reduction reduction = Reduce(graph()->NewNode(
|
||||||
machine()->TruncateFloat64ToInt32(), Float64Constant(x)));
|
machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript),
|
||||||
|
Float64Constant(x)));
|
||||||
ASSERT_TRUE(reduction.Changed());
|
ASSERT_TRUE(reduction.Changed());
|
||||||
EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x)));
|
EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x)));
|
||||||
}
|
}
|
||||||
@ -482,14 +442,16 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithPhi) {
|
|||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
Node* const p1 = Parameter(1);
|
Node* const p1 = Parameter(1);
|
||||||
Node* const merge = graph()->start();
|
Node* const merge = graph()->start();
|
||||||
|
TRACED_FOREACH(TruncationMode, mode, kTruncationModes) {
|
||||||
Reduction reduction = Reduce(graph()->NewNode(
|
Reduction reduction = Reduce(graph()->NewNode(
|
||||||
machine()->TruncateFloat64ToInt32(),
|
machine()->TruncateFloat64ToInt32(mode),
|
||||||
graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge)));
|
graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge)));
|
||||||
ASSERT_TRUE(reduction.Changed());
|
ASSERT_TRUE(reduction.Changed());
|
||||||
EXPECT_THAT(reduction.replacement(),
|
EXPECT_THAT(reduction.replacement(),
|
||||||
IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0),
|
IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0),
|
||||||
IsTruncateFloat64ToInt32(p1), merge));
|
IsTruncateFloat64ToInt32(p1), merge));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -224,7 +224,6 @@ const PureOperator kPureOperators[] = {
|
|||||||
PURE(ChangeUint32ToFloat64, 1, 0, 1), // --
|
PURE(ChangeUint32ToFloat64, 1, 0, 1), // --
|
||||||
PURE(ChangeUint32ToUint64, 1, 0, 1), // --
|
PURE(ChangeUint32ToUint64, 1, 0, 1), // --
|
||||||
PURE(TruncateFloat64ToFloat32, 1, 0, 1), // --
|
PURE(TruncateFloat64ToFloat32, 1, 0, 1), // --
|
||||||
PURE(TruncateFloat64ToInt32, 1, 0, 1), // --
|
|
||||||
PURE(TruncateInt64ToInt32, 1, 0, 1), // --
|
PURE(TruncateInt64ToInt32, 1, 0, 1), // --
|
||||||
PURE(Float32Abs, 1, 0, 1), // --
|
PURE(Float32Abs, 1, 0, 1), // --
|
||||||
PURE(Float32Add, 2, 0, 1), // --
|
PURE(Float32Add, 2, 0, 1), // --
|
||||||
|
Loading…
Reference in New Issue
Block a user