Commit b5d50296 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Optimize truncated safe integer multiplications.

For a * b with only truncated word32 uses (or result known to be in
signed32 range), we can use Int32Mul if we know for sure that the
intermediate result is inside the safe integer range, and a and b are
in signed32 range.

Drive-by-fix: Also use TypeCache in SimplifiedLowering.

R=jarin@chromium.org

Review URL: https://codereview.chromium.org/1478953002

Cr-Commit-Position: refs/heads/master@{#32330}
parent c82bbf31
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/compiler/source-position.h" #include "src/compiler/source-position.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/type-cache.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -195,10 +196,8 @@ class RepresentationSelector { ...@@ -195,10 +196,8 @@ class RepresentationSelector {
phase_(PROPAGATE), phase_(PROPAGATE),
changer_(changer), changer_(changer),
queue_(zone), queue_(zone),
source_positions_(source_positions) { source_positions_(source_positions),
safe_int_additive_range_ = type_cache_(TypeCache::Get()) {}
Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone);
}
void Run(SimplifiedLowering* lowering) { void Run(SimplifiedLowering* lowering) {
// Run propagation phase to a fixpoint. // Run propagation phase to a fixpoint.
...@@ -567,11 +566,18 @@ class RepresentationSelector { ...@@ -567,11 +566,18 @@ class RepresentationSelector {
// TODO(jarin): we could support the uint32 case here, but that would // TODO(jarin): we could support the uint32 case here, but that would
// require setting kTypeUint32 as the output type. Eventually, we will want // require setting kTypeUint32 as the output type. Eventually, we will want
// to use only the big types, then this should work automatically. // to use only the big types, then this should work automatically.
return BothInputsAre(node, safe_int_additive_range_) && return BothInputsAre(node, type_cache_.kAdditiveSafeInteger) &&
(use.TruncatesToWord32() || (use.TruncatesToWord32() ||
NodeProperties::GetType(node)->Is(Type::Signed32())); NodeProperties::GetType(node)->Is(Type::Signed32()));
} }
bool CanLowerToInt32MultiplicativeBinop(Node* node, Truncation use) {
return BothInputsAre(node, Type::Signed32()) &&
(NodeProperties::GetType(node)->Is(Type::Signed32()) ||
(use.TruncatesToWord32() &&
NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger)));
}
// Dispatching routine for visiting the node {node} with the usage {use}. // Dispatching routine for visiting the node {node} with the usage {use}.
// Depending on the operator, propagate new usage info to the inputs. // Depending on the operator, propagate new usage info to the inputs.
void VisitNode(Node* node, Truncation truncation, void VisitNode(Node* node, Truncation truncation,
...@@ -709,18 +715,17 @@ class RepresentationSelector { ...@@ -709,18 +715,17 @@ class RepresentationSelector {
break; break;
} }
case IrOpcode::kNumberMultiply: { case IrOpcode::kNumberMultiply: {
NumberMatcher right(node->InputAt(1)); // Multiply reduces to Int32Mul if the inputs are
if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa. // already integers and all uses are truncating.
if (CanLowerToInt32Binop(node, truncation)) { if (CanLowerToInt32MultiplicativeBinop(node, truncation)) {
// => signed Int32Mul // => signed Int32Mul
VisitInt32Binop(node); VisitInt32Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
break; } else {
}
}
// => Float64Mul // => Float64Mul
VisitFloat64Binop(node); VisitFloat64Binop(node);
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
}
break; break;
} }
case IrOpcode::kNumberDivide: { case IrOpcode::kNumberDivide: {
...@@ -1160,7 +1165,7 @@ class RepresentationSelector { ...@@ -1160,7 +1165,7 @@ class RepresentationSelector {
// lowering. Once this phase becomes a vanilla reducer, it should get source // lowering. Once this phase becomes a vanilla reducer, it should get source
// position information via the SourcePositionWrapper like all other reducers. // position information via the SourcePositionWrapper like all other reducers.
SourcePositionTable* source_positions_; SourcePositionTable* source_positions_;
Type* safe_int_additive_range_; TypeCache const& type_cache_;
NodeInfo* GetInfo(Node* node) { NodeInfo* GetInfo(Node* node) {
DCHECK(node->id() >= 0); DCHECK(node->id() >= 0);
...@@ -1174,7 +1179,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone, ...@@ -1174,7 +1179,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
SourcePositionTable* source_positions) SourcePositionTable* source_positions)
: jsgraph_(jsgraph), : jsgraph_(jsgraph),
zone_(zone), zone_(zone),
zero_thirtyone_range_(Type::Range(0, 31, zone)), type_cache_(TypeCache::Get()),
source_positions_(source_positions) {} source_positions_(source_positions) {}
...@@ -1555,7 +1560,7 @@ Node* SimplifiedLowering::Uint32Mod(Node* const node) { ...@@ -1555,7 +1560,7 @@ Node* SimplifiedLowering::Uint32Mod(Node* const node) {
void SimplifiedLowering::DoShift(Node* node, Operator const* op) { void SimplifiedLowering::DoShift(Node* node, Operator const* op) {
Node* const rhs = NodeProperties::GetValueInput(node, 1); Node* const rhs = NodeProperties::GetValueInput(node, 1);
Type* const rhs_type = NodeProperties::GetType(rhs); Type* const rhs_type = NodeProperties::GetType(rhs);
if (!rhs_type->Is(zero_thirtyone_range_)) { if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs, node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
jsgraph()->Int32Constant(0x1f))); jsgraph()->Int32Constant(0x1f)));
} }
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declarations.
class TypeCache;
namespace compiler { namespace compiler {
// Forward declarations. // Forward declarations.
...@@ -41,7 +46,7 @@ class SimplifiedLowering final { ...@@ -41,7 +46,7 @@ class SimplifiedLowering final {
private: private:
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Zone* const zone_; Zone* const zone_;
Type* const zero_thirtyone_range_; TypeCache const& type_cache_;
// TODO(danno): SimplifiedLowering shouldn't know anything about the source // TODO(danno): SimplifiedLowering shouldn't know anything about the source
// positions table, but must for now since there currently is no other way to // positions table, but must for now since there currently is no other way to
......
...@@ -42,6 +42,7 @@ class TypeCache final { ...@@ -42,6 +42,7 @@ class TypeCache final {
Type* const kSingletonZero = CreateRange(0.0, 0.0); Type* const kSingletonZero = CreateRange(0.0, 0.0);
Type* const kSingletonOne = CreateRange(1.0, 1.0); Type* const kSingletonOne = CreateRange(1.0, 1.0);
Type* const kZeroOrOne = CreateRange(0.0, 1.0); Type* const kZeroOrOne = CreateRange(0.0, 1.0);
Type* const kZeroToThirtyOne = CreateRange(0.0, 31.0);
Type* const kZeroToThirtyTwo = CreateRange(0.0, 32.0); Type* const kZeroToThirtyTwo = CreateRange(0.0, 32.0);
Type* const kZeroish = Type* const kZeroish =
Type::Union(kSingletonZero, Type::MinusZeroOrNaN(), zone()); Type::Union(kSingletonZero, Type::MinusZeroOrNaN(), zone());
...@@ -52,6 +53,9 @@ class TypeCache final { ...@@ -52,6 +53,9 @@ class TypeCache final {
Type* const kIntegerOrMinusZeroOrNaN = Type* const kIntegerOrMinusZeroOrNaN =
Type::Union(kIntegerOrMinusZero, Type::NaN(), zone()); Type::Union(kIntegerOrMinusZero, Type::NaN(), zone());
Type* const kAdditiveSafeInteger =
CreateRange(-4503599627370496.0, 4503599627370496.0);
Type* const kSafeInteger = CreateRange(-kMaxSafeInteger, kMaxSafeInteger);
Type* const kPositiveSafeInteger = CreateRange(0.0, kMaxSafeInteger); Type* const kPositiveSafeInteger = CreateRange(0.0, kMaxSafeInteger);
// Asm.js related types. // Asm.js related types.
......
...@@ -1605,22 +1605,6 @@ TEST(RunNumberDivide_minus_1_TruncatingToInt32) { ...@@ -1605,22 +1605,6 @@ TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
} }
TEST(NumberMultiply_TruncatingToInt32) {
int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000};
for (size_t i = 0; i < arraysize(constants); i++) {
TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(constants[i]);
Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
t.Return(trunc);
t.Lower();
CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode());
}
}
TEST(RunNumberMultiply_TruncatingToInt32) { TEST(RunNumberMultiply_TruncatingToInt32) {
int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999}; int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment