Revision: 13656
Author:   [email protected]
Date:     Wed Feb 13 06:16:15 2013
Log: Infrastructure classes for evaluating numeric relations between values.

Review URL: https://codereview.chromium.org/12226112
http://code.google.com/p/v8/source/detail?r=13656

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/mips/lithium-mips.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Tue Feb 12 03:44:08 2013
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Wed Feb 13 06:16:15 2013
@@ -1683,6 +1683,11 @@
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
   return DefineAsRegister(result);
 }
+
+
+LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) {
+  return NULL;
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Tue Feb 12 04:04:29 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Feb 13 06:16:15 2013
@@ -405,9 +405,10 @@
   if (dominator->block() != dominated->block()) {
     return dominator->block()->Dominates(dominated->block());
   } else {
-    // If both arguments are in the same block we check if "dominator" has
- // already been processed or if it is a phi: if yes it dominates the other. - return dominator->CheckFlag(kIDefsProcessingDone) || dominator->IsPhi(); + // If both arguments are in the same block we check if dominator is a phi + // or if dominated has not already been processed: in either case we know
+    // that dominator precedes dominated.
+ return dominator->IsPhi() | | !dominated->CheckFlag(kIDefsProcessingDone);
   }
 }

@@ -522,6 +523,16 @@
     default: return "";
   }
 }
+
+
+bool HValue::IsInteger32Constant() {
+  return IsConstant() && HConstant::cast(this)->HasInteger32Value();
+}
+
+
+int32_t HValue::GetInteger32Constant() {
+  return HConstant::cast(this)->Integer32Value();
+}


 void HValue::SetOperandAt(int index, HValue* value) {
@@ -799,6 +810,37 @@
   }
 }
 #endif
+
+
+HNumericConstraint* HNumericConstraint::AddToGraph(
+    HValue* constrained_value,
+    NumericRelation relation,
+    HValue* related_value,
+    HInstruction* insertion_point) {
+  if (insertion_point == NULL) {
+    if (constrained_value->IsInstruction()) {
+      insertion_point = HInstruction::cast(constrained_value);
+    } else if (constrained_value->IsPhi()) {
+      insertion_point = constrained_value->block()->first();
+    } else {
+      UNREACHABLE();
+    }
+  }
+  HNumericConstraint* result =
+      new(insertion_point->block()->zone()) HNumericConstraint(
+          constrained_value, relation, related_value);
+  result->InsertAfter(insertion_point);
+  return result;
+}
+
+
+void HNumericConstraint::PrintDataTo(StringStream* stream) {
+  stream->Add("(");
+  constrained_value()->PrintNameTo(stream);
+  stream->Add(" %s ", relation().Mnemonic());
+  related_value()->PrintNameTo(stream);
+  stream->Add(")");
+}


 void HDummyUse::PrintDataTo(StringStream* stream) {
@@ -822,10 +864,38 @@
 }


+void HBoundsCheck::AddInformativeDefinitions() {
+  // TODO(mmassi): Executing this code during AddInformativeDefinitions
+  // is a hack. Move it to some other HPhase.
+  if (index()->IsRelationTrue(NumericRelation::Ge(),
+                              block()->graph()->GetConstant0()) &&
+      index()->IsRelationTrue(NumericRelation::Lt(), length())) {
+    set_skip_check(true);
+  }
+}
+
+
+bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation,
+                                          HValue* related_value) {
+  if (related_value == length()) {
+    // A HBoundsCheck is smaller than the length it compared against.
+    return NumericRelation::Lt().Implies(relation);
+  } else if (related_value == block()->graph()->GetConstant0()) {
+    // A HBoundsCheck is greater than or equal to zero.
+    return NumericRelation::Ge().Implies(relation);
+  } else {
+    return false;
+  }
+}
+
+
 void HBoundsCheck::PrintDataTo(StringStream* stream) {
   index()->PrintNameTo(stream);
   stream->Add(" ");
   length()->PrintNameTo(stream);
+  if (skip_check()) {
+    stream->Add(" [DISABLED]");
+  }
 }


@@ -1480,6 +1550,38 @@
     return HValue::InferRange(zone);
   }
 }
