diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 94 |
1 files changed, 90 insertions, 4 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 8b56166610..a35fa1d8c3 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -103,7 +103,7 @@ class HInstructionList { // Control-flow graph of a method. Contains a list of basic blocks. class HGraph : public ArenaObject<kArenaAllocMisc> { public: - HGraph(ArenaAllocator* arena, int start_instruction_id = 0) + HGraph(ArenaAllocator* arena, bool debuggable = false, int start_instruction_id = 0) : arena_(arena), blocks_(arena, kDefaultNumberOfBlocks), reverse_post_order_(arena, kDefaultNumberOfBlocks), @@ -114,6 +114,7 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { number_of_in_vregs_(0), temporaries_vreg_slots_(0), has_array_accesses_(false), + debuggable_(debuggable), current_instruction_id_(start_instruction_id) {} ArenaAllocator* GetArena() const { return arena_; } @@ -132,8 +133,13 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { // recognition. Returns whether it was successful in doing all these steps. bool TryBuildingSsa() { BuildDominatorTree(); + // The SSA builder requires loops to all be natural. Specifically, the dead phi + // elimination phase checks the consistency of the graph when doing a post-order + // visit for eliminating dead phis: a dead phi can only have loop header phi + // users remaining when being visited. + if (!AnalyzeNaturalLoops()) return false; TransformToSsa(); - return AnalyzeNaturalLoops(); + return true; } void BuildDominatorTree(); @@ -208,6 +214,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { has_array_accesses_ = value; } + bool IsDebuggable() const { return debuggable_; } + HNullConstant* GetNullConstant(); private: @@ -248,6 +256,11 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { // Has array accesses. We can totally skip BCE if it's false. bool has_array_accesses_; + // Indicates whether the graph should be compiled in a way that + // ensures full debuggability. If false, we can apply more + // aggressive optimizations that may limit the level of debugging. + const bool debuggable_; + // The current id to assign to a newly added instruction. See HInstruction.id_. int32_t current_instruction_id_; @@ -1096,6 +1109,7 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { bool HasUses() const { return !uses_.IsEmpty() || !env_uses_.IsEmpty(); } bool HasEnvironmentUses() const { return !env_uses_.IsEmpty(); } + bool HasNonEnvironmentUses() const { return !uses_.IsEmpty(); } // Does this instruction strictly dominate `other_instruction`? // Returns false if this instruction and `other_instruction` are the same. @@ -1561,6 +1575,14 @@ class HBinaryOperation : public HExpression<2> { virtual int32_t Evaluate(int32_t x, int32_t y) const = 0; virtual int64_t Evaluate(int64_t x, int64_t y) const = 0; + // Returns an input that can legally be used as the right input and is + // constant, or nullptr. + HConstant* GetConstantRight() const; + + // If `GetConstantRight()` returns one of the input, this returns the other + // one. Otherwise it returns nullptr. + HInstruction* GetLeastConstantLeft() const; + DECLARE_INSTRUCTION(BinaryOperation); private: @@ -1832,6 +1854,12 @@ class HConstant : public HExpression<0> { bool CanBeMoved() const OVERRIDE { return true; } + virtual bool IsMinusOne() const { return false; } + virtual bool IsZero() const { return false; } + virtual bool IsOne() const { return false; } + + static HConstant* NewConstant(ArenaAllocator* allocator, Primitive::Type type, int64_t val); + DECLARE_INSTRUCTION(Constant); private: @@ -1851,6 +1879,16 @@ class HFloatConstant : public HConstant { size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } + bool IsMinusOne() const OVERRIDE { + return bit_cast<uint32_t>(AsFloatConstant()->GetValue()) == bit_cast<uint32_t>((-1.0f)); + } + bool IsZero() const OVERRIDE { + return AsFloatConstant()->GetValue() == 0.0f; + } + bool IsOne() const OVERRIDE { + return bit_cast<uint32_t>(AsFloatConstant()->GetValue()) == bit_cast<uint32_t>(1.0f); + } + DECLARE_INSTRUCTION(FloatConstant); private: @@ -1872,6 +1910,16 @@ class HDoubleConstant : public HConstant { size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } + bool IsMinusOne() const OVERRIDE { + return bit_cast<uint64_t>(AsDoubleConstant()->GetValue()) == bit_cast<uint64_t>((-1.0)); + } + bool IsZero() const OVERRIDE { + return AsDoubleConstant()->GetValue() == 0.0; + } + bool IsOne() const OVERRIDE { + return bit_cast<uint64_t>(AsDoubleConstant()->GetValue()) == bit_cast<uint64_t>(1.0); + } + DECLARE_INSTRUCTION(DoubleConstant); private: @@ -1917,6 +1965,10 @@ class HIntConstant : public HConstant { // method is an workaround until we fix the above. bool ActAsNullConstant() const OVERRIDE { return value_ == 0; } + bool IsMinusOne() const OVERRIDE { return GetValue() == -1; } + bool IsZero() const OVERRIDE { return GetValue() == 0; } + bool IsOne() const OVERRIDE { return GetValue() == 1; } + DECLARE_INSTRUCTION(IntConstant); private: @@ -1937,6 +1989,10 @@ class HLongConstant : public HConstant { size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); } + bool IsMinusOne() const OVERRIDE { return GetValue() == -1; } + bool IsZero() const OVERRIDE { return GetValue() == 0; } + bool IsOne() const OVERRIDE { return GetValue() == 1; } + DECLARE_INSTRUCTION(LongConstant); private: @@ -2498,6 +2554,19 @@ class HPhi : public HInstruction { inputs_.SetSize(number_of_inputs); } + // Returns a type equivalent to the given `type`, but that a `HPhi` can hold. + static Primitive::Type ToPhiType(Primitive::Type type) { + switch (type) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimChar: + return Primitive::kPrimInt; + default: + return type; + } + } + size_t InputCount() const OVERRIDE { return inputs_.Size(); } void AddInput(HInstruction* input); @@ -3289,8 +3358,19 @@ class HParallelMove : public HTemplateInstruction<0> { if (kIsDebugBuild) { if (instruction != nullptr) { for (size_t i = 0, e = moves_.Size(); i < e; ++i) { - DCHECK_NE(moves_.Get(i).GetInstruction(), instruction) - << "Doing parallel moves for the same instruction."; + if (moves_.Get(i).GetInstruction() == instruction) { + // Special case the situation where the move is for the spill slot + // of the instruction. + if ((GetPrevious() == instruction) + || ((GetPrevious() == nullptr) + && instruction->IsPhi() + && instruction->GetBlock() == GetBlock())) { + DCHECK_NE(destination.GetKind(), moves_.Get(i).GetDestination().GetKind()) + << "Doing parallel moves for the same instruction."; + } else { + DCHECK(false) << "Doing parallel moves for the same instruction."; + } + } } } for (size_t i = 0, e = moves_.Size(); i < e; ++i) { @@ -3441,6 +3521,12 @@ class HBlocksInLoopIterator : public ValueObject { DISALLOW_COPY_AND_ASSIGN(HBlocksInLoopIterator); }; +inline int64_t Int64FromConstant(HConstant* constant) { + DCHECK(constant->IsIntConstant() || constant->IsLongConstant()); + return constant->IsIntConstant() ? constant->AsIntConstant()->GetValue() + : constant->AsLongConstant()->GetValue(); +} + } // namespace art #endif // ART_COMPILER_OPTIMIZING_NODES_H_ |