blob: 7a2857c36b2c9a1593c02fb0250ea199b6d7df63 [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
19#include "constants.h"
20#include "ir_builder.h"
21#include "logging.h"
22
23#include <llvm/ADT/OwningPtr.h>
24#include <llvm/ADT/StringSet.h>
25#include <llvm/ADT/Triple.h>
26#include <llvm/Analysis/CallGraph.h>
27#include <llvm/Analysis/DebugInfo.h>
28#include <llvm/Analysis/LoopPass.h>
29#include <llvm/Analysis/RegionPass.h>
30#include <llvm/Analysis/Verifier.h>
31#include <llvm/Assembly/PrintModulePass.h>
32#include <llvm/Bitcode/ReaderWriter.h>
33#include <llvm/CallGraphSCCPass.h>
34#include <llvm/DerivedTypes.h>
35#include <llvm/LLVMContext.h>
36#include <llvm/LinkAllPasses.h>
37#include <llvm/LinkAllVMCore.h>
38#include <llvm/Module.h>
39#include <llvm/PassManager.h>
40#include <llvm/Support/Debug.h>
41#include <llvm/Support/FormattedStream.h>
42#include <llvm/Support/ManagedStatic.h>
43#include <llvm/Support/PassNameParser.h>
44#include <llvm/Support/PluginLoader.h>
45#include <llvm/Support/PrettyStackTrace.h>
46#include <llvm/Support/Signals.h>
47#include <llvm/Support/SystemUtils.h>
48#include <llvm/Support/TargetRegistry.h>
49#include <llvm/Support/TargetSelect.h>
50#include <llvm/Support/ToolOutputFile.h>
51#include <llvm/Support/raw_ostream.h>
52#include <llvm/Target/TargetData.h>
53#include <llvm/Target/TargetLibraryInfo.h>
54#include <llvm/Target/TargetMachine.h>
55#include <llvm/Transforms/IPO/PassManagerBuilder.h>
56
57#include <string>
58
59namespace art {
60namespace compiler_llvm {
61
62llvm::Module* makeLLVMModuleContents(llvm::Module* module);
63
64
65CompilationUnit::CompilationUnit(InstructionSet insn_set)
66: insn_set_(insn_set), context_(new llvm::LLVMContext()), mem_usage_(0) {
67
68 // Create the module and include the runtime function declaration
69 module_ = new llvm::Module("art", *context_);
70 makeLLVMModuleContents(module_);
71
72 // Create IRBuilder
73 irb_.reset(new IRBuilder(*context_, *module_));
74}
75
76
77CompilationUnit::~CompilationUnit() {
78}
79
80
81bool CompilationUnit::WriteBitcodeToFile() {
82 std::string errmsg;
83
84 llvm::OwningPtr<llvm::tool_output_file> out_file(
85 new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
86 llvm::raw_fd_ostream::F_Binary));
87
88
89 if (!errmsg.empty()) {
90 LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
91 return false;
92 }
93
94 llvm::WriteBitcodeToFile(module_, out_file->os());
95 out_file->keep();
96
97 return true;
98}
99
100
101bool CompilationUnit::Materialize() {
102 // Initialize LLVM optimization passes
103 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
104
105 llvm::initializeCore(Registry);
106 llvm::initializeScalarOpts(Registry);
107 llvm::initializeIPO(Registry);
108 llvm::initializeAnalysis(Registry);
109 llvm::initializeIPA(Registry);
110 llvm::initializeTransformUtils(Registry);
111 llvm::initializeInstCombine(Registry);
112 llvm::initializeInstrumentation(Registry);
113 llvm::initializeTarget(Registry);
114
115 // Lookup the LLVM target
116 char const* target_triple = NULL;
117 char const* target_attr = NULL;
118
119 if (insn_set_ == kThumb2) {
120 target_triple = "thumb-none-linux-gnueabi";
121 target_attr = "+thumb2,+neon,+neonfp,+vfp3";
122 } else if (insn_set_ == kArm) {
123 target_triple = "armv7-none-linux-gnueabi";
124 target_attr = "+v7,+neon,+neonfp,+vfp3";
125 } else if (insn_set_ == kX86) {
126 target_triple = "i386-pc-linux-gnu";
127 target_attr = "";
128 // } else if (insn_set_ == kMips) {
129 // target_triple = "mipsel-unknown-linux";
130 // target_attr = "";
131 } else {
132 LOG(FATAL) << "Unknown instruction set: " << insn_set_;
133 }
134
135 std::string errmsg;
136 llvm::Target const* target =
137 llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
138
139 CHECK(target != NULL) << errmsg;
140
141 // Target options
142 llvm::TargetOptions target_options;
143
144 target_options.FloatABIType = llvm::FloatABI::Soft;
145 target_options.UseSoftFloat = false;
Shih-wei Liao5b8b1ed2012-02-23 23:48:21 -0800146 target_options.NoFramePointerElim = true;
147 target_options.NoFramePointerElimNonLeaf = true;
Logan Chien8b977d32012-02-21 19:14:55 +0800148
149 // Create the llvm::TargetMachine
150 llvm::TargetMachine* target_machine =
151 target->createTargetMachine(target_triple, "", target_attr, target_options,
152 llvm::Reloc::Static, llvm::CodeModel::Small,
153 llvm::CodeGenOpt::Aggressive);
154
155 CHECK(target_machine != NULL) << "Failed to create target machine";
156
157
158 // Add target data
159 llvm::TargetData const* target_data = target_machine->getTargetData();
160
161 // PassManager for code generation passes
162 llvm::PassManager pm;
163 pm.add(new llvm::TargetData(*target_data));
164
165 // FunctionPassManager for optimization pass
166 llvm::FunctionPassManager fpm(module_);
167 fpm.add(new llvm::TargetData(*target_data));
168
169 // Add optimization pass
170 llvm::PassManagerBuilder pm_builder;
171 pm_builder.Inliner = NULL; // TODO: add some inline in the future
172 pm_builder.OptLevel = 3;
173 pm_builder.DisableSimplifyLibCalls = 1;
174 pm_builder.populateModulePassManager(pm);
175 pm_builder.populateFunctionPassManager(fpm);
176
177 // Add passes to emit file
178 llvm::OwningPtr<llvm::tool_output_file> out_file(
179 new llvm::tool_output_file(elf_filename_.c_str(), errmsg,
180 llvm::raw_fd_ostream::F_Binary));
181
182 llvm::formatted_raw_ostream formatted_os(out_file->os(), false);
183
184 // Ask the target to add backend passes as necessary.
185 if (target_machine->addPassesToEmitFile(pm,
186 formatted_os,
187 llvm::TargetMachine::CGFT_ObjectFile,
188 true)) {
189 LOG(FATAL) << "Unable to generate ELF for this target";
190 return false;
191 }
192
193 // Run the per-function optimization
194 fpm.doInitialization();
195 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
196 F != E; ++F) {
197 fpm.run(*F);
198 }
199 fpm.doFinalization();
200 LOG(INFO) << "Intraprocedural optimization finished!";
201
202 // Run the code generation passes
203 pm.run(*module_);
204 LOG(INFO) << "Code generation finished!";
205
206 out_file->keep();
207 LOG(DEBUG) << "ELF: " << elf_filename_ << " (done)";
208
209 return true;
210}
211
212
213void CompilationUnit::Finalize() {
214 context_.reset(NULL);
215 irb_.reset(NULL);
216 module_ = NULL;
217}
218
219} // namespace compiler_llvm
220} // namespace art