Re-apply: Initial check-in of an optimizing compiler.
The classes and the names are very much inspired by V8/Dart.
It currently only supports the RETURN_VOID dex instruction,
and there is a pretty printer to check if the building of the
graph is correct.
Change-Id: I28e125dfee86ae6ec9b3fec6aa1859523b92a893
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
new file mode 100644
index 0000000..3d1c25e
--- /dev/null
+++ b/compiler/optimizing/nodes.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
+#define ART_COMPILER_OPTIMIZING_NODES_H_
+
+#include "utils/allocation.h"
+#include "utils/growable_array.h"
+
+namespace art {
+
+class HBasicBlock;
+class HInstruction;
+class HGraphVisitor;
+
+static const int kDefaultNumberOfBlocks = 8;
+static const int kDefaultNumberOfSuccessors = 2;
+static const int kDefaultNumberOfPredecessors = 2;
+
+// Control-flow graph of a method. Contains a list of basic blocks.
+class HGraph : public ArenaObject {
+ public:
+ explicit HGraph(ArenaAllocator* arena)
+ : arena_(arena),
+ blocks_(arena, kDefaultNumberOfBlocks) { }
+
+ ArenaAllocator* arena() const { return arena_; }
+ const GrowableArray<HBasicBlock*>* blocks() const { return &blocks_; }
+
+ void AddBlock(HBasicBlock* block);
+
+ private:
+ ArenaAllocator* const arena_;
+ GrowableArray<HBasicBlock*> blocks_;
+
+ DISALLOW_COPY_AND_ASSIGN(HGraph);
+};
+
+// A block in a method. Contains the list of instructions represented
+// as a double linked list. Each block knows its predecessors and
+// successors.
+class HBasicBlock : public ArenaObject {
+ public:
+ explicit HBasicBlock(HGraph* graph)
+ : graph_(graph),
+ predecessors_(graph->arena(), kDefaultNumberOfPredecessors),
+ successors_(graph->arena(), kDefaultNumberOfSuccessors),
+ first_instruction_(nullptr),
+ last_instruction_(nullptr),
+ block_id_(-1) { }
+
+ const GrowableArray<HBasicBlock*>* predecessors() const {
+ return &predecessors_;
+ }
+
+ const GrowableArray<HBasicBlock*>* successors() const {
+ return &successors_;
+ }
+
+ HGraph* graph() const { return graph_; }
+
+ int block_id() const { return block_id_; }
+ void set_block_id(int id) { block_id_ = id; }
+
+ HInstruction* first_instruction() const { return first_instruction_; }
+ HInstruction* last_instruction() const { return last_instruction_; }
+
+ void AddSuccessor(HBasicBlock* block) {
+ successors_.Add(block);
+ block->predecessors_.Add(this);
+ }
+
+ void AddInstruction(HInstruction* instruction);
+
+ private:
+ HGraph* const graph_;
+ GrowableArray<HBasicBlock*> predecessors_;
+ GrowableArray<HBasicBlock*> successors_;
+ HInstruction* first_instruction_;
+ HInstruction* last_instruction_;
+ int block_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
+};
+
+#define FOR_EACH_INSTRUCTION(M) \
+ M(Exit) \
+ M(Goto) \
+ M(ReturnVoid) \
+
+#define DECLARE_INSTRUCTION(type) \
+ virtual void Accept(HGraphVisitor* visitor); \
+ virtual const char* DebugName() const { return #type; } \
+
+class HInstruction : public ArenaObject {
+ public:
+ explicit HInstruction(HBasicBlock* block)
+ : previous_(nullptr),
+ next_(nullptr) { }
+ virtual ~HInstruction() { }
+
+ HInstruction* next() const { return next_; }
+ HInstruction* previous() const { return previous_; }
+
+ virtual intptr_t InputCount() const = 0;
+ virtual HInstruction* InputAt(intptr_t i) const = 0;
+
+ virtual void Accept(HGraphVisitor* visitor) = 0;
+ virtual const char* DebugName() const = 0;
+
+ private:
+ HInstruction* previous_;
+ HInstruction* next_;
+
+ friend class HBasicBlock;
+
+ DISALLOW_COPY_AND_ASSIGN(HInstruction);
+};
+
+class HInstructionIterator : public ValueObject {
+ public:
+ explicit HInstructionIterator(HBasicBlock* block)
+ : instruction_(block->first_instruction()) {
+ next_ = Done() ? nullptr : instruction_->next();
+ }
+
+ inline bool Done() const { return instruction_ == nullptr; }
+ inline HInstruction* Current() { return instruction_; }
+ inline void Advance() {
+ instruction_ = next_;
+ next_ = Done() ? nullptr : instruction_->next();
+ }
+
+ private:
+ HInstruction* instruction_;
+ HInstruction* next_;
+};
+
+// An embedded container with N elements of type T. Used (with partial
+// specialization for N=0) because embedded arrays cannot have size 0.
+template<typename T, intptr_t N>
+class EmbeddedArray {
+ public:
+ EmbeddedArray() : elements_() { }
+
+ intptr_t length() const { return N; }
+
+ const T& operator[](intptr_t i) const {
+ ASSERT(i < length());
+ return elements_[i];
+ }
+
+ T& operator[](intptr_t i) {
+ ASSERT(i < length());
+ return elements_[i];
+ }
+
+ const T& At(intptr_t i) const {
+ return (*this)[i];
+ }
+
+ void SetAt(intptr_t i, const T& val) {
+ (*this)[i] = val;
+ }
+
+ private:
+ T elements_[N];
+};
+
+template<typename T>
+class EmbeddedArray<T, 0> {
+ public:
+ intptr_t length() const { return 0; }
+ const T& operator[](intptr_t i) const {
+ LOG(FATAL) << "Unreachable";
+ static T sentinel = 0;
+ return sentinel;
+ }
+ T& operator[](intptr_t i) {
+ LOG(FATAL) << "Unreachable";
+ static T sentinel = 0;
+ return sentinel;
+ }
+};
+
+template<intptr_t N>
+class HTemplateInstruction: public HInstruction {
+ public:
+ HTemplateInstruction<N>(HBasicBlock* block)
+ : HInstruction(block),
+ inputs_() { }
+ virtual ~HTemplateInstruction() { }
+
+ virtual intptr_t InputCount() const { return N; }
+ virtual HInstruction* InputAt(intptr_t i) const { return inputs_[i]; }
+
+ private:
+ EmbeddedArray<HInstruction*, N> inputs_;
+};
+
+// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
+// instruction that branches to the exit block.
+class HReturnVoid : public HTemplateInstruction<0> {
+ public:
+ explicit HReturnVoid(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+ DECLARE_INSTRUCTION(ReturnVoid)
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HReturnVoid);
+};
+
+// The exit instruction is the only instruction of the exit block.
+// Instructions aborting the method (HTrow and HReturn) must branch to the
+// exit block.
+class HExit : public HTemplateInstruction<0> {
+ public:
+ explicit HExit(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+ DECLARE_INSTRUCTION(Exit)
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HExit);
+};
+
+// Jumps from one block to another.
+class HGoto : public HTemplateInstruction<0> {
+ public:
+ explicit HGoto(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+ DECLARE_INSTRUCTION(Goto)
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HGoto);
+};
+
+class HGraphVisitor : public ValueObject {
+ public:
+ explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
+ virtual ~HGraphVisitor() { }
+
+ virtual void VisitInstruction(HInstruction* instruction) { }
+ virtual void VisitBasicBlock(HBasicBlock* block);
+
+ void VisitInsertionOrder();
+
+ // Visit functions for instruction classes.
+#define DECLARE_VISIT_INSTRUCTION(name) \
+ virtual void Visit##name(H##name* instr) { VisitInstruction(instr); }
+
+ FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+ HGraph* graph_;
+
+ DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_NODES_H_