blob: 30c6aa1e140182e99587d390f30fb4a47dbb0187 [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>
TDYa127f15b0ab2012-05-11 21:01:36 -070034#include <llvm/Analysis/Dominators.h>
35#include <llvm/Analysis/LoopInfo.h>
Logan Chien8b977d32012-02-21 19:14:55 +080036#include <llvm/Analysis/LoopPass.h>
37#include <llvm/Analysis/RegionPass.h>
TDYa127f15b0ab2012-05-11 21:01:36 -070038#include <llvm/Analysis/ScalarEvolution.h>
Logan Chien8b977d32012-02-21 19:14:55 +080039#include <llvm/Analysis/Verifier.h>
40#include <llvm/Assembly/PrintModulePass.h>
41#include <llvm/Bitcode/ReaderWriter.h>
42#include <llvm/CallGraphSCCPass.h>
Logan Chien110bcba2012-04-16 19:11:28 +080043#include <llvm/CodeGen/MachineFrameInfo.h>
44#include <llvm/CodeGen/MachineFunction.h>
45#include <llvm/CodeGen/MachineFunctionPass.h>
Logan Chien8b977d32012-02-21 19:14:55 +080046#include <llvm/DerivedTypes.h>
47#include <llvm/LLVMContext.h>
Logan Chien8b977d32012-02-21 19:14:55 +080048#include <llvm/Module.h>
49#include <llvm/PassManager.h>
50#include <llvm/Support/Debug.h>
51#include <llvm/Support/FormattedStream.h>
52#include <llvm/Support/ManagedStatic.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070053#include <llvm/Support/MemoryBuffer.h>
Logan Chien8b977d32012-02-21 19:14:55 +080054#include <llvm/Support/PassNameParser.h>
55#include <llvm/Support/PluginLoader.h>
56#include <llvm/Support/PrettyStackTrace.h>
57#include <llvm/Support/Signals.h>
58#include <llvm/Support/SystemUtils.h>
59#include <llvm/Support/TargetRegistry.h>
60#include <llvm/Support/TargetSelect.h>
61#include <llvm/Support/ToolOutputFile.h>
62#include <llvm/Support/raw_ostream.h>
Shih-wei Liaod7726e42012-04-20 15:23:36 -070063#include <llvm/Support/system_error.h>
Logan Chien8b977d32012-02-21 19:14:55 +080064#include <llvm/Target/TargetData.h>
65#include <llvm/Target/TargetLibraryInfo.h>
66#include <llvm/Target/TargetMachine.h>
Shih-wei Liaof1cb9a52012-04-20 01:49:18 -070067#include <llvm/Transforms/IPO.h>
Logan Chien8b977d32012-02-21 19:14:55 +080068#include <llvm/Transforms/IPO/PassManagerBuilder.h>
TDYa127f15b0ab2012-05-11 21:01:36 -070069#include <llvm/Transforms/Scalar.h>
Logan Chien8b977d32012-02-21 19:14:55 +080070
Shih-wei Liaod7726e42012-04-20 15:23:36 -070071#include <sys/types.h>
72#include <sys/wait.h>
73#include <unistd.h>
74
Logan Chien8b977d32012-02-21 19:14:55 +080075#include <string>
76
Logan Chien110bcba2012-04-16 19:11:28 +080077namespace {
78
79class UpdateFrameSizePass : public llvm::MachineFunctionPass {
80 public:
81 static char ID;
82
83 UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) {
84 LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass";
85 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
86 // this constructor won't work because we have no information on
87 // CompilationUnit. Thus, we should place a LOG(FATAL) here.
88 }
89
90 UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit)
91 : llvm::MachineFunctionPass(ID), cunit_(cunit) {
92 }
93
94 virtual bool runOnMachineFunction(llvm::MachineFunction &MF) {
95 cunit_->UpdateFrameSizeInBytes(MF.getFunction(),
96 MF.getFrameInfo()->getStackSize());
97 return false;
98 }
99
100 private:
101 art::compiler_llvm::CompilationUnit* cunit_;
102};
103
104char UpdateFrameSizePass::ID = 0;
105
106llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
107 "update-frame-size", "Update frame size pass", false, false);
108
TDYa127f15b0ab2012-05-11 21:01:36 -0700109
110// TODO: We may need something to manage these passes.
111// TODO: We need high-level IR to analysis and do this at the IRBuilder level.
112class AddSuspendCheckToLoopLatchPass : public llvm::LoopPass {
113 public:
114 static char ID;
115
116 AddSuspendCheckToLoopLatchPass() : llvm::LoopPass(ID), irb_(NULL) {
117 LOG(FATAL) << "Unexpected instantiation of AddSuspendCheckToLoopLatchPass";
118 // NOTE: We have to declare this constructor for llvm::RegisterPass, but
119 // this constructor won't work because we have no information on
120 // IRBuilder. Thus, we should place a LOG(FATAL) here.
121 }
122
123 AddSuspendCheckToLoopLatchPass(art::compiler_llvm::IRBuilder* irb)
124 : llvm::LoopPass(ID), irb_(irb) {
125 }
126
127 virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const {
128 AU.addRequiredID(llvm::LoopSimplifyID);
129
130 AU.addPreserved<llvm::DominatorTree>();
131 AU.addPreserved<llvm::LoopInfo>();
132 AU.addPreservedID(llvm::LoopSimplifyID);
133 AU.addPreserved<llvm::ScalarEvolution>();
134 AU.addPreservedID(llvm::BreakCriticalEdgesID);
135 }
136
137 virtual bool runOnLoop(llvm::Loop *loop, llvm::LPPassManager &lpm) {
138 CHECK_EQ(loop->getNumBackEdges(), 1U) << "Loop must be simplified!";
139 llvm::BasicBlock* bb = loop->getLoopLatch();
140 CHECK_NE(bb, static_cast<void*>(NULL)) << "A single loop latch must exist.";
141
142 irb_->SetInsertPoint(bb->getTerminator());
143
144 using namespace art::compiler_llvm::runtime_support;
145 llvm::Value* runtime_func = irb_->GetRuntime(TestSuspend);
146 llvm::Value* thread_object_addr = irb_->CreateCall(irb_->GetRuntime(GetCurrentThread));
147 irb_->CreateCall(runtime_func, thread_object_addr);
148
149 return true;
150 }
151
152 private:
153 art::compiler_llvm::IRBuilder* irb_;
154};
155
156char AddSuspendCheckToLoopLatchPass::ID = 0;
157
158llvm::RegisterPass<AddSuspendCheckToLoopLatchPass> reg_add_suspend_check_to_loop_latch_pass_(
159 "add-suspend-check-to-loop-latch", "Add suspend check to loop latch pass", false, false);
160
161
Logan Chien110bcba2012-04-16 19:11:28 +0800162} // end anonymous namespace
163
Logan Chien8b977d32012-02-21 19:14:55 +0800164namespace art {
165namespace compiler_llvm {
166
167llvm::Module* makeLLVMModuleContents(llvm::Module* module);
168
169
Logan Chien6546ec52012-03-17 20:08:29 +0800170CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx)
Logan Chien8ba2fc52012-04-23 09:10:46 +0800171: cunit_lock_("compilation_unit_lock"), insn_set_(insn_set), elf_idx_(elf_idx),
172 context_(new llvm::LLVMContext()), mem_usage_(0), num_elf_funcs_(0) {
Logan Chien8b977d32012-02-21 19:14:55 +0800173
174 // Create the module and include the runtime function declaration
175 module_ = new llvm::Module("art", *context_);
176 makeLLVMModuleContents(module_);
177
178 // Create IRBuilder
179 irb_.reset(new IRBuilder(*context_, *module_));
TDYa127d668a062012-04-13 12:36:57 -0700180
181 // We always need a switch case, so just use a normal function.
182 switch(insn_set_) {
183 default:
184 runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
185 break;
186 case kArm:
187 case kThumb2:
188 runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
189 break;
190 case kX86:
191 runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
192 break;
193 }
194
195 runtime_support_->OptimizeRuntimeSupport();
196
197 irb_->SetRuntimeSupport(runtime_support_.get());
Logan Chien8b977d32012-02-21 19:14:55 +0800198}
199
200
201CompilationUnit::~CompilationUnit() {
202}
203
204
Logan Chien08e1ba32012-05-08 15:08:51 +0800205bool CompilationUnit::Materialize(size_t thread_count) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800206 MutexLock GUARD(cunit_lock_);
207
Logan Chien08e1ba32012-05-08 15:08:51 +0800208 if (thread_count == 1) {
209 llvm::raw_string_ostream str_os(elf_image_);
Logan Chienb1bab1c2012-05-11 11:05:45 +0800210 bool success = MaterializeToFile(str_os);
TDYa127a22ea032012-05-09 12:20:01 -0700211 LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)");
TDYa127388a83b2012-05-09 18:56:22 -0700212
213 // Free the resources
214 context_.reset(NULL);
215 irb_.reset(NULL);
216 module_ = NULL;
217
TDYa127a22ea032012-05-09 12:20:01 -0700218 return success;
Logan Chien08e1ba32012-05-08 15:08:51 +0800219 }
220
Logan Chien799ef4f2012-04-23 00:17:47 +0800221 // Prepare the pipe between parent process and child process
222 int pipe_fd[2];
223 if (pipe(pipe_fd) == -1) {
Shih-wei Liaoe8ecce72012-04-23 15:00:32 -0700224 PLOG(FATAL) << "Failed to create pipe for CompilerWorker";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700225 return false;
226 }
Shih-wei Liao17765722012-04-17 16:42:19 -0700227
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700228 // Fork a process to do the compilation
229 pid_t pid = fork();
Logan Chien799ef4f2012-04-23 00:17:47 +0800230 if (pid < 0) {
231 close(pipe_fd[0]);
232 close(pipe_fd[1]);
233 PLOG(FATAL) << "Failed to fork a process to do the compilation";
234 return false;
235
236 } else if (pid == 0) { // Child process
237 // Close the unused pipe read end
238 close(pipe_fd[0]);
239
240 // Change process groups, so we don't get ripped by ProcessManager
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700241 setpgid(0, 0);
Logan Chienb9eaeea2012-03-17 19:45:01 +0800242
Logan Chien08e1ba32012-05-08 15:08:51 +0800243 llvm::raw_fd_ostream fd_os(pipe_fd[1], /* shouldClose */true);
244
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700245 // TODO: Should use exec* family instead of invoking a function.
246 // Forward our compilation request to bcc.
Logan Chienb1bab1c2012-05-11 11:05:45 +0800247 exit(static_cast<int>(!MaterializeToFile(fd_os)));
Logan Chien799ef4f2012-04-23 00:17:47 +0800248
249 } else { // Parent process
250 // Close the unused pipe write end
251 close(pipe_fd[1]);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700252
253 // Free the resources
254 context_.reset(NULL);
255 irb_.reset(NULL);
256 module_ = NULL;
257
Logan Chien799ef4f2012-04-23 00:17:47 +0800258 // Read the result out from the pipe read end (until failure)
259 const size_t buf_size = 1024;
260 std::vector<uint8_t> buf(buf_size);
261 while (true) {
262 // Read from the pipe
263 ssize_t nread = read(pipe_fd[0], &*buf.begin(), buf_size);
264 if (nread < 0) {
265 if (errno == EAGAIN || errno == EINTR) {
266 continue;
267 } else {
268 LOG(ERROR) << "Unexpected error during IPC: " << strerror(errno);
269 }
270 }
271
272 // Append to the end of the elf_image_
Logan Chien08e1ba32012-05-08 15:08:51 +0800273 elf_image_.append(buf.begin(), buf.begin() + nread);
Logan Chien799ef4f2012-04-23 00:17:47 +0800274
275 if (nread < static_cast<ssize_t>(buf_size)) { // EOF reached!
276 break;
277 }
278 }
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700279
Shih-wei Liaoe8ecce72012-04-23 15:00:32 -0700280 close(pipe_fd[0]);
281
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700282 // Wait for child to finish
Logan Chien799ef4f2012-04-23 00:17:47 +0800283 int status;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700284 pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
285 if (got_pid != pid) {
286 PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
Logan Chien799ef4f2012-04-23 00:17:47 +0800287 elf_image_.clear();
Logan Chienb9eaeea2012-03-17 19:45:01 +0800288 return false;
289 }
290
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700291 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
292 LOG(ERROR) << "Failed to compile the bitcode: " << WEXITSTATUS(status);
Logan Chien799ef4f2012-04-23 00:17:47 +0800293 elf_image_.clear();
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700294 return false;
Shih-wei Liao17765722012-04-17 16:42:19 -0700295 }
Logan Chien799ef4f2012-04-23 00:17:47 +0800296
297 LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
298 return true;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700299 }
Logan Chien8b977d32012-02-21 19:14:55 +0800300}
301
302
Logan Chien110bcba2012-04-16 19:11:28 +0800303void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
304 CompiledMethod* compiled_method) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800305 MutexLock GUARD(cunit_lock_);
Logan Chien110bcba2012-04-16 19:11:28 +0800306 compiled_methods_map_.Put(func, compiled_method);
307}
308
309
310void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
311 size_t frame_size_in_bytes) {
Logan Chien8ba2fc52012-04-23 09:10:46 +0800312 MutexLock GUARD(cunit_lock_);
Logan Chien110bcba2012-04-16 19:11:28 +0800313 SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
314 compiled_methods_map_.find(func);
315
316 if (iter != compiled_methods_map_.end()) {
317 CompiledMethod* compiled_method = iter->second;
318 compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
319
320 if (frame_size_in_bytes > 1728u) {
321 LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
322 << " elf_idx=" << compiled_method->GetElfIndex()
323 << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
324 }
325 }
326}
327
Logan Chienb1bab1c2012-05-11 11:05:45 +0800328bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) {
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700329 // Lookup the LLVM target
330 char const* target_triple = NULL;
331 char const* target_attr = NULL;
332
Logan Chienb1bab1c2012-05-11 11:05:45 +0800333 switch (insn_set_) {
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700334 case kThumb2:
335 target_triple = "thumb-none-linux-gnueabi";
336 target_attr = "+thumb2,+neon,+neonfp,+vfp3";
337 break;
338
339 case kArm:
340 target_triple = "armv7-none-linux-gnueabi";
341 // TODO: Fix for Xoom.
342 target_attr = "+v7,+neon,+neonfp,+vfp3";
343 break;
344
345 case kX86:
346 target_triple = "i386-pc-linux-gnu";
347 target_attr = "";
348 break;
349
350 case kMips:
351 target_triple = "mipsel-unknown-linux";
352 target_attr = "mips32r2";
353 break;
354
355 default:
Logan Chienb1bab1c2012-05-11 11:05:45 +0800356 LOG(FATAL) << "Unknown instruction set: " << insn_set_;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700357 }
358
359 std::string errmsg;
360 llvm::Target const* target =
361 llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
362
363 CHECK(target != NULL) << errmsg;
364
365 // Target options
366 llvm::TargetOptions target_options;
367 target_options.FloatABIType = llvm::FloatABI::Soft;
368 target_options.NoFramePointerElim = true;
369 target_options.NoFramePointerElimNonLeaf = true;
370 target_options.UseSoftFloat = false;
371 target_options.EnableFastISel = true;
372
373 // Create the llvm::TargetMachine
Logan Chienb6bed0b2012-05-04 15:03:56 +0800374 llvm::OwningPtr<llvm::TargetMachine> target_machine(
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700375 target->createTargetMachine(target_triple, "", target_attr, target_options,
376 llvm::Reloc::Static, llvm::CodeModel::Small,
TDYa127e4c2ccc2012-05-13 21:10:36 -0700377 llvm::CodeGenOpt::Less));
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700378
Logan Chienb6bed0b2012-05-04 15:03:56 +0800379 CHECK(target_machine.get() != NULL) << "Failed to create target machine";
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700380
381 // Add target data
382 llvm::TargetData const* target_data = target_machine->getTargetData();
383
384 // PassManager for code generation passes
385 llvm::PassManager pm;
386 pm.add(new llvm::TargetData(*target_data));
387
388 // FunctionPassManager for optimization pass
Logan Chien799ef4f2012-04-23 00:17:47 +0800389 llvm::FunctionPassManager fpm(module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700390 fpm.add(new llvm::TargetData(*target_data));
391
TDYa127f15b0ab2012-05-11 21:01:36 -0700392 if (bitcode_filename_.empty()) {
393 // If we don't need write the bitcode to file, add the AddSuspendCheckToLoopLatchPass to the
394 // regular FunctionPass.
395 fpm.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
396 } else {
397 // Run AddSuspendCheckToLoopLatchPass before we write the bitcode to file.
398 llvm::FunctionPassManager fpm2(module_);
399 fpm2.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
400 fpm2.doInitialization();
401 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
402 F != E; ++F) {
403 fpm2.run(*F);
404 }
405 fpm2.doFinalization();
406
407
408 // Write bitcode to file
409 std::string errmsg;
410
411 llvm::OwningPtr<llvm::tool_output_file> out_file(
412 new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
413 llvm::raw_fd_ostream::F_Binary));
414
415
416 if (!errmsg.empty()) {
417 LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
418 return false;
419 }
420
421 llvm::WriteBitcodeToFile(module_, out_file->os());
422 out_file->keep();
423 }
424
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700425 // Add optimization pass
426 llvm::PassManagerBuilder pm_builder;
Shih-wei Liaoe0e40242012-05-08 01:04:03 -0700427 //pm_builder.Inliner = llvm::createFunctionInliningPass();
428 pm_builder.Inliner = llvm::createAlwaysInlinerPass();
Shih-wei Liao415576b2012-04-23 15:28:53 -0700429 //pm_builder.Inliner = llvm::createPartialInliningPass();
430 pm_builder.OptLevel = 3;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700431 pm_builder.DisableSimplifyLibCalls = 1;
TDYa127e4c2ccc2012-05-13 21:10:36 -0700432 pm_builder.DisableUnitAtATime = 1;
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700433 pm_builder.populateModulePassManager(pm);
434 pm_builder.populateFunctionPassManager(fpm);
435
436 // Add passes to emit ELF image
437 {
Logan Chien08e1ba32012-05-08 15:08:51 +0800438 llvm::formatted_raw_ostream formatted_os(out_stream, false);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700439
440 // Ask the target to add backend passes as necessary.
441 if (target_machine->addPassesToEmitFile(pm,
442 formatted_os,
443 llvm::TargetMachine::CGFT_ObjectFile,
444 true)) {
445 LOG(FATAL) << "Unable to generate ELF for this target";
446 return false;
447 }
448
449 // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to
450 // update the value reside in the different address space.
451 // Add pass to update the frame_size_in_bytes_
452 //pm.add(new ::UpdateFrameSizePass(this));
453
454 // Run the per-function optimization
455 fpm.doInitialization();
Logan Chien799ef4f2012-04-23 00:17:47 +0800456 for (llvm::Module::iterator F = module_->begin(), E = module_->end();
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700457 F != E; ++F) {
458 fpm.run(*F);
459 }
460 fpm.doFinalization();
461
462 // Run the code generation passes
Logan Chien799ef4f2012-04-23 00:17:47 +0800463 pm.run(*module_);
Shih-wei Liaod7726e42012-04-20 15:23:36 -0700464 }
465
466 return true;
467}
Logan Chien110bcba2012-04-16 19:11:28 +0800468
Logan Chien8b977d32012-02-21 19:14:55 +0800469} // namespace compiler_llvm
470} // namespace art