1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* This file contains codegen for the Mips ISA */
18
19 #include "codegen_mips.h"
20 #include "dex/quick/mir_to_lir-inl.h"
21 #include "dex/reg_storage_eq.h"
22 #include "entrypoints/quick/quick_entrypoints.h"
23 #include "mips_lir.h"
24 #include "mirror/array.h"
25
26 namespace art {
27
28 /*
29 * Compare two 64-bit values
30 * x = y return 0
31 * x < y return -1
32 * x > y return 1
33 *
34 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
35 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
36 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
37 * bnez res, finish
38 * sltu t0, x.lo, y.lo
39 * sgtu r1, x.lo, y.lo
40 * subu res, t0, t1
41 * finish:
42 *
43 */
GenCmpLong(RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)44 void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
45 RegLocation rl_src2) {
46 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
47 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
48 RegStorage t0 = AllocTemp();
49 RegStorage t1 = AllocTemp();
50 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
51 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
52 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
53 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
54 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
55 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
56 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
57 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
58 FreeTemp(t0);
59 FreeTemp(t1);
60 LIR* target = NewLIR0(kPseudoTargetLabel);
61 branch->target = target;
62 StoreValue(rl_dest, rl_result);
63 }
64
OpCmpBranch(ConditionCode cond,RegStorage src1,RegStorage src2,LIR * target)65 LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
66 LIR* branch;
67 MipsOpCode slt_op;
68 MipsOpCode br_op;
69 bool cmp_zero = false;
70 bool swapped = false;
71 switch (cond) {
72 case kCondEq:
73 br_op = kMipsBeq;
74 cmp_zero = true;
75 break;
76 case kCondNe:
77 br_op = kMipsBne;
78 cmp_zero = true;
79 break;
80 case kCondUlt:
81 slt_op = kMipsSltu;
82 br_op = kMipsBnez;
83 break;
84 case kCondUge:
85 slt_op = kMipsSltu;
86 br_op = kMipsBeqz;
87 break;
88 case kCondGe:
89 slt_op = kMipsSlt;
90 br_op = kMipsBeqz;
91 break;
92 case kCondGt:
93 slt_op = kMipsSlt;
94 br_op = kMipsBnez;
95 swapped = true;
96 break;
97 case kCondLe:
98 slt_op = kMipsSlt;
99 br_op = kMipsBeqz;
100 swapped = true;
101 break;
102 case kCondLt:
103 slt_op = kMipsSlt;
104 br_op = kMipsBnez;
105 break;
106 case kCondHi: // Gtu
107 slt_op = kMipsSltu;
108 br_op = kMipsBnez;
109 swapped = true;
110 break;
111 default:
112 LOG(FATAL) << "No support for ConditionCode: " << cond;
113 return NULL;
114 }
115 if (cmp_zero) {
116 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
117 } else {
118 RegStorage t_reg = AllocTemp();
119 if (swapped) {
120 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
121 } else {
122 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
123 }
124 branch = NewLIR1(br_op, t_reg.GetReg());
125 FreeTemp(t_reg);
126 }
127 branch->target = target;
128 return branch;
129 }
130
OpCmpImmBranch(ConditionCode cond,RegStorage reg,int check_value,LIR * target)131 LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
132 LIR* branch;
133 if (check_value != 0) {
134 // TUNING: handle s16 & kCondLt/Mi case using slti
135 RegStorage t_reg = AllocTemp();
136 LoadConstant(t_reg, check_value);
137 branch = OpCmpBranch(cond, reg, t_reg, target);
138 FreeTemp(t_reg);
139 return branch;
140 }
141 MipsOpCode opc;
142 switch (cond) {
143 case kCondEq: opc = kMipsBeqz; break;
144 case kCondGe: opc = kMipsBgez; break;
145 case kCondGt: opc = kMipsBgtz; break;
146 case kCondLe: opc = kMipsBlez; break;
147 // case KCondMi:
148 case kCondLt: opc = kMipsBltz; break;
149 case kCondNe: opc = kMipsBnez; break;
150 default:
151 // Tuning: use slti when applicable
152 RegStorage t_reg = AllocTemp();
153 LoadConstant(t_reg, check_value);
154 branch = OpCmpBranch(cond, reg, t_reg, target);
155 FreeTemp(t_reg);
156 return branch;
157 }
158 branch = NewLIR1(opc, reg.GetReg());
159 branch->target = target;
160 return branch;
161 }
162
OpRegCopyNoInsert(RegStorage r_dest,RegStorage r_src)163 LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
164 // If src or dest is a pair, we'll be using low reg.
165 if (r_dest.IsPair()) {
166 r_dest = r_dest.GetLow();
167 }
168 if (r_src.IsPair()) {
169 r_src = r_src.GetLow();
170 }
171 if (r_dest.IsFloat() || r_src.IsFloat())
172 return OpFpRegCopy(r_dest, r_src);
173 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
174 r_dest.GetReg(), r_src.GetReg());
175 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
176 res->flags.is_nop = true;
177 }
178 return res;
179 }
180
OpRegCopy(RegStorage r_dest,RegStorage r_src)181 void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
182 if (r_dest != r_src) {
183 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
184 AppendLIR(res);
185 }
186 }
187
OpRegCopyWide(RegStorage r_dest,RegStorage r_src)188 void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
189 if (r_dest != r_src) {
190 bool dest_fp = r_dest.IsFloat();
191 bool src_fp = r_src.IsFloat();
192 if (dest_fp) {
193 if (src_fp) {
194 OpRegCopy(r_dest, r_src);
195 } else {
196 /* note the operands are swapped for the mtc1 instr */
197 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
198 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
199 }
200 } else {
201 if (src_fp) {
202 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
203 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
204 } else {
205 // Handle overlap
206 if (r_src.GetHighReg() == r_dest.GetLowReg()) {
207 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
208 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
209 } else {
210 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
211 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
212 }
213 }
214 }
215 }
216 }
217
GenSelectConst32(RegStorage left_op,RegStorage right_op,ConditionCode code,int32_t true_val,int32_t false_val,RegStorage rs_dest,int dest_reg_class)218 void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
219 int32_t true_val, int32_t false_val, RegStorage rs_dest,
220 int dest_reg_class) {
221 // Implement as a branch-over.
222 // TODO: Conditional move?
223 LoadConstant(rs_dest, false_val); // Favors false.
224 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
225 LoadConstant(rs_dest, true_val);
226 LIR* target_label = NewLIR0(kPseudoTargetLabel);
227 ne_branchover->target = target_label;
228 }
229
GenSelect(BasicBlock * bb,MIR * mir)230 void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
231 UNIMPLEMENTED(FATAL) << "Need codegen for select";
232 }
233
GenFusedLongCmpBranch(BasicBlock * bb,MIR * mir)234 void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
235 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
236 }
237
GenDivRem(RegLocation rl_dest,RegStorage reg1,RegStorage reg2,bool is_div)238 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
239 bool is_div) {
240 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
241 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
242 if (is_div) {
243 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
244 } else {
245 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
246 }
247 return rl_result;
248 }
249
GenDivRemLit(RegLocation rl_dest,RegStorage reg1,int lit,bool is_div)250 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
251 bool is_div) {
252 RegStorage t_reg = AllocTemp();
253 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
254 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
255 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
256 if (is_div) {
257 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
258 } else {
259 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
260 }
261 FreeTemp(t_reg);
262 return rl_result;
263 }
264
GenDivRem(RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2,bool is_div,bool check_zero)265 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
266 RegLocation rl_src2, bool is_div, bool check_zero) {
267 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
268 return rl_dest;
269 }
270
GenDivRemLit(RegLocation rl_dest,RegLocation rl_src1,int lit,bool is_div)271 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
272 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
273 return rl_dest;
274 }
275
GenInlinedCas(CallInfo * info,bool is_long,bool is_object)276 bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
277 DCHECK_NE(cu_->instruction_set, kThumb2);
278 return false;
279 }
280
GenInlinedAbsFloat(CallInfo * info)281 bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
282 // TODO - add Mips implementation
283 return false;
284 }
285
GenInlinedAbsDouble(CallInfo * info)286 bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
287 // TODO - add Mips implementation
288 return false;
289 }
290
GenInlinedSqrt(CallInfo * info)291 bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
292 DCHECK_NE(cu_->instruction_set, kThumb2);
293 return false;
294 }
295
GenInlinedPeek(CallInfo * info,OpSize size)296 bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
297 if (size != kSignedByte) {
298 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
299 return false;
300 }
301 RegLocation rl_src_address = info->args[0]; // long address
302 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
303 RegLocation rl_dest = InlineTarget(info);
304 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
305 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
306 DCHECK(size == kSignedByte);
307 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
308 StoreValue(rl_dest, rl_result);
309 return true;
310 }
311
GenInlinedPoke(CallInfo * info,OpSize size)312 bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
313 if (size != kSignedByte) {
314 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
315 return false;
316 }
317 RegLocation rl_src_address = info->args[0]; // long address
318 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
319 RegLocation rl_src_value = info->args[2]; // [size] value
320 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
321 DCHECK(size == kSignedByte);
322 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
323 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
324 return true;
325 }
326
OpPcRelLoad(RegStorage reg,LIR * target)327 LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
328 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
329 return NULL;
330 }
331
OpVldm(RegStorage r_base,int count)332 LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
333 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
334 return NULL;
335 }
336
OpVstm(RegStorage r_base,int count)337 LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
338 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
339 return NULL;
340 }
341
GenMultiplyByTwoBitMultiplier(RegLocation rl_src,RegLocation rl_result,int lit,int first_bit,int second_bit)342 void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
343 RegLocation rl_result, int lit,
344 int first_bit, int second_bit) {
345 RegStorage t_reg = AllocTemp();
346 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
347 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
348 FreeTemp(t_reg);
349 if (first_bit != 0) {
350 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
351 }
352 }
353
GenDivZeroCheckWide(RegStorage reg)354 void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
355 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
356 RegStorage t_reg = AllocTemp();
357 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
358 GenDivZeroCheck(t_reg);
359 FreeTemp(t_reg);
360 }
361
362 // Test suspend flag, return target of taken suspend branch
OpTestSuspend(LIR * target)363 LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
364 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
365 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
366 }
367
368 // Decrement register and branch on condition
OpDecAndBranch(ConditionCode c_code,RegStorage reg,LIR * target)369 LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
370 OpRegImm(kOpSub, reg, 1);
371 return OpCmpImmBranch(c_code, reg, 0, target);
372 }
373
SmallLiteralDivRem(Instruction::Code dalvik_opcode,bool is_div,RegLocation rl_src,RegLocation rl_dest,int lit)374 bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
375 RegLocation rl_src, RegLocation rl_dest, int lit) {
376 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
377 return false;
378 }
379
EasyMultiply(RegLocation rl_src,RegLocation rl_dest,int lit)380 bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
381 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
382 return false;
383 }
384
OpIT(ConditionCode cond,const char * guide)385 LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
386 LOG(FATAL) << "Unexpected use of OpIT in Mips";
387 return NULL;
388 }
389
OpEndIT(LIR * it)390 void MipsMir2Lir::OpEndIT(LIR* it) {
391 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
392 }
393
394
GenAddLong(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)395 void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
396 RegLocation rl_src1, RegLocation rl_src2) {
397 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
398 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
399 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
400 /*
401 * [v1 v0] = [a1 a0] + [a3 a2];
402 * addu v0,a2,a0
403 * addu t1,a3,a1
404 * sltu v1,v0,a2
405 * addu v1,v1,t1
406 */
407
408 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
409 RegStorage t_reg = AllocTemp();
410 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
411 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
412 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
413 FreeTemp(t_reg);
414 StoreValueWide(rl_dest, rl_result);
415 }
416
GenSubLong(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)417 void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
418 RegLocation rl_src1, RegLocation rl_src2) {
419 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
420 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
421 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
422 /*
423 * [v1 v0] = [a1 a0] - [a3 a2];
424 * sltu t1,a0,a2
425 * subu v0,a0,a2
426 * subu v1,a1,a3
427 * subu v1,v1,t1
428 */
429
430 RegStorage t_reg = AllocTemp();
431 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
432 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
433 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
434 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
435 FreeTemp(t_reg);
436 StoreValueWide(rl_dest, rl_result);
437 }
438
GenArithOpLong(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)439 void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
440 RegLocation rl_src2) {
441 switch (opcode) {
442 case Instruction::ADD_LONG:
443 case Instruction::ADD_LONG_2ADDR:
444 GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
445 return;
446 case Instruction::SUB_LONG:
447 case Instruction::SUB_LONG_2ADDR:
448 GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
449 return;
450 case Instruction::NEG_LONG:
451 GenNegLong(rl_dest, rl_src2);
452 return;
453
454 default:
455 break;
456 }
457
458 // Fallback for all other ops.
459 Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
460 }
461
GenNegLong(RegLocation rl_dest,RegLocation rl_src)462 void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
463 rl_src = LoadValueWide(rl_src, kCoreReg);
464 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
465 /*
466 * [v1 v0] = -[a1 a0]
467 * negu v0,a0
468 * negu v1,a1
469 * sltu t1,r_zero
470 * subu v1,v1,t1
471 */
472
473 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
474 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
475 RegStorage t_reg = AllocTemp();
476 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
477 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
478 FreeTemp(t_reg);
479 StoreValueWide(rl_dest, rl_result);
480 }
481
482 /*
483 * Generate array load
484 */
GenArrayGet(int opt_flags,OpSize size,RegLocation rl_array,RegLocation rl_index,RegLocation rl_dest,int scale)485 void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
486 RegLocation rl_index, RegLocation rl_dest, int scale) {
487 RegisterClass reg_class = RegClassBySize(size);
488 int len_offset = mirror::Array::LengthOffset().Int32Value();
489 int data_offset;
490 RegLocation rl_result;
491 rl_array = LoadValue(rl_array, kRefReg);
492 rl_index = LoadValue(rl_index, kCoreReg);
493
494 // FIXME: need to add support for rl_index.is_const.
495
496 if (size == k64 || size == kDouble) {
497 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
498 } else {
499 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
500 }
501
502 /* null object? */
503 GenNullCheck(rl_array.reg, opt_flags);
504
505 RegStorage reg_ptr = AllocTemp();
506 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
507 RegStorage reg_len;
508 if (needs_range_check) {
509 reg_len = AllocTemp();
510 /* Get len */
511 Load32Disp(rl_array.reg, len_offset, reg_len);
512 }
513 /* reg_ptr -> array data */
514 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
515 FreeTemp(rl_array.reg);
516 if ((size == k64) || (size == kDouble)) {
517 if (scale) {
518 RegStorage r_new_index = AllocTemp();
519 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
520 OpRegReg(kOpAdd, reg_ptr, r_new_index);
521 FreeTemp(r_new_index);
522 } else {
523 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
524 }
525 FreeTemp(rl_index.reg);
526 rl_result = EvalLoc(rl_dest, reg_class, true);
527
528 if (needs_range_check) {
529 GenArrayBoundsCheck(rl_index.reg, reg_len);
530 FreeTemp(reg_len);
531 }
532 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
533
534 FreeTemp(reg_ptr);
535 StoreValueWide(rl_dest, rl_result);
536 } else {
537 rl_result = EvalLoc(rl_dest, reg_class, true);
538
539 if (needs_range_check) {
540 GenArrayBoundsCheck(rl_index.reg, reg_len);
541 FreeTemp(reg_len);
542 }
543 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
544
545 FreeTemp(reg_ptr);
546 StoreValue(rl_dest, rl_result);
547 }
548 }
549
550 /*
551 * Generate array store
552 *
553 */
GenArrayPut(int opt_flags,OpSize size,RegLocation rl_array,RegLocation rl_index,RegLocation rl_src,int scale,bool card_mark)554 void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
555 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
556 RegisterClass reg_class = RegClassBySize(size);
557 int len_offset = mirror::Array::LengthOffset().Int32Value();
558 int data_offset;
559
560 if (size == k64 || size == kDouble) {
561 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
562 } else {
563 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
564 }
565
566 rl_array = LoadValue(rl_array, kRefReg);
567 rl_index = LoadValue(rl_index, kCoreReg);
568
569 // FIXME: need to add support for rl_index.is_const.
570
571 RegStorage reg_ptr;
572 bool allocated_reg_ptr_temp = false;
573 if (IsTemp(rl_array.reg) && !card_mark) {
574 Clobber(rl_array.reg);
575 reg_ptr = rl_array.reg;
576 } else {
577 reg_ptr = AllocTemp();
578 OpRegCopy(reg_ptr, rl_array.reg);
579 allocated_reg_ptr_temp = true;
580 }
581
582 /* null object? */
583 GenNullCheck(rl_array.reg, opt_flags);
584
585 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
586 RegStorage reg_len;
587 if (needs_range_check) {
588 reg_len = AllocTemp();
589 // NOTE: max live temps(4) here.
590 /* Get len */
591 Load32Disp(rl_array.reg, len_offset, reg_len);
592 }
593 /* reg_ptr -> array data */
594 OpRegImm(kOpAdd, reg_ptr, data_offset);
595 /* at this point, reg_ptr points to array, 2 live temps */
596 if ((size == k64) || (size == kDouble)) {
597 // TUNING: specific wide routine that can handle fp regs
598 if (scale) {
599 RegStorage r_new_index = AllocTemp();
600 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
601 OpRegReg(kOpAdd, reg_ptr, r_new_index);
602 FreeTemp(r_new_index);
603 } else {
604 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
605 }
606 rl_src = LoadValueWide(rl_src, reg_class);
607
608 if (needs_range_check) {
609 GenArrayBoundsCheck(rl_index.reg, reg_len);
610 FreeTemp(reg_len);
611 }
612
613 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
614 } else {
615 rl_src = LoadValue(rl_src, reg_class);
616 if (needs_range_check) {
617 GenArrayBoundsCheck(rl_index.reg, reg_len);
618 FreeTemp(reg_len);
619 }
620 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
621 }
622 if (allocated_reg_ptr_temp) {
623 FreeTemp(reg_ptr);
624 }
625 if (card_mark) {
626 MarkGCCard(rl_src.reg, rl_array.reg);
627 }
628 }
629
GenShiftImmOpLong(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_shift)630 void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
631 RegLocation rl_src1, RegLocation rl_shift) {
632 // Default implementation is just to ignore the constant case.
633 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
634 }
635
GenArithImmOpLong(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)636 void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
637 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
638 // Default - bail to non-const handler.
639 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
640 }
641
642 } // namespace art
643