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 */
dvmCompilerResetRegPool(CompilationUnit * cUnit)71 extern 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 */
dvmCompilerInitPool(RegisterInfo * regs,int * regNums,int num)83 extern 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
dumpRegPool(RegisterInfo * p,int numRegs)96 static 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
getRegInfo(CompilationUnit * cUnit,int reg)108 static 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
flushRegWide(CompilationUnit * cUnit,int reg1,int reg2)130 static 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
flushReg(CompilationUnit * cUnit,int reg)149 static 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 */
clobberRegBody(CompilationUnit * cUnit,RegisterInfo * p,int numTemps,int reg)161 static 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. */
dvmCompilerClobber(CompilationUnit * cUnit,int reg)190 void 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
clobberSRegBody(RegisterInfo * p,int numTemps,int sReg)199 static 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 */
dvmCompilerClobberSReg(CompilationUnit * cUnit,int sReg)212 extern 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
allocTempBody(CompilationUnit * cUnit,RegisterInfo * p,int numTemps,int * nextTemp,bool required)220 static 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.
dvmCompilerAllocTempDouble(CompilationUnit * cUnit)258 extern 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 */
dvmCompilerAllocFreeTemp(CompilationUnit * cUnit)306 extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit)
307 {
308 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
309 cUnit->regPool->numCoreTemps,
310 &cUnit->regPool->nextCoreTemp, true);
311 }
312
dvmCompilerAllocTemp(CompilationUnit * cUnit)313 extern int dvmCompilerAllocTemp(CompilationUnit *cUnit)
314 {
315 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
316 cUnit->regPool->numCoreTemps,
317 &cUnit->regPool->nextCoreTemp, true);
318 }
319
dvmCompilerAllocTempFloat(CompilationUnit * cUnit)320 extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit)
321 {
322 return allocTempBody(cUnit, cUnit->regPool->FPTemps,
323 cUnit->regPool->numFPTemps,
324 &cUnit->regPool->nextFPTemp, true);
325 }
326
allocLiveBody(RegisterInfo * p,int numTemps,int sReg)327 static 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
allocLive(CompilationUnit * cUnit,int sReg,int regClass)341 static 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
dvmCompilerFreeTemp(CompilationUnit * cUnit,int reg)367 extern 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 */
dvmCompilerIsLive(CompilationUnit * cUnit,int reg)396 extern 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
dvmCompilerIsTemp(CompilationUnit * cUnit,int reg)416 extern 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 */
dvmCompilerLockTemp(CompilationUnit * cUnit,int reg)441 extern 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 */
dvmCompilerClobberCallRegs(CompilationUnit * cUnit)467 extern 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. */
dvmCompilerClobberHandlerRegs(CompilationUnit * cUnit)480 extern 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
dvmCompilerResetDef(CompilationUnit * cUnit,int reg)491 extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg)
492 {
493 RegisterInfo *p = getRegInfo(cUnit, reg);
494 p->defStart = NULL;
495 p->defEnd = NULL;
496 }
497
nullifyRange(CompilationUnit * cUnit,LIR * start,LIR * finish,int sReg1,int sReg2)498 static 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 */
dvmCompilerMarkDef(CompilationUnit * cUnit,RegLocation rl,LIR * start,LIR * finish)517 extern 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 */
dvmCompilerMarkDefWide(CompilationUnit * cUnit,RegLocation rl,LIR * start,LIR * finish)533 extern 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
dvmCompilerWideToNarrow(CompilationUnit * cUnit,RegLocation rl)545 extern 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
dvmCompilerResetDefLoc(CompilationUnit * cUnit,RegLocation rl)577 extern 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
dvmCompilerResetDefLocWide(CompilationUnit * cUnit,RegLocation rl)589 extern 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
dvmCompilerResetDefTracking(CompilationUnit * cUnit)602 extern 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
dvmCompilerClobberAllRegs(CompilationUnit * cUnit)613 extern 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 */
dvmCompilerLockAllTemps(CompilationUnit * cUnit)625 extern 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
flushAllRegsBody(CompilationUnit * cUnit,RegisterInfo * info,int numRegs)634 static 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
dvmCompilerFlushAllRegs(CompilationUnit * cUnit)649 extern 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
regClassMatches(int regClass,int reg)660 static 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
dvmCompilerMarkLive(CompilationUnit * cUnit,int reg,int sReg)671 extern 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
dvmCompilerMarkPair(CompilationUnit * cUnit,int lowReg,int highReg)686 extern 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
dvmCompilerMarkClean(CompilationUnit * cUnit,int reg)695 extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
696 {
697 RegisterInfo *info = getRegInfo(cUnit, reg);
698 info->dirty = false;
699 }
700
dvmCompilerMarkDirty(CompilationUnit * cUnit,int reg)701 extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
702 {
703 RegisterInfo *info = getRegInfo(cUnit, reg);
704 info->dirty = true;
705 }
706
dvmCompilerMarkInUse(CompilationUnit * cUnit,int reg)707 extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
708 {
709 RegisterInfo *info = getRegInfo(cUnit, reg);
710 info->inUse = true;
711 }
712
copyRegInfo(CompilationUnit * cUnit,int newReg,int oldReg)713 void 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 */
dvmCompilerUpdateLoc(CompilationUnit * cUnit,RegLocation loc)730 extern 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 */
dvmCompilerUpdateLocWide(CompilationUnit * cUnit,RegLocation loc)750 extern 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
evalLocWide(CompilationUnit * cUnit,RegLocation loc,int regClass,bool update)800 static 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
dvmCompilerEvalLoc(CompilationUnit * cUnit,RegLocation loc,int regClass,bool update)851 extern 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
getDestSSAName(MIR * mir,int num)883 static 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.
dvmCompilerGetSrc(CompilationUnit * cUnit,MIR * mir,int num)890 extern 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.
dvmCompilerGetDest(CompilationUnit * cUnit,MIR * mir,int num)900 extern 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
getLocWide(CompilationUnit * cUnit,MIR * mir,int low,int high,bool isSrc)909 static 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
dvmCompilerGetDestWide(CompilationUnit * cUnit,MIR * mir,int low,int high)933 extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
934 int low, int high)
935 {
936 return getLocWide(cUnit, mir, low, high, false);
937 }
938
dvmCompilerGetSrcWide(CompilationUnit * cUnit,MIR * mir,int low,int high)939 extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
940 int low, int high)
941 {
942 return getLocWide(cUnit, mir, low, high, true);
943 }
944
dvmCompilerGetReturnWide(CompilationUnit * cUnit)945 extern 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
dvmCompilerGetReturnWideAlt(CompilationUnit * cUnit)956 extern 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
dvmCompilerGetReturn(CompilationUnit * cUnit)969 extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
970 {
971 RegLocation res = LOC_C_RETURN;
972 dvmCompilerClobber(cUnit, r0);
973 dvmCompilerMarkInUse(cUnit, r0);
974 return res;
975 }
976
dvmCompilerGetReturnAlt(CompilationUnit * cUnit)977 extern 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 */
dvmCompilerKillNullCheckedLoc(CompilationUnit * cUnit,RegLocation loc)987 extern 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
dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit * cUnit,int reg1,int reg2)1001 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
1002 int reg1, int reg2)
1003 {
1004 flushRegWide(cUnit, reg1, reg2);
1005 }
1006
dvmCompilerFlushRegForV5TEVFP(CompilationUnit * cUnit,int reg)1007 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
1008 {
1009 flushReg(cUnit, reg);
1010 }
1011