Fix code generation of materialized conditions.
Move the logic for knowing if a condition needs to be materialized
in an optimization pass (so that the information does not change
as a side effect of another optimization).
Also clean-up arm and x86_64 codegen:
- arm: ldr and str are for power-users when a constant is
in play. We should use LoadFromOffset and StoreToOffset.
- x86_64: fix misuses of movq instead of movl.
Change-Id: I01a03b91803624be2281a344a13ad5efbf4f3ef3
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fc5b06d..41713a4 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -465,50 +465,51 @@
DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
};
-#define FOR_EACH_CONCRETE_INSTRUCTION(M) \
- M(Add) \
- M(Condition) \
- M(Equal) \
- M(NotEqual) \
- M(LessThan) \
- M(LessThanOrEqual) \
- M(GreaterThan) \
- M(GreaterThanOrEqual) \
- M(Exit) \
- M(Goto) \
- M(If) \
- M(IntConstant) \
- M(InvokeStatic) \
- M(InvokeVirtual) \
- M(LoadLocal) \
- M(Local) \
- M(LongConstant) \
- M(NewInstance) \
- M(Not) \
- M(ParameterValue) \
- M(ParallelMove) \
- M(Phi) \
- M(Return) \
- M(ReturnVoid) \
- M(StoreLocal) \
- M(Sub) \
- M(Compare) \
- M(InstanceFieldGet) \
- M(InstanceFieldSet) \
- M(ArrayGet) \
- M(ArraySet) \
- M(ArrayLength) \
- M(BoundsCheck) \
- M(NullCheck) \
- M(Temporary) \
- M(SuspendCheck) \
+#define FOR_EACH_CONCRETE_INSTRUCTION(M) \
+ M(Add, BinaryOperation) \
+ M(Condition, BinaryOperation) \
+ M(Equal, Condition) \
+ M(NotEqual, Condition) \
+ M(LessThan, Condition) \
+ M(LessThanOrEqual, Condition) \
+ M(GreaterThan, Condition) \
+ M(GreaterThanOrEqual, Condition) \
+ M(Exit, Instruction) \
+ M(Goto, Instruction) \
+ M(If, Instruction) \
+ M(IntConstant, Constant) \
+ M(InvokeStatic, Invoke) \
+ M(InvokeVirtual, Invoke) \
+ M(LoadLocal, Instruction) \
+ M(Local, Instruction) \
+ M(LongConstant, Constant) \
+ M(NewInstance, Instruction) \
+ M(Not, Instruction) \
+ M(ParameterValue, Instruction) \
+ M(ParallelMove, Instruction) \
+ M(Phi, Instruction) \
+ M(Return, Instruction) \
+ M(ReturnVoid, Instruction) \
+ M(StoreLocal, Instruction) \
+ M(Sub, BinaryOperation) \
+ M(Compare, BinaryOperation) \
+ M(InstanceFieldGet, Instruction) \
+ M(InstanceFieldSet, Instruction) \
+ M(ArrayGet, Instruction) \
+ M(ArraySet, Instruction) \
+ M(ArrayLength, Instruction) \
+ M(BoundsCheck, Instruction) \
+ M(NullCheck, Instruction) \
+ M(Temporary, Instruction) \
+ M(SuspendCheck, Instruction) \
-#define FOR_EACH_INSTRUCTION(M) \
- FOR_EACH_CONCRETE_INSTRUCTION(M) \
- M(Constant) \
- M(BinaryOperation)
+#define FOR_EACH_INSTRUCTION(M) \
+ FOR_EACH_CONCRETE_INSTRUCTION(M) \
+ M(Constant, Instruction) \
+ M(BinaryOperation, Instruction) \
+ M(Invoke, Instruction)
-#define FORWARD_DECLARATION(type) class H##type;
+#define FORWARD_DECLARATION(type, super) class H##type;
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
#undef FORWARD_DECLARATION
@@ -623,7 +624,7 @@
virtual ~HInstruction() {}
-#define DECLARE_KIND(type) k##type,
+#define DECLARE_KIND(type, super) k##type,
enum InstructionKind {
FOR_EACH_INSTRUCTION(DECLARE_KIND)
};
@@ -709,7 +710,7 @@
return uses_ != nullptr && uses_->GetTail() == nullptr;
}
-#define INSTRUCTION_TYPE_CHECK(type) \
+#define INSTRUCTION_TYPE_CHECK(type, super) \
bool Is##type() const { return (As##type() != nullptr); } \
virtual const H##type* As##type() const { return nullptr; } \
virtual H##type* As##type() { return nullptr; }
@@ -1118,13 +1119,13 @@
class HCondition : public HBinaryOperation {
public:
HCondition(HInstruction* first, HInstruction* second)
- : HBinaryOperation(Primitive::kPrimBoolean, first, second) {}
+ : HBinaryOperation(Primitive::kPrimBoolean, first, second),
+ needs_materialization_(true) {}
virtual bool IsCommutative() { return true; }
- // For register allocation purposes, returns whether this instruction needs to be
- // materialized (that is, not just be in the processor flags).
- bool NeedsMaterialization() const;
+ bool NeedsMaterialization() const { return needs_materialization_; }
+ void ClearNeedsMaterialization() { needs_materialization_ = false; }
// For code generation purposes, returns whether this instruction is just before
// `if_`, and disregard moves in between.
@@ -1135,6 +1136,10 @@
virtual IfCondition GetCondition() const = 0;
private:
+ // For register allocation purposes, returns whether this instruction needs to be
+ // materialized (that is, not just be in the processor flags).
+ bool needs_materialization_;
+
DISALLOW_COPY_AND_ASSIGN(HCondition);
};
@@ -1437,6 +1442,8 @@
uint32_t GetDexPc() const { return dex_pc_; }
+ DECLARE_INSTRUCTION(Invoke);
+
protected:
GrowableArray<HInstruction*> inputs_;
const Primitive::Type return_type_;
@@ -1954,7 +1961,7 @@
HGraph* GetGraph() const { return graph_; }
// Visit functions for instruction classes.
-#define DECLARE_VISIT_INSTRUCTION(name) \
+#define DECLARE_VISIT_INSTRUCTION(name, super) \
virtual void Visit##name(H##name* instr) { VisitInstruction(instr); }
FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -1967,6 +1974,23 @@
DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
};
+class HGraphDelegateVisitor : public HGraphVisitor {
+ public:
+ explicit HGraphDelegateVisitor(HGraph* graph) : HGraphVisitor(graph) {}
+ virtual ~HGraphDelegateVisitor() {}
+
+ // Visit functions that delegate to to super class.
+#define DECLARE_VISIT_INSTRUCTION(name, super) \
+ virtual void Visit##name(H##name* instr) OVERRIDE { Visit##super(instr); }
+
+ FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HGraphDelegateVisitor);
+};
+
class HInsertionOrderIterator : public ValueObject {
public:
explicit HInsertionOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {}