Compiler: Spring cleaning

Significant restructuring of the Quick compiler to break out the
common frontend more cleanly.  Additional C++'ification.

The goal is to move from the monolithic structure of the old
JIT towards a more modular model in which components - in
particular the compiler backend - can be replaced.  This CL
focuses on moving MIR-related data from the CompilationUnit
struct into a new MIRGraph class.  The next CL will isolate all
LIR-related data and code down into the Quick backend.

This change will happen in multiple steps, and may look uglier
before it starts looking better.

Among the changes:

   o Moved all mir-related fields from CompilationUnit to new
     MirGraph class.

   o Moved the register promotion stuff into the Quick backend.

   o Deleted the GBC to LIR conversion code.

   o Replaced with old C-style function pointer dataflow analysis
     dispatcher with a basic block iterator class.

   o Renamed some files to make the name more consistent with what
     the code actually does.

   o Added the foundation for future inlining support.

   o Stripped out the remains of the old fingerprinting mechanism.

Change-Id: I6c30facc642f8084b1c7b2075cf7014de387aa56
diff --git a/src/compiler/dex/compiler_ir.h b/src/compiler/dex/compiler_ir.h
index f8cdd34..caa23d7 100644
--- a/src/compiler/dex/compiler_ir.h
+++ b/src/compiler/dex/compiler_ir.h
@@ -33,6 +33,7 @@
 
 namespace art {
 
+//TODO: replace these macros
 #define SLOW_FIELD_PATH (cu->enable_debug & (1 << kDebugSlowFieldPath))
 #define SLOW_INVOKE_PATH (cu->enable_debug & (1 << kDebugSlowInvokePath))
 #define SLOW_STRING_PATH (cu->enable_debug & (1 << kDebugSlowStringPath))
@@ -62,7 +63,7 @@
   RegLocationType location:3;
   unsigned wide:1;
   unsigned defined:1;   // Do we know the type?
-  unsigned is_const:1;  // Constant, value in cu->constant_values[].
+  unsigned is_const:1;  // Constant, value in mir_graph->constant_values[].
   unsigned fp:1;        // Floating point?
   unsigned core:1;      // Non-floating point?
   unsigned ref:1;       // Something GC cares about.
@@ -215,6 +216,7 @@
   DecodedInstruction dalvikInsn;
   unsigned int width;
   unsigned int offset;
+  int m_unit_index;               // From which method was this MIR included
   MIR* prev;
   MIR* next;
   SSARepresentation* ssa_rep;
@@ -227,7 +229,23 @@
   } meta;
 };
 
