blob: c5ff6d747693d663f8d14e3683666dd733d8d103 [file] [log] [blame]
TDYa127d668a062012-04-13 12:36:57 -07001/*
2 * Copyright (C) 2011 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 "runtime_support_builder.h"
18
TDYa12783bb6622012-04-17 02:20:34 -070019#include "card_table.h"
TDYa127d668a062012-04-13 12:36:57 -070020#include "ir_builder.h"
21#include "shadow_frame.h"
22#include "thread.h"
TDYa127853cd092012-04-21 22:15:31 -070023#include "utils_llvm.h"
TDYa127d668a062012-04-13 12:36:57 -070024
25#include <llvm/DerivedTypes.h>
26#include <llvm/Function.h>
27#include <llvm/Module.h>
28#include <llvm/Type.h>
29
30using namespace llvm;
31
32namespace art {
33namespace compiler_llvm {
34
35using namespace runtime_support;
36
37
38RuntimeSupportBuilder::RuntimeSupportBuilder(llvm::LLVMContext& context,
39 llvm::Module& module,
40 IRBuilder& irb)
41 : context_(context), module_(module), irb_(irb)
42{
TDYa12783bb6622012-04-17 02:20:34 -070043 memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
TDYa127d668a062012-04-13 12:36:57 -070044#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
45 do { \
46 llvm::Function* fn = module_.getFunction(#NAME); \
47 DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
48 runtime_support_func_decls_[ID] = fn; \
49 } while (0);
50
51#include "runtime_support_func_list.h"
52 RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
53#undef RUNTIME_SUPPORT_FUNC_LIST
54#undef GET_RUNTIME_SUPPORT_FUNC_DECL
55}
56
57void RuntimeSupportBuilder::MakeFunctionInline(llvm::Function* func) {
58 func->setLinkage(GlobalValue::LinkOnceODRLinkage);
59
60 SmallVector<AttributeWithIndex, 4> Attrs;
61 AttributeWithIndex PAWI;
62 PAWI.Index = ~0U;
63 PAWI.Attrs = Attribute::None | Attribute::NoUnwind | Attribute::AlwaysInline;
64 Attrs.push_back(PAWI);
65 AttrListPtr func_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end());
66
67 func->setAttributes(func_PAL);
68}
69
70void RuntimeSupportBuilder::OverrideRuntimeSupportFunction(RuntimeId id, llvm::Function* function) {
71 // TODO: Check function prototype.
72 if (id >= 0 && id < MAX_ID) {
73 runtime_support_func_decls_[id] = function;
74 target_runtime_support_func_[id] = true;
75 } else {
76 LOG(ERROR) << "Unknown runtime function id: " << id;
77 }
78}
79
80void RuntimeSupportBuilder::OptimizeRuntimeSupport() {
81 TargetOptimizeRuntimeSupport();
82
83 if (!target_runtime_support_func_[PushShadowFrame]) {
84 Function* func = GetRuntimeSupportFunction(PushShadowFrame);
85 MakeFunctionInline(func);
86 BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
87 irb_.SetInsertPoint(basic_block);
88
89 Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
90 Value* thread = irb_.CreateCall(get_thread);
91 Value* new_shadow_frame = func->arg_begin();
92 Value* old_shadow_frame = irb_.LoadFromObjectOffset(thread,
93 Thread::TopShadowFrameOffset().Int32Value(),
94 irb_.getJObjectTy());
95 irb_.StoreToObjectOffset(new_shadow_frame,
96 ShadowFrame::LinkOffset(),
97 old_shadow_frame);
98 irb_.StoreToObjectOffset(thread,
99 Thread::TopShadowFrameOffset().Int32Value(),
100 new_shadow_frame);
101 irb_.CreateRetVoid();
TDYa127853cd092012-04-21 22:15:31 -0700102
103 VERIFY_LLVM_FUNCTION(*func);
TDYa127d668a062012-04-13 12:36:57 -0700104 }
105
106 if (!target_runtime_support_func_[PopShadowFrame]) {
107 Function* func = GetRuntimeSupportFunction(PopShadowFrame);
108 MakeFunctionInline(func);
109 BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
110 irb_.SetInsertPoint(basic_block);
111
112 Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
113 Value* thread = irb_.CreateCall(get_thread);
114 Value* new_shadow_frame = irb_.LoadFromObjectOffset(thread,
115 Thread::TopShadowFrameOffset().Int32Value(),
116 irb_.getJObjectTy());
117 Value* old_shadow_frame = irb_.LoadFromObjectOffset(new_shadow_frame,
118 ShadowFrame::LinkOffset(),
119 irb_.getJObjectTy());
120 irb_.StoreToObjectOffset(thread,
121 Thread::TopShadowFrameOffset().Int32Value(),
122 old_shadow_frame);
123 irb_.CreateRetVoid();
TDYa127853cd092012-04-21 22:15:31 -0700124
125 VERIFY_LLVM_FUNCTION(*func);
TDYa127d668a062012-04-13 12:36:57 -0700126 }
127
128 if (!target_runtime_support_func_[IsExceptionPending]) {
129 Function* func = GetRuntimeSupportFunction(IsExceptionPending);
130 MakeFunctionInline(func);
131 BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
132 irb_.SetInsertPoint(basic_block);
133
134 Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
135 Value* thread = irb_.CreateCall(get_thread);
136 Value* exception = irb_.LoadFromObjectOffset(thread,
137 Thread::ExceptionOffset().Int32Value(),
138 irb_.getJObjectTy());
139 Value* is_exception_not_null = irb_.CreateICmpNE(exception, irb_.getJNull());
140 irb_.CreateRet(is_exception_not_null);
TDYa127853cd092012-04-21 22:15:31 -0700141
142 VERIFY_LLVM_FUNCTION(*func);
TDYa127d668a062012-04-13 12:36:57 -0700143 }
144
145 if (!target_runtime_support_func_[TestSuspend]) {
146 Function* slow_func = GetRuntimeSupportFunction(TestSuspend);
147
148 Function* func = Function::Create(slow_func->getFunctionType(),
149 GlobalValue::LinkOnceODRLinkage,
150 "test_suspend_fast",
151 &module_);
152 MakeFunctionInline(func);
153 BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
154 irb_.SetInsertPoint(basic_block);
155
TDYa127853cd092012-04-21 22:15:31 -0700156 Value* thread = func->arg_begin();
TDYa127d668a062012-04-13 12:36:57 -0700157 Value* suspend_count = irb_.LoadFromObjectOffset(thread,
158 Thread::SuspendCountOffset().Int32Value(),
159 irb_.getJIntTy());
160 Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getJInt(0));
161
162 BasicBlock* basic_block_suspend = BasicBlock::Create(context_, "suspend", func);
163 BasicBlock* basic_block_else = BasicBlock::Create(context_, "else", func);
164 irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_else);
TDYa127706e9b62012-04-19 12:24:26 -0700165
TDYa127d668a062012-04-13 12:36:57 -0700166 irb_.SetInsertPoint(basic_block_suspend);
TDYa127706e9b62012-04-19 12:24:26 -0700167 irb_.CreateCall(slow_func, thread);
TDYa127d668a062012-04-13 12:36:57 -0700168 irb_.CreateBr(basic_block_else);
TDYa127706e9b62012-04-19 12:24:26 -0700169
TDYa127d668a062012-04-13 12:36:57 -0700170 irb_.SetInsertPoint(basic_block_else);
171 irb_.CreateRetVoid();
172
173 OverrideRuntimeSupportFunction(TestSuspend, func);
TDYa127853cd092012-04-21 22:15:31 -0700174
175 VERIFY_LLVM_FUNCTION(*func);
TDYa127d668a062012-04-13 12:36:57 -0700176 }
TDYa12783bb6622012-04-17 02:20:34 -0700177
178 if (!target_runtime_support_func_[MarkGCCard]) {
179 Function* func = GetRuntimeSupportFunction(MarkGCCard);
180 MakeFunctionInline(func);
181 BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
182 irb_.SetInsertPoint(basic_block);
183 Function::arg_iterator arg_iter = func->arg_begin();
184 Value* value = arg_iter++;
185 Value* target_addr = arg_iter++;
186
187 llvm::Value* is_value_null = irb_.CreateICmpEQ(value, irb_.getJNull());
188
189 llvm::BasicBlock* block_value_is_null = BasicBlock::Create(context_, "value_is_null", func);
190 llvm::BasicBlock* block_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", func);
191
192 irb_.CreateCondBr(is_value_null, block_value_is_null, block_mark_gc_card);
193
194 irb_.SetInsertPoint(block_value_is_null);
195 irb_.CreateRetVoid();
196
197 irb_.SetInsertPoint(block_mark_gc_card);
198 Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
199 Value* thread = irb_.CreateCall(get_thread);
200 Value* card_table = irb_.LoadFromObjectOffset(thread,
201 Thread::CardTableOffset().Int32Value(),
202 irb_.getInt8Ty()->getPointerTo());
203 Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
204 Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(GC_CARD_SHIFT));
205 Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
206 irb_.CreateStore(irb_.getInt8(GC_CARD_DIRTY), card_table_entry);
207 irb_.CreateRetVoid();
TDYa127853cd092012-04-21 22:15:31 -0700208
209 VERIFY_LLVM_FUNCTION(*func);
TDYa12783bb6622012-04-17 02:20:34 -0700210 }
TDYa127d668a062012-04-13 12:36:57 -0700211}
212
213} // namespace compiler_llvm
214} // namespace art