blob: 77c1bf5aa183347595c5c437bdb60312d012d1f8 [file] [log] [blame]
Shih-wei Liao21d28f52012-06-12 05:55:00 -07001/*
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 "ir_builder.h"
18#include "utils_llvm.h"
19
20#include "greenland/intrinsic_helper.h"
21#include "object.h"
22#include "thread.h"
23
24#include <llvm/ADT/STLExtras.h>
25#include <llvm/Intrinsics.h>
26#include <llvm/Pass.h>
27#include <llvm/Support/CFG.h>
28#include <llvm/Support/InstIterator.h>
29
30#include <vector>
31
32using namespace art;
33using namespace compiler_llvm;
34
35using art::greenland::IntrinsicHelper;
36
37namespace {
38
39class GBCExpanderPass : public llvm::FunctionPass {
40 private:
41 const IntrinsicHelper& intrinsic_helper_;
42 IRBuilder& irb_;
43
44 llvm::LLVMContext& context_;
45 RuntimeSupportBuilder& rtb_;
46
47 private:
48 llvm::AllocaInst* shadow_frame_;
49 llvm::Value* old_shadow_frame_;
50 uint32_t shadow_frame_size_;
51
52 private:
53 //----------------------------------------------------------------------------
54 // Helper function for GBC expansion
55 //----------------------------------------------------------------------------
56
57 // Split the basic block containing INST at INST and insert a sequence of
58 // basic blocks with a single entry at BEGIN_BB and a single exit at END_BB
59 // before INST.
60 llvm::BasicBlock*
61 SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
62 llvm::BasicBlock* begin_bb,
63 llvm::BasicBlock* end_bb);
64
65 llvm::Value* ExpandToRuntime(runtime_support::RuntimeId rt,
66 llvm::CallInst& inst);
67
68 private:
69 // TODO: Almost all Emit* are directly copy-n-paste from MethodCompiler.
70 // Refactor these utility functions from MethodCompiler to avoid forking.
71
72 bool EmitStackOverflowCheck(llvm::Instruction* first_non_alloca);
73
74 //----------------------------------------------------------------------------
75 // Dex cache code generation helper function
76 //----------------------------------------------------------------------------
77 llvm::Value* EmitLoadDexCacheAddr(MemberOffset dex_cache_offset);
78
79 llvm::Value* EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx);
80
81 llvm::Value* EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx);
82
83 llvm::Value* EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx);
84
85 llvm::Value* EmitLoadDexCacheStringFieldAddr(uint32_t string_idx);
86
87 //----------------------------------------------------------------------------
88 // Code generation helper function
89 //----------------------------------------------------------------------------
90 llvm::Value* EmitLoadMethodObjectAddr();
91
92 llvm::Value* EmitLoadArrayLength(llvm::Value* array);
93
94 llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
95
96 llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
97 llvm::Value* this_addr);
98
99 llvm::Value* EmitArrayGEP(llvm::Value* array_addr,
100 llvm::Value* index_value,
101 JType elem_jty);
102
103 private:
104 //----------------------------------------------------------------------------
105 // Expand Greenland intrinsics
106 //----------------------------------------------------------------------------
107 void Expand_TestSuspend(llvm::CallInst& call_inst);
108
109 llvm::Value* Expand_GetException();
110
111 llvm::Value* Expand_LoadStringFromDexCache(llvm::Value* string_idx_value);
112
113 llvm::Value* Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value);
114
115 void Expand_LockObject(llvm::Value* obj);
116
117 void Expand_UnlockObject(llvm::Value* obj);
118
119 llvm::Value* Expand_ArrayGet(llvm::Value* array_addr,
120 llvm::Value* index_value,
121 JType elem_jty);
122
123 void Expand_ArrayPut(llvm::Value* new_value,
124 llvm::Value* array_addr,
125 llvm::Value* index_value,
126 JType elem_jty);
127
128 void Expand_FilledNewArray(llvm::CallInst& call_inst);
129
130 llvm::Value* Expand_IGetFast(llvm::Value* field_offset_value,
131 llvm::Value* is_volatile_value,
132 llvm::Value* object_addr,
133 JType field_jty);
134
135 void Expand_IPutFast(llvm::Value* field_offset_value,
136 llvm::Value* is_volatile_value,
137 llvm::Value* object_addr,
138 llvm::Value* new_value,
139 JType field_jty);
140
141 llvm::Value* Expand_SGetFast(llvm::Value* static_storage_addr,
142 llvm::Value* field_offset_value,
143 llvm::Value* is_volatile_value,
144 JType field_jty);
145
146 void Expand_SPutFast(llvm::Value* static_storage_addr,
147 llvm::Value* field_offset_value,
148 llvm::Value* is_volatile_value,
149 llvm::Value* new_value,
150 JType field_jty);
151
152 llvm::Value* Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr);
153
154 llvm::Value* Expand_LoadClassSSBFromDexCache(llvm::Value* type_idx_value);
155
156 llvm::Value*
157 Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value);
158
159 llvm::Value*
160 Expand_GetVirtualCalleeMethodObjAddrFast(llvm::Value* vtable_idx_value,
161 llvm::Value* this_addr);
162
163 llvm::Value* Expand_Invoke(llvm::CallInst& call_inst);
164
165 llvm::Value* Expand_DivRem(llvm::Value* dividend, llvm::Value* divisor,
166 bool is_div, JType op_jty);
167
168 void Expand_AllocaShadowFrame(llvm::Value* num_entry_value);
169
170 void Expand_SetShadowFrameEntry(llvm::Value* obj, llvm::Value* entry_idx);
171
172 void Expand_PopShadowFrame();
173
174 void Expand_UpdateDexPC(llvm::Value* dex_pc_value);
175
176 public:
177 static char ID;
178
179 GBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb)
180 : llvm::FunctionPass(ID), intrinsic_helper_(intrinsic_helper), irb_(irb),
181 context_(irb.getContext()), rtb_(irb.Runtime())
182 { }
183
184 bool runOnFunction(llvm::Function& func);
185
186 private:
187 bool InsertStackOverflowCheck(llvm::Function& func);
188
189 llvm::Value* ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id,
190 llvm::CallInst& call_inst);
191
192};
193
194char GBCExpanderPass::ID = 0;
195
196bool GBCExpanderPass::runOnFunction(llvm::Function& func) {
TDYa127b672d1e2012-06-28 21:21:45 -0700197 // Runtime support or stub
198 if (func.getName().startswith("art_") || func.getName().startswith("Art")) {
199 return false;
200 }
Shih-wei Liao21d28f52012-06-12 05:55:00 -0700201 bool changed;
202
TDYa127b672d1e2012-06-28 21:21:45 -0700203 // TODO: Use intrinsic.
Shih-wei Liao21d28f52012-06-12 05:55:00 -0700204 changed = InsertStackOverflowCheck(func);
205
206 std::list<std::pair<llvm::CallInst*,
207 IntrinsicHelper::IntrinsicId> > work_list;
208
209 for (llvm::inst_iterator inst_iter = llvm::inst_begin(func),
210 inst_end = llvm::inst_end(func); inst_iter != inst_end; inst_iter++) {
211 // Only CallInst with its called function is dexlang intrinsic need to
212 // process
213 llvm::Instruction* inst = &*inst_iter;
214 if (llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(inst)) {
215 const llvm::Function* callee = call_inst->getCalledFunction();
216
217 if (callee != NULL) {
218 IntrinsicHelper::IntrinsicId intr_id =
219 intrinsic_helper_.GetIntrinsicId(callee);
220
221 if (intr_id != IntrinsicHelper::UnknownId) {
222 work_list.push_back(std::make_pair(call_inst, intr_id));
223 }
224 }
225 }
226 }
227
228 changed |= !work_list.empty();
229
230 shadow_frame_ = NULL;
231 old_shadow_frame_ = NULL;
232 shadow_frame_size_ = 0;
233
234 // Remove the instruction containing in the work_list
235 while (!work_list.empty()) {
236 llvm::CallInst* intr_inst = work_list.front().first;
237 IntrinsicHelper::IntrinsicId intr_id = work_list.front().second;
238
239 // Remove the instruction from work list
240 work_list.pop_front();
241
242 // Move the IRBuilder insert pointer
243 irb_.SetInsertPoint(intr_inst);
244
245 // Process the expansion
246 llvm::Value* new_value = ExpandIntrinsic(intr_id, *intr_inst);
247
248 // Use the new value from the expansion
249 if (new_value != NULL) {
250 intr_inst->replaceAllUsesWith(new_value);
251 }
252
253 // Remove the intrinsic instruction
254 intr_inst->eraseFromParent();
255 }
256
257 VERIFY_LLVM_FUNCTION(func);
258
259 return changed;
260}
261
262llvm::BasicBlock*
263GBCExpanderPass::SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
264 llvm::BasicBlock* begin_bb,
265 llvm::BasicBlock* end_bb) {
266 llvm::BasicBlock* original = inst->getParent();
267 llvm::Function* parent = original->getParent();
268
269 // 1. Create a new basic block A after ORIGINAL
270 llvm::BasicBlock *insert_before =
271 llvm::next(llvm::Function::iterator(original)).getNodePtrUnchecked();
272 llvm::BasicBlock* a =
273 llvm::BasicBlock::Create(context_, "", parent, insert_before);
274
275 // 2. Move all instructions in ORIGINAL after INST (included) to A
276 a->getInstList().splice(a->end(), original->getInstList(),
277 inst, original->end());
278
279 // 3. Add an unconditional branch in ORIGINAL to begin_bb
280 llvm::BranchInst::Create(begin_bb, original);
281
282 // 4. Add an unconditional branch in END_BB to A
283 llvm::BranchInst::Create(a, end_bb);
284
285 // 5. Update the PHI nodes in the successors of A. Update the PHI node entry
286 // with incoming basic block from ORIGINAL to A
287 for (llvm::succ_iterator succ_iter = llvm::succ_begin(a),
288 succ_end = llvm::succ_end(a); succ_iter != succ_end; succ_iter++) {
289 llvm::BasicBlock* succ = *succ_iter;
290 llvm::PHINode* phi;
291 for (llvm::BasicBlock::iterator inst_iter = succ->begin();
292 (phi = llvm::dyn_cast<llvm::PHINode>(inst_iter)); ++inst_iter) {
293 int idx;
294 while ((idx = phi->getBasicBlockIndex(original)) != -1) {
295 phi->setIncomingBlock(static_cast<unsigned>(idx), a);
296 }
297 }
298 }
299
300 return a;
301}
302
303llvm::Value* GBCExpanderPass::ExpandToRuntime(runtime_support::RuntimeId rt,
304 llvm::CallInst& inst) {
305 // Some GBC intrinsic can directly replace with IBC runtime. "Directly" means
306 // the arguments passed to the GBC intrinsic are as the same as IBC runtime
307 // function, therefore only called function is needed to change.
308 unsigned num_args = inst.getNumArgOperands();
309
310 if (num_args <= 0) {
311 return irb_.CreateCall(irb_.GetRuntime(rt));
312 } else {
313 std::vector<llvm::Value*> args;
314 for (unsigned i = 0; i < num_args; i++) {
315 args.push_back(inst.getArgOperand(i));
316 }
317
318 return irb_.CreateCall(irb_.GetRuntime(rt), args);
319 }
320}
321
322bool
323GBCExpanderPass::EmitStackOverflowCheck(llvm::Instruction* first_non_alloca) {
324 llvm::Function* func = first_non_alloca->getParent()->getParent();
325 llvm::Module* module = func->getParent();
326
327 llvm::BasicBlock* block_entry =
328 llvm::BasicBlock::Create(context_, "stack_overflow_entry", func);
329
330 irb_.SetInsertPoint(block_entry);
331
332 // Call llvm intrinsic function to get frame address.
333 llvm::Function* frameaddress =
334 llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::frameaddress);
335
336 // The type of llvm::frameaddress is: i8* @llvm.frameaddress(i32)
337 llvm::Value* frame_address = irb_.CreateCall(frameaddress, irb_.getInt32(0));
338
339 // Cast i8* to int
340 frame_address = irb_.CreatePtrToInt(frame_address, irb_.getPtrEquivIntTy());
341
342 // Get thread.stack_end_
343 llvm::Value* stack_end =
344 irb_.Runtime().EmitLoadFromThreadOffset(Thread::StackEndOffset().Int32Value(),
345 irb_.getPtrEquivIntTy(),
346 kTBAARuntimeInfo);
347
348 // Check the frame address < thread.stack_end_ ?
349 llvm::Value* is_stack_overflow = irb_.CreateICmpULT(frame_address, stack_end);
350
351 llvm::BasicBlock* block_exception =
352 llvm::BasicBlock::Create(context_, "stack_overflow", func);
353
354 llvm::BasicBlock* block_continue =
355 llvm::BasicBlock::Create(context_, "stack_overflow_cont", func);
356
357 irb_.CreateCondBr(is_stack_overflow, block_exception, block_continue, kUnlikely);
358
359 // If stack overflow, throw exception.
360 irb_.SetInsertPoint(block_exception);
361 irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowStackOverflowException));
362
363 // Unwind.
364 llvm::Type* ret_type = func->getReturnType();
365 if (ret_type->isVoidTy()) {
366 irb_.CreateRetVoid();
367 } else {
368 // The return value is ignored when there's an exception. MethodCompiler
369 // returns zero value under the the corresponding return type in this case.
370 // GBCExpander returns LLVM undef value here for brevity
371 irb_.CreateRet(llvm::UndefValue::get(ret_type));
372 }
373
374 irb_.SetInsertPoint(block_continue);
375
376 SplitAndInsertBasicBlocksAfter(*first_non_alloca, block_entry, block_continue);
377
378 return true;
379}
380
381llvm::Value* GBCExpanderPass::EmitLoadDexCacheAddr(MemberOffset offset) {
382 llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
383
384 return irb_.LoadFromObjectOffset(method_object_addr,
385 offset.Int32Value(),
386 irb_.getJObjectTy(),
387 kTBAAConstJObject);
388}
389
390llvm::Value*
391GBCExpanderPass::EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx) {
392 llvm::Value* static_storage_dex_cache_addr =
393 EmitLoadDexCacheAddr(Method::DexCacheInitializedStaticStorageOffset());
394
395 llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx);
396
397 return EmitArrayGEP(static_storage_dex_cache_addr, type_idx_value, kObject);
398}
399
400llvm::Value*
401GBCExpanderPass::EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx) {
402 llvm::Value* resolved_type_dex_cache_addr =
403 EmitLoadDexCacheAddr(Method::DexCacheResolvedTypesOffset());
404
405 llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx);
406
407 return EmitArrayGEP(resolved_type_dex_cache_addr, type_idx_value, kObject);
408}
409
410llvm::Value* GBCExpanderPass::
411EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx) {
412 llvm::Value* resolved_method_dex_cache_addr =
413 EmitLoadDexCacheAddr(Method::DexCacheResolvedMethodsOffset());
414
415 llvm::Value* method_idx_value = irb_.getPtrEquivInt(method_idx);
416
417 return EmitArrayGEP(resolved_method_dex_cache_addr, method_idx_value, kObject);
418}
419
420llvm::Value* GBCExpanderPass::
421EmitLoadDexCacheStringFieldAddr(uint32_t string_idx) {
422 llvm::Value* string_dex_cache_addr =
423 EmitLoadDexCacheAddr(Method::DexCacheStringsOffset());
424
425 llvm::Value* string_idx_value = irb_.getPtrEquivInt(string_idx);
426
427 return EmitArrayGEP(string_dex_cache_addr, string_idx_value, kObject);
428}
429
430llvm::Value* GBCExpanderPass::EmitLoadMethodObjectAddr() {
431 llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
432 return parent_func->arg_begin();
433}
434
435llvm::Value* GBCExpanderPass::EmitLoadArrayLength(llvm::Value* array) {
436 // Load array length
437 return irb_.LoadFromObjectOffset(array,
438 Array::LengthOffset().Int32Value(),
439 irb_.getJIntTy(),
440 kTBAAConstJObject);
441
442}
443
444llvm::Value*
445GBCExpanderPass::EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) {
446 llvm::Value* callee_method_object_field_addr =
447 EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
448
449 return irb_.CreateLoad(callee_method_object_field_addr, kTBAAJRuntime);
450}
451
452llvm::Value* GBCExpanderPass::
453EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx, llvm::Value* this_addr) {
454 // Load class object of *this* pointer
455 llvm::Value* class_object_addr =
456 irb_.LoadFromObjectOffset(this_addr,
457 Object::ClassOffset().Int32Value(),
458 irb_.getJObjectTy(),
459 kTBAAConstJObject);
460
461 // Load vtable address
462 llvm::Value* vtable_addr =
463 irb_.LoadFromObjectOffset(class_object_addr,
464 Class::VTableOffset().Int32Value(),
465 irb_.getJObjectTy(),
466 kTBAAConstJObject);
467
468 // Load callee method object
469 llvm::Value* vtable_idx_value =
470 irb_.getPtrEquivInt(static_cast<uint64_t>(vtable_idx));
471
472 llvm::Value* method_field_addr =
473 EmitArrayGEP(vtable_addr, vtable_idx_value, kObject);
474
475 return irb_.CreateLoad(method_field_addr, kTBAAConstJObject);
476}
477
478// Emit Array GetElementPtr
479llvm::Value* GBCExpanderPass::EmitArrayGEP(llvm::Value* array_addr,
480 llvm::Value* index_value,
481 JType elem_jty) {
482
483 int data_offset;
484 if (elem_jty == kLong || elem_jty == kDouble ||
485 (elem_jty == kObject && sizeof(uint64_t) == sizeof(Object*))) {
486 data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value();
487 } else {
488 data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value();
489 }
490
491 llvm::Constant* data_offset_value =
492 irb_.getPtrEquivInt(data_offset);
493
494 llvm::Type* elem_type = irb_.getJType(elem_jty, kArray);
495
496 llvm::Value* array_data_addr =
497 irb_.CreatePtrDisp(array_addr, data_offset_value,
498 elem_type->getPointerTo());
499
500 return irb_.CreateGEP(array_data_addr, index_value);
501}
502
503void GBCExpanderPass::Expand_TestSuspend(llvm::CallInst& call_inst) {
504 llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
505 llvm::BasicBlock* suspend_test_begin_bb =
506 llvm::BasicBlock::Create(context_, "suspend_test", parent_func);
507
508 irb_.SetInsertPoint(suspend_test_begin_bb);
509 irb_.Runtime().EmitTestSuspend();
510
511 llvm::BasicBlock* suspend_test_end_bb = irb_.GetInsertBlock();
512
513 SplitAndInsertBasicBlocksAfter(call_inst, suspend_test_begin_bb,
514 suspend_test_end_bb);
515 return;
516}
517
518llvm::Value* GBCExpanderPass::Expand_GetException() {
519 // Get thread-local exception field address
520 llvm::Value* exception_object_addr =
521 irb_.Runtime().EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
522 irb_.getJObjectTy(),
523 kTBAAJRuntime);
524
525 // Set thread-local exception field address to NULL
526 irb_.Runtime().EmitStoreToThreadOffset(Thread::ExceptionOffset().Int32Value(),
527 irb_.getJNull(),
528 kTBAAJRuntime);
529
530 return exception_object_addr;
531}
532
533llvm::Value*
534GBCExpanderPass::Expand_LoadStringFromDexCache(llvm::Value* string_idx_value) {
535 uint32_t string_idx =
536 llvm::cast<llvm::ConstantInt>(string_idx_value)->getZExtValue();
537
538 llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx);
539
540 return irb_.CreateLoad(string_field_addr, kTBAAJRuntime);
541}
542
543llvm::Value*
544GBCExpanderPass::Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value) {
545 uint32_t type_idx =
546 llvm::cast<llvm::ConstantInt>(type_idx_value)->getZExtValue();
547
548 llvm::Value* type_field_addr =
549 EmitLoadDexCacheResolvedTypeFieldAddr(type_idx);
550
551 return irb_.CreateLoad(type_field_addr, kTBAAJRuntime);
552}
553
554void GBCExpanderPass::Expand_LockObject(llvm::Value* obj) {
555 llvm::BasicBlock::iterator lock_obj_inst = irb_.GetInsertPoint();
556 llvm::Function* parent = irb_.GetInsertBlock()->getParent();
557
558 llvm::BasicBlock* lock_obj_begin_bb =
559 llvm::BasicBlock::Create(context_, "", parent);
560
561 irb_.SetInsertPoint(lock_obj_begin_bb);
562 rtb_.EmitLockObject(obj);
563
564 llvm::BasicBlock* lock_obj_end_bb = irb_.GetInsertBlock();
565
566 SplitAndInsertBasicBlocksAfter(lock_obj_inst, lock_obj_begin_bb,
567 lock_obj_end_bb);
568
569 return;
570}
571
572void GBCExpanderPass::Expand_UnlockObject(llvm::Value* obj) {
573 llvm::BasicBlock::iterator unlock_obj_inst = irb_.GetInsertPoint();
574 llvm::Function* parent = irb_.GetInsertBlock()->getParent();
575
576 llvm::BasicBlock* unlock_obj_begin_bb =
577 llvm::BasicBlock::Create(context_, "", parent);
578
579 irb_.SetInsertPoint(unlock_obj_begin_bb);
580 rtb_.EmitUnlockObject(obj);
581
582 llvm::BasicBlock* unlock_obj_end_bb = irb_.GetInsertBlock();
583
584 SplitAndInsertBasicBlocksAfter(unlock_obj_inst, unlock_obj_begin_bb,
585 unlock_obj_end_bb);
586
587 return;
588}
589
590llvm::Value* GBCExpanderPass::Expand_ArrayGet(llvm::Value* array_addr,
591 llvm::Value* index_value,
592 JType elem_jty) {
593 llvm::Value* array_elem_addr =
594 EmitArrayGEP(array_addr, index_value, elem_jty);
595
596 return irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, elem_jty);
597}
598
599void GBCExpanderPass::Expand_ArrayPut(llvm::Value* new_value,
600 llvm::Value* array_addr,
601 llvm::Value* index_value,
602 JType elem_jty) {
603 llvm::Value* array_elem_addr =
604 EmitArrayGEP(array_addr, index_value, elem_jty);
605
606 irb_.CreateStore(new_value, array_elem_addr, kTBAAHeapArray, elem_jty);
607
608 return;
609}
610
611void GBCExpanderPass::Expand_FilledNewArray(llvm::CallInst& call_inst) {
612 // Most of the codes refer to MethodCompiler::EmitInsn_FilledNewArray
613 llvm::Value* array = call_inst.getArgOperand(0);
614
615 uint32_t element_jty =
616 llvm::cast<llvm::ConstantInt>(call_inst.getArgOperand(1))->getZExtValue();
617
618 DCHECK(call_inst.getNumArgOperands() > 2);
619 unsigned num_elements = (call_inst.getNumArgOperands() - 2);
620
621 bool is_elem_int_ty = (static_cast<JType>(element_jty) == kInt);
622
623 uint32_t alignment;
624 llvm::Constant* elem_size;
625 llvm::PointerType* field_type;
626
627 // NOTE: Currently filled-new-array only supports 'L', '[', and 'I'
628 // as the element, thus we are only checking 2 cases: primitive int and
629 // non-primitive type.
630 if (is_elem_int_ty) {
631 alignment = sizeof(int32_t);
632 elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
633 field_type = irb_.getJIntTy()->getPointerTo();
634 } else {
635 alignment = irb_.getSizeOfPtrEquivInt();
636 elem_size = irb_.getSizeOfPtrEquivIntValue();
637 field_type = irb_.getJObjectTy()->getPointerTo();
638 }
639
640 llvm::Value* data_field_offset =
641 irb_.getPtrEquivInt(Array::DataOffset(alignment).Int32Value());
642
643 llvm::Value* data_field_addr =
644 irb_.CreatePtrDisp(array, data_field_offset, field_type);
645
646 for (unsigned i = 0; i < num_elements; ++i) {
647 // Values to fill the array begin at the 3rd argument
648 llvm::Value* reg_value = call_inst.getArgOperand(2 + i);
649
650 irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray);
651
652 data_field_addr =
653 irb_.CreatePtrDisp(data_field_addr, elem_size, field_type);
654 }
655
656 return;
657}
658
659llvm::Value* GBCExpanderPass::Expand_IGetFast(llvm::Value* field_offset_value,
660 llvm::Value* /*is_volatile_value*/,
661 llvm::Value* object_addr,
662 JType field_jty) {
663 int field_offset =
664 llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
665
666 DCHECK_GE(field_offset, 0);
667
668 llvm::PointerType* field_type =
669 irb_.getJType(field_jty, kField)->getPointerTo();
670
671 field_offset_value = irb_.getPtrEquivInt(field_offset);
672
673 llvm::Value* field_addr =
674 irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
675
676 // TODO: Check is_volatile. We need to generate atomic load instruction
677 // when is_volatile is true.
678 return irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty);
679}
680
681void GBCExpanderPass::Expand_IPutFast(llvm::Value* field_offset_value,
682 llvm::Value* /* is_volatile_value */,
683 llvm::Value* object_addr,
684 llvm::Value* new_value,
685 JType field_jty) {
686 int field_offset =
687 llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
688
689 DCHECK_GE(field_offset, 0);
690
691 llvm::PointerType* field_type =
692 irb_.getJType(field_jty, kField)->getPointerTo();
693
694 field_offset_value = irb_.getPtrEquivInt(field_offset);
695
696 llvm::Value* field_addr =
697 irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
698
699 // TODO: Check is_volatile. We need to generate atomic store instruction
700 // when is_volatile is true.
701 irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty);
702
703 return;
704}
705
706llvm::Value* GBCExpanderPass::Expand_SGetFast(llvm::Value* static_storage_addr,
707 llvm::Value* field_offset_value,
708 llvm::Value* /*is_volatile_value*/,
709 JType field_jty) {
710 int field_offset =
711 llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
712
713 DCHECK_GE(field_offset, 0);
714
715 llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
716
717 llvm::Value* static_field_addr =
718 irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
719 irb_.getJType(field_jty, kField)->getPointerTo());
720
721 // TODO: Check is_volatile. We need to generate atomic store instruction
722 // when is_volatile is true.
723 return irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty);
724}
725
726void GBCExpanderPass::Expand_SPutFast(llvm::Value* static_storage_addr,
727 llvm::Value* field_offset_value,
728 llvm::Value* /* is_volatile_value */,
729 llvm::Value* new_value,
730 JType field_jty) {
731 int field_offset =
732 llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
733
734 DCHECK_GE(field_offset, 0);
735
736 llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
737
738 llvm::Value* static_field_addr =
739 irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
740 irb_.getJType(field_jty, kField)->getPointerTo());
741
742 // TODO: Check is_volatile. We need to generate atomic store instruction
743 // when is_volatile is true.
744 irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty);
745
746 return;
747}
748
749llvm::Value*
750GBCExpanderPass::Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr) {
751 return irb_.LoadFromObjectOffset(method_object_addr,
752 Method::DeclaringClassOffset().Int32Value(),
753 irb_.getJObjectTy(),
754 kTBAAConstJObject);
755}
756
757llvm::Value*
758GBCExpanderPass::Expand_LoadClassSSBFromDexCache(llvm::Value* type_idx_value) {
759 uint32_t type_idx =
760 llvm::cast<llvm::ConstantInt>(type_idx_value)->getZExtValue();
761
762 llvm::Value* storage_field_addr =
763 EmitLoadDexCacheStaticStorageFieldAddr(type_idx);
764
765 return irb_.CreateLoad(storage_field_addr, kTBAAJRuntime);
766}
767
768llvm::Value*
769GBCExpanderPass::Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value) {
770 uint32_t callee_method_idx =
771 llvm::cast<llvm::ConstantInt>(callee_method_idx_value)->getZExtValue();
772
773 return EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
774}
775
776llvm::Value* GBCExpanderPass::Expand_GetVirtualCalleeMethodObjAddrFast(
777 llvm::Value* vtable_idx_value,
778 llvm::Value* this_addr) {
779 int vtable_idx =
780 llvm::cast<llvm::ConstantInt>(vtable_idx_value)->getSExtValue();
781
782 return EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr);
783}
784
785llvm::Value* GBCExpanderPass::Expand_Invoke(llvm::CallInst& call_inst) {
786 // Most of the codes refer to MethodCompiler::EmitInsn_Invoke
787 llvm::Value* callee_method_object_addr = call_inst.getArgOperand(0);
788 unsigned num_args = call_inst.getNumArgOperands();
789 llvm::Type* ret_type = call_inst.getType();
790
791 // Determine the function type of the callee method
792 std::vector<llvm::Type*> args_type;
793 std::vector<llvm::Value*> args;
794 for (unsigned i = 0; i < num_args; i++) {
795 args.push_back(call_inst.getArgOperand(i));
796 args_type.push_back(args[i]->getType());
797 }
798
799 llvm::FunctionType* callee_method_type =
800 llvm::FunctionType::get(ret_type, args_type, false);
801
802 llvm::Value* code_addr =
803 irb_.LoadFromObjectOffset(callee_method_object_addr,
804 Method::GetCodeOffset().Int32Value(),
805 callee_method_type->getPointerTo(),
806 kTBAAJRuntime);
807
808 // Invoke callee
809 llvm::Value* retval = irb_.CreateCall(code_addr, args);
810
811 return retval;
812}
813
814llvm::Value* GBCExpanderPass::Expand_DivRem(llvm::Value* dividend,
815 llvm::Value* divisor,
816 bool is_div, JType op_jty) {
817 // Most of the codes refer to MethodCompiler::EmitIntDivRemResultComputation
818
819 // Check the special case: MININT / -1 = MININT
820 // That case will cause overflow, which is undefined behavior in llvm.
821 // So we check the divisor is -1 or not, if the divisor is -1, we do
822 // the special path to avoid undefined behavior.
823 llvm::Type* op_type = irb_.getJType(op_jty, kAccurate);
824 llvm::Value* zero = irb_.getJZero(op_jty);
825 llvm::Value* neg_one = llvm::ConstantInt::getSigned(op_type, -1);
826
827 llvm::BasicBlock::iterator div_rem_inst = irb_.GetInsertPoint();
828 llvm::Function* parent = irb_.GetInsertBlock()->getParent();
829
830 llvm::BasicBlock* begin_div_rem =
831 llvm::BasicBlock::Create(context_, "", parent);
832 llvm::BasicBlock* eq_neg_one = llvm::BasicBlock::Create(context_, "", parent);
833 llvm::BasicBlock* ne_neg_one = llvm::BasicBlock::Create(context_, "", parent);
834 llvm::BasicBlock* neg_one_cont =
835 llvm::BasicBlock::Create(context_, "", parent);
836
837 irb_.SetInsertPoint(begin_div_rem);
838 llvm::Value* is_equal_neg_one = irb_.CreateICmpEQ(divisor, neg_one);
839 irb_.CreateCondBr(is_equal_neg_one, eq_neg_one, ne_neg_one, kUnlikely);
840
841 // If divisor == -1
842 irb_.SetInsertPoint(eq_neg_one);
843 llvm::Value* eq_result;
844 if (is_div) {
845 // We can just change from "dividend div -1" to "neg dividend". The sub
846 // don't care the sign/unsigned because of two's complement representation.
847 // And the behavior is what we want:
848 // -(2^n) (2^n)-1
849 // MININT < k <= MAXINT -> mul k -1 = -k
850 // MININT == k -> mul k -1 = k
851 //
852 // LLVM use sub to represent 'neg'
853 eq_result = irb_.CreateSub(zero, dividend);
854 } else {
855 // Everything modulo -1 will be 0.
856 eq_result = zero;
857 }
858 irb_.CreateBr(neg_one_cont);
859
860 // If divisor != -1, just do the division.
861 irb_.SetInsertPoint(ne_neg_one);
862 llvm::Value* ne_result;
863 if (is_div) {
864 ne_result = irb_.CreateSDiv(dividend, divisor);
865 } else {
866 ne_result = irb_.CreateSRem(dividend, divisor);
867 }
868 irb_.CreateBr(neg_one_cont);
869
870 irb_.SetInsertPoint(neg_one_cont);
871 llvm::PHINode* result = irb_.CreatePHI(op_type, 2);
872 result->addIncoming(eq_result, eq_neg_one);
873 result->addIncoming(ne_result, ne_neg_one);
874
875 SplitAndInsertBasicBlocksAfter(div_rem_inst, begin_div_rem, neg_one_cont);
876
877 return result;
878}
879
880void GBCExpanderPass::Expand_AllocaShadowFrame(llvm::Value* num_entry_value) {
881 // Most of the codes refer to MethodCompiler::EmitPrologueAllocShadowFrame and
882 // MethodCompiler::EmitPushShadowFrame
883 shadow_frame_size_ =
884 llvm::cast<llvm::ConstantInt>(num_entry_value)->getZExtValue();
885
886 llvm::StructType* shadow_frame_type =
887 irb_.getShadowFrameTy(shadow_frame_size_);
888
889 shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
890
891 // Alloca a pointer to old shadow frame
892 old_shadow_frame_ =
893 irb_.CreateAlloca(shadow_frame_type->getElementType(0)->getPointerTo());
894
895 // Zero-initialization of the shadow frame table
896 llvm::Value* shadow_frame_table =
897 irb_.CreateConstGEP2_32(shadow_frame_, 0, 1);
898 llvm::Type* table_type = shadow_frame_type->getElementType(1);
899
900 llvm::ConstantAggregateZero* zero_initializer =
901 llvm::ConstantAggregateZero::get(table_type);
902
903 irb_.CreateStore(zero_initializer, shadow_frame_table, kTBAAShadowFrame);
904
905 // Push the shadow frame
906 llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
907
908 // Push the shadow frame
909 llvm::Value* shadow_frame_upcast =
910 irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
911
912 llvm::Value* result = rtb_.EmitPushShadowFrame(shadow_frame_upcast,
913 method_object_addr,
914 shadow_frame_size_);
915
916 irb_.CreateStore(result, old_shadow_frame_, kTBAARegister);
917
918 return;
919}
920
921void GBCExpanderPass::Expand_SetShadowFrameEntry(llvm::Value* obj,
922 llvm::Value* entry_idx) {
923 DCHECK(shadow_frame_ != NULL);
924
925 llvm::Value* gep_index[] = {
926 irb_.getInt32(0), // No pointer displacement
927 irb_.getInt32(1), // SIRT
928 entry_idx // Pointer field
929 };
930
931 llvm::Value* entry_addr = irb_.CreateGEP(shadow_frame_, gep_index);
932 irb_.CreateStore(obj, entry_addr, kTBAAShadowFrame);
933 return;
934}
935
936void GBCExpanderPass::Expand_PopShadowFrame() {
937 rtb_.EmitPopShadowFrame(irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
938 return;
939}
940
941void GBCExpanderPass::Expand_UpdateDexPC(llvm::Value* dex_pc_value) {
942 irb_.StoreToObjectOffset(shadow_frame_,
943 ShadowFrame::DexPCOffset(),
944 dex_pc_value,
945 kTBAAShadowFrame);
946 return;
947}
948
949bool GBCExpanderPass::InsertStackOverflowCheck(llvm::Function& func) {
950 // DexLang generates all alloca instruction in the first basic block of the
951 // FUNC and also there's no any alloca instructions after the first non-alloca
952 // instruction
953
954 llvm::BasicBlock::iterator first_non_alloca = func.front().begin();
955 while (llvm::isa<llvm::AllocaInst>(first_non_alloca)) {
956 ++first_non_alloca;
957 }
958
959 // Insert stack overflow check codes before first_non_alloca (i.e., after all
960 // alloca instructions)
961 return EmitStackOverflowCheck(&*first_non_alloca);
962}
963
964llvm::Value*
965GBCExpanderPass::ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id,
966 llvm::CallInst& call_inst) {
967 switch (intr_id) {
968 //==- Thread -----------------------------------------------------------==//
969 case IntrinsicHelper::GetCurrentThread: {
TDYa127b672d1e2012-06-28 21:21:45 -0700970 return irb_.Runtime().EmitGetCurrentThread();
Shih-wei Liao21d28f52012-06-12 05:55:00 -0700971 }
972 case IntrinsicHelper::TestSuspend: {
973 Expand_TestSuspend(call_inst);
974 return NULL;
975 }
976 case IntrinsicHelper::MarkGCCard: {
977 return ExpandToRuntime(runtime_support::MarkGCCard, call_inst);
978 }
979 //==- Exception --------------------------------------------------------==//
980 case IntrinsicHelper::ThrowException: {
981 return ExpandToRuntime(runtime_support::ThrowException, call_inst);
982 }
983 case IntrinsicHelper::GetException: {
984 return Expand_GetException();
985 }
986 case IntrinsicHelper::IsExceptionPending: {
987 return irb_.Runtime().EmitIsExceptionPending();
988 }
989 case IntrinsicHelper::FindCatchBlock: {
990 return ExpandToRuntime(runtime_support::FindCatchBlock, call_inst);
991 }
992 case IntrinsicHelper::ThrowDivZeroException: {
993 return ExpandToRuntime(runtime_support::ThrowDivZeroException, call_inst);
994 }
995 case IntrinsicHelper::ThrowNullPointerException: {
996 return ExpandToRuntime(runtime_support::ThrowNullPointerException, call_inst);
997 }
998 case IntrinsicHelper::ThrowIndexOutOfBounds: {
999 return ExpandToRuntime(runtime_support::ThrowIndexOutOfBounds, call_inst);
1000 }
1001 //==- ConstString ------------------------------------------------------==//
1002 case IntrinsicHelper::LoadStringFromDexCache: {
1003 return Expand_LoadStringFromDexCache(call_inst.getArgOperand(0));
1004 }
1005 case IntrinsicHelper::ResolveString: {
1006 return ExpandToRuntime(runtime_support::ResolveString, call_inst);
1007 }
1008 //==- ConstClass -------------------------------------------------------==//
1009 case IntrinsicHelper::InitializeTypeAndVerifyAccess: {
1010 return ExpandToRuntime(runtime_support::InitializeTypeAndVerifyAccess, call_inst);
1011 }
1012 case IntrinsicHelper::LoadTypeFromDexCache: {
1013 return Expand_LoadTypeFromDexCache(call_inst.getArgOperand(0));
1014 }
1015 case IntrinsicHelper::InitializeType: {
1016 return ExpandToRuntime(runtime_support::InitializeType, call_inst);
1017 }
1018 //==- Lock -------------------------------------------------------------==//
1019 case IntrinsicHelper::LockObject: {
1020 Expand_LockObject(call_inst.getArgOperand(0));
1021 return NULL;
1022 }
1023 case IntrinsicHelper::UnlockObject: {
1024 Expand_UnlockObject(call_inst.getArgOperand(0));
1025 return NULL;
1026 }
1027 //==- Cast -------------------------------------------------------------==//
1028 case IntrinsicHelper::CheckCast: {
1029 return ExpandToRuntime(runtime_support::CheckCast, call_inst);
1030 }
1031 case IntrinsicHelper::IsAssignable: {
1032 return ExpandToRuntime(runtime_support::IsAssignable, call_inst);
1033 }
1034 //==- Alloc ------------------------------------------------------------==//
1035 case IntrinsicHelper::AllocObject: {
1036 return ExpandToRuntime(runtime_support::AllocObject, call_inst);
1037 }
1038 case IntrinsicHelper::AllocObjectWithAccessCheck: {
1039 return ExpandToRuntime(runtime_support::AllocObjectWithAccessCheck, call_inst);
1040 }
1041 //==- Array ------------------------------------------------------------==//
1042 case IntrinsicHelper::ArrayLength: {
1043 return EmitLoadArrayLength(call_inst.getArgOperand(0));
1044 }
1045 case IntrinsicHelper::AllocArray: {
1046 return ExpandToRuntime(runtime_support::AllocArray, call_inst);
1047 }
1048 case IntrinsicHelper::AllocArrayWithAccessCheck: {
1049 return ExpandToRuntime(runtime_support::AllocArrayWithAccessCheck,
1050 call_inst);
1051 }
1052 case IntrinsicHelper::CheckAndAllocArray: {
1053 return ExpandToRuntime(runtime_support::CheckAndAllocArray, call_inst);
1054 }
1055 case IntrinsicHelper::CheckAndAllocArrayWithAccessCheck: {
1056 return ExpandToRuntime(runtime_support::CheckAndAllocArrayWithAccessCheck,
1057 call_inst);
1058 }
1059 case IntrinsicHelper::ArrayGet: {
1060 return Expand_ArrayGet(call_inst.getArgOperand(0),
1061 call_inst.getArgOperand(1),
1062 kInt);
1063 }
1064 case IntrinsicHelper::ArrayGetWide: {
1065 return Expand_ArrayGet(call_inst.getArgOperand(0),
1066 call_inst.getArgOperand(1),
1067 kLong);
1068 }
1069 case IntrinsicHelper::ArrayGetObject: {
1070 return Expand_ArrayGet(call_inst.getArgOperand(0),
1071 call_inst.getArgOperand(1),
1072 kObject);
1073 }
1074 case IntrinsicHelper::ArrayGetBoolean: {
1075 return Expand_ArrayGet(call_inst.getArgOperand(0),
1076 call_inst.getArgOperand(1),
1077 kBoolean);
1078 }
1079 case IntrinsicHelper::ArrayGetByte: {
1080 return Expand_ArrayGet(call_inst.getArgOperand(0),
1081 call_inst.getArgOperand(1),
1082 kByte);
1083 }
1084 case IntrinsicHelper::ArrayGetChar: {
1085 return Expand_ArrayGet(call_inst.getArgOperand(0),
1086 call_inst.getArgOperand(1),
1087 kChar);
1088 }
1089 case IntrinsicHelper::ArrayGetShort: {
1090 return Expand_ArrayGet(call_inst.getArgOperand(0),
1091 call_inst.getArgOperand(1),
1092 kShort);
1093 }
1094 case IntrinsicHelper::ArrayPut: {
1095 Expand_ArrayPut(call_inst.getArgOperand(0),
1096 call_inst.getArgOperand(1),
1097 call_inst.getArgOperand(2),
1098 kInt);
1099 return NULL;
1100 }
1101 case IntrinsicHelper::ArrayPutWide: {
1102 Expand_ArrayPut(call_inst.getArgOperand(0),
1103 call_inst.getArgOperand(1),
1104 call_inst.getArgOperand(2),
1105 kLong);
1106 return NULL;
1107 }
1108 case IntrinsicHelper::ArrayPutObject: {
1109 Expand_ArrayPut(call_inst.getArgOperand(0),
1110 call_inst.getArgOperand(1),
1111 call_inst.getArgOperand(2),
1112 kObject);
1113 return NULL;
1114 }
1115 case IntrinsicHelper::ArrayPutBoolean: {
1116 Expand_ArrayPut(call_inst.getArgOperand(0),
1117 call_inst.getArgOperand(1),
1118 call_inst.getArgOperand(2),
1119 kBoolean);
1120 return NULL;
1121 }
1122 case IntrinsicHelper::ArrayPutByte: {
1123 Expand_ArrayPut(call_inst.getArgOperand(0),
1124 call_inst.getArgOperand(1),
1125 call_inst.getArgOperand(2),
1126 kByte);
1127 return NULL;
1128 }
1129 case IntrinsicHelper::ArrayPutChar: {
1130 Expand_ArrayPut(call_inst.getArgOperand(0),
1131 call_inst.getArgOperand(1),
1132 call_inst.getArgOperand(2),
1133 kChar);
1134 return NULL;
1135 }
1136 case IntrinsicHelper::ArrayPutShort: {
1137 Expand_ArrayPut(call_inst.getArgOperand(0),
1138 call_inst.getArgOperand(1),
1139 call_inst.getArgOperand(2),
1140 kShort);
1141 return NULL;
1142 }
1143 case IntrinsicHelper::CheckPutArrayElement: {
1144 return ExpandToRuntime(runtime_support::CheckPutArrayElement, call_inst);
1145 }
1146 case IntrinsicHelper::FilledNewArray: {
1147 Expand_FilledNewArray(call_inst);
1148 return NULL;
1149 }
1150 case IntrinsicHelper::FillArrayData: {
1151 return ExpandToRuntime(runtime_support::FillArrayData, call_inst);
1152 }
1153 //==- Instance Field ---------------------------------------------------==//
1154 case IntrinsicHelper::InstanceFieldGet:
1155 case IntrinsicHelper::InstanceFieldGetBoolean:
1156 case IntrinsicHelper::InstanceFieldGetByte:
1157 case IntrinsicHelper::InstanceFieldGetChar:
1158 case IntrinsicHelper::InstanceFieldGetShort: {
1159 return ExpandToRuntime(runtime_support::Get32Instance, call_inst);
1160 }
1161 case IntrinsicHelper::InstanceFieldGetWide: {
1162 return ExpandToRuntime(runtime_support::Get64Instance, call_inst);
1163 }
1164 case IntrinsicHelper::InstanceFieldGetObject: {
1165 return ExpandToRuntime(runtime_support::GetObjectInstance, call_inst);
1166 }
1167 case IntrinsicHelper::InstanceFieldGetFast: {
1168 return Expand_IGetFast(call_inst.getArgOperand(0),
1169 call_inst.getArgOperand(1),
1170 call_inst.getArgOperand(2),
1171 kInt);
1172 }
1173 case IntrinsicHelper::InstanceFieldGetWideFast: {
1174 return Expand_IGetFast(call_inst.getArgOperand(0),
1175 call_inst.getArgOperand(1),
1176 call_inst.getArgOperand(2),
1177 kLong);
1178 }
1179 case IntrinsicHelper::InstanceFieldGetObjectFast: {
1180 return Expand_IGetFast(call_inst.getArgOperand(0),
1181 call_inst.getArgOperand(1),
1182 call_inst.getArgOperand(2),
1183 kObject);
1184 }
1185 case IntrinsicHelper::InstanceFieldGetBooleanFast: {
1186 return Expand_IGetFast(call_inst.getArgOperand(0),
1187 call_inst.getArgOperand(1),
1188 call_inst.getArgOperand(2),
1189 kBoolean);
1190 }
1191 case IntrinsicHelper::InstanceFieldGetByteFast: {
1192 return Expand_IGetFast(call_inst.getArgOperand(0),
1193 call_inst.getArgOperand(1),
1194 call_inst.getArgOperand(2),
1195 kByte);
1196 }
1197 case IntrinsicHelper::InstanceFieldGetCharFast: {
1198 return Expand_IGetFast(call_inst.getArgOperand(0),
1199 call_inst.getArgOperand(1),
1200 call_inst.getArgOperand(2),
1201 kChar);
1202 }
1203 case IntrinsicHelper::InstanceFieldGetShortFast: {
1204 return Expand_IGetFast(call_inst.getArgOperand(0),
1205 call_inst.getArgOperand(1),
1206 call_inst.getArgOperand(2),
1207 kShort);
1208 }
1209 case IntrinsicHelper::InstanceFieldPut:
1210 case IntrinsicHelper::InstanceFieldPutBoolean:
1211 case IntrinsicHelper::InstanceFieldPutByte:
1212 case IntrinsicHelper::InstanceFieldPutChar:
1213 case IntrinsicHelper::InstanceFieldPutShort: {
1214 return ExpandToRuntime(runtime_support::Set32Instance, call_inst);
1215 }
1216 case IntrinsicHelper::InstanceFieldPutWide: {
1217 return ExpandToRuntime(runtime_support::Set64Instance, call_inst);
1218 }
1219 case IntrinsicHelper::InstanceFieldPutObject: {
1220 return ExpandToRuntime(runtime_support::SetObjectInstance, call_inst);
1221 }
1222 case IntrinsicHelper::InstanceFieldPutFast: {
1223 Expand_IPutFast(call_inst.getArgOperand(0),
1224 call_inst.getArgOperand(1),
1225 call_inst.getArgOperand(2),
1226 call_inst.getArgOperand(3),
1227 kInt);
1228 return NULL;
1229 }
1230 case IntrinsicHelper::InstanceFieldPutWideFast: {
1231 Expand_IPutFast(call_inst.getArgOperand(0),
1232 call_inst.getArgOperand(1),
1233 call_inst.getArgOperand(2),
1234 call_inst.getArgOperand(3),
1235 kLong);
1236 return NULL;
1237 }
1238 case IntrinsicHelper::InstanceFieldPutObjectFast: {
1239 Expand_IPutFast(call_inst.getArgOperand(0),
1240 call_inst.getArgOperand(1),
1241 call_inst.getArgOperand(2),
1242 call_inst.getArgOperand(3),
1243 kObject);
1244 return NULL;
1245 }
1246 case IntrinsicHelper::InstanceFieldPutBooleanFast: {
1247 Expand_IPutFast(call_inst.getArgOperand(0),
1248 call_inst.getArgOperand(1),
1249 call_inst.getArgOperand(2),
1250 call_inst.getArgOperand(3),
1251 kBoolean);
1252 return NULL;
1253 }
1254 case IntrinsicHelper::InstanceFieldPutByteFast: {
1255 Expand_IPutFast(call_inst.getArgOperand(0),
1256 call_inst.getArgOperand(1),
1257 call_inst.getArgOperand(2),
1258 call_inst.getArgOperand(3),
1259 kByte);
1260 return NULL;
1261 }
1262 case IntrinsicHelper::InstanceFieldPutCharFast: {
1263 Expand_IPutFast(call_inst.getArgOperand(0),
1264 call_inst.getArgOperand(1),
1265 call_inst.getArgOperand(2),
1266 call_inst.getArgOperand(3),
1267 kChar);
1268 return NULL;
1269 }
1270 case IntrinsicHelper::InstanceFieldPutShortFast: {
1271 Expand_IPutFast(call_inst.getArgOperand(0),
1272 call_inst.getArgOperand(1),
1273 call_inst.getArgOperand(2),
1274 call_inst.getArgOperand(3),
1275 kShort);
1276 return NULL;
1277 }
1278 //==- Static Field -----------------------------------------------------==//
1279 case IntrinsicHelper::StaticFieldGet:
1280 case IntrinsicHelper::StaticFieldGetBoolean:
1281 case IntrinsicHelper::StaticFieldGetByte:
1282 case IntrinsicHelper::StaticFieldGetChar:
1283 case IntrinsicHelper::StaticFieldGetShort: {
1284 return ExpandToRuntime(runtime_support::Get32Static, call_inst);
1285 }
1286 case IntrinsicHelper::StaticFieldGetWide: {
1287 return ExpandToRuntime(runtime_support::Get64Static, call_inst);
1288 }
1289 case IntrinsicHelper::StaticFieldGetObject: {
1290 return ExpandToRuntime(runtime_support::GetObjectStatic, call_inst);
1291 }
1292 case IntrinsicHelper::StaticFieldGetFast: {
1293 return Expand_SGetFast(call_inst.getArgOperand(0),
1294 call_inst.getArgOperand(1),
1295 call_inst.getArgOperand(2),
1296 kInt);
1297 }
1298 case IntrinsicHelper::StaticFieldGetWideFast: {
1299 return Expand_SGetFast(call_inst.getArgOperand(0),
1300 call_inst.getArgOperand(1),
1301 call_inst.getArgOperand(2),
1302 kLong);
1303 }
1304 case IntrinsicHelper::StaticFieldGetObjectFast: {
1305 return Expand_SGetFast(call_inst.getArgOperand(0),
1306 call_inst.getArgOperand(1),
1307 call_inst.getArgOperand(2),
1308 kObject);
1309 }
1310 case IntrinsicHelper::StaticFieldGetBooleanFast: {
1311 return Expand_SGetFast(call_inst.getArgOperand(0),
1312 call_inst.getArgOperand(1),
1313 call_inst.getArgOperand(2),
1314 kBoolean);
1315 }
1316 case IntrinsicHelper::StaticFieldGetByteFast: {
1317 return Expand_SGetFast(call_inst.getArgOperand(0),
1318 call_inst.getArgOperand(1),
1319 call_inst.getArgOperand(2),
1320 kByte);
1321 }
1322 case IntrinsicHelper::StaticFieldGetCharFast: {
1323 return Expand_SGetFast(call_inst.getArgOperand(0),
1324 call_inst.getArgOperand(1),
1325 call_inst.getArgOperand(2),
1326 kChar);
1327 }
1328 case IntrinsicHelper::StaticFieldGetShortFast: {
1329 return Expand_SGetFast(call_inst.getArgOperand(0),
1330 call_inst.getArgOperand(1),
1331 call_inst.getArgOperand(2),
1332 kShort);
1333 }
1334 case IntrinsicHelper::StaticFieldPut:
1335 case IntrinsicHelper::StaticFieldPutBoolean:
1336 case IntrinsicHelper::StaticFieldPutByte:
1337 case IntrinsicHelper::StaticFieldPutChar:
1338 case IntrinsicHelper::StaticFieldPutShort: {
1339 return ExpandToRuntime(runtime_support::Set32Static, call_inst);
1340 }
1341 case IntrinsicHelper::StaticFieldPutWide: {
1342 return ExpandToRuntime(runtime_support::Set64Static, call_inst);
1343 }
1344 case IntrinsicHelper::StaticFieldPutObject: {
1345 return ExpandToRuntime(runtime_support::SetObjectStatic, call_inst);
1346 }
1347 case IntrinsicHelper::StaticFieldPutFast: {
1348 Expand_SPutFast(call_inst.getArgOperand(0),
1349 call_inst.getArgOperand(1),
1350 call_inst.getArgOperand(2),
1351 call_inst.getArgOperand(3),
1352 kInt);
1353 return NULL;
1354 }
1355 case IntrinsicHelper::StaticFieldPutWideFast: {
1356 Expand_SPutFast(call_inst.getArgOperand(0),
1357 call_inst.getArgOperand(1),
1358 call_inst.getArgOperand(2),
1359 call_inst.getArgOperand(3),
1360 kLong);
1361 return NULL;
1362 }
1363 case IntrinsicHelper::StaticFieldPutObjectFast: {
1364 Expand_SPutFast(call_inst.getArgOperand(0),
1365 call_inst.getArgOperand(1),
1366 call_inst.getArgOperand(2),
1367 call_inst.getArgOperand(3),
1368 kObject);
1369 return NULL;
1370 }
1371 case IntrinsicHelper::StaticFieldPutBooleanFast: {
1372 Expand_SPutFast(call_inst.getArgOperand(0),
1373 call_inst.getArgOperand(1),
1374 call_inst.getArgOperand(2),
1375 call_inst.getArgOperand(3),
1376 kBoolean);
1377 return NULL;
1378 }
1379 case IntrinsicHelper::StaticFieldPutByteFast: {
1380 Expand_SPutFast(call_inst.getArgOperand(0),
1381 call_inst.getArgOperand(1),
1382 call_inst.getArgOperand(2),
1383 call_inst.getArgOperand(3),
1384 kByte);
1385 return NULL;
1386 }
1387 case IntrinsicHelper::StaticFieldPutCharFast: {
1388 Expand_SPutFast(call_inst.getArgOperand(0),
1389 call_inst.getArgOperand(1),
1390 call_inst.getArgOperand(2),
1391 call_inst.getArgOperand(3),
1392 kChar);
1393 return NULL;
1394 }
1395 case IntrinsicHelper::StaticFieldPutShortFast: {
1396 Expand_SPutFast(call_inst.getArgOperand(0),
1397 call_inst.getArgOperand(1),
1398 call_inst.getArgOperand(2),
1399 call_inst.getArgOperand(3),
1400 kShort);
1401 return NULL;
1402 }
1403 case IntrinsicHelper::LoadDeclaringClassSSB: {
1404 return Expand_LoadDeclaringClassSSB(call_inst.getArgOperand(0));
1405 }
1406 case IntrinsicHelper::LoadClassSSBFromDexCache: {
1407 return Expand_LoadClassSSBFromDexCache(call_inst.getArgOperand(0));
1408 }
1409 case IntrinsicHelper::InitializeAndLoadClassSSB: {
1410 return ExpandToRuntime(runtime_support::InitializeStaticStorage, call_inst);
1411 }
1412 //==- Invoke -----------------------------------------------------------==//
1413 case IntrinsicHelper::FindStaticMethodWithAccessCheck: {
1414 return ExpandToRuntime(runtime_support::FindStaticMethodWithAccessCheck, call_inst);
1415 }
1416 case IntrinsicHelper::FindDirectMethodWithAccessCheck: {
1417 return ExpandToRuntime(runtime_support::FindDirectMethodWithAccessCheck, call_inst);
1418 }
1419 case IntrinsicHelper::FindVirtualMethodWithAccessCheck: {
1420 return ExpandToRuntime(runtime_support::FindVirtualMethodWithAccessCheck, call_inst);
1421 }
1422 case IntrinsicHelper::FindSuperMethodWithAccessCheck: {
1423 return ExpandToRuntime(runtime_support::FindSuperMethodWithAccessCheck, call_inst);
1424 }
1425 case IntrinsicHelper::FindInterfaceMethodWithAccessCheck: {
1426 return ExpandToRuntime(runtime_support::FindInterfaceMethodWithAccessCheck, call_inst);
1427 }
1428 case IntrinsicHelper::GetSDCalleeMethodObjAddrFast: {
1429 return Expand_GetSDCalleeMethodObjAddrFast(call_inst.getArgOperand(0));
1430 }
1431 case IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast: {
1432 return Expand_GetVirtualCalleeMethodObjAddrFast(
1433 call_inst.getArgOperand(0), call_inst.getArgOperand(1));
1434 }
1435 case IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast: {
1436 return ExpandToRuntime(runtime_support::FindInterfaceMethod, call_inst);
1437 }
1438 case IntrinsicHelper::InvokeRetVoid:
1439 case IntrinsicHelper::InvokeRetBoolean:
1440 case IntrinsicHelper::InvokeRetByte:
1441 case IntrinsicHelper::InvokeRetChar:
1442 case IntrinsicHelper::InvokeRetShort:
1443 case IntrinsicHelper::InvokeRetInt:
1444 case IntrinsicHelper::InvokeRetLong:
1445 case IntrinsicHelper::InvokeRetFloat:
1446 case IntrinsicHelper::InvokeRetDouble:
1447 case IntrinsicHelper::InvokeRetObject: {
1448 return Expand_Invoke(call_inst);
1449 }
1450 //==- Math -------------------------------------------------------------==//
1451 case IntrinsicHelper::DivInt: {
1452 return Expand_DivRem(call_inst.getArgOperand(0),
1453 call_inst.getArgOperand(1),
1454 /* is_div */true, kInt);
1455 }
1456 case IntrinsicHelper::RemInt: {
1457 return Expand_DivRem(call_inst.getArgOperand(0),
1458 call_inst.getArgOperand(1),
1459 /* is_div */false, kInt);
1460 }
1461 case IntrinsicHelper::DivLong: {
1462 return Expand_DivRem(call_inst.getArgOperand(0),
1463 call_inst.getArgOperand(1),
1464 /* is_div */true, kLong);
1465 }
1466 case IntrinsicHelper::RemLong: {
1467 return Expand_DivRem(call_inst.getArgOperand(0),
1468 call_inst.getArgOperand(1),
1469 /* is_div */false, kLong);
1470 }
1471 case IntrinsicHelper::D2L: {
1472 return ExpandToRuntime(runtime_support::art_d2l, call_inst);
1473 }
1474 case IntrinsicHelper::D2I: {
1475 return ExpandToRuntime(runtime_support::art_d2i, call_inst);
1476 }
1477 case IntrinsicHelper::F2L: {
1478 return ExpandToRuntime(runtime_support::art_f2l, call_inst);
1479 }
1480 case IntrinsicHelper::F2I: {
1481 return ExpandToRuntime(runtime_support::art_f2i, call_inst);
1482 }
1483 //==- Shadow Frame -----------------------------------------------------==//
1484 case IntrinsicHelper::AllocaShadowFrame: {
1485 Expand_AllocaShadowFrame(call_inst.getArgOperand(0));
1486 return NULL;
1487 }
1488 case IntrinsicHelper::SetShadowFrameEntry: {
1489 Expand_SetShadowFrameEntry(call_inst.getArgOperand(0),
1490 call_inst.getArgOperand(1));
1491 return NULL;
1492 }
1493 case IntrinsicHelper::PopShadowFrame: {
1494 Expand_PopShadowFrame();
1495 return NULL;
1496 }
1497 case IntrinsicHelper::UpdateDexPC: {
1498 Expand_UpdateDexPC(call_inst.getArgOperand(0));
1499 return NULL;
1500 }
1501 default: {
1502 const IntrinsicHelper::IntrinsicInfo& intr_info =
1503 IntrinsicHelper::GetInfo(intr_id);
1504
1505 UNIMPLEMENTED(FATAL) << "expand DexLang intrinsic: " << intr_info.name_;
1506 break;
1507 }
1508 }
1509 return NULL;
1510}
1511
1512} // anonymous namespace
1513
1514namespace art {
1515namespace compiler_llvm {
1516
1517llvm::FunctionPass*
1518CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb) {
1519 return new GBCExpanderPass(intrinsic_helper, irb);
1520}
1521
1522} // namespace compiler_llvm
1523} // namespace art