-struct BasicBlockDataFlow;
+struct BasicBlockDataFlow {
+  ArenaBitVector* use_v;
+  ArenaBitVector* def_v;
+  ArenaBitVector* live_in_v;
+  ArenaBitVector* phi_v;
+  int* vreg_to_ssa_map;
+  ArenaBitVector* ending_null_check_v;
+};
+
+struct SSARepresentation {
+  int num_uses;
+  int* uses;
+  bool* fp_use;
+  int num_defs;
+  int* defs;
+  bool* fp_def;
+};
 
 struct BasicBlock {
   int id;
@@ -273,14 +291,14 @@
 struct RegisterPool;
 struct ArenaMemBlock;
 struct Memstats;
+class MIRGraph;
 class Codegen;
 
 #define NOTVISITED (-1)
 
 struct CompilationUnit {
   CompilationUnit()
-    : num_blocks(0),
-      compiler_driver(NULL),
+    : compiler_driver(NULL),
       class_linker(NULL),
       dex_file(NULL),
       class_loader(NULL),
@@ -290,48 +308,14 @@
       access_flags(0),
       invoke_type(kDirect),
       shorty(NULL),
-      first_lir_insn(NULL),
-      last_lir_insn(NULL),
-      literal_list(NULL),
-      method_literal_list(NULL),
-      code_literal_list(NULL),
       disable_opt(0),
       enable_debug(0),
-      data_offset(0),
-      total_size(0),
-      assembler_status(kSuccess),
-      assembler_retries(0),
       verbose(false),
-      has_loop(false),
-      has_invoke(false),
-      qd_mode(false),
-      reg_pool(NULL),
+      gen_bitcode(false),
+      disable_dataflow(false),
       instruction_set(kNone),
-      num_ssa_regs(0),
-      ssa_base_vregs(NULL),
-      ssa_subscripts(NULL),
-      ssa_strings(NULL),
-      vreg_to_ssa_map(NULL),
-      ssa_last_defs(NULL),
-      is_constant_v(NULL),
-      must_flush_constant_v(NULL),
-      constant_values(NULL),
-      reg_location(NULL),
-      promotion_map(NULL),
-      method_sreg(0),
-      num_reachable_blocks(0),
       num_dalvik_registers(0),
-      entry_block(NULL),
-      exit_block(NULL),
-      cur_block(NULL),
-      i_dom_list(NULL),
-      try_block_addr(NULL),
-      def_block_matrix(NULL),
-      temp_block_v(NULL),
-      temp_dalvik_register_v(NULL),
-      temp_ssa_register_v(NULL),
-      temp_ssa_block_id_v(NULL),
-      block_label_list(NULL),
+      insns(NULL),
       num_ins(0),
       num_outs(0),
       num_regs(0),
@@ -339,22 +323,18 @@
       num_fp_spills(0),
       num_compiler_temps(0),
       frame_size(0),
-      core_spill_mask(0U),
-      fp_spill_mask(0U),
-      attrs(0U),
-      current_dalvik_offset(0),
-      insns(NULL),
-      insns_size(0U),
-      disable_dataflow(false),
-      def_count(0),
+      core_spill_mask(0),
+      fp_spill_mask(0),
+      attributes(0),
       compiler_flip_match(false),
       arena_head(NULL),
       current_arena(NULL),
       num_arena_blocks(0),
       mstats(NULL),
       checkstats(NULL),
-      gen_bitcode(false),
-      llvm_compilation_unit(NULL),
+      mir_graph(NULL),
+      cg(NULL),
+      live_sreg(0),
       llvm_info(NULL),
       context(NULL),
       module(NULL),
@@ -365,14 +345,24 @@
       entry_bb(NULL),
       entryTarget_bb(NULL),
       temp_name(0),
-#ifndef NDEBUG
-      live_sreg(0),
-#endif
-      opcode_count(NULL),
-      cg(NULL) {}
-
-  int num_blocks;
-  GrowableList block_list;
+      first_lir_insn(NULL),
+      last_lir_insn(NULL),
+      literal_list(NULL),
+      method_literal_list(NULL),
+      code_literal_list(NULL),
+      data_offset(0),
+      total_size(0),
+      reg_pool(NULL),
+      reg_location(NULL),
+      promotion_map(NULL),
+      method_sreg(0),
+      block_label_list(NULL),
+      current_dalvik_offset(0)
+ {}
+  /*
+   * Fields needed/generated by common frontend and generally used throughout
+   * the compiler.
+  */
   CompilerDriver* compiler_driver;
   ClassLinker* class_linker;           // Linker to resolve fields and methods.
   const DexFile* dex_file;             // DexFile containing the method being compiled.
@@ -383,91 +373,21 @@
   uint32_t access_flags;               // compiling method's access flags.
   InvokeType invoke_type;              // compiling method's invocation type.
   const char* shorty;                  // compiling method's shorty.
-  LIR* first_lir_insn;
-  LIR* last_lir_insn;
-  LIR* literal_list;                   // Constants.
-  LIR* method_literal_list;            // Method literals requiring patching.
-  LIR* code_literal_list;              // Code literals requiring patching.
   uint32_t disable_opt;                // opt_control_vector flags.
   uint32_t enable_debug;               // debugControlVector flags.
-  int data_offset;                     // starting offset of literal pool.
-  int total_size;                      // header + code size.
-  AssemblerStatus assembler_status;    // Success or fix and retry.
-  int assembler_retries;
   std::vector<uint8_t> code_buffer;
-  /*
-   * Holds mapping from native PC to dex PC for safepoints where we may deoptimize.
-   * Native PC is on the return address of the safepointed operation.  Dex PC is for
-   * the instruction being executed at the safepoint.
-   */
-  std::vector<uint32_t> pc2dexMappingTable;
-  /*
-   * Holds mapping from Dex PC to native PC for catch entry points.  Native PC and Dex PC
-   * immediately preceed the instruction.
-   */
-  std::vector<uint32_t> dex2pcMappingTable;
+  bool verbose;
   std::vector<uint32_t> combined_mapping_table;
   std::vector<uint32_t> core_vmap_table;
   std::vector<uint32_t> fp_vmap_table;
   std::vector<uint8_t> native_gc_map;
-  std::vector<BasicBlock*> extended_basic_blocks;
-  bool verbose;
-  bool has_loop;                       // Contains a loop.
-  bool has_invoke;                     // Contains an invoke instruction.
-  bool qd_mode;                        // Compile for code size/compile time.
-  RegisterPool* reg_pool;
+  bool gen_bitcode;
+  bool disable_dataflow;               // Skip dataflow analysis if possible
   InstructionSet instruction_set;
-  // Number of total regs used in the whole cu after SSA transformation .
-  int num_ssa_regs;
-  // Map SSA reg i to the base virtual register/subscript.
-  GrowableList* ssa_base_vregs;
-  GrowableList* ssa_subscripts;
-  GrowableList* ssa_strings;
 
-  // Map original Dalvik virtual reg i to the current SSA name.
-  int* vreg_to_ssa_map;            // length == method->registers_size
-  int* ssa_last_defs;              // length == method->registers_size
-  ArenaBitVector* is_constant_v;   // length == num_ssa_reg
-  ArenaBitVector* must_flush_constant_v;   // length == num_ssa_reg
-  int* constant_values;            // length == num_ssa_reg
-
-  // Use counts of ssa names.
-  GrowableList use_counts;         // Weighted by nesting depth
-  GrowableList raw_use_counts;     // Not weighted
-
-  // Optimization support.
-  GrowableList loop_headers;
-
-  // Map SSA names to location.
-  RegLocation* reg_location;
-
-  // Keep track of Dalvik v_reg to physical register mappings.
-  PromotionMap* promotion_map;
-
-  // SSA name for Method*.
-  int method_sreg;
-  RegLocation method_loc;          // Describes location of method*.
-
-  int num_reachable_blocks;
+  // CLEANUP: much of this info available elsewhere.  Go to the original source?
   int num_dalvik_registers;        // method->registers_size.
-  BasicBlock* entry_block;
-  BasicBlock* exit_block;
-  BasicBlock* cur_block;
-  GrowableList dfs_order;
-  GrowableList dfs_post_order;
-  GrowableList dom_post_order_traversal;
-  GrowableList throw_launchpads;
-  GrowableList suspend_launchpads;
-  GrowableList intrinsic_launchpads;
-  GrowableList compiler_temps;
-  int* i_dom_list;
-  ArenaBitVector* try_block_addr;
-  ArenaBitVector** def_block_matrix;    // num_dalvik_register x num_blocks.
-  ArenaBitVector* temp_block_v;
-  ArenaBitVector* temp_dalvik_register_v;
-  ArenaBitVector* temp_ssa_register_v;  // num_ssa_regs.
-  int* temp_ssa_block_id_v;             // working storage for Phi labels.
-  LIR* block_label_list;
+  const uint16_t* insns;
   /*
    * Frame layout details.
    * NOTE: for debug support it will be necessary to add a structure
@@ -483,27 +403,7 @@
   int frame_size;
   unsigned int core_spill_mask;
   unsigned int fp_spill_mask;
-  unsigned int attrs;
-  /*
-   * TODO: The code generation utilities don't have a built-in
-   * mechanism to propagate the original Dalvik opcode address to the
-   * associated generated instructions.  For the trace compiler, this wasn't
-   * necessary because the interpreter handled all throws and debugging
-   * requests.  For now we'll handle this by placing the Dalvik offset
-   * in the CompilationUnit struct before codegen for each instruction.
-   * The low-level LIR creation utilites will pull it from here.  Rework this.
-   */
-  int current_dalvik_offset;
-  GrowableList switch_tables;
-  GrowableList fill_array_data;
-  const uint16_t* insns;
-  uint32_t insns_size;
-  bool disable_dataflow; // Skip dataflow analysis if possible
-  SafeMap<unsigned int, BasicBlock*> block_map; // FindBlock lookup cache.
-  SafeMap<unsigned int, unsigned int> block_id_map; // Block collapse lookup cache.
-  SafeMap<unsigned int, LIR*> boundary_map; // boundary lookup cache.
-  int def_count;         // Used to estimate number of SSA names.
-
+  unsigned int attributes;
   // If non-empty, apply optimizer/debug flags only to matching methods.
   std::string compiler_method_match;
   // Flips sense of compiler_method_match - apply flags if doesn't match.
@@ -513,10 +413,21 @@
   int num_arena_blocks;
   Memstats* mstats;
   Checkstats* checkstats;
-  bool gen_bitcode;
+  UniquePtr<MIRGraph> mir_graph;   // MIR container.
+  UniquePtr<Codegen> cg;           // Target-specific codegen.
+  /*
+   * Sanity checking for the register temp tracking.  The same ssa
+   * name should never be associated with one temp register per
+   * instruction compilation.
+   */
+  int live_sreg;
 
   // Fields for Portable
   llvm::LlvmCompilationUnit* llvm_compilation_unit;
+ /*
+  * Fields needed by GBC creation.  Candidates for moving to a new MIR to
+  * llvm bitcode class.
+  */
   LLVMInfo* llvm_info;
   std::string symbol;
   ::llvm::LLVMContext* context;
@@ -531,109 +442,62 @@
   std::string bitcode_filename;
   GrowableList llvm_values;
   int32_t temp_name;
-  SafeMap< ::llvm::BasicBlock*, LIR*> block_to_label_map; // llvm bb -> LIR label.
-  SafeMap<int32_t, ::llvm::BasicBlock*> id_to_block_map; // block id -> llvm bb.
-  SafeMap< ::llvm::Value*, RegLocation> loc_map; // llvm Value to loc rec.
-  std::set< ::llvm::BasicBlock*> llvm_blocks;
-#ifndef NDEBUG
+  SafeMap<int32_t, ::llvm::BasicBlock*> id_to_block_map;  // block id -> llvm bb.
+
+ /*
+  * Fields needed by the Quick backend.  Candidates for moving to a new
+  * QuickBackend class.
+  */
+  LIR* first_lir_insn;
+  LIR* last_lir_insn;
+  LIR* literal_list;                   // Constants.
+  LIR* method_literal_list;            // Method literals requiring patching.
+  LIR* code_literal_list;              // Code literals requiring patching.
+  int data_offset;                     // starting offset of literal pool.
+  int total_size;                      // header + code size.
+  RegisterPool* reg_pool;
+  // Map SSA names to location.
+  RegLocation* reg_location;
+  // Keep track of Dalvik v_reg to physical register mappings.
+  PromotionMap* promotion_map;
+  // SSA name for Method*.
+  int method_sreg;
+  RegLocation method_loc;          // Describes location of method*.
+  GrowableList throw_launchpads;
+  GrowableList suspend_launchpads;
+  GrowableList intrinsic_launchpads;
+  GrowableList compiler_temps;
+  LIR* block_label_list;
   /*
-   * Sanity checking for the register temp tracking.  The same ssa
-   * name should never be associated with one temp register per
-   * instruction compilation.
+   * TODO: The code generation utilities don't have a built-in
+   * mechanism to propagate the original Dalvik opcode address to the
+   * associated generated instructions.  For the trace compiler, this wasn't
+   * necessary because the interpreter handled all throws and debugging
+   * requests.  For now we'll handle this by placing the Dalvik offset
+   * in the CompilationUnit struct before codegen for each instruction.
+   * The low-level LIR creation utilites will pull it from here.  Rework this.
    */
-  int live_sreg;
-#endif
-  std::set<uint32_t> catches;
-  int* opcode_count;    // Count Dalvik opcodes for tuning.
-  UniquePtr<Codegen> cg;
+  int current_dalvik_offset;
+  GrowableList switch_tables;
+  GrowableList fill_array_data;
+  SafeMap<unsigned int, unsigned int> block_id_map; // Block collapse lookup cache.
+  SafeMap<unsigned int, LIR*> boundary_map; // boundary lookup cache.
+  /*
+   * Holds mapping from native PC to dex PC for safepoints where we may deoptimize.
+   * Native PC is on the return address of the safepointed operation.  Dex PC is for
+   * the instruction being executed at the safepoint.
+   */
+  std::vector<uint32_t> pc2dexMappingTable;
+  /*
+   * Holds mapping from Dex PC to native PC for catch entry points.  Native PC and Dex PC
+   * immediately preceed the instruction.
+   */
+  std::vector<uint32_t> dex2pcMappingTable;
 };
 
-struct SwitchTable {
-  int offset;
-  const uint16_t* table;      // Original dex table.
-  int vaddr;                  // Dalvik offset of switch opcode.
-  LIR* anchor;                // Reference instruction for relative offsets.
-  LIR** targets;              // Array of case targets.
-};
+// TODO: move this
+int SRegToVReg(const CompilationUnit* cu, int ssa_reg);
 
-struct FillArrayData {
-  int offset;
-  const uint16_t* table;      // Original dex table.
-  int size;
-  int vaddr;                  // Dalvik offset of FILL_ARRAY_DATA opcode.
-};
-
-#define MAX_PATTERN_LEN 5
-
-struct CodePattern {
-  const Instruction::Code opcodes[MAX_PATTERN_LEN];
-  const SpecialCaseHandler handler_code;
-};
-
-static const CodePattern special_patterns[] = {
-  {{Instruction::RETURN_VOID}, kNullMethod},
-  {{Instruction::CONST, Instruction::RETURN}, kConstFunction},
-  {{Instruction::CONST_4, Instruction::RETURN}, kConstFunction},
-  {{Instruction::CONST_4, Instruction::RETURN_OBJECT}, kConstFunction},
-  {{Instruction::CONST_16, Instruction::RETURN}, kConstFunction},
-  {{Instruction::IGET, Instruction:: RETURN}, kIGet},
-  {{Instruction::IGET_BOOLEAN, Instruction::RETURN}, kIGetBoolean},
-  {{Instruction::IGET_OBJECT, Instruction::RETURN_OBJECT}, kIGetObject},
-  {{Instruction::IGET_BYTE, Instruction::RETURN}, kIGetByte},
-  {{Instruction::IGET_CHAR, Instruction::RETURN}, kIGetChar},
-  {{Instruction::IGET_SHORT, Instruction::RETURN}, kIGetShort},
-  {{Instruction::IGET_WIDE, Instruction::RETURN_WIDE}, kIGetWide},
-  {{Instruction::IPUT, Instruction::RETURN_VOID}, kIPut},
-  {{Instruction::IPUT_BOOLEAN, Instruction::RETURN_VOID}, kIPutBoolean},
-  {{Instruction::IPUT_OBJECT, Instruction::RETURN_VOID}, kIPutObject},
-  {{Instruction::IPUT_BYTE, Instruction::RETURN_VOID}, kIPutByte},
-  {{Instruction::IPUT_CHAR, Instruction::RETURN_VOID}, kIPutChar},
-  {{Instruction::IPUT_SHORT, Instruction::RETURN_VOID}, kIPutShort},
-  {{Instruction::IPUT_WIDE, Instruction::RETURN_VOID}, kIPutWide},
-  {{Instruction::RETURN}, kIdentity},
-  {{Instruction::RETURN_OBJECT}, kIdentity},
-  {{Instruction::RETURN_WIDE}, kIdentity},
-};
-
-static inline bool IsConst(const CompilationUnit* cu, int32_t s_reg)
-{
-  return (IsBitSet(cu->is_constant_v, s_reg));
-}
-
-static inline bool IsConst(const CompilationUnit* cu, RegLocation loc)
-{
-  return (IsConst(cu, loc.orig_sreg));
-}
-
-static inline int32_t ConstantValue(const CompilationUnit* cu, RegLocation loc)
-{
-  DCHECK(IsConst(cu, loc));
-  return cu->constant_values[loc.orig_sreg];
-}
-
-static inline int32_t ConstantValue(const CompilationUnit* cu, int32_t s_reg)
-{
-  DCHECK(IsConst(cu, s_reg));
-  return cu->constant_values[s_reg];
-}
-
-static inline int64_t ConstantValueWide(const CompilationUnit* cu, RegLocation loc)
-{
-  DCHECK(IsConst(cu, loc));
-  return (static_cast<int64_t>(cu->constant_values[loc.orig_sreg + 1]) << 32) |
-      Low32Bits(static_cast<int64_t>(cu->constant_values[loc.orig_sreg]));
-}
-
-static inline bool IsConstantNullRef(const CompilationUnit* cu, RegLocation loc)
-{
-  return loc.ref && loc.is_const && (ConstantValue(cu, loc) == 0);
-}
-
-static inline bool MustFlushConstant(const CompilationUnit* cu, RegLocation loc)
-{
-  DCHECK(IsConst(cu, loc));
-  return IsBitSet(cu->must_flush_constant_v, loc.orig_sreg);
-}
 
 }  // namespace art