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