blob: 66fdba06c6305dce40b2f66176175b1ba14d807f [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"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070020#include "instruction_set.h"
Logan Chien8b977d32012-02-21 19:14:55 +080021#include "ir_builder.h"
22#include "logging.h"
23
TDYa127d668a062012-04-13 12:36:57 -070024#include "runtime_support_builder_arm.h"
25#include "runtime_support_builder_x86.h"
26
Logan Chien8b977d32012-02-21 19:14:55 +080027#include <llvm/ADT/OwningPtr.h>
28#include <llvm/ADT/StringSet.h>
29#include <llvm/ADT/Triple.h>
30#include <llvm/Analysis/CallGraph.h>
31#include <llvm/Analysis/DebugInfo.h>
32#include <llvm/Analysis/LoopPass.h>
33#include <llvm/Analysis/RegionPass.h>
34#include <llvm/Analysis/Verifier.h>
35#include <llvm/Assembly/PrintModulePass.h>
36#include <llvm/Bitcode/ReaderWriter.h>
37#include <llvm/CallGraphSCCPass.h>
Logan Chien110bcba2012-04-16 19:11:28 +080038#include <llvm/CodeGen/MachineFrameInfo.h>
39#include <llvm/CodeGen/MachineFunction.h>
40#include <llvm/CodeGen/MachineFunctionPass.h>
Logan Chien8b977d32012-02-21 19:14:55 +080041#include <llvm/DerivedTypes.h>
42#include <llvm/LLVMContext.h>
Logan Chien8b977d32012-02-21 19:14:55 +080043#include <llvm/Module.h>
44#include <llvm/PassManager.h>
45#include <llvm/Support/Debug.h>
46#include <llvm/Support/FormattedStream.h>
47#include <llvm/Support/ManagedStatic.h>
48#include <llvm/Support/PassNameParser.h>
49#include <llvm/Support/PluginLoader.h>
50#include <llvm/Support/PrettyStackTrace.h>
51#include <llvm/Support/Signals.h>
52#include <llvm/Support/SystemUtils.h>
53#include <llvm/Support/TargetRegistry.h>
54#include <llvm/Support/TargetSelect.h>
55#include <llvm/Support/ToolOutputFile.h>
56#include <llvm/Support/raw_ostream.h>
57#include <llvm/Target/TargetData.h>
58#include <llvm/Target/TargetLibraryInfo.h>
59#include <llvm/Target/TargetMachine.h>
Shih-wei Liaof1cb9a52012-04-20 01:49:18 -070060#include <llvm/Transforms/IPO.h>
Logan Chien8b977d32012-02-21 19:14:55 +080061#include <llvm/Transforms/IPO/PassManagerBuilder.h>
62
63#include <string>
64
Logan Chien110bcba2012-04-16 19:11:28 +080065namespace {
66
67class UpdateFrameSizePass : public llvm::MachineFunctionPass {
68 public:
69 static char ID;
70
71 UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) {
72 LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass";
73 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
74 // this constructor won't work because we have no information on
75 // CompilationUnit. Thus, we should place a LOG(FATAL) here.
76 }
77
78 UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit)
79 : llvm::MachineFunctionPass(ID), cunit_(cunit) {
80 }
81
82 virtual bool runOnMachineFunction(llvm::MachineFunction &MF) {
83 cunit_->UpdateFrameSizeInBytes(MF.getFunction(),
84 MF.getFrameInfo()->getStackSize());
85 return false;
86 }
87
88 private:
89 art::compiler_llvm::CompilationUnit* cunit_;
90};
91
92char UpdateFrameSizePass::ID = 0;
93
94llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
95 "update-frame-size", "Update frame size pass", false, false);
96
97} // end anonymous namespace
98
Logan Chien8b977d32012-02-21 19:14:55 +080099namespace art {
100namespace compiler_llvm {
101
102llvm::Module* makeLLVMModuleContents(llvm::Module* module);
103
104
Logan Chien6546ec52012-03-17 20:08:29 +0800105CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx)
106: insn_set_(insn_set), elf_idx_(elf_idx), context_(new llvm::LLVMContext()),
Logan Chien937105a2012-04-02 02:37:37 +0800107 mem_usage_(0), num_elf_funcs_(0) {
Logan Chien8b977d32012-02-21 19:14:55 +0800108
109 // Create the module and include the runtime function declaration
110 module_ = new llvm::Module("art", *context_);
111 makeLLVMModuleContents(module_);
112
113 // Create IRBuilder
114 irb_.reset(new IRBuilder(*context_, *module_));
TDYa127d668a062012-04-13 12:36:57 -0700115
116 // We always need a switch case, so just use a normal function.
117 switch(insn_set_) {
118 default:
119 runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
120 break;
121 case kArm:
122 case kThumb2:
123 runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
124 break;
125 case kX86:
126 runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
127 break;
128 }
129
130 runtime_support_->OptimizeRuntimeSupport();
131
132 irb_->SetRuntimeSupport(runtime_support_.get());
Logan Chien8b977d32012-02-21 19:14:55 +0800133}
134
135
136CompilationUnit::~CompilationUnit() {
137}
138
139
140bool CompilationUnit::WriteBitcodeToFile() {
141 std::string errmsg;
142
143 llvm::OwningPtr<llvm::tool_output_file> out_file(
144 new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
145 llvm::raw_fd_ostream::F_Binary));
146
147
148 if (!errmsg.empty()) {
149 LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
150 return false;
151 }
152
153 llvm::WriteBitcodeToFile(module_, out_file->os());
154 out_file->keep();
155
156 return true;
157}
158
159
160bool CompilationUnit::Materialize() {
Logan Chien8b977d32012-02-21 19:14:55 +0800161 // Lookup the LLVM target
162 char const* target_triple = NULL;
163 char const* target_attr = NULL;
164
Logan Chien8ee03b52012-03-01 13:53:02 +0800165 switch (insn_set_) {
166 case kThumb2:
Logan Chien8b977d32012-02-21 19:14:55 +0800167 target_triple = "thumb-none-linux-gnueabi";
168 target_attr = "+thumb2,+neon,+neonfp,+vfp3";
Logan Chien8ee03b52012-03-01 13:53:02 +0800169 break;
170
171 case kArm:
Logan Chien8b977d32012-02-21 19:14:55 +0800172 target_triple = "armv7-none-linux-gnueabi";
173 target_attr = "+v7,+neon,+neonfp,+vfp3";
Logan Chien8ee03b52012-03-01 13:53:02 +0800174 break;
175
176 case kX86:
Logan Chien8b977d32012-02-21 19:14:55 +0800177 target_triple = "i386-pc-linux-gnu";
178 target_attr = "";
Logan Chien8ee03b52012-03-01 13:53:02 +0800179 break;
180
Shih-wei Liao6edfde42012-03-01 15:49:12 -0800181 case kMips:
182 target_triple = "mipsel-unknown-linux";
183 target_attr = "mips32r2";
184 break;
Logan Chien8ee03b52012-03-01 13:53:02 +0800185
186 default:
Logan Chien8b977d32012-02-21 19:14:55 +0800187 LOG(FATAL) << "Unknown instruction set: " << insn_set_;
188 }
189
190 std::string errmsg;
191 llvm::Target const* target =
192 llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
193
194 CHECK(target != NULL) << errmsg;
195
196 // Target options
197 llvm::TargetOptions target_options;
Logan Chien8b977d32012-02-21 19:14:55 +0800198 target_options.FloatABIType = llvm::FloatABI::Soft;
Shih-wei Liao5b8b1ed2012-02-23 23:48:21 -0800199 target_options.NoFramePointerElim = true;
200 target_options.NoFramePointerElimNonLeaf = true;
Logan Chien6d6d7542012-03-02 14:00:31 +0800201 target_options.UseSoftFloat = false;
Shih-wei Liaoc6c317e2012-03-30 01:41:18 -0700202 target_options.EnableFastISel = true;
Logan Chien8b977d32012-02-21 19:14:55 +0800203
204 // Create the llvm::TargetMachine
205 llvm::TargetMachine* target_machine =
206 target->createTargetMachine(target_triple, "", target_attr, target_options,
207 llvm::Reloc::Static, llvm::CodeModel::Small,
Shih-wei Liao17765722012-04-17 16:42:19 -0700208 llvm::CodeGenOpt::Less);
Logan Chien8b977d32012-02-21 19:14:55 +0800209
210 CHECK(target_machine != NULL) << "Failed to create target machine";
211
212
213 // Add target data
214 llvm::TargetData const* target_data = target_machine->getTargetData();
215
216 // PassManager for code generation passes
217 llvm::PassManager pm;
218 pm.add(new llvm::TargetData(*target_data));
219
220 // FunctionPassManager for optimization pass
221 llvm::FunctionPassManager fpm(module_);
222 fpm.add(new llvm::TargetData(*target_data));
223
Shih-wei Liao17765722012-04-17 16:42:19 -0700224 // Add optimization pass
225 llvm::PassManagerBuilder pm_builder;
Shih-wei Liaof1cb9a52012-04-20 01:49:18 -0700226 pm_builder.Inliner = llvm::createAlwaysInlinerPass();
Shih-wei Liao17765722012-04-17 16:42:19 -0700227 pm_builder.OptLevel = 1;
228 pm_builder.DisableSimplifyLibCalls = 1;
229 pm_builder.populateModulePassManager(pm);
230 pm_builder.populateFunctionPassManager(fpm);
231
Logan Chienb9eaeea2012-03-17 19:45:01 +0800232 // Add passes to emit ELF image
233 {
234 llvm::formatted_raw_ostream formatted_os(
235 *(new llvm::raw_string_ostream(elf_image_)), true);
236
237 // Ask the target to add backend passes as necessary.
238 if (target_machine->addPassesToEmitFile(pm,
239 formatted_os,
240 llvm::TargetMachine::CGFT_ObjectFile,
241 true)) {
242 LOG(FATAL) << "Unable to generate ELF for this target";
243 return false;
244 }
245
Logan Chien110bcba2012-04-16 19:11:28 +0800246 // Add pass to update the frame_size_in_bytes_
247 pm.add(new ::UpdateFrameSizePass(this));
248
Shih-wei Liao17765722012-04-17 16:42:19 -0700249 // Run the per-function optimization
250 fpm.doInitialization();
251 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
252 F != E; ++F) {
253 fpm.run(*F);
254 }
255 fpm.doFinalization();
256
Logan Chienb9eaeea2012-03-17 19:45:01 +0800257 // Run the code generation passes
258 pm.run(*module_);
259 }
260
Logan Chiende08e842012-03-21 00:34:12 +0800261 LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
Logan Chien7f767612012-03-01 18:54:49 +0800262
263 // Free the resources
264 context_.reset(NULL);
265 irb_.reset(NULL);
266 module_ = NULL;
Logan Chien8b977d32012-02-21 19:14:55 +0800267
268 return true;
269}
270
271
Logan Chien110bcba2012-04-16 19:11:28 +0800272void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
273 CompiledMethod* compiled_method) {
274 compiled_methods_map_.Put(func, compiled_method);
275}
276
277
278void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
279 size_t frame_size_in_bytes) {
280 SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
281 compiled_methods_map_.find(func);
282
283 if (iter != compiled_methods_map_.end()) {
284 CompiledMethod* compiled_method = iter->second;
285 compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
286
287 if (frame_size_in_bytes > 1728u) {
288 LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
289 << " elf_idx=" << compiled_method->GetElfIndex()
290 << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
291 }
292 }
293}
294
295
Logan Chien8b977d32012-02-21 19:14:55 +0800296} // namespace compiler_llvm
297} // namespace art