+
+
+void HPhi::AddInformativeDefinitions() {
+  if (OperandCount() == 2) {
+    for (int operand_index = 0; operand_index < 2; operand_index++) {
+      int other_operand_index = (operand_index + 1) % 2;
+
+      // Add an idef that "discards" the OSR entry block branch.
+      if (OperandAt(operand_index)->block()->is_osr_entry()) {
+        HNumericConstraint::AddToGraph(
+            this, NumericRelation::Eq(), OperandAt(other_operand_index));
+      }
+
+      static NumericRelation relations[] = {
+        NumericRelation::Ge(),
+        NumericRelation::Le()
+      };
+
+      // Check if this phi is an induction variable. If, e.g., we know that
+      // its first input is greater than the phi itself, then that must be
+ // the back edge, and the phi is always greater than its second input.
+      for (int relation_index = 0; relation_index < 2; relation_index++) {
+ if (OperandAt(operand_index)->IsRelationTrue(relations[relation_index],
+                                                     this)) {
+          HNumericConstraint::AddToGraph(this,
+                                         relations[relation_index],
+                                         OperandAt(other_operand_index));
+        }
+      }
+    }
+  }
+}


 Range* HMathMinMax::InferRange(Zone* zone) {
@@ -1941,6 +2043,16 @@
   stream->Add(" ");
   HControlInstruction::PrintDataTo(stream);
 }
+
+
+void HCompareIDAndBranch::AddInformativeDefinitions() {
+  NumericRelation r = NumericRelation::FromToken(token());
+  if (r.IsNone()) return;
+
+ HNumericConstraint::AddToGraph(left(), r, right(), SuccessorAt(0)->first());
+  HNumericConstraint::AddToGraph(
+        left(), r.Negated(), right(), SuccessorAt(1)->first());
+}


 void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Feb 12 04:04:29 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Feb 13 06:16:15 2013
@@ -147,6 +147,7 @@
   V(MathMinMax)                                \
   V(Mod)                                       \
   V(Mul)                                       \
+  V(NumericConstraint)                         \
   V(ObjectLiteral)                             \
   V(OsrEntry)                                  \
   V(OuterContext)                              \
@@ -550,6 +551,127 @@
 #undef COUNT_FLAG
 };

+
+class NumericRelation {
+ public:
+  enum Kind { NONE, EQ, GT, GE, LT, LE, NE };
+  static const char* MnemonicFromKind(Kind kind) {
+    switch (kind) {
+      case NONE: return "NONE";
+      case EQ: return "EQ";
+      case GT: return "GT";
+      case GE: return "GE";
+      case LT: return "LT";
+      case LE: return "LE";
+      case NE: return "NE";
+    }
+    UNREACHABLE();
+    return NULL;
+  }
+  const char* Mnemonic() const { return MnemonicFromKind(kind_); }
+
+  static NumericRelation None() { return NumericRelation(NONE); }
+  static NumericRelation Eq() { return NumericRelation(EQ); }
+  static NumericRelation Gt() { return NumericRelation(GT); }
+  static NumericRelation Ge() { return NumericRelation(GE); }
+  static NumericRelation Lt() { return NumericRelation(LT); }
+  static NumericRelation Le() { return NumericRelation(LE); }
+  static NumericRelation Ne() { return NumericRelation(NE); }
+
+  bool IsNone() { return kind_ == NONE; }
+
+  static NumericRelation FromToken(Token::Value token) {
+    switch (token) {
+      case Token::EQ: return Eq();
+      case Token::EQ_STRICT: return Eq();
+      case Token::LT: return Lt();
+      case Token::GT: return Gt();
+      case Token::LTE: return Le();
+      case Token::GTE: return Ge();
+      case Token::NE: return Ne();
+      case Token::NE_STRICT: return Ne();
+      default: return None();
+    }
+  }
+
+  // The semantics of "Reversed" is that if "x rel y" is true then also
+ // "y rel.Reversed() x" is true, and that rel.Reversed().Reversed() == rel.
+  NumericRelation Reversed() {
+    switch (kind_) {
+      case NONE: return None();
+      case EQ: return Eq();
+      case GT: return Lt();
+      case GE: return Le();
+      case LT: return Gt();
+      case LE: return Ge();
+      case NE: return Ne();
+    }
+    UNREACHABLE();
+    return None();
+  }
+
+  // The semantics of "Negated" is that if "x rel y" is true then also
+  // "!(x rel.Negated() y)" is true.
+  NumericRelation Negated() {
+    switch (kind_) {
+      case NONE: return None();
+      case EQ: return Ne();
+      case GT: return Le();
+      case GE: return Lt();
+      case LT: return Ge();
+      case LE: return Gt();
+      case NE: return Eq();
+    }
+    UNREACHABLE();
+    return None();
+  }
+
+  // The semantics of "Implies" is that if "x rel y" is true
+  // then also "x other_relation y" is true.
+  bool Implies(NumericRelation other_relation) {
+    switch (kind_) {
+      case NONE: return false;
+      case EQ: return (other_relation.kind_ == EQ)
+          || (other_relation.kind_ == GE)
+          || (other_relation.kind_ == LE);
+      case GT: return (other_relation.kind_ == GT)
+          || (other_relation.kind_ == GE)
+          || (other_relation.kind_ == NE);
+      case LT: return (other_relation.kind_ == LT)
+          || (other_relation.kind_ == LE)
+          || (other_relation.kind_ == NE);
+      case GE: return (other_relation.kind_ == GE);
+      case LE: return (other_relation.kind_ == LE);
+      case NE: return (other_relation.kind_ == NE);
+    }
+    UNREACHABLE();
+    return false;
+  }
+
+  // The semantics of "IsExtendable" is that if
+  // "rel.IsExtendable(direction)" is true then
+  // "x rel y" implies "(x + direction) rel y" .
+  bool IsExtendable(int direction) {
+    switch (kind_) {
+      case NONE: return false;
+      case EQ: return false;
+      case GT: return (direction >= 0);
+      case GE: return (direction >= 0);
+      case LT: return (direction <= 0);
+      case LE: return (direction <= 0);
+      case NE: return false;
+    }
+    UNREACHABLE();
+    return false;
+  }
+
+ private:
+  explicit NumericRelation(Kind kind) : kind_(kind) {}
+
+  Kind kind_;
+};
+
+
 typedef EnumSet<GVNFlag> GVNFlagSet;


