blob: 12bdddd8d0fcd76ee0c70663597cb7adbd6f1cba [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
buzbee395116c2013-02-27 14:30:25 -080017#include "compiler/dex/compiler_ir.h"
buzbee311ca162013-02-28 15:56:43 -080018#include "compiler/dex/compiler_internals.h"
Ian Rogers8d3a1172013-06-04 01:13:28 -070019#include "compiler/dex/quick/mir_to_lir-inl.h"
Ian Rogers33e95662013-05-20 20:29:14 -070020#include "mirror/array.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "oat/runtime/oat_support_entrypoints.h"
Dragos Sbirlea980d16b2013-06-04 15:01:40 -070022#include "verifier/method_verifier.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070023
buzbee31a4a6f2012-02-28 15:36:15 -080024namespace art {
25
26/*
27 * This source files contains "gen" codegen routines that should
28 * be applicable to most targets. Only mid-level support utilities
29 * and "op" calls may be used here.
30 */
buzbee31a4a6f2012-02-28 15:36:15 -080031
buzbee31a4a6f2012-02-28 15:36:15 -080032/*
33 * Generate an kPseudoBarrier marker to indicate the boundary of special
34 * blocks.
35 */
buzbee1fd33462013-03-25 13:40:45 -070036void Mir2Lir::GenBarrier()
buzbee31a4a6f2012-02-28 15:36:15 -080037{
buzbee1fd33462013-03-25 13:40:45 -070038 LIR* barrier = NewLIR0(kPseudoBarrier);
Bill Buzbeea114add2012-05-03 15:00:40 -070039 /* Mark all resources as being clobbered */
buzbeefa57c472012-11-21 12:06:18 -080040 barrier->def_mask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -080041}
42
buzbee5de34942012-03-01 14:51:57 -080043// FIXME: need to do some work to split out targets with
44// condition codes and those without
buzbee1fd33462013-03-25 13:40:45 -070045LIR* Mir2Lir::GenCheck(ConditionCode c_code, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080046{
buzbee1fd33462013-03-25 13:40:45 -070047 DCHECK_NE(cu_->instruction_set, kMips);
48 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_);
49 LIR* branch = OpCondBranch(c_code, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070050 // Remember branch target - will process later
buzbee862a7602013-04-05 10:58:54 -070051 throw_launchpads_.Insert(tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070052 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080053}
54
buzbee1fd33462013-03-25 13:40:45 -070055LIR* Mir2Lir::GenImmedCheck(ConditionCode c_code, int reg, int imm_val, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080056{
buzbee1fd33462013-03-25 13:40:45 -070057 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg, imm_val);
Bill Buzbeea114add2012-05-03 15:00:40 -070058 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -080059 if (c_code == kCondAl) {
buzbee1fd33462013-03-25 13:40:45 -070060 branch = OpUnconditionalBranch(tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070061 } else {
buzbee1fd33462013-03-25 13:40:45 -070062 branch = OpCmpImmBranch(c_code, reg, imm_val, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070063 }
64 // Remember branch target - will process later
buzbee862a7602013-04-05 10:58:54 -070065 throw_launchpads_.Insert(tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070066 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080067}
68
69/* Perform null-check on a register. */
buzbee1fd33462013-03-25 13:40:45 -070070LIR* Mir2Lir::GenNullCheck(int s_reg, int m_reg, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -080071{
buzbee1fd33462013-03-25 13:40:45 -070072 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
buzbeefa57c472012-11-21 12:06:18 -080073 opt_flags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -070074 return NULL;
75 }
buzbee1fd33462013-03-25 13:40:45 -070076 return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -080077}
78
79/* Perform check on two registers */
buzbee1fd33462013-03-25 13:40:45 -070080LIR* Mir2Lir::GenRegRegCheck(ConditionCode c_code, int reg1, int reg2,
buzbee02031b12012-11-23 09:41:35 -080081 ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080082{
buzbee1fd33462013-03-25 13:40:45 -070083 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg1, reg2);
84 LIR* branch = OpCmpBranch(c_code, reg1, reg2, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070085 // Remember branch target - will process later
buzbee862a7602013-04-05 10:58:54 -070086 throw_launchpads_.Insert(tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070087 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080088}
89
buzbee1fd33462013-03-25 13:40:45 -070090void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
91 RegLocation rl_src2, LIR* taken,
buzbee02031b12012-11-23 09:41:35 -080092 LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -080093{
Bill Buzbeea114add2012-05-03 15:00:40 -070094 ConditionCode cond;
Bill Buzbeea114add2012-05-03 15:00:40 -070095 switch (opcode) {
96 case Instruction::IF_EQ:
97 cond = kCondEq;
98 break;
99 case Instruction::IF_NE:
100 cond = kCondNe;
101 break;
102 case Instruction::IF_LT:
103 cond = kCondLt;
104 break;
105 case Instruction::IF_GE:
106 cond = kCondGe;
107 break;
108 case Instruction::IF_GT:
109 cond = kCondGt;
110 break;
111 case Instruction::IF_LE:
112 cond = kCondLe;
113 break;
114 default:
buzbeecbd6d442012-11-17 14:11:25 -0800115 cond = static_cast<ConditionCode>(0);
116 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700117 }
buzbeee6285f92012-12-06 15:57:46 -0800118
119 // Normalize such that if either operand is constant, src2 will be constant
120 if (rl_src1.is_const) {
121 RegLocation rl_temp = rl_src1;
122 rl_src1 = rl_src2;
123 rl_src2 = rl_temp;
124 cond = FlipComparisonOrder(cond);
125 }
126
buzbee1fd33462013-03-25 13:40:45 -0700127 rl_src1 = LoadValue(rl_src1, kCoreReg);
buzbeee6285f92012-12-06 15:57:46 -0800128 // Is this really an immediate comparison?
129 if (rl_src2.is_const) {
buzbeee6285f92012-12-06 15:57:46 -0800130 // If it's already live in a register or not easily materialized, just keep going
buzbee1fd33462013-03-25 13:40:45 -0700131 RegLocation rl_temp = UpdateLoc(rl_src2);
buzbee4ef3e452012-12-14 13:35:28 -0800132 if ((rl_temp.location == kLocDalvikFrame) &&
buzbee1fd33462013-03-25 13:40:45 -0700133 InexpensiveConstantInt(mir_graph_->ConstantValue(rl_src2))) {
buzbeee6285f92012-12-06 15:57:46 -0800134 // OK - convert this to a compare immediate and branch
buzbee1fd33462013-03-25 13:40:45 -0700135 OpCmpImmBranch(cond, rl_src1.low_reg, mir_graph_->ConstantValue(rl_src2), taken);
136 OpUnconditionalBranch(fall_through);
buzbeee6285f92012-12-06 15:57:46 -0800137 return;
138 }
139 }
buzbee1fd33462013-03-25 13:40:45 -0700140 rl_src2 = LoadValue(rl_src2, kCoreReg);
141 OpCmpBranch(cond, rl_src1.low_reg, rl_src2.low_reg, taken);
142 OpUnconditionalBranch(fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800143}
144
buzbee1fd33462013-03-25 13:40:45 -0700145void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken,
146 LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -0800147{
Bill Buzbeea114add2012-05-03 15:00:40 -0700148 ConditionCode cond;
buzbee1fd33462013-03-25 13:40:45 -0700149 rl_src = LoadValue(rl_src, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700150 switch (opcode) {
151 case Instruction::IF_EQZ:
152 cond = kCondEq;
153 break;
154 case Instruction::IF_NEZ:
155 cond = kCondNe;
156 break;
157 case Instruction::IF_LTZ:
158 cond = kCondLt;
159 break;
160 case Instruction::IF_GEZ:
161 cond = kCondGe;
162 break;
163 case Instruction::IF_GTZ:
164 cond = kCondGt;
165 break;
166 case Instruction::IF_LEZ:
167 cond = kCondLe;
168 break;
169 default:
buzbeecbd6d442012-11-17 14:11:25 -0800170 cond = static_cast<ConditionCode>(0);
171 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 }
buzbee1fd33462013-03-25 13:40:45 -0700173 OpCmpImmBranch(cond, rl_src.low_reg, 0, taken);
174 OpUnconditionalBranch(fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800175}
176
buzbee1fd33462013-03-25 13:40:45 -0700177void Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800178{
buzbee1fd33462013-03-25 13:40:45 -0700179 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbeefa57c472012-11-21 12:06:18 -0800180 if (rl_src.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700181 OpRegCopy(rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700182 } else {
buzbee1fd33462013-03-25 13:40:45 -0700183 LoadValueDirect(rl_src, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700184 }
buzbee1fd33462013-03-25 13:40:45 -0700185 OpRegRegImm(kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
186 StoreValueWide(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800187}
188
buzbee1fd33462013-03-25 13:40:45 -0700189void Mir2Lir::GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -0800190 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800191{
buzbee1fd33462013-03-25 13:40:45 -0700192 rl_src = LoadValue(rl_src, kCoreReg);
193 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700195 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 case Instruction::INT_TO_BYTE:
197 op = kOp2Byte;
198 break;
199 case Instruction::INT_TO_SHORT:
200 op = kOp2Short;
201 break;
202 case Instruction::INT_TO_CHAR:
203 op = kOp2Char;
204 break;
205 default:
206 LOG(ERROR) << "Bad int conversion type";
207 }
buzbee1fd33462013-03-25 13:40:45 -0700208 OpRegReg(op, rl_result.low_reg, rl_src.low_reg);
209 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800210}
211
212/*
213 * Let helper function take care of everything. Will call
214 * Array::AllocFromCode(type_idx, method, count);
215 * Note: AllocFromCode will handle checks for errNegativeArraySize.
216 */
buzbee1fd33462013-03-25 13:40:45 -0700217void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -0800218 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800219{
buzbee1fd33462013-03-25 13:40:45 -0700220 FlushAllRegs(); /* Everything to home location */
buzbeefa57c472012-11-21 12:06:18 -0800221 int func_offset;
buzbee1fd33462013-03-25 13:40:45 -0700222 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
223 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800224 func_offset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700225 } else {
buzbeefa57c472012-11-21 12:06:18 -0800226 func_offset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700227 }
buzbee1fd33462013-03-25 13:40:45 -0700228 CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
229 RegLocation rl_result = GetReturn(false);
230 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800231}
232
233/*
buzbee52a77fc2012-11-20 19:50:46 -0800234 * Similar to GenNewArray, but with post-allocation initialization.
buzbee31a4a6f2012-02-28 15:36:15 -0800235 * Verifier guarantees we're dealing with an array class. Current
236 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
237 * Current code also throws internal unimp if not 'L', '[' or 'I'.
238 */
buzbee1fd33462013-03-25 13:40:45 -0700239void Mir2Lir::GenFilledNewArray(CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800240{
buzbeefa57c472012-11-21 12:06:18 -0800241 int elems = info->num_arg_words;
242 int type_idx = info->index;
buzbee1fd33462013-03-25 13:40:45 -0700243 FlushAllRegs(); /* Everything to home location */
buzbeefa57c472012-11-21 12:06:18 -0800244 int func_offset;
buzbee1fd33462013-03-25 13:40:45 -0700245 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
246 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800247 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 } else {
buzbeefa57c472012-11-21 12:06:18 -0800249 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700250 }
buzbee1fd33462013-03-25 13:40:45 -0700251 CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true);
252 FreeTemp(TargetReg(kArg2));
253 FreeTemp(TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700254 /*
255 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
256 * return region. Because AllocFromCode placed the new array
buzbeef0504cd2012-11-13 16:31:10 -0800257 * in kRet0, we'll just lock it into place. When debugger support is
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 * added, it may be necessary to additionally copy all return
259 * values to a home location in thread-local storage
260 */
buzbee1fd33462013-03-25 13:40:45 -0700261 LockTemp(TargetReg(kRet0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700262
263 // TODO: use the correct component size, currently all supported types
264 // share array alignment with ints (see comment at head of function)
265 size_t component_size = sizeof(int32_t);
266
267 // Having a range of 0 is legal
buzbeefa57c472012-11-21 12:06:18 -0800268 if (info->is_range && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800269 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700270 * Bit of ugliness here. We're going generate a mem copy loop
271 * on the register range, but it is possible that some regs
272 * in the range have been promoted. This is unlikely, but
273 * before generating the copy, we'll just force a flush
274 * of any regs in the source range that have been promoted to
275 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800276 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700277 for (int i = 0; i < elems; i++) {
buzbee1fd33462013-03-25 13:40:45 -0700278 RegLocation loc = UpdateLoc(info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700279 if (loc.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700280 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800281 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700282 }
buzbee31a4a6f2012-02-28 15:36:15 -0800283 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700284 /*
285 * TUNING note: generated code here could be much improved, but
286 * this is an uncommon operation and isn't especially performance
287 * critical.
288 */
buzbee1fd33462013-03-25 13:40:45 -0700289 int r_src = AllocTemp();
290 int r_dst = AllocTemp();
291 int r_idx = AllocTemp();
buzbeefa57c472012-11-21 12:06:18 -0800292 int r_val = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -0700293 switch(cu_->instruction_set) {
buzbeeb046e162012-10-30 15:48:42 -0700294 case kThumb2:
buzbeefa57c472012-11-21 12:06:18 -0800295 r_val = TargetReg(kLr);
buzbeeb046e162012-10-30 15:48:42 -0700296 break;
297 case kX86:
buzbee1fd33462013-03-25 13:40:45 -0700298 FreeTemp(TargetReg(kRet0));
299 r_val = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700300 break;
301 case kMips:
buzbee1fd33462013-03-25 13:40:45 -0700302 r_val = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700303 break;
buzbee1fd33462013-03-25 13:40:45 -0700304 default: LOG(FATAL) << "Unexpected instruction set: " << cu_->instruction_set;
buzbeeb046e162012-10-30 15:48:42 -0700305 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700306 // Set up source pointer
buzbeefa57c472012-11-21 12:06:18 -0800307 RegLocation rl_first = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700308 OpRegRegImm(kOpAdd, r_src, TargetReg(kSp), SRegOffset(rl_first.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700309 // Set up the target pointer
buzbee1fd33462013-03-25 13:40:45 -0700310 OpRegRegImm(kOpAdd, r_dst, TargetReg(kRet0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800311 mirror::Array::DataOffset(component_size).Int32Value());
Bill Buzbeea114add2012-05-03 15:00:40 -0700312 // Set up the loop counter (known to be > 0)
buzbee1fd33462013-03-25 13:40:45 -0700313 LoadConstant(r_idx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700314 // Generate the copy loop. Going backwards for convenience
buzbee1fd33462013-03-25 13:40:45 -0700315 LIR* target = NewLIR0(kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700316 // Copy next element
buzbee1fd33462013-03-25 13:40:45 -0700317 LoadBaseIndexed(r_src, r_idx, r_val, 2, kWord);
318 StoreBaseIndexed(r_dst, r_idx, r_val, 2, kWord);
319 FreeTemp(r_val);
320 OpDecAndBranch(kCondGe, r_idx, target);
321 if (cu_->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700322 // Restore the target pointer
buzbee1fd33462013-03-25 13:40:45 -0700323 OpRegRegImm(kOpAdd, TargetReg(kRet0), r_dst,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800324 -mirror::Array::DataOffset(component_size).Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700325 }
buzbeefa57c472012-11-21 12:06:18 -0800326 } else if (!info->is_range) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700327 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700328 for (int i = 0; i < elems; i++) {
buzbee1fd33462013-03-25 13:40:45 -0700329 RegLocation rl_arg = LoadValue(info->args[i], kCoreReg);
330 StoreBaseDisp(TargetReg(kRet0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800331 mirror::Array::DataOffset(component_size).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800332 i * 4, rl_arg.low_reg, kWord);
buzbee52a77fc2012-11-20 19:50:46 -0800333 // If the LoadValue caused a temp to be allocated, free it
buzbee1fd33462013-03-25 13:40:45 -0700334 if (IsTemp(rl_arg.low_reg)) {
335 FreeTemp(rl_arg.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700336 }
337 }
338 }
buzbeee5f01222012-06-14 15:19:35 -0700339 if (info->result.location != kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700340 StoreValue(info->result, GetReturn(false /* not fp */));
buzbeee5f01222012-06-14 15:19:35 -0700341 }
buzbee31a4a6f2012-02-28 15:36:15 -0800342}
343
buzbee1fd33462013-03-25 13:40:45 -0700344void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_double,
345 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800346{
buzbeefa57c472012-11-21 12:06:18 -0800347 int field_offset;
348 int ssb_index;
349 bool is_volatile;
350 bool is_referrers_class;
buzbee1fd33462013-03-25 13:40:45 -0700351 bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
352 field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
buzbee311ca162013-02-28 15:56:43 -0800353 is_referrers_class, is_volatile, true);
buzbeefa57c472012-11-21 12:06:18 -0800354 if (fast_path && !SLOW_FIELD_PATH) {
355 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700356 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800357 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700358 // Fast path, static storage base is this method's class
buzbee1fd33462013-03-25 13:40:45 -0700359 RegLocation rl_method = LoadCurrMethod();
360 rBase = AllocTemp();
361 LoadWordDisp(rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800362 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee1fd33462013-03-25 13:40:45 -0700363 if (IsTemp(rl_method.low_reg)) {
364 FreeTemp(rl_method.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700365 }
buzbee31a4a6f2012-02-28 15:36:15 -0800366 } else {
Ian Rogersaed07162013-03-15 12:00:53 -0700367 // Medium path, static storage base in a different class which requires checks that the other
368 // class is initialized.
369 // TODO: remove initialized check now that we are initializing classes in the compiler driver.
buzbeefa57c472012-11-21 12:06:18 -0800370 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700371 // May do runtime call so everything to home locations.
buzbee1fd33462013-03-25 13:40:45 -0700372 FlushAllRegs();
Ian Rogersaed07162013-03-15 12:00:53 -0700373 // Using fixed register to sync with possible call to runtime support.
buzbeefa57c472012-11-21 12:06:18 -0800374 int r_method = TargetReg(kArg1);
buzbee1fd33462013-03-25 13:40:45 -0700375 LockTemp(r_method);
376 LoadCurrMethodDirect(r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800377 rBase = TargetReg(kArg0);
buzbee1fd33462013-03-25 13:40:45 -0700378 LockTemp(rBase);
379 LoadWordDisp(r_method,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800380 mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700381 rBase);
buzbee1fd33462013-03-25 13:40:45 -0700382 LoadWordDisp(rBase,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800383 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800384 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 // rBase now points at appropriate static storage base (Class*)
386 // or NULL if not initialized. Check for NULL and call helper if NULL.
387 // TUNING: fast path should fall through
buzbee1fd33462013-03-25 13:40:45 -0700388 LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL);
389 LoadConstant(TargetReg(kArg0), ssb_index);
390 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
391 if (cu_->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800392 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbee1fd33462013-03-25 13:40:45 -0700393 OpRegCopy(rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700394 }
buzbee1fd33462013-03-25 13:40:45 -0700395 LIR* skip_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -0800396 branch_over->target = skip_target;
buzbee1fd33462013-03-25 13:40:45 -0700397 FreeTemp(r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800398 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700399 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800400 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700401 rl_src = LoadValueWide(rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700402 } else {
buzbee1fd33462013-03-25 13:40:45 -0700403 rl_src = LoadValue(rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700404 }
buzbeefa57c472012-11-21 12:06:18 -0800405 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700406 GenMemBarrier(kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700407 }
buzbeefa57c472012-11-21 12:06:18 -0800408 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700409 StoreBaseDispWide(rBase, field_offset, rl_src.low_reg,
buzbeefa57c472012-11-21 12:06:18 -0800410 rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700411 } else {
buzbee1fd33462013-03-25 13:40:45 -0700412 StoreWordDisp(rBase, field_offset, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700413 }
buzbeefa57c472012-11-21 12:06:18 -0800414 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700415 GenMemBarrier(kStoreLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700416 }
buzbee1fd33462013-03-25 13:40:45 -0700417 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
418 MarkGCCard(rl_src.low_reg, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700419 }
buzbee1fd33462013-03-25 13:40:45 -0700420 FreeTemp(rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700421 } else {
buzbee1fd33462013-03-25 13:40:45 -0700422 FlushAllRegs(); // Everything to home locations
buzbeefa57c472012-11-21 12:06:18 -0800423 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Static) :
424 (is_object ? ENTRYPOINT_OFFSET(pSetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 : ENTRYPOINT_OFFSET(pSet32Static));
buzbee1fd33462013-03-25 13:40:45 -0700426 CallRuntimeHelperImmRegLocation(setter_offset, field_idx, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 }
buzbee31a4a6f2012-02-28 15:36:15 -0800428}
429
buzbee1fd33462013-03-25 13:40:45 -0700430void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -0800431 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800432{
buzbeefa57c472012-11-21 12:06:18 -0800433 int field_offset;
434 int ssb_index;
435 bool is_volatile;
436 bool is_referrers_class;
buzbee1fd33462013-03-25 13:40:45 -0700437 bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
438 field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index,
buzbee311ca162013-02-28 15:56:43 -0800439 is_referrers_class, is_volatile, false);
buzbeefa57c472012-11-21 12:06:18 -0800440 if (fast_path && !SLOW_FIELD_PATH) {
441 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700442 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800443 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700444 // Fast path, static storage base is this method's class
buzbee1fd33462013-03-25 13:40:45 -0700445 RegLocation rl_method = LoadCurrMethod();
446 rBase = AllocTemp();
447 LoadWordDisp(rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800448 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800449 } else {
Ian Rogersaed07162013-03-15 12:00:53 -0700450 // Medium path, static storage base in a different class which requires checks that the other
451 // class is initialized
452 // TODO: remove initialized check now that we are initializing classes in the compiler driver.
buzbeefa57c472012-11-21 12:06:18 -0800453 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700454 // May do runtime call so everything to home locations.
buzbee1fd33462013-03-25 13:40:45 -0700455 FlushAllRegs();
Ian Rogersaed07162013-03-15 12:00:53 -0700456 // Using fixed register to sync with possible call to runtime support.
buzbeefa57c472012-11-21 12:06:18 -0800457 int r_method = TargetReg(kArg1);
buzbee1fd33462013-03-25 13:40:45 -0700458 LockTemp(r_method);
459 LoadCurrMethodDirect(r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800460 rBase = TargetReg(kArg0);
buzbee1fd33462013-03-25 13:40:45 -0700461 LockTemp(rBase);
462 LoadWordDisp(r_method,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800463 mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700464 rBase);
buzbee1fd33462013-03-25 13:40:45 -0700465 LoadWordDisp(rBase, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800466 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700467 // rBase now points at appropriate static storage base (Class*)
468 // or NULL if not initialized. Check for NULL and call helper if NULL.
469 // TUNING: fast path should fall through
buzbee1fd33462013-03-25 13:40:45 -0700470 LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL);
471 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
472 if (cu_->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800473 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbee1fd33462013-03-25 13:40:45 -0700474 OpRegCopy(rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700475 }
buzbee1fd33462013-03-25 13:40:45 -0700476 LIR* skip_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -0800477 branch_over->target = skip_target;
buzbee1fd33462013-03-25 13:40:45 -0700478 FreeTemp(r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800479 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700480 // rBase now holds static storage base
buzbee1fd33462013-03-25 13:40:45 -0700481 RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true);
buzbeefa57c472012-11-21 12:06:18 -0800482 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700483 GenMemBarrier(kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700484 }
buzbeefa57c472012-11-21 12:06:18 -0800485 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700486 LoadBaseDispWide(rBase, field_offset, rl_result.low_reg,
buzbeefa57c472012-11-21 12:06:18 -0800487 rl_result.high_reg, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700488 } else {
buzbee1fd33462013-03-25 13:40:45 -0700489 LoadWordDisp(rBase, field_offset, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700490 }
buzbee1fd33462013-03-25 13:40:45 -0700491 FreeTemp(rBase);
buzbeefa57c472012-11-21 12:06:18 -0800492 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700493 StoreValueWide(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700494 } else {
buzbee1fd33462013-03-25 13:40:45 -0700495 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700496 }
497 } else {
buzbee1fd33462013-03-25 13:40:45 -0700498 FlushAllRegs(); // Everything to home locations
buzbeefa57c472012-11-21 12:06:18 -0800499 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Static) :
500 (is_object ? ENTRYPOINT_OFFSET(pGetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700501 : ENTRYPOINT_OFFSET(pGet32Static));
buzbee1fd33462013-03-25 13:40:45 -0700502 CallRuntimeHelperImm(getterOffset, field_idx, true);
buzbeefa57c472012-11-21 12:06:18 -0800503 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700504 RegLocation rl_result = GetReturnWide(rl_dest.fp);
505 StoreValueWide(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700506 } else {
buzbee1fd33462013-03-25 13:40:45 -0700507 RegLocation rl_result = GetReturn(rl_dest.fp);
508 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700509 }
510 }
buzbee31a4a6f2012-02-28 15:36:15 -0800511}
512
buzbee1fd33462013-03-25 13:40:45 -0700513void Mir2Lir::HandleSuspendLaunchPads()
buzbee31a4a6f2012-02-28 15:36:15 -0800514{
buzbee862a7602013-04-05 10:58:54 -0700515 int num_elems = suspend_launchpads_.Size();
buzbeefa57c472012-11-21 12:06:18 -0800516 int helper_offset = ENTRYPOINT_OFFSET(pTestSuspendFromCode);
517 for (int i = 0; i < num_elems; i++) {
buzbee1fd33462013-03-25 13:40:45 -0700518 ResetRegPool();
519 ResetDefTracking();
buzbee862a7602013-04-05 10:58:54 -0700520 LIR* lab = suspend_launchpads_.Get(i);
buzbeefa57c472012-11-21 12:06:18 -0800521 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]);
buzbee1fd33462013-03-25 13:40:45 -0700522 current_dalvik_offset_ = lab->operands[1];
523 AppendLIR(lab);
524 int r_tgt = CallHelperSetup(helper_offset);
525 CallHelper(r_tgt, helper_offset, true /* MarkSafepointPC */);
526 OpUnconditionalBranch(resume_lab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700527 }
buzbee31a4a6f2012-02-28 15:36:15 -0800528}
529
buzbee1fd33462013-03-25 13:40:45 -0700530void Mir2Lir::HandleIntrinsicLaunchPads()
buzbeefc9e6fa2012-03-23 15:14:29 -0700531{
buzbee862a7602013-04-05 10:58:54 -0700532 int num_elems = intrinsic_launchpads_.Size();
buzbeefa57c472012-11-21 12:06:18 -0800533 for (int i = 0; i < num_elems; i++) {
buzbee1fd33462013-03-25 13:40:45 -0700534 ResetRegPool();
535 ResetDefTracking();
buzbee862a7602013-04-05 10:58:54 -0700536 LIR* lab = intrinsic_launchpads_.Get(i);
buzbeecbd6d442012-11-17 14:11:25 -0800537 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
buzbee1fd33462013-03-25 13:40:45 -0700538 current_dalvik_offset_ = info->offset;
539 AppendLIR(lab);
buzbee52a77fc2012-11-20 19:50:46 -0800540 // NOTE: GenInvoke handles MarkSafepointPC
buzbee1fd33462013-03-25 13:40:45 -0700541 GenInvoke(info);
buzbeefa57c472012-11-21 12:06:18 -0800542 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]);
543 if (resume_lab != NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700544 OpUnconditionalBranch(resume_lab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700545 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700546 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700547}
548
buzbee1fd33462013-03-25 13:40:45 -0700549void Mir2Lir::HandleThrowLaunchPads()
buzbee31a4a6f2012-02-28 15:36:15 -0800550{
buzbee862a7602013-04-05 10:58:54 -0700551 int num_elems = throw_launchpads_.Size();
buzbeefa57c472012-11-21 12:06:18 -0800552 for (int i = 0; i < num_elems; i++) {
buzbee1fd33462013-03-25 13:40:45 -0700553 ResetRegPool();
554 ResetDefTracking();
buzbee862a7602013-04-05 10:58:54 -0700555 LIR* lab = throw_launchpads_.Get(i);
buzbee1fd33462013-03-25 13:40:45 -0700556 current_dalvik_offset_ = lab->operands[1];
557 AppendLIR(lab);
buzbeefa57c472012-11-21 12:06:18 -0800558 int func_offset = 0;
Bill Buzbeea114add2012-05-03 15:00:40 -0700559 int v1 = lab->operands[2];
560 int v2 = lab->operands[3];
buzbee1fd33462013-03-25 13:40:45 -0700561 bool target_x86 = (cu_->instruction_set == kX86);
Bill Buzbeea114add2012-05-03 15:00:40 -0700562 switch (lab->operands[0]) {
563 case kThrowNullPointer:
buzbeefa57c472012-11-21 12:06:18 -0800564 func_offset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700565 break;
buzbee4ef3e452012-12-14 13:35:28 -0800566 case kThrowConstantArrayBounds: // v1 is length reg (for Arm/Mips), v2 constant index
567 // v1 holds the constant array index. Mips/Arm uses v2 for length, x86 reloads.
568 if (target_x86) {
buzbee1fd33462013-03-25 13:40:45 -0700569 OpRegMem(kOpMov, TargetReg(kArg1), v1, mirror::Array::LengthOffset().Int32Value());
buzbee4ef3e452012-12-14 13:35:28 -0800570 } else {
buzbee1fd33462013-03-25 13:40:45 -0700571 OpRegCopy(TargetReg(kArg1), v1);
buzbee4ef3e452012-12-14 13:35:28 -0800572 }
573 // Make sure the following LoadConstant doesn't mess with kArg1.
buzbee1fd33462013-03-25 13:40:45 -0700574 LockTemp(TargetReg(kArg1));
575 LoadConstant(TargetReg(kArg0), v2);
buzbee4ef3e452012-12-14 13:35:28 -0800576 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
577 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700578 case kThrowArrayBounds:
buzbeef0504cd2012-11-13 16:31:10 -0800579 // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
buzbee52a77fc2012-11-20 19:50:46 -0800580 if (v2 != TargetReg(kArg0)) {
buzbee1fd33462013-03-25 13:40:45 -0700581 OpRegCopy(TargetReg(kArg0), v1);
buzbeefa57c472012-11-21 12:06:18 -0800582 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700583 // x86 leaves the array pointer in v2, so load the array length that the handler expects
buzbee1fd33462013-03-25 13:40:45 -0700584 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700585 } else {
buzbee1fd33462013-03-25 13:40:45 -0700586 OpRegCopy(TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700587 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700588 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800589 if (v1 == TargetReg(kArg1)) {
buzbeef0504cd2012-11-13 16:31:10 -0800590 // Swap v1 and v2, using kArg2 as a temp
buzbee1fd33462013-03-25 13:40:45 -0700591 OpRegCopy(TargetReg(kArg2), v1);
buzbeefa57c472012-11-21 12:06:18 -0800592 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700593 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbee1fd33462013-03-25 13:40:45 -0700594 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700595 } else {
buzbee1fd33462013-03-25 13:40:45 -0700596 OpRegCopy(TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700597 }
buzbee1fd33462013-03-25 13:40:45 -0700598 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700599 } else {
buzbeefa57c472012-11-21 12:06:18 -0800600 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700601 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbee1fd33462013-03-25 13:40:45 -0700602 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700603 } else {
buzbee1fd33462013-03-25 13:40:45 -0700604 OpRegCopy(TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700605 }
buzbee1fd33462013-03-25 13:40:45 -0700606 OpRegCopy(TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700607 }
buzbee31a4a6f2012-02-28 15:36:15 -0800608 }
buzbeefa57c472012-11-21 12:06:18 -0800609 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700610 break;
611 case kThrowDivZero:
buzbeefa57c472012-11-21 12:06:18 -0800612 func_offset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700613 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700614 case kThrowNoSuchMethod:
buzbee1fd33462013-03-25 13:40:45 -0700615 OpRegCopy(TargetReg(kArg0), v1);
buzbeefa57c472012-11-21 12:06:18 -0800616 func_offset =
Bill Buzbeea114add2012-05-03 15:00:40 -0700617 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
618 break;
619 case kThrowStackOverflow:
buzbeefa57c472012-11-21 12:06:18 -0800620 func_offset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700621 // Restore stack alignment
buzbeefa57c472012-11-21 12:06:18 -0800622 if (target_x86) {
buzbee1fd33462013-03-25 13:40:45 -0700623 OpRegImm(kOpAdd, TargetReg(kSp), frame_size_);
buzbeeb046e162012-10-30 15:48:42 -0700624 } else {
buzbee1fd33462013-03-25 13:40:45 -0700625 OpRegImm(kOpAdd, TargetReg(kSp), (num_core_spills_ + num_fp_spills_) * 4);
buzbeeb046e162012-10-30 15:48:42 -0700626 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700627 break;
628 default:
629 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800630 }
buzbee1fd33462013-03-25 13:40:45 -0700631 ClobberCalleeSave();
632 int r_tgt = CallHelperSetup(func_offset);
633 CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */);
Bill Buzbeea114add2012-05-03 15:00:40 -0700634 }
buzbee31a4a6f2012-02-28 15:36:15 -0800635}
636
buzbee1fd33462013-03-25 13:40:45 -0700637void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
buzbee02031b12012-11-23 09:41:35 -0800638 RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
639 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800640{
buzbeefa57c472012-11-21 12:06:18 -0800641 int field_offset;
642 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800643
buzbee1fd33462013-03-25 13:40:45 -0700644 bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800645
buzbeefa57c472012-11-21 12:06:18 -0800646 if (fast_path && !SLOW_FIELD_PATH) {
647 RegLocation rl_result;
648 RegisterClass reg_class = oat_reg_class_by_size(size);
649 DCHECK_GE(field_offset, 0);
buzbee1fd33462013-03-25 13:40:45 -0700650 rl_obj = LoadValue(rl_obj, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800651 if (is_long_or_double) {
652 DCHECK(rl_dest.wide);
buzbee1fd33462013-03-25 13:40:45 -0700653 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
654 if (cu_->instruction_set == kX86) {
655 rl_result = EvalLoc(rl_dest, reg_class, true);
656 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
657 LoadBaseDispWide(rl_obj.low_reg, field_offset, rl_result.low_reg,
buzbeefa57c472012-11-21 12:06:18 -0800658 rl_result.high_reg, rl_obj.s_reg_low);
659 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700660 GenMemBarrier(kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700661 }
662 } else {
buzbee1fd33462013-03-25 13:40:45 -0700663 int reg_ptr = AllocTemp();
664 OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
665 rl_result = EvalLoc(rl_dest, reg_class, true);
666 LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
buzbeefa57c472012-11-21 12:06:18 -0800667 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700668 GenMemBarrier(kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700669 }
buzbee1fd33462013-03-25 13:40:45 -0700670 FreeTemp(reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700671 }
buzbee1fd33462013-03-25 13:40:45 -0700672 StoreValueWide(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800673 } else {
buzbee1fd33462013-03-25 13:40:45 -0700674 rl_result = EvalLoc(rl_dest, reg_class, true);
675 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
676 LoadBaseDisp(rl_obj.low_reg, field_offset, rl_result.low_reg,
buzbeefa57c472012-11-21 12:06:18 -0800677 kWord, rl_obj.s_reg_low);
678 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700679 GenMemBarrier(kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700680 }
buzbee1fd33462013-03-25 13:40:45 -0700681 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800682 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700683 } else {
buzbeefa57c472012-11-21 12:06:18 -0800684 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Instance) :
685 (is_object ? ENTRYPOINT_OFFSET(pGetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700686 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbee1fd33462013-03-25 13:40:45 -0700687 CallRuntimeHelperImmRegLocation(getterOffset, field_idx, rl_obj, true);
buzbeefa57c472012-11-21 12:06:18 -0800688 if (is_long_or_double) {
buzbee1fd33462013-03-25 13:40:45 -0700689 RegLocation rl_result = GetReturnWide(rl_dest.fp);
690 StoreValueWide(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700691 } else {
buzbee1fd33462013-03-25 13:40:45 -0700692 RegLocation rl_result = GetReturn(rl_dest.fp);
693 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700694 }
695 }
buzbee31a4a6f2012-02-28 15:36:15 -0800696}
697
buzbee1fd33462013-03-25 13:40:45 -0700698void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
buzbee02031b12012-11-23 09:41:35 -0800699 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
700 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800701{
buzbeefa57c472012-11-21 12:06:18 -0800702 int field_offset;
703 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800704
buzbee1fd33462013-03-25 13:40:45 -0700705 bool fast_path = FastInstance(field_idx, field_offset, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700706 true);
buzbeefa57c472012-11-21 12:06:18 -0800707 if (fast_path && !SLOW_FIELD_PATH) {
708 RegisterClass reg_class = oat_reg_class_by_size(size);
709 DCHECK_GE(field_offset, 0);
buzbee1fd33462013-03-25 13:40:45 -0700710 rl_obj = LoadValue(rl_obj, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800711 if (is_long_or_double) {
712 int reg_ptr;
buzbee1fd33462013-03-25 13:40:45 -0700713 rl_src = LoadValueWide(rl_src, kAnyReg);
714 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
715 reg_ptr = AllocTemp();
716 OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
buzbeefa57c472012-11-21 12:06:18 -0800717 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700718 GenMemBarrier(kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700719 }
buzbee1fd33462013-03-25 13:40:45 -0700720 StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
buzbeefa57c472012-11-21 12:06:18 -0800721 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700722 GenMemBarrier(kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700723 }
buzbee1fd33462013-03-25 13:40:45 -0700724 FreeTemp(reg_ptr);
buzbee31a4a6f2012-02-28 15:36:15 -0800725 } else {
buzbee1fd33462013-03-25 13:40:45 -0700726 rl_src = LoadValue(rl_src, reg_class);
727 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
buzbeefa57c472012-11-21 12:06:18 -0800728 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700729 GenMemBarrier(kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700730 }
buzbee1fd33462013-03-25 13:40:45 -0700731 StoreBaseDisp(rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
buzbeefa57c472012-11-21 12:06:18 -0800732 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -0700733 GenMemBarrier(kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700734 }
buzbee1fd33462013-03-25 13:40:45 -0700735 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
736 MarkGCCard(rl_src.low_reg, rl_obj.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700737 }
buzbee31a4a6f2012-02-28 15:36:15 -0800738 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700739 } else {
buzbeefa57c472012-11-21 12:06:18 -0800740 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Instance) :
741 (is_object ? ENTRYPOINT_OFFSET(pSetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700742 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbee1fd33462013-03-25 13:40:45 -0700743 CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_idx, rl_obj, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700744 }
buzbee31a4a6f2012-02-28 15:36:15 -0800745}
746
buzbee1fd33462013-03-25 13:40:45 -0700747void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800748{
buzbee1fd33462013-03-25 13:40:45 -0700749 RegLocation rl_method = LoadCurrMethod();
750 int res_reg = AllocTemp();
751 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
752 if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
753 *cu_->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700754 type_idx)) {
755 // Call out to helper which resolves type and verifies access.
buzbeef0504cd2012-11-13 16:31:10 -0800756 // Resolved type returned in kRet0.
buzbee1fd33462013-03-25 13:40:45 -0700757 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbeefa57c472012-11-21 12:06:18 -0800758 type_idx, rl_method.low_reg, true);
buzbee1fd33462013-03-25 13:40:45 -0700759 RegLocation rl_result = GetReturn(false);
760 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700761 } else {
762 // We're don't need access checks, load type from dex cache
763 int32_t dex_cache_offset =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800764 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value();
buzbee1fd33462013-03-25 13:40:45 -0700765 LoadWordDisp(rl_method.low_reg, dex_cache_offset, res_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700766 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800767 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
Bill Buzbeea114add2012-05-03 15:00:40 -0700768 * type_idx);
buzbee1fd33462013-03-25 13:40:45 -0700769 LoadWordDisp(res_reg, offset_of_type, rl_result.low_reg);
770 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700771 type_idx) || SLOW_TYPE_PATH) {
772 // Slow path, at runtime test if type is null and if so initialize
buzbee1fd33462013-03-25 13:40:45 -0700773 FlushAllRegs();
774 LIR* branch1 = OpCmpImmBranch(kCondEq, rl_result.low_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700775 // Resolved, store and hop over following code
buzbee1fd33462013-03-25 13:40:45 -0700776 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700777 /*
778 * Because we have stores of the target value on two paths,
779 * clobber temp tracking for the destination using the ssa name
780 */
buzbee1fd33462013-03-25 13:40:45 -0700781 ClobberSReg(rl_dest.s_reg_low);
782 LIR* branch2 = OpUnconditionalBranch(0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700783 // TUNING: move slow path to end & remove unconditional branch
buzbee1fd33462013-03-25 13:40:45 -0700784 LIR* target1 = NewLIR0(kPseudoTargetLabel);
buzbeef0504cd2012-11-13 16:31:10 -0800785 // Call out to helper, which will return resolved type in kArg0
buzbee1fd33462013-03-25 13:40:45 -0700786 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
buzbeefa57c472012-11-21 12:06:18 -0800787 rl_method.low_reg, true);
buzbee1fd33462013-03-25 13:40:45 -0700788 RegLocation rl_result = GetReturn(false);
789 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700790 /*
791 * Because we have stores of the target value on two paths,
792 * clobber temp tracking for the destination using the ssa name
793 */
buzbee1fd33462013-03-25 13:40:45 -0700794 ClobberSReg(rl_dest.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -0700795 // Rejoin code paths
buzbee1fd33462013-03-25 13:40:45 -0700796 LIR* target2 = NewLIR0(kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800797 branch1->target = target1;
798 branch2->target = target2;
buzbee31a4a6f2012-02-28 15:36:15 -0800799 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700800 // Fast path, we're done - just store result
buzbee1fd33462013-03-25 13:40:45 -0700801 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800802 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700803 }
buzbee31a4a6f2012-02-28 15:36:15 -0800804}
Ian Rogersab2b55d2012-03-18 00:06:11 -0700805
buzbee1fd33462013-03-25 13:40:45 -0700806void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800807{
Bill Buzbeea114add2012-05-03 15:00:40 -0700808 /* NOTE: Most strings should be available at compile time */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800809 int32_t offset_of_string = mirror::Array::DataOffset(sizeof(mirror::String*)).Int32Value() +
810 (sizeof(mirror::String*) * string_idx);
buzbee1fd33462013-03-25 13:40:45 -0700811 if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache(
812 *cu_->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700813 // slow path, resolve string if not in dex cache
buzbee1fd33462013-03-25 13:40:45 -0700814 FlushAllRegs();
815 LockCallTemps(); // Using explicit registers
816 LoadCurrMethodDirect(TargetReg(kArg2));
817 LoadWordDisp(TargetReg(kArg2),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800818 mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800819 // Might call out to helper, which will return resolved string in kRet0
buzbee1fd33462013-03-25 13:40:45 -0700820 int r_tgt = CallHelperSetup(ENTRYPOINT_OFFSET(pResolveStringFromCode));
821 LoadWordDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
822 LoadConstant(TargetReg(kArg1), string_idx);
823 if (cu_->instruction_set == kThumb2) {
824 OpRegImm(kOpCmp, TargetReg(kRet0), 0); // Is resolved?
825 GenBarrier();
buzbeeb046e162012-10-30 15:48:42 -0700826 // For testing, always force through helper
827 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee1fd33462013-03-25 13:40:45 -0700828 OpIT(kCondEq, "T");
buzbeeb046e162012-10-30 15:48:42 -0700829 }
buzbee1fd33462013-03-25 13:40:45 -0700830 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .eq
831 LIR* call_inst = OpReg(kOpBlx, r_tgt); // .eq, helper(Method*, string_idx)
832 MarkSafepointPC(call_inst);
833 FreeTemp(r_tgt);
834 } else if (cu_->instruction_set == kMips) {
835 LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kRet0), 0, NULL);
836 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .eq
837 LIR* call_inst = OpReg(kOpBlx, r_tgt);
838 MarkSafepointPC(call_inst);
839 FreeTemp(r_tgt);
840 LIR* target = NewLIR0(kPseudoTargetLabel);
buzbeeb046e162012-10-30 15:48:42 -0700841 branch->target = target;
842 } else {
buzbee1fd33462013-03-25 13:40:45 -0700843 DCHECK_EQ(cu_->instruction_set, kX86);
844 CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true);
buzbee31a4a6f2012-02-28 15:36:15 -0800845 }
buzbee1fd33462013-03-25 13:40:45 -0700846 GenBarrier();
847 StoreValue(rl_dest, GetReturn(false));
Bill Buzbeea114add2012-05-03 15:00:40 -0700848 } else {
buzbee1fd33462013-03-25 13:40:45 -0700849 RegLocation rl_method = LoadCurrMethod();
850 int res_reg = AllocTemp();
851 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
852 LoadWordDisp(rl_method.low_reg,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800853 mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), res_reg);
buzbee1fd33462013-03-25 13:40:45 -0700854 LoadWordDisp(res_reg, offset_of_string, rl_result.low_reg);
855 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700856 }
buzbee31a4a6f2012-02-28 15:36:15 -0800857}
858
859/*
860 * Let helper function take care of everything. Will
861 * call Class::NewInstanceFromCode(type_idx, method);
862 */
buzbee1fd33462013-03-25 13:40:45 -0700863void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800864{
buzbee1fd33462013-03-25 13:40:45 -0700865 FlushAllRegs(); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700866 // alloc will always check for resolution, do we also need to verify
867 // access because the verifier was unable to?
buzbeefa57c472012-11-21 12:06:18 -0800868 int func_offset;
buzbee1fd33462013-03-25 13:40:45 -0700869 if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks(
870 cu_->method_idx, *cu_->dex_file, type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800871 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700872 } else {
buzbeefa57c472012-11-21 12:06:18 -0800873 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700874 }
buzbee1fd33462013-03-25 13:40:45 -0700875 CallRuntimeHelperImmMethod(func_offset, type_idx, true);
876 RegLocation rl_result = GetReturn(false);
877 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800878}
879
buzbee1fd33462013-03-25 13:40:45 -0700880void Mir2Lir::GenThrow(RegLocation rl_src)
Ian Rogersab2b55d2012-03-18 00:06:11 -0700881{
buzbee1fd33462013-03-25 13:40:45 -0700882 FlushAllRegs();
883 CallRuntimeHelperRegLocation(ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700884}
885
buzbee1fd33462013-03-25 13:40:45 -0700886void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -0800887 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800888{
buzbee1fd33462013-03-25 13:40:45 -0700889 FlushAllRegs();
Bill Buzbeea114add2012-05-03 15:00:40 -0700890 // May generate a call - use explicit registers
buzbee1fd33462013-03-25 13:40:45 -0700891 LockCallTemps();
892 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
buzbeefa57c472012-11-21 12:06:18 -0800893 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
buzbee1fd33462013-03-25 13:40:45 -0700894 if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
895 *cu_->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700896 type_idx)) {
897 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -0800898 // returns Class* in kArg0
buzbee1fd33462013-03-25 13:40:45 -0700899 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -0700900 type_idx, true);
buzbee1fd33462013-03-25 13:40:45 -0700901 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
902 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -0700903 } else {
buzbeefa57c472012-11-21 12:06:18 -0800904 // Load dex cache entry into class_reg (kArg2)
buzbee1fd33462013-03-25 13:40:45 -0700905 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
906 LoadWordDisp(TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800907 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700908 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800909 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
Bill Buzbeea114add2012-05-03 15:00:40 -0700910 * type_idx);
buzbee1fd33462013-03-25 13:40:45 -0700911 LoadWordDisp(class_reg, offset_of_type, class_reg);
912 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
913 *cu_->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700914 // Need to test presence of type in dex cache at runtime
buzbee1fd33462013-03-25 13:40:45 -0700915 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700916 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -0800917 // Call out to helper, which will return resolved type in kRet0
buzbee1fd33462013-03-25 13:40:45 -0700918 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
919 OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
920 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -0700921 // Rejoin code paths
buzbee1fd33462013-03-25 13:40:45 -0700922 LIR* hop_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -0800923 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -0800924 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700925 }
buzbeef0504cd2012-11-13 16:31:10 -0800926 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
buzbee1fd33462013-03-25 13:40:45 -0700927 RegLocation rl_result = GetReturn(false);
928 if (cu_->instruction_set == kMips) {
929 LoadConstant(rl_result.low_reg, 0); // store false result for if branch is taken
buzbeeb046e162012-10-30 15:48:42 -0700930 }
buzbee1fd33462013-03-25 13:40:45 -0700931 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700932 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800933 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
buzbee1fd33462013-03-25 13:40:45 -0700934 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -0800935 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbeeb046e162012-10-30 15:48:42 -0700936 LIR* branchover = NULL;
buzbee1fd33462013-03-25 13:40:45 -0700937 if (cu_->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700938 /* Uses conditional nullification */
buzbee1fd33462013-03-25 13:40:45 -0700939 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
940 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
941 OpIT(kCondEq, "EE"); // if-convert the test
942 LoadConstant(TargetReg(kArg0), 1); // .eq case - load true
943 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
Ian Rogers397c0482013-05-31 16:46:31 -0700944 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
buzbee1fd33462013-03-25 13:40:45 -0700945 FreeTemp(r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700946 } else {
947 /* Uses branchovers */
buzbee1fd33462013-03-25 13:40:45 -0700948 LoadConstant(rl_result.low_reg, 1); // assume true
949 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
950 if (cu_->instruction_set != kX86) {
951 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
952 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
Ian Rogers397c0482013-05-31 16:46:31 -0700953 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
buzbee1fd33462013-03-25 13:40:45 -0700954 FreeTemp(r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700955 } else {
buzbee1fd33462013-03-25 13:40:45 -0700956 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
Ian Rogers397c0482013-05-31 16:46:31 -0700957 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
buzbeeb046e162012-10-30 15:48:42 -0700958 }
959 }
buzbee1fd33462013-03-25 13:40:45 -0700960 ClobberCalleeSave();
Bill Buzbeea114add2012-05-03 15:00:40 -0700961 /* branch targets here */
buzbee1fd33462013-03-25 13:40:45 -0700962 LIR* target = NewLIR0(kPseudoTargetLabel);
963 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700964 branch1->target = target;
buzbee1fd33462013-03-25 13:40:45 -0700965 if (cu_->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700966 branchover->target = target;
967 }
buzbee31a4a6f2012-02-28 15:36:15 -0800968}
969
Dragos Sbirlea980d16b2013-06-04 15:01:40 -0700970void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800971{
Dragos Sbirlea980d16b2013-06-04 15:01:40 -0700972 DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
973 const CompilerDriver::MethodReference mr(
974 cu->GetDexFile(),
975 cu->GetDexMethodIndex());
976
Ian Rogersfae370a2013-06-05 08:33:27 -0700977 if (cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
978 // Verifier type analysis proved this check cast would never cause an exception.
Dragos Sbirlea980d16b2013-06-04 15:01:40 -0700979 return;
980 }
buzbee1fd33462013-03-25 13:40:45 -0700981 FlushAllRegs();
Bill Buzbeea114add2012-05-03 15:00:40 -0700982 // May generate a call - use explicit registers
buzbee1fd33462013-03-25 13:40:45 -0700983 LockCallTemps();
984 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
buzbeefa57c472012-11-21 12:06:18 -0800985 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
buzbee1fd33462013-03-25 13:40:45 -0700986 if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
987 *cu_->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700988 type_idx)) {
989 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -0800990 // returns Class* in kRet0
Bill Buzbeea114add2012-05-03 15:00:40 -0700991 // InitializeTypeAndVerifyAccess(idx, method)
buzbee1fd33462013-03-25 13:40:45 -0700992 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee52a77fc2012-11-20 19:50:46 -0800993 type_idx, TargetReg(kArg1), true);
buzbee1fd33462013-03-25 13:40:45 -0700994 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -0700995 } else {
buzbeefa57c472012-11-21 12:06:18 -0800996 // Load dex cache entry into class_reg (kArg2)
buzbee1fd33462013-03-25 13:40:45 -0700997 LoadWordDisp(TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800998 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700999 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001000 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
1001 (sizeof(mirror::Class*) * type_idx);
buzbee1fd33462013-03-25 13:40:45 -07001002 LoadWordDisp(class_reg, offset_of_type, class_reg);
1003 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
1004 *cu_->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001005 // Need to test presence of type in dex cache at runtime
buzbee1fd33462013-03-25 13:40:45 -07001006 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001007 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001008 // Call out to helper, which will return resolved type in kArg0
Bill Buzbeea114add2012-05-03 15:00:40 -07001009 // InitializeTypeFromCode(idx, method)
buzbee1fd33462013-03-25 13:40:45 -07001010 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001011 true);
buzbee1fd33462013-03-25 13:40:45 -07001012 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001013 // Rejoin code paths
buzbee1fd33462013-03-25 13:40:45 -07001014 LIR* hop_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001015 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -08001016 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 }
buzbeefa57c472012-11-21 12:06:18 -08001018 // At this point, class_reg (kArg2) has class
buzbee1fd33462013-03-25 13:40:45 -07001019 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001020 /* Null is OK - continue */
buzbee1fd33462013-03-25 13:40:45 -07001021 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001022 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001023 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
buzbee1fd33462013-03-25 13:40:45 -07001024 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001025 /* kArg1 now contains object->klass_ */
buzbeeb046e162012-10-30 15:48:42 -07001026 LIR* branch2;
buzbee1fd33462013-03-25 13:40:45 -07001027 if (cu_->instruction_set == kThumb2) {
1028 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pCheckCastFromCode));
1029 OpRegReg(kOpCmp, TargetReg(kArg1), class_reg);
1030 branch2 = OpCondBranch(kCondEq, NULL); /* If eq, trivial yes */
1031 OpRegCopy(TargetReg(kArg0), TargetReg(kArg1));
1032 OpRegCopy(TargetReg(kArg1), TargetReg(kArg2));
1033 ClobberCalleeSave();
1034 LIR* call_inst = OpReg(kOpBlx, r_tgt);
1035 MarkSafepointPC(call_inst);
1036 FreeTemp(r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001037 } else {
buzbee1fd33462013-03-25 13:40:45 -07001038 branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
1039 CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
buzbeeb046e162012-10-30 15:48:42 -07001040 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001041 /* branch target here */
buzbee1fd33462013-03-25 13:40:45 -07001042 LIR* target = NewLIR0(kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001043 branch1->target = target;
1044 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001045}
1046
buzbee1fd33462013-03-25 13:40:45 -07001047void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
1048 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001049{
buzbeefa57c472012-11-21 12:06:18 -08001050 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001051 if (cu_->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001052 /*
1053 * NOTE: This is the one place in the code in which we might have
1054 * as many as six live temporary registers. There are 5 in the normal
1055 * set for Arm. Until we have spill capabilities, temporarily add
1056 * lr to the temp set. It is safe to do this locally, but note that
1057 * lr is used explicitly elsewhere in the code generator and cannot
1058 * normally be used as a general temp register.
1059 */
buzbee1fd33462013-03-25 13:40:45 -07001060 MarkTemp(TargetReg(kLr)); // Add lr to the temp pool
1061 FreeTemp(TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001062 }
buzbee1fd33462013-03-25 13:40:45 -07001063 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1064 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1065 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001066 // The longs may overlap - use intermediate temp if so
buzbeefa57c472012-11-21 12:06:18 -08001067 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)){
buzbee1fd33462013-03-25 13:40:45 -07001068 int t_reg = AllocTemp();
1069 OpRegRegReg(first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1070 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1071 OpRegCopy(rl_result.low_reg, t_reg);
1072 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001073 } else {
buzbee1fd33462013-03-25 13:40:45 -07001074 OpRegRegReg(first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1075 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg,
buzbeefa57c472012-11-21 12:06:18 -08001076 rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001077 }
1078 /*
buzbeefa57c472012-11-21 12:06:18 -08001079 * NOTE: If rl_dest refers to a frame variable in a large frame, the
buzbee52a77fc2012-11-20 19:50:46 -08001080 * following StoreValueWide might need to allocate a temp register.
Bill Buzbeea114add2012-05-03 15:00:40 -07001081 * To further work around the lack of a spill capability, explicitly
buzbeefa57c472012-11-21 12:06:18 -08001082 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
Bill Buzbeea114add2012-05-03 15:00:40 -07001083 * Remove when spill is functional.
1084 */
buzbee1fd33462013-03-25 13:40:45 -07001085 FreeRegLocTemps(rl_result, rl_src1);
1086 FreeRegLocTemps(rl_result, rl_src2);
1087 StoreValueWide(rl_dest, rl_result);
1088 if (cu_->instruction_set == kThumb2) {
1089 Clobber(TargetReg(kLr));
1090 UnmarkTemp(TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001091 }
buzbee31a4a6f2012-02-28 15:36:15 -08001092}
1093
1094
buzbee1fd33462013-03-25 13:40:45 -07001095void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001096 RegLocation rl_src1, RegLocation rl_shift)
buzbee31a4a6f2012-02-28 15:36:15 -08001097{
buzbeea5954be2013-02-07 10:41:40 -08001098 int func_offset = -1; // Make gcc happy
buzbee31a4a6f2012-02-28 15:36:15 -08001099
buzbee408ad162012-06-06 16:45:18 -07001100 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001101 case Instruction::SHL_LONG:
1102 case Instruction::SHL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001103 func_offset = ENTRYPOINT_OFFSET(pShlLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001104 break;
1105 case Instruction::SHR_LONG:
1106 case Instruction::SHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001107 func_offset = ENTRYPOINT_OFFSET(pShrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001108 break;
1109 case Instruction::USHR_LONG:
1110 case Instruction::USHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001111 func_offset = ENTRYPOINT_OFFSET(pUshrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001112 break;
1113 default:
1114 LOG(FATAL) << "Unexpected case";
Bill Buzbeea114add2012-05-03 15:00:40 -07001115 }
buzbee1fd33462013-03-25 13:40:45 -07001116 FlushAllRegs(); /* Send everything to home location */
1117 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false);
1118 RegLocation rl_result = GetReturnWide(false);
1119 StoreValueWide(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001120}
1121
1122
buzbee1fd33462013-03-25 13:40:45 -07001123void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001124 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001125{
Bill Buzbeea114add2012-05-03 15:00:40 -07001126 OpKind op = kOpBkpt;
buzbeefa57c472012-11-21 12:06:18 -08001127 bool is_div_rem = false;
1128 bool check_zero = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001129 bool unary = false;
buzbeefa57c472012-11-21 12:06:18 -08001130 RegLocation rl_result;
1131 bool shift_op = false;
buzbee408ad162012-06-06 16:45:18 -07001132 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001133 case Instruction::NEG_INT:
1134 op = kOpNeg;
1135 unary = true;
1136 break;
1137 case Instruction::NOT_INT:
1138 op = kOpMvn;
1139 unary = true;
1140 break;
1141 case Instruction::ADD_INT:
1142 case Instruction::ADD_INT_2ADDR:
1143 op = kOpAdd;
1144 break;
1145 case Instruction::SUB_INT:
1146 case Instruction::SUB_INT_2ADDR:
1147 op = kOpSub;
1148 break;
1149 case Instruction::MUL_INT:
1150 case Instruction::MUL_INT_2ADDR:
1151 op = kOpMul;
1152 break;
1153 case Instruction::DIV_INT:
1154 case Instruction::DIV_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001155 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001156 op = kOpDiv;
buzbeefa57c472012-11-21 12:06:18 -08001157 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001158 break;
buzbeef0504cd2012-11-13 16:31:10 -08001159 /* NOTE: returns in kArg1 */
Bill Buzbeea114add2012-05-03 15:00:40 -07001160 case Instruction::REM_INT:
1161 case Instruction::REM_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001162 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001163 op = kOpRem;
buzbeefa57c472012-11-21 12:06:18 -08001164 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001165 break;
1166 case Instruction::AND_INT:
1167 case Instruction::AND_INT_2ADDR:
1168 op = kOpAnd;
1169 break;
1170 case Instruction::OR_INT:
1171 case Instruction::OR_INT_2ADDR:
1172 op = kOpOr;
1173 break;
1174 case Instruction::XOR_INT:
1175 case Instruction::XOR_INT_2ADDR:
1176 op = kOpXor;
1177 break;
1178 case Instruction::SHL_INT:
1179 case Instruction::SHL_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001180 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001181 op = kOpLsl;
1182 break;
1183 case Instruction::SHR_INT:
1184 case Instruction::SHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001185 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001186 op = kOpAsr;
1187 break;
1188 case Instruction::USHR_INT:
1189 case Instruction::USHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001190 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001191 op = kOpLsr;
1192 break;
1193 default:
buzbeecbd6d442012-11-17 14:11:25 -08001194 LOG(FATAL) << "Invalid word arith op: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001195 }
buzbeefa57c472012-11-21 12:06:18 -08001196 if (!is_div_rem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001197 if (unary) {
buzbee1fd33462013-03-25 13:40:45 -07001198 rl_src1 = LoadValue(rl_src1, kCoreReg);
1199 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1200 OpRegReg(op, rl_result.low_reg, rl_src1.low_reg);
buzbee31a4a6f2012-02-28 15:36:15 -08001201 } else {
buzbeefa57c472012-11-21 12:06:18 -08001202 if (shift_op) {
1203 int t_reg = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -07001204 if (cu_->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001205 // X86 doesn't require masking and must use ECX
buzbeefa57c472012-11-21 12:06:18 -08001206 t_reg = TargetReg(kCount); // rCX
buzbee1fd33462013-03-25 13:40:45 -07001207 LoadValueDirectFixed(rl_src2, t_reg);
buzbeeb046e162012-10-30 15:48:42 -07001208 } else {
buzbee1fd33462013-03-25 13:40:45 -07001209 rl_src2 = LoadValue(rl_src2, kCoreReg);
1210 t_reg = AllocTemp();
1211 OpRegRegImm(kOpAnd, t_reg, rl_src2.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001212 }
buzbee1fd33462013-03-25 13:40:45 -07001213 rl_src1 = LoadValue(rl_src1, kCoreReg);
1214 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1215 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1216 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001217 } else {
buzbee1fd33462013-03-25 13:40:45 -07001218 rl_src1 = LoadValue(rl_src1, kCoreReg);
1219 rl_src2 = LoadValue(rl_src2, kCoreReg);
1220 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1221 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001222 }
buzbee31a4a6f2012-02-28 15:36:15 -08001223 }
buzbee1fd33462013-03-25 13:40:45 -07001224 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001225 } else {
buzbee1fd33462013-03-25 13:40:45 -07001226 if (cu_->instruction_set == kMips) {
1227 rl_src1 = LoadValue(rl_src1, kCoreReg);
1228 rl_src2 = LoadValue(rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001229 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001230 GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001231 }
buzbee1fd33462013-03-25 13:40:45 -07001232 rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001233 } else {
buzbeefa57c472012-11-21 12:06:18 -08001234 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee1fd33462013-03-25 13:40:45 -07001235 FlushAllRegs(); /* Send everything to home location */
1236 LoadValueDirectFixed(rl_src2, TargetReg(kArg1));
1237 int r_tgt = CallHelperSetup(func_offset);
1238 LoadValueDirectFixed(rl_src1, TargetReg(kArg0));
buzbeefa57c472012-11-21 12:06:18 -08001239 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001240 GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001241 }
1242 // NOTE: callout here is not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001243 CallHelper(r_tgt, func_offset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001244 if (op == kOpDiv)
buzbee1fd33462013-03-25 13:40:45 -07001245 rl_result = GetReturn(false);
buzbeeb046e162012-10-30 15:48:42 -07001246 else
buzbee1fd33462013-03-25 13:40:45 -07001247 rl_result = GetReturnAlt();
jeffhao4f8f04a2012-10-02 18:10:35 -07001248 }
buzbee1fd33462013-03-25 13:40:45 -07001249 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001250 }
buzbee31a4a6f2012-02-28 15:36:15 -08001251}
1252
1253/*
1254 * The following are the first-level codegen routines that analyze the format
1255 * of each bytecode then either dispatch special purpose codegen routines
1256 * or produce corresponding Thumb instructions directly.
1257 */
1258
buzbeeaad94382012-11-21 07:40:50 -08001259static bool IsPowerOfTwo(int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001260{
Bill Buzbeea114add2012-05-03 15:00:40 -07001261 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001262}
1263
1264// Returns true if no more than two bits are set in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001265static bool IsPopCountLE2(unsigned int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001266{
Bill Buzbeea114add2012-05-03 15:00:40 -07001267 x &= x - 1;
1268 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001269}
1270
1271// Returns the index of the lowest set bit in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001272static int LowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001273 int bit_posn = 0;
1274 while ((x & 0xf) == 0) {
1275 bit_posn += 4;
1276 x >>= 4;
1277 }
1278 while ((x & 1) == 0) {
1279 bit_posn++;
1280 x >>= 1;
1281 }
1282 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001283}
1284
buzbeefa57c472012-11-21 12:06:18 -08001285// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1286// and store the result in 'rl_dest'.
buzbee1fd33462013-03-25 13:40:45 -07001287bool Mir2Lir::HandleEasyDivide(Instruction::Code dalvik_opcode,
1288 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001289{
buzbee1fd33462013-03-25 13:40:45 -07001290 if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001291 return false;
buzbee0f79d722012-11-01 15:35:27 -07001292 }
buzbeeb046e162012-10-30 15:48:42 -07001293 // No divide instruction for Arm, so check for more special cases
buzbee1fd33462013-03-25 13:40:45 -07001294 if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
1295 return SmallLiteralDivide(dalvik_opcode, rl_src, rl_dest, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001296 }
buzbee52a77fc2012-11-20 19:50:46 -08001297 int k = LowestSetBit(lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001298 if (k >= 30) {
1299 // Avoid special cases.
1300 return false;
1301 }
buzbeefa57c472012-11-21 12:06:18 -08001302 bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
1303 dalvik_opcode == Instruction::DIV_INT_LIT16);
buzbee1fd33462013-03-25 13:40:45 -07001304 rl_src = LoadValue(rl_src, kCoreReg);
1305 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001306 if (div) {
buzbee1fd33462013-03-25 13:40:45 -07001307 int t_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -07001308 if (lit == 2) {
1309 // Division by 2 is by far the most common division by constant.
buzbee1fd33462013-03-25 13:40:45 -07001310 OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1311 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1312 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001313 } else {
buzbee1fd33462013-03-25 13:40:45 -07001314 OpRegRegImm(kOpAsr, t_reg, rl_src.low_reg, 31);
1315 OpRegRegImm(kOpLsr, t_reg, t_reg, 32 - k);
1316 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1317 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001318 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001319 } else {
buzbee1fd33462013-03-25 13:40:45 -07001320 int t_reg1 = AllocTemp();
1321 int t_reg2 = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -07001322 if (lit == 2) {
buzbee1fd33462013-03-25 13:40:45 -07001323 OpRegRegImm(kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1324 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1325 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit -1);
1326 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001327 } else {
buzbee1fd33462013-03-25 13:40:45 -07001328 OpRegRegImm(kOpAsr, t_reg1, rl_src.low_reg, 31);
1329 OpRegRegImm(kOpLsr, t_reg1, t_reg1, 32 - k);
1330 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1331 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1);
1332 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001333 }
1334 }
buzbee1fd33462013-03-25 13:40:45 -07001335 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001336 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001337}
1338
buzbeefa57c472012-11-21 12:06:18 -08001339// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1340// and store the result in 'rl_dest'.
buzbee1fd33462013-03-25 13:40:45 -07001341bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001342{
Bill Buzbeea114add2012-05-03 15:00:40 -07001343 // Can we simplify this multiplication?
buzbeefa57c472012-11-21 12:06:18 -08001344 bool power_of_two = false;
1345 bool pop_count_le2 = false;
1346 bool power_of_two_minus_one = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001347 if (lit < 2) {
1348 // Avoid special cases.
1349 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001350 } else if (IsPowerOfTwo(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001351 power_of_two = true;
buzbee52a77fc2012-11-20 19:50:46 -08001352 } else if (IsPopCountLE2(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001353 pop_count_le2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001354 } else if (IsPowerOfTwo(lit + 1)) {
buzbeefa57c472012-11-21 12:06:18 -08001355 power_of_two_minus_one = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001356 } else {
1357 return false;
1358 }
buzbee1fd33462013-03-25 13:40:45 -07001359 rl_src = LoadValue(rl_src, kCoreReg);
1360 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbeefa57c472012-11-21 12:06:18 -08001361 if (power_of_two) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001362 // Shift.
buzbee1fd33462013-03-25 13:40:45 -07001363 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit));
buzbeefa57c472012-11-21 12:06:18 -08001364 } else if (pop_count_le2) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001365 // Shift and add and shift.
buzbeefa57c472012-11-21 12:06:18 -08001366 int first_bit = LowestSetBit(lit);
1367 int second_bit = LowestSetBit(lit ^ (1 << first_bit));
buzbee1fd33462013-03-25 13:40:45 -07001368 GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001369 } else {
1370 // Reverse subtract: (src << (shift + 1)) - src.
buzbeefa57c472012-11-21 12:06:18 -08001371 DCHECK(power_of_two_minus_one);
buzbee52a77fc2012-11-20 19:50:46 -08001372 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
buzbee1fd33462013-03-25 13:40:45 -07001373 int t_reg = AllocTemp();
1374 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1375 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001376 }
buzbee1fd33462013-03-25 13:40:45 -07001377 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001378 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001379}
1380
buzbee1fd33462013-03-25 13:40:45 -07001381void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src,
1382 int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001383{
buzbeefa57c472012-11-21 12:06:18 -08001384 RegLocation rl_result;
buzbeecbd6d442012-11-17 14:11:25 -08001385 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
buzbeefa57c472012-11-21 12:06:18 -08001386 int shift_op = false;
1387 bool is_div = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001388
buzbee408ad162012-06-06 16:45:18 -07001389 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001390 case Instruction::RSUB_INT_LIT8:
1391 case Instruction::RSUB_INT: {
buzbee1fd33462013-03-25 13:40:45 -07001392 rl_src = LoadValue(rl_src, kCoreReg);
1393 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1394 if (cu_->instruction_set == kThumb2) {
1395 OpRegRegImm(kOpRsub, rl_result.low_reg, rl_src.low_reg, lit);
buzbeec7d1f912013-02-07 15:22:39 -08001396 } else {
buzbee1fd33462013-03-25 13:40:45 -07001397 OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg);
1398 OpRegImm(kOpAdd, rl_result.low_reg, lit);
buzbeec7d1f912013-02-07 15:22:39 -08001399 }
buzbee1fd33462013-03-25 13:40:45 -07001400 StoreValue(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001401 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001402 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001403
buzbeee6285f92012-12-06 15:57:46 -08001404 case Instruction::SUB_INT:
1405 case Instruction::SUB_INT_2ADDR:
1406 lit = -lit;
1407 // Intended fallthrough
1408 case Instruction::ADD_INT:
1409 case Instruction::ADD_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001410 case Instruction::ADD_INT_LIT8:
1411 case Instruction::ADD_INT_LIT16:
1412 op = kOpAdd;
1413 break;
buzbeee6285f92012-12-06 15:57:46 -08001414 case Instruction::MUL_INT:
1415 case Instruction::MUL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001416 case Instruction::MUL_INT_LIT8:
1417 case Instruction::MUL_INT_LIT16: {
buzbee1fd33462013-03-25 13:40:45 -07001418 if (HandleEasyMultiply(rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001419 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001420 }
1421 op = kOpMul;
1422 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001423 }
buzbeee6285f92012-12-06 15:57:46 -08001424 case Instruction::AND_INT:
1425 case Instruction::AND_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001426 case Instruction::AND_INT_LIT8:
1427 case Instruction::AND_INT_LIT16:
1428 op = kOpAnd;
1429 break;
buzbeee6285f92012-12-06 15:57:46 -08001430 case Instruction::OR_INT:
1431 case Instruction::OR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001432 case Instruction::OR_INT_LIT8:
1433 case Instruction::OR_INT_LIT16:
1434 op = kOpOr;
1435 break;
buzbeee6285f92012-12-06 15:57:46 -08001436 case Instruction::XOR_INT:
1437 case Instruction::XOR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001438 case Instruction::XOR_INT_LIT8:
1439 case Instruction::XOR_INT_LIT16:
1440 op = kOpXor;
1441 break;
1442 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001443 case Instruction::SHL_INT:
buzbeee6285f92012-12-06 15:57:46 -08001444 case Instruction::SHL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001445 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001446 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001447 op = kOpLsl;
1448 break;
1449 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001450 case Instruction::SHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001451 case Instruction::SHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001452 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001453 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001454 op = kOpAsr;
1455 break;
1456 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001457 case Instruction::USHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001458 case Instruction::USHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001459 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001460 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001461 op = kOpLsr;
1462 break;
1463
buzbeee6285f92012-12-06 15:57:46 -08001464 case Instruction::DIV_INT:
1465 case Instruction::DIV_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001466 case Instruction::DIV_INT_LIT8:
1467 case Instruction::DIV_INT_LIT16:
buzbeee6285f92012-12-06 15:57:46 -08001468 case Instruction::REM_INT:
1469 case Instruction::REM_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001470 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07001471 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07001472 if (lit == 0) {
buzbee1fd33462013-03-25 13:40:45 -07001473 GenImmedCheck(kCondAl, 0, 0, kThrowDivZero);
buzbeea5954be2013-02-07 10:41:40 -08001474 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001475 }
buzbee1fd33462013-03-25 13:40:45 -07001476 if (HandleEasyDivide(opcode, rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001477 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001478 }
buzbee408ad162012-06-06 16:45:18 -07001479 if ((opcode == Instruction::DIV_INT_LIT8) ||
buzbeee6285f92012-12-06 15:57:46 -08001480 (opcode == Instruction::DIV_INT) ||
1481 (opcode == Instruction::DIV_INT_2ADDR) ||
buzbee408ad162012-06-06 16:45:18 -07001482 (opcode == Instruction::DIV_INT_LIT16)) {
buzbeefa57c472012-11-21 12:06:18 -08001483 is_div = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001484 } else {
buzbeefa57c472012-11-21 12:06:18 -08001485 is_div = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001486 }
buzbee1fd33462013-03-25 13:40:45 -07001487 if (cu_->instruction_set == kMips) {
1488 rl_src = LoadValue(rl_src, kCoreReg);
1489 rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
jeffhao4f8f04a2012-10-02 18:10:35 -07001490 } else {
buzbee1fd33462013-03-25 13:40:45 -07001491 FlushAllRegs(); /* Everything to home location */
1492 LoadValueDirectFixed(rl_src, TargetReg(kArg0));
1493 Clobber(TargetReg(kArg0));
buzbeefa57c472012-11-21 12:06:18 -08001494 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee1fd33462013-03-25 13:40:45 -07001495 CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false);
buzbeefa57c472012-11-21 12:06:18 -08001496 if (is_div)
buzbee1fd33462013-03-25 13:40:45 -07001497 rl_result = GetReturn(false);
buzbeeb046e162012-10-30 15:48:42 -07001498 else
buzbee1fd33462013-03-25 13:40:45 -07001499 rl_result = GetReturnAlt();
jeffhao4f8f04a2012-10-02 18:10:35 -07001500 }
buzbee1fd33462013-03-25 13:40:45 -07001501 StoreValue(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001502 return;
jeffhao4f8f04a2012-10-02 18:10:35 -07001503 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001504 default:
buzbeee6285f92012-12-06 15:57:46 -08001505 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001506 }
buzbee1fd33462013-03-25 13:40:45 -07001507 rl_src = LoadValue(rl_src, kCoreReg);
1508 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001509 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
buzbeefa57c472012-11-21 12:06:18 -08001510 if (shift_op && (lit == 0)) {
buzbee1fd33462013-03-25 13:40:45 -07001511 OpRegCopy(rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001512 } else {
buzbee1fd33462013-03-25 13:40:45 -07001513 OpRegRegImm(op, rl_result.low_reg, rl_src.low_reg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001514 }
buzbee1fd33462013-03-25 13:40:45 -07001515 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001516}
1517
buzbee1fd33462013-03-25 13:40:45 -07001518void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001519 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001520{
buzbeefa57c472012-11-21 12:06:18 -08001521 RegLocation rl_result;
1522 OpKind first_op = kOpBkpt;
1523 OpKind second_op = kOpBkpt;
1524 bool call_out = false;
1525 bool check_zero = false;
1526 int func_offset;
1527 int ret_reg = TargetReg(kRet0);
buzbee31a4a6f2012-02-28 15:36:15 -08001528
buzbee408ad162012-06-06 16:45:18 -07001529 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001530 case Instruction::NOT_LONG:
buzbee1fd33462013-03-25 13:40:45 -07001531 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1532 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001533 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -08001534 if (rl_result.low_reg == rl_src2.high_reg) {
buzbee1fd33462013-03-25 13:40:45 -07001535 int t_reg = AllocTemp();
1536 OpRegCopy(t_reg, rl_src2.high_reg);
1537 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1538 OpRegReg(kOpMvn, rl_result.high_reg, t_reg);
1539 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001540 } else {
buzbee1fd33462013-03-25 13:40:45 -07001541 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1542 OpRegReg(kOpMvn, rl_result.high_reg, rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001543 }
buzbee1fd33462013-03-25 13:40:45 -07001544 StoreValueWide(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001545 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001546 case Instruction::ADD_LONG:
1547 case Instruction::ADD_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001548 if (cu_->instruction_set != kThumb2) {
1549 GenAddLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001550 return;
buzbeeb046e162012-10-30 15:48:42 -07001551 }
buzbeefa57c472012-11-21 12:06:18 -08001552 first_op = kOpAdd;
1553 second_op = kOpAdc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001554 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001555 case Instruction::SUB_LONG:
1556 case Instruction::SUB_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001557 if (cu_->instruction_set != kThumb2) {
1558 GenSubLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001559 return;
buzbeeb046e162012-10-30 15:48:42 -07001560 }
buzbeefa57c472012-11-21 12:06:18 -08001561 first_op = kOpSub;
1562 second_op = kOpSbc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001563 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001564 case Instruction::MUL_LONG:
1565 case Instruction::MUL_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001566 if (cu_->instruction_set == kThumb2) {
1567 GenMulLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001568 return;
buzbee4ef3e452012-12-14 13:35:28 -08001569 } else {
1570 call_out = true;
1571 ret_reg = TargetReg(kRet0);
1572 func_offset = ENTRYPOINT_OFFSET(pLmul);
1573 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001574 break;
1575 case Instruction::DIV_LONG:
1576 case Instruction::DIV_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001577 call_out = true;
1578 check_zero = true;
1579 ret_reg = TargetReg(kRet0);
1580 func_offset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 break;
1582 case Instruction::REM_LONG:
1583 case Instruction::REM_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001584 call_out = true;
1585 check_zero = true;
1586 func_offset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08001587 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbee1fd33462013-03-25 13:40:45 -07001588 ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001589 break;
1590 case Instruction::AND_LONG_2ADDR:
1591 case Instruction::AND_LONG:
buzbee1fd33462013-03-25 13:40:45 -07001592 if (cu_->instruction_set == kX86) {
1593 return GenAndLong(rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001594 }
buzbeefa57c472012-11-21 12:06:18 -08001595 first_op = kOpAnd;
1596 second_op = kOpAnd;
Bill Buzbeea114add2012-05-03 15:00:40 -07001597 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001598 case Instruction::OR_LONG:
1599 case Instruction::OR_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001600 if (cu_->instruction_set == kX86) {
1601 GenOrLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001602 return;
buzbeeb046e162012-10-30 15:48:42 -07001603 }
buzbeefa57c472012-11-21 12:06:18 -08001604 first_op = kOpOr;
1605 second_op = kOpOr;
Bill Buzbeea114add2012-05-03 15:00:40 -07001606 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001607 case Instruction::XOR_LONG:
1608 case Instruction::XOR_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001609 if (cu_->instruction_set == kX86) {
1610 GenXorLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001611 return;
buzbeeb046e162012-10-30 15:48:42 -07001612 }
buzbeefa57c472012-11-21 12:06:18 -08001613 first_op = kOpXor;
1614 second_op = kOpXor;
Bill Buzbeea114add2012-05-03 15:00:40 -07001615 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001616 case Instruction::NEG_LONG: {
buzbee1fd33462013-03-25 13:40:45 -07001617 GenNegLong(rl_dest, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001618 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001619 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001620 default:
1621 LOG(FATAL) << "Invalid long arith op";
1622 }
buzbeefa57c472012-11-21 12:06:18 -08001623 if (!call_out) {
buzbee1fd33462013-03-25 13:40:45 -07001624 GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2);
Bill Buzbeea114add2012-05-03 15:00:40 -07001625 } else {
buzbee1fd33462013-03-25 13:40:45 -07001626 FlushAllRegs(); /* Send everything to home location */
buzbeefa57c472012-11-21 12:06:18 -08001627 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001628 LoadValueDirectWideFixed(rl_src2, TargetReg(kArg2), TargetReg(kArg3));
1629 int r_tgt = CallHelperSetup(func_offset);
1630 GenDivZeroCheck(TargetReg(kArg2), TargetReg(kArg3));
1631 LoadValueDirectWideFixed(rl_src1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07001632 // NOTE: callout here is not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001633 CallHelper(r_tgt, func_offset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08001634 } else {
buzbee1fd33462013-03-25 13:40:45 -07001635 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001636 }
buzbeef0504cd2012-11-13 16:31:10 -08001637 // Adjust return regs in to handle case of rem returning kArg2/kArg3
buzbeefa57c472012-11-21 12:06:18 -08001638 if (ret_reg == TargetReg(kRet0))
buzbee1fd33462013-03-25 13:40:45 -07001639 rl_result = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -07001640 else
buzbee1fd33462013-03-25 13:40:45 -07001641 rl_result = GetReturnWideAlt();
1642 StoreValueWide(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001643 }
buzbee31a4a6f2012-02-28 15:36:15 -08001644}
1645
buzbee1fd33462013-03-25 13:40:45 -07001646void Mir2Lir::GenConversionCall(int func_offset,
buzbee02031b12012-11-23 09:41:35 -08001647 RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001648{
Bill Buzbeea114add2012-05-03 15:00:40 -07001649 /*
1650 * Don't optimize the register usage since it calls out to support
1651 * functions
1652 */
buzbee1fd33462013-03-25 13:40:45 -07001653 FlushAllRegs(); /* Send everything to home location */
buzbeefa57c472012-11-21 12:06:18 -08001654 if (rl_src.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001655 LoadValueDirectWideFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -08001656 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07001657 } else {
buzbee1fd33462013-03-25 13:40:45 -07001658 LoadValueDirectFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07001659 }
buzbee1fd33462013-03-25 13:40:45 -07001660 CallRuntimeHelperRegLocation(func_offset, rl_src, false);
buzbeefa57c472012-11-21 12:06:18 -08001661 if (rl_dest.wide) {
1662 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001663 rl_result = GetReturnWide(rl_dest.fp);
1664 StoreValueWide(rl_dest, rl_result);
buzbee408ad162012-06-06 16:45:18 -07001665 } else {
buzbeefa57c472012-11-21 12:06:18 -08001666 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001667 rl_result = GetReturn(rl_dest.fp);
1668 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001669 }
buzbee31a4a6f2012-02-28 15:36:15 -08001670}
1671
buzbee31a4a6f2012-02-28 15:36:15 -08001672/* Check if we need to check for pending suspend request */
buzbee1fd33462013-03-25 13:40:45 -07001673void Mir2Lir::GenSuspendTest(int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -08001674{
buzbeefa57c472012-11-21 12:06:18 -08001675 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001676 return;
1677 }
buzbee1fd33462013-03-25 13:40:45 -07001678 FlushAllRegs();
1679 LIR* branch = OpTestSuspend(NULL);
1680 LIR* ret_lab = NewLIR0(kPseudoTargetLabel);
1681 LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1682 reinterpret_cast<uintptr_t>(ret_lab), current_dalvik_offset_);
buzbeecbd6d442012-11-17 14:11:25 -08001683 branch->target = target;
buzbee862a7602013-04-05 10:58:54 -07001684 suspend_launchpads_.Insert(target);
buzbee31a4a6f2012-02-28 15:36:15 -08001685}
1686
buzbeefead2932012-03-30 14:02:01 -07001687/* Check if we need to check for pending suspend request */
buzbee1fd33462013-03-25 13:40:45 -07001688void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07001689{
buzbeefa57c472012-11-21 12:06:18 -08001690 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbee1fd33462013-03-25 13:40:45 -07001691 OpUnconditionalBranch(target);
Bill Buzbeea114add2012-05-03 15:00:40 -07001692 return;
1693 }
buzbee1fd33462013-03-25 13:40:45 -07001694 OpTestSuspend(target);
buzbeefa57c472012-11-21 12:06:18 -08001695 LIR* launch_pad =
buzbee1fd33462013-03-25 13:40:45 -07001696 RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1697 reinterpret_cast<uintptr_t>(target), current_dalvik_offset_);
1698 FlushAllRegs();
1699 OpUnconditionalBranch(launch_pad);
buzbee862a7602013-04-05 10:58:54 -07001700 suspend_launchpads_.Insert(launch_pad);
buzbeefead2932012-03-30 14:02:01 -07001701}
1702
buzbee31a4a6f2012-02-28 15:36:15 -08001703} // namespace art