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