@@ -712,6 +834,9 @@
   void UpdateRedefinedUses() {
     UpdateRedefinedUsesInner<Dominates>();
   }
+
+  bool IsInteger32Constant();
+  int32_t GetInteger32Constant();

   bool IsDefinedAfter(HBasicBlock* other) const;

@@ -838,6 +963,24 @@
 #ifdef DEBUG
   virtual void Verify() = 0;
 #endif
+
+  // This method is recursive but it is guaranteed to terminate because
+  // RedefinedOperand() always dominates "this".
+  bool IsRelationTrue(NumericRelation relation, HValue* other) {
+    if (this == other) {
+      return NumericRelation::Eq().Implies(relation);
+    }
+
+    bool result = IsRelationTrueInternal(relation, other) ||
+        other->IsRelationTrueInternal(relation.Reversed(), this);
+    if (!result) {
+      HValue* redefined = RedefinedOperand();
+      if (redefined != NULL) {
+        result = redefined->IsRelationTrue(relation, other);
+      }
+    }
+    return result;
+  }

  protected:
// This function must be overridden for instructions with flag kUseGVN, to
@@ -900,6 +1043,12 @@
       }
     }
   }
+
+  // Informative definitions can override this method to state any numeric
+  // relation they provide on the redefined value.
+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) {
+    return false;
+  }

   static GVNFlagSet AllDependsOnFlagSet() {
     GVNFlagSet result;
@@ -1125,6 +1274,50 @@
 };


+class HNumericConstraint : public HTemplateInstruction<2> {
+ public:
+  static HNumericConstraint* AddToGraph(HValue* constrained_value,
+                                        NumericRelation relation,
+                                        HValue* related_value,
+ HInstruction* insertion_point = NULL);
+
+  HValue* constrained_value() { return OperandAt(0); }
+  HValue* related_value() { return OperandAt(1); }
+  NumericRelation relation() { return relation_; }
+
+  virtual int RedefinedOperandIndex() { return 0; }
+
+  virtual Representation RequiredInputRepresentation(int index) {
+    return representation();
+  }
+
+  virtual void PrintDataTo(StringStream* stream);
+
+  virtual bool IsRelationTrueInternal(NumericRelation other_relation,
+                                      HValue* other_related_value) {
+    if (related_value() == other_related_value) {
+      return relation().Implies(other_relation);
+    } else {
+      return false;
+    }
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumericConstraint)
+
+ private:
+  HNumericConstraint(HValue* constrained_value,
+                     NumericRelation relation,
+                     HValue* related_value)
+      : relation_(relation) {
+    SetOperandAt(0, constrained_value);
+    SetOperandAt(1, related_value);
+    set_representation(constrained_value->representation());
+  }
+
+  NumericRelation relation_;
+};
+
+
 // We insert soft-deoptimize when we hit code with unknown typefeedback,
 // so that we get a chance of re-optimizing with useful typefeedback.
 // HSoftDeoptimize does not end a basic block as opposed to HDeoptimize.
@@ -2676,6 +2869,8 @@
   bool IsReceiver() { return merged_index_ == 0; }

   int merged_index() const { return merged_index_; }
+
+  virtual void AddInformativeDefinitions();

   virtual void PrintTo(StringStream* stream);

@@ -3153,6 +3348,9 @@
   virtual Representation observed_input_representation(int index) {
     return Representation::Integer32();
   }
+
+  virtual bool IsRelationTrueInternal(NumericRelation relation,
+                                      HValue* related_value);

   virtual void PrintDataTo(StringStream* stream);
   virtual void InferRepresentation(HInferRepresentation* h_infer);
