blob: a5a8d7edfe0b4159e65330ce2bf09e7d1bc7538e [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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 "../../compiler_internals.h"
18#include "mips_lir.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080019#include "../ralloc_util.h"
20#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080021
22#include <string>
23
24namespace art {
25
26static int coreRegs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
27 r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
28 r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
29 r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
30static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
31 r_RA};
32static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
33 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8};
34#ifdef __mips_hard_float
35static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
36 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
37static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
38 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
39#endif
40
41RegLocation locCReturn()
42{
43 RegLocation res = MIPS_LOC_C_RETURN;
44 return res;
45}
46
47RegLocation locCReturnWide()
48{
49 RegLocation res = MIPS_LOC_C_RETURN_WIDE;
50 return res;
51}
52
53RegLocation locCReturnFloat()
54{
55 RegLocation res = MIPS_LOC_C_RETURN_FLOAT;
56 return res;
57}
58
59RegLocation locCReturnDouble()
60{
61 RegLocation res = MIPS_LOC_C_RETURN_DOUBLE;
62 return res;
63}
64
65// Return a target-dependent special register.
66int targetReg(SpecialTargetRegister reg) {
67 int res = INVALID_REG;
68 switch (reg) {
69 case kSelf: res = rMIPS_SELF; break;
70 case kSuspend: res = rMIPS_SUSPEND; break;
71 case kLr: res = rMIPS_LR; break;
72 case kPc: res = rMIPS_PC; break;
73 case kSp: res = rMIPS_SP; break;
74 case kArg0: res = rMIPS_ARG0; break;
75 case kArg1: res = rMIPS_ARG1; break;
76 case kArg2: res = rMIPS_ARG2; break;
77 case kArg3: res = rMIPS_ARG3; break;
78 case kFArg0: res = rMIPS_FARG0; break;
79 case kFArg1: res = rMIPS_FARG1; break;
80 case kFArg2: res = rMIPS_FARG2; break;
81 case kFArg3: res = rMIPS_FARG3; break;
82 case kRet0: res = rMIPS_RET0; break;
83 case kRet1: res = rMIPS_RET1; break;
84 case kInvokeTgt: res = rMIPS_INVOKE_TGT; break;
85 case kCount: res = rMIPS_COUNT; break;
86 }
87 return res;
88}
89
90// Create a double from a pair of singles.
91int s2d(int lowReg, int highReg)
92{
93 return MIPS_S2D(lowReg, highReg);
94}
95
96// Is reg a single or double?
97bool fpReg(int reg)
98{
99 return MIPS_FPREG(reg);
100}
101
102// Is reg a single?
103bool singleReg(int reg)
104{
105 return MIPS_SINGLEREG(reg);
106}
107
108// Is reg a double?
109bool doubleReg(int reg)
110{
111 return MIPS_DOUBLEREG(reg);
112}
113
114// Return mask to strip off fp reg flags and bias.
115uint32_t fpRegMask()
116{
117 return MIPS_FP_REG_MASK;
118}
119
120// True if both regs single, both core or both double.
121bool sameRegType(int reg1, int reg2)
122{
123 return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
124}
125
126/*
127 * Decode the register id.
128 */
buzbeeeaf09bc2012-11-15 14:51:41 -0800129uint64_t getRegMaskCommon(CompilationUnit* cUnit, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800130{
buzbeeeaf09bc2012-11-15 14:51:41 -0800131 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800132 int shift;
133 int regId;
134
135
136 regId = reg & 0x1f;
137 /* Each double register is equal to a pair of single-precision FP registers */
138 seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
139 /* FP register starts at bit position 16 */
140 shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
141 /* Expand the double register id into single offset */
142 shift += regId;
143 return (seed << shift);
144}
145
146uint64_t getPCUseDefEncoding()
147{
148 return ENCODE_MIPS_REG_PC;
149}
150
151
152void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir)
153{
154 DCHECK_EQ(cUnit->instructionSet, kMips);
155
156 // Mips-specific resource map setup here.
157 uint64_t flags = EncodingMap[lir->opcode].flags;
158
159 if (flags & REG_DEF_SP) {
160 lir->defMask |= ENCODE_MIPS_REG_SP;
161 }
162
163 if (flags & REG_USE_SP) {
164 lir->useMask |= ENCODE_MIPS_REG_SP;
165 }
166
167 if (flags & REG_DEF_LR) {
168 lir->defMask |= ENCODE_MIPS_REG_LR;
169 }
170}
171
172/* For dumping instructions */
173#define MIPS_REG_COUNT 32
174static const char *mipsRegName[MIPS_REG_COUNT] = {
175 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
176 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
177 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
178 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
179};
180
181/*
182 * Interpret a format string and build a string no longer than size
183 * See format key in Assemble.c.
184 */
185std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr)
186{
187 std::string buf;
188 int i;
189 const char *fmtEnd = &fmt[strlen(fmt)];
190 char tbuf[256];
191 char nc;
192 while (fmt < fmtEnd) {
193 int operand;
194 if (*fmt == '!') {
195 fmt++;
196 DCHECK_LT(fmt, fmtEnd);
197 nc = *fmt++;
198 if (nc=='!') {
199 strcpy(tbuf, "!");
200 } else {
201 DCHECK_LT(fmt, fmtEnd);
202 DCHECK_LT((unsigned)(nc-'0'), 4u);
203 operand = lir->operands[nc-'0'];
204 switch (*fmt++) {
205 case 'b':
206 strcpy(tbuf,"0000");
207 for (i=3; i>= 0; i--) {
208 tbuf[i] += operand & 1;
209 operand >>= 1;
210 }
211 break;
212 case 's':
213 sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK);
214 break;
215 case 'S':
216 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
217 sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK);
218 break;
219 case 'h':
220 sprintf(tbuf,"%04x", operand);
221 break;
222 case 'M':
223 case 'd':
224 sprintf(tbuf,"%d", operand);
225 break;
226 case 'D':
227 sprintf(tbuf,"%d", operand+1);
228 break;
229 case 'E':
230 sprintf(tbuf,"%d", operand*4);
231 break;
232 case 'F':
233 sprintf(tbuf,"%d", operand*2);
234 break;
235 case 't':
236 sprintf(tbuf,"0x%08x (L%p)", (int) baseAddr + lir->offset + 4 +
237 (operand << 2), lir->target);
238 break;
239 case 'T':
240 sprintf(tbuf,"0x%08x", (int) (operand << 2));
241 break;
242 case 'u': {
243 int offset_1 = lir->operands[0];
244 int offset_2 = NEXT_LIR(lir)->operands[0];
245 intptr_t target =
246 ((((intptr_t) baseAddr + lir->offset + 4) & ~3) +
247 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
248 sprintf(tbuf, "%p", (void *) target);
249 break;
250 }
251
252 /* Nothing to print for BLX_2 */
253 case 'v':
254 strcpy(tbuf, "see above");
255 break;
256 case 'r':
257 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
258 strcpy(tbuf, mipsRegName[operand]);
259 break;
260 case 'N':
261 // Placeholder for delay slot handling
262 strcpy(tbuf, "; nop");
263 break;
264 default:
265 strcpy(tbuf,"DecodeError");
266 break;
267 }
268 buf += tbuf;
269 }
270 } else {
271 buf += *fmt++;
272 }
273 }
274 return buf;
275}
276
277// FIXME: need to redo resource maps for MIPS - fix this at that time
buzbeeeaf09bc2012-11-15 14:51:41 -0800278void oatDumpResourceMask(LIR *lir, uint64_t mask, const char *prefix)
buzbeeefc63692012-11-14 16:31:52 -0800279{
280 char buf[256];
281 buf[0] = 0;
282 LIR *mipsLIR = (LIR *) lir;
283
284 if (mask == ENCODE_ALL) {
285 strcpy(buf, "all");
286 } else {
287 char num[8];
288 int i;
289
290 for (i = 0; i < kMipsRegEnd; i++) {
291 if (mask & (1ULL << i)) {
292 sprintf(num, "%d ", i);
293 strcat(buf, num);
294 }
295 }
296
297 if (mask & ENCODE_CCODE) {
298 strcat(buf, "cc ");
299 }
300 if (mask & ENCODE_FP_STATUS) {
301 strcat(buf, "fpcc ");
302 }
303 /* Memory bits */
304 if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
305 sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
306 (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
307 }
308 if (mask & ENCODE_LITERAL) {
309 strcat(buf, "lit ");
310 }
311
312 if (mask & ENCODE_HEAP_REF) {
313 strcat(buf, "heap ");
314 }
315 if (mask & ENCODE_MUST_NOT_ALIAS) {
316 strcat(buf, "noalias ");
317 }
318 }
319 if (buf[0]) {
320 LOG(INFO) << prefix << ": " << buf;
321 }
322}
323
324/*
325 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
326 * instructions might call out to C/assembly helper functions. Until
327 * machinery is in place, always spill lr.
328 */
329
330void oatAdjustSpillMask(CompilationUnit* cUnit)
331{
332 cUnit->coreSpillMask |= (1 << r_RA);
333 cUnit->numCoreSpills++;
334}
335
336/*
337 * Mark a callee-save fp register as promoted. Note that
338 * vpush/vpop uses contiguous register lists so we must
339 * include any holes in the mask. Associate holes with
340 * Dalvik register INVALID_VREG (0xFFFFU).
341 */
342void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
343{
344 LOG(FATAL) << "No support yet for promoted FP regs";
345}
346
347void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
348{
349 RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
350 RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
351 DCHECK(info1 && info2 && info1->pair && info2->pair &&
352 (info1->partner == info2->reg) &&
353 (info2->partner == info1->reg));
354 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
355 if (!(info1->isTemp && info2->isTemp)) {
356 /* Should not happen. If it does, there's a problem in evalLoc */
357 LOG(FATAL) << "Long half-temp, half-promoted";
358 }
359
360 info1->dirty = false;
361 info2->dirty = false;
362 if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg))
363 info1 = info2;
364 int vReg = SRegToVReg(cUnit, info1->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800365 storeBaseDispWide(cUnit, rMIPS_SP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800366 }
367}
368
369void oatFlushReg(CompilationUnit* cUnit, int reg)
370{
371 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
372 if (info->live && info->dirty) {
373 info->dirty = false;
374 int vReg = SRegToVReg(cUnit, info->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800375 storeBaseDisp(cUnit, rMIPS_SP, oatVRegOffset(cUnit, vReg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800376 }
377}
378
379/* Give access to the target-dependent FP register encoding to common code */
380bool oatIsFpReg(int reg) {
381 return MIPS_FPREG(reg);
382}
383
384uint32_t oatFpRegMask() {
385 return MIPS_FP_REG_MASK;
386}
387
388/* Clobber all regs that might be used by an external C call */
389extern void oatClobberCalleeSave(CompilationUnit *cUnit)
390{
391 oatClobber(cUnit, r_ZERO);
392 oatClobber(cUnit, r_AT);
393 oatClobber(cUnit, r_V0);
394 oatClobber(cUnit, r_V1);
395 oatClobber(cUnit, r_A0);
396 oatClobber(cUnit, r_A1);
397 oatClobber(cUnit, r_A2);
398 oatClobber(cUnit, r_A3);
399 oatClobber(cUnit, r_T0);
400 oatClobber(cUnit, r_T1);
401 oatClobber(cUnit, r_T2);
402 oatClobber(cUnit, r_T3);
403 oatClobber(cUnit, r_T4);
404 oatClobber(cUnit, r_T5);
405 oatClobber(cUnit, r_T6);
406 oatClobber(cUnit, r_T7);
407 oatClobber(cUnit, r_T8);
408 oatClobber(cUnit, r_T9);
409 oatClobber(cUnit, r_K0);
410 oatClobber(cUnit, r_K1);
411 oatClobber(cUnit, r_GP);
412 oatClobber(cUnit, r_FP);
413 oatClobber(cUnit, r_RA);
414 oatClobber(cUnit, r_F0);
415 oatClobber(cUnit, r_F1);
416 oatClobber(cUnit, r_F2);
417 oatClobber(cUnit, r_F3);
418 oatClobber(cUnit, r_F4);
419 oatClobber(cUnit, r_F5);
420 oatClobber(cUnit, r_F6);
421 oatClobber(cUnit, r_F7);
422 oatClobber(cUnit, r_F8);
423 oatClobber(cUnit, r_F9);
424 oatClobber(cUnit, r_F10);
425 oatClobber(cUnit, r_F11);
426 oatClobber(cUnit, r_F12);
427 oatClobber(cUnit, r_F13);
428 oatClobber(cUnit, r_F14);
429 oatClobber(cUnit, r_F15);
430}
431
432extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
433{
434 UNIMPLEMENTED(FATAL) << "No oatGetReturnWideAlt for MIPS";
435 RegLocation res = locCReturnWide();
436 return res;
437}
438
439extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
440{
441 UNIMPLEMENTED(FATAL) << "No oatGetReturnAlt for MIPS";
442 RegLocation res = locCReturn();
443 return res;
444}
445
446extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
447{
448 return MIPS_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & MIPS_FP_REG_MASK]
449 : &cUnit->regPool->coreRegs[reg];
450}
451
452/* To be used when explicitly managing register use */
453extern void oatLockCallTemps(CompilationUnit* cUnit)
454{
455 oatLockTemp(cUnit, rMIPS_ARG0);
456 oatLockTemp(cUnit, rMIPS_ARG1);
457 oatLockTemp(cUnit, rMIPS_ARG2);
458 oatLockTemp(cUnit, rMIPS_ARG3);
459}
460
461/* To be used when explicitly managing register use */
462extern void oatFreeCallTemps(CompilationUnit* cUnit)
463{
464 oatFreeTemp(cUnit, rMIPS_ARG0);
465 oatFreeTemp(cUnit, rMIPS_ARG1);
466 oatFreeTemp(cUnit, rMIPS_ARG2);
467 oatFreeTemp(cUnit, rMIPS_ARG3);
468}
469
470/* Convert an instruction to a NOP */
471void oatNopLIR( LIR* lir)
472{
473 ((LIR*)lir)->flags.isNop = true;
474}
475
476/*
477 * Determine the initial instruction set to be used for this trace.
478 * Later components may decide to change this.
479 */
480InstructionSet oatInstructionSet()
481{
482 return kMips;
483}
484
485/* Architecture-specific initializations and checks go here */
486bool oatArchVariantInit(void)
487{
488 return true;
489}
490
buzbeeefc63692012-11-14 16:31:52 -0800491void oatGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
492{
493#if ANDROID_SMP != 0
494 newLIR1(cUnit, kMipsSync, barrierKind);
495#endif
496}
497
498/*
499 * Alloc a pair of core registers, or a double. Low reg in low byte,
500 * high reg in next byte.
501 */
502int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
503 int regClass)
504{
505 int highReg;
506 int lowReg;
507 int res = 0;
508
509#ifdef __mips_hard_float
510 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
511 lowReg = oatAllocTempDouble(cUnit);
512 highReg = lowReg + 1;
513 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
514 return res;
515 }
516#endif
517
518 lowReg = oatAllocTemp(cUnit);
519 highReg = oatAllocTemp(cUnit);
520 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
521 return res;
522}
523
524int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
525{
526#ifdef __mips_hard_float
527 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
528{
529 return oatAllocTempFloat(cUnit);
530}
531#endif
532 return oatAllocTemp(cUnit);
533}
534
535void oatInitializeRegAlloc(CompilationUnit* cUnit)
536{
537 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
538 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
539 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
540#ifdef __mips_hard_float
541 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
542 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
543#else
544 int numFPRegs = 0;
545 int numFPTemps = 0;
546#endif
547 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
548 kAllocRegAlloc);
549 cUnit->regPool = pool;
550 pool->numCoreRegs = numRegs;
551 pool->coreRegs = (RegisterInfo *)
552 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
553 true, kAllocRegAlloc);
554 pool->numFPRegs = numFPRegs;
555 pool->FPRegs = (RegisterInfo *)
556 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
557 kAllocRegAlloc);
558 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
559 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
560 // Keep special registers from being allocated
561 for (int i = 0; i < numReserved; i++) {
562 if (NO_SUSPEND && (reservedRegs[i] == rMIPS_SUSPEND)) {
563 //To measure cost of suspend check
564 continue;
565 }
566 oatMarkInUse(cUnit, reservedRegs[i]);
567 }
568 // Mark temp regs - all others not in use can be used for promotion
569 for (int i = 0; i < numTemps; i++) {
570 oatMarkTemp(cUnit, coreTemps[i]);
571 }
572 for (int i = 0; i < numFPTemps; i++) {
573 oatMarkTemp(cUnit, fpTemps[i]);
574 }
575 // Construct the alias map.
576 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
577 sizeof(cUnit->phiAliasMap[0]), false,
578 kAllocDFInfo);
579 for (int i = 0; i < cUnit->numSSARegs; i++) {
580 cUnit->phiAliasMap[i] = i;
581 }
582 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
583 int defReg = phi->ssaRep->defs[0];
584 for (int i = 0; i < phi->ssaRep->numUses; i++) {
585 for (int j = 0; j < cUnit->numSSARegs; j++) {
586 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
587 cUnit->phiAliasMap[j] = defReg;
588 }
589 }
590 }
591 }
592}
593
594void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
595 RegLocation rlFree)
596{
597 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
598 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
599 // No overlap, free both
600 oatFreeTemp(cUnit, rlFree.lowReg);
601 oatFreeTemp(cUnit, rlFree.highReg);
602 }
603}
604/*
605 * In the Arm code a it is typical to use the link register
606 * to hold the target address. However, for Mips we must
607 * ensure that all branch instructions can be restarted if
608 * there is a trap in the shadow. Allocate a temp register.
609 */
610int loadHelper(CompilationUnit* cUnit, int offset)
611{
612 loadWordDisp(cUnit, rMIPS_SELF, offset, r_T9);
613 return r_T9;
614}
615
616void spillCoreRegs(CompilationUnit* cUnit)
617{
618 if (cUnit->numCoreSpills == 0) {
619 return;
620 }
621 uint32_t mask = cUnit->coreSpillMask;
622 int offset = cUnit->numCoreSpills * 4;
623 opRegImm(cUnit, kOpSub, rMIPS_SP, offset);
624 for (int reg = 0; mask; mask >>= 1, reg++) {
625 if (mask & 0x1) {
626 offset -= 4;
627 storeWordDisp(cUnit, rMIPS_SP, offset, reg);
628 }
629 }
630}
631
632void unSpillCoreRegs(CompilationUnit* cUnit)
633{
634 if (cUnit->numCoreSpills == 0) {
635 return;
636 }
637 uint32_t mask = cUnit->coreSpillMask;
638 int offset = cUnit->frameSize;
639 for (int reg = 0; mask; mask >>= 1, reg++) {
640 if (mask & 0x1) {
641 offset -= 4;
642 loadWordDisp(cUnit, rMIPS_SP, offset, reg);
643 }
644 }
645 opRegImm(cUnit, kOpAdd, rMIPS_SP, cUnit->frameSize);
646}
647
648/*
649 * Nop any unconditional branches that go to the next instruction.
650 * Note: new redundant branches may be inserted later, and we'll
651 * use a check in final instruction assembly to nop those out.
652 */
653void removeRedundantBranches(CompilationUnit* cUnit)
654{
655 LIR* thisLIR;
656
657 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
658 thisLIR != (LIR*) cUnit->lastLIRInsn;
659 thisLIR = NEXT_LIR(thisLIR)) {
660
661 /* Branch to the next instruction */
662 if (thisLIR->opcode == kMipsB) {
663 LIR* nextLIR = thisLIR;
664
665 while (true) {
666 nextLIR = NEXT_LIR(nextLIR);
667
668 /*
669 * Is the branch target the next instruction?
670 */
671 if (nextLIR == (LIR*) thisLIR->target) {
672 thisLIR->flags.isNop = true;
673 break;
674 }
675
676 /*
677 * Found real useful stuff between the branch and the target.
678 * Need to explicitly check the lastLIRInsn here because it
679 * might be the last real instruction.
680 */
681 if (!isPseudoOpcode(nextLIR->opcode) ||
682 (nextLIR = (LIR*) cUnit->lastLIRInsn))
683 break;
684 }
685 }
686 }
687}
688
689
690/* Common initialization routine for an architecture family */
691bool oatArchInit()
692{
693 int i;
694
695 for (i = 0; i < kMipsLast; i++) {
696 if (EncodingMap[i].opcode != i) {
697 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
698 " is wrong: expecting " << i << ", seeing " <<
699 (int)EncodingMap[i].opcode;
700 }
701 }
702
703 return oatArchVariantInit();
704}
705
706} // namespace art