frontend.cc revision df62950e7a32031b82360c407d46a37b94188fbb
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <llvm/Support/Threading.h>
18
19#include "compiler_internals.h"
20#include "driver/compiler_driver.h"
21#include "dataflow_iterator-inl.h"
22#include "leb128.h"
23#include "mirror/object.h"
24#include "runtime.h"
25#include "backend.h"
26#include "base/logging.h"
27
28#if defined(ART_USE_PORTABLE_COMPILER)
29#include "dex/portable/mir_to_gbc.h"
30#include "llvm/llvm_compilation_unit.h"
31#endif
32
33namespace {
34#if !defined(ART_USE_PORTABLE_COMPILER)
35  pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
36#endif
37  void InitializeLLVMForQuick() {
38    ::llvm::llvm_start_multithreaded();
39  }
40}
41
42namespace art {
43namespace llvm {
44::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
45}
46
47LLVMInfo::LLVMInfo() {
48#if !defined(ART_USE_PORTABLE_COMPILER)
49  pthread_once(&llvm_multi_init, InitializeLLVMForQuick);
50#endif
51  // Create context, module, intrinsic helper & ir builder
52  llvm_context_.reset(new ::llvm::LLVMContext());
53  llvm_module_ = new ::llvm::Module("art", *llvm_context_);
54  ::llvm::StructType::create(*llvm_context_, "JavaObject");
55  art::llvm::makeLLVMModuleContents(llvm_module_);
56  intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
57  ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
58}
59
60LLVMInfo::~LLVMInfo() {
61}
62
63extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) {
64  CHECK(compiler.GetCompilerContext() == NULL);
65  LLVMInfo* llvm_info = new LLVMInfo();
66  compiler.SetCompilerContext(llvm_info);
67}
68
69extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) {
70  delete reinterpret_cast<LLVMInfo*>(compiler.GetCompilerContext());
71  compiler.SetCompilerContext(NULL);
72}
73
74/* Default optimizer/debug setting for the compiler. */
75static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
76  (1 << kLoadStoreElimination) |
77  //(1 << kLoadHoisting) |
78  //(1 << kSuppressLoads) |
79  //(1 << kNullCheckElimination) |
80  //(1 << kPromoteRegs) |
81  //(1 << kTrackLiveTemps) |
82  //(1 << kSafeOptimizations) |
83  //(1 << kBBOpt) |
84  //(1 << kMatch) |
85  //(1 << kPromoteCompilerTemps) |
86  0;
87
88static uint32_t kCompilerDebugFlags = 0 |     // Enable debug/testing modes
89  //(1 << kDebugDisplayMissingTargets) |
90  //(1 << kDebugVerbose) |
91  //(1 << kDebugDumpCFG) |
92  //(1 << kDebugSlowFieldPath) |
93  //(1 << kDebugSlowInvokePath) |
94  //(1 << kDebugSlowStringPath) |
95  //(1 << kDebugSlowestFieldPath) |
96  //(1 << kDebugSlowestStringPath) |
97  //(1 << kDebugExerciseResolveMethod) |
98  //(1 << kDebugVerifyDataflow) |
99  //(1 << kDebugShowMemoryUsage) |
100  //(1 << kDebugShowNops) |
101  //(1 << kDebugCountOpcodes) |
102  //(1 << kDebugDumpCheckStats) |
103  //(1 << kDebugDumpBitcodeFile) |
104  //(1 << kDebugVerifyBitcode) |
105  //(1 << kDebugShowSummaryMemoryUsage) |
106  0;
107
108static CompiledMethod* CompileMethod(CompilerDriver& compiler,
109                                     const CompilerBackend compiler_backend,
110                                     const DexFile::CodeItem* code_item,
111                                     uint32_t access_flags, InvokeType invoke_type,
112                                     uint32_t class_def_idx, uint32_t method_idx,
113                                     jobject class_loader, const DexFile& dex_file
114#if defined(ART_USE_PORTABLE_COMPILER)
115                                     , llvm::LlvmCompilationUnit* llvm_compilation_unit
116#endif
117) {
118  VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
119
120  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
121  UniquePtr<CompilationUnit> cu(new CompilationUnit);
122
123  cu->compiler_driver = &compiler;
124  cu->class_linker = class_linker;
125  cu->instruction_set = compiler.GetInstructionSet();
126  cu->compiler_backend = compiler_backend;
127  DCHECK((cu->instruction_set == kThumb2) ||
128         (cu->instruction_set == kX86) ||
129         (cu->instruction_set == kMips));
130
131
132  /* Adjust this value accordingly once inlining is performed */
133  cu->num_dalvik_registers = code_item->registers_size_;
134  // TODO: set this from command line
135  cu->compiler_flip_match = false;
136  bool use_match = !cu->compiler_method_match.empty();
137  bool match = use_match && (cu->compiler_flip_match ^
138      (PrettyMethod(method_idx, dex_file).find(cu->compiler_method_match) !=
139       std::string::npos));
140  if (!use_match || match) {
141    cu->disable_opt = kCompilerOptimizerDisableFlags;
142    cu->enable_debug = kCompilerDebugFlags;
143    cu->verbose = VLOG_IS_ON(compiler) ||
144        (cu->enable_debug & (1 << kDebugVerbose));
145  }
146
147  /*
148   * TODO: rework handling of optimization and debug flags.  Should we split out
149   * MIR and backend flags?  Need command-line setting as well.
150   */
151
152  if (compiler_backend == kPortable) {
153    // Fused long branches not currently usseful in bitcode.
154    cu->disable_opt |= (1 << kBranchFusing);
155  }
156
157  if (cu->instruction_set == kMips) {
158    // Disable some optimizations for mips for now
159    cu->disable_opt |= (
160        (1 << kLoadStoreElimination) |
161        (1 << kLoadHoisting) |
162        (1 << kSuppressLoads) |
163        (1 << kNullCheckElimination) |
164        (1 << kPromoteRegs) |
165        (1 << kTrackLiveTemps) |
166        (1 << kSafeOptimizations) |
167        (1 << kBBOpt) |
168        (1 << kMatch) |
169        (1 << kPromoteCompilerTemps));
170  }
171
172  cu->mir_graph.reset(new MIRGraph(cu.get(), &cu->arena));
173
174  /* Gathering opcode stats? */
175  if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
176    cu->mir_graph->EnableOpcodeCounting();
177  }
178
179  /* Build the raw MIR graph */
180  cu->mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx,
181                              class_loader, dex_file);
182
183  /* Do a code layout pass */
184  cu->mir_graph->CodeLayout();
185
186  /* Perform SSA transformation for the whole method */
187  cu->mir_graph->SSATransformation();
188
189  /* Do constant propagation */
190  cu->mir_graph->PropagateConstants();
191
192  /* Count uses */
193  cu->mir_graph->MethodUseCount();
194
195  /* Perform null check elimination */
196  cu->mir_graph->NullCheckElimination();
197
198  /* Combine basic blocks where possible */
199  cu->mir_graph->BasicBlockCombine();
200
201  /* Do some basic block optimizations */
202  cu->mir_graph->BasicBlockOptimization();
203
204  if (cu->enable_debug & (1 << kDebugDumpCheckStats)) {
205    cu->mir_graph->DumpCheckStats();
206  }
207
208  if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
209    cu->mir_graph->ShowOpcodeStats();
210  }
211
212  /* Set up regLocation[] array to describe values - one for each ssa_name. */
213  cu->mir_graph->BuildRegLocations();
214
215  CompiledMethod* result = NULL;
216
217#if defined(ART_USE_PORTABLE_COMPILER)
218  if (compiler_backend == kPortable) {
219    cu->cg.reset(PortableCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena,
220                                       llvm_compilation_unit));
221  } else
222#endif
223  { // NOLINT(whitespace/braces)
224    switch (compiler.GetInstructionSet()) {
225      case kThumb2:
226        cu->cg.reset(ArmCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
227        break;
228      case kMips:
229        cu->cg.reset(MipsCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
230        break;
231      case kX86:
232        cu->cg.reset(X86CodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
233        break;
234      default:
235        LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet();
236    }
237  }
238
239  cu->cg->Materialize();
240
241  result = cu->cg->GetCompiledMethod();
242
243  if (result) {
244    VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file);
245  } else {
246    VLOG(compiler) << "Deferred " << PrettyMethod(method_idx, dex_file);
247  }
248
249  if (cu->enable_debug & (1 << kDebugShowMemoryUsage)) {
250    if (cu->arena.BytesAllocated() > (5 * 1024 *1024)) {
251      MemStats mem_stats(cu->arena);
252      LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats);
253    }
254  }
255
256  if (cu->enable_debug & (1 << kDebugShowSummaryMemoryUsage)) {
257    LOG(INFO) << "MEMINFO " << cu->arena.BytesAllocated() << " " << cu->mir_graph->GetNumBlocks()
258              << " " << PrettyMethod(method_idx, dex_file);
259  }
260
261  return result;
262}
263
264CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
265                                 const CompilerBackend backend,
266                                 const DexFile::CodeItem* code_item,
267                                 uint32_t access_flags,
268                                 InvokeType invoke_type,
269                                 uint32_t class_def_idx,
270                                 uint32_t method_idx,
271                                 jobject class_loader,
272                                 const DexFile& dex_file,
273                                 llvm::LlvmCompilationUnit* llvm_compilation_unit) {
274  return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
275                       method_idx, class_loader, dex_file
276#if defined(ART_USE_PORTABLE_COMPILER)
277                       , llvm_compilation_unit
278#endif
279                       ); // NOLINT(whitespace/parens)
280}
281
282}  // namespace art
283
284extern "C" art::CompiledMethod*
285    ArtQuickCompileMethod(art::CompilerDriver& compiler,
286                          const art::DexFile::CodeItem* code_item,
287                          uint32_t access_flags, art::InvokeType invoke_type,
288                          uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
289                          const art::DexFile& dex_file) {
290  // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use build default
291  art::CompilerBackend backend = compiler.GetCompilerBackend();
292  return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
293                               class_def_idx, method_idx, class_loader, dex_file,
294                               NULL /* use thread llvm_info */);
295}
296