LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Representation from = instr->from();
Representation to = instr->to();
+ if (from.IsSmi()) {
+ if (to.IsTagged()) {
+ LOperand* value = UseRegister(instr->value());
+ return DefineSameAsFirst(new(zone()) LDummyUse(value));
+ }
+ from = Representation::Tagged();
+ }
if (from.IsTagged()) {
if (to.IsDouble()) {
info()->MarkAsDeferredCalling();
LOperand* value = UseRegister(instr->value());
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
return AssignEnvironment(DefineAsRegister(res));
+ } else if (to.IsSmi()) {
+ HValue* val = instr->value();
+ LOperand* value = UseRegisterAtStart(val);
+ return AssignEnvironment(
+ DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
LOperand* value = NULL;
LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
Define(result, result_temp);
return AssignPointerMap(result);
+ } else if (to.IsSmi()) {
+ LOperand* value = UseRegister(instr->value());
+ return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToSmi(value,
+ TempRegister(), TempRegister())));
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
LNumberTagI* result = new(zone()) LNumberTagI(value);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
+ } else if (to.IsSmi()) {
+ HValue* val = instr->value();
+ LOperand* value = UseRegister(val);
+ LInstruction* result =
+ DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
+ if (val->HasRange() && val->range()->IsInSmiRange()) {
+ return result;
+ }
+ return AssignEnvironment(result);
} else {
ASSERT(to.IsDouble());
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new(zone()) LConstantD);
- } else if (r.IsTagged()) {
+ } else if (r.IsTagged() || r.IsSmi()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
UNREACHABLE();
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(DoubleToSmi) \
V(DummyUse) \
V(ElementsKind) \
V(FixedArrayBaseLength) \
V(InstanceSize) \
V(InstructionGap) \
V(Integer32ToDouble) \
+ V(Integer32ToSmi) \
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
};
+class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LInteger32ToSmi(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> {
public:
explicit LUint32ToDouble(LOperand* value) {
};
+class LDoubleToSmi: public LTemplateInstruction<1, 1, 2> {
+ public:
+ LDoubleToSmi(LOperand* value, LOperand* temp, LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ temps_[1] = temp2;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+ bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
// Sometimes truncating conversion from a tagged value to an int32.
class LDoubleToI: public LTemplateInstruction<1, 1, 2> {
public:
};
-class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
+class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
- ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
+ ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
return constant->handle();
}
}
+bool LCodeGen::IsSmi(LConstantOperand* op) const {
+ return chunk_->LookupLiteralRepresentation(op).IsSmi();
+}
+
+
int LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
return constant->Integer32Value();
int false_block = chunk_->LookupDestination(instr->false_block_id());
Representation r = instr->hydrogen()->value()->representation();
- if (r.IsInteger32()) {
+ if (r.IsInteger32() || r.IsSmi()) {
Register reg = ToRegister(instr->value());
__ cmp(reg, Operand::Zero());
EmitBranch(true_block, false_block, ne);
Handle<Map> transition = instr->transition();
- if (FLAG_track_fields && representation.IsSmi()) {
- Register value = ToRegister(instr->value());
- __ SmiTag(value, value, SetCC);
- if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
- DeoptimizeIf(vs, instr->environment());
- }
- } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
+ if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
Register value = ToRegister(instr->value());
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ SmiTst(value);
}
+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()) {
+ DeoptimizeIf(vs, instr->environment());
+ }
+}
+
+
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
LOperand* input = instr->value();
LOperand* output = instr->result();
DwVfpRegister double_input = ToDoubleRegister(instr->value());
DwVfpRegister double_scratch = double_scratch0();
- Label done;
+ if (instr->truncating()) {
+ Register scratch3 = ToRegister(instr->temp2());
+ __ ECMAToInt32(result_reg, double_input,
+ scratch1, scratch2, scratch3, double_scratch);
+ } else {
+ __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
+ // Deoptimize if the input wasn't a int32 (inside a double).
+ DeoptimizeIf(ne, instr->environment());
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label done;
+ __ cmp(result_reg, Operand::Zero());
+ __ b(ne, &done);
+ __ vmov(scratch1, double_input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
+ }
+}
+
+
+void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
+ Register result_reg = ToRegister(instr->result());
+ Register scratch1 = scratch0();
+ Register scratch2 = ToRegister(instr->temp());
+ DwVfpRegister double_input = ToDoubleRegister(instr->value());
+ DwVfpRegister double_scratch = double_scratch0();
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
// Deoptimize if the input wasn't a int32 (inside a double).
DeoptimizeIf(ne, instr->environment());
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ Label done;
+ __ cmp(result_reg, Operand::Zero());
+ __ b(ne, &done);
+ __ vmov(scratch1, double_input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
}
- __ bind(&done);
+ __ SmiTag(result_reg, SetCC);
+ DeoptimizeIf(vs, instr->environment());
}
MemOperand ToHighMemOperand(LOperand* op) const;
bool IsInteger32(LConstantOperand* op) const;
+ bool IsSmi(LConstantOperand* op) const;
Handle<Object> ToHandle(LConstantOperand* op) const;
// Try to generate code for the entire chunk, but it may fail if the
Range* HChange::InferRange(Zone* zone) {
Range* input_range = value()->range();
if (from().IsInteger32() &&
- to().IsTagged() &&
+ to().IsSmiOrTagged() &&
!value()->CheckFlag(HInstruction::kUint32) &&
input_range != NULL && input_range->IsInSmiRange()) {
set_type(HType::Smi());
HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
if (hint_value != NULL) {
Representation hint = hint_value->representation();
- if (hint.IsTagged()) return hint;
+ if (hint.IsSmiOrTagged()) return hint;
if (hint.IsDouble()) double_occurred = true;
if (hint.IsInteger32()) int32_occurred = true;
}
}
if (value->representation().IsDouble()) double_occurred = true;
if (value->representation().IsInteger32()) int32_occurred = true;
- if (value->representation().IsTagged()) {
+ if (value->representation().IsSmiOrTagged()) {
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
if (constant->IsConvertibleToInteger()) {
if (FLAG_track_fields && field_representation.IsSmi()) {
set_type(HType::Smi());
- set_representation(Representation::Tagged());
+ set_representation(field_representation);
} else if (FLAG_track_double_fields && field_representation.IsDouble()) {
set_representation(field_representation);
} else if (FLAG_track_heap_object_fields &&
return field_representation_;
} else if (FLAG_track_fields &&
index == 1 && field_representation_.IsSmi()) {
- return Representation::Integer32();
+ return field_representation_;
}
return Representation::Tagged();
}
Representation from = change->value()->representation();
ASSERT(from.Equals(change->from()));
if (from.IsInteger32()) {
- ASSERT(change->to().IsTagged() || change->to().IsDouble());
+ ASSERT(change->to().IsTagged() ||
+ change->to().IsDouble() ||
+ change->to().IsSmi());
ASSERT(visited.IsEmpty());
PropagateMinusZeroChecks(change->value(), &visited);
visited.Clear();
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
- ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
+ ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
return constant->handle();
}
}
+bool LCodeGen::IsSmi(LConstantOperand* op) const {
+ return chunk_->LookupLiteralRepresentation(op).IsSmi();
+}
+
+
Operand LCodeGen::ToOperand(LOperand* op) const {
if (op->IsRegister()) return Operand(ToRegister(op));
if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
CpuFeatureScope scope(masm(), SSE2);
Representation r = instr->hydrogen()->value()->representation();
- if (r.IsInteger32()) {
+ if (r.IsInteger32() || r.IsSmi()) {
Register reg = ToRegister(instr->value());
__ test(reg, Operand(reg));
EmitBranch(true_block, false_block, not_zero);
if (FLAG_track_fields && representation.IsSmi()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
- if (!IsInteger32(operand_value)) {
+ if (!IsSmi(operand_value)) {
DeoptimizeIf(no_condition, instr->environment());
}
- } else {
- Register value = ToRegister(instr->value());
- __ SmiTag(value);
- if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
- DeoptimizeIf(overflow, instr->environment());
- }
}
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
- if (IsInteger32(operand_value)) {
- // In lithium register preparation, we made sure that the constant integer
- // operand fits into smi range.
- Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
- __ mov(FieldOperand(write_register, offset), Immediate(smi_value));
- } else if (operand_value->IsRegister()) {
+ if (operand_value->IsRegister()) {
__ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
} else {
Handle<Object> handle_value = ToHandle(operand_value);
}
+void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
+ Register input = ToRegister(instr->value());
+ __ SmiTag(input);
+ if (!instr->hydrogen()->value()->HasRange() ||
+ !instr->hydrogen()->value()->range()->IsInSmiRange()) {
+ DeoptimizeIf(overflow, instr->environment());
+ }
+}
+
+
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
CpuFeatureScope scope(masm(), SSE2);
LOperand* input = instr->value();
}
+void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
+ LOperand* input = instr->value();
+ ASSERT(input->IsDoubleRegister());
+ LOperand* result = instr->result();
+ ASSERT(result->IsRegister());
+ CpuFeatureScope scope(masm(), SSE2);
+
+ XMMRegister input_reg = ToDoubleRegister(input);
+ Register result_reg = ToRegister(result);
+
+ Label done;
+ __ cvttsd2si(result_reg, Operand(input_reg));
+ __ cvtsi2sd(xmm0, Operand(result_reg));
+ __ ucomisd(xmm0, input_reg);
+ DeoptimizeIf(not_equal, instr->environment());
+ DeoptimizeIf(parity_even, instr->environment()); // NaN.
+
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // The integer converted back is equal to the original. We
+ // only have to test if we got -0 as an input.
+ __ test(result_reg, Operand(result_reg));
+ __ j(not_zero, &done, Label::kNear);
+ __ movmskpd(result_reg, input_reg);
+ // Bit 0 contains the sign of the double in input_reg.
+ // If input was positive, we are ok and return 0, otherwise
+ // deoptimize.
+ __ and_(result_reg, 1);
+ DeoptimizeIf(not_zero, instr->environment());
+ __ bind(&done);
+ }
+ __ SmiTag(result_reg);
+ DeoptimizeIf(overflow, instr->environment());
+}
+
+
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->value();
__ test(ToOperand(input), Immediate(kSmiTagMask));
bool IsX87TopOfStack(LOperand* op) const;
bool IsInteger32(LConstantOperand* op) const;
+ bool IsSmi(LConstantOperand* op) const;
Immediate ToInteger32Immediate(LOperand* op) const {
return Immediate(ToInteger32(LConstantOperand::cast(op)));
}
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Representation from = instr->from();
Representation to = instr->to();
+ if (from.IsSmi()) {
+ if (to.IsTagged()) {
+ LOperand* value = UseRegister(instr->value());
+ return DefineSameAsFirst(new(zone()) LDummyUse(value));
+ }
+ from = Representation::Tagged();
+ }
// Only mark conversions that might need to allocate as calling rather than
// all changes. This makes simple, non-allocating conversion not have to force
// building a stack frame.
} else {
return AssignEnvironment(DefineX87TOS(res));
}
+ } else if (to.IsSmi()) {
+ HValue* val = instr->value();
+ LOperand* value = UseRegisterAtStart(val);
+ return AssignEnvironment(
+ DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
if (instr->value()->type().IsSmi()) {
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
return AssignPointerMap(Define(result, result_temp));
+ } else if (to.IsSmi()) {
+ LOperand* value = UseRegister(instr->value());
+ return AssignEnvironment(
+ DefineAsRegister(new(zone()) LDoubleToSmi(value)));
} else {
ASSERT(to.IsInteger32());
bool truncating = instr->CanTruncateToInt32();
LNumberTagI* result = new(zone()) LNumberTagI(value);
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
}
+ } else if (to.IsSmi()) {
+ HValue* val = instr->value();
+ LOperand* value = UseRegister(val);
+ LInstruction* result =
+ DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
+ if (val->HasRange() && val->range()->IsInSmiRange()) {
+ return result;
+ }
+ return AssignEnvironment(result);
} else {
ASSERT(to.IsDouble());
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseAtStart(instr->value());
- return AssignEnvironment(new(zone()) LCheckSmi(value));
+ return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
}
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
LOperand* value = UseAtStart(instr->value());
- return AssignEnvironment(new(zone()) LCheckSmi(value));
+ return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
}
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(DoubleToSmi) \
V(DummyUse) \
V(ElementsKind) \
V(FixedArrayBaseLength) \
V(InstanceSize) \
V(InstructionGap) \
V(Integer32ToDouble) \
+ V(Integer32ToSmi) \
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
};
+class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LInteger32ToSmi(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
public:
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
};
+class LDoubleToSmi: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LDoubleToSmi(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+};
+
+
// Truncating conversion from a tagged value to an int32.
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
public:
};
-class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
+class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
LInstruction* branch =
InstructionAt(cur_block->last_instruction_index());
if (branch->HasPointerMap()) {
- if (phi->representation().IsTagged()) {
+ if (phi->representation().IsSmiOrTagged()) {
branch->pointer_map()->RecordPointer(phi_operand, zone());
} else if (!phi->representation().IsDouble()) {
branch->pointer_map()->RecordUntagged(phi_operand, zone());
bool LAllocator::HasTaggedValue(int virtual_register) const {
HValue* value = graph_->LookupValue(virtual_register);
if (value == NULL) return false;
- return value->representation().IsTagged();
+ return value->representation().IsSmiOrTagged();
}
Representation representation,
bool is_uint32) {
values_.Add(operand, zone());
- if (representation.IsTagged()) {
+ if (representation.IsSmiOrTagged()) {
ASSERT(!is_uint32);
is_tagged_.Add(values_.length() - 1);
}
bool IsNone() const { return kind_ == kNone; }
bool IsTagged() const { return kind_ == kTagged; }
bool IsSmi() const { return kind_ == kSmi; }
+ bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
bool IsInteger32() const { return kind_ == kInteger32; }
bool IsDouble() const { return kind_ == kDouble; }
bool IsHeapObject() const { return kind_ == kHeapObject; }
}
+bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
+ return op->IsConstantOperand() &&
+ chunk_->LookupLiteralRepresentation(op).IsSmi();
+}
+
+
bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
return op->IsConstantOperand() &&
chunk_->LookupLiteralRepresentation(op).IsTagged();
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
- ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
+ ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
return constant->handle();
}
Register reg = ToRegister(instr->value());
__ testl(reg, reg);
EmitBranch(true_block, false_block, not_zero);
+ } else if (r.IsSmi()) {
+ Register reg = ToRegister(instr->value());
+ __ testq(reg, reg);
+ EmitBranch(true_block, false_block, not_zero);
} else if (r.IsDouble()) {
XMMRegister reg = ToDoubleRegister(instr->value());
__ xorps(xmm0, xmm0);
if (FLAG_track_fields && representation.IsSmi()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
- if (!IsInteger32Constant(operand_value)) {
+ if (!IsSmiConstant(operand_value)) {
DeoptimizeIf(no_condition, instr->environment());
}
- } else {
- Register value = ToRegister(instr->value());
- __ Integer32ToSmi(value, value);
}
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
- if (IsInteger32Constant(operand_value)) {
- // In lithium register preparation, we made sure that the constant integer
- // operand fits into smi range.
- Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
- __ Move(FieldOperand(write_register, offset), smi_value);
- } else if (operand_value->IsRegister()) {
+ if (operand_value->IsRegister()) {
__ movq(FieldOperand(write_register, offset),
ToRegister(operand_value));
} else {
}
+void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
+ LOperand* input = instr->value();
+ ASSERT(input->IsRegister());
+ LOperand* output = instr->result();
+ __ Integer32ToSmi(ToRegister(output), ToRegister(input));
+ if (!instr->hydrogen()->value()->HasRange() ||
+ !instr->hydrogen()->value()->range()->IsInSmiRange()) {
+ DeoptimizeIf(overflow, instr->environment());
+ }
+}
+
+
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
LOperand* input = instr->value();
LOperand* output = instr->result();
}
+void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
+ LOperand* input = instr->value();
+ ASSERT(input->IsDoubleRegister());
+ LOperand* result = instr->result();
+ ASSERT(result->IsRegister());
+ CpuFeatureScope scope(masm(), SSE2);
+
+ XMMRegister input_reg = ToDoubleRegister(input);
+ Register result_reg = ToRegister(result);
+
+ Label done;
+ __ cvttsd2si(result_reg, input_reg);
+ __ cvtlsi2sd(xmm0, result_reg);
+ __ ucomisd(xmm0, input_reg);
+ DeoptimizeIf(not_equal, instr->environment());
+ DeoptimizeIf(parity_even, instr->environment()); // NaN.
+
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // The integer converted back is equal to the original. We
+ // only have to test if we got -0 as an input.
+ __ testl(result_reg, result_reg);
+ __ j(not_zero, &done, Label::kNear);
+ __ movmskpd(result_reg, input_reg);
+ // Bit 0 contains the sign of the double in input_reg.
+ // If input was positive, we are ok and return 0, otherwise
+ // deoptimize.
+ __ andl(result_reg, Immediate(1));
+ DeoptimizeIf(not_zero, instr->environment());
+ __ bind(&done);
+ }
+ __ Integer32ToSmi(result_reg, result_reg);
+ DeoptimizeIf(overflow, instr->environment());
+}
+
+
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->value();
Condition cc = masm()->CheckSmi(ToRegister(input));
Register ToRegister(LOperand* op) const;
XMMRegister ToDoubleRegister(LOperand* op) const;
bool IsInteger32Constant(LConstantOperand* op) const;
+ bool IsSmiConstant(LConstantOperand* op) const;
int ToInteger32(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
bool IsTaggedConstant(LConstantOperand* op) const;
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Representation from = instr->from();
Representation to = instr->to();
+ if (from.IsSmi()) {
+ if (to.IsTagged()) {
+ LOperand* value = UseRegister(instr->value());
+ return DefineSameAsFirst(new(zone()) LDummyUse(value));
+ }
+ from = Representation::Tagged();
+ }
// Only mark conversions that might need to allocate as calling rather than
// all changes. This makes simple, non-allocating conversion not have to force
// building a stack frame.
LOperand* value = UseRegister(instr->value());
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
return AssignEnvironment(DefineAsRegister(res));
+ } else if (to.IsSmi()) {
+ HValue* val = instr->value();
+ LOperand* value = UseRegisterAtStart(val);
+ return AssignEnvironment(
+ DefineSameAsFirst(new(zone()) LCheckSmi(value)));
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
return AssignPointerMap(Define(result, result_temp));
+ } else if (to.IsSmi()) {
+ LOperand* value = UseRegister(instr->value());
+ return AssignEnvironment(
+ DefineAsRegister(new(zone()) LDoubleToSmi(value)));
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
- return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToI(value)));
+ return AssignEnvironment(
+ DefineAsRegister(new(zone()) LDoubleToI(value)));
}
} else if (from.IsInteger32()) {
info()->MarkAsDeferredCalling();
LNumberTagI* result = new(zone()) LNumberTagI(value);
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
}
+ } 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;
+ }
+ return AssignEnvironment(result);
} else {
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
LOperand* temp = FixedTemp(xmm1);
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new(zone()) LCheckSmi(value));
+ return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
}
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new(zone()) LCheckSmi(value));
+ return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
}
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(DoubleToSmi) \
V(DummyUse) \
V(ElementsKind) \
V(FixedArrayBaseLength) \
V(InstanceSize) \
V(InstructionGap) \
V(Integer32ToDouble) \
+ V(Integer32ToSmi) \
V(Uint32ToDouble) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
};
+class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LInteger32ToSmi(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
public:
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
};
+class LDoubleToSmi: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LDoubleToSmi(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+};
+
+
// Truncating conversion from a tagged value to an int32.
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
public:
};
-class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
+class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
--- /dev/null
+// 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: --track-fields --track-double-fields --allow-natives-syntax
+
+function smi_field() {
+ return {"smi":0};
+}
+
+function check_smi_repr(o, d1, d2) {
+ var s = o.smi;
+ var d = d1 - d2;
+ s = s + d;
+ o.smi = s;
+ return o;
+}
+
+var test = smi_field();
+check_smi_repr(smi_field(), 5, 3);
+check_smi_repr(smi_field(), 6, 2);
+%OptimizeFunctionOnNextCall(check_smi_repr);
+var val = check_smi_repr(smi_field(), 8, 1);
+assertTrue(%HaveSameMap(val, test));
+
+function tagged_smi_field() {
+ var o = {"tag":false};
+ o.tag = 10;
+ return o;
+}
+
+function check_smi_repr_from_tagged(o, o2) {
+ var t = o2.tag;
+ o.smi = t;
+ return o;
+}
+
+check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
+check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
+%OptimizeFunctionOnNextCall(check_smi_repr_from_tagged);
+var val = check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
+assertTrue(%HaveSameMap(val, test));
+var overflow = tagged_smi_field();
+overflow.tag = 0x80000000;
+var val = check_smi_repr_from_tagged(smi_field(), overflow);