Bias commutative single-use register inputs and support lea adds
This improves register allocation for many common add and multiply patterns on ia32 and x64 by reducing register pressure. R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/14856015 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14587 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
75d939aceb
commit
bd9274436c
@ -1305,8 +1305,8 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
return DefineAsRegister(new(zone()) LBitI(left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
@ -1484,15 +1484,15 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left;
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* right = UseOrConstant(instr->BetterRightOperand());
|
||||
LOperand* temp = NULL;
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
||||
(instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
!right->IsConstantOperand())) {
|
||||
left = UseRegister(instr->LeastConstantOperand());
|
||||
left = UseRegister(instr->BetterLeftOperand());
|
||||
temp = TempRegister();
|
||||
} else {
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
}
|
||||
LMulI* mul = new(zone()) LMulI(left, right, temp);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
@ -1602,8 +1602,8 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
LAddI* add = new(zone()) LAddI(left, right);
|
||||
LInstruction* result = DefineAsRegister(add);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
@ -1634,8 +1634,8 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
} else {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
|
@ -3357,16 +3357,27 @@ class HBinaryOperation: public HTemplateInstruction<3> {
|
||||
HValue* left() { return OperandAt(1); }
|
||||
HValue* right() { return OperandAt(2); }
|
||||
|
||||
// TODO(kasperl): Move these helpers to the IA-32 Lithium
|
||||
// instruction sequence builder.
|
||||
HValue* LeastConstantOperand() {
|
||||
if (IsCommutative() && left()->IsConstant()) return right();
|
||||
return left();
|
||||
// True if switching left and right operands likely generates better code.
|
||||
bool AreOperandsBetterSwitched() {
|
||||
if (!IsCommutative()) return false;
|
||||
|
||||
// Constant operands are better off on the right, they can be inlined in
|
||||
// many situations on most platforms.
|
||||
if (left()->IsConstant()) return true;
|
||||
if (right()->IsConstant()) return false;
|
||||
|
||||
// Otherwise, if there is only one use of the right operand, it would be
|
||||
// better off on the left for platforms that only have 2-arg arithmetic
|
||||
// ops (e.g ia32, x64) that clobber the left operand.
|
||||
return (right()->UseCount() == 1);
|
||||
}
|
||||
|
||||
HValue* MostConstantOperand() {
|
||||
if (IsCommutative() && left()->IsConstant()) return left();
|
||||
return right();
|
||||
HValue* BetterLeftOperand() {
|
||||
return AreOperandsBetterSwitched() ? right() : left();
|
||||
}
|
||||
|
||||
HValue* BetterRightOperand() {
|
||||
return AreOperandsBetterSwitched() ? left() : right();
|
||||
}
|
||||
|
||||
void set_observed_input_representation(int index, Representation rep) {
|
||||
|
@ -1906,16 +1906,24 @@ void LCodeGen::DoThrow(LThrow* instr) {
|
||||
void LCodeGen::DoAddI(LAddI* instr) {
|
||||
LOperand* left = instr->left();
|
||||
LOperand* right = instr->right();
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
|
||||
if (right->IsConstantOperand()) {
|
||||
__ add(ToOperand(left), ToInteger32Immediate(right));
|
||||
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
|
||||
if (right->IsConstantOperand()) {
|
||||
int32_t offset = ToInteger32(LConstantOperand::cast(right));
|
||||
__ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
|
||||
} else {
|
||||
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
|
||||
__ lea(ToRegister(instr->result()), address);
|
||||
}
|
||||
} else {
|
||||
__ add(ToRegister(left), ToOperand(right));
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
||||
DeoptimizeIf(overflow, instr->environment());
|
||||
if (right->IsConstantOperand()) {
|
||||
__ add(ToOperand(left), ToInteger32Immediate(right));
|
||||
} else {
|
||||
__ add(ToRegister(left), ToOperand(right));
|
||||
}
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
||||
DeoptimizeIf(overflow, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -834,8 +834,8 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
ASSERT(instr->right()->representation().IsDouble());
|
||||
ASSERT(op != Token::MOD);
|
||||
LOperand* left = UseRegisterAtStart(instr->left());
|
||||
LOperand* right = UseRegisterAtStart(instr->right());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
|
||||
LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
|
||||
return DefineSameAsFirst(result);
|
||||
}
|
||||
@ -1392,8 +1392,8 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
return DefineSameAsFirst(new(zone()) LBitI(left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
@ -1560,8 +1560,8 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstant(instr->BetterRightOperand());
|
||||
LOperand* temp = NULL;
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
temp = TempRegister();
|
||||
@ -1604,13 +1604,24 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
|
||||
|
||||
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
// Check to see if it would be advantageous to use an lea instruction rather
|
||||
// than an add. This is the case when no overflow check is needed and there
|
||||
// are multiple uses of the add's inputs, so using a 3-register add will
|
||||
// preserve all input values for later uses.
|
||||
bool use_lea = LAddI::UseLea(instr);
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
HValue* right_candidate = instr->BetterRightOperand();
|
||||
LOperand* right = use_lea
|
||||
? UseRegisterOrConstantAtStart(right_candidate)
|
||||
: UseOrConstantAtStart(right_candidate);
|
||||
LAddI* add = new(zone()) LAddI(left, right);
|
||||
LInstruction* result = DefineSameAsFirst(add);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
|
||||
LInstruction* result = use_lea
|
||||
? DefineAsRegister(add)
|
||||
: DefineSameAsFirst(add);
|
||||
if (can_overflow) {
|
||||
result = AssignEnvironment(result);
|
||||
}
|
||||
return result;
|
||||
@ -1629,8 +1640,8 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
} else {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
|
@ -1369,6 +1369,11 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
LOperand* left() { return inputs_[0]; }
|
||||
LOperand* right() { return inputs_[1]; }
|
||||
|
||||
static bool UseLea(HAdd* add) {
|
||||
return !add->CheckFlag(HValue::kCanOverflow) &&
|
||||
add->BetterLeftOperand()->UseCount() > 1;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
|
||||
DECLARE_HYDROGEN_ACCESSOR(Add)
|
||||
};
|
||||
|
@ -1306,8 +1306,8 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
return DefineAsRegister(new(zone()) LBitI(left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
@ -1402,15 +1402,15 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left;
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* right = UseOrConstant(instr->BetterRightOperand());
|
||||
LOperand* temp = NULL;
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
||||
(instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
!right->IsConstantOperand())) {
|
||||
left = UseRegister(instr->LeastConstantOperand());
|
||||
left = UseRegister(instr->BetterLeftOperand());
|
||||
temp = TempRegister();
|
||||
} else {
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
}
|
||||
LMulI* mul = new(zone()) LMulI(left, right, temp);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
@ -1475,8 +1475,8 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
LAddI* add = new(zone()) LAddI(left, right);
|
||||
LInstruction* result = DefineAsRegister(add);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
@ -1507,8 +1507,8 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
} else {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
|
@ -1674,19 +1674,27 @@ void LCodeGen::DoThrow(LThrow* instr) {
|
||||
void LCodeGen::DoAddI(LAddI* instr) {
|
||||
LOperand* left = instr->left();
|
||||
LOperand* right = instr->right();
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
|
||||
if (right->IsConstantOperand()) {
|
||||
__ addl(ToRegister(left),
|
||||
Immediate(ToInteger32(LConstantOperand::cast(right))));
|
||||
} else if (right->IsRegister()) {
|
||||
__ addl(ToRegister(left), ToRegister(right));
|
||||
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
|
||||
if (right->IsConstantOperand()) {
|
||||
int32_t offset = ToInteger32(LConstantOperand::cast(right));
|
||||
__ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
|
||||
} else {
|
||||
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
|
||||
__ lea(ToRegister(instr->result()), address);
|
||||
}
|
||||
} else {
|
||||
__ addl(ToRegister(left), ToOperand(right));
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
||||
DeoptimizeIf(overflow, instr->environment());
|
||||
if (right->IsConstantOperand()) {
|
||||
__ addl(ToRegister(left),
|
||||
Immediate(ToInteger32(LConstantOperand::cast(right))));
|
||||
} else if (right->IsRegister()) {
|
||||
__ addl(ToRegister(left), ToRegister(right));
|
||||
} else {
|
||||
__ addl(ToRegister(left), ToOperand(right));
|
||||
}
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
||||
DeoptimizeIf(overflow, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,8 +782,8 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
ASSERT(instr->right()->representation().IsDouble());
|
||||
ASSERT(op != Token::MOD);
|
||||
LOperand* left = UseRegisterAtStart(instr->left());
|
||||
LOperand* right = UseRegisterAtStart(instr->right());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
|
||||
LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
|
||||
return DefineSameAsFirst(result);
|
||||
}
|
||||
@ -1309,8 +1309,8 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
return DefineSameAsFirst(new(zone()) LBitI(left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
@ -1473,8 +1473,8 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
LOperand* right = UseOrConstant(instr->BetterRightOperand());
|
||||
LMulI* mul = new(zone()) LMulI(left, right);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
@ -1513,13 +1513,24 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
|
||||
|
||||
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
// Check to see if it would be advantageous to use an lea instruction rather
|
||||
// than an add. This is the case when no overflow check is needed and there
|
||||
// are multiple uses of the add's inputs, so using a 3-register add will
|
||||
// preserve all input values for later uses.
|
||||
bool use_lea = LAddI::UseLea(instr);
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
HValue* right_candidate = instr->BetterRightOperand();
|
||||
LOperand* right = use_lea
|
||||
? UseRegisterOrConstantAtStart(right_candidate)
|
||||
: UseOrConstantAtStart(right_candidate);
|
||||
LAddI* add = new(zone()) LAddI(left, right);
|
||||
LInstruction* result = DefineSameAsFirst(add);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
|
||||
LInstruction* result = use_lea
|
||||
? DefineAsRegister(add)
|
||||
: DefineSameAsFirst(add);
|
||||
if (can_overflow) {
|
||||
result = AssignEnvironment(result);
|
||||
}
|
||||
return result;
|
||||
@ -1539,8 +1550,8 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
left = UseRegisterAtStart(instr->BetterLeftOperand());
|
||||
right = UseOrConstantAtStart(instr->BetterRightOperand());
|
||||
} else {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->left()->representation().IsDouble());
|
||||
|
@ -1345,6 +1345,11 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
|
||||
LOperand* left() { return inputs_[0]; }
|
||||
LOperand* right() { return inputs_[1]; }
|
||||
|
||||
static bool UseLea(HAdd* add) {
|
||||
return !add->CheckFlag(HValue::kCanOverflow) &&
|
||||
add->BetterLeftOperand()->UseCount() > 1;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
|
||||
DECLARE_HYDROGEN_ACCESSOR(Add)
|
||||
};
|
||||
|
84
test/mjsunit/lea-add.js
Normal file
84
test/mjsunit/lea-add.js
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function a() {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 500; ++i) {
|
||||
sum = (i + sum) | 0;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
function b() {
|
||||
var sum = 0;
|
||||
for (var i = -500; i < 0; ++i) {
|
||||
sum = (i + sum) | 0;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
function c() {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 500; ++i) {
|
||||
sum += (i + -0x7fffffff) | 0;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
function d() {
|
||||
var sum = 0;
|
||||
for (var i = -501; i < 0; ++i) {
|
||||
sum += (i + 501) | 0;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
a();
|
||||
a();
|
||||
%OptimizeFunctionOnNextCall(a);
|
||||
assertEquals(124750, a());
|
||||
assertEquals(124750, a());
|
||||
|
||||
b();
|
||||
b();
|
||||
%OptimizeFunctionOnNextCall(b);
|
||||
assertEquals(-125250, b());
|
||||
assertEquals(-125250, b());
|
||||
|
||||
c();
|
||||
c();
|
||||
%OptimizeFunctionOnNextCall(c);
|
||||
assertEquals(-1073741698750, c());
|
||||
assertEquals(-1073741698750, c());
|
||||
|
||||
d();
|
||||
d();
|
||||
%OptimizeFunctionOnNextCall(d);
|
||||
assertEquals(125250, d());
|
||||
assertEquals(125250, d());
|
Loading…
Reference in New Issue
Block a user