Add a genuine unary minus instruction to Crankshaft.

This change introduces an instruction for negation instead
of generating a multiplication with -1.

The code for x64 and ARM is not included in this change.


Review URL: http://codereview.chromium.org/6461021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6748 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 356c8ec2
...@@ -1298,6 +1298,12 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ...@@ -1298,6 +1298,12 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
} }
LInstruction* LChunkBuilder::DoNeg(HNeg* instr) {
Abort("Unimplemented: %s", "DoNeg");
return NULL;
}
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) { LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
return DoBit(Token::BIT_OR, instr); return DoBit(Token::BIT_OR, instr);
} }
......
...@@ -120,6 +120,7 @@ DEFINE_bool(time_hydrogen, false, "timing for hydrogen") ...@@ -120,6 +120,7 @@ DEFINE_bool(time_hydrogen, false, "timing for hydrogen")
DEFINE_bool(trace_hydrogen, false, "trace generated hydrogen to file") DEFINE_bool(trace_hydrogen, false, "trace generated hydrogen to file")
DEFINE_bool(trace_inlining, false, "trace inlining decisions") DEFINE_bool(trace_inlining, false, "trace inlining decisions")
DEFINE_bool(trace_alloc, false, "trace register allocator") DEFINE_bool(trace_alloc, false, "trace register allocator")
DEFINE_bool(trace_all_uses, false, "trace all use positions")
DEFINE_bool(trace_range, false, "trace range analysis") DEFINE_bool(trace_range, false, "trace range analysis")
DEFINE_bool(trace_gvn, false, "trace global value numbering") DEFINE_bool(trace_gvn, false, "trace global value numbering")
DEFINE_bool(trace_representation, false, "trace representation types") DEFINE_bool(trace_representation, false, "trace representation types")
......
...@@ -762,6 +762,12 @@ void HChange::PrintDataTo(StringStream* stream) const { ...@@ -762,6 +762,12 @@ void HChange::PrintDataTo(StringStream* stream) const {
} }
void HNeg::PrintDataTo(StringStream* stream) const {
HUnaryOperation::PrintDataTo(stream);
if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
}
HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction( HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction(
HValue* value) { HValue* value) {
STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE); STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE);
...@@ -967,6 +973,22 @@ Range* HMod::InferRange() { ...@@ -967,6 +973,22 @@ Range* HMod::InferRange() {
} }
Range* HNeg::InferRange() {
if (representation().IsInteger32()) {
Range* input_range = value()->range();
Range* result = input_range->Copy();
Range neg_one(-1, -1);
if (!result->MulAndCheckOverflow(&neg_one)) {
ClearFlag(HValue::kCanOverflow);
}
result->set_can_be_minus_zero(input_range->CanBeZero());
return result;
} else {
return HValue::InferRange();
}
}
void HPhi::PrintTo(StringStream* stream) const { void HPhi::PrintTo(StringStream* stream) const {
stream->Add("["); stream->Add("[");
for (int i = 0; i < OperandCount(); ++i) { for (int i = 0; i < OperandCount(); ++i) {
...@@ -1389,6 +1411,11 @@ HType HBitNot::CalculateInferredType() const { ...@@ -1389,6 +1411,11 @@ HType HBitNot::CalculateInferredType() const {
} }
HType HNeg::CalculateInferredType() const {
return HType::TaggedNumber();
}
HType HUnaryMathOperation::CalculateInferredType() const { HType HUnaryMathOperation::CalculateInferredType() const {
return HType::TaggedNumber(); return HType::TaggedNumber();
} }
...@@ -1467,6 +1494,15 @@ HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) { ...@@ -1467,6 +1494,15 @@ HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) {
} }
HValue* HNeg::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
if (range() == NULL || range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
return NULL;
}
HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) { HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id()); visited->Add(id());
// Propagate to the left argument. If the left argument cannot be -0, then // Propagate to the left argument. If the left argument cannot be -0, then
......
...@@ -131,6 +131,7 @@ class LChunkBuilder; ...@@ -131,6 +131,7 @@ class LChunkBuilder;
V(LoadPixelArrayExternalPointer) \ V(LoadPixelArrayExternalPointer) \
V(Mod) \ V(Mod) \
V(Mul) \ V(Mul) \
V(Neg) \
V(ObjectLiteral) \ V(ObjectLiteral) \
V(OsrEntry) \ V(OsrEntry) \
V(OuterContext) \ V(OuterContext) \
...@@ -1466,6 +1467,39 @@ class HBitNot: public HUnaryOperation { ...@@ -1466,6 +1467,39 @@ class HBitNot: public HUnaryOperation {
}; };
class HNeg: public HUnaryOperation {
public:
explicit HNeg(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kFlexibleRepresentation);
SetFlag(kCanOverflow);
SetAllSideEffects();
}
virtual void RepresentationChanged(Representation to) {
// May change from tagged to untagged, not vice versa.
ASSERT(representation().IsTagged() || representation().Equals(to));
if (!to.IsTagged()) {
ClearAllSideEffects();
SetFlag(kUseGVN);
}
}
virtual Representation RequiredInputRepresentation(int index) const {
return representation();
}
virtual HType CalculateInferredType() const;
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(Neg, "neg")
protected:
virtual bool DataEquals(HValue* other) const { return true; }
virtual Range* InferRange();
};
class HUnaryMathOperation: public HUnaryOperation { class HUnaryMathOperation: public HUnaryOperation {
public: public:
HUnaryMathOperation(HValue* value, BuiltinFunctionId op) HUnaryMathOperation(HValue* value, BuiltinFunctionId op)
......
...@@ -4700,7 +4700,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4700,7 +4700,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
instr = new HBitNot(value); instr = new HBitNot(value);
break; break;
case Token::SUB: case Token::SUB:
instr = new HMul(graph_->GetConstantMinus1(), value); instr = new HNeg(value);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -5911,7 +5911,7 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type) { ...@@ -5911,7 +5911,7 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type) {
UsePosition* current_pos = range->first_pos(); UsePosition* current_pos = range->first_pos();
while (current_pos != NULL) { while (current_pos != NULL) {
if (current_pos->RegisterIsBeneficial()) { if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
trace_.Add(" %d M", current_pos->pos().Value()); trace_.Add(" %d M", current_pos->pos().Value());
} }
current_pos = current_pos->next(); current_pos = current_pos->next();
......
...@@ -1035,6 +1035,36 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) { ...@@ -1035,6 +1035,36 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) {
} }
void LCodeGen::DoNegI(LNegI* instr) {
Register input = ToRegister(instr->value());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ test(input, Operand(input));
DeoptimizeIf(zero, instr->environment());
}
__ neg(input);
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
}
}
void LCodeGen::DoNegD(LNegD* instr) {
XMMRegister reg = ToDoubleRegister(instr->value());
Register temp = ToRegister(instr->TempAt(0));
__ Set(temp, Immediate(0x80000000));
__ movd(xmm0, Operand(temp));
__ psllq(xmm0, 32);
__ xorpd(reg, xmm0);
}
void LCodeGen::DoNegT(LNegT* instr) {
UnaryOverwriteMode overwrite = UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoThrow(LThrow* instr) {
__ push(ToOperand(instr->InputAt(0))); __ push(ToOperand(instr->InputAt(0)));
CallRuntime(Runtime::kThrow, 1, instr, false); CallRuntime(Runtime::kThrow, 1, instr, false);
......
...@@ -1316,6 +1316,29 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ...@@ -1316,6 +1316,29 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
} }
LInstruction* LChunkBuilder::DoNeg(HNeg* instr) {
Representation r = instr->representation();
if (r.IsInteger32()) {
LOperand* input = UseRegister(instr->value());
LNegI* result = new LNegI(input);
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow)) {
AssignEnvironment(result);
}
return DefineSameAsFirst(result);
} else if (r.IsDouble()) {
LOperand* input = UseRegister(instr->value());
LOperand* temp = TempRegister();
return DefineSameAsFirst(new LNegD(input, temp));
} else {
ASSERT(r.IsTagged());
LOperand* input = UseFixed(instr->value(), eax);
LNegT* result = new LNegT(input);
return MarkAsCall(DefineFixed(result, eax), instr);
}
}
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) { LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
return DoBit(Token::BIT_OR, instr); return DoBit(Token::BIT_OR, instr);
} }
......
...@@ -128,6 +128,9 @@ class LCodeGen; ...@@ -128,6 +128,9 @@ class LCodeGen;
V(LoadPixelArrayExternalPointer) \ V(LoadPixelArrayExternalPointer) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(NegI) \
V(NegD) \
V(NegT) \
V(NumberTagD) \ V(NumberTagD) \
V(NumberTagI) \ V(NumberTagI) \
V(NumberUntagD) \ V(NumberUntagD) \
...@@ -1079,6 +1082,40 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> { ...@@ -1079,6 +1082,40 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> {
}; };
class LNegI: public LTemplateInstruction<1, 1, 0> {
public:
explicit LNegI(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(NegI, "neg-i")
DECLARE_HYDROGEN_ACCESSOR(Neg)
LOperand* value() { return inputs_[0]; }
};
class LNegD: public LTemplateInstruction<1, 1, 1> {
public:
explicit LNegD(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(NegD, "neg-d")
LOperand* value() { return inputs_[0]; }
};
class LNegT: public LTemplateInstruction<1, 1, 0> {
public:
explicit LNegT(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(NegT, "neg-t")
};
class LAddI: public LTemplateInstruction<1, 2, 0> { class LAddI: public LTemplateInstruction<1, 2, 0> {
public: public:
LAddI(LOperand* left, LOperand* right) { LAddI(LOperand* left, LOperand* right) {
......
...@@ -1250,6 +1250,12 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ...@@ -1250,6 +1250,12 @@ LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
} }
LInstruction* LChunkBuilder::DoNeg(HNeg* instr) {
Abort("Unimplemented: %s", "DoNeg");
return NULL;
}
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) { LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
return DoBit(Token::BIT_OR, instr); return DoBit(Token::BIT_OR, instr);
} }
......
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