blob: 8aa5fc71fdb29481340e3662327785dc1d4cdf2d [file] [log] [blame]
Bill Buzbee1465db52009-09-23 17:17:35 -07001/*
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 register alloction support and is intended to be
19 * included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25#include "Codegen.h"
26#include "../../Dataflow.h"
27
28/*
29 * Register usage for 16-bit Thumb systems:
30 * r0-r3: Temp/argument
31 * lr(r14): Temp for translations, return address for handlers
32 * rGLUE(r6): Pointer to InterpState
33 * rFP(r5): Dalvik frame pointer
34 * r4, r7: Temp for translations
35 * r8, r9, r10: Temp preserved across C calls
36 * r11, ip(r12): Temp not preserved across C calls
37 *
38 * Register usage for 32-bit Thumb systems:
39 * r0-r3: Temp/argument
40 * lr(r14): Temp for translations, return address for handlers
41 * rGLUE(r6): Pointer to InterpState
42 * rFP(r5): Dalvik frame pointer
43 * r4, r7: Temp for translations
44 * r8, r9, r10 Temp preserved across C calls
45 * r11, ip(r12): Temp not preserved across C calls
46 * fp0-fp15: Hot temps, not preserved across C calls
47 * fp16-fp31: Promotion pool
48 *
49 */
50
51static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
52 int displacement, int rSrc, OpSize size);
53static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
54 int displacement, int rSrcLo, int rSrcHi);
55static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
56 int regClass);
57static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass);
58void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
59 int srcLo, int srcHi);
60static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
61static void clobberReg(CompilationUnit *cUnit, int reg);
62static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg);
63
64#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
65/*
66 * Get the "real" sreg number associated with an sReg slot. In general,
67 * sReg values passed through codegen are the SSA names created by
68 * dataflow analysis and refer to slot numbers in the cUnit->regLocation
69 * array. However, renaming is accomplished by simply replacing RegLocation
70 * entries in the cUnit->reglocation[] array. Therefore, when location
71 * records for operands are first created, we need to ask the locRecord
72 * identified by the dataflow pass what it's new name is.
73 */
74
75static inline int hiSReg(int lowSreg) {
76 return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
77}
78
79static int sReg2vReg(CompilationUnit *cUnit, int sReg)
80{
81 assert(sReg != INVALID_SREG);
82 return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
83}
84
85static bool liveOut(CompilationUnit *cUnit, int sReg)
86{
87 //TODO: fully implement
88 return true;
89}
90
91/*
92 * Free all allocated temps in the temp pools. Note that this does
93 * not affect the "liveness" of a temp register, which will stay
94 * live until it is either explicitly killed or reallocated.
95 */
96static void resetRegPool(CompilationUnit *cUnit)
97{
98 int i;
99 for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
100 cUnit->regPool->coreTemps[i].inUse = false;
101 }
102 for (i=0; i < cUnit->regPool->numFPTemps; i++) {
103 cUnit->regPool->FPTemps[i].inUse = false;
104 }
105}
106
107 /* Set up temp & preserved register pools specialized by target */
108static void initPool(RegisterInfo *regs, int *regNums, int num)
109{
110 int i;
111 for (i=0; i < num; i++) {
112 regs[i].reg = regNums[i];
113 regs[i].inUse = false;
114 regs[i].pair = false;
115 regs[i].live = false;
116 regs[i].dirty = false;
117 regs[i].sReg = INVALID_SREG;
118 }
119}
120
121static void dumpRegPool(RegisterInfo *p, int numRegs)
122{
123 int i;
124 LOGE("================================================");
125 for (i=0; i < numRegs; i++ ){
126 LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
127 p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
128 p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
129 }
130 LOGE("================================================");
131}
132
133static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
134 bool required)
135{
136 int i;
137 //Tuning: redo this to widen the live window on freed temps
138 for (i=0; i< numTemps; i++) {
139 if (!p[i].inUse && !p[i].live) {
140 clobberReg(cUnit, p[i].reg);
141 p[i].inUse = true;
142 p[i].pair = false;
143 return p[i].reg;
144 }
145 }
146 for (i=0; i< numTemps; i++) {
147 if (!p[i].inUse) {
148 clobberReg(cUnit, p[i].reg);
149 p[i].inUse = true;
150 p[i].pair = false;
151 return p[i].reg;
152 }
153 }
154 if (required) {
155 LOGE("No free temp registers");
156 assert(0);
157 }
158 return -1; // No register available
159}
160
161//REDO: too many assumptions.
162static int allocTempDouble(CompilationUnit *cUnit)
163{
164 RegisterInfo *p = cUnit->regPool->FPTemps;
165 int numTemps = cUnit->regPool->numFPTemps;
166 int i;
167
168 for (i=0; i < numTemps; i+=2) {
169 if ((!p[i].inUse && !p[i].live) &&
170 (!p[i+1].inUse && !p[i+1].live)) {
171 clobberReg(cUnit, p[i].reg);
172 clobberReg(cUnit, p[i+1].reg);
173 p[i].inUse = true;
174 p[i+1].inUse = true;
175 assert((p[i].reg+1) == p[i+1].reg);
176 assert((p[i].reg & 0x1) == 0);
177 return p[i].reg;
178 }
179 }
180 for (i=0; i < numTemps; i+=2) {
181 if (!p[i].inUse && !p[i+1].inUse) {
182 clobberReg(cUnit, p[i].reg);
183 clobberReg(cUnit, p[i+1].reg);
184 p[i].inUse = true;
185 p[i+1].inUse = true;
186 assert((p[i].reg+1) == p[i+1].reg);
187 assert((p[i].reg & 0x1) == 0);
188 return p[i].reg;
189 }
190 }
191 LOGE("No free temp registers");
192 *((int*)0) = 0; //For development, die instantly. Later abort translation
193 dvmAbort();
194 return -1;
195}
196
197/* Return a temp if one is available, -1 otherwise */
198static int allocFreeTemp(CompilationUnit *cUnit)
199{
200 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
201 cUnit->regPool->numCoreTemps, true);
202}
203
204static int allocTemp(CompilationUnit *cUnit)
205{
206 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
207 cUnit->regPool->numCoreTemps, true);
208}
209
210static int allocTempFloat(CompilationUnit *cUnit)
211{
212 return allocTempBody(cUnit, cUnit->regPool->FPTemps,
213 cUnit->regPool->numFPTemps, true);
214}
215
216static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
217{
218 int i;
219 if (sReg == -1)
220 return NULL;
221 for (i=0; i < numTemps; i++) {
222 if (p[i].live && (p[i].sReg == sReg)) {
223 p[i].inUse = true;
224 return &p[i];
225 }
226 }
227 return NULL;
228}
229
230static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
231 int regClass)
232{
233 RegisterInfo *res = NULL;
234 switch(regClass) {
235 case kAnyReg:
236 res = allocLiveBody(cUnit->regPool->FPTemps,
237 cUnit->regPool->numFPTemps, sReg);
238 if (res)
239 break;
240 /* Intentional fallthrough */
241 case kCoreReg:
242 res = allocLiveBody(cUnit->regPool->coreTemps,
243 cUnit->regPool->numCoreTemps, sReg);
244 break;
245 case kFPReg:
246 res = allocLiveBody(cUnit->regPool->FPTemps,
247 cUnit->regPool->numFPTemps, sReg);
248 break;
249 default:
250 LOGE("Invalid register type");
251 assert(0);
252 dvmAbort();
253 }
254 return res;
255}
256
257static void freeTemp(CompilationUnit *cUnit, int reg)
258{
259 RegisterInfo *p = cUnit->regPool->coreTemps;
260 int numTemps = cUnit->regPool->numCoreTemps;
261 int i;
262 for (i=0; i< numTemps; i++) {
263 if (p[i].reg == reg) {
264 p[i].inUse = false;
265 p[i].pair = false;
266 return;
267 }
268 }
269 p = cUnit->regPool->FPTemps;
270 numTemps = cUnit->regPool->numFPTemps;
271 for (i=0; i< numTemps; i++) {
272 if (p[i].reg == reg) {
273 p[i].inUse = false;
274 p[i].pair = false;
275 return;
276 }
277 }
278 LOGE("Tried to free a non-existant temp: r%d",reg);
279 dvmAbort();
280}
281
282//FIXME - this needs to also check the preserved pool.
283static RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
284{
285 RegisterInfo *p = cUnit->regPool->coreTemps;
286 int numTemps = cUnit->regPool->numCoreTemps;
287 int i;
288 for (i=0; i< numTemps; i++) {
289 if (p[i].reg == reg) {
290 return p[i].live ? &p[i] : NULL;
291 }
292 }
293 p = cUnit->regPool->FPTemps;
294 numTemps = cUnit->regPool->numFPTemps;
295 for (i=0; i< numTemps; i++) {
296 if (p[i].reg == reg) {
297 return p[i].live ? &p[i] : NULL;
298 }
299 }
300 return NULL;
301}
302
303static RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
304{
305 RegisterInfo *p = cUnit->regPool->coreTemps;
306 int numTemps = cUnit->regPool->numCoreTemps;
307 int i;
308 for (i=0; i< numTemps; i++) {
309 if (p[i].reg == reg) {
310 return &p[i];
311 }
312 }
313 p = cUnit->regPool->FPTemps;
314 numTemps = cUnit->regPool->numFPTemps;
315 for (i=0; i< numTemps; i++) {
316 if (p[i].reg == reg) {
317 return &p[i];
318 }
319 }
320 return NULL;
321}
322
323static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
324{
325 RegisterInfo *info1 = getRegInfo(cUnit, reg1);
326 RegisterInfo *info2 = getRegInfo(cUnit, reg2);
327 assert(info1 && info2 && info1->pair && info2->pair &&
328 (info1->partner == info2->reg) &&
329 (info2->partner == info1->reg));
330 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
331 info1->dirty = false;
332 info2->dirty = false;
333 if (sReg2vReg(cUnit, info2->sReg) < sReg2vReg(cUnit, info1->sReg))
334 info1 = info2;
335 storeBaseDispWide(cUnit, rFP, sReg2vReg(cUnit, info1->sReg) << 2,
336 info1->reg, info1->partner);
337 }
338}
339
340static void flushReg(CompilationUnit *cUnit, int reg)
341{
342 RegisterInfo *info = getRegInfo(cUnit, reg);
343 if (info->live && info->dirty) {
344 info->dirty = false;
345 storeBaseDisp(cUnit, rFP, sReg2vReg(cUnit, info->sReg) << 2, reg,
346 kWord);
347 }
348}
349
350/* return true if found reg to clobber */
351static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
352 int numTemps, int reg)
353{
354 int i;
355 for (i=0; i< numTemps; i++) {
356 if (p[i].reg == reg) {
357 if (p[i].live && p[i].dirty) {
358 if (p[i].pair) {
359 flushRegWide(cUnit, p[i].reg, p[i].partner);
360 } else {
361 flushReg(cUnit, p[i].reg);
362 }
363 }
364 p[i].live = false;
365 p[i].sReg = INVALID_SREG;
366 p[i].defStart = NULL;
367 p[i].defEnd = NULL;
368 if (p[i].pair) {
369 p[i].pair = false;
370 clobberReg(cUnit, p[i].partner);
371 }
372 return true;
373 }
374 }
375 return false;
376}
377
378/* Mark a temp register as dead. Does not affect allocation state. */
379static void clobberReg(CompilationUnit *cUnit, int reg)
380{
381 if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
382 cUnit->regPool->numCoreTemps, reg)) {
383 clobberRegBody(cUnit, cUnit->regPool->FPTemps,
384 cUnit->regPool->numFPTemps, reg);
385 }
386}
387
388static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
389{
390 int i;
391 for (i=0; i< numTemps; i++) {
392 if (p[i].sReg == sReg) {
393 p[i].live = false;
394 p[i].defStart = NULL;
395 p[i].defEnd = NULL;
396 }
397 }
398}
399
400/* Clobber any temp associated with an sReg. Could be in either class */
401static void clobberSReg(CompilationUnit *cUnit, int sReg)
402{
403 clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
404 sReg);
405 clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
406 sReg);
407}
408
409static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
410{
411 int numTemps = cUnit->regPool->numCoreTemps;
412 RegisterInfo *p = cUnit->regPool->coreTemps;
413 int i;
414 for (i=0; i< numTemps; i++) {
415 if (p[i].reg == reg) {
416 return &p[i];
417 }
418 }
419 p = cUnit->regPool->FPTemps;
420 numTemps = cUnit->regPool->numFPTemps;
421 for (i=0; i< numTemps; i++) {
422 if (p[i].reg == reg) {
423 return &p[i];
424 }
425 }
426 LOGE("Tried to get info on a non-existant temp: r%d",reg);
427 dvmAbort();
428 return NULL;
429}
430
431/*
432 * Similar to allocTemp(), but forces the allocation of a specific
433 * register. No check is made to see if the register was previously
434 * allocated. Use with caution.
435 */
436static void lockTemp(CompilationUnit *cUnit, int reg)
437{
438 RegisterInfo *p = cUnit->regPool->coreTemps;
439 int numTemps = cUnit->regPool->numCoreTemps;
440 int i;
441 for (i=0; i< numTemps; i++) {
442 if (p[i].reg == reg) {
443 p[i].inUse = true;
444 p[i].live = false;
445 return;
446 }
447 }
448 p = cUnit->regPool->FPTemps;
449 numTemps = cUnit->regPool->numFPTemps;
450 for (i=0; i< numTemps; i++) {
451 if (p[i].reg == reg) {
452 p[i].inUse = true;
453 p[i].live = false;
454 return;
455 }
456 }
457 LOGE("Tried to lock a non-existant temp: r%d",reg);
458 dvmAbort();
459}
460
461static void lockArgRegs(CompilationUnit *cUnit)
462{
463 lockTemp(cUnit, r0);
464 lockTemp(cUnit, r1);
465 lockTemp(cUnit, r2);
466 lockTemp(cUnit, r3);
467}
468
469/* Clobber all regs that might be used by an external C call */
470static void clobberCallRegs(CompilationUnit *cUnit)
471{
472 clobberReg(cUnit, r0);
473 clobberReg(cUnit, r1);
474 clobberReg(cUnit, r2);
475 clobberReg(cUnit, r3);
476 clobberReg(cUnit, r9); // Not sure we need to do this, be convervative
477 clobberReg(cUnit, r11);
478 clobberReg(cUnit, r12);
479 clobberReg(cUnit, rlr);
480}
481
482/* Clobber all of the temps that might be used by a handler. */
483static void clobberHandlerRegs(CompilationUnit *cUnit)
484{
485 //TUNING: reduce the set of regs used by handlers. Only a few need lots.
486 clobberCallRegs(cUnit);
487 clobberReg(cUnit, r9);
488 clobberReg(cUnit, r10);
489}
490
491static void resetDef(CompilationUnit *cUnit, int reg)
492{
493 RegisterInfo *p = getRegInfo(cUnit, reg);
494 p->defStart = NULL;
495 p->defEnd = NULL;
496}
497
498static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
499 int sReg1, int sReg2)
500{
501 if (start && finish) {
502 LIR *p;
503 assert(sReg1 == sReg2);
504 for (p = start; ;p = p->next) {
505 ((ArmLIR *)p)->isNop = true;
506 if (p == finish)
507 break;
508 }
509 }
510}
511
512/*
513 * Mark the beginning and end LIR of a def sequence. Note that
514 * on entry start points to the LIR prior to the beginning of the
515 * sequence.
516 */
517static void markDef(CompilationUnit *cUnit, RegLocation rl,
518 LIR *start, LIR *finish)
519{
520 assert(!rl.wide);
521 assert(start && start->next);
522 assert(finish);
523 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
524 p->defStart = start->next;
525 p->defEnd = finish;
526}
527
528/*
529 * Mark the beginning and end LIR of a def sequence. Note that
530 * on entry start points to the LIR prior to the beginning of the
531 * sequence.
532 */
533static void markDefWide(CompilationUnit *cUnit, RegLocation rl,
534 LIR *start, LIR *finish)
535{
536 assert(rl.wide);
537 assert(start && start->next);
538 assert(finish);
539 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
540 resetDef(cUnit, rl.highReg); // Only track low of pair
541 p->defStart = start->next;
542 p->defEnd = finish;
543}
544
545static RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
546{
547 assert(rl.wide);
548 if (rl.location == kLocPhysReg) {
549 RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
550 RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
551 if (!infoLo->pair) {
552 dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
553 assert(infoLo->pair);
554 }
555 if (!infoHi->pair) {
556 dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
557 assert(infoHi->pair);
558 }
559 assert(infoLo->pair);
560 assert(infoHi->pair);
561 assert(infoLo->partner == infoHi->reg);
562 assert(infoHi->partner == infoLo->reg);
563 infoLo->pair = false;
564 infoHi->pair = false;
565 infoLo->defStart = NULL;
566 infoLo->defEnd = NULL;
567 infoHi->defStart = NULL;
568 infoHi->defEnd = NULL;
569 }
570 rl.wide = false;
571 return rl;
572}
573
574static void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
575{
576 assert(!rl.wide);
577 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
578 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
579 assert(!p->pair);
580 nullifyRange(cUnit, p->defStart, p->defEnd,
581 p->sReg, rl.sRegLow);
582 }
583 resetDef(cUnit, rl.lowReg);
584}
585
586static void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
587{
588 assert(rl.wide);
589 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
590 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
591 assert(p->pair);
592 nullifyRange(cUnit, p->defStart, p->defEnd,
593 p->sReg, rl.sRegLow);
594 }
595 resetDef(cUnit, rl.lowReg);
596 resetDef(cUnit, rl.highReg);
597}
598
599static void resetDefTracking(CompilationUnit *cUnit)
600{
601 int i;
602 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
603 resetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
604 }
605 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
606 resetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
607 }
608}
609
610static void clobberAllRegs(CompilationUnit *cUnit)
611{
612 int i;
613 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
614 clobberReg(cUnit, cUnit->regPool->coreTemps[i].reg);
615 }
616 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
617 clobberReg(cUnit, cUnit->regPool->FPTemps[i].reg);
618 }
619}
620
621/* To be used when explicitly managing register use */
622static void lockAllTemps(CompilationUnit *cUnit)
623{
624 int i;
625 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
626 lockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
627 }
628}
629
630// Make sure nothing is live and dirty
631static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
632 int numRegs)
633{
634 int i;
635 for (i=0; i < numRegs; i++) {
636 if (info[i].live && info[i].dirty) {
637 if (info[i].pair) {
638 flushRegWide(cUnit, info[i].reg, info[i].partner);
639 } else {
640 flushReg(cUnit, info[i].reg);
641 }
642 }
643 }
644}
645
646static void flushAllRegs(CompilationUnit *cUnit)
647{
648 flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
649 cUnit->regPool->numCoreTemps);
650 flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
651 cUnit->regPool->numFPTemps);
652 clobberAllRegs(cUnit);
653}
654
655
656//TUNING: rewrite all of this reg stuff. Probably use an attribute table
657static bool regClassMatches(int regClass, int reg)
658{
659 if (regClass == kAnyReg) {
660 return true;
661 } else if (regClass == kCoreReg) {
662 return !FPREG(reg);
663 } else {
664 return FPREG(reg);
665 }
666}
667
668static void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
669{
670 RegisterInfo *info = getRegInfo(cUnit, reg);
671 if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
672 return; /* already live */
673 } else if (sReg != INVALID_SREG) {
674 clobberSReg(cUnit, sReg);
675 info->live = true;
676 } else {
677 /* Can't be live if no associated sReg */
678 info->live = false;
679 }
680 info->sReg = sReg;
681}
682
683static void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
684{
685 RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
686 RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
687 infoLo->pair = infoHi->pair = true;
688 infoLo->partner = highReg;
689 infoHi->partner = lowReg;
690}
691
692static void markRegSingle(CompilationUnit *cUnit, int reg)
693{
694 RegisterInfo *info = getRegInfo(cUnit, reg);
695 info->pair = false;
696}
697
698static void markRegClean(CompilationUnit *cUnit, int reg)
699{
700 RegisterInfo *info = getRegInfo(cUnit, reg);
701 info->dirty = false;
702}
703
704static void markRegDirty(CompilationUnit *cUnit, int reg)
705{
706 RegisterInfo *info = getRegInfo(cUnit, reg);
707 info->dirty = true;
708}
709
710static void markRegInUse(CompilationUnit *cUnit, int reg)
711{
712 RegisterInfo *info = getRegInfo(cUnit, reg);
713 info->inUse = true;
714}
715
716/* Return true if live & dirty */
717static bool isDirty(CompilationUnit *cUnit, int reg)
718{
719 RegisterInfo *info = getRegInfo(cUnit, reg);
720 return (info && info->live && info->dirty);
721}
722
723void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
724{
725 RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
726 RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
727 *newInfo = *oldInfo;
728 newInfo->reg = newReg;
729}
730
731/*
732 * Return an updated location record with current in-register status.
733 * If the value lives in live temps, reflect that fact. No code
734 * is generated. The the live value is part of an older pair,
735 * clobber both low and high.
736 * TUNING: clobbering both is a bit heavy-handed, but the alternative
737 * is a bit complex when dealing with FP regs. Examine code to see
738 * if it's worthwhile trying to be more clever here.
739 */
740static RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
741{
742 assert(!loc.wide);
743 if (loc.location == kLocDalvikFrame) {
744 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
745 if (infoLo) {
746 if (infoLo->pair) {
747 clobberReg(cUnit, infoLo->reg);
748 clobberReg(cUnit, infoLo->partner);
749 } else {
750 loc.lowReg = infoLo->reg;
751 loc.location = kLocPhysReg;
752 }
753 }
754 }
755
756 return loc;
757}
758
759/* see comments for updateLoc */
760static RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
761{
762 assert(loc.wide);
763 if (loc.location == kLocDalvikFrame) {
764 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
765 RegisterInfo *infoHi = allocLive(cUnit, hiSReg(loc.sRegLow), kAnyReg);
766 bool match = true;
767 match = match && (infoLo != NULL);
768 match = match && (infoHi != NULL);
769 match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
770 if (match && FPREG(infoLo->reg)) {
771 match &= ((infoLo->reg & 0x1) == 0);
772 match &= ((infoHi->reg - infoLo->reg) == 1);
773 }
774 if (match) {
775 loc.lowReg = infoLo->reg;
776 loc.highReg = infoHi->reg;
777 loc.location = kLocPhysReg;
778 markRegPair(cUnit, loc.lowReg, loc.highReg);
779 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
780 return loc;
781 }
782 /* Can't easily reuse - just clobber any overlaps */
783 if (infoLo) {
784 clobberReg(cUnit, infoLo->reg);
785 if (infoLo->pair)
786 clobberReg(cUnit, infoLo->partner);
787 }
788 if (infoHi) {
789 clobberReg(cUnit, infoHi->reg);
790 if (infoHi->pair)
791 clobberReg(cUnit, infoHi->partner);
792 }
793 }
794
795 return loc;
796}
797
798static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
799 int regClass, bool update)
800{
801 assert(loc.wide);
802 int newRegs;
803 int lowReg;
804 int highReg;
805
806 loc = updateLocWide(cUnit, loc);
807
808 /* If already in registers, we can assume proper form. Right reg class? */
809 if (loc.location == kLocPhysReg) {
810 assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
811 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
812 if (!regClassMatches(regClass, loc.lowReg)) {
813 /* Wrong register class. Reallocate and copy */
814 newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
815 lowReg = newRegs & 0xff;
816 highReg = (newRegs >> 8) & 0xff;
817 genRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
818 loc.highReg);
819 copyRegInfo(cUnit, lowReg, loc.lowReg);
820 copyRegInfo(cUnit, highReg, loc.highReg);
821 clobberReg(cUnit, loc.lowReg);
822 clobberReg(cUnit, loc.highReg);
823 loc.lowReg = lowReg;
824 loc.highReg = highReg;
825 markRegPair(cUnit, loc.lowReg, loc.highReg);
826 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
827 }
828 return loc;
829 }
830
831 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
832 assert((loc.location != kLocRetval) || (hiSReg(loc.sRegLow) == INVALID_SREG));
833
834 newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
835 loc.lowReg = newRegs & 0xff;
836 loc.highReg = (newRegs >> 8) & 0xff;
837
838 markRegPair(cUnit, loc.lowReg, loc.highReg);
839 if (update) {
840 loc.location = kLocPhysReg;
841 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
842 markRegLive(cUnit, loc.highReg, hiSReg(loc.sRegLow));
843 }
844 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
845 return loc;
846}
847
848static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
849 int regClass, bool update)
850{
851 RegisterInfo *infoLo = NULL;
852 int newReg;
853 if (loc.wide)
854 return evalLocWide(cUnit, loc, regClass, update);
855 loc = updateLoc(cUnit, loc);
856
857 if (loc.location == kLocPhysReg) {
858 if (!regClassMatches(regClass, loc.lowReg)) {
859 /* Wrong register class. Realloc, copy and transfer ownership */
860 newReg = allocTypedTemp(cUnit, loc.fp, regClass);
861 genRegCopy(cUnit, newReg, loc.lowReg);
862 copyRegInfo(cUnit, newReg, loc.lowReg);
863 clobberReg(cUnit, loc.lowReg);
864 loc.lowReg = newReg;
865 }
866 return loc;
867 }
868
869 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
870
871 newReg = allocTypedTemp(cUnit, loc.fp, regClass);
872 loc.lowReg = newReg;
873
874 if (update) {
875 loc.location = kLocPhysReg;
876 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
877 }
878 return loc;
879}
880
881static inline int getSrcSSAName(MIR *mir, int num)
882{
883 assert(mir->ssaRep->numUses > num);
884 return mir->ssaRep->uses[num];
885}
886
887static inline int getDestSSAName(MIR *mir, int num)
888{
889 assert(mir->ssaRep->numDefs > num);
890 return mir->ssaRep->defs[num];
891}
892
893// Get the LocRecord associated with an SSA name use.
894static inline RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
895{
896 RegLocation loc = cUnit->regLocation[SREG(cUnit, getSrcSSAName(mir, num))];
897 loc.fp = cUnit->regLocation[getSrcSSAName(mir, num)].fp;
898 loc.wide = false;
899 return loc;
900}
901
902// Get the LocRecord associated with an SSA name def.
903static inline RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
904{
905 RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
906 loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
907 loc.wide = false;
908 return loc;
909}
910
911static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
912 int low, int high, bool isSrc)
913{
914 RegLocation lowLoc;
915 RegLocation highLoc;
916 /* Copy loc record for low word and patch in data from high word */
917 if (isSrc) {
918 lowLoc = getSrcLoc(cUnit, mir, low);
919 highLoc = getSrcLoc(cUnit, mir, high);
920 } else {
921 lowLoc = getDestLoc(cUnit, mir, low);
922 highLoc = getDestLoc(cUnit, mir, high);
923 }
924 /* Avoid this case by either promoting both or neither. */
925 assert(lowLoc.location == highLoc.location);
926 if (lowLoc.location == kLocPhysReg) {
927 /* This case shouldn't happen if we've named correctly */
928 assert(lowLoc.fp == highLoc.fp);
929 }
930 lowLoc.wide = true;
931 lowLoc.highReg = highLoc.lowReg;
932 return lowLoc;
933}
934static RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
935 int low, int high)
936{
937 return getLocWide(cUnit, mir, low, high, false);
938}
939
940static RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
941 int low, int high)
942{
943 return getLocWide(cUnit, mir, low, high, true);
944}
945
946/* Reset the tracker to unknown state */
947static inline void resetNullCheckTracker(CompilationUnit *cUnit)
948{
949 dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
950}
951
952static RegLocation getReturnLocWide(CompilationUnit *cUnit)
953{
954 RegLocation res = LOC_C_RETURN_WIDE;
955 clobberReg(cUnit, r0);
956 clobberReg(cUnit, r1);
957 markRegInUse(cUnit, r0);
958 markRegInUse(cUnit, r1);
959 markRegPair(cUnit, res.lowReg, res.highReg);
960 return res;
961}
962
963static RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
964{
965 RegLocation res = LOC_C_RETURN_WIDE;
966 res.lowReg = r2;
967 res.highReg = r3;
968 clobberReg(cUnit, r2);
969 clobberReg(cUnit, r3);
970 markRegInUse(cUnit, r2);
971 markRegInUse(cUnit, r3);
972 markRegPair(cUnit, res.lowReg, res.highReg);
973 return res;
974}
975
976static RegLocation getReturnLoc(CompilationUnit *cUnit)
977{
978 RegLocation res = LOC_C_RETURN;
979 clobberReg(cUnit, r0);
980 markRegInUse(cUnit, r0);
981 return res;
982}
983
984static RegLocation getReturnLocAlt(CompilationUnit *cUnit)
985{
986 RegLocation res = LOC_C_RETURN;
987 res.lowReg = r1;
988 clobberReg(cUnit, r1);
989 markRegInUse(cUnit, r1);
990 return res;
991}
992
993/* Kill the corresponding bit in the null-checked register list */
994static inline void killNullCheckedLocation(CompilationUnit *cUnit,
995 RegLocation loc)
996{
997 if (loc.location != kLocRetval) {
998 assert(loc.sRegLow != INVALID_SREG);
999 dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
1000 if (loc.wide) {
1001 assert(hiSReg(loc.sRegLow) != INVALID_SREG);
1002 dvmClearBit(cUnit->regPool->nullCheckedRegs, hiSReg(loc.sRegLow));
1003 }
1004 }
1005}