• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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