Commit 015f963e authored by titzer@chromium.org's avatar titzer@chromium.org

Lower NumberMultiply, NumberDivide, and NumberModulus to Int32Mul,...

Lower NumberMultiply, NumberDivide, and NumberModulus to Int32Mul, Int32[U]Div, and Int32[U]Mod when possible in simplified-lowering.

R=mstarzinger@chromium.org
BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24462 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent fd7fb06b
......@@ -8,6 +8,7 @@
#include "src/code-factory.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph-inl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties-inl.h"
#include "src/compiler/representation-change.h"
#include "src/compiler/simplified-lowering.h"
......@@ -354,6 +355,27 @@ class RepresentationSelector {
return changer_->Float64OperatorFor(node->opcode());
}
bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
}
bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
}
bool CanObserveNonInt32(MachineTypeUnion use) {
return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
}
bool CanObserveMinusZero(MachineTypeUnion use) {
// TODO(turbofan): technically Uint32 cannot observe minus zero either.
return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
}
bool CanObserveNonUint32(MachineTypeUnion use) {
return (use & (kTypeInt32 | kTypeNumber | kTypeAny)) != 0;
}
// Dispatching routine for visiting the node {node} with the usage {use}.
// Depending on the operator, propagate new usage info to the inputs.
void VisitNode(Node* node, MachineTypeUnion use,
......@@ -478,13 +500,11 @@ class RepresentationSelector {
case IrOpcode::kNumberSubtract: {
// Add and subtract reduce to Int32Add/Sub if the inputs
// are already integers and all uses are truncating.
if (BothInputsAre(node, Type::Signed32()) &&
(use & (kTypeUint32 | kTypeNumber | kTypeAny)) == 0) {
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Add/Sub
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
} else if (BothInputsAre(node, Type::Unsigned32()) &&
(use & (kTypeInt32 | kTypeNumber | kTypeAny)) == 0) {
} else if (CanLowerToUint32Binop(node, use)) {
// => unsigned Int32Add/Sub
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
......@@ -495,10 +515,58 @@ class RepresentationSelector {
}
break;
}
case IrOpcode::kNumberMultiply:
case IrOpcode::kNumberDivide:
case IrOpcode::kNumberMultiply: {
NumberMatcher right(node->InputAt(1));
if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Mul
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
break;
}
}
// => Float64Mul
VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node));
break;
}
case IrOpcode::kNumberDivide: {
NumberMatcher right(node->InputAt(1));
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Div
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
break;
} else if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Div
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
break;
}
}
// => Float64Div
VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node));
break;
}
case IrOpcode::kNumberModulus: {
// Float64Mul/Div/Mod
NumberMatcher right(node->InputAt(1));
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (BothInputsAre(node, Type::Signed32()) &&
!CanObserveMinusZero(use)) {
// => signed Int32Mod
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
break;
} else if (BothInputsAre(node, Type::Unsigned32())) {
// => unsigned Uint32Mod
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
break;
}
}
// => Float64Mod
VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node));
break;
......@@ -507,12 +575,16 @@ class RepresentationSelector {
MachineTypeUnion use_rep = use & kRepMask;
Node* input = node->InputAt(0);
MachineTypeUnion in = GetInfo(input)->output;
if (NodeProperties::GetBounds(input).upper->Is(Type::Signed32()) ||
(in & kTypeMask) == kTypeInt32 || (in & kRepMask) == kRepWord32) {
// If the input has type int32, or is already a word32, just change
// representation if necessary.
if (NodeProperties::GetBounds(input).upper->Is(Type::Signed32())) {
// If the input has type int32, pass through representation.
VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else if ((in & kTypeMask) == kTypeUint32 ||
(in & kTypeMask) == kTypeInt32 ||
(in & kRepMask) == kRepWord32) {
// Just change representation if necessary.
VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
// Require the input in float64 format and perform truncation.
// TODO(turbofan): avoid a truncation with a smi check.
......@@ -526,11 +598,16 @@ class RepresentationSelector {
MachineTypeUnion use_rep = use & kRepMask;
Node* input = node->InputAt(0);
MachineTypeUnion in = GetInfo(input)->output;
if (NodeProperties::GetBounds(input).upper->Is(Type::Unsigned32()) ||
(in & kTypeMask) == kTypeUint32) {
// If the input has type uint32, just change representation.
if (NodeProperties::GetBounds(input).upper->Is(Type::Unsigned32())) {
// If the input has type uint32, pass through representation.
VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else if ((in & kTypeMask) == kTypeUint32 ||
(in & kTypeMask) == kTypeInt32 ||
(in & kRepMask) == kRepWord32) {
// Just change representation if necessary.
VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
// Require the input in float64 format and perform truncation.
// TODO(turbofan): avoid a truncation with a smi check.
......@@ -744,6 +821,11 @@ class RepresentationSelector {
}
void DeferReplacement(Node* node, Node* replacement) {
if (FLAG_trace_representation) {
TRACE(("defer replacement #%d:%s with #%d:%s\n", node->id(),
node->op()->mnemonic(), replacement->id(),
replacement->op()->mnemonic()));
}
if (replacement->id() < count_) {
// Replace with a previously existing node eagerly.
node->ReplaceUses(replacement);
......
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i|0;
return i / 3 | 0;
}
function f2(i) {
i = i|0;
return i / 13 | 0;
}
function f3(i) {
i = i|0;
return i / 1024 | 0;
}
function f4(i) {
i = i|0;
return i / 3733331 | 0;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = -2147483648; i < 2147483648; i += 3999777) {
assertEquals(i / 3 | 0, m.f1(i));
assertEquals(i / 13 | 0, m.f2(i));
assertEquals(i / 1024 | 0, m.f3(i));
assertEquals(i / 3733331 | 0, m.f4(i));
}
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i|0;
return i % 3;
}
function f2(i) {
i = i|0;
return i % 9;
}
function f3(i) {
i = i|0;
return i % 1024;
}
function f4(i) {
i = i|0;
return i % 3133335;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = -2147483648; i < 2147483648; i += 3999773) {
assertEquals(i % 3, m.f1(i));
assertEquals(i % 9, m.f2(i));
assertEquals(i % 1024, m.f3(i));
assertEquals(i % 3133335, m.f4(i));
}
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i|0;
return i * 3 | 0;
}
function f2(i) {
i = i|0;
return i * 7 | 0;
}
function f3(i) {
i = i|0;
return i * 1024 | 0;
}
function f4(i) {
i = i|0;
return i * 3333339 | 0;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = -2147483648; i < 2147483648; i += 3999771) {
assertEquals(i * 3 | 0, m.f1(i));
assertEquals(i * 7 | 0, m.f2(i));
assertEquals(i * 1024 | 0, m.f3(i));
assertEquals(i * 3333339 | 0, m.f4(i));
}
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i|0;
return i % 3 | 0;
}
function f2(i) {
i = i|0;
return i % 9 | 0;
}
function f3(i) {
i = i|0;
return i % 1024 | 0;
}
function f4(i) {
i = i|0;
return i % 3333339 | 0;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = -2147483648; i < 2147483648; i += 3999773) {
assertEquals(i % 3 | 0, m.f1(i));
assertEquals(i % 9 | 0, m.f2(i));
assertEquals(i % 1024 | 0, m.f3(i));
assertEquals(i % 3333339 | 0, m.f4(i));
}
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i>>>0;
return i / 3 | 0;
}
function f2(i) {
i = i>>>0;
return i / 17 | 0;
}
function f3(i) {
i = i>>>0;
return i / 1024 | 0;
}
function f4(i) {
i = i>>>0;
return i / 3343330 | 0;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = 0; i < 4294967296; i += 3999777) {
assertEquals(i / 3 | 0, m.f1(i));
assertEquals(i / 17 | 0, m.f2(i));
assertEquals(i / 1024 | 0, m.f3(i));
assertEquals(i / 3343330 | 0, m.f4(i));
}
// Copyright 2014 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.
function Module(stdlib, foreign, heap) {
"use asm";
function f1(i) {
i = i>>>0;
return i % 3;
}
function f2(i) {
i = i>>>0;
return i % 11;
}
function f3(i) {
i = i>>>0;
return i % 1024;
}
function f4(i) {
i = i>>>0;
return i % 3333337;
}
return { f1: f1, f2: f2, f3: f3, f4: f4 };
}
var m = Module(this, {}, new ArrayBuffer(1024));
for (var i = 0; i < 4294967296; i += 3999777) {
assertEquals(i % 3, m.f1(i));
assertEquals(i % 11, m.f2(i));
assertEquals(i % 1024, m.f3(i));
assertEquals(i % 3333337, m.f4(i));
}
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