}
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
+ __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+ __ ldr(r1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
+ __ cmp(r2, Operand(0x80000000));
+ __ cmp(r1, Operand(0x00000000), eq);
+
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(eq, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+ HCompareMinusZeroAndBranch* instr) {
+ LInstruction* goto_instr = CheckElideControlInstruction(instr);
+ if (goto_instr != NULL) return goto_instr;
+ LOperand* value = UseRegister(instr->value());
+ LOperand* scratch = TempRegister();
+ return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
V(ClampIToUint8) \
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
+ V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
};
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 1> {
+ public:
+ LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+ "cmp-minus-zero-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
}
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+ Representation rep = instr->hydrogen()->value()->representation();
+ ASSERT(!rep.IsInteger32());
+ Label if_false;
+ Register scratch = ToRegister(instr->temp());
+
+ if (rep.IsDouble()) {
+ DwVfpRegister value = ToDoubleRegister(instr->value());
+ __ VFPCompareAndSetFlags(value, 0.0);
+ __ b(ne, &if_false);
+ __ VmovHigh(scratch, value);
+ __ cmp(scratch, Operand(0x80000000));
+ } else {
+ Register value = ToRegister(instr->value());
+ __ CheckMap(
+ value, scratch, Heap::kHeapNumberMapRootIndex, &if_false, DO_SMI_CHECK);
+ __ ldr(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
+ __ ldr(ip, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+ __ cmp(scratch, Operand(0x80000000));
+ __ cmp(ip, Operand(0x00000000), eq);
+ }
+ EmitBranch(instr, eq);
+
+ __ bind(&if_false);
+ EmitFalseBranch(instr, al);
+}
+
+
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Label* is_not_object,
}
+bool HCompareMinusZeroAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
+ if (value()->representation().IsSmiOrInteger32()) {
+ // A Smi or Integer32 cannot contain minus zero.
+ *block = SecondSuccessor();
+ return true;
+ }
+ *block = NULL;
+ return false;
+}
+
+
+void HCompareMinusZeroAndBranch::InferRepresentation(
+ HInferRepresentationPhase* h_infer) {
+ ChangeRepresentation(value()->representation());
+}
+
+
+
void HGoto::PrintDataTo(StringStream* stream) {
stream->Add("B%d", SuccessorAt(0)->block_id());
}
V(CompareNumericAndBranch) \
V(CompareHoleAndBranch) \
V(CompareGeneric) \
+ V(CompareMinusZeroAndBranch) \
V(CompareObjectEqAndBranch) \
V(CompareMap) \
V(Constant) \
};
+class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction {
+ public:
+ DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
+
+ virtual void InferRepresentation(
+ HInferRepresentationPhase* h_infer) V8_OVERRIDE;
+
+ virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
+ return representation();
+ }
+
+ virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
+
+ DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
+
+ private:
+ explicit HCompareMinusZeroAndBranch(HValue* value)
+ : HUnaryControlInstruction(value, NULL, NULL) {
+ }
+};
+
+
class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
public:
HCompareObjectEqAndBranch(HValue* left,
PropagateMinusZeroChecks(change->value());
visited_.Clear();
}
+ } else if (current->IsCompareMinusZeroAndBranch()) {
+ HCompareMinusZeroAndBranch* check =
+ HCompareMinusZeroAndBranch::cast(current);
+ if (check->value()->representation().IsSmiOrInteger32()) {
+ ASSERT(visited_.IsEmpty());
+ PropagateMinusZeroChecks(check->value());
+ visited_.Clear();
+ }
}
}
}
}
+void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
+ return ast_context()->ReturnControl(result, call->id());
+}
+
+
void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
}
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+ __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
+ __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x80000000));
+ __ j(not_equal, if_false);
+ __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x00000000));
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
+
void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+ Representation rep = instr->hydrogen()->value()->representation();
+ ASSERT(!rep.IsInteger32());
+ Label if_false;
+ Register scratch = ToRegister(instr->temp());
+
+ if (rep.IsDouble()) {
+ CpuFeatureScope use_sse2(masm(), SSE2);
+ XMMRegister value = ToDoubleRegister(instr->value());
+ XMMRegister xmm_scratch = double_scratch0();
+ __ xorps(xmm_scratch, xmm_scratch);
+ __ ucomisd(xmm_scratch, value);
+ __ j(not_equal, &if_false);
+ __ movmskpd(scratch, value);
+ __ test(scratch, Immediate(1));
+ EmitBranch(instr, not_zero);
+ } else {
+ Register value = ToRegister(instr->value());
+ Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+ __ CheckMap(eax, map, &if_false, DO_SMI_CHECK);
+ __ cmp(FieldOperand(value, HeapNumber::kExponentOffset),
+ Immediate(0x80000000));
+ __ j(not_equal, &if_false);
+ __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset),
+ Immediate(0x00000000));
+ EmitBranch(instr, equal);
+ }
+
+ __ bind(&if_false);
+ EmitFalseBranch(instr, no_condition);
+}
+
+
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Label* is_not_object,
}
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+ HCompareMinusZeroAndBranch* instr) {
+ LInstruction* goto_instr = CheckElideControlInstruction(instr);
+ if (goto_instr != NULL) return goto_instr;
+ LOperand* value = UseRegister(instr->value());
+ LOperand* scratch = TempRegister();
+ return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsSmiOrTagged());
LOperand* temp = TempRegister();
V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \
V(ClobberDoubles) \
+ V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
};
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 1> {
+ public:
+ LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+ "cmp-minus-zero-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
F(MathTan, 1, 1) \
F(MathSqrt, 1, 1) \
F(MathLog, 1, 1) \
+ F(IsMinusZero, 1, 1) \
F(IsRegExpEquivalent, 2, 1) \
F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \
}
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+ __ CheckMap(rax, map, if_false, DO_SMI_CHECK);
+ __ cmpl(FieldOperand(rax, HeapNumber::kExponentOffset),
+ Immediate(0x80000000));
+ __ j(not_equal, if_false);
+ __ cmpl(FieldOperand(rax, HeapNumber::kMantissaOffset),
+ Immediate(0x00000000));
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+ Representation rep = instr->hydrogen()->value()->representation();
+ ASSERT(!rep.IsInteger32());
+ Label if_false;
+
+ if (rep.IsDouble()) {
+ XMMRegister value = ToDoubleRegister(instr->value());
+ XMMRegister xmm_scratch = double_scratch0();
+ __ xorps(xmm_scratch, xmm_scratch);
+ __ ucomisd(xmm_scratch, value);
+ __ j(not_equal, &if_false);
+ __ movmskpd(kScratchRegister, value);
+ __ testl(kScratchRegister, Immediate(1));
+ EmitBranch(instr, not_zero);
+ } else {
+ Register value = ToRegister(instr->value());
+ Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
+ __ CheckMap(rax, map, &if_false, DO_SMI_CHECK);
+ __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset),
+ Immediate(0x80000000));
+ __ j(not_equal, &if_false);
+ __ cmpl(FieldOperand(value, HeapNumber::kMantissaOffset),
+ Immediate(0x00000000));
+ EmitBranch(instr, equal);
+ }
+
+ __ bind(&if_false);
+ EmitFalseBranch(instr, always);
+}
+
+
Condition LCodeGen::EmitIsObject(Register input,
Label* is_not_object,
Label* is_object) {
}
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+ HCompareMinusZeroAndBranch* instr) {
+ LInstruction* goto_instr = CheckElideControlInstruction(instr);
+ if (goto_instr != NULL) return goto_instr;
+ LOperand* value = UseRegister(instr->value());
+ return new(zone()) LCompareMinusZeroAndBranch(value);
+}
+
+
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
V(ClampIToUint8) \
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
+ V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
};
+class LCompareMinusZeroAndBranch V8_FINAL : public LControlInstruction<1, 0> {
+ public:
+ explicit LCompareMinusZeroAndBranch(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+ "cmp-minus-zero-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
+
class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 0> {
public:
explicit LIsObjectAndBranch(LOperand* value) {
// (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
+// Flags: --allow-natives-syntax --no-fold-constants
function add(x, y) {
return x + y;
assertEquals(0, add(0, 0));
%OptimizeFunctionOnNextCall(add);
assertEquals(-0, add(-0, -0));
+
+
+function test(x, y) {
+ assertTrue(%_IsMinusZero(-0));
+ assertTrue(%_IsMinusZero(1/(-Infinity)));
+ assertTrue(%_IsMinusZero(x));
+
+ assertFalse(%_IsMinusZero(0));
+ assertFalse(%_IsMinusZero(1/Infinity));
+ assertFalse(%_IsMinusZero(0.1));
+ assertFalse(%_IsMinusZero(-0.2));
+ assertFalse(%_IsMinusZero({}));
+ assertFalse(%_IsMinusZero(""));
+ assertFalse(%_IsMinusZero("-0"));
+ assertFalse(%_IsMinusZero(function() {}));
+ assertFalse(%_IsMinusZero(y));
+}
+
+test(-0, 1.2);
+test(-0, 1.2);
+%OptimizeFunctionOnNextCall(test);
+test(-0, 1.2);
+assertOptimized(test);
+
+
+function testsin() {
+ assertTrue(%_IsMinusZero(Math.sin(-0)));
+}
+
+testsin();
+testsin();
+%OptimizeFunctionOnNextCall(testsin);
+testsin();
+
+
+function testfloor() {
+ assertTrue(%_IsMinusZero(Math.floor(-0)));
+ assertFalse(%_IsMinusZero(Math.floor(2)));
+}
+
+testfloor();
+testfloor();
+%OptimizeFunctionOnNextCall(testfloor);
+testfloor();
+
+
+var double_one = Math.cos(0);
+
+function add(a, b) {
+ return a + b;
+}
+
+assertEquals(1, 1/add(double_one, 0));
+assertEquals(1, 1/add(0, double_one));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(1/(-0 + -0), 1/add(-0, -0));