blob: cdfd42224fdf4f60e6839182316fdf69a9100a79 [file] [log] [blame]
Logan Chien8b977d32012-02-21 19:14:55 +08001/*
2 * Copyright (C) 2012 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 "compilation_unit.h"
18
Logan Chien110bcba2012-04-16 19:11:28 +080019#include "compiled_method.h"
Shih-wei Liaod7726e42012-04-20 15:23:36 -070020#include "file.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070021#include "instruction_set.h"
Logan Chien8b977d32012-02-21 19:14:55 +080022#include "ir_builder.h"
23#include "logging.h"
Shih-wei Liaod7726e42012-04-20 15:23:36 -070024#include "os.h"
Logan Chien8b977d32012-02-21 19:14:55 +080025
TDYa127d668a062012-04-13 12:36:57 -070026#include "runtime_support_builder_arm.h"
TDYa127b08ed122012-06-05 23:51:19 -070027#include "runtime_support_builder_thumb2.h"
TDYa127d668a062012-04-13 12:36:57 -070028#include "runtime_support_builder_x86.h"
29
Logan Chien8b977d32012-02-21 19:14:55 +080030#include <llvm/ADT/OwningPtr.h>
31#include <llvm/ADT/StringSet.h>
32#include <llvm/ADT/Triple.h>
33#include <llvm/Analysis/CallGraph.h>
34#include <llvm/Analysis/DebugInfo.h>
TDYa127f15b0ab2012-05-11 21:01:36 -070035#include <llvm/Analysis/Dominators.h>
36#include <llvm/Analysis/LoopInfo.h>
Logan Chien8b977d32012-02-21 19:14:55 +080037#include <llvm/Analysis/LoopPass.h>
38#include <llvm/Analysis/RegionPass.h>
TDYa127f15b0ab2012-05-11 21:01:36 -070039#include <llvm/Analysis/ScalarEvolution.h>
Logan Chien8b977d32012-02-21 19:14:55 +080040#include <llvm/Analysis/Verifier.h>
41#include <llvm/Assembly/PrintModulePass.h>
42#include <llvm/Bitcode/ReaderWriter.h>
43#include <llvm/CallGraphSCCPass.h>
Logan Chien110bcba2012-04-16 19:11:28 +080044#include <llvm/CodeGen/MachineFrameInfo.h>
45#include <llvm/CodeGen/MachineFunction.h>
46#include <llvm/CodeGen/MachineFunctionPass.h>
Logan Chien8b977d32012-02-21 19:14:55 +080047#include <llvm/DerivedTypes.h>
48#include <llvm/LLVMContext.h>
Logan Chien8b977d32012-02-21 19:14:55 +080049#include <llvm/Module.h>
50#include <llvm/PassManager.h>
51#include <llvm/Support/Debug.h>
52#include <llvm/Support/FormattedStream.h>
53#include <llvm/Support/ManagedStatic.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070054#include <llvm/Support/MemoryBuffer.h>
Logan Chien8b977d32012-02-21 19:14:55 +080055#include <llvm/Support/PassNameParser.h>
56#include <llvm/Support/PluginLoader.h>
57#include <llvm/Support/PrettyStackTrace.h>
58#include <llvm/Support/Signals.h>
59#include <llvm/Support/SystemUtils.h>
60#include <llvm/Support/TargetRegistry.h>
61#include <llvm/Support/TargetSelect.h>
62#include <llvm/Support/ToolOutputFile.h>
63#include <llvm/Support/raw_ostream.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070064#include <llvm/Support/system_error.h>
Logan Chien8b977d32012-02-21 19:14:55 +080065#include <llvm/Target/TargetData.h>
66#include <llvm/Target/TargetLibraryInfo.h>
67#include <llvm/Target/TargetMachine.h>
Shih-wei Liaof1cb9a52012-04-20 01:49:18 -070068#include <llvm/Transforms/IPO.h>
Logan Chien8b977d32012-02-21 19:14:55 +080069#include <llvm/Transforms/IPO/PassManagerBuilder.h>
TDYa127f15b0ab2012-05-11 21:01:36 -070070#include <llvm/Transforms/Scalar.h>
Logan Chien8b977d32012-02-21 19:14:55 +080071
Shih-wei Liaod7726e42012-04-20 15:23:36 -070072#include <sys/types.h>
73#include <sys/wait.h>
74#include <unistd.h>
75
Logan Chien8b977d32012-02-21 19:14:55 +080076#include <string>
77
Logan Chien110bcba2012-04-16 19:11:28 +080078namespace {
79
80class UpdateFrameSizePass : public llvm::MachineFunctionPass {
81 public:
82 static char ID;
83
84 UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) {
85 LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass";
86 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
87 // this constructor won't work because we have no information on
88 // CompilationUnit. Thus, we should place a LOG(FATAL) here.
89 }
90
91 UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit)
92 : llvm::MachineFunctionPass(ID), cunit_(cunit) {
93 }
94
95 virtual bool runOnMachineFunction(llvm::MachineFunction &MF) {
96 cunit_->UpdateFrameSizeInBytes(MF.getFunction(),
97 MF.getFrameInfo()->getStackSize());
98 return false;
99 }
100
101 private:
102 art::compiler_llvm::CompilationUnit* cunit_;
103};
104
105char UpdateFrameSizePass::ID = 0;
106
107llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
108 "update-frame-size", "Update frame size pass", false, false);
109
TDYa127f15b0ab2012-05-11 21:01:36 -0700110
111// TODO: We may need something to manage these passes.
112// TODO: We need high-level IR to analysis and do this at the IRBuilder level.
113class AddSuspendCheckToLoopLatchPass : public llvm::LoopPass {
114 public:
115 static char ID;
116
117 AddSuspendCheckToLoopLatchPass() : llvm::LoopPass(ID), irb_(NULL) {
118 LOG(FATAL) << "Unexpected instantiation of AddSuspendCheckToLoopLatchPass";
119 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
120 // this constructor won't work because we have no information on
121 // IRBuilder. Thus, we should place a LOG(FATAL) here.
122 }
123
124 AddSuspendCheckToLoopLatchPass(art::compiler_llvm::IRBuilder* irb)
125 : llvm::LoopPass(ID), irb_(irb) {
126 }
127
128 virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const {
129 AU.addRequiredID(llvm::LoopSimplifyID);
130
TDYa127afa97e22012-06-22 22:20:11 -0700131 // TODO: Preserve more.
132 //AU.addPreserved<llvm::DominatorTree>();
TDYa127f15b0ab2012-05-11 21:01:36 -0700133 AU.addPreserved<llvm::LoopInfo>();
TDYa127afa97e22012-06-22 22:20:11 -0700134 //AU.addPreservedID(llvm::LoopSimplifyID);
TDYa127f15b0ab2012-05-11 21:01:36 -0700135 AU.addPreserved<llvm::ScalarEvolution>();
136 AU.addPreservedID(llvm::BreakCriticalEdgesID);
137 }
138
139 virtual bool runOnLoop(llvm::Loop *loop, llvm::LPPassManager &lpm) {
140 CHECK_EQ(loop->getNumBackEdges(), 1U) << "Loop must be simplified!";
141 llvm::BasicBlock* bb = loop->getLoopLatch();
142 CHECK_NE(bb, static_cast<void*>(NULL)) << "A single loop latch must exist.";
143
TDYa127afa97e22012-06-22 22:20:11 -0700144 llvm::BasicBlock* tb = bb->splitBasicBlock(bb->getTerminator(), "suspend_exit");
145 // Remove unconditional branch which is added by splitBasicBlock.
146 bb->getTerminator()->eraseFromParent();
TDYa127f15b0ab2012-05-11 21:01:36 -0700147
TDYa127afa97e22012-06-22 22:20:11 -0700148 irb_->SetInsertPoint(bb);
149 irb_->Runtime().EmitTestSuspend();
150 irb_->CreateBr(tb);
TDYa127f15b0ab2012-05-11 21:01:36 -0700151
152 return true;
153 }
154
155 private:
156 art::compiler_llvm::IRBuilder* irb_;
157};
158
159char AddSuspendCheckToLoopLatchPass::ID = 0;
160
161llvm::RegisterPass<AddSuspendCheckToLoopLatchPass> reg_add_suspend_check_to_loop_latch_pass_(
162 "add-suspend-check-to-loop-latch", "Add suspend check to loop latch pass", false, false);
163
164
Logan Chien110bcba2012-04-16 19:11:28 +0800165} // end anonymous namespace
166
Logan Chien8b977d32012-02-21 19:14:55 +0800167namespace art {
168namespace compiler_llvm {
169
170llvm::Module* makeLLVMModuleContents(llvm::Module* module);
171
172
Logan Chien6546ec52012-03-17 20:08:29 +0800173CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx)
Logan Chien8ba2fc52012-04-23 09:10:46 +0800174: cunit_lock_("compilation_unit_lock"), insn_set_(insn_set), elf_idx_(elf_idx),
TDYa127b2eb5c12012-05-24 15:52:10 -0700175 context_(new llvm::LLVMContext()), compiled_methods_map_(new CompiledMethodMap()),
176 mem_usage_(0), num_elf_funcs_(0) {
Logan Chien8b977d32012-02-21 19:14:55 +0800177
178 // Create the module and include the runtime function declaration
179 module_ = new llvm::Module("art", *context_);
180 makeLLVMModuleContents(module_);
181
182 // Create IRBuilder
183 irb_.reset(new IRBuilder(*context_, *module_));
TDYa127d668a062012-04-13 12:36:57 -0700184
185 // We always need a switch case, so just use a normal function.
186 switch(insn_set_) {
TDYa127b08ed122012-06-05 23:51:19 -0700187 default:
188 runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
189 break;
TDYa127d668a062012-04-13 12:36:57 -0700190 case kArm:
TDYa127d668a062012-04-13 12:36:57 -0700191 runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
192 break;
TDYa127b08ed122012-06-05 23:51:19 -0700193 case kThumb2:
194 runtime_support_.reset(new RuntimeSupportBuilderThumb2(*context_, *module_, *irb_));
195 break;
TDYa127d668a062012-04-13 12:36:57 -0700196 case kX86:
197 runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
198 break;
199 }
200
TDYa127d668a062012-04-13 12:36:57 -0700201 irb_->SetRuntimeSupport(runtime_support_.get());
Logan Chien8b977d32012-02-21 19:14:55 +0800202}
203
204
205CompilationUnit::~CompilationUnit() {
206}
207
208
Logan Chien08e1ba32012-05-08 15:08:51 +0800209bool CompilationUnit::Materialize(size_t thread_count) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800210 MutexLock GUARD(cunit_lock_);
211
Logan Chienb5eb00c2012-05-18 19:56:46 +0800212 // Materialize the bitcode to elf_image_
213 llvm::raw_string_ostream str_os(elf_image_);
214 bool success = MaterializeToFile(str_os);
215 LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)");
TDYa127388a83b2012-05-09 18:56:22 -0700216
Logan Chienb5eb00c2012-05-18 19:56:46 +0800217 // Free the resources
218 context_.reset(NULL);
219 irb_.reset(NULL);
220 module_ = NULL;
TDYa127b2eb5c12012-05-24 15:52:10 -0700221 runtime_support_.reset(NULL);
222 compiled_methods_map_.reset(NULL);
TDYa127388a83b2012-05-09 18:56:22 -0700223
Logan Chienb5eb00c2012-05-18 19:56:46 +0800224 return success;
Logan Chien8b977d32012-02-21 19:14:55 +0800225}
226
227
Logan Chien110bcba2012-04-16 19:11:28 +0800228void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
229 CompiledMethod* compiled_method) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800230 MutexLock GUARD(cunit_lock_);
TDYa127b2eb5c12012-05-24 15:52:10 -0700231 compiled_methods_map_->Put(func, compiled_method);
Logan Chien110bcba2012-04-16 19:11:28 +0800232}
233
234
235void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
236 size_t frame_size_in_bytes) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800237 MutexLock GUARD(cunit_lock_);
Logan Chien110bcba2012-04-16 19:11:28 +0800238 SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
TDYa127b2eb5c12012-05-24 15:52:10 -0700239 compiled_methods_map_->find(func);
Logan Chien110bcba2012-04-16 19:11:28 +0800240
TDYa127b2eb5c12012-05-24 15:52:10 -0700241 if (iter != compiled_methods_map_->end()) {
Logan Chien110bcba2012-04-16 19:11:28 +0800242 CompiledMethod* compiled_method = iter->second;
243 compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
244
245 if (frame_size_in_bytes > 1728u) {
246 LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
247 << " elf_idx=" << compiled_method->GetElfIndex()
248 << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
249 }
250 }
251}
252
Logan Chienb1bab1c2012-05-11 11:05:45 +0800253bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) {
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700254 // Lookup the LLVM target
255 char const* target_triple = NULL;
Shih-wei Liao53519bf2012-06-17 03:45:00 -0700256 char const* target_cpu = "";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700257 char const* target_attr = NULL;
258
Logan Chienb1bab1c2012-05-11 11:05:45 +0800259 switch (insn_set_) {
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700260 case kThumb2:
261 target_triple = "thumb-none-linux-gnueabi";
Shih-wei Liao53519bf2012-06-17 03:45:00 -0700262 target_cpu = "cortex-a9";
TDYa127b08ed122012-06-05 23:51:19 -0700263 target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700264 break;
265
266 case kArm:
267 target_triple = "armv7-none-linux-gnueabi";
Shih-wei Liao53519bf2012-06-17 03:45:00 -0700268 // TODO: Fix for Nexus S.
269 target_cpu = "cortex-a9";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700270 // TODO: Fix for Xoom.
TDYa127b08ed122012-06-05 23:51:19 -0700271 target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700272 break;
273
274 case kX86:
275 target_triple = "i386-pc-linux-gnu";
276 target_attr = "";
277 break;
278
279 case kMips:
280 target_triple = "mipsel-unknown-linux";
281 target_attr = "mips32r2";
282 break;
283
284 default:
Logan Chienb1bab1c2012-05-11 11:05:45 +0800285 LOG(FATAL) << "Unknown instruction set: " << insn_set_;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700286 }
287
288 std::string errmsg;
289 llvm::Target const* target =
290 llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
291
292 CHECK(target != NULL) << errmsg;
293
294 // Target options
295 llvm::TargetOptions target_options;
296 target_options.FloatABIType = llvm::FloatABI::Soft;
297 target_options.NoFramePointerElim = true;
298 target_options.NoFramePointerElimNonLeaf = true;
299 target_options.UseSoftFloat = false;
TDYa1273978da52012-05-19 07:45:39 -0700300 target_options.EnableFastISel = false;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700301
302 // Create the llvm::TargetMachine
Logan Chienb6bed0b2012-05-04 15:03:56 +0800303 llvm::OwningPtr<llvm::TargetMachine> target_machine(
Shih-wei Liao53519bf2012-06-17 03:45:00 -0700304 target->createTargetMachine(target_triple, target_cpu, target_attr, target_options,
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700305 llvm::Reloc::Static, llvm::CodeModel::Small,
Shih-wei Liaodac5eb22012-06-03 14:06:04 -0700306 llvm::CodeGenOpt::Aggressive));
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700307
Logan Chienb6bed0b2012-05-04 15:03:56 +0800308 CHECK(target_machine.get() != NULL) << "Failed to create target machine";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700309
310 // Add target data
311 llvm::TargetData const* target_data = target_machine->getTargetData();
312
313 // PassManager for code generation passes
314 llvm::PassManager pm;
315 pm.add(new llvm::TargetData(*target_data));
316
317 // FunctionPassManager for optimization pass
Logan Chien799ef4f2012-04-23 00:17:47 +0800318 llvm::FunctionPassManager fpm(module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700319 fpm.add(new llvm::TargetData(*target_data));
320
TDYa127f15b0ab2012-05-11 21:01:36 -0700321 if (bitcode_filename_.empty()) {
322 // If we don't need write the bitcode to file, add the AddSuspendCheckToLoopLatchPass to the
323 // regular FunctionPass.
324 fpm.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
325 } else {
326 // Run AddSuspendCheckToLoopLatchPass before we write the bitcode to file.
327 llvm::FunctionPassManager fpm2(module_);
328 fpm2.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
329 fpm2.doInitialization();
330 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
331 F != E; ++F) {
332 fpm2.run(*F);
333 }
334 fpm2.doFinalization();
335
336
337 // Write bitcode to file
338 std::string errmsg;
339
340 llvm::OwningPtr<llvm::tool_output_file> out_file(
341 new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
342 llvm::raw_fd_ostream::F_Binary));
343
344
345 if (!errmsg.empty()) {
346 LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
347 return false;
348 }
349
350 llvm::WriteBitcodeToFile(module_, out_file->os());
351 out_file->keep();
352 }
353
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700354 // Add optimization pass
355 llvm::PassManagerBuilder pm_builder;
TDYa127afa97e22012-06-22 22:20:11 -0700356 // TODO: Use inliner after we can do IPO.
357 pm_builder.Inliner = NULL;
Shih-wei Liaoe0e40242012-05-08 01:04:03 -0700358 //pm_builder.Inliner = llvm::createFunctionInliningPass();
TDYa127afa97e22012-06-22 22:20:11 -0700359 //pm_builder.Inliner = llvm::createAlwaysInlinerPass();
Shih-wei Liao415576b2012-04-23 15:28:53 -0700360 //pm_builder.Inliner = llvm::createPartialInliningPass();
361 pm_builder.OptLevel = 3;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700362 pm_builder.DisableSimplifyLibCalls = 1;
TDYa127e4c2ccc2012-05-13 21:10:36 -0700363 pm_builder.DisableUnitAtATime = 1;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700364 pm_builder.populateFunctionPassManager(fpm);
TDYa127ce9c3172012-05-15 06:09:27 -0700365 pm_builder.populateModulePassManager(pm);
366 pm.add(llvm::createStripDeadPrototypesPass());
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700367
368 // Add passes to emit ELF image
369 {
Logan Chien08e1ba32012-05-08 15:08:51 +0800370 llvm::formatted_raw_ostream formatted_os(out_stream, false);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700371
372 // Ask the target to add backend passes as necessary.
373 if (target_machine->addPassesToEmitFile(pm,
374 formatted_os,
375 llvm::TargetMachine::CGFT_ObjectFile,
376 true)) {
377 LOG(FATAL) << "Unable to generate ELF for this target";
378 return false;
379 }
380
381 // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to
382 // update the value reside in the different address space.
383 // Add pass to update the frame_size_in_bytes_
384 //pm.add(new ::UpdateFrameSizePass(this));
385
386 // Run the per-function optimization
387 fpm.doInitialization();
Logan Chien799ef4f2012-04-23 00:17:47 +0800388 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700389 F != E; ++F) {
390 fpm.run(*F);
391 }
392 fpm.doFinalization();
393
394 // Run the code generation passes
Logan Chien799ef4f2012-04-23 00:17:47 +0800395 pm.run(*module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700396 }
397
398 return true;
399}
Logan Chien110bcba2012-04-16 19:11:28 +0800400
Logan Chien8b977d32012-02-21 19:14:55 +0800401} // namespace compiler_llvm
402} // namespace art