utility_mips.cc revision 468532ea115657709bc32ee498e701a4c71762d4
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::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) {
329  LIR *res;
330  res = LoadConstantNoClobber(r_dest_lo, Low32Bits(value));
331  LoadConstantNoClobber(r_dest_hi, High32Bits(value));
332  return res;
333}
334
335/* Load value from base + scaled index. */
336LIR* MipsMir2Lir::LoadBaseIndexed(int rBase, int r_index, int r_dest,
337                                  int scale, OpSize size) {
338  LIR *first = NULL;
339  LIR *res;
340  MipsOpCode opcode = kMipsNop;
341  int t_reg = AllocTemp();
342
343  if (MIPS_FPREG(r_dest)) {
344    DCHECK(MIPS_SINGLEREG(r_dest));
345    DCHECK((size == kWord) || (size == kSingle));
346    size = kSingle;
347  } else {
348    if (size == kSingle)
349      size = kWord;
350  }
351
352  if (!scale) {
353    first = NewLIR3(kMipsAddu, t_reg , rBase, r_index);
354  } else {
355    first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
356    NewLIR3(kMipsAddu, t_reg , rBase, t_reg);
357  }
358
359  switch (size) {
360    case kSingle:
361      opcode = kMipsFlwc1;
362      break;
363    case kWord:
364      opcode = kMipsLw;
365      break;
366    case kUnsignedHalf:
367      opcode = kMipsLhu;
368      break;
369    case kSignedHalf:
370      opcode = kMipsLh;
371      break;
372    case kUnsignedByte:
373      opcode = kMipsLbu;
374      break;
375    case kSignedByte:
376      opcode = kMipsLb;
377      break;
378    default:
379      LOG(FATAL) << "Bad case in LoadBaseIndexed";
380  }
381
382  res = NewLIR3(opcode, r_dest, 0, t_reg);
383  FreeTemp(t_reg);
384  return (first) ? first : res;
385}
386
387/* store value base base + scaled index. */
388LIR* MipsMir2Lir::StoreBaseIndexed(int rBase, int r_index, int r_src,
389                                   int scale, OpSize size) {
390  LIR *first = NULL;
391  MipsOpCode opcode = kMipsNop;
392  int r_new_index = r_index;
393  int t_reg = AllocTemp();
394
395  if (MIPS_FPREG(r_src)) {
396    DCHECK(MIPS_SINGLEREG(r_src));
397    DCHECK((size == kWord) || (size == kSingle));
398    size = kSingle;
399  } else {
400    if (size == kSingle)
401      size = kWord;
402  }
403
404  if (!scale) {
405    first = NewLIR3(kMipsAddu, t_reg , rBase, r_index);
406  } else {
407    first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
408    NewLIR3(kMipsAddu, t_reg , rBase, t_reg);
409  }
410
411  switch (size) {
412    case kSingle:
413      opcode = kMipsFswc1;
414      break;
415    case kWord:
416      opcode = kMipsSw;
417      break;
418    case kUnsignedHalf:
419    case kSignedHalf:
420      opcode = kMipsSh;
421      break;
422    case kUnsignedByte:
423    case kSignedByte:
424      opcode = kMipsSb;
425      break;
426    default:
427      LOG(FATAL) << "Bad case in StoreBaseIndexed";
428  }
429  NewLIR3(opcode, r_src, 0, t_reg);
430  FreeTemp(r_new_index);
431  return first;
432}
433
434LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest,
435                                   int r_dest_hi, OpSize size, int s_reg) {
436/*
437 * Load value from base + displacement.  Optionally perform null check
438 * on base (which must have an associated s_reg and MIR).  If not
439 * performing null check, incoming MIR can be null. IMPORTANT: this
440 * code must not allocate any new temps.  If a new register is needed
441 * and base and dest are the same, spill some other register to
442 * rlp and then restore.
443 */
444  LIR *res;
445  LIR *load = NULL;
446  LIR *load2 = NULL;
447  MipsOpCode opcode = kMipsNop;
448  bool short_form = IS_SIMM16(displacement);
449  bool pair = false;
450
451  switch (size) {
452    case kLong:
453    case kDouble:
454      pair = true;
455      opcode = kMipsLw;
456      if (MIPS_FPREG(r_dest)) {
457        opcode = kMipsFlwc1;
458        if (MIPS_DOUBLEREG(r_dest)) {
459          r_dest = r_dest - MIPS_FP_DOUBLE;
460        } else {
461          DCHECK(MIPS_FPREG(r_dest_hi));
462          DCHECK(r_dest == (r_dest_hi - 1));
463        }
464        r_dest_hi = r_dest + 1;
465      }
466      short_form = IS_SIMM16_2WORD(displacement);
467      DCHECK_EQ((displacement & 0x3), 0);
468      break;
469    case kWord:
470    case kSingle:
471      opcode = kMipsLw;
472      if (MIPS_FPREG(r_dest)) {
473        opcode = kMipsFlwc1;
474        DCHECK(MIPS_SINGLEREG(r_dest));
475      }
476      DCHECK_EQ((displacement & 0x3), 0);
477      break;
478    case kUnsignedHalf:
479      opcode = kMipsLhu;
480      DCHECK_EQ((displacement & 0x1), 0);
481      break;
482    case kSignedHalf:
483      opcode = kMipsLh;
484      DCHECK_EQ((displacement & 0x1), 0);
485      break;
486    case kUnsignedByte:
487      opcode = kMipsLbu;
488      break;
489    case kSignedByte:
490      opcode = kMipsLb;
491      break;
492    default:
493      LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
494  }
495
496  if (short_form) {
497    if (!pair) {
498      load = res = NewLIR3(opcode, r_dest, displacement, rBase);
499    } else {
500      load = res = NewLIR3(opcode, r_dest,
501                           displacement + LOWORD_OFFSET, rBase);
502      load2 = NewLIR3(opcode, r_dest_hi,
503                      displacement + HIWORD_OFFSET, rBase);
504    }
505  } else {
506    if (pair) {
507      int r_tmp = AllocFreeTemp();
508      res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
509      load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp);
510      load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp);
511      FreeTemp(r_tmp);
512    } else {
513      int r_tmp = (rBase == r_dest) ? AllocFreeTemp() : r_dest;
514      res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
515      load = NewLIR3(opcode, r_dest, 0, r_tmp);
516      if (r_tmp != r_dest)
517        FreeTemp(r_tmp);
518    }
519  }
520
521  if (rBase == rMIPS_SP) {
522    AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
523                            true /* is_load */, pair /* is64bit */);
524    if (pair) {
525      AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
526                              true /* is_load */, pair /* is64bit */);
527    }
528  }
529  return load;
530}
531
532LIR* MipsMir2Lir::LoadBaseDisp(int rBase, int displacement, int r_dest,
533                               OpSize size, int s_reg) {
534  return LoadBaseDispBody(rBase, displacement, r_dest, -1,
535                          size, s_reg);
536}
537
538LIR* MipsMir2Lir::LoadBaseDispWide(int rBase, int displacement,
539                                   int r_dest_lo, int r_dest_hi, int s_reg) {
540  return LoadBaseDispBody(rBase, displacement, r_dest_lo, r_dest_hi, kLong, s_reg);
541}
542
543LIR* MipsMir2Lir::StoreBaseDispBody(int rBase, int displacement,
544                                    int r_src, int r_src_hi, OpSize size) {
545  LIR *res;
546  LIR *store = NULL;
547  LIR *store2 = NULL;
548  MipsOpCode opcode = kMipsNop;
549  bool short_form = IS_SIMM16(displacement);
550  bool pair = false;
551
552  switch (size) {
553    case kLong:
554    case kDouble:
555      pair = true;
556      opcode = kMipsSw;
557      if (MIPS_FPREG(r_src)) {
558        opcode = kMipsFswc1;
559        if (MIPS_DOUBLEREG(r_src)) {
560          r_src = r_src - MIPS_FP_DOUBLE;
561        } else {
562          DCHECK(MIPS_FPREG(r_src_hi));
563          DCHECK_EQ(r_src, (r_src_hi - 1));
564        }
565        r_src_hi = r_src + 1;
566      }
567      short_form = IS_SIMM16_2WORD(displacement);
568      DCHECK_EQ((displacement & 0x3), 0);
569      break;
570    case kWord:
571    case kSingle:
572      opcode = kMipsSw;
573      if (MIPS_FPREG(r_src)) {
574        opcode = kMipsFswc1;
575        DCHECK(MIPS_SINGLEREG(r_src));
576      }
577      DCHECK_EQ((displacement & 0x3), 0);
578      break;
579    case kUnsignedHalf:
580    case kSignedHalf:
581      opcode = kMipsSh;
582      DCHECK_EQ((displacement & 0x1), 0);
583      break;
584    case kUnsignedByte:
585    case kSignedByte:
586      opcode = kMipsSb;
587      break;
588    default:
589      LOG(FATAL) << "Bad case in StoreBaseIndexedBody";
590  }
591
592  if (short_form) {
593    if (!pair) {
594      store = res = NewLIR3(opcode, r_src, displacement, rBase);
595    } else {
596      store = res = NewLIR3(opcode, r_src, displacement + LOWORD_OFFSET,
597                            rBase);
598      store2 = NewLIR3(opcode, r_src_hi, displacement + HIWORD_OFFSET,
599                       rBase);
600    }
601  } else {
602    int r_scratch = AllocTemp();
603    res = OpRegRegImm(kOpAdd, r_scratch, rBase, displacement);
604    if (!pair) {
605      store =  NewLIR3(opcode, r_src, 0, r_scratch);
606    } else {
607      store =  NewLIR3(opcode, r_src, LOWORD_OFFSET, r_scratch);
608      store2 = NewLIR3(opcode, r_src_hi, HIWORD_OFFSET, r_scratch);
609    }
610    FreeTemp(r_scratch);
611  }
612
613  if (rBase == rMIPS_SP) {
614    AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
615                            false /* is_load */, pair /* is64bit */);
616    if (pair) {
617      AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
618                              false /* is_load */, pair /* is64bit */);
619    }
620  }
621
622  return res;
623}
624
625LIR* MipsMir2Lir::StoreBaseDisp(int rBase, int displacement, int r_src,
626                                OpSize size) {
627  return StoreBaseDispBody(rBase, displacement, r_src, -1, size);
628}
629
630LIR* MipsMir2Lir::StoreBaseDispWide(int rBase, int displacement,
631                                    int r_src_lo, int r_src_hi) {
632  return StoreBaseDispBody(rBase, displacement, r_src_lo, r_src_hi, kLong);
633}
634
635LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset thread_offset) {
636  LOG(FATAL) << "Unexpected use of OpThreadMem for MIPS";
637  return NULL;
638}
639
640LIR* MipsMir2Lir::OpMem(OpKind op, int rBase, int disp) {
641  LOG(FATAL) << "Unexpected use of OpMem for MIPS";
642  return NULL;
643}
644
645LIR* MipsMir2Lir::StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
646                                       int r_src, int r_src_hi, OpSize size, int s_reg) {
647  LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS";
648  return NULL;
649}
650
651LIR* MipsMir2Lir::OpRegMem(OpKind op, int r_dest, int rBase,
652              int offset) {
653  LOG(FATAL) << "Unexpected use of OpRegMem for MIPS";
654  return NULL;
655}
656
657LIR* MipsMir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
658                                      int r_dest, int r_dest_hi, OpSize size, int s_reg) {
659  LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS";
660  return NULL;
661}
662
663LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
664  LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
665  return NULL;
666}
667
668}  // namespace art
669