blob: ae6e0a2cf6a2614fd83df66c27cdbad506813bb3 [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"
27#include "runtime_support_builder_x86.h"
28
Logan Chien8b977d32012-02-21 19:14:55 +080029#include <llvm/ADT/OwningPtr.h>
30#include <llvm/ADT/StringSet.h>
31#include <llvm/ADT/Triple.h>
32#include <llvm/Analysis/CallGraph.h>
33#include <llvm/Analysis/DebugInfo.h>
34#include <llvm/Analysis/LoopPass.h>
35#include <llvm/Analysis/RegionPass.h>
36#include <llvm/Analysis/Verifier.h>
37#include <llvm/Assembly/PrintModulePass.h>
38#include <llvm/Bitcode/ReaderWriter.h>
39#include <llvm/CallGraphSCCPass.h>
Logan Chien110bcba2012-04-16 19:11:28 +080040#include <llvm/CodeGen/MachineFrameInfo.h>
41#include <llvm/CodeGen/MachineFunction.h>
42#include <llvm/CodeGen/MachineFunctionPass.h>
Logan Chien8b977d32012-02-21 19:14:55 +080043#include <llvm/DerivedTypes.h>
44#include <llvm/LLVMContext.h>
Logan Chien8b977d32012-02-21 19:14:55 +080045#include <llvm/Module.h>
46#include <llvm/PassManager.h>
47#include <llvm/Support/Debug.h>
48#include <llvm/Support/FormattedStream.h>
49#include <llvm/Support/ManagedStatic.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070050#include <llvm/Support/MemoryBuffer.h>
Logan Chien8b977d32012-02-21 19:14:55 +080051#include <llvm/Support/PassNameParser.h>
52#include <llvm/Support/PluginLoader.h>
53#include <llvm/Support/PrettyStackTrace.h>
54#include <llvm/Support/Signals.h>
55#include <llvm/Support/SystemUtils.h>
56#include <llvm/Support/TargetRegistry.h>
57#include <llvm/Support/TargetSelect.h>
58#include <llvm/Support/ToolOutputFile.h>
59#include <llvm/Support/raw_ostream.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070060#include <llvm/Support/system_error.h>
Logan Chien8b977d32012-02-21 19:14:55 +080061#include <llvm/Target/TargetData.h>
62#include <llvm/Target/TargetLibraryInfo.h>
63#include <llvm/Target/TargetMachine.h>
Shih-wei Liaof1cb9a52012-04-20 01:49:18 -070064#include <llvm/Transforms/IPO.h>
Logan Chien8b977d32012-02-21 19:14:55 +080065#include <llvm/Transforms/IPO/PassManagerBuilder.h>
66
Shih-wei Liaod7726e42012-04-20 15:23:36 -070067#include <sys/types.h>
68#include <sys/wait.h>
69#include <unistd.h>
70
Logan Chien8b977d32012-02-21 19:14:55 +080071#include <string>
72
Logan Chien110bcba2012-04-16 19:11:28 +080073namespace {
74
75class UpdateFrameSizePass : public llvm::MachineFunctionPass {
76 public:
77 static char ID;
78
79 UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) {
80 LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass";
81 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
82 // this constructor won't work because we have no information on
83 // CompilationUnit. Thus, we should place a LOG(FATAL) here.
84 }
85
86 UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit)
87 : llvm::MachineFunctionPass(ID), cunit_(cunit) {
88 }
89
90 virtual bool runOnMachineFunction(llvm::MachineFunction &MF) {
91 cunit_->UpdateFrameSizeInBytes(MF.getFunction(),
92 MF.getFrameInfo()->getStackSize());
93 return false;
94 }
95
96 private:
97 art::compiler_llvm::CompilationUnit* cunit_;
98};
99
100char UpdateFrameSizePass::ID = 0;
101
102llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
103 "update-frame-size", "Update frame size pass", false, false);
104
105} // end anonymous namespace
106
Logan Chien8b977d32012-02-21 19:14:55 +0800107namespace art {
108namespace compiler_llvm {
109
110llvm::Module* makeLLVMModuleContents(llvm::Module* module);
111
112
Logan Chien6546ec52012-03-17 20:08:29 +0800113CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx)
Logan Chien8ba2fc52012-04-23 09:10:46 +0800114: cunit_lock_("compilation_unit_lock"), insn_set_(insn_set), elf_idx_(elf_idx),
115 context_(new llvm::LLVMContext()), mem_usage_(0), num_elf_funcs_(0) {
Logan Chien8b977d32012-02-21 19:14:55 +0800116
117 // Create the module and include the runtime function declaration
118 module_ = new llvm::Module("art", *context_);
119 makeLLVMModuleContents(module_);
120
121 // Create IRBuilder
122 irb_.reset(new IRBuilder(*context_, *module_));
TDYa127d668a062012-04-13 12:36:57 -0700123
124 // We always need a switch case, so just use a normal function.
125 switch(insn_set_) {
126 default:
127 runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
128 break;
129 case kArm:
130 case kThumb2:
131 runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
132 break;
133 case kX86:
134 runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
135 break;
136 }
137
138 runtime_support_->OptimizeRuntimeSupport();
139
140 irb_->SetRuntimeSupport(runtime_support_.get());
Logan Chien8b977d32012-02-21 19:14:55 +0800141}
142
143
144CompilationUnit::~CompilationUnit() {
145}
146
147
Shih-wei Liaodbd00342012-04-20 14:27:29 -0700148bool CompilationUnit::WriteBitcodeToFile(const std::string& bitcode_filename) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800149 MutexLock GUARD(cunit_lock_);
Logan Chien8b977d32012-02-21 19:14:55 +0800150 std::string errmsg;
151
152 llvm::OwningPtr<llvm::tool_output_file> out_file(
Shih-wei Liaodbd00342012-04-20 14:27:29 -0700153 new llvm::tool_output_file(bitcode_filename.c_str(), errmsg,
Logan Chien8b977d32012-02-21 19:14:55 +0800154 llvm::raw_fd_ostream::F_Binary));
155
156
157 if (!errmsg.empty()) {
158 LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
159 return false;
160 }
161
162 llvm::WriteBitcodeToFile(module_, out_file->os());
163 out_file->keep();
164
165 return true;
166}
167
Logan Chien8b977d32012-02-21 19:14:55 +0800168
Logan Chien08e1ba32012-05-08 15:08:51 +0800169bool CompilationUnit::Materialize(size_t thread_count) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800170 MutexLock GUARD(cunit_lock_);
171
Logan Chien08e1ba32012-05-08 15:08:51 +0800172 if (thread_count == 1) {
173 llvm::raw_string_ostream str_os(elf_image_);
TDYa127a22ea032012-05-09 12:20:01 -0700174 bool success = MaterializeToFile(str_os, insn_set_);
175 LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)");
TDYa127388a83b2012-05-09 18:56:22 -0700176
177 // Free the resources
178 context_.reset(NULL);
179 irb_.reset(NULL);
180 module_ = NULL;
181
TDYa127a22ea032012-05-09 12:20:01 -0700182 return success;
Logan Chien08e1ba32012-05-08 15:08:51 +0800183 }
184
Logan Chien799ef4f2012-04-23 00:17:47 +0800185 // Prepare the pipe between parent process and child process
186 int pipe_fd[2];
187 if (pipe(pipe_fd) == -1) {
Shih-wei Liaoe8ecce72012-04-23 15:00:32 -0700188 PLOG(FATAL) << "Failed to create pipe for CompilerWorker";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700189 return false;
190 }
Shih-wei Liao17765722012-04-17 16:42:19 -0700191
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700192 // Fork a process to do the compilation
193 pid_t pid = fork();
Logan Chien799ef4f2012-04-23 00:17:47 +0800194 if (pid < 0) {
195 close(pipe_fd[0]);
196 close(pipe_fd[1]);
197 PLOG(FATAL) << "Failed to fork a process to do the compilation";
198 return false;
199
200 } else if (pid == 0) { // Child process
201 // Close the unused pipe read end
202 close(pipe_fd[0]);
203
204 // Change process groups, so we don't get ripped by ProcessManager
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700205 setpgid(0, 0);
Logan Chienb9eaeea2012-03-17 19:45:01 +0800206
Logan Chien08e1ba32012-05-08 15:08:51 +0800207 llvm::raw_fd_ostream fd_os(pipe_fd[1], /* shouldClose */true);
208
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700209 // TODO: Should use exec* family instead of invoking a function.
210 // Forward our compilation request to bcc.
Logan Chien08e1ba32012-05-08 15:08:51 +0800211 exit(static_cast<int>(!MaterializeToFile(fd_os, insn_set_)));
Logan Chien799ef4f2012-04-23 00:17:47 +0800212
213 } else { // Parent process
214 // Close the unused pipe write end
215 close(pipe_fd[1]);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700216
217 // Free the resources
218 context_.reset(NULL);
219 irb_.reset(NULL);
220 module_ = NULL;
221
Logan Chien799ef4f2012-04-23 00:17:47 +0800222 // Read the result out from the pipe read end (until failure)
223 const size_t buf_size = 1024;
224 std::vector<uint8_t> buf(buf_size);
225 while (true) {
226 // Read from the pipe
227 ssize_t nread = read(pipe_fd[0], &*buf.begin(), buf_size);
228 if (nread < 0) {
229 if (errno == EAGAIN || errno == EINTR) {
230 continue;
231 } else {
232 LOG(ERROR) << "Unexpected error during IPC: " << strerror(errno);
233 }
234 }
235
236 // Append to the end of the elf_image_
Logan Chien08e1ba32012-05-08 15:08:51 +0800237 elf_image_.append(buf.begin(), buf.begin() + nread);
Logan Chien799ef4f2012-04-23 00:17:47 +0800238
239 if (nread < static_cast<ssize_t>(buf_size)) { // EOF reached!
240 break;
241 }
242 }
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700243
Shih-wei Liaoe8ecce72012-04-23 15:00:32 -0700244 close(pipe_fd[0]);
245
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700246 // Wait for child to finish
Logan Chien799ef4f2012-04-23 00:17:47 +0800247 int status;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700248 pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
249 if (got_pid != pid) {
250 PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
Logan Chien799ef4f2012-04-23 00:17:47 +0800251 elf_image_.clear();
Logan Chienb9eaeea2012-03-17 19:45:01 +0800252 return false;
253 }
254
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700255 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
256 LOG(ERROR) << "Failed to compile the bitcode: " << WEXITSTATUS(status);
Logan Chien799ef4f2012-04-23 00:17:47 +0800257 elf_image_.clear();
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700258 return false;
Shih-wei Liao17765722012-04-17 16:42:19 -0700259 }
Logan Chien799ef4f2012-04-23 00:17:47 +0800260
261 LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
262 return true;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700263 }
Logan Chien8b977d32012-02-21 19:14:55 +0800264}
265
266
Logan Chien110bcba2012-04-16 19:11:28 +0800267void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
268 CompiledMethod* compiled_method) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800269 MutexLock GUARD(cunit_lock_);
Logan Chien110bcba2012-04-16 19:11:28 +0800270 compiled_methods_map_.Put(func, compiled_method);
271}
272
273
274void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
275 size_t frame_size_in_bytes) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800276 MutexLock GUARD(cunit_lock_);
Logan Chien110bcba2012-04-16 19:11:28 +0800277 SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
278 compiled_methods_map_.find(func);
279
280 if (iter != compiled_methods_map_.end()) {
281 CompiledMethod* compiled_method = iter->second;
282 compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
283
284 if (frame_size_in_bytes > 1728u) {
285 LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
286 << " elf_idx=" << compiled_method->GetElfIndex()
287 << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
288 }
289 }
290}
291
Logan Chien08e1ba32012-05-08 15:08:51 +0800292bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream,
Logan Chien799ef4f2012-04-23 00:17:47 +0800293 InstructionSet insn_set) {
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700294 // Initialize the LLVM first
295 llvm::InitializeAllTargets();
296 llvm::InitializeAllTargetMCs();
297 llvm::InitializeAllAsmPrinters();
298 llvm::InitializeAllAsmParsers();
299
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700300 // Lookup the LLVM target
301 char const* target_triple = NULL;
302 char const* target_attr = NULL;
303
304 switch (insn_set) {
305 case kThumb2:
306 target_triple = "thumb-none-linux-gnueabi";
307 target_attr = "+thumb2,+neon,+neonfp,+vfp3";
308 break;
309
310 case kArm:
311 target_triple = "armv7-none-linux-gnueabi";
312 // TODO: Fix for Xoom.
313 target_attr = "+v7,+neon,+neonfp,+vfp3";
314 break;
315
316 case kX86:
317 target_triple = "i386-pc-linux-gnu";
318 target_attr = "";
319 break;
320
321 case kMips:
322 target_triple = "mipsel-unknown-linux";
323 target_attr = "mips32r2";
324 break;
325
326 default:
327 LOG(FATAL) << "Unknown instruction set: " << insn_set;
328 }
329
330 std::string errmsg;
331 llvm::Target const* target =
332 llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
333
334 CHECK(target != NULL) << errmsg;
335
336 // Target options
337 llvm::TargetOptions target_options;
338 target_options.FloatABIType = llvm::FloatABI::Soft;
339 target_options.NoFramePointerElim = true;
340 target_options.NoFramePointerElimNonLeaf = true;
341 target_options.UseSoftFloat = false;
342 target_options.EnableFastISel = true;
343
344 // Create the llvm::TargetMachine
Logan Chienb6bed0b2012-05-04 15:03:56 +0800345 llvm::OwningPtr<llvm::TargetMachine> target_machine(
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700346 target->createTargetMachine(target_triple, "", target_attr, target_options,
347 llvm::Reloc::Static, llvm::CodeModel::Small,
Logan Chienb6bed0b2012-05-04 15:03:56 +0800348 llvm::CodeGenOpt::Aggressive));
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700349
Logan Chienb6bed0b2012-05-04 15:03:56 +0800350 CHECK(target_machine.get() != NULL) << "Failed to create target machine";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700351
352 // Add target data
353 llvm::TargetData const* target_data = target_machine->getTargetData();
354
355 // PassManager for code generation passes
356 llvm::PassManager pm;
357 pm.add(new llvm::TargetData(*target_data));
358
359 // FunctionPassManager for optimization pass
Logan Chien799ef4f2012-04-23 00:17:47 +0800360 llvm::FunctionPassManager fpm(module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700361 fpm.add(new llvm::TargetData(*target_data));
362
363 // Add optimization pass
364 llvm::PassManagerBuilder pm_builder;
Shih-wei Liaoe0e40242012-05-08 01:04:03 -0700365 //pm_builder.Inliner = llvm::createFunctionInliningPass();
366 pm_builder.Inliner = llvm::createAlwaysInlinerPass();
Shih-wei Liao415576b2012-04-23 15:28:53 -0700367 //pm_builder.Inliner = llvm::createPartialInliningPass();
368 pm_builder.OptLevel = 3;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700369 pm_builder.DisableSimplifyLibCalls = 1;
370 pm_builder.populateModulePassManager(pm);
371 pm_builder.populateFunctionPassManager(fpm);
372
373 // Add passes to emit ELF image
374 {
Logan Chien08e1ba32012-05-08 15:08:51 +0800375 llvm::formatted_raw_ostream formatted_os(out_stream, false);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700376
377 // Ask the target to add backend passes as necessary.
378 if (target_machine->addPassesToEmitFile(pm,
379 formatted_os,
380 llvm::TargetMachine::CGFT_ObjectFile,
381 true)) {
382 LOG(FATAL) << "Unable to generate ELF for this target";
383 return false;
384 }
385
386 // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to
387 // update the value reside in the different address space.
388 // Add pass to update the frame_size_in_bytes_
389 //pm.add(new ::UpdateFrameSizePass(this));
390
391 // Run the per-function optimization
392 fpm.doInitialization();
Logan Chien799ef4f2012-04-23 00:17:47 +0800393 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700394 F != E; ++F) {
395 fpm.run(*F);
396 }
397 fpm.doFinalization();
398
399 // Run the code generation passes
Logan Chien799ef4f2012-04-23 00:17:47 +0800400 pm.run(*module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700401 }
402
403 return true;
404}
Logan Chien110bcba2012-04-16 19:11:28 +0800405
Logan Chien8b977d32012-02-21 19:14:55 +0800406} // namespace compiler_llvm
407} // namespace art