summaryrefslogtreecommitdiffstats
path: root/compiler/optimizing/nodes.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r--compiler/optimizing/nodes.h94
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_