diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 625 |
1 files changed, 448 insertions, 177 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 854854f238..01ba704610 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2394,7 +2394,7 @@ class HIntConstant : public HConstant { } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - DCHECK(other->IsIntConstant()); + DCHECK(other->IsIntConstant()) << other->DebugName(); return other->AsIntConstant()->value_ == value_; } @@ -2427,7 +2427,7 @@ class HLongConstant : public HConstant { uint64_t GetValueAsUint64() const OVERRIDE { return value_; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - DCHECK(other->IsLongConstant()); + DCHECK(other->IsLongConstant()) << other->DebugName(); return other->AsLongConstant()->value_ == value_; } @@ -2449,6 +2449,92 @@ class HLongConstant : public HConstant { DISALLOW_COPY_AND_ASSIGN(HLongConstant); }; +class HFloatConstant : public HConstant { + public: + float GetValue() const { return value_; } + + uint64_t GetValueAsUint64() const OVERRIDE { + return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_)); + } + + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { + DCHECK(other->IsFloatConstant()) << other->DebugName(); + return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64(); + } + + size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } + + bool IsMinusOne() const OVERRIDE { + return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f)); + } + bool IsZero() const OVERRIDE { + return value_ == 0.0f; + } + bool IsOne() const OVERRIDE { + return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f); + } + bool IsNaN() const { + return std::isnan(value_); + } + + DECLARE_INSTRUCTION(FloatConstant); + + private: + explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc) + : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {} + explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc) + : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {} + + const float value_; + + // Only the SsaBuilder and HGraph can create floating-point constants. + friend class SsaBuilder; + friend class HGraph; + DISALLOW_COPY_AND_ASSIGN(HFloatConstant); +}; + +class HDoubleConstant : public HConstant { + public: + double GetValue() const { return value_; } + + uint64_t GetValueAsUint64() const OVERRIDE { return bit_cast<uint64_t, double>(value_); } + + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { + DCHECK(other->IsDoubleConstant()) << other->DebugName(); + return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64(); + } + + size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } + + bool IsMinusOne() const OVERRIDE { + return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0)); + } + bool IsZero() const OVERRIDE { + return value_ == 0.0; + } + bool IsOne() const OVERRIDE { + return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0); + } + bool IsNaN() const { + return std::isnan(value_); + } + + DECLARE_INSTRUCTION(DoubleConstant); + + private: + explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc) + : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {} + explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc) + : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {} + + const double value_; + + // Only the SsaBuilder and HGraph can create floating-point constants. + friend class SsaBuilder; + friend class HGraph; + DISALLOW_COPY_AND_ASSIGN(HDoubleConstant); +}; + // Conditional branch. A block ending with an HIf instruction must have // two successors. class HIf : public HTemplateInstruction<1> { @@ -2650,14 +2736,16 @@ class HUnaryOperation : public HExpression<1> { return true; } - // Try to statically evaluate `operation` and return a HConstant - // containing the result of this evaluation. If `operation` cannot + // Try to statically evaluate `this` and return a HConstant + // containing the result of this evaluation. If `this` cannot // be evaluated as a constant, return null. HConstant* TryStaticEvaluation() const; // Apply this operation to `x`. virtual HConstant* Evaluate(HIntConstant* x) const = 0; virtual HConstant* Evaluate(HLongConstant* x) const = 0; + virtual HConstant* Evaluate(HFloatConstant* x) const = 0; + virtual HConstant* Evaluate(HDoubleConstant* x) const = 0; DECLARE_ABSTRACT_INSTRUCTION(UnaryOperation); @@ -2720,12 +2808,17 @@ class HBinaryOperation : public HExpression<2> { return true; } - // Try to statically evaluate `operation` and return a HConstant - // containing the result of this evaluation. If `operation` cannot + // Try to statically evaluate `this` and return a HConstant + // containing the result of this evaluation. If `this` cannot // be evaluated as a constant, return null. HConstant* TryStaticEvaluation() const; // Apply this operation to `x` and `y`. + virtual HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, + HNullConstant* y ATTRIBUTE_UNUSED) const { + VLOG(compiler) << DebugName() << " is not defined for the (null, null) case."; + return nullptr; + } virtual HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const = 0; virtual HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const = 0; virtual HConstant* Evaluate(HIntConstant* x ATTRIBUTE_UNUSED, @@ -2738,11 +2831,8 @@ class HBinaryOperation : public HExpression<2> { VLOG(compiler) << DebugName() << " is not defined for the (long, int) case."; return nullptr; } - virtual HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, - HNullConstant* y ATTRIBUTE_UNUSED) const { - VLOG(compiler) << DebugName() << " is not defined for the (null, null) case."; - return nullptr; - } + virtual HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const = 0; + virtual HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const = 0; // Returns an input that can legally be used as the right input and is // constant, or null. @@ -2766,6 +2856,8 @@ enum class ComparisonBias { kLtBias, // return -1 for NaN comparisons }; +std::ostream& operator<<(std::ostream& os, const ComparisonBias& rhs); + class HCondition : public HBinaryOperation { public: HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) @@ -2783,7 +2875,7 @@ class HCondition : public HBinaryOperation { virtual IfCondition GetOppositeCondition() const = 0; bool IsGtBias() const { return bias_ == ComparisonBias::kGtBias; } - + ComparisonBias GetBias() const { return bias_; } void SetBias(ComparisonBias bias) { bias_ = bias; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { @@ -2791,17 +2883,34 @@ class HCondition : public HBinaryOperation { } bool IsFPConditionTrueIfNaN() const { - DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())); + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType(); IfCondition if_cond = GetCondition(); return IsGtBias() ? ((if_cond == kCondGT) || (if_cond == kCondGE)) : (if_cond == kCondNE); } bool IsFPConditionFalseIfNaN() const { - DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())); + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType(); IfCondition if_cond = GetCondition(); return IsGtBias() ? ((if_cond == kCondLT) || (if_cond == kCondLE)) : (if_cond == kCondEQ); } + protected: + template <typename T> + int32_t Compare(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); } + + template <typename T> + int32_t CompareFP(T x, T y) const { + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType(); + DCHECK_NE(GetBias(), ComparisonBias::kNoBias); + // Handle the bias. + return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compare(x, y); + } + + // Return an integer constant containing the result of a condition evaluated at compile time. + HIntConstant* MakeConstantCondition(bool value, uint32_t dex_pc) const { + return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc); + } + private: // Needed if we merge a HCompare into a HCondition. ComparisonBias bias_; @@ -2817,17 +2926,25 @@ class HEqual : public HCondition { bool IsCommutative() const OVERRIDE { return true; } + HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, + HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + return MakeConstantCondition(true, GetDexPc()); + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HEqual instruction; evaluate it as + // `Compare(x, y) == 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), + GetDexPc()); } - HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, - HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant(1); + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(Equal); @@ -2853,17 +2970,24 @@ class HNotEqual : public HCondition { bool IsCommutative() const OVERRIDE { return true; } + HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, + HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + return MakeConstantCondition(false, GetDexPc()); + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HNotEqual instruction; evaluate it as + // `Compare(x, y) != 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc()); } - HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED, - HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant(0); + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(NotEqual); @@ -2888,12 +3012,19 @@ class HLessThan : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HLessThan instruction; evaluate it as + // `Compare(x, y) < 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(LessThan); @@ -2918,12 +3049,19 @@ class HLessThanOrEqual : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HLessThanOrEqual instruction; evaluate it as + // `Compare(x, y) <= 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(LessThanOrEqual); @@ -2948,12 +3086,19 @@ class HGreaterThan : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HGreaterThan instruction; evaluate it as + // `Compare(x, y) > 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(GreaterThan); @@ -2978,12 +3123,19 @@ class HGreaterThanOrEqual : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + // In the following Evaluate methods, a HCompare instruction has + // been merged into this HGreaterThanOrEqual instruction; evaluate it as + // `Compare(x, y) >= 0`. HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc()); } DECLARE_INSTRUCTION(GreaterThanOrEqual); @@ -3008,14 +3160,20 @@ class HBelow : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint32_t>(x->GetValue()), - static_cast<uint32_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint64_t>(x->GetValue()), - static_cast<uint64_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); } DECLARE_INSTRUCTION(Below); @@ -3029,7 +3187,9 @@ class HBelow : public HCondition { } private: - template <typename T> bool Compute(T x, T y) const { return x < y; } + template <typename T> bool Compute(T x, T y) const { + return MakeUnsigned(x) < MakeUnsigned(y); + } DISALLOW_COPY_AND_ASSIGN(HBelow); }; @@ -3040,14 +3200,20 @@ class HBelowOrEqual : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint32_t>(x->GetValue()), - static_cast<uint32_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint64_t>(x->GetValue()), - static_cast<uint64_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); } DECLARE_INSTRUCTION(BelowOrEqual); @@ -3061,7 +3227,9 @@ class HBelowOrEqual : public HCondition { } private: - template <typename T> bool Compute(T x, T y) const { return x <= y; } + template <typename T> bool Compute(T x, T y) const { + return MakeUnsigned(x) <= MakeUnsigned(y); + } DISALLOW_COPY_AND_ASSIGN(HBelowOrEqual); }; @@ -3072,14 +3240,20 @@ class HAbove : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint32_t>(x->GetValue()), - static_cast<uint32_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint64_t>(x->GetValue()), - static_cast<uint64_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); } DECLARE_INSTRUCTION(Above); @@ -3093,7 +3267,9 @@ class HAbove : public HCondition { } private: - template <typename T> bool Compute(T x, T y) const { return x > y; } + template <typename T> bool Compute(T x, T y) const { + return MakeUnsigned(x) > MakeUnsigned(y); + } DISALLOW_COPY_AND_ASSIGN(HAbove); }; @@ -3104,14 +3280,20 @@ class HAboveOrEqual : public HCondition { : HCondition(first, second, dex_pc) {} HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint32_t>(x->GetValue()), - static_cast<uint32_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(static_cast<uint64_t>(x->GetValue()), - static_cast<uint64_t>(y->GetValue())), GetDexPc()); + return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); } DECLARE_INSTRUCTION(AboveOrEqual); @@ -3125,7 +3307,9 @@ class HAboveOrEqual : public HCondition { } private: - template <typename T> bool Compute(T x, T y) const { return x >= y; } + template <typename T> bool Compute(T x, T y) const { + return MakeUnsigned(x) >= MakeUnsigned(y); + } DISALLOW_COPY_AND_ASSIGN(HAboveOrEqual); }; @@ -3150,15 +3334,32 @@ class HCompare : public HBinaryOperation { } template <typename T> - int32_t Compute(T x, T y) const { return x == y ? 0 : x > y ? 1 : -1; } + int32_t Compute(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); } + + template <typename T> + int32_t ComputeFP(T x, T y) const { + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType(); + DCHECK_NE(GetBias(), ComparisonBias::kNoBias); + // Handle the bias. + return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compute(x, y); + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + // Note that there is no "cmp-int" Dex instruction so we shouldn't + // reach this code path when processing a freshly built HIR + // graph. However HCompare integer instructions can be synthesized + // by the instruction simplifier to implement IntegerCompare and + // IntegerSignum intrinsics, so we have to handle this case. + return MakeConstantComparison(Compute(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + return MakeConstantComparison(Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { @@ -3167,8 +3368,12 @@ class HCompare : public HBinaryOperation { ComparisonBias GetBias() const { return bias_; } - bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; } - + // Does this compare instruction have a "gt bias" (vs an "lt bias")? + // Only meaninfgul for floating-point comparisons. + bool IsGtBias() const { + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType(); + return bias_ == ComparisonBias::kGtBias; + } static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) { // MIPS64 uses a runtime call for FP comparisons. @@ -3177,6 +3382,13 @@ class HCompare : public HBinaryOperation { DECLARE_INSTRUCTION(Compare); + protected: + // Return an integer constant containing the result of a comparison evaluated at compile time. + HIntConstant* MakeConstantComparison(int32_t value, uint32_t dex_pc) const { + DCHECK(value == -1 || value == 0 || value == 1) << value; + return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc); + } + private: const ComparisonBias bias_; @@ -3234,92 +3446,6 @@ class HStoreLocal : public HTemplateInstruction<2> { DISALLOW_COPY_AND_ASSIGN(HStoreLocal); }; -class HFloatConstant : public HConstant { - public: - float GetValue() const { return value_; } - - uint64_t GetValueAsUint64() const OVERRIDE { - return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_)); - } - - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - DCHECK(other->IsFloatConstant()); - return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64(); - } - - size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } - - bool IsMinusOne() const OVERRIDE { - return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f)); - } - bool IsZero() const OVERRIDE { - return value_ == 0.0f; - } - bool IsOne() const OVERRIDE { - return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f); - } - bool IsNaN() const { - return std::isnan(value_); - } - - DECLARE_INSTRUCTION(FloatConstant); - - private: - explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc) - : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {} - explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {} - - const float value_; - - // Only the SsaBuilder and HGraph can create floating-point constants. - friend class SsaBuilder; - friend class HGraph; - DISALLOW_COPY_AND_ASSIGN(HFloatConstant); -}; - -class HDoubleConstant : public HConstant { - public: - double GetValue() const { return value_; } - - uint64_t GetValueAsUint64() const OVERRIDE { return bit_cast<uint64_t, double>(value_); } - - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - DCHECK(other->IsDoubleConstant()); - return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64(); - } - - size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } - - bool IsMinusOne() const OVERRIDE { - return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0)); - } - bool IsZero() const OVERRIDE { - return value_ == 0.0; - } - bool IsOne() const OVERRIDE { - return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0); - } - bool IsNaN() const { - return std::isnan(value_); - } - - DECLARE_INSTRUCTION(DoubleConstant); - - private: - explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc) - : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {} - explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {} - - const double value_; - - // Only the SsaBuilder and HGraph can create floating-point constants. - friend class SsaBuilder; - friend class HGraph; - DISALLOW_COPY_AND_ASSIGN(HDoubleConstant); -}; - class HNewInstance : public HExpression<2> { public: HNewInstance(HInstruction* cls, @@ -3871,6 +3997,12 @@ class HNeg : public HUnaryOperation { HConstant* Evaluate(HLongConstant* x) const OVERRIDE { return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant(Compute(x->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant(Compute(x->GetValue()), GetDexPc()); + } DECLARE_INSTRUCTION(Neg); @@ -3937,6 +4069,14 @@ class HAdd : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } DECLARE_INSTRUCTION(Add); @@ -3962,6 +4102,14 @@ class HSub : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } DECLARE_INSTRUCTION(Sub); @@ -3989,6 +4137,14 @@ class HMul : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } DECLARE_INSTRUCTION(Mul); @@ -4005,7 +4161,8 @@ class HDiv : public HBinaryOperation { : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {} template <typename T> - T Compute(T x, T y) const { + T ComputeIntegral(T x, T y) const { + DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType(); // Our graph structure ensures we never have 0 for `y` during // constant folding. DCHECK_NE(y, 0); @@ -4013,13 +4170,27 @@ class HDiv : public HBinaryOperation { return (y == -1) ? -x : x / y; } + template <typename T> + T ComputeFP(T x, T y) const { + DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType(); + return x / y; + } + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetLongConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); } static SideEffects SideEffectsForArchRuntimeCalls() { @@ -4042,7 +4213,8 @@ class HRem : public HBinaryOperation { : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {} template <typename T> - T Compute(T x, T y) const { + T ComputeIntegral(T x, T y) const { + DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType(); // Our graph structure ensures we never have 0 for `y` during // constant folding. DCHECK_NE(y, 0); @@ -4050,15 +4222,28 @@ class HRem : public HBinaryOperation { return (y == -1) ? 0 : x % y; } + template <typename T> + T ComputeFP(T x, T y) const { + DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType(); + return std::fmod(x, y); + } + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); } HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetLongConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + ComputeFP(x->GetValue(), y->GetValue()), GetDexPc()); } - static SideEffects SideEffectsForArchRuntimeCalls() { return SideEffects::CanTriggerGC(); @@ -4125,6 +4310,16 @@ class HShl : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Shl); @@ -4161,6 +4356,16 @@ class HShr : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Shr); @@ -4198,6 +4403,16 @@ class HUShr : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(UShr); @@ -4234,6 +4449,16 @@ class HAnd : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(And); @@ -4270,6 +4495,16 @@ class HOr : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Or); @@ -4306,6 +4541,16 @@ class HXor : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Xor); @@ -4344,6 +4589,16 @@ class HRor : public HBinaryOperation { return GetBlock()->GetGraph()->GetLongConstant( Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Ror); @@ -4410,6 +4665,14 @@ class HNot : public HUnaryOperation { HConstant* Evaluate(HLongConstant* x) const OVERRIDE { return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc()); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(Not); @@ -4428,7 +4691,7 @@ class HBooleanNot : public HUnaryOperation { } template <typename T> bool Compute(T x) const { - DCHECK(IsUint<1>(x)); + DCHECK(IsUint<1>(x)) << x; return !x; } @@ -4439,6 +4702,14 @@ class HBooleanNot : public HUnaryOperation { LOG(FATAL) << DebugName() << " is not defined for long values"; UNREACHABLE(); } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } DECLARE_INSTRUCTION(BooleanNot); @@ -4786,10 +5057,10 @@ class HArrayGet : public HExpression<2> { DCHECK_EQ(GetArray(), other->GetArray()); DCHECK_EQ(GetIndex(), other->GetIndex()); if (Primitive::IsIntOrLongType(GetType())) { - DCHECK(Primitive::IsFloatingPointType(other->GetType())); + DCHECK(Primitive::IsFloatingPointType(other->GetType())) << other->GetType(); } else { - DCHECK(Primitive::IsFloatingPointType(GetType())); - DCHECK(Primitive::IsIntOrLongType(other->GetType())); + DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType(); + DCHECK(Primitive::IsIntOrLongType(other->GetType())) << other->GetType(); } } return result; @@ -6004,7 +6275,7 @@ inline int64_t Int64FromConstant(HConstant* constant) { } else if (constant->IsLongConstant()) { return constant->AsLongConstant()->GetValue(); } else { - DCHECK(constant->IsNullConstant()); + DCHECK(constant->IsNullConstant()) << constant->DebugName(); return 0; } } |