utility_mips.cc revision bd288c2c1206bc99fafebfb9120a83f13cf9723b
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#include "codegen_mips.h"
18#include "dex/quick/mir_to_lir-inl.h"
19#include "mips_lir.h"
20
21namespace art {
22
23/* This file contains codegen for the MIPS32 ISA. */
24LIR* MipsMir2Lir::OpFpRegCopy(int r_dest, int r_src) {
25  int opcode;
26  /* must be both DOUBLE or both not DOUBLE */
27  DCHECK_EQ(MIPS_DOUBLEREG(r_dest), MIPS_DOUBLEREG(r_src));
28  if (MIPS_DOUBLEREG(r_dest)) {
29    opcode = kMipsFmovd;
30  } else {
31    if (MIPS_SINGLEREG(r_dest)) {
32      if (MIPS_SINGLEREG(r_src)) {
33        opcode = kMipsFmovs;
34      } else {
35        /* note the operands are swapped for the mtc1 instr */
36        int t_opnd = r_src;
37        r_src = r_dest;
38        r_dest = t_opnd;
39        opcode = kMipsMtc1;
40      }
41    } else {
42      DCHECK(MIPS_SINGLEREG(r_src));
43      opcode = kMipsMfc1;
44    }
45  }
46  LIR* res = RawLIR(current_dalvik_offset_, opcode, r_src, r_dest);
47  if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
48    res->flags.is_nop = true;
49  }
50  return res;
51}
52
53bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
54  return ((value == 0) || IsUint(16, value) || ((value < 0) && (value >= -32768)));
55}
56
57bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
58  return false;  // TUNING
59}
60
61bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
62  return false;  // TUNING
63}
64
65bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
66  return false;  // TUNING
67}
68
69/*
70 * Load a immediate using a shortcut if possible; otherwise
71 * grab from the per-translation literal pool.  If target is
72 * a high register, build constant into a low register and copy.
73 *
74 * No additional register clobbering operation performed. Use this version when
75 * 1) r_dest is freshly returned from AllocTemp or
76 * 2) The codegen is under fixed register usage
77 */
78LIR* MipsMir2Lir::LoadConstantNoClobber(int r_dest, int value) {
79  LIR *res;
80
81  int r_dest_save = r_dest;
82  int is_fp_reg = MIPS_FPREG(r_dest);
83  if (is_fp_reg) {
84    DCHECK(MIPS_SINGLEREG(r_dest));
85    r_dest = AllocTemp();
86  }
87
88  /* See if the value can be constructed cheaply */
89  if (value == 0) {
90    res = NewLIR2(kMipsMove, r_dest, r_ZERO);
91  } else if ((value > 0) && (value <= 65535)) {
92    res = NewLIR3(kMipsOri, r_dest, r_ZERO, value);
93  } else if ((value < 0) && (value >= -32768)) {
94    res = NewLIR3(kMipsAddiu, r_dest, r_ZERO, value);
95  } else {
96    res = NewLIR2(kMipsLui, r_dest, value >> 16);
97    if (value & 0xffff)
98      NewLIR3(kMipsOri, r_dest, r_dest, value);
99  }
100
101  if (is_fp_reg) {
102    NewLIR2(kMipsMtc1, r_dest, r_dest_save);
103    FreeTemp(r_dest);
104  }
105
106  return res;
107}
108
109LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
110  LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
111  res->target = target;
112  return res;
113}
114
115LIR* MipsMir2Lir::OpReg(OpKind op, int r_dest_src) {
116  MipsOpCode opcode = kMipsNop;
117  switch (op) {
118    case kOpBlx:
119      opcode = kMipsJalr;
120      break;
121    case kOpBx:
122      return NewLIR1(kMipsJr, r_dest_src);
123      break;
124    default:
125      LOG(FATAL) << "Bad case in OpReg";
126  }
127  return NewLIR2(opcode, r_RA, r_dest_src);
128}
129
130LIR* MipsMir2Lir::OpRegImm(OpKind op, int r_dest_src1,
131          int value) {
132  LIR *res;
133  bool neg = (value < 0);
134  int abs_value = (neg) ? -value : value;
135  bool short_form = (abs_value & 0xff) == abs_value;
136  MipsOpCode opcode = kMipsNop;
137  switch (op) {
138    case kOpAdd:
139      return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
140      break;
141    case kOpSub:
142      return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
143      break;
144    default:
145      LOG(FATAL) << "Bad case in OpRegImm";
146      break;
147  }
148  if (short_form) {
149    res = NewLIR2(opcode, r_dest_src1, abs_value);
150  } else {
151    int r_scratch = AllocTemp();
152    res = LoadConstant(r_scratch, value);
153    if (op == kOpCmp)
154      NewLIR2(opcode, r_dest_src1, r_scratch);
155    else
156      NewLIR3(opcode, r_dest_src1, r_dest_src1, r_scratch);
157  }
158  return res;
159}
160
161LIR* MipsMir2Lir::OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2) {
162  MipsOpCode opcode = kMipsNop;
163  switch (op) {
164    case kOpAdd:
165      opcode = kMipsAddu;
166      break;
167    case kOpSub:
168      opcode = kMipsSubu;
169      break;
170    case kOpAnd:
171      opcode = kMipsAnd;
172      break;
173    case kOpMul:
174      opcode = kMipsMul;
175      break;
176    case kOpOr:
177      opcode = kMipsOr;
178      break;
179    case kOpXor:
180      opcode = kMipsXor;
181      break;
182    case kOpLsl:
183      opcode = kMipsSllv;
184      break;
185    case kOpLsr:
186      opcode = kMipsSrlv;
187      break;
188    case kOpAsr:
189      opcode = kMipsSrav;
190      break;
191    case kOpAdc:
192    case kOpSbc:
193      LOG(FATAL) << "No carry bit on MIPS";
194      break;
195    default:
196      LOG(FATAL) << "bad case in OpRegRegReg";
197      break;
198  }
199  return NewLIR3(opcode, r_dest, r_src1, r_src2);
200}
201
202LIR* MipsMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) {
203  LIR *res;
204  MipsOpCode opcode = kMipsNop;
205  bool short_form = true;
206
207  switch (op) {
208    case kOpAdd:
209      if (IS_SIMM16(value)) {
210        opcode = kMipsAddiu;
211      } else {
212        short_form = false;
213        opcode = kMipsAddu;
214      }
215      break;
216    case kOpSub:
217      if (IS_SIMM16((-value))) {
218        value = -value;
219        opcode = kMipsAddiu;
220      } else {
221        short_form = false;
222        opcode = kMipsSubu;
223      }
224      break;
225    case kOpLsl:
226        DCHECK(value >= 0 && value <= 31);
227        opcode = kMipsSll;
228        break;
229    case kOpLsr:
230        DCHECK(value >= 0 && value <= 31);
231        opcode = kMipsSrl;
232        break;
233    case kOpAsr:
234        DCHECK(value >= 0 && value <= 31);
235        opcode = kMipsSra;
236        break;
237    case kOpAnd:
238      if (IS_UIMM16((value))) {
239        opcode = kMipsAndi;
240      } else {
241        short_form = false;
242        opcode = kMipsAnd;
243      }
244      break;
245    case kOpOr:
246      if (IS_UIMM16((value))) {
247        opcode = kMipsOri;
248      } else {
249        short_form = false;
250        opcode = kMipsOr;
251      }
252      break;
253    case kOpXor:
254      if (IS_UIMM16((value))) {
255        opcode = kMipsXori;
256      } else {
257        short_form = false;
258        opcode = kMipsXor;
259      }
260      break;
261    case kOpMul:
262      short_form = false;
263      opcode = kMipsMul;
264      break;
265    default:
266      LOG(FATAL) << "Bad case in OpRegRegImm";
267      break;
268  }
269
270  if (short_form) {
271    res = NewLIR3(opcode, r_dest, r_src1, value);
272  } else {
273    if (r_dest != r_src1) {
274      res = LoadConstant(r_dest, value);
275      NewLIR3(opcode, r_dest, r_src1, r_dest);
276    } else {
277      int r_scratch = AllocTemp();
278      res = LoadConstant(r_scratch, value);
279      NewLIR3(opcode, r_dest, r_src1, r_scratch);
280    }
281  }
282  return res;
283}
284
285LIR* MipsMir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) {
286  MipsOpCode opcode = kMipsNop;
287  LIR *res;
288  switch (op) {
289    case kOpMov:
290      opcode = kMipsMove;
291      break;
292    case kOpMvn:
293      return NewLIR3(kMipsNor, r_dest_src1, r_src2, r_ZERO);
294    case kOpNeg:
295      return NewLIR3(kMipsSubu, r_dest_src1, r_ZERO, r_src2);
296    case kOpAdd:
297    case kOpAnd:
298    case kOpMul:
299    case kOpOr:
300    case kOpSub:
301    case kOpXor:
302      return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
303    case kOp2Byte:
304#if __mips_isa_rev >= 2
305      res = NewLIR2(kMipsSeb, r_dest_src1, r_src2);
306#else
307      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
308      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
309#endif
310      return res;
311    case kOp2Short:
312#if __mips_isa_rev >= 2
313      res = NewLIR2(kMipsSeh, r_dest_src1, r_src2);
314#else
315      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
316      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
317#endif
318      return res;
319    case kOp2Char:
320       return NewLIR3(kMipsAndi, r_dest_src1, r_src2, 0xFFFF);
321    default:
322      LOG(FATAL) << "Bad case in OpRegReg";
323      break;
324  }
325  return NewLIR2(opcode, r_dest_src1, r_src2);
326}
327
328LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
329  LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
330  return NULL;
331}
332
333LIR* MipsMir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) {
334  LIR *res;
335  res = LoadConstantNoClobber(r_dest_lo, Low32Bits(value));
336  LoadConstantNoClobber(r_dest_hi, High32Bits(value));
337  return res;
338}
339
340/* Load value from base + scaled index. */
341LIR* MipsMir2Lir::LoadBaseIndexed(int rBase, int r_index, int r_dest,
342                                  int scale, OpSize size) {
343  LIR *first = NULL;
344  LIR *res;
345  MipsOpCode opcode = kMipsNop;
346  int t_reg = AllocTemp();
347
348  if (MIPS_FPREG(r_dest)) {
349    DCHECK(MIPS_SINGLEREG(r_dest));
350    DCHECK((size == kWord) || (size == kSingle));
351    size = kSingle;
352  } else {
353    if (size == kSingle)
354      size = kWord;
355  }
356
357  if (!scale) {
358    first = NewLIR3(kMipsAddu, t_reg , rBase, r_index);
359  } else {
360    first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
361    NewLIR3(kMipsAddu, t_reg , rBase, t_reg);
362  }
363
364  switch (size) {
365    case kSingle:
366      opcode = kMipsFlwc1;
367      break;
368    case kWord:
369      opcode = kMipsLw;
370      break;
371    case kUnsignedHalf:
372      opcode = kMipsLhu;
373      break;
374    case kSignedHalf:
375      opcode = kMipsLh;
376      break;
377    case kUnsignedByte:
378      opcode = kMipsLbu;
379      break;
380    case kSignedByte:
381      opcode = kMipsLb;
382      break;
383    default:
384      LOG(FATAL) << "Bad case in LoadBaseIndexed";
385  }
386
387  res = NewLIR3(opcode, r_dest, 0, t_reg);
388  FreeTemp(t_reg);
389  return (first) ? first : res;
390}
391
392/* store value base base + scaled index. */
393LIR* MipsMir2Lir::StoreBaseIndexed(int rBase, int r_index, int r_src,
394                                   int scale, OpSize size) {
395  LIR *first = NULL;
396  MipsOpCode opcode = kMipsNop;
397  int r_new_index = r_index;
398  int t_reg = AllocTemp();
399
400  if (MIPS_FPREG(r_src)) {
401    DCHECK(MIPS_SINGLEREG(r_src));
402    DCHECK((size == kWord) || (size == kSingle));
403    size = kSingle;
404  } else {
405    if (size == kSingle)
406      size = kWord;
407  }
408
409  if (!scale) {
410    first = NewLIR3(kMipsAddu, t_reg , rBase, r_index);
411  } else {
412    first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
413    NewLIR3(kMipsAddu, t_reg , rBase, t_reg);
414  }
415
416  switch (size) {
417    case kSingle:
418      opcode = kMipsFswc1;
419      break;
420    case kWord:
421      opcode = kMipsSw;
422      break;
423    case kUnsignedHalf:
424    case kSignedHalf:
425      opcode = kMipsSh;
426      break;
427    case kUnsignedByte:
428    case kSignedByte:
429      opcode = kMipsSb;
430      break;
431    default:
432      LOG(FATAL) << "Bad case in StoreBaseIndexed";
433  }
434  NewLIR3(opcode, r_src, 0, t_reg);
435  FreeTemp(r_new_index);
436  return first;
437}
438
439LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest,
440                                   int r_dest_hi, OpSize size, int s_reg) {
441/*
442 * Load value from base + displacement.  Optionally perform null check
443 * on base (which must have an associated s_reg and MIR).  If not
444 * performing null check, incoming MIR can be null. IMPORTANT: this
445 * code must not allocate any new temps.  If a new register is needed
446 * and base and dest are the same, spill some other register to
447 * rlp and then restore.
448 */
449  LIR *res;
450  LIR *load = NULL;
451  LIR *load2 = NULL;
452  MipsOpCode opcode = kMipsNop;
453  bool short_form = IS_SIMM16(displacement);
454  bool pair = false;
455
456  switch (size) {
457    case kLong:
458    case kDouble:
459      pair = true;
460      opcode = kMipsLw;
461      if (MIPS_FPREG(r_dest)) {
462        opcode = kMipsFlwc1;
463        if (MIPS_DOUBLEREG(r_dest)) {
464          r_dest = r_dest - MIPS_FP_DOUBLE;
465        } else {
466          DCHECK(MIPS_FPREG(r_dest_hi));
467          DCHECK(r_dest == (r_dest_hi - 1));
468        }
469        r_dest_hi = r_dest + 1;
470      }
471      short_form = IS_SIMM16_2WORD(displacement);
472      DCHECK_EQ((displacement & 0x3), 0);
473      break;
474    case kWord:
475    case kSingle:
476      opcode = kMipsLw;
477      if (MIPS_FPREG(r_dest)) {
478        opcode = kMipsFlwc1;
479        DCHECK(MIPS_SINGLEREG(r_dest));
480      }
481      DCHECK_EQ((displacement & 0x3), 0);
482      break;
483    case kUnsignedHalf:
484      opcode = kMipsLhu;
485      DCHECK_EQ((displacement & 0x1), 0);
486      break;
487    case kSignedHalf:
488      opcode = kMipsLh;
489      DCHECK_EQ((displacement & 0x1), 0);
490      break;
491    case kUnsignedByte:
492      opcode = kMipsLbu;
493      break;
494    case kSignedByte:
495      opcode = kMipsLb;
496      break;
497    default:
498      LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
499  }
500
501  if (short_form) {
502    if (!pair) {
503      load = res = NewLIR3(opcode, r_dest, displacement, rBase);
504    } else {
505      load = res = NewLIR3(opcode, r_dest,
506                           displacement + LOWORD_OFFSET, rBase);
507      load2 = NewLIR3(opcode, r_dest_hi,
508                      displacement + HIWORD_OFFSET, rBase);
509    }
510  } else {
511    if (pair) {
512      int r_tmp = AllocTemp();
513      res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
514      load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp);
515      load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp);
516      FreeTemp(r_tmp);
517    } else {
518      int r_tmp = (rBase == r_dest) ? AllocTemp() : r_dest;
519      res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
520      load = NewLIR3(opcode, r_dest, 0, r_tmp);
521      if (r_tmp != r_dest)
522        FreeTemp(r_tmp);
523    }
524  }
525
526  if (rBase == rMIPS_SP) {
527    AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
528                            true /* is_load */, pair /* is64bit */);
529    if (pair) {
530      AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
531                              true /* is_load */, pair /* is64bit */);
532    }
533  }
534  return load;
535}
536
537LIR* MipsMir2Lir::LoadBaseDisp(int rBase, int displacement, int r_dest,
538                               OpSize size, int s_reg) {
539  return LoadBaseDispBody(rBase, displacement, r_dest, -1,
540                          size, s_reg);
541}
542
543LIR* MipsMir2Lir::LoadBaseDispWide(int rBase, int displacement,
544                                   int r_dest_lo, int r_dest_hi, int s_reg) {
545  return LoadBaseDispBody(rBase, displacement, r_dest_lo, r_dest_hi, kLong, s_reg);
546}
547
548LIR* MipsMir2Lir::StoreBaseDispBody(int rBase, int displacement,
549                                    int r_src, int r_src_hi, OpSize size) {
550  LIR *res;
551  LIR *store = NULL;
552  LIR *store2 = NULL;
553  MipsOpCode opcode = kMipsNop;
554  bool short_form = IS_SIMM16(displacement);
555  bool pair = false;
556
557  switch (size) {
558    case kLong:
559    case kDouble:
560      pair = true;
561      opcode = kMipsSw;
562      if (MIPS_FPREG(r_src)) {
563        opcode = kMipsFswc1;
564        if (MIPS_DOUBLEREG(r_src)) {
565          r_src = r_src - MIPS_FP_DOUBLE;
566        } else {
567          DCHECK(MIPS_FPREG(r_src_hi));
568          DCHECK_EQ(r_src, (r_src_hi - 1));
569        }
570        r_src_hi = r_src + 1;
571      }
572      short_form = IS_SIMM16_2WORD(displacement);
573      DCHECK_EQ((displacement & 0x3), 0);
574      break;
575    case kWord:
576    case kSingle:
577      opcode = kMipsSw;
578      if (MIPS_FPREG(r_src)) {
579        opcode = kMipsFswc1;
580        DCHECK(MIPS_SINGLEREG(r_src));
581      }
582      DCHECK_EQ((displacement & 0x3), 0);
583      break;
584    case kUnsignedHalf:
585    case kSignedHalf:
586      opcode = kMipsSh;
587      DCHECK_EQ((displacement & 0x1), 0);
588      break;
589    case kUnsignedByte:
590    case kSignedByte:
591      opcode = kMipsSb;
592      break;
593    default:
594      LOG(FATAL) << "Bad case in StoreBaseIndexedBody";
595  }
596
597  if (short_form) {
598    if (!pair) {
599      store = res = NewLIR3(opcode, r_src, displacement, rBase);
600    } else {
601      store = res = NewLIR3(opcode, r_src, displacement + LOWORD_OFFSET,
602                            rBase);
603      store2 = NewLIR3(opcode, r_src_hi, displacement + HIWORD_OFFSET,
604                       rBase);
605    }
606  } else {
607    int r_scratch = AllocTemp();
608    res = OpRegRegImm(kOpAdd, r_scratch, rBase, displacement);
609    if (!pair) {
610      store =  NewLIR3(opcode, r_src, 0, r_scratch);
611    } else {
612      store =  NewLIR3(opcode, r_src, LOWORD_OFFSET, r_scratch);
613      store2 = NewLIR3(opcode, r_src_hi, HIWORD_OFFSET, r_scratch);
614    }
615    FreeTemp(r_scratch);
616  }
617
618  if (rBase == rMIPS_SP) {
619    AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
620                            false /* is_load */, pair /* is64bit */);
621    if (pair) {
622      AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
623                              false /* is_load */, pair /* is64bit */);
624    }
625  }
626
627  return res;
628}
629
630LIR* MipsMir2Lir::StoreBaseDisp(int rBase, int displacement, int r_src,
631                                OpSize size) {
632  return StoreBaseDispBody(rBase, displacement, r_src, -1, size);
633}
634
635LIR* MipsMir2Lir::StoreBaseDispWide(int rBase, int displacement,
636                                    int r_src_lo, int r_src_hi) {
637  return StoreBaseDispBody(rBase, displacement, r_src_lo, r_src_hi, kLong);
638}
639
640LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset thread_offset) {
641  LOG(FATAL) << "Unexpected use of OpThreadMem for MIPS";
642  return NULL;
643}
644
645LIR* MipsMir2Lir::OpMem(OpKind op, int rBase, int disp) {
646  LOG(FATAL) << "Unexpected use of OpMem for MIPS";
647  return NULL;
648}
649
650LIR* MipsMir2Lir::StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
651                                       int r_src, int r_src_hi, OpSize size, int s_reg) {
652  LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS";
653  return NULL;
654}
655
656LIR* MipsMir2Lir::OpRegMem(OpKind op, int r_dest, int rBase,
657              int offset) {
658  LOG(FATAL) << "Unexpected use of OpRegMem for MIPS";
659  return NULL;
660}
661
662LIR* MipsMir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
663                                      int r_dest, int r_dest_hi, OpSize size, int s_reg) {
664  LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS";
665  return NULL;
666}
667
668LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
669  LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
670  return NULL;
671}
672
673}  // namespace art
674