blob: 652a44817a7d7964c2d3e87f9bc78c91b9554f4c [file] [log] [blame]
buzbee31a4a6f2012-02-28 15:36:15 -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
Brian Carlstrom265091e2013-01-30 14:08:26 -080017#include "compiler/dex/quick/codegen_util.h"
buzbee395116c2013-02-27 14:30:25 -080018#include "compiler/dex/compiler_ir.h"
buzbee311ca162013-02-28 15:56:43 -080019#include "compiler/dex/compiler_internals.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080020#include "oat/runtime/oat_support_entrypoints.h"
21#include "ralloc_util.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070022
buzbee31a4a6f2012-02-28 15:36:15 -080023namespace art {
24
25/*
26 * This source files contains "gen" codegen routines that should
27 * be applicable to most targets. Only mid-level support utilities
28 * and "op" calls may be used here.
29 */
buzbee31a4a6f2012-02-28 15:36:15 -080030
buzbee31a4a6f2012-02-28 15:36:15 -080031/*
32 * Generate an kPseudoBarrier marker to indicate the boundary of special
33 * blocks.
34 */
buzbee02031b12012-11-23 09:41:35 -080035void Codegen::GenBarrier(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -080036{
buzbeefa57c472012-11-21 12:06:18 -080037 LIR* barrier = NewLIR0(cu, kPseudoBarrier);
Bill Buzbeea114add2012-05-03 15:00:40 -070038 /* Mark all resources as being clobbered */
buzbeefa57c472012-11-21 12:06:18 -080039 barrier->def_mask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -080040}
41
buzbee5de34942012-03-01 14:51:57 -080042// FIXME: need to do some work to split out targets with
43// condition codes and those without
buzbee02031b12012-11-23 09:41:35 -080044LIR* Codegen::GenCheck(CompilationUnit* cu, ConditionCode c_code, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080045{
buzbeefa57c472012-11-21 12:06:18 -080046 DCHECK_NE(cu->instruction_set, kMips);
47 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
48 cu->current_dalvik_offset);
49 LIR* branch = OpCondBranch(cu, c_code, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070050 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080051 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070052 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080053}
54
buzbee02031b12012-11-23 09:41:35 -080055LIR* Codegen::GenImmedCheck(CompilationUnit* cu, ConditionCode c_code, int reg, int imm_val,
56 ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080057{
buzbeefa57c472012-11-21 12:06:18 -080058 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
buzbee4ef3e452012-12-14 13:35:28 -080059 cu->current_dalvik_offset, reg, imm_val);
Bill Buzbeea114add2012-05-03 15:00:40 -070060 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -080061 if (c_code == kCondAl) {
62 branch = OpUnconditionalBranch(cu, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070063 } else {
buzbeefa57c472012-11-21 12:06:18 -080064 branch = OpCmpImmBranch(cu, c_code, reg, imm_val, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070065 }
66 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080067 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070068 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080069}
70
71/* Perform null-check on a register. */
buzbee02031b12012-11-23 09:41:35 -080072LIR* Codegen::GenNullCheck(CompilationUnit* cu, int s_reg, int m_reg, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -080073{
buzbeefa57c472012-11-21 12:06:18 -080074 if (!(cu->disable_opt & (1 << kNullCheckElimination)) &&
75 opt_flags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -070076 return NULL;
77 }
buzbeefa57c472012-11-21 12:06:18 -080078 return GenImmedCheck(cu, kCondEq, m_reg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -080079}
80
81/* Perform check on two registers */
buzbee02031b12012-11-23 09:41:35 -080082LIR* Codegen::GenRegRegCheck(CompilationUnit* cu, ConditionCode c_code, int reg1, int reg2,
83 ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080084{
buzbeefa57c472012-11-21 12:06:18 -080085 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
86 cu->current_dalvik_offset, reg1, reg2);
87 LIR* branch = OpCmpBranch(cu, c_code, reg1, reg2, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070088 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080089 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070090 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080091}
92
buzbee02031b12012-11-23 09:41:35 -080093void Codegen::GenCompareAndBranch(CompilationUnit* cu, Instruction::Code opcode,
94 RegLocation rl_src1, RegLocation rl_src2, LIR* taken,
95 LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -080096{
Bill Buzbeea114add2012-05-03 15:00:40 -070097 ConditionCode cond;
Bill Buzbeea114add2012-05-03 15:00:40 -070098 switch (opcode) {
99 case Instruction::IF_EQ:
100 cond = kCondEq;
101 break;
102 case Instruction::IF_NE:
103 cond = kCondNe;
104 break;
105 case Instruction::IF_LT:
106 cond = kCondLt;
107 break;
108 case Instruction::IF_GE:
109 cond = kCondGe;
110 break;
111 case Instruction::IF_GT:
112 cond = kCondGt;
113 break;
114 case Instruction::IF_LE:
115 cond = kCondLe;
116 break;
117 default:
buzbeecbd6d442012-11-17 14:11:25 -0800118 cond = static_cast<ConditionCode>(0);
119 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700120 }
buzbeee6285f92012-12-06 15:57:46 -0800121
122 // Normalize such that if either operand is constant, src2 will be constant
123 if (rl_src1.is_const) {
124 RegLocation rl_temp = rl_src1;
125 rl_src1 = rl_src2;
126 rl_src2 = rl_temp;
127 cond = FlipComparisonOrder(cond);
128 }
129
130 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
131 // Is this really an immediate comparison?
132 if (rl_src2.is_const) {
buzbeee6285f92012-12-06 15:57:46 -0800133 // If it's already live in a register or not easily materialized, just keep going
134 RegLocation rl_temp = UpdateLoc(cu, rl_src2);
buzbee4ef3e452012-12-14 13:35:28 -0800135 if ((rl_temp.location == kLocDalvikFrame) &&
buzbee311ca162013-02-28 15:56:43 -0800136 InexpensiveConstantInt(cu->mir_graph->ConstantValue(rl_src2))) {
buzbeee6285f92012-12-06 15:57:46 -0800137 // OK - convert this to a compare immediate and branch
buzbee311ca162013-02-28 15:56:43 -0800138 OpCmpImmBranch(cu, cond, rl_src1.low_reg, cu->mir_graph->ConstantValue(rl_src2), taken);
buzbeee6285f92012-12-06 15:57:46 -0800139 OpUnconditionalBranch(cu, fall_through);
140 return;
141 }
142 }
143 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800144 OpCmpBranch(cu, cond, rl_src1.low_reg, rl_src2.low_reg, taken);
145 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800146}
147
buzbee02031b12012-11-23 09:41:35 -0800148void Codegen::GenCompareZeroAndBranch(CompilationUnit* cu, Instruction::Code opcode,
149 RegLocation rl_src, LIR* taken, LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -0800150{
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 ConditionCode cond;
buzbeefa57c472012-11-21 12:06:18 -0800152 rl_src = LoadValue(cu, rl_src, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 switch (opcode) {
154 case Instruction::IF_EQZ:
155 cond = kCondEq;
156 break;
157 case Instruction::IF_NEZ:
158 cond = kCondNe;
159 break;
160 case Instruction::IF_LTZ:
161 cond = kCondLt;
162 break;
163 case Instruction::IF_GEZ:
164 cond = kCondGe;
165 break;
166 case Instruction::IF_GTZ:
167 cond = kCondGt;
168 break;
169 case Instruction::IF_LEZ:
170 cond = kCondLe;
171 break;
172 default:
buzbeecbd6d442012-11-17 14:11:25 -0800173 cond = static_cast<ConditionCode>(0);
174 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700175 }
buzbeee6285f92012-12-06 15:57:46 -0800176 OpCmpImmBranch(cu, cond, rl_src.low_reg, 0, taken);
buzbeefa57c472012-11-21 12:06:18 -0800177 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800178}
179
buzbee02031b12012-11-23 09:41:35 -0800180void Codegen::GenIntToLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800181{
buzbeefa57c472012-11-21 12:06:18 -0800182 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
183 if (rl_src.location == kLocPhysReg) {
184 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700185 } else {
buzbeefa57c472012-11-21 12:06:18 -0800186 LoadValueDirect(cu, rl_src, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700187 }
buzbeefa57c472012-11-21 12:06:18 -0800188 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
189 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800190}
191
buzbee02031b12012-11-23 09:41:35 -0800192void Codegen::GenIntNarrowing(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
193 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800194{
buzbeefa57c472012-11-21 12:06:18 -0800195 rl_src = LoadValue(cu, rl_src, kCoreReg);
196 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700197 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700198 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 case Instruction::INT_TO_BYTE:
200 op = kOp2Byte;
201 break;
202 case Instruction::INT_TO_SHORT:
203 op = kOp2Short;
204 break;
205 case Instruction::INT_TO_CHAR:
206 op = kOp2Char;
207 break;
208 default:
209 LOG(ERROR) << "Bad int conversion type";
210 }
buzbeefa57c472012-11-21 12:06:18 -0800211 OpRegReg(cu, op, rl_result.low_reg, rl_src.low_reg);
212 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800213}
214
215/*
216 * Let helper function take care of everything. Will call
217 * Array::AllocFromCode(type_idx, method, count);
218 * Note: AllocFromCode will handle checks for errNegativeArraySize.
219 */
buzbee02031b12012-11-23 09:41:35 -0800220void Codegen::GenNewArray(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
221 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800222{
buzbeefa57c472012-11-21 12:06:18 -0800223 FlushAllRegs(cu); /* Everything to home location */
224 int func_offset;
Ian Rogers1212a022013-03-04 10:48:41 -0800225 if (cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx,
226 *cu->dex_file,
227 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800228 func_offset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700229 } else {
buzbeefa57c472012-11-21 12:06:18 -0800230 func_offset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700231 }
buzbeefa57c472012-11-21 12:06:18 -0800232 CallRuntimeHelperImmMethodRegLocation(cu, func_offset, type_idx, rl_src, true);
233 RegLocation rl_result = GetReturn(cu, false);
234 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800235}
236
237/*
buzbee52a77fc2012-11-20 19:50:46 -0800238 * Similar to GenNewArray, but with post-allocation initialization.
buzbee31a4a6f2012-02-28 15:36:15 -0800239 * Verifier guarantees we're dealing with an array class. Current
240 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
241 * Current code also throws internal unimp if not 'L', '[' or 'I'.
242 */
buzbee02031b12012-11-23 09:41:35 -0800243void Codegen::GenFilledNewArray(CompilationUnit* cu, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800244{
buzbeefa57c472012-11-21 12:06:18 -0800245 int elems = info->num_arg_words;
246 int type_idx = info->index;
247 FlushAllRegs(cu); /* Everything to home location */
248 int func_offset;
Ian Rogers1212a022013-03-04 10:48:41 -0800249 if (cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx,
250 *cu->dex_file,
251 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800252 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 } else {
buzbeefa57c472012-11-21 12:06:18 -0800254 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 }
buzbeefa57c472012-11-21 12:06:18 -0800256 CallRuntimeHelperImmMethodImm(cu, func_offset, type_idx, elems, true);
257 FreeTemp(cu, TargetReg(kArg2));
258 FreeTemp(cu, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700259 /*
260 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
261 * return region. Because AllocFromCode placed the new array
buzbeef0504cd2012-11-13 16:31:10 -0800262 * in kRet0, we'll just lock it into place. When debugger support is
Bill Buzbeea114add2012-05-03 15:00:40 -0700263 * added, it may be necessary to additionally copy all return
264 * values to a home location in thread-local storage
265 */
buzbeefa57c472012-11-21 12:06:18 -0800266 LockTemp(cu, TargetReg(kRet0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700267
268 // TODO: use the correct component size, currently all supported types
269 // share array alignment with ints (see comment at head of function)
270 size_t component_size = sizeof(int32_t);
271
272 // Having a range of 0 is legal
buzbeefa57c472012-11-21 12:06:18 -0800273 if (info->is_range && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800274 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 * Bit of ugliness here. We're going generate a mem copy loop
276 * on the register range, but it is possible that some regs
277 * in the range have been promoted. This is unlikely, but
278 * before generating the copy, we'll just force a flush
279 * of any regs in the source range that have been promoted to
280 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800281 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700282 for (int i = 0; i < elems; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800283 RegLocation loc = UpdateLoc(cu, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700284 if (loc.location == kLocPhysReg) {
buzbeefa57c472012-11-21 12:06:18 -0800285 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
286 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700287 }
buzbee31a4a6f2012-02-28 15:36:15 -0800288 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700289 /*
290 * TUNING note: generated code here could be much improved, but
291 * this is an uncommon operation and isn't especially performance
292 * critical.
293 */
buzbeefa57c472012-11-21 12:06:18 -0800294 int r_src = AllocTemp(cu);
295 int r_dst = AllocTemp(cu);
296 int r_idx = AllocTemp(cu);
297 int r_val = INVALID_REG;
298 switch(cu->instruction_set) {
buzbeeb046e162012-10-30 15:48:42 -0700299 case kThumb2:
buzbeefa57c472012-11-21 12:06:18 -0800300 r_val = TargetReg(kLr);
buzbeeb046e162012-10-30 15:48:42 -0700301 break;
302 case kX86:
buzbeefa57c472012-11-21 12:06:18 -0800303 FreeTemp(cu, TargetReg(kRet0));
304 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700305 break;
306 case kMips:
buzbeefa57c472012-11-21 12:06:18 -0800307 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700308 break;
buzbeefa57c472012-11-21 12:06:18 -0800309 default: LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
buzbeeb046e162012-10-30 15:48:42 -0700310 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700311 // Set up source pointer
buzbeefa57c472012-11-21 12:06:18 -0800312 RegLocation rl_first = info->args[0];
313 OpRegRegImm(cu, kOpAdd, r_src, TargetReg(kSp),
314 SRegOffset(cu, rl_first.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700315 // Set up the target pointer
buzbeefa57c472012-11-21 12:06:18 -0800316 OpRegRegImm(cu, kOpAdd, r_dst, TargetReg(kRet0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800317 mirror::Array::DataOffset(component_size).Int32Value());
Bill Buzbeea114add2012-05-03 15:00:40 -0700318 // Set up the loop counter (known to be > 0)
buzbeefa57c472012-11-21 12:06:18 -0800319 LoadConstant(cu, r_idx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700320 // Generate the copy loop. Going backwards for convenience
buzbeefa57c472012-11-21 12:06:18 -0800321 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700322 // Copy next element
buzbeefa57c472012-11-21 12:06:18 -0800323 LoadBaseIndexed(cu, r_src, r_idx, r_val, 2, kWord);
324 StoreBaseIndexed(cu, r_dst, r_idx, r_val, 2, kWord);
325 FreeTemp(cu, r_val);
326 OpDecAndBranch(cu, kCondGe, r_idx, target);
327 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700328 // Restore the target pointer
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800329 OpRegRegImm(cu, kOpAdd, TargetReg(kRet0), r_dst,
330 -mirror::Array::DataOffset(component_size).Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700331 }
buzbeefa57c472012-11-21 12:06:18 -0800332 } else if (!info->is_range) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700333 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700334 for (int i = 0; i < elems; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800335 RegLocation rl_arg = LoadValue(cu, info->args[i], kCoreReg);
336 StoreBaseDisp(cu, TargetReg(kRet0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800337 mirror::Array::DataOffset(component_size).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800338 i * 4, rl_arg.low_reg, kWord);
buzbee52a77fc2012-11-20 19:50:46 -0800339 // If the LoadValue caused a temp to be allocated, free it
buzbeefa57c472012-11-21 12:06:18 -0800340 if (IsTemp(cu, rl_arg.low_reg)) {
341 FreeTemp(cu, rl_arg.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700342 }
343 }
344 }
buzbeee5f01222012-06-14 15:19:35 -0700345 if (info->result.location != kLocInvalid) {
buzbeefa57c472012-11-21 12:06:18 -0800346 StoreValue(cu, info->result, GetReturn(cu, false /* not fp */));
buzbeee5f01222012-06-14 15:19:35 -0700347 }
buzbee31a4a6f2012-02-28 15:36:15 -0800348}
349
buzbee02031b12012-11-23 09:41:35 -0800350void Codegen::GenSput(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_src,
351 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800352{
buzbeefa57c472012-11-21 12:06:18 -0800353 int field_offset;
354 int ssb_index;
355 bool is_volatile;
356 bool is_referrers_class;
buzbee311ca162013-02-28 15:56:43 -0800357 bool fast_path = cu->compiler_driver->ComputeStaticFieldInfo(
358 field_idx, cu->mir_graph->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
359 is_referrers_class, is_volatile, true);
buzbeefa57c472012-11-21 12:06:18 -0800360 if (fast_path && !SLOW_FIELD_PATH) {
361 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700362 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800363 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700364 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800365 RegLocation rl_method = LoadCurrMethod(cu);
366 rBase = AllocTemp(cu);
367 LoadWordDisp(cu, rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800368 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbeefa57c472012-11-21 12:06:18 -0800369 if (IsTemp(cu, rl_method.low_reg)) {
370 FreeTemp(cu, rl_method.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700371 }
buzbee31a4a6f2012-02-28 15:36:15 -0800372 } else {
Ian Rogersaed07162013-03-15 12:00:53 -0700373 // Medium path, static storage base in a different class which requires checks that the other
374 // class is initialized.
375 // TODO: remove initialized check now that we are initializing classes in the compiler driver.
buzbeefa57c472012-11-21 12:06:18 -0800376 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800378 FlushAllRegs(cu);
Ian Rogersaed07162013-03-15 12:00:53 -0700379 // Using fixed register to sync with possible call to runtime support.
buzbeefa57c472012-11-21 12:06:18 -0800380 int r_method = TargetReg(kArg1);
381 LockTemp(cu, r_method);
382 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800383 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800384 LockTemp(cu, rBase);
385 LoadWordDisp(cu, r_method,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800386 mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800388 LoadWordDisp(cu, rBase,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800389 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800390 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700391 // rBase now points at appropriate static storage base (Class*)
392 // or NULL if not initialized. Check for NULL and call helper if NULL.
393 // TUNING: fast path should fall through
buzbeefa57c472012-11-21 12:06:18 -0800394 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
395 LoadConstant(cu, TargetReg(kArg0), ssb_index);
396 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
397 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800398 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800399 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700400 }
buzbeefa57c472012-11-21 12:06:18 -0800401 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
402 branch_over->target = skip_target;
403 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800404 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700405 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800406 if (is_long_or_double) {
407 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700408 } else {
buzbeefa57c472012-11-21 12:06:18 -0800409 rl_src = LoadValue(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700410 }
buzbeefa57c472012-11-21 12:06:18 -0800411 if (is_volatile) {
412 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700413 }
buzbeefa57c472012-11-21 12:06:18 -0800414 if (is_long_or_double) {
415 StoreBaseDispWide(cu, rBase, field_offset, rl_src.low_reg,
416 rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700417 } else {
buzbeefa57c472012-11-21 12:06:18 -0800418 StoreWordDisp(cu, rBase, field_offset, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700419 }
buzbeefa57c472012-11-21 12:06:18 -0800420 if (is_volatile) {
421 GenMemBarrier(cu, kStoreLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700422 }
buzbee311ca162013-02-28 15:56:43 -0800423 if (is_object && !cu->mir_graph->IsConstantNullRef(rl_src)) {
buzbeefa57c472012-11-21 12:06:18 -0800424 MarkGCCard(cu, rl_src.low_reg, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 }
buzbeefa57c472012-11-21 12:06:18 -0800426 FreeTemp(cu, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 } else {
buzbeefa57c472012-11-21 12:06:18 -0800428 FlushAllRegs(cu); // Everything to home locations
429 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Static) :
430 (is_object ? ENTRYPOINT_OFFSET(pSetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700431 : ENTRYPOINT_OFFSET(pSet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800432 CallRuntimeHelperImmRegLocation(cu, setter_offset, field_idx, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700433 }
buzbee31a4a6f2012-02-28 15:36:15 -0800434}
435
buzbee02031b12012-11-23 09:41:35 -0800436void Codegen::GenSget(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_dest,
437 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800438{
buzbeefa57c472012-11-21 12:06:18 -0800439 int field_offset;
440 int ssb_index;
441 bool is_volatile;
442 bool is_referrers_class;
buzbee311ca162013-02-28 15:56:43 -0800443 bool fast_path = cu->compiler_driver->ComputeStaticFieldInfo(
444 field_idx, cu->mir_graph->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
445 is_referrers_class, is_volatile, false);
buzbeefa57c472012-11-21 12:06:18 -0800446 if (fast_path && !SLOW_FIELD_PATH) {
447 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700448 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800449 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700450 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800451 RegLocation rl_method = LoadCurrMethod(cu);
452 rBase = AllocTemp(cu);
453 LoadWordDisp(cu, rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800454 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800455 } else {
Ian Rogersaed07162013-03-15 12:00:53 -0700456 // Medium path, static storage base in a different class which requires checks that the other
457 // class is initialized
458 // TODO: remove initialized check now that we are initializing classes in the compiler driver.
buzbeefa57c472012-11-21 12:06:18 -0800459 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700460 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800461 FlushAllRegs(cu);
Ian Rogersaed07162013-03-15 12:00:53 -0700462 // Using fixed register to sync with possible call to runtime support.
buzbeefa57c472012-11-21 12:06:18 -0800463 int r_method = TargetReg(kArg1);
464 LockTemp(cu, r_method);
465 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800466 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800467 LockTemp(cu, rBase);
468 LoadWordDisp(cu, r_method,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800469 mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700470 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800471 LoadWordDisp(cu, rBase,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800472 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800473 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700474 // rBase now points at appropriate static storage base (Class*)
475 // or NULL if not initialized. Check for NULL and call helper if NULL.
476 // TUNING: fast path should fall through
buzbeefa57c472012-11-21 12:06:18 -0800477 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
478 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
479 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800480 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800481 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700482 }
buzbeefa57c472012-11-21 12:06:18 -0800483 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
484 branch_over->target = skip_target;
485 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800486 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700487 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800488 RegLocation rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
489 if (is_volatile) {
490 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700491 }
buzbeefa57c472012-11-21 12:06:18 -0800492 if (is_long_or_double) {
493 LoadBaseDispWide(cu, rBase, field_offset, rl_result.low_reg,
494 rl_result.high_reg, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700495 } else {
buzbeefa57c472012-11-21 12:06:18 -0800496 LoadWordDisp(cu, rBase, field_offset, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700497 }
buzbeefa57c472012-11-21 12:06:18 -0800498 FreeTemp(cu, rBase);
499 if (is_long_or_double) {
500 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700501 } else {
buzbeefa57c472012-11-21 12:06:18 -0800502 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700503 }
504 } else {
buzbeefa57c472012-11-21 12:06:18 -0800505 FlushAllRegs(cu); // Everything to home locations
506 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Static) :
507 (is_object ? ENTRYPOINT_OFFSET(pGetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700508 : ENTRYPOINT_OFFSET(pGet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800509 CallRuntimeHelperImm(cu, getterOffset, field_idx, true);
510 if (is_long_or_double) {
511 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
512 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700513 } else {
buzbeefa57c472012-11-21 12:06:18 -0800514 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
515 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700516 }
517 }
buzbee31a4a6f2012-02-28 15:36:15 -0800518}
519
520
521// Debugging routine - if null target, branch to DebugMe
buzbee02031b12012-11-23 09:41:35 -0800522void Codegen::GenShowTarget(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800523{
buzbeefa57c472012-11-21 12:06:18 -0800524 DCHECK_NE(cu->instruction_set, kX86) << "unimplemented GenShowTarget";
525 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, TargetReg(kInvokeTgt), 0, NULL);
526 LoadWordDisp(cu, TargetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), TargetReg(kInvokeTgt));
527 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
528 branch_over->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800529}
530
buzbee02031b12012-11-23 09:41:35 -0800531void Codegen::HandleSuspendLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800532{
buzbeefa57c472012-11-21 12:06:18 -0800533 LIR** suspend_label = reinterpret_cast<LIR**>(cu->suspend_launchpads.elem_list);
534 int num_elems = cu->suspend_launchpads.num_used;
535 int helper_offset = ENTRYPOINT_OFFSET(pTestSuspendFromCode);
536 for (int i = 0; i < num_elems; i++) {
537 ResetRegPool(cu);
538 ResetDefTracking(cu);
539 LIR* lab = suspend_label[i];
540 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]);
541 cu->current_dalvik_offset = lab->operands[1];
542 AppendLIR(cu, lab);
543 int r_tgt = CallHelperSetup(cu, helper_offset);
544 CallHelper(cu, r_tgt, helper_offset, true /* MarkSafepointPC */);
545 OpUnconditionalBranch(cu, resume_lab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700546 }
buzbee31a4a6f2012-02-28 15:36:15 -0800547}
548
buzbee02031b12012-11-23 09:41:35 -0800549void Codegen::HandleIntrinsicLaunchPads(CompilationUnit *cu)
buzbeefc9e6fa2012-03-23 15:14:29 -0700550{
buzbeefa57c472012-11-21 12:06:18 -0800551 LIR** intrinsic_label = reinterpret_cast<LIR**>(cu->intrinsic_launchpads.elem_list);
552 int num_elems = cu->intrinsic_launchpads.num_used;
553 for (int i = 0; i < num_elems; i++) {
554 ResetRegPool(cu);
555 ResetDefTracking(cu);
556 LIR* lab = intrinsic_label[i];
buzbeecbd6d442012-11-17 14:11:25 -0800557 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
buzbeefa57c472012-11-21 12:06:18 -0800558 cu->current_dalvik_offset = info->offset;
559 AppendLIR(cu, lab);
buzbee52a77fc2012-11-20 19:50:46 -0800560 // NOTE: GenInvoke handles MarkSafepointPC
buzbeefa57c472012-11-21 12:06:18 -0800561 GenInvoke(cu, info);
562 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]);
563 if (resume_lab != NULL) {
564 OpUnconditionalBranch(cu, resume_lab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700565 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700566 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700567}
568
buzbee02031b12012-11-23 09:41:35 -0800569void Codegen::HandleThrowLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800570{
buzbeefa57c472012-11-21 12:06:18 -0800571 LIR** throw_label = reinterpret_cast<LIR**>(cu->throw_launchpads.elem_list);
572 int num_elems = cu->throw_launchpads.num_used;
573 for (int i = 0; i < num_elems; i++) {
574 ResetRegPool(cu);
575 ResetDefTracking(cu);
576 LIR* lab = throw_label[i];
577 cu->current_dalvik_offset = lab->operands[1];
578 AppendLIR(cu, lab);
579 int func_offset = 0;
Bill Buzbeea114add2012-05-03 15:00:40 -0700580 int v1 = lab->operands[2];
581 int v2 = lab->operands[3];
buzbeefa57c472012-11-21 12:06:18 -0800582 bool target_x86 = (cu->instruction_set == kX86);
Bill Buzbeea114add2012-05-03 15:00:40 -0700583 switch (lab->operands[0]) {
584 case kThrowNullPointer:
buzbeefa57c472012-11-21 12:06:18 -0800585 func_offset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700586 break;
buzbee4ef3e452012-12-14 13:35:28 -0800587 case kThrowConstantArrayBounds: // v1 is length reg (for Arm/Mips), v2 constant index
588 // v1 holds the constant array index. Mips/Arm uses v2 for length, x86 reloads.
589 if (target_x86) {
590 OpRegMem(cu, kOpMov, TargetReg(kArg1), v1, mirror::Array::LengthOffset().Int32Value());
591 } else {
592 OpRegCopy(cu, TargetReg(kArg1), v1);
593 }
594 // Make sure the following LoadConstant doesn't mess with kArg1.
595 LockTemp(cu, TargetReg(kArg1));
596 LoadConstant(cu, TargetReg(kArg0), v2);
597 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
598 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700599 case kThrowArrayBounds:
buzbeef0504cd2012-11-13 16:31:10 -0800600 // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
buzbee52a77fc2012-11-20 19:50:46 -0800601 if (v2 != TargetReg(kArg0)) {
buzbeefa57c472012-11-21 12:06:18 -0800602 OpRegCopy(cu, TargetReg(kArg0), v1);
603 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700604 // x86 leaves the array pointer in v2, so load the array length that the handler expects
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800605 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700606 } else {
buzbeefa57c472012-11-21 12:06:18 -0800607 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700608 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700609 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800610 if (v1 == TargetReg(kArg1)) {
buzbeef0504cd2012-11-13 16:31:10 -0800611 // Swap v1 and v2, using kArg2 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800612 OpRegCopy(cu, TargetReg(kArg2), v1);
613 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700614 // x86 leaves the array pointer in v2; load the array length that the handler expects
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800615 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700616 } else {
buzbeefa57c472012-11-21 12:06:18 -0800617 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700618 }
buzbeefa57c472012-11-21 12:06:18 -0800619 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700620 } else {
buzbeefa57c472012-11-21 12:06:18 -0800621 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700622 // x86 leaves the array pointer in v2; load the array length that the handler expects
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800623 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700624 } else {
buzbeefa57c472012-11-21 12:06:18 -0800625 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700626 }
buzbeefa57c472012-11-21 12:06:18 -0800627 OpRegCopy(cu, TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700628 }
buzbee31a4a6f2012-02-28 15:36:15 -0800629 }
buzbeefa57c472012-11-21 12:06:18 -0800630 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700631 break;
632 case kThrowDivZero:
buzbeefa57c472012-11-21 12:06:18 -0800633 func_offset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700634 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700635 case kThrowNoSuchMethod:
buzbeefa57c472012-11-21 12:06:18 -0800636 OpRegCopy(cu, TargetReg(kArg0), v1);
637 func_offset =
Bill Buzbeea114add2012-05-03 15:00:40 -0700638 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
639 break;
640 case kThrowStackOverflow:
buzbeefa57c472012-11-21 12:06:18 -0800641 func_offset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700642 // Restore stack alignment
buzbeefa57c472012-11-21 12:06:18 -0800643 if (target_x86) {
644 OpRegImm(cu, kOpAdd, TargetReg(kSp), cu->frame_size);
buzbeeb046e162012-10-30 15:48:42 -0700645 } else {
buzbeefa57c472012-11-21 12:06:18 -0800646 OpRegImm(cu, kOpAdd, TargetReg(kSp), (cu->num_core_spills + cu->num_fp_spills) * 4);
buzbeeb046e162012-10-30 15:48:42 -0700647 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700648 break;
649 default:
650 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800651 }
buzbeefa57c472012-11-21 12:06:18 -0800652 ClobberCalleeSave(cu);
653 int r_tgt = CallHelperSetup(cu, func_offset);
654 CallHelper(cu, r_tgt, func_offset, true /* MarkSafepointPC */);
Bill Buzbeea114add2012-05-03 15:00:40 -0700655 }
buzbee31a4a6f2012-02-28 15:36:15 -0800656}
657
buzbee02031b12012-11-23 09:41:35 -0800658void Codegen::GenIGet(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
659 RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
660 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800661{
buzbeefa57c472012-11-21 12:06:18 -0800662 int field_offset;
663 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800664
buzbeefa57c472012-11-21 12:06:18 -0800665 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800666
buzbeefa57c472012-11-21 12:06:18 -0800667 if (fast_path && !SLOW_FIELD_PATH) {
668 RegLocation rl_result;
669 RegisterClass reg_class = oat_reg_class_by_size(size);
670 DCHECK_GE(field_offset, 0);
671 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
672 if (is_long_or_double) {
673 DCHECK(rl_dest.wide);
674 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
675 if (cu->instruction_set == kX86) {
676 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
677 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
678 LoadBaseDispWide(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
679 rl_result.high_reg, rl_obj.s_reg_low);
680 if (is_volatile) {
681 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700682 }
683 } else {
buzbeefa57c472012-11-21 12:06:18 -0800684 int reg_ptr = AllocTemp(cu);
685 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
686 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
buzbeee6285f92012-12-06 15:57:46 -0800687 LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
buzbeefa57c472012-11-21 12:06:18 -0800688 if (is_volatile) {
689 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700690 }
buzbeefa57c472012-11-21 12:06:18 -0800691 FreeTemp(cu, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700692 }
buzbeefa57c472012-11-21 12:06:18 -0800693 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800694 } else {
buzbeefa57c472012-11-21 12:06:18 -0800695 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
696 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
697 LoadBaseDisp(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
698 kWord, rl_obj.s_reg_low);
699 if (is_volatile) {
700 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700701 }
buzbeefa57c472012-11-21 12:06:18 -0800702 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800703 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700704 } else {
buzbeefa57c472012-11-21 12:06:18 -0800705 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Instance) :
706 (is_object ? ENTRYPOINT_OFFSET(pGetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700707 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800708 CallRuntimeHelperImmRegLocation(cu, getterOffset, field_idx, rl_obj, true);
709 if (is_long_or_double) {
710 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
711 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700712 } else {
buzbeefa57c472012-11-21 12:06:18 -0800713 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
714 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700715 }
716 }
buzbee31a4a6f2012-02-28 15:36:15 -0800717}
718
buzbee02031b12012-11-23 09:41:35 -0800719void Codegen::GenIPut(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
720 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
721 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800722{
buzbeefa57c472012-11-21 12:06:18 -0800723 int field_offset;
724 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800725
buzbeefa57c472012-11-21 12:06:18 -0800726 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700727 true);
buzbeefa57c472012-11-21 12:06:18 -0800728 if (fast_path && !SLOW_FIELD_PATH) {
729 RegisterClass reg_class = oat_reg_class_by_size(size);
730 DCHECK_GE(field_offset, 0);
731 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
732 if (is_long_or_double) {
733 int reg_ptr;
734 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
735 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
736 reg_ptr = AllocTemp(cu);
737 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
738 if (is_volatile) {
739 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700740 }
buzbeefa57c472012-11-21 12:06:18 -0800741 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
742 if (is_volatile) {
743 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700744 }
buzbeefa57c472012-11-21 12:06:18 -0800745 FreeTemp(cu, reg_ptr);
buzbee31a4a6f2012-02-28 15:36:15 -0800746 } else {
buzbeefa57c472012-11-21 12:06:18 -0800747 rl_src = LoadValue(cu, rl_src, reg_class);
748 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
749 if (is_volatile) {
750 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700751 }
buzbeefa57c472012-11-21 12:06:18 -0800752 StoreBaseDisp(cu, rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
753 if (is_volatile) {
754 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700755 }
buzbee311ca162013-02-28 15:56:43 -0800756 if (is_object && !cu->mir_graph->IsConstantNullRef(rl_src)) {
buzbeefa57c472012-11-21 12:06:18 -0800757 MarkGCCard(cu, rl_src.low_reg, rl_obj.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700758 }
buzbee31a4a6f2012-02-28 15:36:15 -0800759 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700760 } else {
buzbeefa57c472012-11-21 12:06:18 -0800761 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Instance) :
762 (is_object ? ENTRYPOINT_OFFSET(pSetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700763 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800764 CallRuntimeHelperImmRegLocationRegLocation(cu, setter_offset, field_idx, rl_obj, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700765 }
buzbee31a4a6f2012-02-28 15:36:15 -0800766}
767
buzbee02031b12012-11-23 09:41:35 -0800768void Codegen::GenConstClass(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800769{
buzbeefa57c472012-11-21 12:06:18 -0800770 RegLocation rl_method = LoadCurrMethod(cu);
771 int res_reg = AllocTemp(cu);
772 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Ian Rogers1212a022013-03-04 10:48:41 -0800773 if (!cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800774 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700775 type_idx)) {
776 // Call out to helper which resolves type and verifies access.
buzbeef0504cd2012-11-13 16:31:10 -0800777 // Resolved type returned in kRet0.
buzbeefa57c472012-11-21 12:06:18 -0800778 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
779 type_idx, rl_method.low_reg, true);
780 RegLocation rl_result = GetReturn(cu, false);
781 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700782 } else {
783 // We're don't need access checks, load type from dex cache
784 int32_t dex_cache_offset =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800785 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value();
buzbeefa57c472012-11-21 12:06:18 -0800786 LoadWordDisp(cu, rl_method.low_reg, dex_cache_offset, res_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700787 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800788 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
Bill Buzbeea114add2012-05-03 15:00:40 -0700789 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -0800790 LoadWordDisp(cu, res_reg, offset_of_type, rl_result.low_reg);
Ian Rogers1212a022013-03-04 10:48:41 -0800791 if (!cu->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700792 type_idx) || SLOW_TYPE_PATH) {
793 // Slow path, at runtime test if type is null and if so initialize
buzbeefa57c472012-11-21 12:06:18 -0800794 FlushAllRegs(cu);
795 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, rl_result.low_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700796 // Resolved, store and hop over following code
buzbeefa57c472012-11-21 12:06:18 -0800797 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700798 /*
799 * Because we have stores of the target value on two paths,
800 * clobber temp tracking for the destination using the ssa name
801 */
buzbeefa57c472012-11-21 12:06:18 -0800802 ClobberSReg(cu, rl_dest.s_reg_low);
803 LIR* branch2 = OpUnconditionalBranch(cu,0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700804 // TUNING: move slow path to end & remove unconditional branch
buzbeefa57c472012-11-21 12:06:18 -0800805 LIR* target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeef0504cd2012-11-13 16:31:10 -0800806 // Call out to helper, which will return resolved type in kArg0
buzbeefa57c472012-11-21 12:06:18 -0800807 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
808 rl_method.low_reg, true);
809 RegLocation rl_result = GetReturn(cu, false);
810 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700811 /*
812 * Because we have stores of the target value on two paths,
813 * clobber temp tracking for the destination using the ssa name
814 */
buzbeefa57c472012-11-21 12:06:18 -0800815 ClobberSReg(cu, rl_dest.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -0700816 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -0800817 LIR* target2 = NewLIR0(cu, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800818 branch1->target = target1;
819 branch2->target = target2;
buzbee31a4a6f2012-02-28 15:36:15 -0800820 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700821 // Fast path, we're done - just store result
buzbeefa57c472012-11-21 12:06:18 -0800822 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800823 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700824 }
buzbee31a4a6f2012-02-28 15:36:15 -0800825}
Ian Rogersab2b55d2012-03-18 00:06:11 -0700826
buzbee02031b12012-11-23 09:41:35 -0800827void Codegen::GenConstString(CompilationUnit* cu, uint32_t string_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800828{
Bill Buzbeea114add2012-05-03 15:00:40 -0700829 /* NOTE: Most strings should be available at compile time */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800830 int32_t offset_of_string = mirror::Array::DataOffset(sizeof(mirror::String*)).Int32Value() +
831 (sizeof(mirror::String*) * string_idx);
Ian Rogers1212a022013-03-04 10:48:41 -0800832 if (!cu->compiler_driver->CanAssumeStringIsPresentInDexCache(
buzbeefa57c472012-11-21 12:06:18 -0800833 *cu->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700834 // slow path, resolve string if not in dex cache
buzbeefa57c472012-11-21 12:06:18 -0800835 FlushAllRegs(cu);
836 LockCallTemps(cu); // Using explicit registers
837 LoadCurrMethodDirect(cu, TargetReg(kArg2));
838 LoadWordDisp(cu, TargetReg(kArg2),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800839 mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800840 // Might call out to helper, which will return resolved string in kRet0
buzbeefa57c472012-11-21 12:06:18 -0800841 int r_tgt = CallHelperSetup(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode));
842 LoadWordDisp(cu, TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
843 LoadConstant(cu, TargetReg(kArg1), string_idx);
844 if (cu->instruction_set == kThumb2) {
845 OpRegImm(cu, kOpCmp, TargetReg(kRet0), 0); // Is resolved?
846 GenBarrier(cu);
buzbeeb046e162012-10-30 15:48:42 -0700847 // For testing, always force through helper
848 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee02031b12012-11-23 09:41:35 -0800849 OpIT(cu, kCondEq, "T");
buzbeeb046e162012-10-30 15:48:42 -0700850 }
buzbeefa57c472012-11-21 12:06:18 -0800851 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
852 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt); // .eq, helper(Method*, string_idx)
853 MarkSafepointPC(cu, call_inst);
854 FreeTemp(cu, r_tgt);
855 } else if (cu->instruction_set == kMips) {
856 LIR* branch = OpCmpImmBranch(cu, kCondNe, TargetReg(kRet0), 0, NULL);
857 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
858 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
859 MarkSafepointPC(cu, call_inst);
860 FreeTemp(cu, r_tgt);
861 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
buzbeeb046e162012-10-30 15:48:42 -0700862 branch->target = target;
863 } else {
buzbeefa57c472012-11-21 12:06:18 -0800864 DCHECK_EQ(cu->instruction_set, kX86);
865 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true);
buzbee31a4a6f2012-02-28 15:36:15 -0800866 }
buzbeefa57c472012-11-21 12:06:18 -0800867 GenBarrier(cu);
868 StoreValue(cu, rl_dest, GetReturn(cu, false));
Bill Buzbeea114add2012-05-03 15:00:40 -0700869 } else {
buzbeefa57c472012-11-21 12:06:18 -0800870 RegLocation rl_method = LoadCurrMethod(cu);
871 int res_reg = AllocTemp(cu);
872 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
873 LoadWordDisp(cu, rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800874 mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), res_reg);
buzbeefa57c472012-11-21 12:06:18 -0800875 LoadWordDisp(cu, res_reg, offset_of_string, rl_result.low_reg);
876 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700877 }
buzbee31a4a6f2012-02-28 15:36:15 -0800878}
879
880/*
881 * Let helper function take care of everything. Will
882 * call Class::NewInstanceFromCode(type_idx, method);
883 */
buzbee02031b12012-11-23 09:41:35 -0800884void Codegen::GenNewInstance(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800885{
buzbeefa57c472012-11-21 12:06:18 -0800886 FlushAllRegs(cu); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700887 // alloc will always check for resolution, do we also need to verify
888 // access because the verifier was unable to?
buzbeefa57c472012-11-21 12:06:18 -0800889 int func_offset;
Ian Rogers1212a022013-03-04 10:48:41 -0800890 if (cu->compiler_driver->CanAccessInstantiableTypeWithoutChecks(
buzbeefa57c472012-11-21 12:06:18 -0800891 cu->method_idx, *cu->dex_file, type_idx)) {
892 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700893 } else {
buzbeefa57c472012-11-21 12:06:18 -0800894 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700895 }
buzbeefa57c472012-11-21 12:06:18 -0800896 CallRuntimeHelperImmMethod(cu, func_offset, type_idx, true);
897 RegLocation rl_result = GetReturn(cu, false);
898 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800899}
900
buzbee02031b12012-11-23 09:41:35 -0800901void Codegen::GenThrow(CompilationUnit* cu, RegLocation rl_src)
Ian Rogersab2b55d2012-03-18 00:06:11 -0700902{
buzbeefa57c472012-11-21 12:06:18 -0800903 FlushAllRegs(cu);
904 CallRuntimeHelperRegLocation(cu, ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700905}
906
buzbee02031b12012-11-23 09:41:35 -0800907void Codegen::GenInstanceof(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
908 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800909{
buzbeefa57c472012-11-21 12:06:18 -0800910 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700911 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -0800912 LockCallTemps(cu);
913 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
914 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
Ian Rogers1212a022013-03-04 10:48:41 -0800915 if (!cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800916 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700917 type_idx)) {
918 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -0800919 // returns Class* in kArg0
buzbeefa57c472012-11-21 12:06:18 -0800920 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -0700921 type_idx, true);
buzbeefa57c472012-11-21 12:06:18 -0800922 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
923 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -0700924 } else {
buzbeefa57c472012-11-21 12:06:18 -0800925 // Load dex cache entry into class_reg (kArg2)
926 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
927 LoadWordDisp(cu, TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800928 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700929 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800930 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
Bill Buzbeea114add2012-05-03 15:00:40 -0700931 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -0800932 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
Ian Rogers1212a022013-03-04 10:48:41 -0800933 if (!cu->compiler_driver->CanAssumeTypeIsPresentInDexCache(
buzbeefa57c472012-11-21 12:06:18 -0800934 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700935 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -0800936 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700937 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -0800938 // Call out to helper, which will return resolved type in kRet0
buzbeefa57c472012-11-21 12:06:18 -0800939 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
940 OpRegCopy(cu, TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
941 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -0700942 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -0800943 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
944 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -0800945 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700946 }
buzbeef0504cd2012-11-13 16:31:10 -0800947 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
buzbeefa57c472012-11-21 12:06:18 -0800948 RegLocation rl_result = GetReturn(cu, false);
949 if (cu->instruction_set == kMips) {
950 LoadConstant(cu, rl_result.low_reg, 0); // store false result for if branch is taken
buzbeeb046e162012-10-30 15:48:42 -0700951 }
buzbeefa57c472012-11-21 12:06:18 -0800952 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700953 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800954 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
955 LoadWordDisp(cu, TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -0800956 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbeefa57c472012-11-21 12:06:18 -0800957 LIR* call_inst;
buzbeeb046e162012-10-30 15:48:42 -0700958 LIR* branchover = NULL;
buzbeefa57c472012-11-21 12:06:18 -0800959 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700960 /* Uses conditional nullification */
buzbeefa57c472012-11-21 12:06:18 -0800961 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
962 OpRegReg(cu, kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
buzbee02031b12012-11-23 09:41:35 -0800963 OpIT(cu, kCondEq, "EE"); // if-convert the test
buzbeefa57c472012-11-21 12:06:18 -0800964 LoadConstant(cu, TargetReg(kArg0), 1); // .eq case - load true
965 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
966 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
967 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700968 } else {
969 /* Uses branchovers */
buzbeefa57c472012-11-21 12:06:18 -0800970 LoadConstant(cu, rl_result.low_reg, 1); // assume true
971 branchover = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
972 if (cu->instruction_set != kX86) {
973 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
974 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
975 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
976 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700977 } else {
buzbeefa57c472012-11-21 12:06:18 -0800978 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
979 call_inst = OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
buzbeeb046e162012-10-30 15:48:42 -0700980 }
981 }
buzbeefa57c472012-11-21 12:06:18 -0800982 MarkSafepointPC(cu, call_inst);
983 ClobberCalleeSave(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700984 /* branch targets here */
buzbeefa57c472012-11-21 12:06:18 -0800985 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
986 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700987 branch1->target = target;
buzbeefa57c472012-11-21 12:06:18 -0800988 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700989 branchover->target = target;
990 }
buzbee31a4a6f2012-02-28 15:36:15 -0800991}
992
buzbee02031b12012-11-23 09:41:35 -0800993void Codegen::GenCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800994{
buzbeefa57c472012-11-21 12:06:18 -0800995 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700996 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -0800997 LockCallTemps(cu);
998 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
999 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
Ian Rogers1212a022013-03-04 10:48:41 -08001000 if (!cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx,
buzbeefa57c472012-11-21 12:06:18 -08001001 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001002 type_idx)) {
1003 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -08001004 // returns Class* in kRet0
Bill Buzbeea114add2012-05-03 15:00:40 -07001005 // InitializeTypeAndVerifyAccess(idx, method)
buzbeefa57c472012-11-21 12:06:18 -08001006 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee52a77fc2012-11-20 19:50:46 -08001007 type_idx, TargetReg(kArg1), true);
buzbeefa57c472012-11-21 12:06:18 -08001008 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001009 } else {
buzbeefa57c472012-11-21 12:06:18 -08001010 // Load dex cache entry into class_reg (kArg2)
1011 LoadWordDisp(cu, TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001012 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001013 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001014 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
1015 (sizeof(mirror::Class*) * type_idx);
buzbeefa57c472012-11-21 12:06:18 -08001016 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
Ian Rogers1212a022013-03-04 10:48:41 -08001017 if (!cu->compiler_driver->CanAssumeTypeIsPresentInDexCache(
buzbeefa57c472012-11-21 12:06:18 -08001018 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001019 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -08001020 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001021 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001022 // Call out to helper, which will return resolved type in kArg0
Bill Buzbeea114add2012-05-03 15:00:40 -07001023 // InitializeTypeFromCode(idx, method)
buzbeefa57c472012-11-21 12:06:18 -08001024 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001025 true);
buzbeefa57c472012-11-21 12:06:18 -08001026 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001027 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -08001028 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
1029 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -08001030 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001031 }
buzbeefa57c472012-11-21 12:06:18 -08001032 // At this point, class_reg (kArg2) has class
1033 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001034 /* Null is OK - continue */
buzbeefa57c472012-11-21 12:06:18 -08001035 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001036 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001037 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
1038 LoadWordDisp(cu, TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001039 /* kArg1 now contains object->klass_ */
buzbeeb046e162012-10-30 15:48:42 -07001040 LIR* branch2;
buzbeefa57c472012-11-21 12:06:18 -08001041 if (cu->instruction_set == kThumb2) {
1042 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1043 OpRegReg(cu, kOpCmp, TargetReg(kArg1), class_reg);
1044 branch2 = OpCondBranch(cu, kCondEq, NULL); /* If eq, trivial yes */
1045 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg1));
1046 OpRegCopy(cu, TargetReg(kArg1), TargetReg(kArg2));
1047 ClobberCalleeSave(cu);
1048 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
1049 MarkSafepointPC(cu, call_inst);
1050 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001051 } else {
buzbeefa57c472012-11-21 12:06:18 -08001052 branch2 = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), class_reg, NULL);
1053 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
buzbeeb046e162012-10-30 15:48:42 -07001054 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001055 /* branch target here */
buzbeefa57c472012-11-21 12:06:18 -08001056 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001057 branch1->target = target;
1058 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001059}
1060
buzbee02031b12012-11-23 09:41:35 -08001061void Codegen::GenLong3Addr(CompilationUnit* cu, OpKind first_op, OpKind second_op,
1062 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001063{
buzbeefa57c472012-11-21 12:06:18 -08001064 RegLocation rl_result;
1065 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001066 /*
1067 * NOTE: This is the one place in the code in which we might have
1068 * as many as six live temporary registers. There are 5 in the normal
1069 * set for Arm. Until we have spill capabilities, temporarily add
1070 * lr to the temp set. It is safe to do this locally, but note that
1071 * lr is used explicitly elsewhere in the code generator and cannot
1072 * normally be used as a general temp register.
1073 */
buzbeefa57c472012-11-21 12:06:18 -08001074 MarkTemp(cu, TargetReg(kLr)); // Add lr to the temp pool
1075 FreeTemp(cu, TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001076 }
buzbeefa57c472012-11-21 12:06:18 -08001077 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1078 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
1079 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001080 // The longs may overlap - use intermediate temp if so
buzbeefa57c472012-11-21 12:06:18 -08001081 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)){
1082 int t_reg = AllocTemp(cu);
1083 OpRegRegReg(cu, first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1084 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1085 OpRegCopy(cu, rl_result.low_reg, t_reg);
1086 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001087 } else {
buzbeefa57c472012-11-21 12:06:18 -08001088 OpRegRegReg(cu, first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1089 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg,
1090 rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001091 }
1092 /*
buzbeefa57c472012-11-21 12:06:18 -08001093 * NOTE: If rl_dest refers to a frame variable in a large frame, the
buzbee52a77fc2012-11-20 19:50:46 -08001094 * following StoreValueWide might need to allocate a temp register.
Bill Buzbeea114add2012-05-03 15:00:40 -07001095 * To further work around the lack of a spill capability, explicitly
buzbeefa57c472012-11-21 12:06:18 -08001096 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
Bill Buzbeea114add2012-05-03 15:00:40 -07001097 * Remove when spill is functional.
1098 */
buzbeefa57c472012-11-21 12:06:18 -08001099 FreeRegLocTemps(cu, rl_result, rl_src1);
1100 FreeRegLocTemps(cu, rl_result, rl_src2);
1101 StoreValueWide(cu, rl_dest, rl_result);
1102 if (cu->instruction_set == kThumb2) {
1103 Clobber(cu, TargetReg(kLr));
1104 UnmarkTemp(cu, TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001105 }
buzbee31a4a6f2012-02-28 15:36:15 -08001106}
1107
1108
buzbeea5954be2013-02-07 10:41:40 -08001109void Codegen::GenShiftOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001110 RegLocation rl_src1, RegLocation rl_shift)
buzbee31a4a6f2012-02-28 15:36:15 -08001111{
buzbeea5954be2013-02-07 10:41:40 -08001112 int func_offset = -1; // Make gcc happy
buzbee31a4a6f2012-02-28 15:36:15 -08001113
buzbee408ad162012-06-06 16:45:18 -07001114 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001115 case Instruction::SHL_LONG:
1116 case Instruction::SHL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001117 func_offset = ENTRYPOINT_OFFSET(pShlLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001118 break;
1119 case Instruction::SHR_LONG:
1120 case Instruction::SHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001121 func_offset = ENTRYPOINT_OFFSET(pShrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001122 break;
1123 case Instruction::USHR_LONG:
1124 case Instruction::USHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001125 func_offset = ENTRYPOINT_OFFSET(pUshrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001126 break;
1127 default:
1128 LOG(FATAL) << "Unexpected case";
Bill Buzbeea114add2012-05-03 15:00:40 -07001129 }
buzbeefa57c472012-11-21 12:06:18 -08001130 FlushAllRegs(cu); /* Send everything to home location */
1131 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_shift, false);
1132 RegLocation rl_result = GetReturnWide(cu, false);
1133 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001134}
1135
1136
buzbeea5954be2013-02-07 10:41:40 -08001137void Codegen::GenArithOpInt(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001138 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001139{
Bill Buzbeea114add2012-05-03 15:00:40 -07001140 OpKind op = kOpBkpt;
buzbeefa57c472012-11-21 12:06:18 -08001141 bool is_div_rem = false;
1142 bool check_zero = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001143 bool unary = false;
buzbeefa57c472012-11-21 12:06:18 -08001144 RegLocation rl_result;
1145 bool shift_op = false;
buzbee408ad162012-06-06 16:45:18 -07001146 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001147 case Instruction::NEG_INT:
1148 op = kOpNeg;
1149 unary = true;
1150 break;
1151 case Instruction::NOT_INT:
1152 op = kOpMvn;
1153 unary = true;
1154 break;
1155 case Instruction::ADD_INT:
1156 case Instruction::ADD_INT_2ADDR:
1157 op = kOpAdd;
1158 break;
1159 case Instruction::SUB_INT:
1160 case Instruction::SUB_INT_2ADDR:
1161 op = kOpSub;
1162 break;
1163 case Instruction::MUL_INT:
1164 case Instruction::MUL_INT_2ADDR:
1165 op = kOpMul;
1166 break;
1167 case Instruction::DIV_INT:
1168 case Instruction::DIV_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001169 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001170 op = kOpDiv;
buzbeefa57c472012-11-21 12:06:18 -08001171 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001172 break;
buzbeef0504cd2012-11-13 16:31:10 -08001173 /* NOTE: returns in kArg1 */
Bill Buzbeea114add2012-05-03 15:00:40 -07001174 case Instruction::REM_INT:
1175 case Instruction::REM_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001176 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001177 op = kOpRem;
buzbeefa57c472012-11-21 12:06:18 -08001178 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001179 break;
1180 case Instruction::AND_INT:
1181 case Instruction::AND_INT_2ADDR:
1182 op = kOpAnd;
1183 break;
1184 case Instruction::OR_INT:
1185 case Instruction::OR_INT_2ADDR:
1186 op = kOpOr;
1187 break;
1188 case Instruction::XOR_INT:
1189 case Instruction::XOR_INT_2ADDR:
1190 op = kOpXor;
1191 break;
1192 case Instruction::SHL_INT:
1193 case Instruction::SHL_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001194 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001195 op = kOpLsl;
1196 break;
1197 case Instruction::SHR_INT:
1198 case Instruction::SHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001199 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001200 op = kOpAsr;
1201 break;
1202 case Instruction::USHR_INT:
1203 case Instruction::USHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001204 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001205 op = kOpLsr;
1206 break;
1207 default:
buzbeecbd6d442012-11-17 14:11:25 -08001208 LOG(FATAL) << "Invalid word arith op: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001209 }
buzbeefa57c472012-11-21 12:06:18 -08001210 if (!is_div_rem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 if (unary) {
buzbeefa57c472012-11-21 12:06:18 -08001212 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1213 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1214 OpRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg);
buzbee31a4a6f2012-02-28 15:36:15 -08001215 } else {
buzbeefa57c472012-11-21 12:06:18 -08001216 if (shift_op) {
1217 int t_reg = INVALID_REG;
1218 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001219 // X86 doesn't require masking and must use ECX
buzbeefa57c472012-11-21 12:06:18 -08001220 t_reg = TargetReg(kCount); // rCX
1221 LoadValueDirectFixed(cu, rl_src2, t_reg);
buzbeeb046e162012-10-30 15:48:42 -07001222 } else {
buzbeefa57c472012-11-21 12:06:18 -08001223 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1224 t_reg = AllocTemp(cu);
1225 OpRegRegImm(cu, kOpAnd, t_reg, rl_src2.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001226 }
buzbeefa57c472012-11-21 12:06:18 -08001227 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1228 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1229 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1230 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001231 } else {
buzbeefa57c472012-11-21 12:06:18 -08001232 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1233 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1234 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1235 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001236 }
buzbee31a4a6f2012-02-28 15:36:15 -08001237 }
buzbeefa57c472012-11-21 12:06:18 -08001238 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001239 } else {
buzbeefa57c472012-11-21 12:06:18 -08001240 if (cu->instruction_set == kMips) {
1241 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1242 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1243 if (check_zero) {
1244 GenImmedCheck(cu, kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001245 }
buzbeefa57c472012-11-21 12:06:18 -08001246 rl_result = GenDivRem(cu, rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001247 } else {
buzbeefa57c472012-11-21 12:06:18 -08001248 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1249 FlushAllRegs(cu); /* Send everything to home location */
1250 LoadValueDirectFixed(cu, rl_src2, TargetReg(kArg1));
1251 int r_tgt = CallHelperSetup(cu, func_offset);
1252 LoadValueDirectFixed(cu, rl_src1, TargetReg(kArg0));
1253 if (check_zero) {
1254 GenImmedCheck(cu, kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001255 }
1256 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001257 CallHelper(cu, r_tgt, func_offset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001258 if (op == kOpDiv)
buzbeefa57c472012-11-21 12:06:18 -08001259 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001260 else
buzbeefa57c472012-11-21 12:06:18 -08001261 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001262 }
buzbeefa57c472012-11-21 12:06:18 -08001263 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001264 }
buzbee31a4a6f2012-02-28 15:36:15 -08001265}
1266
1267/*
1268 * The following are the first-level codegen routines that analyze the format
1269 * of each bytecode then either dispatch special purpose codegen routines
1270 * or produce corresponding Thumb instructions directly.
1271 */
1272
buzbeeaad94382012-11-21 07:40:50 -08001273static bool IsPowerOfTwo(int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001274{
Bill Buzbeea114add2012-05-03 15:00:40 -07001275 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001276}
1277
1278// Returns true if no more than two bits are set in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001279static bool IsPopCountLE2(unsigned int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001280{
Bill Buzbeea114add2012-05-03 15:00:40 -07001281 x &= x - 1;
1282 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001283}
1284
1285// Returns the index of the lowest set bit in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001286static int LowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001287 int bit_posn = 0;
1288 while ((x & 0xf) == 0) {
1289 bit_posn += 4;
1290 x >>= 4;
1291 }
1292 while ((x & 1) == 0) {
1293 bit_posn++;
1294 x >>= 1;
1295 }
1296 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001297}
1298
buzbeefa57c472012-11-21 12:06:18 -08001299// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1300// and store the result in 'rl_dest'.
1301static bool HandleEasyDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
1302 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001303{
buzbeefa57c472012-11-21 12:06:18 -08001304 if ((lit < 2) || ((cu->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001305 return false;
buzbee0f79d722012-11-01 15:35:27 -07001306 }
buzbee02031b12012-11-23 09:41:35 -08001307 Codegen* cg = cu->cg.get();
buzbeeb046e162012-10-30 15:48:42 -07001308 // No divide instruction for Arm, so check for more special cases
buzbeefa57c472012-11-21 12:06:18 -08001309 if ((cu->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
buzbee02031b12012-11-23 09:41:35 -08001310 return cg->SmallLiteralDivide(cu, dalvik_opcode, rl_src, rl_dest, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001311 }
buzbee52a77fc2012-11-20 19:50:46 -08001312 int k = LowestSetBit(lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001313 if (k >= 30) {
1314 // Avoid special cases.
1315 return false;
1316 }
buzbeefa57c472012-11-21 12:06:18 -08001317 bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
1318 dalvik_opcode == Instruction::DIV_INT_LIT16);
buzbee02031b12012-11-23 09:41:35 -08001319 rl_src = cg->LoadValue(cu, rl_src, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001320 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001321 if (div) {
buzbeefa57c472012-11-21 12:06:18 -08001322 int t_reg = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001323 if (lit == 2) {
1324 // Division by 2 is by far the most common division by constant.
buzbee02031b12012-11-23 09:41:35 -08001325 cg->OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1326 cg->OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1327 cg->OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001328 } else {
buzbee02031b12012-11-23 09:41:35 -08001329 cg->OpRegRegImm(cu, kOpAsr, t_reg, rl_src.low_reg, 31);
1330 cg->OpRegRegImm(cu, kOpLsr, t_reg, t_reg, 32 - k);
1331 cg->OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1332 cg->OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001333 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001334 } else {
buzbeefa57c472012-11-21 12:06:18 -08001335 int t_reg1 = AllocTemp(cu);
1336 int t_reg2 = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001337 if (lit == 2) {
buzbee02031b12012-11-23 09:41:35 -08001338 cg->OpRegRegImm(cu, kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1339 cg->OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1340 cg->OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit -1);
1341 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001342 } else {
buzbee02031b12012-11-23 09:41:35 -08001343 cg->OpRegRegImm(cu, kOpAsr, t_reg1, rl_src.low_reg, 31);
1344 cg->OpRegRegImm(cu, kOpLsr, t_reg1, t_reg1, 32 - k);
1345 cg->OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1346 cg->OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit - 1);
1347 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001348 }
1349 }
buzbee02031b12012-11-23 09:41:35 -08001350 cg->StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001351 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001352}
1353
buzbeefa57c472012-11-21 12:06:18 -08001354// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1355// and store the result in 'rl_dest'.
1356static bool HandleEasyMultiply(CompilationUnit* cu, RegLocation rl_src,
1357 RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001358{
Bill Buzbeea114add2012-05-03 15:00:40 -07001359 // Can we simplify this multiplication?
buzbeefa57c472012-11-21 12:06:18 -08001360 bool power_of_two = false;
1361 bool pop_count_le2 = false;
1362 bool power_of_two_minus_one = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001363 if (lit < 2) {
1364 // Avoid special cases.
1365 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001366 } else if (IsPowerOfTwo(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001367 power_of_two = true;
buzbee52a77fc2012-11-20 19:50:46 -08001368 } else if (IsPopCountLE2(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001369 pop_count_le2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001370 } else if (IsPowerOfTwo(lit + 1)) {
buzbeefa57c472012-11-21 12:06:18 -08001371 power_of_two_minus_one = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001372 } else {
1373 return false;
1374 }
buzbee02031b12012-11-23 09:41:35 -08001375 Codegen* cg = cu->cg.get();
1376 rl_src = cg->LoadValue(cu, rl_src, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001377 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1378 if (power_of_two) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001379 // Shift.
buzbee02031b12012-11-23 09:41:35 -08001380 cg->OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit));
buzbeefa57c472012-11-21 12:06:18 -08001381 } else if (pop_count_le2) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001382 // Shift and add and shift.
buzbeefa57c472012-11-21 12:06:18 -08001383 int first_bit = LowestSetBit(lit);
1384 int second_bit = LowestSetBit(lit ^ (1 << first_bit));
buzbee02031b12012-11-23 09:41:35 -08001385 cg->GenMultiplyByTwoBitMultiplier(cu, rl_src, rl_result, lit, first_bit, second_bit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001386 } else {
1387 // Reverse subtract: (src << (shift + 1)) - src.
buzbeefa57c472012-11-21 12:06:18 -08001388 DCHECK(power_of_two_minus_one);
buzbee52a77fc2012-11-20 19:50:46 -08001389 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
buzbeefa57c472012-11-21 12:06:18 -08001390 int t_reg = AllocTemp(cu);
buzbee02031b12012-11-23 09:41:35 -08001391 cg->OpRegRegImm(cu, kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1392 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001393 }
buzbee02031b12012-11-23 09:41:35 -08001394 cg->StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001395 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001396}
1397
buzbeea5954be2013-02-07 10:41:40 -08001398void Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode,
buzbee02031b12012-11-23 09:41:35 -08001399 RegLocation rl_dest, RegLocation rl_src, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001400{
buzbeefa57c472012-11-21 12:06:18 -08001401 RegLocation rl_result;
buzbeecbd6d442012-11-17 14:11:25 -08001402 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
buzbeefa57c472012-11-21 12:06:18 -08001403 int shift_op = false;
1404 bool is_div = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001405
buzbee408ad162012-06-06 16:45:18 -07001406 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001407 case Instruction::RSUB_INT_LIT8:
1408 case Instruction::RSUB_INT: {
buzbeefa57c472012-11-21 12:06:18 -08001409 rl_src = LoadValue(cu, rl_src, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001410 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeec7d1f912013-02-07 15:22:39 -08001411 if (cu->instruction_set == kThumb2) {
1412 OpRegRegImm(cu, kOpRsub, rl_result.low_reg, rl_src.low_reg, lit);
1413 } else {
1414 OpRegReg(cu, kOpNeg, rl_result.low_reg, rl_src.low_reg);
1415 OpRegImm(cu, kOpAdd, rl_result.low_reg, lit);
1416 }
buzbeefa57c472012-11-21 12:06:18 -08001417 StoreValue(cu, rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001418 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001419 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001420
buzbeee6285f92012-12-06 15:57:46 -08001421 case Instruction::SUB_INT:
1422 case Instruction::SUB_INT_2ADDR:
1423 lit = -lit;
1424 // Intended fallthrough
1425 case Instruction::ADD_INT:
1426 case Instruction::ADD_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001427 case Instruction::ADD_INT_LIT8:
1428 case Instruction::ADD_INT_LIT16:
1429 op = kOpAdd;
1430 break;
buzbeee6285f92012-12-06 15:57:46 -08001431 case Instruction::MUL_INT:
1432 case Instruction::MUL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001433 case Instruction::MUL_INT_LIT8:
1434 case Instruction::MUL_INT_LIT16: {
buzbeefa57c472012-11-21 12:06:18 -08001435 if (HandleEasyMultiply(cu, rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001436 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001437 }
1438 op = kOpMul;
1439 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001440 }
buzbeee6285f92012-12-06 15:57:46 -08001441 case Instruction::AND_INT:
1442 case Instruction::AND_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001443 case Instruction::AND_INT_LIT8:
1444 case Instruction::AND_INT_LIT16:
1445 op = kOpAnd;
1446 break;
buzbeee6285f92012-12-06 15:57:46 -08001447 case Instruction::OR_INT:
1448 case Instruction::OR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001449 case Instruction::OR_INT_LIT8:
1450 case Instruction::OR_INT_LIT16:
1451 op = kOpOr;
1452 break;
buzbeee6285f92012-12-06 15:57:46 -08001453 case Instruction::XOR_INT:
1454 case Instruction::XOR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001455 case Instruction::XOR_INT_LIT8:
1456 case Instruction::XOR_INT_LIT16:
1457 op = kOpXor;
1458 break;
1459 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001460 case Instruction::SHL_INT:
buzbeee6285f92012-12-06 15:57:46 -08001461 case Instruction::SHL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001462 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001463 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001464 op = kOpLsl;
1465 break;
1466 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001467 case Instruction::SHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001468 case Instruction::SHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001469 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001470 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001471 op = kOpAsr;
1472 break;
1473 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001474 case Instruction::USHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001475 case Instruction::USHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001476 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001477 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001478 op = kOpLsr;
1479 break;
1480
buzbeee6285f92012-12-06 15:57:46 -08001481 case Instruction::DIV_INT:
1482 case Instruction::DIV_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001483 case Instruction::DIV_INT_LIT8:
1484 case Instruction::DIV_INT_LIT16:
buzbeee6285f92012-12-06 15:57:46 -08001485 case Instruction::REM_INT:
1486 case Instruction::REM_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001487 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07001488 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07001489 if (lit == 0) {
buzbeefa57c472012-11-21 12:06:18 -08001490 GenImmedCheck(cu, kCondAl, 0, 0, kThrowDivZero);
buzbeea5954be2013-02-07 10:41:40 -08001491 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001492 }
buzbeefa57c472012-11-21 12:06:18 -08001493 if (HandleEasyDivide(cu, opcode, rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001494 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001495 }
buzbee408ad162012-06-06 16:45:18 -07001496 if ((opcode == Instruction::DIV_INT_LIT8) ||
buzbeee6285f92012-12-06 15:57:46 -08001497 (opcode == Instruction::DIV_INT) ||
1498 (opcode == Instruction::DIV_INT_2ADDR) ||
buzbee408ad162012-06-06 16:45:18 -07001499 (opcode == Instruction::DIV_INT_LIT16)) {
buzbeefa57c472012-11-21 12:06:18 -08001500 is_div = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001501 } else {
buzbeefa57c472012-11-21 12:06:18 -08001502 is_div = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001503 }
buzbeefa57c472012-11-21 12:06:18 -08001504 if (cu->instruction_set == kMips) {
1505 rl_src = LoadValue(cu, rl_src, kCoreReg);
1506 rl_result = GenDivRemLit(cu, rl_dest, rl_src.low_reg, lit, is_div);
jeffhao4f8f04a2012-10-02 18:10:35 -07001507 } else {
buzbeefa57c472012-11-21 12:06:18 -08001508 FlushAllRegs(cu); /* Everything to home location */
1509 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0));
1510 Clobber(cu, TargetReg(kArg0));
1511 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1512 CallRuntimeHelperRegImm(cu, func_offset, TargetReg(kArg0), lit, false);
1513 if (is_div)
1514 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001515 else
buzbeefa57c472012-11-21 12:06:18 -08001516 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001517 }
buzbeefa57c472012-11-21 12:06:18 -08001518 StoreValue(cu, rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001519 return;
jeffhao4f8f04a2012-10-02 18:10:35 -07001520 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001521 default:
buzbeee6285f92012-12-06 15:57:46 -08001522 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001523 }
buzbeefa57c472012-11-21 12:06:18 -08001524 rl_src = LoadValue(cu, rl_src, kCoreReg);
1525 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001526 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
buzbeefa57c472012-11-21 12:06:18 -08001527 if (shift_op && (lit == 0)) {
1528 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001529 } else {
buzbeefa57c472012-11-21 12:06:18 -08001530 OpRegRegImm(cu, op, rl_result.low_reg, rl_src.low_reg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001531 }
buzbeefa57c472012-11-21 12:06:18 -08001532 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001533}
1534
buzbeea5954be2013-02-07 10:41:40 -08001535void Codegen::GenArithOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001536 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001537{
buzbeefa57c472012-11-21 12:06:18 -08001538 RegLocation rl_result;
1539 OpKind first_op = kOpBkpt;
1540 OpKind second_op = kOpBkpt;
1541 bool call_out = false;
1542 bool check_zero = false;
1543 int func_offset;
1544 int ret_reg = TargetReg(kRet0);
buzbee31a4a6f2012-02-28 15:36:15 -08001545
buzbee408ad162012-06-06 16:45:18 -07001546 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001547 case Instruction::NOT_LONG:
buzbeefa57c472012-11-21 12:06:18 -08001548 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
1549 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001550 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -08001551 if (rl_result.low_reg == rl_src2.high_reg) {
1552 int t_reg = AllocTemp(cu);
1553 OpRegCopy(cu, t_reg, rl_src2.high_reg);
1554 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1555 OpRegReg(cu, kOpMvn, rl_result.high_reg, t_reg);
1556 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001557 } else {
buzbeefa57c472012-11-21 12:06:18 -08001558 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1559 OpRegReg(cu, kOpMvn, rl_result.high_reg, rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001560 }
buzbeefa57c472012-11-21 12:06:18 -08001561 StoreValueWide(cu, rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001562 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001563 case Instruction::ADD_LONG:
1564 case Instruction::ADD_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001565 if (cu->instruction_set != kThumb2) {
buzbeea5954be2013-02-07 10:41:40 -08001566 GenAddLong(cu, rl_dest, rl_src1, rl_src2);
1567 return;
buzbeeb046e162012-10-30 15:48:42 -07001568 }
buzbeefa57c472012-11-21 12:06:18 -08001569 first_op = kOpAdd;
1570 second_op = kOpAdc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001571 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001572 case Instruction::SUB_LONG:
1573 case Instruction::SUB_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001574 if (cu->instruction_set != kThumb2) {
buzbeea5954be2013-02-07 10:41:40 -08001575 GenSubLong(cu, rl_dest, rl_src1, rl_src2);
1576 return;
buzbeeb046e162012-10-30 15:48:42 -07001577 }
buzbeefa57c472012-11-21 12:06:18 -08001578 first_op = kOpSub;
1579 second_op = kOpSbc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001580 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 case Instruction::MUL_LONG:
1582 case Instruction::MUL_LONG_2ADDR:
buzbee4ef3e452012-12-14 13:35:28 -08001583 if (cu->instruction_set == kThumb2) {
1584 GenMulLong(cu, rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001585 return;
buzbee4ef3e452012-12-14 13:35:28 -08001586 } else {
1587 call_out = true;
1588 ret_reg = TargetReg(kRet0);
1589 func_offset = ENTRYPOINT_OFFSET(pLmul);
1590 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001591 break;
1592 case Instruction::DIV_LONG:
1593 case Instruction::DIV_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001594 call_out = true;
1595 check_zero = true;
1596 ret_reg = TargetReg(kRet0);
1597 func_offset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07001598 break;
1599 case Instruction::REM_LONG:
1600 case Instruction::REM_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001601 call_out = true;
1602 check_zero = true;
1603 func_offset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08001604 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbeefa57c472012-11-21 12:06:18 -08001605 ret_reg = (cu->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001606 break;
1607 case Instruction::AND_LONG_2ADDR:
1608 case Instruction::AND_LONG:
buzbeefa57c472012-11-21 12:06:18 -08001609 if (cu->instruction_set == kX86) {
1610 return GenAndLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001611 }
buzbeefa57c472012-11-21 12:06:18 -08001612 first_op = kOpAnd;
1613 second_op = kOpAnd;
Bill Buzbeea114add2012-05-03 15:00:40 -07001614 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001615 case Instruction::OR_LONG:
1616 case Instruction::OR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001617 if (cu->instruction_set == kX86) {
buzbeea5954be2013-02-07 10:41:40 -08001618 GenOrLong(cu, rl_dest, rl_src1, rl_src2);
1619 return;
buzbeeb046e162012-10-30 15:48:42 -07001620 }
buzbeefa57c472012-11-21 12:06:18 -08001621 first_op = kOpOr;
1622 second_op = kOpOr;
Bill Buzbeea114add2012-05-03 15:00:40 -07001623 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001624 case Instruction::XOR_LONG:
1625 case Instruction::XOR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001626 if (cu->instruction_set == kX86) {
buzbeea5954be2013-02-07 10:41:40 -08001627 GenXorLong(cu, rl_dest, rl_src1, rl_src2);
1628 return;
buzbeeb046e162012-10-30 15:48:42 -07001629 }
buzbeefa57c472012-11-21 12:06:18 -08001630 first_op = kOpXor;
1631 second_op = kOpXor;
Bill Buzbeea114add2012-05-03 15:00:40 -07001632 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001633 case Instruction::NEG_LONG: {
buzbeea5954be2013-02-07 10:41:40 -08001634 GenNegLong(cu, rl_dest, rl_src2);
1635 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001636 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001637 default:
1638 LOG(FATAL) << "Invalid long arith op";
1639 }
buzbeefa57c472012-11-21 12:06:18 -08001640 if (!call_out) {
1641 GenLong3Addr(cu, first_op, second_op, rl_dest, rl_src1, rl_src2);
Bill Buzbeea114add2012-05-03 15:00:40 -07001642 } else {
buzbeefa57c472012-11-21 12:06:18 -08001643 FlushAllRegs(cu); /* Send everything to home location */
1644 if (check_zero) {
1645 LoadValueDirectWideFixed(cu, rl_src2, TargetReg(kArg2), TargetReg(kArg3));
1646 int r_tgt = CallHelperSetup(cu, func_offset);
1647 GenDivZeroCheck(cu, TargetReg(kArg2), TargetReg(kArg3));
1648 LoadValueDirectWideFixed(cu, rl_src1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07001649 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001650 CallHelper(cu, r_tgt, func_offset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08001651 } else {
buzbeefa57c472012-11-21 12:06:18 -08001652 CallRuntimeHelperRegLocationRegLocation(cu, func_offset,
1653 rl_src1, rl_src2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001654 }
buzbeef0504cd2012-11-13 16:31:10 -08001655 // Adjust return regs in to handle case of rem returning kArg2/kArg3
buzbeefa57c472012-11-21 12:06:18 -08001656 if (ret_reg == TargetReg(kRet0))
1657 rl_result = GetReturnWide(cu, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07001658 else
buzbeefa57c472012-11-21 12:06:18 -08001659 rl_result = GetReturnWideAlt(cu);
1660 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001661 }
buzbee31a4a6f2012-02-28 15:36:15 -08001662}
1663
buzbeea5954be2013-02-07 10:41:40 -08001664void Codegen::GenConversionCall(CompilationUnit* cu, int func_offset,
buzbee02031b12012-11-23 09:41:35 -08001665 RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001666{
Bill Buzbeea114add2012-05-03 15:00:40 -07001667 /*
1668 * Don't optimize the register usage since it calls out to support
1669 * functions
1670 */
buzbeefa57c472012-11-21 12:06:18 -08001671 FlushAllRegs(cu); /* Send everything to home location */
1672 if (rl_src.wide) {
1673 LoadValueDirectWideFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
1674 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07001675 } else {
buzbeefa57c472012-11-21 12:06:18 -08001676 LoadValueDirectFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07001677 }
buzbeefa57c472012-11-21 12:06:18 -08001678 CallRuntimeHelperRegLocation(cu, func_offset, rl_src, false);
1679 if (rl_dest.wide) {
1680 RegLocation rl_result;
1681 rl_result = GetReturnWide(cu, rl_dest.fp);
1682 StoreValueWide(cu, rl_dest, rl_result);
buzbee408ad162012-06-06 16:45:18 -07001683 } else {
buzbeefa57c472012-11-21 12:06:18 -08001684 RegLocation rl_result;
1685 rl_result = GetReturn(cu, rl_dest.fp);
1686 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001687 }
buzbee31a4a6f2012-02-28 15:36:15 -08001688}
1689
buzbee31a4a6f2012-02-28 15:36:15 -08001690/* Check if we need to check for pending suspend request */
buzbee02031b12012-11-23 09:41:35 -08001691void Codegen::GenSuspendTest(CompilationUnit* cu, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -08001692{
buzbeefa57c472012-11-21 12:06:18 -08001693 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001694 return;
1695 }
buzbeefa57c472012-11-21 12:06:18 -08001696 FlushAllRegs(cu);
1697 LIR* branch = OpTestSuspend(cu, NULL);
1698 LIR* ret_lab = NewLIR0(cu, kPseudoTargetLabel);
1699 LIR* target = RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
1700 reinterpret_cast<uintptr_t>(ret_lab), cu->current_dalvik_offset);
buzbeecbd6d442012-11-17 14:11:25 -08001701 branch->target = target;
buzbeefa57c472012-11-21 12:06:18 -08001702 InsertGrowableList(cu, &cu->suspend_launchpads, reinterpret_cast<uintptr_t>(target));
buzbee31a4a6f2012-02-28 15:36:15 -08001703}
1704
buzbeefead2932012-03-30 14:02:01 -07001705/* Check if we need to check for pending suspend request */
buzbee02031b12012-11-23 09:41:35 -08001706void Codegen::GenSuspendTestAndBranch(CompilationUnit* cu, int opt_flags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07001707{
buzbeefa57c472012-11-21 12:06:18 -08001708 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
1709 OpUnconditionalBranch(cu, target);
Bill Buzbeea114add2012-05-03 15:00:40 -07001710 return;
1711 }
buzbeefa57c472012-11-21 12:06:18 -08001712 OpTestSuspend(cu, target);
1713 LIR* launch_pad =
1714 RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
1715 reinterpret_cast<uintptr_t>(target), cu->current_dalvik_offset);
1716 FlushAllRegs(cu);
1717 OpUnconditionalBranch(cu, launch_pad);
1718 InsertGrowableList(cu, &cu->suspend_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
buzbeefead2932012-03-30 14:02:01 -07001719}
1720
buzbee31a4a6f2012-02-28 15:36:15 -08001721} // namespace art