blob: ff7700260c42096cf69d2db07c41ecb5bd5889be [file] [log] [blame]
Bill Buzbee1465db52009-09-23 17:17:35 -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
Ben Cheng5d90c202009-11-22 23:31:11 -080025#include "compiler/CompilerUtility.h"
26#include "compiler/CompilerIR.h"
27#include "compiler/Dataflow.h"
28#include "ArmLIR.h"
Bill Buzbee1465db52009-09-23 17:17:35 -070029#include "Codegen.h"
Ben Cheng5d90c202009-11-22 23:31:11 -080030#include "Ralloc.h"
31
32/*
33 * FIXME - dvmCompiler prefixes are not added yet to routines exposed to the
34 * code generator.
35 */
Bill Buzbee1465db52009-09-23 17:17:35 -070036
37/*
38 * Register usage for 16-bit Thumb systems:
39 * r0-r3: Temp/argument
40 * lr(r14): Temp for translations, return address for handlers
41 * rGLUE(r6): Pointer to InterpState
42 * rFP(r5): Dalvik frame pointer
43 * r4, r7: Temp for translations
44 * r8, r9, r10: Temp preserved across C calls
45 * r11, ip(r12): Temp not preserved across C calls
46 *
47 * Register usage for 32-bit Thumb systems:
48 * r0-r3: Temp/argument
49 * lr(r14): Temp for translations, return address for handlers
50 * rGLUE(r6): Pointer to InterpState
51 * rFP(r5): Dalvik frame pointer
52 * r4, r7: Temp for translations
53 * r8, r9, r10 Temp preserved across C calls
54 * r11, ip(r12): Temp not preserved across C calls
55 * fp0-fp15: Hot temps, not preserved across C calls
56 * fp16-fp31: Promotion pool
57 *
58 */
59
Bill Buzbee1465db52009-09-23 17:17:35 -070060#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
61/*
62 * Get the "real" sreg number associated with an sReg slot. In general,
63 * sReg values passed through codegen are the SSA names created by
64 * dataflow analysis and refer to slot numbers in the cUnit->regLocation
65 * array. However, renaming is accomplished by simply replacing RegLocation
66 * entries in the cUnit->reglocation[] array. Therefore, when location
67 * records for operands are first created, we need to ask the locRecord
68 * identified by the dataflow pass what it's new name is.
69 */
70
Bill Buzbee1465db52009-09-23 17:17:35 -070071/*
72 * Free all allocated temps in the temp pools. Note that this does
73 * not affect the "liveness" of a temp register, which will stay
74 * live until it is either explicitly killed or reallocated.
75 */
Ben Cheng5d90c202009-11-22 23:31:11 -080076extern void resetRegPool(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -070077{
78 int i;
79 for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
80 cUnit->regPool->coreTemps[i].inUse = false;
81 }
82 for (i=0; i < cUnit->regPool->numFPTemps; i++) {
83 cUnit->regPool->FPTemps[i].inUse = false;
84 }
85}
86
87 /* Set up temp & preserved register pools specialized by target */
Ben Cheng5d90c202009-11-22 23:31:11 -080088extern void initPool(RegisterInfo *regs, int *regNums, int num)
Bill Buzbee1465db52009-09-23 17:17:35 -070089{
90 int i;
91 for (i=0; i < num; i++) {
92 regs[i].reg = regNums[i];
93 regs[i].inUse = false;
94 regs[i].pair = false;
95 regs[i].live = false;
96 regs[i].dirty = false;
97 regs[i].sReg = INVALID_SREG;
98 }
99}
100
101static void dumpRegPool(RegisterInfo *p, int numRegs)
102{
103 int i;
104 LOGE("================================================");
105 for (i=0; i < numRegs; i++ ){
106 LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
107 p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
108 p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
109 }
110 LOGE("================================================");
111}
112
Ben Cheng5d90c202009-11-22 23:31:11 -0800113static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
114{
115 int numTemps = cUnit->regPool->numCoreTemps;
116 RegisterInfo *p = cUnit->regPool->coreTemps;
117 int i;
118 for (i=0; i< numTemps; i++) {
119 if (p[i].reg == reg) {
120 return &p[i];
121 }
122 }
123 p = cUnit->regPool->FPTemps;
124 numTemps = cUnit->regPool->numFPTemps;
125 for (i=0; i< numTemps; i++) {
126 if (p[i].reg == reg) {
127 return &p[i];
128 }
129 }
130 LOGE("Tried to get info on a non-existant temp: r%d",reg);
131 dvmAbort();
132 return NULL;
133}
134
135static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
136{
137 RegisterInfo *info1 = getRegInfo(cUnit, reg1);
138 RegisterInfo *info2 = getRegInfo(cUnit, reg2);
139 assert(info1 && info2 && info1->pair && info2->pair &&
140 (info1->partner == info2->reg) &&
141 (info2->partner == info1->reg));
142 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
143 info1->dirty = false;
144 info2->dirty = false;
145 if (sReg2vReg(cUnit, info2->sReg) < sReg2vReg(cUnit, info1->sReg))
146 info1 = info2;
147 dvmCompilerFlushRegWideImpl(cUnit, rFP,
148 sReg2vReg(cUnit, info1->sReg) << 2,
149 info1->reg, info1->partner);
150 }
151}
152
153static void flushReg(CompilationUnit *cUnit, int reg)
154{
155 RegisterInfo *info = getRegInfo(cUnit, reg);
156 if (info->live && info->dirty) {
157 info->dirty = false;
158 dvmCompilerFlushRegImpl(cUnit, rFP, sReg2vReg(cUnit, info->sReg) << 2,
159 reg, kWord);
160 }
161}
162
163/* return true if found reg to clobber */
164static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
165 int numTemps, int reg)
166{
167 int i;
168 for (i=0; i< numTemps; i++) {
169 if (p[i].reg == reg) {
170 if (p[i].live && p[i].dirty) {
171 if (p[i].pair) {
172 flushRegWide(cUnit, p[i].reg, p[i].partner);
173 } else {
174 flushReg(cUnit, p[i].reg);
175 }
176 }
177 p[i].live = false;
178 p[i].sReg = INVALID_SREG;
179 p[i].defStart = NULL;
180 p[i].defEnd = NULL;
181 if (p[i].pair) {
182 p[i].pair = false;
183 /* partners should be in same pool */
184 clobberRegBody(cUnit, p, numTemps, p[i].partner);
185 }
186 return true;
187 }
188 }
189 return false;
190}
191
192/* Mark a temp register as dead. Does not affect allocation state. */
193void clobberReg(CompilationUnit *cUnit, int reg)
194{
195 if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
196 cUnit->regPool->numCoreTemps, reg)) {
197 clobberRegBody(cUnit, cUnit->regPool->FPTemps,
198 cUnit->regPool->numFPTemps, reg);
199 }
200}
201
202static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
203{
204 int i;
205 for (i=0; i< numTemps; i++) {
206 if (p[i].sReg == sReg) {
207 p[i].live = false;
208 p[i].defStart = NULL;
209 p[i].defEnd = NULL;
210 }
211 }
212}
213
214/* Clobber any temp associated with an sReg. Could be in either class */
215extern void clobberSReg(CompilationUnit *cUnit, int sReg)
216{
217 clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
218 sReg);
219 clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
220 sReg);
221}
222
Bill Buzbee1465db52009-09-23 17:17:35 -0700223static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
224 bool required)
225{
226 int i;
227 //Tuning: redo this to widen the live window on freed temps
228 for (i=0; i< numTemps; i++) {
229 if (!p[i].inUse && !p[i].live) {
230 clobberReg(cUnit, p[i].reg);
231 p[i].inUse = true;
232 p[i].pair = false;
233 return p[i].reg;
234 }
235 }
236 for (i=0; i< numTemps; i++) {
237 if (!p[i].inUse) {
238 clobberReg(cUnit, p[i].reg);
239 p[i].inUse = true;
240 p[i].pair = false;
241 return p[i].reg;
242 }
243 }
244 if (required) {
245 LOGE("No free temp registers");
246 assert(0);
247 }
248 return -1; // No register available
249}
250
251//REDO: too many assumptions.
Ben Cheng5d90c202009-11-22 23:31:11 -0800252extern int allocTempDouble(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700253{
254 RegisterInfo *p = cUnit->regPool->FPTemps;
255 int numTemps = cUnit->regPool->numFPTemps;
256 int i;
257
258 for (i=0; i < numTemps; i+=2) {
259 if ((!p[i].inUse && !p[i].live) &&
260 (!p[i+1].inUse && !p[i+1].live)) {
261 clobberReg(cUnit, p[i].reg);
262 clobberReg(cUnit, p[i+1].reg);
263 p[i].inUse = true;
264 p[i+1].inUse = true;
265 assert((p[i].reg+1) == p[i+1].reg);
266 assert((p[i].reg & 0x1) == 0);
267 return p[i].reg;
268 }
269 }
270 for (i=0; i < numTemps; i+=2) {
271 if (!p[i].inUse && !p[i+1].inUse) {
272 clobberReg(cUnit, p[i].reg);
273 clobberReg(cUnit, p[i+1].reg);
274 p[i].inUse = true;
275 p[i+1].inUse = true;
276 assert((p[i].reg+1) == p[i+1].reg);
277 assert((p[i].reg & 0x1) == 0);
278 return p[i].reg;
279 }
280 }
281 LOGE("No free temp registers");
282 *((int*)0) = 0; //For development, die instantly. Later abort translation
283 dvmAbort();
284 return -1;
285}
286
287/* Return a temp if one is available, -1 otherwise */
Ben Cheng5d90c202009-11-22 23:31:11 -0800288extern int allocFreeTemp(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700289{
290 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
291 cUnit->regPool->numCoreTemps, true);
292}
293
Ben Cheng5d90c202009-11-22 23:31:11 -0800294extern int allocTemp(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700295{
296 return allocTempBody(cUnit, cUnit->regPool->coreTemps,
297 cUnit->regPool->numCoreTemps, true);
298}
299
Ben Cheng5d90c202009-11-22 23:31:11 -0800300extern int allocTempFloat(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700301{
302 return allocTempBody(cUnit, cUnit->regPool->FPTemps,
303 cUnit->regPool->numFPTemps, true);
304}
305
306static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
307{
308 int i;
309 if (sReg == -1)
310 return NULL;
311 for (i=0; i < numTemps; i++) {
312 if (p[i].live && (p[i].sReg == sReg)) {
313 p[i].inUse = true;
314 return &p[i];
315 }
316 }
317 return NULL;
318}
319
320static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
321 int regClass)
322{
323 RegisterInfo *res = NULL;
324 switch(regClass) {
325 case kAnyReg:
326 res = allocLiveBody(cUnit->regPool->FPTemps,
327 cUnit->regPool->numFPTemps, sReg);
328 if (res)
329 break;
330 /* Intentional fallthrough */
331 case kCoreReg:
332 res = allocLiveBody(cUnit->regPool->coreTemps,
333 cUnit->regPool->numCoreTemps, sReg);
334 break;
335 case kFPReg:
336 res = allocLiveBody(cUnit->regPool->FPTemps,
337 cUnit->regPool->numFPTemps, sReg);
338 break;
339 default:
340 LOGE("Invalid register type");
341 assert(0);
342 dvmAbort();
343 }
344 return res;
345}
346
Ben Cheng5d90c202009-11-22 23:31:11 -0800347extern void freeTemp(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700348{
349 RegisterInfo *p = cUnit->regPool->coreTemps;
350 int numTemps = cUnit->regPool->numCoreTemps;
351 int i;
352 for (i=0; i< numTemps; i++) {
353 if (p[i].reg == reg) {
354 p[i].inUse = false;
355 p[i].pair = false;
356 return;
357 }
358 }
359 p = cUnit->regPool->FPTemps;
360 numTemps = cUnit->regPool->numFPTemps;
361 for (i=0; i< numTemps; i++) {
362 if (p[i].reg == reg) {
363 p[i].inUse = false;
364 p[i].pair = false;
365 return;
366 }
367 }
368 LOGE("Tried to free a non-existant temp: r%d",reg);
369 dvmAbort();
370}
371
372//FIXME - this needs to also check the preserved pool.
Ben Cheng5d90c202009-11-22 23:31:11 -0800373extern RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700374{
375 RegisterInfo *p = cUnit->regPool->coreTemps;
376 int numTemps = cUnit->regPool->numCoreTemps;
377 int i;
378 for (i=0; i< numTemps; i++) {
379 if (p[i].reg == reg) {
380 return p[i].live ? &p[i] : NULL;
381 }
382 }
383 p = cUnit->regPool->FPTemps;
384 numTemps = cUnit->regPool->numFPTemps;
385 for (i=0; i< numTemps; i++) {
386 if (p[i].reg == reg) {
387 return p[i].live ? &p[i] : NULL;
388 }
389 }
390 return NULL;
391}
392
Ben Cheng5d90c202009-11-22 23:31:11 -0800393extern RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700394{
395 RegisterInfo *p = cUnit->regPool->coreTemps;
396 int numTemps = cUnit->regPool->numCoreTemps;
397 int i;
398 for (i=0; i< numTemps; i++) {
399 if (p[i].reg == reg) {
400 return &p[i];
401 }
402 }
403 p = cUnit->regPool->FPTemps;
404 numTemps = cUnit->regPool->numFPTemps;
405 for (i=0; i< numTemps; i++) {
406 if (p[i].reg == reg) {
407 return &p[i];
408 }
409 }
410 return NULL;
411}
412
Bill Buzbee1465db52009-09-23 17:17:35 -0700413/*
414 * Similar to allocTemp(), but forces the allocation of a specific
415 * register. No check is made to see if the register was previously
416 * allocated. Use with caution.
417 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800418extern void lockTemp(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700419{
420 RegisterInfo *p = cUnit->regPool->coreTemps;
421 int numTemps = cUnit->regPool->numCoreTemps;
422 int i;
423 for (i=0; i< numTemps; i++) {
424 if (p[i].reg == reg) {
425 p[i].inUse = true;
426 p[i].live = false;
427 return;
428 }
429 }
430 p = cUnit->regPool->FPTemps;
431 numTemps = cUnit->regPool->numFPTemps;
432 for (i=0; i< numTemps; i++) {
433 if (p[i].reg == reg) {
434 p[i].inUse = true;
435 p[i].live = false;
436 return;
437 }
438 }
439 LOGE("Tried to lock a non-existant temp: r%d",reg);
440 dvmAbort();
441}
442
443static void lockArgRegs(CompilationUnit *cUnit)
444{
445 lockTemp(cUnit, r0);
446 lockTemp(cUnit, r1);
447 lockTemp(cUnit, r2);
448 lockTemp(cUnit, r3);
449}
450
451/* Clobber all regs that might be used by an external C call */
Ben Cheng5d90c202009-11-22 23:31:11 -0800452extern void clobberCallRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700453{
454 clobberReg(cUnit, r0);
455 clobberReg(cUnit, r1);
456 clobberReg(cUnit, r2);
457 clobberReg(cUnit, r3);
458 clobberReg(cUnit, r9); // Not sure we need to do this, be convervative
459 clobberReg(cUnit, r11);
460 clobberReg(cUnit, r12);
461 clobberReg(cUnit, rlr);
462}
463
464/* Clobber all of the temps that might be used by a handler. */
Ben Cheng5d90c202009-11-22 23:31:11 -0800465extern void clobberHandlerRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700466{
467 //TUNING: reduce the set of regs used by handlers. Only a few need lots.
468 clobberCallRegs(cUnit);
469 clobberReg(cUnit, r9);
470 clobberReg(cUnit, r10);
471}
472
Ben Cheng5d90c202009-11-22 23:31:11 -0800473extern void resetDef(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700474{
475 RegisterInfo *p = getRegInfo(cUnit, reg);
476 p->defStart = NULL;
477 p->defEnd = NULL;
478}
479
480static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
481 int sReg1, int sReg2)
482{
483 if (start && finish) {
484 LIR *p;
485 assert(sReg1 == sReg2);
486 for (p = start; ;p = p->next) {
487 ((ArmLIR *)p)->isNop = true;
488 if (p == finish)
489 break;
490 }
491 }
492}
493
494/*
495 * Mark the beginning and end LIR of a def sequence. Note that
496 * on entry start points to the LIR prior to the beginning of the
497 * sequence.
498 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800499extern void markDef(CompilationUnit *cUnit, RegLocation rl,
Bill Buzbee1465db52009-09-23 17:17:35 -0700500 LIR *start, LIR *finish)
501{
502 assert(!rl.wide);
503 assert(start && start->next);
504 assert(finish);
505 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
506 p->defStart = start->next;
507 p->defEnd = finish;
508}
509
510/*
511 * Mark the beginning and end LIR of a def sequence. Note that
512 * on entry start points to the LIR prior to the beginning of the
513 * sequence.
514 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800515extern void markDefWide(CompilationUnit *cUnit, RegLocation rl,
Bill Buzbee1465db52009-09-23 17:17:35 -0700516 LIR *start, LIR *finish)
517{
518 assert(rl.wide);
519 assert(start && start->next);
520 assert(finish);
521 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
522 resetDef(cUnit, rl.highReg); // Only track low of pair
523 p->defStart = start->next;
524 p->defEnd = finish;
525}
526
Ben Cheng5d90c202009-11-22 23:31:11 -0800527extern RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700528{
529 assert(rl.wide);
530 if (rl.location == kLocPhysReg) {
531 RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
532 RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
533 if (!infoLo->pair) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800534 dumpRegPool(cUnit->regPool->coreTemps,
535 cUnit->regPool->numCoreTemps);
Bill Buzbee1465db52009-09-23 17:17:35 -0700536 assert(infoLo->pair);
537 }
538 if (!infoHi->pair) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800539 dumpRegPool(cUnit->regPool->coreTemps,
540 cUnit->regPool->numCoreTemps);
Bill Buzbee1465db52009-09-23 17:17:35 -0700541 assert(infoHi->pair);
542 }
543 assert(infoLo->pair);
544 assert(infoHi->pair);
545 assert(infoLo->partner == infoHi->reg);
546 assert(infoHi->partner == infoLo->reg);
547 infoLo->pair = false;
548 infoHi->pair = false;
549 infoLo->defStart = NULL;
550 infoLo->defEnd = NULL;
551 infoHi->defStart = NULL;
552 infoHi->defEnd = NULL;
553 }
554 rl.wide = false;
555 return rl;
556}
557
Ben Cheng5d90c202009-11-22 23:31:11 -0800558extern void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700559{
560 assert(!rl.wide);
561 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
562 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
563 assert(!p->pair);
564 nullifyRange(cUnit, p->defStart, p->defEnd,
565 p->sReg, rl.sRegLow);
566 }
567 resetDef(cUnit, rl.lowReg);
568}
569
Ben Cheng5d90c202009-11-22 23:31:11 -0800570extern void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700571{
572 assert(rl.wide);
573 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
574 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
575 assert(p->pair);
576 nullifyRange(cUnit, p->defStart, p->defEnd,
577 p->sReg, rl.sRegLow);
578 }
579 resetDef(cUnit, rl.lowReg);
580 resetDef(cUnit, rl.highReg);
581}
582
Ben Cheng5d90c202009-11-22 23:31:11 -0800583extern void resetDefTracking(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700584{
585 int i;
586 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
587 resetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
588 }
589 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
590 resetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
591 }
592}
593
Ben Cheng5d90c202009-11-22 23:31:11 -0800594extern void clobberAllRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700595{
596 int i;
597 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
598 clobberReg(cUnit, cUnit->regPool->coreTemps[i].reg);
599 }
600 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
601 clobberReg(cUnit, cUnit->regPool->FPTemps[i].reg);
602 }
603}
604
605/* To be used when explicitly managing register use */
Ben Cheng5d90c202009-11-22 23:31:11 -0800606extern void lockAllTemps(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700607{
608 int i;
609 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
610 lockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
611 }
612}
613
614// Make sure nothing is live and dirty
615static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
616 int numRegs)
617{
618 int i;
619 for (i=0; i < numRegs; i++) {
620 if (info[i].live && info[i].dirty) {
621 if (info[i].pair) {
622 flushRegWide(cUnit, info[i].reg, info[i].partner);
623 } else {
624 flushReg(cUnit, info[i].reg);
625 }
626 }
627 }
628}
629
Ben Cheng5d90c202009-11-22 23:31:11 -0800630extern void flushAllRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700631{
632 flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
633 cUnit->regPool->numCoreTemps);
634 flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
635 cUnit->regPool->numFPTemps);
636 clobberAllRegs(cUnit);
637}
638
639
640//TUNING: rewrite all of this reg stuff. Probably use an attribute table
641static bool regClassMatches(int regClass, int reg)
642{
643 if (regClass == kAnyReg) {
644 return true;
645 } else if (regClass == kCoreReg) {
646 return !FPREG(reg);
647 } else {
648 return FPREG(reg);
649 }
650}
651
Ben Cheng5d90c202009-11-22 23:31:11 -0800652extern void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700653{
654 RegisterInfo *info = getRegInfo(cUnit, reg);
655 if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
656 return; /* already live */
657 } else if (sReg != INVALID_SREG) {
658 clobberSReg(cUnit, sReg);
659 info->live = true;
660 } else {
661 /* Can't be live if no associated sReg */
662 info->live = false;
663 }
664 info->sReg = sReg;
665}
666
Ben Cheng5d90c202009-11-22 23:31:11 -0800667extern void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700668{
669 RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
670 RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
671 infoLo->pair = infoHi->pair = true;
672 infoLo->partner = highReg;
673 infoHi->partner = lowReg;
674}
675
676static void markRegSingle(CompilationUnit *cUnit, int reg)
677{
678 RegisterInfo *info = getRegInfo(cUnit, reg);
679 info->pair = false;
680}
681
Ben Cheng5d90c202009-11-22 23:31:11 -0800682extern void markRegClean(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700683{
684 RegisterInfo *info = getRegInfo(cUnit, reg);
685 info->dirty = false;
686}
687
Ben Cheng5d90c202009-11-22 23:31:11 -0800688extern void markRegDirty(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700689{
690 RegisterInfo *info = getRegInfo(cUnit, reg);
691 info->dirty = true;
692}
693
Ben Cheng5d90c202009-11-22 23:31:11 -0800694extern void markRegInUse(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700695{
Ben Cheng5d90c202009-11-22 23:31:11 -0800696 RegisterInfo *info = getRegInfo(cUnit, reg);
697 info->inUse = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700698}
699
700/* Return true if live & dirty */
701static bool isDirty(CompilationUnit *cUnit, int reg)
702{
703 RegisterInfo *info = getRegInfo(cUnit, reg);
704 return (info && info->live && info->dirty);
705}
706
707void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
708{
709 RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
710 RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
711 *newInfo = *oldInfo;
712 newInfo->reg = newReg;
713}
714
715/*
716 * Return an updated location record with current in-register status.
717 * If the value lives in live temps, reflect that fact. No code
718 * is generated. The the live value is part of an older pair,
719 * clobber both low and high.
720 * TUNING: clobbering both is a bit heavy-handed, but the alternative
721 * is a bit complex when dealing with FP regs. Examine code to see
722 * if it's worthwhile trying to be more clever here.
723 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800724extern RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
Bill Buzbee1465db52009-09-23 17:17:35 -0700725{
726 assert(!loc.wide);
727 if (loc.location == kLocDalvikFrame) {
728 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
729 if (infoLo) {
730 if (infoLo->pair) {
731 clobberReg(cUnit, infoLo->reg);
732 clobberReg(cUnit, infoLo->partner);
733 } else {
734 loc.lowReg = infoLo->reg;
735 loc.location = kLocPhysReg;
736 }
737 }
738 }
739
740 return loc;
741}
742
743/* see comments for updateLoc */
Ben Cheng5d90c202009-11-22 23:31:11 -0800744extern RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
Bill Buzbee1465db52009-09-23 17:17:35 -0700745{
746 assert(loc.wide);
747 if (loc.location == kLocDalvikFrame) {
748 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
749 RegisterInfo *infoHi = allocLive(cUnit, hiSReg(loc.sRegLow), kAnyReg);
750 bool match = true;
751 match = match && (infoLo != NULL);
752 match = match && (infoHi != NULL);
753 match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
754 if (match && FPREG(infoLo->reg)) {
755 match &= ((infoLo->reg & 0x1) == 0);
756 match &= ((infoHi->reg - infoLo->reg) == 1);
757 }
758 if (match) {
759 loc.lowReg = infoLo->reg;
760 loc.highReg = infoHi->reg;
761 loc.location = kLocPhysReg;
762 markRegPair(cUnit, loc.lowReg, loc.highReg);
763 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
764 return loc;
765 }
766 /* Can't easily reuse - just clobber any overlaps */
767 if (infoLo) {
768 clobberReg(cUnit, infoLo->reg);
769 if (infoLo->pair)
770 clobberReg(cUnit, infoLo->partner);
771 }
772 if (infoHi) {
773 clobberReg(cUnit, infoHi->reg);
774 if (infoHi->pair)
775 clobberReg(cUnit, infoHi->partner);
776 }
777 }
778
779 return loc;
780}
781
782static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
783 int regClass, bool update)
784{
785 assert(loc.wide);
786 int newRegs;
787 int lowReg;
788 int highReg;
789
790 loc = updateLocWide(cUnit, loc);
791
792 /* If already in registers, we can assume proper form. Right reg class? */
793 if (loc.location == kLocPhysReg) {
794 assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
795 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
796 if (!regClassMatches(regClass, loc.lowReg)) {
797 /* Wrong register class. Reallocate and copy */
Ben Cheng5d90c202009-11-22 23:31:11 -0800798 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700799 lowReg = newRegs & 0xff;
800 highReg = (newRegs >> 8) & 0xff;
Ben Cheng5d90c202009-11-22 23:31:11 -0800801 dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
802 loc.highReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700803 copyRegInfo(cUnit, lowReg, loc.lowReg);
804 copyRegInfo(cUnit, highReg, loc.highReg);
805 clobberReg(cUnit, loc.lowReg);
806 clobberReg(cUnit, loc.highReg);
807 loc.lowReg = lowReg;
808 loc.highReg = highReg;
809 markRegPair(cUnit, loc.lowReg, loc.highReg);
810 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
811 }
812 return loc;
813 }
814
815 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
Ben Cheng5d90c202009-11-22 23:31:11 -0800816 assert((loc.location != kLocRetval) ||
817 (hiSReg(loc.sRegLow) == INVALID_SREG));
Bill Buzbee1465db52009-09-23 17:17:35 -0700818
Ben Cheng5d90c202009-11-22 23:31:11 -0800819 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700820 loc.lowReg = newRegs & 0xff;
821 loc.highReg = (newRegs >> 8) & 0xff;
822
823 markRegPair(cUnit, loc.lowReg, loc.highReg);
824 if (update) {
825 loc.location = kLocPhysReg;
826 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
827 markRegLive(cUnit, loc.highReg, hiSReg(loc.sRegLow));
828 }
829 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
830 return loc;
831}
832
Ben Cheng5d90c202009-11-22 23:31:11 -0800833extern RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
Bill Buzbee1465db52009-09-23 17:17:35 -0700834 int regClass, bool update)
835{
836 RegisterInfo *infoLo = NULL;
837 int newReg;
838 if (loc.wide)
839 return evalLocWide(cUnit, loc, regClass, update);
840 loc = updateLoc(cUnit, loc);
841
842 if (loc.location == kLocPhysReg) {
843 if (!regClassMatches(regClass, loc.lowReg)) {
844 /* Wrong register class. Realloc, copy and transfer ownership */
Ben Cheng5d90c202009-11-22 23:31:11 -0800845 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
846 dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700847 copyRegInfo(cUnit, newReg, loc.lowReg);
848 clobberReg(cUnit, loc.lowReg);
849 loc.lowReg = newReg;
850 }
851 return loc;
852 }
853
854 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
855
Ben Cheng5d90c202009-11-22 23:31:11 -0800856 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700857 loc.lowReg = newReg;
858
859 if (update) {
860 loc.location = kLocPhysReg;
861 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
862 }
863 return loc;
864}
865
Bill Buzbee1465db52009-09-23 17:17:35 -0700866static inline int getDestSSAName(MIR *mir, int num)
867{
868 assert(mir->ssaRep->numDefs > num);
869 return mir->ssaRep->defs[num];
870}
871
872// Get the LocRecord associated with an SSA name use.
Ben Cheng5d90c202009-11-22 23:31:11 -0800873extern RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
Bill Buzbee1465db52009-09-23 17:17:35 -0700874{
875 RegLocation loc = cUnit->regLocation[SREG(cUnit, getSrcSSAName(mir, num))];
876 loc.fp = cUnit->regLocation[getSrcSSAName(mir, num)].fp;
877 loc.wide = false;
878 return loc;
879}
880
881// Get the LocRecord associated with an SSA name def.
Ben Cheng5d90c202009-11-22 23:31:11 -0800882extern RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
Bill Buzbee1465db52009-09-23 17:17:35 -0700883{
884 RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
885 loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
886 loc.wide = false;
887 return loc;
888}
889
890static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
891 int low, int high, bool isSrc)
892{
893 RegLocation lowLoc;
894 RegLocation highLoc;
895 /* Copy loc record for low word and patch in data from high word */
896 if (isSrc) {
897 lowLoc = getSrcLoc(cUnit, mir, low);
898 highLoc = getSrcLoc(cUnit, mir, high);
899 } else {
900 lowLoc = getDestLoc(cUnit, mir, low);
901 highLoc = getDestLoc(cUnit, mir, high);
902 }
903 /* Avoid this case by either promoting both or neither. */
904 assert(lowLoc.location == highLoc.location);
905 if (lowLoc.location == kLocPhysReg) {
906 /* This case shouldn't happen if we've named correctly */
907 assert(lowLoc.fp == highLoc.fp);
908 }
909 lowLoc.wide = true;
910 lowLoc.highReg = highLoc.lowReg;
911 return lowLoc;
912}
Ben Cheng5d90c202009-11-22 23:31:11 -0800913
914extern RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee1465db52009-09-23 17:17:35 -0700915 int low, int high)
916{
917 return getLocWide(cUnit, mir, low, high, false);
918}
919
Ben Cheng5d90c202009-11-22 23:31:11 -0800920extern RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee1465db52009-09-23 17:17:35 -0700921 int low, int high)
922{
923 return getLocWide(cUnit, mir, low, high, true);
924}
925
Ben Cheng5d90c202009-11-22 23:31:11 -0800926extern RegLocation getReturnLocWide(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700927{
928 RegLocation res = LOC_C_RETURN_WIDE;
929 clobberReg(cUnit, r0);
930 clobberReg(cUnit, r1);
931 markRegInUse(cUnit, r0);
932 markRegInUse(cUnit, r1);
933 markRegPair(cUnit, res.lowReg, res.highReg);
934 return res;
935}
936
Ben Cheng5d90c202009-11-22 23:31:11 -0800937extern RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700938{
939 RegLocation res = LOC_C_RETURN_WIDE;
940 res.lowReg = r2;
941 res.highReg = r3;
942 clobberReg(cUnit, r2);
943 clobberReg(cUnit, r3);
944 markRegInUse(cUnit, r2);
945 markRegInUse(cUnit, r3);
946 markRegPair(cUnit, res.lowReg, res.highReg);
947 return res;
948}
949
Ben Cheng5d90c202009-11-22 23:31:11 -0800950extern RegLocation getReturnLoc(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700951{
952 RegLocation res = LOC_C_RETURN;
953 clobberReg(cUnit, r0);
954 markRegInUse(cUnit, r0);
955 return res;
956}
957
Ben Cheng5d90c202009-11-22 23:31:11 -0800958extern RegLocation getReturnLocAlt(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700959{
960 RegLocation res = LOC_C_RETURN;
961 res.lowReg = r1;
962 clobberReg(cUnit, r1);
963 markRegInUse(cUnit, r1);
964 return res;
965}
966
967/* Kill the corresponding bit in the null-checked register list */
Ben Cheng5d90c202009-11-22 23:31:11 -0800968extern void killNullCheckedLocation(CompilationUnit *cUnit,
Bill Buzbee1465db52009-09-23 17:17:35 -0700969 RegLocation loc)
970{
971 if (loc.location != kLocRetval) {
972 assert(loc.sRegLow != INVALID_SREG);
973 dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
974 if (loc.wide) {
975 assert(hiSReg(loc.sRegLow) != INVALID_SREG);
976 dvmClearBit(cUnit->regPool->nullCheckedRegs, hiSReg(loc.sRegLow));
977 }
978 }
979}
Ben Cheng5d90c202009-11-22 23:31:11 -0800980
981extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
982 int reg1, int reg2)
983{
984 flushRegWide(cUnit, reg1, reg2);
985}
986
987extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
988{
989 flushReg(cUnit, reg);
990}