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