Commit df966503 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Introduce %_IsMinusZero.

R=jkummerow@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17639 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7df10557
......@@ -3104,6 +3104,32 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
}
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);
......
......@@ -1783,6 +1783,16 @@ LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
}
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());
......
......@@ -72,6 +72,7 @@ class LCodeGen;
V(ClampIToUint8) \
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
......@@ -928,6 +929,22 @@ class LCmpHoleAndBranch V8_FINAL : public LControlInstruction<1, 0> {
};
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) {
......
......@@ -2472,6 +2472,34 @@ void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
}
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,
......
......@@ -2944,6 +2944,24 @@ void HCompareHoleAndBranch::InferRepresentation(
}
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());
}
......
......@@ -100,6 +100,7 @@ class LChunkBuilder;
V(CompareNumericAndBranch) \
V(CompareHoleAndBranch) \
V(CompareGeneric) \
V(CompareMinusZeroAndBranch) \
V(CompareObjectEqAndBranch) \
V(CompareMap) \
V(Constant) \
......@@ -4165,6 +4166,28 @@ class HCompareHoleAndBranch V8_FINAL : public HUnaryControlInstruction {
};
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,
......
......@@ -49,6 +49,14 @@ void HComputeMinusZeroChecksPhase::Run() {
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();
}
}
}
}
......
......@@ -9114,6 +9114,15 @@ void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
}
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)));
......
......@@ -3052,6 +3052,32 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
}
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);
......
......@@ -2670,6 +2670,39 @@ void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
}
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,
......
......@@ -1768,6 +1768,16 @@ LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
}
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();
......
......@@ -74,6 +74,7 @@ class LCodeGen;
V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \
V(ClobberDoubles) \
V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
......@@ -900,6 +901,22 @@ class LCmpHoleAndBranch V8_FINAL : public LControlInstruction<1, 0> {
};
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) {
......
......@@ -630,6 +630,7 @@ namespace internal {
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) \
......
......@@ -3026,6 +3026,33 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
}
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);
......
......@@ -2246,6 +2246,37 @@ void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
}
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) {
......
......@@ -1672,6 +1672,15 @@ LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
}
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()));
......
......@@ -72,6 +72,7 @@ class LCodeGen;
V(ClampIToUint8) \
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CompareMinusZeroAndBranch) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
......@@ -874,6 +875,21 @@ class LCmpHoleAndBranch V8_FINAL : public LControlInstruction<1, 0> {
};
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) {
......
......@@ -25,7 +25,7 @@
// (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;
......@@ -35,3 +35,59 @@ assertEquals(0, add(0, 0));
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));
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