blob: 8daafc8d96cdce3993bc2904ed3560c7abf3ce6b [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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