Improvements for x87 stack handling

BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14179 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 74839e86
...@@ -3190,13 +3190,19 @@ class HConstant: public HTemplateInstruction<0> { ...@@ -3190,13 +3190,19 @@ class HConstant: public HTemplateInstruction<0> {
bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); } bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
bool IsSpecialDouble() const {
return has_double_value_ &&
(BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
FixedDoubleArray::is_the_hole_nan(double_value_) ||
isnan(double_value_));
}
bool ImmortalImmovable() const { bool ImmortalImmovable() const {
if (has_int32_value_) { if (has_int32_value_) {
return false; return false;
} }
if (has_double_value_) { if (has_double_value_) {
if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || if (IsSpecialDouble()) {
isnan(double_value_)) {
return true; return true;
} }
return false; return false;
...@@ -3227,7 +3233,9 @@ class HConstant: public HTemplateInstruction<0> { ...@@ -3227,7 +3233,9 @@ class HConstant: public HTemplateInstruction<0> {
return has_int32_value_; return has_int32_value_;
} }
virtual bool EmitAtUses() { return !representation().IsDouble(); } virtual bool EmitAtUses() {
return !representation().IsDouble() || IsSpecialDouble();
}
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType(); virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); } bool IsInteger() { return handle()->IsSmi(); }
...@@ -3246,6 +3254,16 @@ class HConstant: public HTemplateInstruction<0> { ...@@ -3246,6 +3254,16 @@ class HConstant: public HTemplateInstruction<0> {
ASSERT(HasDoubleValue()); ASSERT(HasDoubleValue());
return double_value_; return double_value_;
} }
bool IsTheHole() const {
if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
return true;
}
Heap* heap = isolate()->heap();
if (!handle_.is_null() && *handle_ == heap->the_hole_value()) {
return true;
}
return false;
}
bool HasNumberValue() const { return has_double_value_; } bool HasNumberValue() const { return has_double_value_; }
int32_t NumberValueAsInteger32() const { int32_t NumberValueAsInteger32() const {
ASSERT(HasNumberValue()); ASSERT(HasNumberValue());
...@@ -5677,6 +5695,10 @@ class HStoreKeyed ...@@ -5677,6 +5695,10 @@ class HStoreKeyed
bool IsDehoisted() { return is_dehoisted_; } bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool IsConstantHoleStore() {
return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
}
virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) { virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion); ASSERT(side_effect == kChangesNewSpacePromotion);
new_space_dominator_ = dominator; new_space_dominator_ = dominator;
......
This diff is collapsed.
...@@ -68,6 +68,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -68,6 +68,7 @@ class LCodeGen BASE_EMBEDDED {
osr_pc_offset_(-1), osr_pc_offset_(-1),
last_lazy_deopt_pc_(0), last_lazy_deopt_pc_(0),
frame_is_built_(false), frame_is_built_(false),
x87_stack_depth_(0),
safepoints_(info->zone()), safepoints_(info->zone()),
resolver_(this), resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) { expected_safepoint_kind_(Safepoint::kSimple) {
...@@ -102,10 +103,17 @@ class LCodeGen BASE_EMBEDDED { ...@@ -102,10 +103,17 @@ class LCodeGen BASE_EMBEDDED {
return Immediate(ToInteger32(LConstantOperand::cast(op))); return Immediate(ToInteger32(LConstantOperand::cast(op)));
} }
Handle<Object> ToHandle(LConstantOperand* op) const; // Support for non-sse2 (x87) floating point stack handling.
// These functions maintain the depth of the stack (either 0 or 1)
void PushX87DoubleOperand(Operand src);
void PushX87FloatOperand(Operand src);
void ReadX87Operand(Operand dst);
bool X87StackNonEmpty() const { return x87_stack_depth_ > 0; }
void PopX87();
void CurrentInstructionReturnsX87Result();
void FlushX87StackIfNecessary(LInstruction* instr);
// A utility for instructions that return floating point values on X87. Handle<Object> ToHandle(LConstantOperand* op) const;
void HandleX87FPReturnValue(LInstruction* instr);
// The operand denoting the second word (the one with a higher address) of // The operand denoting the second word (the one with a higher address) of
// a double stack slot. // a double stack slot.
...@@ -129,6 +137,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -129,6 +137,7 @@ class LCodeGen BASE_EMBEDDED {
IntegerSignedness signedness); IntegerSignedness signedness);
void DoDeferredTaggedToI(LTaggedToI* instr); void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredRandom(LRandom* instr); void DoDeferredRandom(LRandom* instr);
...@@ -315,6 +324,14 @@ class LCodeGen BASE_EMBEDDED { ...@@ -315,6 +324,14 @@ class LCodeGen BASE_EMBEDDED {
LEnvironment* env, LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED); NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
void EmitNumberUntagDNoSSE2(
Register input,
Register temp,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env,
NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
// Emits optimized code for typeof x == "y". Modifies input register. // Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to // Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough. // true and false label should be made, to optimize fallthrough.
...@@ -404,6 +421,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -404,6 +421,7 @@ class LCodeGen BASE_EMBEDDED {
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_; int last_lazy_deopt_pc_;
bool frame_is_built_; bool frame_is_built_;
int x87_stack_depth_;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code. // itself is emitted at the end of the generated code.
......
...@@ -324,6 +324,7 @@ void LGapResolver::EmitMove(int index) { ...@@ -324,6 +324,7 @@ void LGapResolver::EmitMove(int index) {
} }
} else if (source->IsDoubleRegister()) { } else if (source->IsDoubleRegister()) {
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(cgen_->masm(), SSE2); CpuFeatureScope scope(cgen_->masm(), SSE2);
XMMRegister src = cgen_->ToDoubleRegister(source); XMMRegister src = cgen_->ToDoubleRegister(source);
if (destination->IsDoubleRegister()) { if (destination->IsDoubleRegister()) {
...@@ -334,7 +335,16 @@ void LGapResolver::EmitMove(int index) { ...@@ -334,7 +335,16 @@ void LGapResolver::EmitMove(int index) {
Operand dst = cgen_->ToOperand(destination); Operand dst = cgen_->ToOperand(destination);
__ movdbl(dst, src); __ movdbl(dst, src);
} }
} else {
// load from the register onto the stack, store in destination, which must
// be a double stack slot in the non-SSE2 case.
ASSERT(source->index() == 0); // source is on top of the stack
ASSERT(destination->IsDoubleStackSlot());
Operand dst = cgen_->ToOperand(destination);
cgen_->ReadX87Operand(dst);
}
} else if (source->IsDoubleStackSlot()) { } else if (source->IsDoubleStackSlot()) {
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(cgen_->masm(), SSE2); CpuFeatureScope scope(cgen_->masm(), SSE2);
ASSERT(destination->IsDoubleRegister() || ASSERT(destination->IsDoubleRegister() ||
destination->IsDoubleStackSlot()); destination->IsDoubleStackSlot());
...@@ -348,6 +358,28 @@ void LGapResolver::EmitMove(int index) { ...@@ -348,6 +358,28 @@ void LGapResolver::EmitMove(int index) {
__ movdbl(xmm0, src); __ movdbl(xmm0, src);
__ movdbl(dst, xmm0); __ movdbl(dst, xmm0);
} }
} else {
// load from the stack slot on top of the floating point stack, and then
// store in destination. If destination is a double register, then it
// represents the top of the stack and nothing needs to be done.
if (destination->IsDoubleStackSlot()) {
Register tmp = EnsureTempRegister();
Operand src0 = cgen_->ToOperand(source);
Operand src1 = cgen_->HighOperand(source);
Operand dst0 = cgen_->ToOperand(destination);
Operand dst1 = cgen_->HighOperand(destination);
__ mov(tmp, src0); // Then use tmp to copy source to destination.
__ mov(dst0, tmp);
__ mov(tmp, src1);
__ mov(dst1, tmp);
} else {
Operand src = cgen_->ToOperand(source);
if (cgen_->X87StackNonEmpty()) {
cgen_->PopX87();
}
cgen_->PushX87DoubleOperand(src);
}
}
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -419,7 +451,6 @@ void LGapResolver::EmitSwap(int index) { ...@@ -419,7 +451,6 @@ void LGapResolver::EmitSwap(int index) {
__ movaps(xmm0, src); __ movaps(xmm0, src);
__ movaps(src, dst); __ movaps(src, dst);
__ movaps(dst, xmm0); __ movaps(dst, xmm0);
} else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) { } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) {
CpuFeatureScope scope(cgen_->masm(), SSE2); CpuFeatureScope scope(cgen_->masm(), SSE2);
// XMM register-memory swap. We rely on having xmm0 // XMM register-memory swap. We rely on having xmm0
...@@ -433,7 +464,6 @@ void LGapResolver::EmitSwap(int index) { ...@@ -433,7 +464,6 @@ void LGapResolver::EmitSwap(int index) {
__ movdbl(xmm0, other); __ movdbl(xmm0, other);
__ movdbl(other, reg); __ movdbl(other, reg);
__ movdbl(reg, Operand(xmm0)); __ movdbl(reg, Operand(xmm0));
} else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) { } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
CpuFeatureScope scope(cgen_->masm(), SSE2); CpuFeatureScope scope(cgen_->masm(), SSE2);
// Double-width memory-to-memory. Spill on demand to use a general // Double-width memory-to-memory. Spill on demand to use a general
......
...@@ -91,6 +91,22 @@ void LInstruction::VerifyCall() { ...@@ -91,6 +91,22 @@ void LInstruction::VerifyCall() {
#endif #endif
bool LInstruction::HasDoubleRegisterResult() {
return HasResult() && result()->IsDoubleRegister();
}
bool LInstruction::HasDoubleRegisterInput() {
for (int i = 0; i < InputCount(); i++) {
LOperand* op = InputAt(i);
if (op->IsDoubleRegister()) {
return true;
}
}
return false;
}
void LInstruction::PrintTo(StringStream* stream) { void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic()); stream->Add("%s ", this->Mnemonic());
...@@ -542,6 +558,11 @@ LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) { ...@@ -542,6 +558,11 @@ LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
} }
LOperand* LChunkBuilder::UseX87TopOfStack(HValue* value) {
return Use(value, ToUnallocated(x87tos));
}
LOperand* LChunkBuilder::UseRegister(HValue* value) { LOperand* LChunkBuilder::UseRegister(HValue* value) {
return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
} }
...@@ -1861,20 +1882,33 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { ...@@ -1861,20 +1882,33 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
? TempRegister() ? TempRegister()
: NULL; : NULL;
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp); LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
return AssignEnvironment(DefineAsRegister(res)); return AssignEnvironment(DefineAsRegister(res));
} else {
return AssignEnvironment(DefineX87TOS(res));
}
} else { } else {
ASSERT(to.IsInteger32()); ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
if (instr->value()->type().IsSmi()) { if (instr->value()->type().IsSmi()) {
LOperand* value = UseRegister(instr->value());
return DefineSameAsFirst(new(zone()) LSmiUntag(value, false)); return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
} else { } else {
bool truncating = instr->CanTruncateToInt32(); bool truncating = instr->CanTruncateToInt32();
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
LOperand* value = UseRegister(instr->value());
LOperand* xmm_temp = LOperand* xmm_temp =
(truncating && CpuFeatures::IsSupported(SSE3)) (truncating && CpuFeatures::IsSupported(SSE3))
? NULL ? NULL
: FixedTemp(xmm1); : FixedTemp(xmm1);
LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp); LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
return AssignEnvironment(DefineSameAsFirst(res)); return AssignEnvironment(DefineSameAsFirst(res));
} else {
LOperand* value = UseFixed(instr->value(), ecx);
LTaggedToINoSSE2* res =
new(zone()) LTaggedToINoSSE2(value, TempRegister(),
TempRegister(), TempRegister());
return AssignEnvironment(DefineFixed(res, ecx));
}
} }
} }
} else if (from.IsDouble()) { } else if (from.IsDouble()) {
...@@ -1992,12 +2026,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { ...@@ -1992,12 +2026,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
return DefineFixed(new(zone()) LClampIToUint8(reg), eax); return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
} else { } else {
ASSERT(input_rep.IsTagged()); ASSERT(input_rep.IsTagged());
if (CpuFeatures::IsSupported(SSE2)) {
LOperand* reg = UseFixed(value, eax); LOperand* reg = UseFixed(value, eax);
// Register allocator doesn't (yet) support allocation of double // Register allocator doesn't (yet) support allocation of double
// temps. Reserve xmm1 explicitly. // temps. Reserve xmm1 explicitly.
LOperand* temp = FixedTemp(xmm1); LOperand* temp = FixedTemp(xmm1);
LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp); LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
return AssignEnvironment(DefineFixed(result, eax)); return AssignEnvironment(DefineFixed(result, eax));
} else {
LOperand* value = UseRegister(instr->value());
LClampTToUint8NoSSE2* res =
new(zone()) LClampTToUint8NoSSE2(value, TempRegister(),
TempRegister(), TempRegister());
return AssignEnvironment(DefineFixed(res, ecx));
}
} }
} }
...@@ -2018,10 +2060,13 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { ...@@ -2018,10 +2060,13 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
return DefineAsRegister(new(zone()) LConstantI); return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) { } else if (r.IsDouble()) {
double value = instr->DoubleValue(); double value = instr->DoubleValue();
LOperand* temp = (BitCast<uint64_t, double>(value) != 0) bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
? TempRegister() if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
: NULL; LOperand* temp = value_is_zero ? NULL : TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp)); return DefineAsRegister(new(zone()) LConstantD(temp));
} else {
return DefineX87TOS(new(zone()) LConstantD(NULL));
}
} else if (r.IsTagged()) { } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT); return DefineAsRegister(new(zone()) LConstantT);
} else { } else {
...@@ -2190,6 +2235,27 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { ...@@ -2190,6 +2235,27 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
} }
LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
ElementsKind elements_kind = instr->elements_kind();
// Determine if we need a byte register in this case for the value.
bool val_is_fixed_register =
elements_kind == EXTERNAL_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_PIXEL_ELEMENTS;
if (val_is_fixed_register) {
return UseFixed(instr->value(), eax);
}
if (!CpuFeatures::IsSafeForSnapshot(SSE2) &&
IsDoubleOrFloatElementsKind(elements_kind)) {
return UseRegisterAtStart(instr->value());
}
return UseRegister(instr->value());
}
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (!instr->is_external()) { if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged()); ASSERT(instr->elements()->representation().IsTagged());
...@@ -2198,7 +2264,12 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { ...@@ -2198,7 +2264,12 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (instr->value()->representation().IsDouble()) { if (instr->value()->representation().IsDouble()) {
LOperand* object = UseRegisterAtStart(instr->elements()); LOperand* object = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value()); LOperand* val = NULL;
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
val = UseRegisterAtStart(instr->value());
} else if (!instr->IsConstantHoleStore()) {
val = UseX87TopOfStack(instr->value());
}
LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyed(object, key, val); return new(zone()) LStoreKeyed(object, key, val);
...@@ -2228,15 +2299,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { ...@@ -2228,15 +2299,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
ASSERT(instr->elements()->representation().IsExternal()); ASSERT(instr->elements()->representation().IsExternal());
LOperand* external_pointer = UseRegister(instr->elements()); LOperand* external_pointer = UseRegister(instr->elements());
// Determine if we need a byte register in this case for the value. LOperand* val = GetStoreKeyedValueOperand(instr);
bool val_is_fixed_register =
elements_kind == EXTERNAL_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_PIXEL_ELEMENTS;
LOperand* val = val_is_fixed_register
? UseFixed(instr->value(), eax)
: UseRegister(instr->value());
bool clobbers_key = ExternalArrayOpRequiresTemp( bool clobbers_key = ExternalArrayOpRequiresTemp(
instr->key()->representation(), elements_kind); instr->key()->representation(), elements_kind);
LOperand* key = clobbers_key LOperand* key = clobbers_key
......
...@@ -74,6 +74,7 @@ class LCodeGen; ...@@ -74,6 +74,7 @@ class LCodeGen;
V(ClampDToUint8) \ V(ClampDToUint8) \
V(ClampIToUint8) \ V(ClampIToUint8) \
V(ClampTToUint8) \ V(ClampTToUint8) \
V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \ V(ClassOfTestAndBranch) \
V(CmpIDAndBranch) \ V(CmpIDAndBranch) \
V(CmpObjectEqAndBranch) \ V(CmpObjectEqAndBranch) \
...@@ -167,6 +168,7 @@ class LCodeGen; ...@@ -167,6 +168,7 @@ class LCodeGen;
V(StringLength) \ V(StringLength) \
V(SubI) \ V(SubI) \
V(TaggedToI) \ V(TaggedToI) \
V(TaggedToINoSSE2) \
V(ThisFunction) \ V(ThisFunction) \
V(Throw) \ V(Throw) \
V(ToFastProperties) \ V(ToFastProperties) \
...@@ -265,6 +267,9 @@ class LInstruction: public ZoneObject { ...@@ -265,6 +267,9 @@ class LInstruction: public ZoneObject {
virtual bool HasResult() const = 0; virtual bool HasResult() const = 0;
virtual LOperand* result() = 0; virtual LOperand* result() = 0;
bool HasDoubleRegisterResult();
bool HasDoubleRegisterInput();
LOperand* FirstInput() { return InputAt(0); } LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; } LOperand* Output() { return HasResult() ? result() : NULL; }
...@@ -1088,6 +1093,10 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> { ...@@ -1088,6 +1093,10 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> {
temps_[0] = temp; temps_[0] = temp;
} }
virtual bool ClobbersDoubleRegisters() const {
return false;
}
LOperand* temp() { return temps_[0]; } LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
...@@ -2018,6 +2027,31 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 1> { ...@@ -2018,6 +2027,31 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
}; };
// Truncating conversion from a tagged value to an int32.
class LTaggedToINoSSE2: public LTemplateInstruction<1, 1, 3> {
public:
LTaggedToINoSSE2(LOperand* value,
LOperand* temp1,
LOperand* temp2,
LOperand* temp3) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = temp3;
}
LOperand* value() { return inputs_[0]; }
LOperand* scratch() { return temps_[0]; }
LOperand* scratch2() { return temps_[1]; }
LOperand* scratch3() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(TaggedToINoSSE2, "tagged-to-i-nosse2")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
};
class LSmiTag: public LTemplateInstruction<1, 1, 0> { class LSmiTag: public LTemplateInstruction<1, 1, 0> {
public: public:
explicit LSmiTag(LOperand* value) { explicit LSmiTag(LOperand* value) {
...@@ -2040,6 +2074,10 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> { ...@@ -2040,6 +2074,10 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
LOperand* value() { return inputs_[0]; } LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; } LOperand* temp() { return temps_[0]; }
virtual bool ClobbersDoubleRegisters() const {
return false;
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change); DECLARE_HYDROGEN_ACCESSOR(Change);
}; };
...@@ -2380,6 +2418,30 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { ...@@ -2380,6 +2418,30 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
}; };
// Truncating conversion from a tagged value to an int32.
class LClampTToUint8NoSSE2: public LTemplateInstruction<1, 1, 3> {
public:
LClampTToUint8NoSSE2(LOperand* unclamped,
LOperand* temp1,
LOperand* temp2,
LOperand* temp3) {
inputs_[0] = unclamped;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = temp3;
}
LOperand* unclamped() { return inputs_[0]; }
LOperand* scratch() { return temps_[0]; }
LOperand* scratch2() { return temps_[1]; }
LOperand* scratch3() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8NoSSE2,
"clamp-t-to-uint8-nosse2")
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
};
class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
public: public:
explicit LCheckNonSmi(LOperand* value) { explicit LCheckNonSmi(LOperand* value) {
...@@ -2742,6 +2804,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -2742,6 +2804,7 @@ class LChunkBuilder BASE_EMBEDDED {
MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register); MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value, MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
XMMRegister fixed_register); XMMRegister fixed_register);
MUST_USE_RESULT LOperand* UseX87TopOfStack(HValue* value);
// A value that is guaranteed to be allocated to a register. // A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of // Operand created by UseRegister is guaranteed to be live until the end of
...@@ -2827,6 +2890,8 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -2827,6 +2890,8 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* DoArithmeticT(Token::Value op, LInstruction* DoArithmeticT(Token::Value op,
HArithmeticBinaryOperation* instr); HArithmeticBinaryOperation* instr);
LOperand* GetStoreKeyedValueOperand(HStoreKeyed* instr);
LPlatformChunk* chunk_; LPlatformChunk* chunk_;
CompilationInfo* info_; CompilationInfo* info_;
HGraph* const graph_; HGraph* const graph_;
......
...@@ -2518,6 +2518,28 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) { ...@@ -2518,6 +2518,28 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
} }
void MacroAssembler::VerifyX87StackDepth(uint depth) {
// Make sure the floating point stack is either empty or has depth items.
ASSERT(depth <= 7);
// The top-of-stack (tos) is 7 if there is one item pushed.
int tos = (8 - depth) % 8;
const int kTopMask = 0x3800;
push(eax);
fwait();
fnstsw_ax();
and_(eax, kTopMask);
shr(eax, 11);
cmp(eax, Immediate(tos));
Label all_ok;
j(equal, &all_ok);
Check(equal, "Unexpected FPU stack depth after instruction");
bind(&all_ok);
fnclex();
pop(eax);
}
void MacroAssembler::Drop(int stack_elements) { void MacroAssembler::Drop(int stack_elements) {
if (stack_elements > 0) { if (stack_elements > 0) {
add(esp, Immediate(stack_elements * kPointerSize)); add(esp, Immediate(stack_elements * kPointerSize));
......
...@@ -807,6 +807,8 @@ class MacroAssembler: public Assembler { ...@@ -807,6 +807,8 @@ class MacroAssembler: public Assembler {
return code_object_; return code_object_;
} }
// Insert code to verify that the x87 stack has the specified depth (0-7)
void VerifyX87StackDepth(uint depth);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// StatsCounter support // StatsCounter support
......
...@@ -1788,7 +1788,7 @@ STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >= ...@@ -1788,7 +1788,7 @@ STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=
bool LAllocator::TryAllocateFreeReg(LiveRange* current) { bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters]; LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters];
for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; i++) { for (int i = 0; i < num_registers_; i++) {
free_until_pos[i] = LifetimePosition::MaxPosition(); free_until_pos[i] = LifetimePosition::MaxPosition();
} }
...@@ -1880,7 +1880,7 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) { ...@@ -1880,7 +1880,7 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) {
LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters]; LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters];
LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters]; LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters];
for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) { for (int i = 0; i < num_registers_; i++) {
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition(); use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
} }
......
...@@ -1495,6 +1495,8 @@ class HeapNumber: public HeapObject { ...@@ -1495,6 +1495,8 @@ class HeapNumber: public HeapObject {
static const int kExponentBits = 11; static const int kExponentBits = 11;
static const int kExponentBias = 1023; static const int kExponentBias = 1023;
static const int kExponentShift = 20; static const int kExponentShift = 20;
static const int kInfinityOrNanExponent =
(kExponentMask >> kExponentShift) - kExponentBias;
static const int kMantissaBitsInTopWord = 20; static const int kMantissaBitsInTopWord = 20;
static const int kNonMantissaBitsInTopWord = 12; static const int kNonMantissaBitsInTopWord = 12;
......
This diff is collapsed.
...@@ -27,12 +27,15 @@ ...@@ -27,12 +27,15 @@
// Flags: --allow-natives-syntax // Flags: --allow-natives-syntax
var pixels = new Uint8ClampedArray(8); var pixels = new Uint8ClampedArray(11);
function f() { function f() {
for (var i = 0; i < 8; i++) { for (var i = 0; i < 8; i++) {
pixels[i] = (i * 1.1); pixels[i] = (i * 1.1);
} }
pixels[8] = 255.5;
pixels[9] = NaN;
pixels[10] = -0.5;
return pixels[1] + pixels[6]; return pixels[1] + pixels[6];
} }
...@@ -42,3 +45,6 @@ assertEquals(6, pixels[5]); ...@@ -42,3 +45,6 @@ assertEquals(6, pixels[5]);
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
f(); f();
assertEquals(6, pixels[5]); assertEquals(6, pixels[5]);
assertEquals(255, pixels[8]);
assertEquals(0, pixels[9]);
assertEquals(0, pixels[10]);
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