1 /*
2 * Copyright (C) 2009 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 /*
18 * This file contains codegen for the Thumb ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25 static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
26 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9, r_S0, r_S4};
27 #ifdef __mips_hard_float
28 static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
29 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
30 #endif
31
32 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
33 int highReg);
34 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
35 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
36 int rDest);
37 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
38 int displacement, int rSrc);
39 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
40 MipsConditionCode cond,
41 int reg1, int reg2, int dOffset,
42 MipsLIR *pcrLabel);
43 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
44
45 #ifdef __mips_hard_float
fpRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)46 static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
47 {
48 MipsLIR* res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
49 res->operands[0] = rDest;
50 res->operands[1] = rSrc;
51 if (rDest == rSrc) {
52 res->flags.isNop = true;
53 } else {
54 /* must be both DOUBLE or both not DOUBLE */
55 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
56 if (DOUBLEREG(rDest)) {
57 res->opcode = kMipsFmovd;
58 } else {
59 if (SINGLEREG(rDest)) {
60 if (SINGLEREG(rSrc)) {
61 res->opcode = kMipsFmovs;
62 } else {
63 /* note the operands are swapped for the mtc1 instr */
64 res->opcode = kMipsMtc1;
65 res->operands[0] = rSrc;
66 res->operands[1] = rDest;
67 }
68 } else {
69 assert(SINGLEREG(rSrc));
70 res->opcode = kMipsMfc1;
71 }
72 }
73 }
74 setupResourceMasks(res);
75 return res;
76 }
77 #endif
78
79 /*
80 * Load a immediate using a shortcut if possible; otherwise
81 * grab from the per-translation literal pool. If target is
82 * a high register, build constant into a low register and copy.
83 *
84 * No additional register clobbering operation performed. Use this version when
85 * 1) rDest is freshly returned from dvmCompilerAllocTemp or
86 * 2) The codegen is under fixed register usage
87 */
loadConstantNoClobber(CompilationUnit * cUnit,int rDest,int value)88 static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
89 int value)
90 {
91 MipsLIR *res;
92
93 #ifdef __mips_hard_float
94 int rDestSave = rDest;
95 int isFpReg = FPREG(rDest);
96 if (isFpReg) {
97 assert(SINGLEREG(rDest));
98 rDest = dvmCompilerAllocTemp(cUnit);
99 }
100 #endif
101
102 /* See if the value can be constructed cheaply */
103 if (value == 0) {
104 res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
105 } else if ((value > 0) && (value <= 65535)) {
106 res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
107 } else if ((value < 0) && (value >= -32768)) {
108 res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
109 } else {
110 res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
111 if (value & 0xffff)
112 newLIR3(cUnit, kMipsOri, rDest, rDest, value);
113 }
114
115 #ifdef __mips_hard_float
116 if (isFpReg) {
117 newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
118 dvmCompilerFreeTemp(cUnit, rDest);
119 }
120 #endif
121
122 return res;
123 }
124
125 /*
126 * Load an immediate value into a fixed or temp register. Target
127 * register is clobbered, and marked inUse.
128 */
loadConstant(CompilationUnit * cUnit,int rDest,int value)129 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
130 {
131 if (dvmCompilerIsTemp(cUnit, rDest)) {
132 dvmCompilerClobber(cUnit, rDest);
133 dvmCompilerMarkInUse(cUnit, rDest);
134 }
135 return loadConstantNoClobber(cUnit, rDest, value);
136 }
137
138 /*
139 * Load a class pointer value into a fixed or temp register. Target
140 * register is clobbered, and marked inUse.
141 */
loadClassPointer(CompilationUnit * cUnit,int rDest,int value)142 static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
143 {
144 MipsLIR *res;
145 if (dvmCompilerIsTemp(cUnit, rDest)) {
146 dvmCompilerClobber(cUnit, rDest);
147 dvmCompilerMarkInUse(cUnit, rDest);
148 }
149 res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
150 if (value & 0xffff)
151 newLIR3(cUnit, kMipsOri, rDest, rDest, value);
152 return res;
153 }
154
opNone(CompilationUnit * cUnit,OpKind op)155 static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
156 {
157 MipsLIR *res;
158 MipsOpCode opcode = kMipsNop;
159 switch (op) {
160 case kOpUncondBr:
161 opcode = kMipsB;
162 break;
163 default:
164 ALOGE("Jit: bad case in opNone");
165 dvmCompilerAbort(cUnit);
166 }
167 res = newLIR0(cUnit, opcode);
168 return res;
169 }
170
opCompareBranch(CompilationUnit * cUnit,MipsOpCode opc,int rs,int rt)171 static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
172 {
173 MipsLIR *res;
174 if (rt < 0) {
175 assert(opc >= kMipsBeqz && opc <= kMipsBnez);
176 res = newLIR1(cUnit, opc, rs);
177 } else {
178 assert(opc == kMipsBeq || opc == kMipsBne);
179 res = newLIR2(cUnit, opc, rs, rt);
180 }
181 return res;
182 }
183
184 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
185
opReg(CompilationUnit * cUnit,OpKind op,int rDestSrc)186 static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
187 {
188 MipsOpCode opcode = kMipsNop;
189 switch (op) {
190 case kOpBlx:
191 opcode = kMipsJalr;
192 break;
193 default:
194 assert(0);
195 }
196 return newLIR2(cUnit, opcode, r_RA, rDestSrc);
197 }
198
199 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
200 int rSrc1, int value);
opRegImm(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int value)201 static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
202 int value)
203 {
204 MipsLIR *res;
205 bool neg = (value < 0);
206 int absValue = (neg) ? -value : value;
207 bool shortForm = (absValue & 0xff) == absValue;
208 MipsOpCode opcode = kMipsNop;
209 switch (op) {
210 case kOpAdd:
211 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
212 break;
213 case kOpSub:
214 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
215 break;
216 default:
217 ALOGE("Jit: bad case in opRegImm");
218 dvmCompilerAbort(cUnit);
219 break;
220 }
221 if (shortForm)
222 res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
223 else {
224 int rScratch = dvmCompilerAllocTemp(cUnit);
225 res = loadConstant(cUnit, rScratch, value);
226 if (op == kOpCmp)
227 newLIR2(cUnit, opcode, rDestSrc1, rScratch);
228 else
229 newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
230 }
231 return res;
232 }
233
opRegRegReg(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int rSrc2)234 static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
235 int rSrc1, int rSrc2)
236 {
237 MipsOpCode opcode = kMipsNop;
238 switch (op) {
239 case kOpAdd:
240 opcode = kMipsAddu;
241 break;
242 case kOpSub:
243 opcode = kMipsSubu;
244 break;
245 case kOpAnd:
246 opcode = kMipsAnd;
247 break;
248 case kOpMul:
249 opcode = kMipsMul;
250 break;
251 case kOpOr:
252 opcode = kMipsOr;
253 break;
254 case kOpXor:
255 opcode = kMipsXor;
256 break;
257 case kOpLsl:
258 opcode = kMipsSllv;
259 break;
260 case kOpLsr:
261 opcode = kMipsSrlv;
262 break;
263 case kOpAsr:
264 opcode = kMipsSrav;
265 break;
266 default:
267 ALOGE("Jit: bad case in opRegRegReg");
268 dvmCompilerAbort(cUnit);
269 break;
270 }
271 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
272 }
273
opRegRegImm(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int value)274 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
275 int rSrc1, int value)
276 {
277 MipsLIR *res;
278 MipsOpCode opcode = kMipsNop;
279 bool shortForm = true;
280
281 switch(op) {
282 case kOpAdd:
283 if (IS_SIMM16(value)) {
284 opcode = kMipsAddiu;
285 }
286 else {
287 shortForm = false;
288 opcode = kMipsAddu;
289 }
290 break;
291 case kOpSub:
292 if (IS_SIMM16((-value))) {
293 value = -value;
294 opcode = kMipsAddiu;
295 }
296 else {
297 shortForm = false;
298 opcode = kMipsSubu;
299 }
300 break;
301 case kOpLsl:
302 assert(value >= 0 && value <= 31);
303 opcode = kMipsSll;
304 break;
305 case kOpLsr:
306 assert(value >= 0 && value <= 31);
307 opcode = kMipsSrl;
308 break;
309 case kOpAsr:
310 assert(value >= 0 && value <= 31);
311 opcode = kMipsSra;
312 break;
313 case kOpAnd:
314 if (IS_UIMM16((value))) {
315 opcode = kMipsAndi;
316 }
317 else {
318 shortForm = false;
319 opcode = kMipsAnd;
320 }
321 break;
322 case kOpOr:
323 if (IS_UIMM16((value))) {
324 opcode = kMipsOri;
325 }
326 else {
327 shortForm = false;
328 opcode = kMipsOr;
329 }
330 break;
331 case kOpXor:
332 if (IS_UIMM16((value))) {
333 opcode = kMipsXori;
334 }
335 else {
336 shortForm = false;
337 opcode = kMipsXor;
338 }
339 break;
340 case kOpMul:
341 shortForm = false;
342 opcode = kMipsMul;
343 break;
344 default:
345 ALOGE("Jit: bad case in opRegRegImm");
346 dvmCompilerAbort(cUnit);
347 break;
348 }
349
350 if (shortForm)
351 res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
352 else {
353 if (rDest != rSrc1) {
354 res = loadConstant(cUnit, rDest, value);
355 newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
356 } else {
357 int rScratch = dvmCompilerAllocTemp(cUnit);
358 res = loadConstant(cUnit, rScratch, value);
359 newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
360 }
361 }
362 return res;
363 }
364
opRegReg(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int rSrc2)365 static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
366 int rSrc2)
367 {
368 MipsOpCode opcode = kMipsNop;
369 MipsLIR *res;
370 switch (op) {
371 case kOpMov:
372 opcode = kMipsMove;
373 break;
374 case kOpMvn:
375 return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
376 case kOpNeg:
377 return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
378 case kOpAdd:
379 case kOpAnd:
380 case kOpMul:
381 case kOpOr:
382 case kOpSub:
383 case kOpXor:
384 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
385 case kOp2Byte:
386 #if __mips_isa_rev>=2
387 res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
388 #else
389 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
390 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
391 #endif
392 return res;
393 case kOp2Short:
394 #if __mips_isa_rev>=2
395 res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
396 #else
397 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
398 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
399 #endif
400 return res;
401 case kOp2Char:
402 return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
403 default:
404 ALOGE("Jit: bad case in opRegReg");
405 dvmCompilerAbort(cUnit);
406 break;
407 }
408 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
409 }
410
loadConstantValueWide(CompilationUnit * cUnit,int rDestLo,int rDestHi,int valLo,int valHi)411 static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
412 int rDestHi, int valLo, int valHi)
413 {
414 MipsLIR *res;
415 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
416 loadConstantNoClobber(cUnit, rDestHi, valHi);
417 return res;
418 }
419
420 /* Load value from base + scaled index. */
loadBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rDest,int scale,OpSize size)421 static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
422 int rIndex, int rDest, int scale, OpSize size)
423 {
424 MipsLIR *first = NULL;
425 MipsLIR *res;
426 MipsOpCode opcode = kMipsNop;
427 int tReg = dvmCompilerAllocTemp(cUnit);
428
429 #ifdef __mips_hard_float
430 if (FPREG(rDest)) {
431 assert(SINGLEREG(rDest));
432 assert((size == kWord) || (size == kSingle));
433 size = kSingle;
434 } else {
435 if (size == kSingle)
436 size = kWord;
437 }
438 #endif
439
440 if (!scale) {
441 first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
442 } else {
443 first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
444 newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
445 }
446
447 switch (size) {
448 #ifdef __mips_hard_float
449 case kSingle:
450 opcode = kMipsFlwc1;
451 break;
452 #endif
453 case kWord:
454 opcode = kMipsLw;
455 break;
456 case kUnsignedHalf:
457 opcode = kMipsLhu;
458 break;
459 case kSignedHalf:
460 opcode = kMipsLh;
461 break;
462 case kUnsignedByte:
463 opcode = kMipsLbu;
464 break;
465 case kSignedByte:
466 opcode = kMipsLb;
467 break;
468 default:
469 ALOGE("Jit: bad case in loadBaseIndexed");
470 dvmCompilerAbort(cUnit);
471 }
472
473 res = newLIR3(cUnit, opcode, rDest, 0, tReg);
474 #if defined(WITH_SELF_VERIFICATION)
475 if (cUnit->heapMemOp)
476 res->flags.insertWrapper = true;
477 #endif
478 dvmCompilerFreeTemp(cUnit, tReg);
479 return (first) ? first : res;
480 }
481
482 /* store value base base + scaled index. */
storeBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rSrc,int scale,OpSize size)483 static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
484 int rIndex, int rSrc, int scale, OpSize size)
485 {
486 MipsLIR *first = NULL;
487 MipsLIR *res;
488 MipsOpCode opcode = kMipsNop;
489 int rNewIndex = rIndex;
490 int tReg = dvmCompilerAllocTemp(cUnit);
491
492 #ifdef __mips_hard_float
493 if (FPREG(rSrc)) {
494 assert(SINGLEREG(rSrc));
495 assert((size == kWord) || (size == kSingle));
496 size = kSingle;
497 } else {
498 if (size == kSingle)
499 size = kWord;
500 }
501 #endif
502
503 if (!scale) {
504 first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
505 } else {
506 first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
507 newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
508 }
509
510 switch (size) {
511 #ifdef __mips_hard_float
512 case kSingle:
513 opcode = kMipsFswc1;
514 break;
515 #endif
516 case kWord:
517 opcode = kMipsSw;
518 break;
519 case kUnsignedHalf:
520 case kSignedHalf:
521 opcode = kMipsSh;
522 break;
523 case kUnsignedByte:
524 case kSignedByte:
525 opcode = kMipsSb;
526 break;
527 default:
528 ALOGE("Jit: bad case in storeBaseIndexed");
529 dvmCompilerAbort(cUnit);
530 }
531 res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
532 #if defined(WITH_SELF_VERIFICATION)
533 if (cUnit->heapMemOp)
534 res->flags.insertWrapper = true;
535 #endif
536 dvmCompilerFreeTemp(cUnit, rNewIndex);
537 return first;
538 }
539
loadMultiple(CompilationUnit * cUnit,int rBase,int rMask)540 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
541 {
542 int i;
543 int loadCnt = 0;
544 MipsLIR *res = NULL ;
545 genBarrier(cUnit);
546
547 for (i = 0; i < 8; i++, rMask >>= 1) {
548 if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
549 newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
550 loadCnt++;
551 }
552 }
553
554 if (loadCnt) {/* increment after */
555 newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
556 }
557
558 #if defined(WITH_SELF_VERIFICATION)
559 if (cUnit->heapMemOp)
560 res->flags.insertWrapper = true;
561 #endif
562 genBarrier(cUnit);
563 return res; /* NULL always returned which should be ok since no callers use it */
564 }
565
storeMultiple(CompilationUnit * cUnit,int rBase,int rMask)566 static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
567 {
568 int i;
569 int storeCnt = 0;
570 MipsLIR *res = NULL ;
571 genBarrier(cUnit);
572
573 for (i = 0; i < 8; i++, rMask >>= 1) {
574 if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
575 newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
576 storeCnt++;
577 }
578 }
579
580 if (storeCnt) { /* increment after */
581 newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
582 }
583
584 #if defined(WITH_SELF_VERIFICATION)
585 if (cUnit->heapMemOp)
586 res->flags.insertWrapper = true;
587 #endif
588 genBarrier(cUnit);
589 return res; /* NULL always returned which should be ok since no callers use it */
590 }
591
loadBaseDispBody(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,int rDestHi,OpSize size,int sReg)592 static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
593 int displacement, int rDest, int rDestHi,
594 OpSize size, int sReg)
595 /*
596 * Load value from base + displacement. Optionally perform null check
597 * on base (which must have an associated sReg and MIR). If not
598 * performing null check, incoming MIR can be null. IMPORTANT: this
599 * code must not allocate any new temps. If a new register is needed
600 * and base and dest are the same, spill some other register to
601 * rlp and then restore.
602 */
603 {
604 MipsLIR *res;
605 MipsLIR *load = NULL;
606 MipsLIR *load2 = NULL;
607 MipsOpCode opcode = kMipsNop;
608 bool shortForm = IS_SIMM16(displacement);
609 bool pair = false;
610
611 switch (size) {
612 case kLong:
613 case kDouble:
614 pair = true;
615 opcode = kMipsLw;
616 #ifdef __mips_hard_float
617 if (FPREG(rDest)) {
618 opcode = kMipsFlwc1;
619 if (DOUBLEREG(rDest)) {
620 rDest = rDest - FP_DOUBLE;
621 } else {
622 assert(FPREG(rDestHi));
623 assert(rDest == (rDestHi - 1));
624 }
625 rDestHi = rDest + 1;
626 }
627 #endif
628 shortForm = IS_SIMM16_2WORD(displacement);
629 assert((displacement & 0x3) == 0);
630 break;
631 case kWord:
632 case kSingle:
633 opcode = kMipsLw;
634 #ifdef __mips_hard_float
635 if (FPREG(rDest)) {
636 opcode = kMipsFlwc1;
637 assert(SINGLEREG(rDest));
638 }
639 #endif
640 assert((displacement & 0x3) == 0);
641 break;
642 case kUnsignedHalf:
643 opcode = kMipsLhu;
644 assert((displacement & 0x1) == 0);
645 break;
646 case kSignedHalf:
647 opcode = kMipsLh;
648 assert((displacement & 0x1) == 0);
649 break;
650 case kUnsignedByte:
651 opcode = kMipsLbu;
652 break;
653 case kSignedByte:
654 opcode = kMipsLb;
655 break;
656 default:
657 ALOGE("Jit: bad case in loadBaseIndexedBody");
658 dvmCompilerAbort(cUnit);
659 }
660
661 if (shortForm) {
662 if (!pair) {
663 load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
664 } else {
665 load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
666 load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
667 }
668 } else {
669 if (pair) {
670 int rTmp = dvmCompilerAllocFreeTemp(cUnit);
671 res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
672 load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
673 load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
674 dvmCompilerFreeTemp(cUnit, rTmp);
675 } else {
676 int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
677 : rDest;
678 res = loadConstant(cUnit, rTmp, displacement);
679 load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
680 if (rTmp != rDest)
681 dvmCompilerFreeTemp(cUnit, rTmp);
682 }
683 }
684
685 if (rBase == rFP) {
686 if (load != NULL)
687 annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
688 true /* isLoad */);
689 if (load2 != NULL)
690 annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
691 true /* isLoad */);
692 }
693 #if defined(WITH_SELF_VERIFICATION)
694 if (load != NULL && cUnit->heapMemOp)
695 load->flags.insertWrapper = true;
696 if (load2 != NULL && cUnit->heapMemOp)
697 load2->flags.insertWrapper = true;
698 #endif
699 return load;
700 }
701
loadBaseDisp(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,OpSize size,int sReg)702 static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
703 int displacement, int rDest, OpSize size,
704 int sReg)
705 {
706 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
707 size, sReg);
708 }
709
loadBaseDispWide(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDestLo,int rDestHi,int sReg)710 static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
711 int displacement, int rDestLo, int rDestHi,
712 int sReg)
713 {
714 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
715 kLong, sReg);
716 }
717
storeBaseDispBody(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,int rSrcHi,OpSize size)718 static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
719 int displacement, int rSrc, int rSrcHi,
720 OpSize size)
721 {
722 MipsLIR *res;
723 MipsLIR *store = NULL;
724 MipsLIR *store2 = NULL;
725 MipsOpCode opcode = kMipsNop;
726 bool shortForm = IS_SIMM16(displacement);
727 bool pair = false;
728
729 switch (size) {
730 case kLong:
731 case kDouble:
732 pair = true;
733 opcode = kMipsSw;
734 #ifdef __mips_hard_float
735 if (FPREG(rSrc)) {
736 opcode = kMipsFswc1;
737 if (DOUBLEREG(rSrc)) {
738 rSrc = rSrc - FP_DOUBLE;
739 } else {
740 assert(FPREG(rSrcHi));
741 assert(rSrc == (rSrcHi - 1));
742 }
743 rSrcHi = rSrc + 1;
744 }
745 #endif
746 shortForm = IS_SIMM16_2WORD(displacement);
747 assert((displacement & 0x3) == 0);
748 break;
749 case kWord:
750 case kSingle:
751 opcode = kMipsSw;
752 #ifdef __mips_hard_float
753 if (FPREG(rSrc)) {
754 opcode = kMipsFswc1;
755 assert(SINGLEREG(rSrc));
756 }
757 #endif
758 assert((displacement & 0x3) == 0);
759 break;
760 case kUnsignedHalf:
761 case kSignedHalf:
762 opcode = kMipsSh;
763 assert((displacement & 0x1) == 0);
764 break;
765 case kUnsignedByte:
766 case kSignedByte:
767 opcode = kMipsSb;
768 break;
769 default:
770 ALOGE("Jit: bad case in storeBaseIndexedBody");
771 dvmCompilerAbort(cUnit);
772 }
773
774 if (shortForm) {
775 if (!pair) {
776 store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
777 } else {
778 store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
779 store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
780 }
781 } else {
782 int rScratch = dvmCompilerAllocTemp(cUnit);
783 res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
784 if (!pair) {
785 store = newLIR3(cUnit, opcode, rSrc, 0, rScratch);
786 } else {
787 store = newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
788 store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
789 }
790 dvmCompilerFreeTemp(cUnit, rScratch);
791 }
792
793 if (rBase == rFP) {
794 if (store != NULL)
795 annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
796 false /* isLoad */);
797 if (store2 != NULL)
798 annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
799 false /* isLoad */);
800 }
801
802 #if defined(WITH_SELF_VERIFICATION)
803 if (store != NULL && cUnit->heapMemOp)
804 store->flags.insertWrapper = true;
805 if (store2 != NULL && cUnit->heapMemOp)
806 store2->flags.insertWrapper = true;
807 #endif
808 return res;
809 }
810
storeBaseDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,OpSize size)811 static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
812 int displacement, int rSrc, OpSize size)
813 {
814 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
815 }
816
storeBaseDispWide(CompilationUnit * cUnit,int rBase,int displacement,int rSrcLo,int rSrcHi)817 static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
818 int displacement, int rSrcLo, int rSrcHi)
819 {
820 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
821 }
822
storePair(CompilationUnit * cUnit,int base,int lowReg,int highReg)823 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
824 {
825 storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
826 storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
827 }
828
loadPair(CompilationUnit * cUnit,int base,int lowReg,int highReg)829 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
830 {
831 loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
832 loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
833 }
834
genRegCopyNoInsert(CompilationUnit * cUnit,int rDest,int rSrc)835 static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
836 {
837 MipsLIR* res;
838 MipsOpCode opcode;
839 #ifdef __mips_hard_float
840 if (FPREG(rDest) || FPREG(rSrc))
841 return fpRegCopy(cUnit, rDest, rSrc);
842 #endif
843 res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
844 opcode = kMipsMove;
845 assert(LOWREG(rDest) && LOWREG(rSrc));
846 res->operands[0] = rDest;
847 res->operands[1] = rSrc;
848 res->opcode = opcode;
849 setupResourceMasks(res);
850 if (rDest == rSrc) {
851 res->flags.isNop = true;
852 }
853 return res;
854 }
855
genRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)856 static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
857 {
858 MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
859 dvmCompilerAppendLIR(cUnit, (LIR*)res);
860 return res;
861 }
862
genRegCopyWide(CompilationUnit * cUnit,int destLo,int destHi,int srcLo,int srcHi)863 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
864 int srcLo, int srcHi)
865 {
866 #ifdef __mips_hard_float
867 bool destFP = FPREG(destLo) && FPREG(destHi);
868 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
869 assert(FPREG(srcLo) == FPREG(srcHi));
870 assert(FPREG(destLo) == FPREG(destHi));
871 if (destFP) {
872 if (srcFP) {
873 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
874 } else {
875 /* note the operands are swapped for the mtc1 instr */
876 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
877 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
878 }
879 } else {
880 if (srcFP) {
881 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
882 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
883 } else {
884 // Handle overlap
885 if (srcHi == destLo) {
886 genRegCopy(cUnit, destHi, srcHi);
887 genRegCopy(cUnit, destLo, srcLo);
888 } else {
889 genRegCopy(cUnit, destLo, srcLo);
890 genRegCopy(cUnit, destHi, srcHi);
891 }
892 }
893 }
894 #else
895 // Handle overlap
896 if (srcHi == destLo) {
897 genRegCopy(cUnit, destHi, srcHi);
898 genRegCopy(cUnit, destLo, srcLo);
899 } else {
900 genRegCopy(cUnit, destLo, srcLo);
901 genRegCopy(cUnit, destHi, srcHi);
902 }
903 #endif
904 }
905
genRegImmCheck(CompilationUnit * cUnit,MipsConditionCode cond,int reg,int checkValue,int dOffset,MipsLIR * pcrLabel)906 static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
907 MipsConditionCode cond, int reg,
908 int checkValue, int dOffset,
909 MipsLIR *pcrLabel)
910 {
911 MipsLIR *branch = NULL;
912
913 if (checkValue == 0) {
914 MipsOpCode opc = kMipsNop;
915 if (cond == kMipsCondEq) {
916 opc = kMipsBeqz;
917 } else if (cond == kMipsCondNe) {
918 opc = kMipsBnez;
919 } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
920 opc = kMipsBltz;
921 } else if (cond == kMipsCondLe) {
922 opc = kMipsBlez;
923 } else if (cond == kMipsCondGt) {
924 opc = kMipsBgtz;
925 } else if (cond == kMipsCondGe) {
926 opc = kMipsBgez;
927 } else {
928 ALOGE("Jit: bad case in genRegImmCheck");
929 dvmCompilerAbort(cUnit);
930 }
931 branch = opCompareBranch(cUnit, opc, reg, -1);
932 } else if (IS_SIMM16(checkValue)) {
933 if (cond == kMipsCondLt) {
934 int tReg = dvmCompilerAllocTemp(cUnit);
935 newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
936 branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
937 dvmCompilerFreeTemp(cUnit, tReg);
938 } else {
939 ALOGE("Jit: bad case in genRegImmCheck");
940 dvmCompilerAbort(cUnit);
941 }
942 } else {
943 ALOGE("Jit: bad case in genRegImmCheck");
944 dvmCompilerAbort(cUnit);
945 }
946
947 if (cUnit->jitMode == kJitMethod) {
948 BasicBlock *bb = cUnit->curBlock;
949 if (bb->taken) {
950 MipsLIR *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
951 exceptionLabel += bb->taken->id;
952 branch->generic.target = (LIR *) exceptionLabel;
953 return exceptionLabel;
954 } else {
955 ALOGE("Catch blocks not handled yet");
956 dvmAbort();
957 return NULL;
958 }
959 } else {
960 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
961 }
962 }
963
964 #if defined(WITH_SELF_VERIFICATION)
genSelfVerificationPreBranch(CompilationUnit * cUnit,MipsLIR * origLIR)965 static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
966 MipsLIR *origLIR) {
967 // DOUGLAS - this still needs to be implemented for MIPS.
968 #if 0
969 /*
970 * We need two separate pushes, since we want r5 to be pushed first.
971 * Store multiple will push LR first.
972 */
973 MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
974 pushFP->opcode = kThumbPush;
975 pushFP->operands[0] = 1 << r5FP;
976 setupResourceMasks(pushFP);
977 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
978
979 MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
980 pushLR->opcode = kThumbPush;
981 /* Thumb push can handle LR, but is encoded differently at bit 8 */
982 pushLR->operands[0] = 1 << 8;
983 setupResourceMasks(pushLR);
984 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
985 #endif
986 }
987
genSelfVerificationPostBranch(CompilationUnit * cUnit,MipsLIR * origLIR)988 static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
989 MipsLIR *origLIR) {
990 // DOUGLAS - this still needs to be implemented for MIPS.
991 #if 0
992 /*
993 * Since Thumb cannot pop memory content into LR, we have to pop LR
994 * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
995 * original r5 from stack.
996 */
997 /* Pop memory content(LR) into r5 first */
998 MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
999 popForLR->opcode = kThumbPop;
1000 popForLR->operands[0] = 1 << r5FP;
1001 setupResourceMasks(popForLR);
1002 dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
1003
1004 MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
1005 dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
1006
1007 /* Now restore the original r5 */
1008 MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
1009 popFP->opcode = kThumbPop;
1010 popFP->operands[0] = 1 << r5FP;
1011 setupResourceMasks(popFP);
1012 dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
1013 #endif
1014 }
1015 #endif
1016