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