From bbba0dbd61fb77391bdbf07b2517a63f61174159 Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Fri, 11 Feb 2011 12:56:30 +0000 Subject: [PATCH] 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 --- src/arm/lithium-arm.cc | 6 ++++++ src/flag-definitions.h | 1 + src/hydrogen-instructions.cc | 36 +++++++++++++++++++++++++++++++ src/hydrogen-instructions.h | 34 +++++++++++++++++++++++++++++ src/hydrogen.cc | 4 ++-- src/ia32/lithium-codegen-ia32.cc | 30 ++++++++++++++++++++++++++ src/ia32/lithium-ia32.cc | 23 ++++++++++++++++++++ src/ia32/lithium-ia32.h | 37 ++++++++++++++++++++++++++++++++ src/x64/lithium-x64.cc | 6 ++++++ 9 files changed, 175 insertions(+), 2 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 82de5d3e18..64f17994f5 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -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) { return DoBit(Token::BIT_OR, instr); } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index b64a76a32e..eb0bd3f70d 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -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_inlining, false, "trace inlining decisions") 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_gvn, false, "trace global value numbering") DEFINE_bool(trace_representation, false, "trace representation types") diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index eb1c5927d2..241a01524d 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -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( HValue* value) { STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE); @@ -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 { stream->Add("["); for (int i = 0; i < OperandCount(); ++i) { @@ -1389,6 +1411,11 @@ HType HBitNot::CalculateInferredType() const { } +HType HNeg::CalculateInferredType() const { + return HType::TaggedNumber(); +} + + HType HUnaryMathOperation::CalculateInferredType() const { return HType::TaggedNumber(); } @@ -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) { visited->Add(id()); // Propagate to the left argument. If the left argument cannot be -0, then diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 701813133c..c65e8303ac 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -131,6 +131,7 @@ class LChunkBuilder; V(LoadPixelArrayExternalPointer) \ V(Mod) \ V(Mul) \ + V(Neg) \ V(ObjectLiteral) \ V(OsrEntry) \ V(OuterContext) \ @@ -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 { public: HUnaryMathOperation(HValue* value, BuiltinFunctionId op) diff --git a/src/hydrogen.cc b/src/hydrogen.cc index d599bd6f8b..c341cd3aff 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4700,7 +4700,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { instr = new HBitNot(value); break; case Token::SUB: - instr = new HMul(graph_->GetConstantMinus1(), value); + instr = new HNeg(value); break; default: UNREACHABLE(); @@ -5911,7 +5911,7 @@ void HTracer::TraceLiveRange(LiveRange* range, const char* type) { UsePosition* current_pos = range->first_pos(); while (current_pos != NULL) { - if (current_pos->RegisterIsBeneficial()) { + if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { trace_.Add(" %d M", current_pos->pos().Value()); } current_pos = current_pos->next(); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 7724f1b820..6a8fca594b 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -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) { __ push(ToOperand(instr->InputAt(0))); CallRuntime(Runtime::kThrow, 1, instr, false); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 0ad3819292..e59cab32db 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -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) { return DoBit(Token::BIT_OR, instr); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index f1b9ffc997..65875c33cc 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -128,6 +128,9 @@ class LCodeGen; V(LoadPixelArrayExternalPointer) \ V(ModI) \ V(MulI) \ + V(NegI) \ + V(NegD) \ + V(NegT) \ V(NumberTagD) \ V(NumberTagI) \ V(NumberUntagD) \ @@ -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> { public: LAddI(LOperand* left, LOperand* right) { diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index a6afbf722e..c38305b27f 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -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) { return DoBit(Token::BIT_OR, instr); }