blob: b13dddfd741d26ad70b432bea71d103abd714aae [file] [log] [blame]
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains register alloction support and is intended to be
19 * included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25#include "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;
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -070076 ALOGE("================================================");
Raghu Gandhama8b91c52012-05-02 14:27:16 -070077 for (i=0; i < numRegs; i++ ){
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -070078 ALOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
Raghu Gandhama8b91c52012-05-02 14:27:16 -070079 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 }
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -070082 ALOGE("================================================");
Raghu Gandhama8b91c52012-05-02 14:27:16 -070083}
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 }
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700102 ALOGE("Tried to get info on a non-existant temp: r%d",reg);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700103 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) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700228 ALOGE("No free temp registers");
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700229 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 }
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700276 ALOGE("No free temp registers");
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700277 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:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700337 ALOGE("Invalid register type");
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700338 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 }
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700364 ALOGE("Tried to free a non-existant temp: r%d",reg);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700365 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 }
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700438 ALOGE("Tried to lock a non-existant temp: r%d",reg);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700439 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}