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