@@ -3161,6 +3359,7 @@
   HValue* length() { return OperandAt(1); }

   virtual int RedefinedOperandIndex() { return 0; }
+  virtual void AddInformativeDefinitions();

   DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)

@@ -3337,6 +3536,8 @@
   }
   virtual void PrintDataTo(StringStream* stream);

+  virtual void AddInformativeDefinitions();
+
   DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)

  private:
@@ -3741,6 +3942,23 @@

   virtual HValue* Canonicalize();

+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) {
+    HValue* base = NULL;
+    int32_t offset = 0;
+    if (left()->IsInteger32Constant()) {
+      base = right();
+      offset = left()->GetInteger32Constant();
+    } else if (right()->IsInteger32Constant()) {
+      base = left();
+      offset = right()->GetInteger32Constant();
+    } else {
+      return false;
+    }
+
+    return relation.IsExtendable(offset)
+        ? base->IsRelationTrue(relation, other) : false;
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(Add)

  protected:
@@ -3766,6 +3984,17 @@
                                HValue* left,
                                HValue* right);

+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) {
+    if (right()->IsInteger32Constant()) {
+      HValue* base = left();
+      int32_t offset = right()->GetInteger32Constant();
+      return relation.IsExtendable(-offset)
+          ? base->IsRelationTrue(relation, other) : false;
+    } else {
+      return false;
+    }
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(Sub)

  protected:
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Feb 12 06:00:39 2013
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Feb 13 06:16:15 2013
@@ -71,7 +71,8 @@
       parent_loop_header_(NULL),
       is_inline_return_target_(false),
       is_deoptimizing_(false),
-      dominates_loop_successors_(false) { }
+      dominates_loop_successors_(false),
+      is_osr_entry_(false) { }


 void HBasicBlock::AttachLoopInformation() {
@@ -3794,6 +3795,12 @@
   OrderBlocks();
   AssignDominators();

+  // We need to create a HConstant "zero" now so that GVN will fold every
+  // zero-valued constant in the graph together.
+  // The constant is needed to make idef-based bounds check work: the pass
+ // evaluates relations with "zero" and that zero cannot be created after GVN.
+  GetConstant0();
+
 #ifdef DEBUG
   // Do a full verify after building the graph and computing dominators.
   Verify(true);
@@ -3871,12 +3878,14 @@
for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) {
     HPhi* phi = block->phis()->at(phi_index);
     phi->AddInformativeDefinitions();
+    phi->SetFlag(HValue::kIDefsProcessingDone);
     // We do not support phis that "redefine just one operand".
     ASSERT(!phi->IsInformativeDefinition());
   }

   for (HInstruction* i = block->first(); i != NULL; i = i->next()) {
     i->AddInformativeDefinitions();
+    i->SetFlag(HValue::kIDefsProcessingDone);
     i->UpdateRedefinedUsesWhileSettingUpInformativeDefinitions();
   }
 }
@@ -4897,6 +4906,7 @@
   non_osr_entry->Goto(loop_predecessor);

   set_current_block(osr_entry);
+  osr_entry->set_osr_entry();
   BailoutId osr_entry_id = statement->OsrEntryId();
   int first_expression_index = environment()->first_expression_index();
   int length = environment()->length();
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Tue Feb 12 03:44:08 2013
+++ /branches/bleeding_edge/src/hydrogen.h      Wed Feb 13 06:16:15 2013
@@ -91,6 +91,8 @@
   void set_last_instruction_index(int index) {
     last_instruction_index_ = index;
   }
+  bool is_osr_entry() { return is_osr_entry_; }
+  void set_osr_entry() { is_osr_entry_ = true; }

   void AttachLoopInformation();
   void DetachLoopInformation();
@@ -193,6 +195,7 @@
   bool is_inline_return_target_;
   bool is_deoptimizing_;
   bool dominates_loop_successors_;
+  bool is_osr_entry_;
 };


=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Feb 12 03:44:08 2013 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Wed Feb 13 06:16:15 2013
@@ -1710,6 +1710,11 @@
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
   return DefineSameAsFirst(result);
 }
+
+
+LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) {
+  return NULL;
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Feb 13 06:01:22 2013 +++ /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Feb 13 06:16:15 2013
@@ -1588,6 +1588,11 @@
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
   return DefineAsRegister(result);
 }
+
+
+LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) {
+  return NULL;
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Tue Feb 12 03:44:08 2013
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Wed Feb 13 06:16:15 2013
@@ -1634,6 +1634,11 @@
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
   return DefineSameAsFirst(result);
 }
+
+
+LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) {
+  return NULL;
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to