blob: 2980acbd06c788874dc3c2460be986336a952a64 [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
Ian Rogersc9e463c2013-06-05 16:52:26 -0700886// For final classes there are no sub-classes to check and so we can answer the instance-of
887// question with simple comparisons.
888void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
889 RegLocation rl_src) {
890 RegLocation object = LoadValue(rl_src, kCoreReg);
891 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
892 int result_reg = rl_result.low_reg;
893 if (result_reg == object.low_reg) {
894 result_reg = AllocTypedTemp(false, kCoreReg);
895 }
896 LoadConstant(result_reg, 0); // assume false
897 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL);
898
899 int check_class = AllocTypedTemp(false, kCoreReg);
900 int object_class = AllocTypedTemp(false, kCoreReg);
901
902 LoadCurrMethodDirect(check_class);
903 if (use_declaring_class) {
904 LoadWordDisp(check_class, mirror::AbstractMethod::DeclaringClassOffset().Int32Value(),
905 check_class);
906 LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class);
907 } else {
908 LoadWordDisp(check_class, mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(),
909 check_class);
910 LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class);
911 int32_t offset_of_type =
912 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
913 (sizeof(mirror::Class*) * type_idx);
914 LoadWordDisp(check_class, offset_of_type, check_class);
915 }
916
917 LIR* ne_branchover = NULL;
918 if (cu_->instruction_set == kThumb2) {
919 OpRegReg(kOpCmp, check_class, object_class); // Same?
920 OpIT(kCondEq, ""); // if-convert the test
921 LoadConstant(result_reg, 1); // .eq case - load true
922 } else {
923 ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL);
924 LoadConstant(result_reg, 1); // eq case - load true
925 }
926 LIR* target = NewLIR0(kPseudoTargetLabel);
927 null_branchover->target = target;
928 if (ne_branchover != NULL) {
929 ne_branchover->target = target;
930 }
931 FreeTemp(object_class);
932 FreeTemp(check_class);
933 if (IsTemp(result_reg)) {
934 OpRegCopy(rl_result.low_reg, result_reg);
935 FreeTemp(result_reg);
936 }
937 StoreValue(rl_dest, rl_result);
938}
939
940void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
941 bool type_known_abstract, bool use_declaring_class,
942 bool can_assume_type_is_in_dex_cache,
943 uint32_t type_idx, RegLocation rl_dest,
944 RegLocation rl_src) {
buzbee1fd33462013-03-25 13:40:45 -0700945 FlushAllRegs();
Bill Buzbeea114add2012-05-03 15:00:40 -0700946 // May generate a call - use explicit registers
buzbee1fd33462013-03-25 13:40:45 -0700947 LockCallTemps();
948 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
buzbeefa57c472012-11-21 12:06:18 -0800949 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
Ian Rogersc9e463c2013-06-05 16:52:26 -0700950 if (needs_access_check) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -0800952 // returns Class* in kArg0
buzbee1fd33462013-03-25 13:40:45 -0700953 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -0700954 type_idx, true);
buzbee1fd33462013-03-25 13:40:45 -0700955 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
956 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
Ian Rogersc9e463c2013-06-05 16:52:26 -0700957 } else if (use_declaring_class) {
958 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
959 LoadWordDisp(TargetReg(kArg1),
960 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700961 } else {
buzbeefa57c472012-11-21 12:06:18 -0800962 // Load dex cache entry into class_reg (kArg2)
buzbee1fd33462013-03-25 13:40:45 -0700963 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
964 LoadWordDisp(TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800965 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700966 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800967 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
Bill Buzbeea114add2012-05-03 15:00:40 -0700968 * type_idx);
buzbee1fd33462013-03-25 13:40:45 -0700969 LoadWordDisp(class_reg, offset_of_type, class_reg);
Ian Rogersc9e463c2013-06-05 16:52:26 -0700970 if (!can_assume_type_is_in_dex_cache) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700971 // Need to test presence of type in dex cache at runtime
buzbee1fd33462013-03-25 13:40:45 -0700972 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700973 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -0800974 // Call out to helper, which will return resolved type in kRet0
buzbee1fd33462013-03-25 13:40:45 -0700975 CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
976 OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
977 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -0700978 // Rejoin code paths
buzbee1fd33462013-03-25 13:40:45 -0700979 LIR* hop_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -0800980 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -0800981 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700982 }
buzbeef0504cd2012-11-13 16:31:10 -0800983 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
buzbee1fd33462013-03-25 13:40:45 -0700984 RegLocation rl_result = GetReturn(false);
985 if (cu_->instruction_set == kMips) {
Ian Rogersc9e463c2013-06-05 16:52:26 -0700986 // On MIPS rArg0 != rl_result, place false in result if branch is taken.
987 LoadConstant(rl_result.low_reg, 0);
buzbeeb046e162012-10-30 15:48:42 -0700988 }
buzbee1fd33462013-03-25 13:40:45 -0700989 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
Ian Rogersc9e463c2013-06-05 16:52:26 -0700990
Bill Buzbeea114add2012-05-03 15:00:40 -0700991 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800992 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
buzbee1fd33462013-03-25 13:40:45 -0700993 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -0800994 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbeeb046e162012-10-30 15:48:42 -0700995 LIR* branchover = NULL;
Ian Rogersc9e463c2013-06-05 16:52:26 -0700996 if (type_known_final) {
997 // rl_result == ref == null == 0.
998 if (cu_->instruction_set == kThumb2) {
999 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
1000 OpIT(kCondEq, "E"); // if-convert the test
1001 LoadConstant(rl_result.low_reg, 1); // .eq case - load true
1002 LoadConstant(rl_result.low_reg, 0); // .ne case - load false
1003 } else {
1004 LoadConstant(rl_result.low_reg, 0); // ne case - load false
1005 branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL);
1006 LoadConstant(rl_result.low_reg, 1); // eq case - load true
1007 }
buzbeeb046e162012-10-30 15:48:42 -07001008 } else {
Ian Rogersc9e463c2013-06-05 16:52:26 -07001009 if (cu_->instruction_set == kThumb2) {
buzbee1fd33462013-03-25 13:40:45 -07001010 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
Ian Rogersc9e463c2013-06-05 16:52:26 -07001011 if (!type_known_abstract) {
1012 /* Uses conditional nullification */
1013 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
1014 OpIT(kCondEq, "EE"); // if-convert the test
1015 LoadConstant(TargetReg(kArg0), 1); // .eq case - load true
1016 }
buzbee1fd33462013-03-25 13:40:45 -07001017 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
Ian Rogers397c0482013-05-31 16:46:31 -07001018 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
buzbee1fd33462013-03-25 13:40:45 -07001019 FreeTemp(r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001020 } else {
Ian Rogersc9e463c2013-06-05 16:52:26 -07001021 if (!type_known_abstract) {
1022 /* Uses branchovers */
1023 LoadConstant(rl_result.low_reg, 1); // assume true
1024 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
1025 }
1026 if (cu_->instruction_set != kX86) {
1027 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1028 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
1029 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
1030 FreeTemp(r_tgt);
1031 } else {
1032 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
1033 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1034 }
buzbeeb046e162012-10-30 15:48:42 -07001035 }
1036 }
Ian Rogersc9e463c2013-06-05 16:52:26 -07001037 // TODO: only clobber when type isn't final?
buzbee1fd33462013-03-25 13:40:45 -07001038 ClobberCalleeSave();
Bill Buzbeea114add2012-05-03 15:00:40 -07001039 /* branch targets here */
buzbee1fd33462013-03-25 13:40:45 -07001040 LIR* target = NewLIR0(kPseudoTargetLabel);
1041 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001042 branch1->target = target;
Ian Rogersc9e463c2013-06-05 16:52:26 -07001043 if (branchover != NULL) {
buzbeeb046e162012-10-30 15:48:42 -07001044 branchover->target = target;
1045 }
buzbee31a4a6f2012-02-28 15:36:15 -08001046}
1047
Ian Rogersc9e463c2013-06-05 16:52:26 -07001048void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) {
1049 bool type_known_final, type_known_abstract, use_declaring_class;
1050 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
1051 *cu_->dex_file,
1052 type_idx,
1053 &type_known_final,
1054 &type_known_abstract,
1055 &use_declaring_class);
1056 bool can_assume_type_is_in_dex_cache = !needs_access_check &&
1057 cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx);
1058
1059 if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) {
1060 GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src);
1061 } else {
1062 GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract,
1063 use_declaring_class, can_assume_type_is_in_dex_cache,
1064 type_idx, rl_dest, rl_src);
1065 }
1066}
1067
Dragos Sbirlea980d16b2013-06-04 15:01:40 -07001068void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001069{
Ian Rogers26309852013-06-07 15:17:46 -07001070 bool type_known_final, type_known_abstract, use_declaring_class;
Ian Rogersa7005962013-06-05 09:22:10 -07001071 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
1072 *cu_->dex_file,
Ian Rogers26309852013-06-07 15:17:46 -07001073 type_idx,
1074 &type_known_final,
1075 &type_known_abstract,
1076 &use_declaring_class);
1077 // Note: currently type_known_final is unused, as optimizing will only improve the performance
1078 // of the exception throw path.
1079 DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
Brian Carlstrom51c24672013-07-11 16:00:56 -07001080 const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
Ian Rogersa7005962013-06-05 09:22:10 -07001081 if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
Ian Rogersfae370a2013-06-05 08:33:27 -07001082 // Verifier type analysis proved this check cast would never cause an exception.
Dragos Sbirlea980d16b2013-06-04 15:01:40 -07001083 return;
1084 }
buzbee1fd33462013-03-25 13:40:45 -07001085 FlushAllRegs();
Bill Buzbeea114add2012-05-03 15:00:40 -07001086 // May generate a call - use explicit registers
buzbee1fd33462013-03-25 13:40:45 -07001087 LockCallTemps();
1088 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
buzbeefa57c472012-11-21 12:06:18 -08001089 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
Ian Rogersa7005962013-06-05 09:22:10 -07001090 if (needs_access_check) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001091 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -08001092 // returns Class* in kRet0
Bill Buzbeea114add2012-05-03 15:00:40 -07001093 // InitializeTypeAndVerifyAccess(idx, method)
buzbee1fd33462013-03-25 13:40:45 -07001094 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee52a77fc2012-11-20 19:50:46 -08001095 type_idx, TargetReg(kArg1), true);
buzbee1fd33462013-03-25 13:40:45 -07001096 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
Ian Rogers26309852013-06-07 15:17:46 -07001097 } else if (use_declaring_class) {
1098 LoadWordDisp(TargetReg(kArg1),
1099 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001100 } else {
buzbeefa57c472012-11-21 12:06:18 -08001101 // Load dex cache entry into class_reg (kArg2)
buzbee1fd33462013-03-25 13:40:45 -07001102 LoadWordDisp(TargetReg(kArg1),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001103 mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001104 int32_t offset_of_type =
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001105 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
1106 (sizeof(mirror::Class*) * type_idx);
buzbee1fd33462013-03-25 13:40:45 -07001107 LoadWordDisp(class_reg, offset_of_type, class_reg);
Ian Rogers26309852013-06-07 15:17:46 -07001108 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001109 // Need to test presence of type in dex cache at runtime
buzbee1fd33462013-03-25 13:40:45 -07001110 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001111 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001112 // Call out to helper, which will return resolved type in kArg0
Bill Buzbeea114add2012-05-03 15:00:40 -07001113 // InitializeTypeFromCode(idx, method)
buzbee1fd33462013-03-25 13:40:45 -07001114 CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001115 true);
buzbee1fd33462013-03-25 13:40:45 -07001116 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001117 // Rejoin code paths
buzbee1fd33462013-03-25 13:40:45 -07001118 LIR* hop_target = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001119 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -08001120 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001121 }
buzbeefa57c472012-11-21 12:06:18 -08001122 // At this point, class_reg (kArg2) has class
buzbee1fd33462013-03-25 13:40:45 -07001123 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001124 /* Null is OK - continue */
buzbee1fd33462013-03-25 13:40:45 -07001125 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001126 /* load object->klass_ */
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001127 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
buzbee1fd33462013-03-25 13:40:45 -07001128 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001129 /* kArg1 now contains object->klass_ */
Ian Rogers26309852013-06-07 15:17:46 -07001130 LIR* branch2 = NULL;
1131 if (!type_known_abstract) {
buzbee1fd33462013-03-25 13:40:45 -07001132 branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
buzbeeb046e162012-10-30 15:48:42 -07001133 }
Ian Rogers26309852013-06-07 15:17:46 -07001134 CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2),
1135 true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001136 /* branch target here */
buzbee1fd33462013-03-25 13:40:45 -07001137 LIR* target = NewLIR0(kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001138 branch1->target = target;
Ian Rogers26309852013-06-07 15:17:46 -07001139 if (branch2 != NULL) {
1140 branch2->target = target;
1141 }
buzbee31a4a6f2012-02-28 15:36:15 -08001142}
1143
buzbee1fd33462013-03-25 13:40:45 -07001144void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
1145 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001146{
buzbeefa57c472012-11-21 12:06:18 -08001147 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001148 if (cu_->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001149 /*
1150 * NOTE: This is the one place in the code in which we might have
1151 * as many as six live temporary registers. There are 5 in the normal
1152 * set for Arm. Until we have spill capabilities, temporarily add
1153 * lr to the temp set. It is safe to do this locally, but note that
1154 * lr is used explicitly elsewhere in the code generator and cannot
1155 * normally be used as a general temp register.
1156 */
buzbee1fd33462013-03-25 13:40:45 -07001157 MarkTemp(TargetReg(kLr)); // Add lr to the temp pool
1158 FreeTemp(TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001159 }
buzbee1fd33462013-03-25 13:40:45 -07001160 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1161 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1162 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001163 // The longs may overlap - use intermediate temp if so
buzbeefa57c472012-11-21 12:06:18 -08001164 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)){
buzbee1fd33462013-03-25 13:40:45 -07001165 int t_reg = AllocTemp();
1166 OpRegRegReg(first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1167 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1168 OpRegCopy(rl_result.low_reg, t_reg);
1169 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001170 } else {
buzbee1fd33462013-03-25 13:40:45 -07001171 OpRegRegReg(first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1172 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg,
buzbeefa57c472012-11-21 12:06:18 -08001173 rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001174 }
1175 /*
buzbeefa57c472012-11-21 12:06:18 -08001176 * NOTE: If rl_dest refers to a frame variable in a large frame, the
buzbee52a77fc2012-11-20 19:50:46 -08001177 * following StoreValueWide might need to allocate a temp register.
Bill Buzbeea114add2012-05-03 15:00:40 -07001178 * To further work around the lack of a spill capability, explicitly
buzbeefa57c472012-11-21 12:06:18 -08001179 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
Bill Buzbeea114add2012-05-03 15:00:40 -07001180 * Remove when spill is functional.
1181 */
buzbee1fd33462013-03-25 13:40:45 -07001182 FreeRegLocTemps(rl_result, rl_src1);
1183 FreeRegLocTemps(rl_result, rl_src2);
1184 StoreValueWide(rl_dest, rl_result);
1185 if (cu_->instruction_set == kThumb2) {
1186 Clobber(TargetReg(kLr));
1187 UnmarkTemp(TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001188 }
buzbee31a4a6f2012-02-28 15:36:15 -08001189}
1190
1191
buzbee1fd33462013-03-25 13:40:45 -07001192void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001193 RegLocation rl_src1, RegLocation rl_shift)
buzbee31a4a6f2012-02-28 15:36:15 -08001194{
buzbeea5954be2013-02-07 10:41:40 -08001195 int func_offset = -1; // Make gcc happy
buzbee31a4a6f2012-02-28 15:36:15 -08001196
buzbee408ad162012-06-06 16:45:18 -07001197 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001198 case Instruction::SHL_LONG:
1199 case Instruction::SHL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001200 func_offset = ENTRYPOINT_OFFSET(pShlLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001201 break;
1202 case Instruction::SHR_LONG:
1203 case Instruction::SHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001204 func_offset = ENTRYPOINT_OFFSET(pShrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001205 break;
1206 case Instruction::USHR_LONG:
1207 case Instruction::USHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001208 func_offset = ENTRYPOINT_OFFSET(pUshrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001209 break;
1210 default:
1211 LOG(FATAL) << "Unexpected case";
Bill Buzbeea114add2012-05-03 15:00:40 -07001212 }
buzbee1fd33462013-03-25 13:40:45 -07001213 FlushAllRegs(); /* Send everything to home location */
1214 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false);
1215 RegLocation rl_result = GetReturnWide(false);
1216 StoreValueWide(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001217}
1218
1219
buzbee1fd33462013-03-25 13:40:45 -07001220void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001221 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001222{
Bill Buzbeea114add2012-05-03 15:00:40 -07001223 OpKind op = kOpBkpt;
buzbeefa57c472012-11-21 12:06:18 -08001224 bool is_div_rem = false;
1225 bool check_zero = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001226 bool unary = false;
buzbeefa57c472012-11-21 12:06:18 -08001227 RegLocation rl_result;
1228 bool shift_op = false;
buzbee408ad162012-06-06 16:45:18 -07001229 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001230 case Instruction::NEG_INT:
1231 op = kOpNeg;
1232 unary = true;
1233 break;
1234 case Instruction::NOT_INT:
1235 op = kOpMvn;
1236 unary = true;
1237 break;
1238 case Instruction::ADD_INT:
1239 case Instruction::ADD_INT_2ADDR:
1240 op = kOpAdd;
1241 break;
1242 case Instruction::SUB_INT:
1243 case Instruction::SUB_INT_2ADDR:
1244 op = kOpSub;
1245 break;
1246 case Instruction::MUL_INT:
1247 case Instruction::MUL_INT_2ADDR:
1248 op = kOpMul;
1249 break;
1250 case Instruction::DIV_INT:
1251 case Instruction::DIV_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001252 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001253 op = kOpDiv;
buzbeefa57c472012-11-21 12:06:18 -08001254 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001255 break;
buzbeef0504cd2012-11-13 16:31:10 -08001256 /* NOTE: returns in kArg1 */
Bill Buzbeea114add2012-05-03 15:00:40 -07001257 case Instruction::REM_INT:
1258 case Instruction::REM_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001259 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001260 op = kOpRem;
buzbeefa57c472012-11-21 12:06:18 -08001261 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001262 break;
1263 case Instruction::AND_INT:
1264 case Instruction::AND_INT_2ADDR:
1265 op = kOpAnd;
1266 break;
1267 case Instruction::OR_INT:
1268 case Instruction::OR_INT_2ADDR:
1269 op = kOpOr;
1270 break;
1271 case Instruction::XOR_INT:
1272 case Instruction::XOR_INT_2ADDR:
1273 op = kOpXor;
1274 break;
1275 case Instruction::SHL_INT:
1276 case Instruction::SHL_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001277 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001278 op = kOpLsl;
1279 break;
1280 case Instruction::SHR_INT:
1281 case Instruction::SHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001282 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001283 op = kOpAsr;
1284 break;
1285 case Instruction::USHR_INT:
1286 case Instruction::USHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001287 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001288 op = kOpLsr;
1289 break;
1290 default:
buzbeecbd6d442012-11-17 14:11:25 -08001291 LOG(FATAL) << "Invalid word arith op: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001292 }
buzbeefa57c472012-11-21 12:06:18 -08001293 if (!is_div_rem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001294 if (unary) {
buzbee1fd33462013-03-25 13:40:45 -07001295 rl_src1 = LoadValue(rl_src1, kCoreReg);
1296 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1297 OpRegReg(op, rl_result.low_reg, rl_src1.low_reg);
buzbee31a4a6f2012-02-28 15:36:15 -08001298 } else {
buzbeefa57c472012-11-21 12:06:18 -08001299 if (shift_op) {
1300 int t_reg = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -07001301 if (cu_->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001302 // X86 doesn't require masking and must use ECX
buzbeefa57c472012-11-21 12:06:18 -08001303 t_reg = TargetReg(kCount); // rCX
buzbee1fd33462013-03-25 13:40:45 -07001304 LoadValueDirectFixed(rl_src2, t_reg);
buzbeeb046e162012-10-30 15:48:42 -07001305 } else {
buzbee1fd33462013-03-25 13:40:45 -07001306 rl_src2 = LoadValue(rl_src2, kCoreReg);
1307 t_reg = AllocTemp();
1308 OpRegRegImm(kOpAnd, t_reg, rl_src2.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001309 }
buzbee1fd33462013-03-25 13:40:45 -07001310 rl_src1 = LoadValue(rl_src1, kCoreReg);
1311 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1312 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1313 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001314 } else {
buzbee1fd33462013-03-25 13:40:45 -07001315 rl_src1 = LoadValue(rl_src1, kCoreReg);
1316 rl_src2 = LoadValue(rl_src2, kCoreReg);
1317 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1318 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001319 }
buzbee31a4a6f2012-02-28 15:36:15 -08001320 }
buzbee1fd33462013-03-25 13:40:45 -07001321 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001322 } else {
buzbee1fd33462013-03-25 13:40:45 -07001323 if (cu_->instruction_set == kMips) {
1324 rl_src1 = LoadValue(rl_src1, kCoreReg);
1325 rl_src2 = LoadValue(rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001326 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001327 GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001328 }
buzbee1fd33462013-03-25 13:40:45 -07001329 rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001330 } else {
buzbeefa57c472012-11-21 12:06:18 -08001331 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee1fd33462013-03-25 13:40:45 -07001332 FlushAllRegs(); /* Send everything to home location */
1333 LoadValueDirectFixed(rl_src2, TargetReg(kArg1));
1334 int r_tgt = CallHelperSetup(func_offset);
1335 LoadValueDirectFixed(rl_src1, TargetReg(kArg0));
buzbeefa57c472012-11-21 12:06:18 -08001336 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001337 GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001338 }
1339 // NOTE: callout here is not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001340 CallHelper(r_tgt, func_offset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001341 if (op == kOpDiv)
buzbee1fd33462013-03-25 13:40:45 -07001342 rl_result = GetReturn(false);
buzbeeb046e162012-10-30 15:48:42 -07001343 else
buzbee1fd33462013-03-25 13:40:45 -07001344 rl_result = GetReturnAlt();
jeffhao4f8f04a2012-10-02 18:10:35 -07001345 }
buzbee1fd33462013-03-25 13:40:45 -07001346 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001347 }
buzbee31a4a6f2012-02-28 15:36:15 -08001348}
1349
1350/*
1351 * The following are the first-level codegen routines that analyze the format
1352 * of each bytecode then either dispatch special purpose codegen routines
1353 * or produce corresponding Thumb instructions directly.
1354 */
1355
buzbeeaad94382012-11-21 07:40:50 -08001356static bool IsPowerOfTwo(int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001357{
Bill Buzbeea114add2012-05-03 15:00:40 -07001358 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001359}
1360
1361// Returns true if no more than two bits are set in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001362static bool IsPopCountLE2(unsigned int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001363{
Bill Buzbeea114add2012-05-03 15:00:40 -07001364 x &= x - 1;
1365 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001366}
1367
1368// Returns the index of the lowest set bit in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001369static int LowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001370 int bit_posn = 0;
1371 while ((x & 0xf) == 0) {
1372 bit_posn += 4;
1373 x >>= 4;
1374 }
1375 while ((x & 1) == 0) {
1376 bit_posn++;
1377 x >>= 1;
1378 }
1379 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001380}
1381
buzbeefa57c472012-11-21 12:06:18 -08001382// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1383// and store the result in 'rl_dest'.
buzbee1fd33462013-03-25 13:40:45 -07001384bool Mir2Lir::HandleEasyDivide(Instruction::Code dalvik_opcode,
1385 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001386{
buzbee1fd33462013-03-25 13:40:45 -07001387 if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001388 return false;
buzbee0f79d722012-11-01 15:35:27 -07001389 }
buzbeeb046e162012-10-30 15:48:42 -07001390 // No divide instruction for Arm, so check for more special cases
buzbee1fd33462013-03-25 13:40:45 -07001391 if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
1392 return SmallLiteralDivide(dalvik_opcode, rl_src, rl_dest, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001393 }
buzbee52a77fc2012-11-20 19:50:46 -08001394 int k = LowestSetBit(lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001395 if (k >= 30) {
1396 // Avoid special cases.
1397 return false;
1398 }
buzbeefa57c472012-11-21 12:06:18 -08001399 bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
1400 dalvik_opcode == Instruction::DIV_INT_LIT16);
buzbee1fd33462013-03-25 13:40:45 -07001401 rl_src = LoadValue(rl_src, kCoreReg);
1402 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001403 if (div) {
buzbee1fd33462013-03-25 13:40:45 -07001404 int t_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -07001405 if (lit == 2) {
1406 // Division by 2 is by far the most common division by constant.
buzbee1fd33462013-03-25 13:40:45 -07001407 OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1408 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1409 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001410 } else {
buzbee1fd33462013-03-25 13:40:45 -07001411 OpRegRegImm(kOpAsr, t_reg, rl_src.low_reg, 31);
1412 OpRegRegImm(kOpLsr, t_reg, t_reg, 32 - k);
1413 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg);
1414 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001415 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001416 } else {
buzbee1fd33462013-03-25 13:40:45 -07001417 int t_reg1 = AllocTemp();
1418 int t_reg2 = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -07001419 if (lit == 2) {
buzbee1fd33462013-03-25 13:40:45 -07001420 OpRegRegImm(kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1421 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1422 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit -1);
1423 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001424 } else {
buzbee1fd33462013-03-25 13:40:45 -07001425 OpRegRegImm(kOpAsr, t_reg1, rl_src.low_reg, 31);
1426 OpRegRegImm(kOpLsr, t_reg1, t_reg1, 32 - k);
1427 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1428 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1);
1429 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001430 }
1431 }
buzbee1fd33462013-03-25 13:40:45 -07001432 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001433 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001434}
1435
buzbeefa57c472012-11-21 12:06:18 -08001436// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1437// and store the result in 'rl_dest'.
buzbee1fd33462013-03-25 13:40:45 -07001438bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001439{
Bill Buzbeea114add2012-05-03 15:00:40 -07001440 // Can we simplify this multiplication?
buzbeefa57c472012-11-21 12:06:18 -08001441 bool power_of_two = false;
1442 bool pop_count_le2 = false;
1443 bool power_of_two_minus_one = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001444 if (lit < 2) {
1445 // Avoid special cases.
1446 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001447 } else if (IsPowerOfTwo(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001448 power_of_two = true;
buzbee52a77fc2012-11-20 19:50:46 -08001449 } else if (IsPopCountLE2(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001450 pop_count_le2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001451 } else if (IsPowerOfTwo(lit + 1)) {
buzbeefa57c472012-11-21 12:06:18 -08001452 power_of_two_minus_one = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001453 } else {
1454 return false;
1455 }
buzbee1fd33462013-03-25 13:40:45 -07001456 rl_src = LoadValue(rl_src, kCoreReg);
1457 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbeefa57c472012-11-21 12:06:18 -08001458 if (power_of_two) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001459 // Shift.
buzbee1fd33462013-03-25 13:40:45 -07001460 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit));
buzbeefa57c472012-11-21 12:06:18 -08001461 } else if (pop_count_le2) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001462 // Shift and add and shift.
buzbeefa57c472012-11-21 12:06:18 -08001463 int first_bit = LowestSetBit(lit);
1464 int second_bit = LowestSetBit(lit ^ (1 << first_bit));
buzbee1fd33462013-03-25 13:40:45 -07001465 GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001466 } else {
1467 // Reverse subtract: (src << (shift + 1)) - src.
buzbeefa57c472012-11-21 12:06:18 -08001468 DCHECK(power_of_two_minus_one);
buzbee52a77fc2012-11-20 19:50:46 -08001469 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
buzbee1fd33462013-03-25 13:40:45 -07001470 int t_reg = AllocTemp();
1471 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1472 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001473 }
buzbee1fd33462013-03-25 13:40:45 -07001474 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001475 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001476}
1477
buzbee1fd33462013-03-25 13:40:45 -07001478void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src,
1479 int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001480{
buzbeefa57c472012-11-21 12:06:18 -08001481 RegLocation rl_result;
buzbeecbd6d442012-11-17 14:11:25 -08001482 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
buzbeefa57c472012-11-21 12:06:18 -08001483 int shift_op = false;
1484 bool is_div = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001485
buzbee408ad162012-06-06 16:45:18 -07001486 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001487 case Instruction::RSUB_INT_LIT8:
1488 case Instruction::RSUB_INT: {
buzbee1fd33462013-03-25 13:40:45 -07001489 rl_src = LoadValue(rl_src, kCoreReg);
1490 rl_result = EvalLoc(rl_dest, kCoreReg, true);
1491 if (cu_->instruction_set == kThumb2) {
1492 OpRegRegImm(kOpRsub, rl_result.low_reg, rl_src.low_reg, lit);
buzbeec7d1f912013-02-07 15:22:39 -08001493 } else {
buzbee1fd33462013-03-25 13:40:45 -07001494 OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg);
1495 OpRegImm(kOpAdd, rl_result.low_reg, lit);
buzbeec7d1f912013-02-07 15:22:39 -08001496 }
buzbee1fd33462013-03-25 13:40:45 -07001497 StoreValue(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001498 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001499 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001500
buzbeee6285f92012-12-06 15:57:46 -08001501 case Instruction::SUB_INT:
1502 case Instruction::SUB_INT_2ADDR:
1503 lit = -lit;
1504 // Intended fallthrough
1505 case Instruction::ADD_INT:
1506 case Instruction::ADD_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001507 case Instruction::ADD_INT_LIT8:
1508 case Instruction::ADD_INT_LIT16:
1509 op = kOpAdd;
1510 break;
buzbeee6285f92012-12-06 15:57:46 -08001511 case Instruction::MUL_INT:
1512 case Instruction::MUL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001513 case Instruction::MUL_INT_LIT8:
1514 case Instruction::MUL_INT_LIT16: {
buzbee1fd33462013-03-25 13:40:45 -07001515 if (HandleEasyMultiply(rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001516 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001517 }
1518 op = kOpMul;
1519 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001520 }
buzbeee6285f92012-12-06 15:57:46 -08001521 case Instruction::AND_INT:
1522 case Instruction::AND_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001523 case Instruction::AND_INT_LIT8:
1524 case Instruction::AND_INT_LIT16:
1525 op = kOpAnd;
1526 break;
buzbeee6285f92012-12-06 15:57:46 -08001527 case Instruction::OR_INT:
1528 case Instruction::OR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001529 case Instruction::OR_INT_LIT8:
1530 case Instruction::OR_INT_LIT16:
1531 op = kOpOr;
1532 break;
buzbeee6285f92012-12-06 15:57:46 -08001533 case Instruction::XOR_INT:
1534 case Instruction::XOR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001535 case Instruction::XOR_INT_LIT8:
1536 case Instruction::XOR_INT_LIT16:
1537 op = kOpXor;
1538 break;
1539 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001540 case Instruction::SHL_INT:
buzbeee6285f92012-12-06 15:57:46 -08001541 case Instruction::SHL_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001542 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001543 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001544 op = kOpLsl;
1545 break;
1546 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001547 case Instruction::SHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001548 case Instruction::SHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001549 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001550 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001551 op = kOpAsr;
1552 break;
1553 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001554 case Instruction::USHR_INT:
buzbeee6285f92012-12-06 15:57:46 -08001555 case Instruction::USHR_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001556 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001557 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001558 op = kOpLsr;
1559 break;
1560
buzbeee6285f92012-12-06 15:57:46 -08001561 case Instruction::DIV_INT:
1562 case Instruction::DIV_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001563 case Instruction::DIV_INT_LIT8:
1564 case Instruction::DIV_INT_LIT16:
buzbeee6285f92012-12-06 15:57:46 -08001565 case Instruction::REM_INT:
1566 case Instruction::REM_INT_2ADDR:
Bill Buzbeea114add2012-05-03 15:00:40 -07001567 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07001568 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07001569 if (lit == 0) {
buzbee1fd33462013-03-25 13:40:45 -07001570 GenImmedCheck(kCondAl, 0, 0, kThrowDivZero);
buzbeea5954be2013-02-07 10:41:40 -08001571 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001572 }
buzbee1fd33462013-03-25 13:40:45 -07001573 if (HandleEasyDivide(opcode, rl_src, rl_dest, lit)) {
buzbeea5954be2013-02-07 10:41:40 -08001574 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001575 }
buzbee408ad162012-06-06 16:45:18 -07001576 if ((opcode == Instruction::DIV_INT_LIT8) ||
buzbeee6285f92012-12-06 15:57:46 -08001577 (opcode == Instruction::DIV_INT) ||
1578 (opcode == Instruction::DIV_INT_2ADDR) ||
buzbee408ad162012-06-06 16:45:18 -07001579 (opcode == Instruction::DIV_INT_LIT16)) {
buzbeefa57c472012-11-21 12:06:18 -08001580 is_div = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 } else {
buzbeefa57c472012-11-21 12:06:18 -08001582 is_div = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001583 }
buzbee1fd33462013-03-25 13:40:45 -07001584 if (cu_->instruction_set == kMips) {
1585 rl_src = LoadValue(rl_src, kCoreReg);
1586 rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
jeffhao4f8f04a2012-10-02 18:10:35 -07001587 } else {
buzbee1fd33462013-03-25 13:40:45 -07001588 FlushAllRegs(); /* Everything to home location */
1589 LoadValueDirectFixed(rl_src, TargetReg(kArg0));
1590 Clobber(TargetReg(kArg0));
buzbeefa57c472012-11-21 12:06:18 -08001591 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee1fd33462013-03-25 13:40:45 -07001592 CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false);
buzbeefa57c472012-11-21 12:06:18 -08001593 if (is_div)
buzbee1fd33462013-03-25 13:40:45 -07001594 rl_result = GetReturn(false);
buzbeeb046e162012-10-30 15:48:42 -07001595 else
buzbee1fd33462013-03-25 13:40:45 -07001596 rl_result = GetReturnAlt();
jeffhao4f8f04a2012-10-02 18:10:35 -07001597 }
buzbee1fd33462013-03-25 13:40:45 -07001598 StoreValue(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001599 return;
jeffhao4f8f04a2012-10-02 18:10:35 -07001600 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001601 default:
buzbeee6285f92012-12-06 15:57:46 -08001602 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001603 }
buzbee1fd33462013-03-25 13:40:45 -07001604 rl_src = LoadValue(rl_src, kCoreReg);
1605 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001606 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
buzbeefa57c472012-11-21 12:06:18 -08001607 if (shift_op && (lit == 0)) {
buzbee1fd33462013-03-25 13:40:45 -07001608 OpRegCopy(rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001609 } else {
buzbee1fd33462013-03-25 13:40:45 -07001610 OpRegRegImm(op, rl_result.low_reg, rl_src.low_reg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001611 }
buzbee1fd33462013-03-25 13:40:45 -07001612 StoreValue(rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001613}
1614
buzbee1fd33462013-03-25 13:40:45 -07001615void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
buzbee02031b12012-11-23 09:41:35 -08001616 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001617{
buzbeefa57c472012-11-21 12:06:18 -08001618 RegLocation rl_result;
1619 OpKind first_op = kOpBkpt;
1620 OpKind second_op = kOpBkpt;
1621 bool call_out = false;
1622 bool check_zero = false;
1623 int func_offset;
1624 int ret_reg = TargetReg(kRet0);
buzbee31a4a6f2012-02-28 15:36:15 -08001625
buzbee408ad162012-06-06 16:45:18 -07001626 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001627 case Instruction::NOT_LONG:
buzbee1fd33462013-03-25 13:40:45 -07001628 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1629 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001630 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -08001631 if (rl_result.low_reg == rl_src2.high_reg) {
buzbee1fd33462013-03-25 13:40:45 -07001632 int t_reg = AllocTemp();
1633 OpRegCopy(t_reg, rl_src2.high_reg);
1634 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1635 OpRegReg(kOpMvn, rl_result.high_reg, t_reg);
1636 FreeTemp(t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001637 } else {
buzbee1fd33462013-03-25 13:40:45 -07001638 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1639 OpRegReg(kOpMvn, rl_result.high_reg, rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001640 }
buzbee1fd33462013-03-25 13:40:45 -07001641 StoreValueWide(rl_dest, rl_result);
buzbeea5954be2013-02-07 10:41:40 -08001642 return;
Bill Buzbeea114add2012-05-03 15:00:40 -07001643 case Instruction::ADD_LONG:
1644 case Instruction::ADD_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001645 if (cu_->instruction_set != kThumb2) {
1646 GenAddLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001647 return;
buzbeeb046e162012-10-30 15:48:42 -07001648 }
buzbeefa57c472012-11-21 12:06:18 -08001649 first_op = kOpAdd;
1650 second_op = kOpAdc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001651 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001652 case Instruction::SUB_LONG:
1653 case Instruction::SUB_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001654 if (cu_->instruction_set != kThumb2) {
1655 GenSubLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001656 return;
buzbeeb046e162012-10-30 15:48:42 -07001657 }
buzbeefa57c472012-11-21 12:06:18 -08001658 first_op = kOpSub;
1659 second_op = kOpSbc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001660 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001661 case Instruction::MUL_LONG:
1662 case Instruction::MUL_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001663 if (cu_->instruction_set == kThumb2) {
1664 GenMulLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001665 return;
buzbee4ef3e452012-12-14 13:35:28 -08001666 } else {
1667 call_out = true;
1668 ret_reg = TargetReg(kRet0);
1669 func_offset = ENTRYPOINT_OFFSET(pLmul);
1670 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001671 break;
1672 case Instruction::DIV_LONG:
1673 case Instruction::DIV_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001674 call_out = true;
1675 check_zero = true;
1676 ret_reg = TargetReg(kRet0);
1677 func_offset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07001678 break;
1679 case Instruction::REM_LONG:
1680 case Instruction::REM_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001681 call_out = true;
1682 check_zero = true;
1683 func_offset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08001684 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbee1fd33462013-03-25 13:40:45 -07001685 ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001686 break;
1687 case Instruction::AND_LONG_2ADDR:
1688 case Instruction::AND_LONG:
buzbee1fd33462013-03-25 13:40:45 -07001689 if (cu_->instruction_set == kX86) {
1690 return GenAndLong(rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001691 }
buzbeefa57c472012-11-21 12:06:18 -08001692 first_op = kOpAnd;
1693 second_op = kOpAnd;
Bill Buzbeea114add2012-05-03 15:00:40 -07001694 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001695 case Instruction::OR_LONG:
1696 case Instruction::OR_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001697 if (cu_->instruction_set == kX86) {
1698 GenOrLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001699 return;
buzbeeb046e162012-10-30 15:48:42 -07001700 }
buzbeefa57c472012-11-21 12:06:18 -08001701 first_op = kOpOr;
1702 second_op = kOpOr;
Bill Buzbeea114add2012-05-03 15:00:40 -07001703 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001704 case Instruction::XOR_LONG:
1705 case Instruction::XOR_LONG_2ADDR:
buzbee1fd33462013-03-25 13:40:45 -07001706 if (cu_->instruction_set == kX86) {
1707 GenXorLong(rl_dest, rl_src1, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001708 return;
buzbeeb046e162012-10-30 15:48:42 -07001709 }
buzbeefa57c472012-11-21 12:06:18 -08001710 first_op = kOpXor;
1711 second_op = kOpXor;
Bill Buzbeea114add2012-05-03 15:00:40 -07001712 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001713 case Instruction::NEG_LONG: {
buzbee1fd33462013-03-25 13:40:45 -07001714 GenNegLong(rl_dest, rl_src2);
buzbeea5954be2013-02-07 10:41:40 -08001715 return;
buzbee31a4a6f2012-02-28 15:36:15 -08001716 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001717 default:
1718 LOG(FATAL) << "Invalid long arith op";
1719 }
buzbeefa57c472012-11-21 12:06:18 -08001720 if (!call_out) {
buzbee1fd33462013-03-25 13:40:45 -07001721 GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2);
Bill Buzbeea114add2012-05-03 15:00:40 -07001722 } else {
buzbee1fd33462013-03-25 13:40:45 -07001723 FlushAllRegs(); /* Send everything to home location */
buzbeefa57c472012-11-21 12:06:18 -08001724 if (check_zero) {
buzbee1fd33462013-03-25 13:40:45 -07001725 LoadValueDirectWideFixed(rl_src2, TargetReg(kArg2), TargetReg(kArg3));
1726 int r_tgt = CallHelperSetup(func_offset);
1727 GenDivZeroCheck(TargetReg(kArg2), TargetReg(kArg3));
1728 LoadValueDirectWideFixed(rl_src1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07001729 // NOTE: callout here is not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001730 CallHelper(r_tgt, func_offset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08001731 } else {
buzbee1fd33462013-03-25 13:40:45 -07001732 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001733 }
buzbeef0504cd2012-11-13 16:31:10 -08001734 // Adjust return regs in to handle case of rem returning kArg2/kArg3
buzbeefa57c472012-11-21 12:06:18 -08001735 if (ret_reg == TargetReg(kRet0))
buzbee1fd33462013-03-25 13:40:45 -07001736 rl_result = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -07001737 else
buzbee1fd33462013-03-25 13:40:45 -07001738 rl_result = GetReturnWideAlt();
1739 StoreValueWide(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001740 }
buzbee31a4a6f2012-02-28 15:36:15 -08001741}
1742
buzbee1fd33462013-03-25 13:40:45 -07001743void Mir2Lir::GenConversionCall(int func_offset,
buzbee02031b12012-11-23 09:41:35 -08001744 RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001745{
Bill Buzbeea114add2012-05-03 15:00:40 -07001746 /*
1747 * Don't optimize the register usage since it calls out to support
1748 * functions
1749 */
buzbee1fd33462013-03-25 13:40:45 -07001750 FlushAllRegs(); /* Send everything to home location */
buzbeefa57c472012-11-21 12:06:18 -08001751 if (rl_src.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001752 LoadValueDirectWideFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -08001753 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07001754 } else {
buzbee1fd33462013-03-25 13:40:45 -07001755 LoadValueDirectFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07001756 }
buzbee1fd33462013-03-25 13:40:45 -07001757 CallRuntimeHelperRegLocation(func_offset, rl_src, false);
buzbeefa57c472012-11-21 12:06:18 -08001758 if (rl_dest.wide) {
1759 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001760 rl_result = GetReturnWide(rl_dest.fp);
1761 StoreValueWide(rl_dest, rl_result);
buzbee408ad162012-06-06 16:45:18 -07001762 } else {
buzbeefa57c472012-11-21 12:06:18 -08001763 RegLocation rl_result;
buzbee1fd33462013-03-25 13:40:45 -07001764 rl_result = GetReturn(rl_dest.fp);
1765 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001766 }
buzbee31a4a6f2012-02-28 15:36:15 -08001767}
1768
buzbee31a4a6f2012-02-28 15:36:15 -08001769/* Check if we need to check for pending suspend request */
buzbee1fd33462013-03-25 13:40:45 -07001770void Mir2Lir::GenSuspendTest(int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -08001771{
buzbeefa57c472012-11-21 12:06:18 -08001772 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001773 return;
1774 }
buzbee1fd33462013-03-25 13:40:45 -07001775 FlushAllRegs();
1776 LIR* branch = OpTestSuspend(NULL);
1777 LIR* ret_lab = NewLIR0(kPseudoTargetLabel);
1778 LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1779 reinterpret_cast<uintptr_t>(ret_lab), current_dalvik_offset_);
buzbeecbd6d442012-11-17 14:11:25 -08001780 branch->target = target;
buzbee862a7602013-04-05 10:58:54 -07001781 suspend_launchpads_.Insert(target);
buzbee31a4a6f2012-02-28 15:36:15 -08001782}
1783
buzbeefead2932012-03-30 14:02:01 -07001784/* Check if we need to check for pending suspend request */
buzbee1fd33462013-03-25 13:40:45 -07001785void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07001786{
buzbeefa57c472012-11-21 12:06:18 -08001787 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbee1fd33462013-03-25 13:40:45 -07001788 OpUnconditionalBranch(target);
Bill Buzbeea114add2012-05-03 15:00:40 -07001789 return;
1790 }
buzbee1fd33462013-03-25 13:40:45 -07001791 OpTestSuspend(target);
buzbeefa57c472012-11-21 12:06:18 -08001792 LIR* launch_pad =
buzbee1fd33462013-03-25 13:40:45 -07001793 RawLIR(current_dalvik_offset_, kPseudoSuspendTarget,
1794 reinterpret_cast<uintptr_t>(target), current_dalvik_offset_);
1795 FlushAllRegs();
1796 OpUnconditionalBranch(launch_pad);
buzbee862a7602013-04-05 10:58:54 -07001797 suspend_launchpads_.Insert(launch_pad);
buzbeefead2932012-03-30 14:02:01 -07001798}
1799
buzbee31a4a6f2012-02-28 15:36:15 -08001800} // namespace art