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