Fix uint32-to-smi conversion in Lithium

BUG=chromium:309623
R=vegorov@google.com, yangguo@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17441 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3cb584c2
......@@ -2014,8 +2014,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (to.IsSmi()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result =
DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
LInstruction* result = val->CheckFlag(HInstruction::kUint32)
? DefineSameAsFirst(new(zone()) LUint32ToSmi(value))
: DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
if (val->HasRange() && val->range()->IsInSmiRange()) {
return result;
}
......
......@@ -184,6 +184,7 @@ class LCodeGen;
V(Typeof) \
V(TypeofIsAndBranch) \
V(Uint32ToDouble) \
V(Uint32ToSmi) \
V(UnknownOSRValue) \
V(ValueOf) \
V(WrapReceiver)
......@@ -2074,6 +2075,19 @@ class LUint32ToDouble V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LUint32ToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LUint32ToSmi(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Uint32ToSmi, "uint32-to-smi")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LNumberTagI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LNumberTagI(LOperand* value) {
......
......@@ -4650,9 +4650,7 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister());
LOperand* output = instr->result();
ASSERT(output->IsRegister());
__ SmiTag(ToRegister(output), ToRegister(input), SetCC);
if (!instr->hydrogen()->value()->HasRange() ||
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
......@@ -4671,6 +4669,18 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
}
void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
LOperand* input = instr->value();
LOperand* output = instr->result();
if (!instr->hydrogen()->value()->HasRange() ||
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
__ tst(ToRegister(input), Operand(0xc0000000));
DeoptimizeIf(ne, instr->environment());
}
__ SmiTag(ToRegister(output), ToRegister(input));
}
void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
class DeferredNumberTagI V8_FINAL : public LDeferredCode {
public:
......
......@@ -35,8 +35,17 @@ bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) {
// Operations that operate on bits are safe.
if (use->IsBitwise() || use->IsShl() || use->IsSar() || use->IsShr()) {
return true;
} else if (use->IsChange() || use->IsSimulate()) {
// Conversions and deoptimization have special support for unt32.
} else if (use->IsSimulate()) {
// Deoptimization has special support for uint32.
return true;
} else if (use->IsChange()) {
// Conversions have special support for uint32.
// This ASSERT guards that the conversion in question is actually
// implemented. Do not extend the whitelist without adding
// support to LChunkBuilder::DoChange().
ASSERT(HChange::cast(use)->to().IsDouble() ||
HChange::cast(use)->to().IsSmi() ||
HChange::cast(use)->to().IsTagged());
return true;
} else if (use->IsStoreKeyed()) {
HStoreKeyed* store = HStoreKeyed::cast(use);
......
......@@ -5012,6 +5012,17 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
}
void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
Register input = ToRegister(instr->value());
if (!instr->hydrogen()->value()->HasRange() ||
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
__ test(input, Immediate(0xc0000000));
DeoptimizeIf(not_zero, instr->environment());
}
__ SmiTag(input);
}
void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
class DeferredNumberTagI V8_FINAL : public LDeferredCode {
public:
......
......@@ -2002,8 +2002,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (to.IsSmi()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result =
DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
LInstruction* result = val->CheckFlag(HInstruction::kUint32)
? DefineSameAsFirst(new(zone()) LUint32ToSmi(value))
: DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
if (val->HasRange() && val->range()->IsInSmiRange()) {
return result;
}
......
......@@ -183,6 +183,7 @@ class LCodeGen;
V(Typeof) \
V(TypeofIsAndBranch) \
V(Uint32ToDouble) \
V(Uint32ToSmi) \
V(UnknownOSRValue) \
V(ValueOf) \
V(WrapReceiver)
......@@ -2076,6 +2077,19 @@ class LUint32ToDouble V8_FINAL : public LTemplateInstruction<1, 1, 1> {
};
class LUint32ToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LUint32ToSmi(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Uint32ToSmi, "uint32-to-smi")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LNumberTagI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LNumberTagI(LOperand* value) {
......
......@@ -4421,6 +4421,22 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
}
void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister());
LOperand* output = instr->result();
if (!instr->hydrogen()->value()->HasRange() ||
!instr->hydrogen()->value()->range()->IsInSmiRange() ||
instr->hydrogen()->value()->range()->upper() == kMaxInt) {
// The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
// interval, so we treat kMaxInt as a sentinel for this entire interval.
__ testl(ToRegister(input), Immediate(0x80000000));
DeoptimizeIf(not_zero, instr->environment());
}
__ Integer32ToSmi(ToRegister(output), ToRegister(input));
}
void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister() && input->Equals(instr->result()));
......
......@@ -1883,10 +1883,18 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (to.IsSmi()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
LInstruction* result =
DefineAsRegister(new(zone()) LInteger32ToSmi(value));
if (val->HasRange() && val->range()->IsInSmiRange()) {
return result;
LInstruction* result = NULL;
if (val->CheckFlag(HInstruction::kUint32)) {
result = DefineAsRegister(new(zone()) LUint32ToSmi(value));
if (val->HasRange() && val->range()->IsInSmiRange() &&
val->range()->upper() != kMaxInt) {
return result;
}
} else {
result = DefineAsRegister(new(zone()) LInteger32ToSmi(value));
if (val->HasRange() && val->range()->IsInSmiRange()) {
return result;
}
}
return AssignEnvironment(result);
} else {
......
......@@ -181,6 +181,7 @@ class LCodeGen;
V(Typeof) \
V(TypeofIsAndBranch) \
V(Uint32ToDouble) \
V(Uint32ToSmi) \
V(UnknownOSRValue) \
V(ValueOf) \
V(WrapReceiver)
......@@ -1943,6 +1944,19 @@ class LUint32ToDouble V8_FINAL : public LTemplateInstruction<1, 1, 1> {
};
class LUint32ToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LUint32ToSmi(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(Uint32ToSmi, "uint32-to-smi")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
class LNumberTagI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LNumberTagI(LOperand* value) {
......
// 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
var u = new Uint32Array(2);
u[0] = 1;
u[1] = 0xEE6B2800;
var a = [0, 1, 2];
a[0] = 0; // Kill the COW.
assertTrue(%HasFastSmiElements(a));
function foo(i) {
a[0] = u[i];
return a[0];
}
assertEquals(u[0], foo(0));
assertEquals(u[0], foo(0));
%OptimizeFunctionOnNextCall(foo);
assertEquals(u[1], foo(1));
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