blob: 5c128460cc048eeff85a06bc55337d3a1f8b917d [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);
Bill Buzbee2527f5b2010-01-28 18:36:55 -0800469 clobberReg(cUnit, r4PC);
Bill Buzbee1465db52009-09-23 17:17:35 -0700470 clobberReg(cUnit, r9);
471 clobberReg(cUnit, r10);
472}
473
Ben Cheng5d90c202009-11-22 23:31:11 -0800474extern void resetDef(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700475{
476 RegisterInfo *p = getRegInfo(cUnit, reg);
477 p->defStart = NULL;
478 p->defEnd = NULL;
479}
480
481static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
482 int sReg1, int sReg2)
483{
484 if (start && finish) {
485 LIR *p;
486 assert(sReg1 == sReg2);
487 for (p = start; ;p = p->next) {
488 ((ArmLIR *)p)->isNop = true;
489 if (p == finish)
490 break;
491 }
492 }
493}
494
495/*
496 * Mark the beginning and end LIR of a def sequence. Note that
497 * on entry start points to the LIR prior to the beginning of the
498 * sequence.
499 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800500extern void markDef(CompilationUnit *cUnit, RegLocation rl,
Bill Buzbee1465db52009-09-23 17:17:35 -0700501 LIR *start, LIR *finish)
502{
503 assert(!rl.wide);
504 assert(start && start->next);
505 assert(finish);
506 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
507 p->defStart = start->next;
508 p->defEnd = finish;
509}
510
511/*
512 * Mark the beginning and end LIR of a def sequence. Note that
513 * on entry start points to the LIR prior to the beginning of the
514 * sequence.
515 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800516extern void markDefWide(CompilationUnit *cUnit, RegLocation rl,
Bill Buzbee1465db52009-09-23 17:17:35 -0700517 LIR *start, LIR *finish)
518{
519 assert(rl.wide);
520 assert(start && start->next);
521 assert(finish);
522 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
523 resetDef(cUnit, rl.highReg); // Only track low of pair
524 p->defStart = start->next;
525 p->defEnd = finish;
526}
527
Ben Cheng5d90c202009-11-22 23:31:11 -0800528extern RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700529{
530 assert(rl.wide);
531 if (rl.location == kLocPhysReg) {
532 RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
533 RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
534 if (!infoLo->pair) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800535 dumpRegPool(cUnit->regPool->coreTemps,
536 cUnit->regPool->numCoreTemps);
Bill Buzbee1465db52009-09-23 17:17:35 -0700537 assert(infoLo->pair);
538 }
539 if (!infoHi->pair) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800540 dumpRegPool(cUnit->regPool->coreTemps,
541 cUnit->regPool->numCoreTemps);
Bill Buzbee1465db52009-09-23 17:17:35 -0700542 assert(infoHi->pair);
543 }
544 assert(infoLo->pair);
545 assert(infoHi->pair);
546 assert(infoLo->partner == infoHi->reg);
547 assert(infoHi->partner == infoLo->reg);
548 infoLo->pair = false;
549 infoHi->pair = false;
550 infoLo->defStart = NULL;
551 infoLo->defEnd = NULL;
552 infoHi->defStart = NULL;
553 infoHi->defEnd = NULL;
554 }
555 rl.wide = false;
556 return rl;
557}
558
Ben Cheng5d90c202009-11-22 23:31:11 -0800559extern void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700560{
561 assert(!rl.wide);
562 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
563 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
564 assert(!p->pair);
565 nullifyRange(cUnit, p->defStart, p->defEnd,
566 p->sReg, rl.sRegLow);
567 }
568 resetDef(cUnit, rl.lowReg);
569}
570
Ben Cheng5d90c202009-11-22 23:31:11 -0800571extern void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
Bill Buzbee1465db52009-09-23 17:17:35 -0700572{
573 assert(rl.wide);
574 if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
575 RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
576 assert(p->pair);
577 nullifyRange(cUnit, p->defStart, p->defEnd,
578 p->sReg, rl.sRegLow);
579 }
580 resetDef(cUnit, rl.lowReg);
581 resetDef(cUnit, rl.highReg);
582}
583
Ben Cheng5d90c202009-11-22 23:31:11 -0800584extern void resetDefTracking(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700585{
586 int i;
587 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
588 resetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
589 }
590 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
591 resetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
592 }
593}
594
Ben Cheng5d90c202009-11-22 23:31:11 -0800595extern void clobberAllRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700596{
597 int i;
598 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
599 clobberReg(cUnit, cUnit->regPool->coreTemps[i].reg);
600 }
601 for (i=0; i< cUnit->regPool->numFPTemps; i++) {
602 clobberReg(cUnit, cUnit->regPool->FPTemps[i].reg);
603 }
604}
605
606/* To be used when explicitly managing register use */
Ben Cheng5d90c202009-11-22 23:31:11 -0800607extern void lockAllTemps(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700608{
609 int i;
610 for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
611 lockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
612 }
613}
614
615// Make sure nothing is live and dirty
616static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
617 int numRegs)
618{
619 int i;
620 for (i=0; i < numRegs; i++) {
621 if (info[i].live && info[i].dirty) {
622 if (info[i].pair) {
623 flushRegWide(cUnit, info[i].reg, info[i].partner);
624 } else {
625 flushReg(cUnit, info[i].reg);
626 }
627 }
628 }
629}
630
Ben Cheng5d90c202009-11-22 23:31:11 -0800631extern void flushAllRegs(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700632{
633 flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
634 cUnit->regPool->numCoreTemps);
635 flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
636 cUnit->regPool->numFPTemps);
637 clobberAllRegs(cUnit);
638}
639
640
641//TUNING: rewrite all of this reg stuff. Probably use an attribute table
642static bool regClassMatches(int regClass, int reg)
643{
644 if (regClass == kAnyReg) {
645 return true;
646 } else if (regClass == kCoreReg) {
647 return !FPREG(reg);
648 } else {
649 return FPREG(reg);
650 }
651}
652
Ben Cheng5d90c202009-11-22 23:31:11 -0800653extern void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700654{
655 RegisterInfo *info = getRegInfo(cUnit, reg);
656 if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
657 return; /* already live */
658 } else if (sReg != INVALID_SREG) {
659 clobberSReg(cUnit, sReg);
660 info->live = true;
661 } else {
662 /* Can't be live if no associated sReg */
663 info->live = false;
664 }
665 info->sReg = sReg;
666}
667
Ben Cheng5d90c202009-11-22 23:31:11 -0800668extern void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700669{
670 RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
671 RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
672 infoLo->pair = infoHi->pair = true;
673 infoLo->partner = highReg;
674 infoHi->partner = lowReg;
675}
676
677static void markRegSingle(CompilationUnit *cUnit, int reg)
678{
679 RegisterInfo *info = getRegInfo(cUnit, reg);
680 info->pair = false;
681}
682
Ben Cheng5d90c202009-11-22 23:31:11 -0800683extern void markRegClean(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700684{
685 RegisterInfo *info = getRegInfo(cUnit, reg);
686 info->dirty = false;
687}
688
Ben Cheng5d90c202009-11-22 23:31:11 -0800689extern void markRegDirty(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700690{
691 RegisterInfo *info = getRegInfo(cUnit, reg);
692 info->dirty = true;
693}
694
Ben Cheng5d90c202009-11-22 23:31:11 -0800695extern void markRegInUse(CompilationUnit *cUnit, int reg)
Bill Buzbee1465db52009-09-23 17:17:35 -0700696{
Ben Cheng5d90c202009-11-22 23:31:11 -0800697 RegisterInfo *info = getRegInfo(cUnit, reg);
698 info->inUse = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700699}
700
701/* Return true if live & dirty */
702static bool isDirty(CompilationUnit *cUnit, int reg)
703{
704 RegisterInfo *info = getRegInfo(cUnit, reg);
705 return (info && info->live && info->dirty);
706}
707
708void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
709{
710 RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
711 RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
712 *newInfo = *oldInfo;
713 newInfo->reg = newReg;
714}
715
716/*
717 * Return an updated location record with current in-register status.
718 * If the value lives in live temps, reflect that fact. No code
719 * is generated. The the live value is part of an older pair,
720 * clobber both low and high.
721 * TUNING: clobbering both is a bit heavy-handed, but the alternative
722 * is a bit complex when dealing with FP regs. Examine code to see
723 * if it's worthwhile trying to be more clever here.
724 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800725extern RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
Bill Buzbee1465db52009-09-23 17:17:35 -0700726{
727 assert(!loc.wide);
728 if (loc.location == kLocDalvikFrame) {
729 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
730 if (infoLo) {
731 if (infoLo->pair) {
732 clobberReg(cUnit, infoLo->reg);
733 clobberReg(cUnit, infoLo->partner);
734 } else {
735 loc.lowReg = infoLo->reg;
736 loc.location = kLocPhysReg;
737 }
738 }
739 }
740
741 return loc;
742}
743
744/* see comments for updateLoc */
Ben Cheng5d90c202009-11-22 23:31:11 -0800745extern RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
Bill Buzbee1465db52009-09-23 17:17:35 -0700746{
747 assert(loc.wide);
748 if (loc.location == kLocDalvikFrame) {
749 RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
750 RegisterInfo *infoHi = allocLive(cUnit, hiSReg(loc.sRegLow), kAnyReg);
751 bool match = true;
752 match = match && (infoLo != NULL);
753 match = match && (infoHi != NULL);
754 match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
755 if (match && FPREG(infoLo->reg)) {
756 match &= ((infoLo->reg & 0x1) == 0);
757 match &= ((infoHi->reg - infoLo->reg) == 1);
758 }
759 if (match) {
760 loc.lowReg = infoLo->reg;
761 loc.highReg = infoHi->reg;
762 loc.location = kLocPhysReg;
763 markRegPair(cUnit, loc.lowReg, loc.highReg);
764 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
765 return loc;
766 }
767 /* Can't easily reuse - just clobber any overlaps */
768 if (infoLo) {
769 clobberReg(cUnit, infoLo->reg);
770 if (infoLo->pair)
771 clobberReg(cUnit, infoLo->partner);
772 }
773 if (infoHi) {
774 clobberReg(cUnit, infoHi->reg);
775 if (infoHi->pair)
776 clobberReg(cUnit, infoHi->partner);
777 }
778 }
779
780 return loc;
781}
782
783static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
784 int regClass, bool update)
785{
786 assert(loc.wide);
787 int newRegs;
788 int lowReg;
789 int highReg;
790
791 loc = updateLocWide(cUnit, loc);
792
793 /* If already in registers, we can assume proper form. Right reg class? */
794 if (loc.location == kLocPhysReg) {
795 assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
796 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
797 if (!regClassMatches(regClass, loc.lowReg)) {
798 /* Wrong register class. Reallocate and copy */
Ben Cheng5d90c202009-11-22 23:31:11 -0800799 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700800 lowReg = newRegs & 0xff;
801 highReg = (newRegs >> 8) & 0xff;
Ben Cheng5d90c202009-11-22 23:31:11 -0800802 dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
803 loc.highReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700804 copyRegInfo(cUnit, lowReg, loc.lowReg);
805 copyRegInfo(cUnit, highReg, loc.highReg);
806 clobberReg(cUnit, loc.lowReg);
807 clobberReg(cUnit, loc.highReg);
808 loc.lowReg = lowReg;
809 loc.highReg = highReg;
810 markRegPair(cUnit, loc.lowReg, loc.highReg);
811 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
812 }
813 return loc;
814 }
815
816 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
Ben Cheng5d90c202009-11-22 23:31:11 -0800817 assert((loc.location != kLocRetval) ||
818 (hiSReg(loc.sRegLow) == INVALID_SREG));
Bill Buzbee1465db52009-09-23 17:17:35 -0700819
Ben Cheng5d90c202009-11-22 23:31:11 -0800820 newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700821 loc.lowReg = newRegs & 0xff;
822 loc.highReg = (newRegs >> 8) & 0xff;
823
824 markRegPair(cUnit, loc.lowReg, loc.highReg);
825 if (update) {
826 loc.location = kLocPhysReg;
827 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
828 markRegLive(cUnit, loc.highReg, hiSReg(loc.sRegLow));
829 }
830 assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
831 return loc;
832}
833
Ben Cheng5d90c202009-11-22 23:31:11 -0800834extern RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
Bill Buzbee1465db52009-09-23 17:17:35 -0700835 int regClass, bool update)
836{
837 RegisterInfo *infoLo = NULL;
838 int newReg;
839 if (loc.wide)
840 return evalLocWide(cUnit, loc, regClass, update);
841 loc = updateLoc(cUnit, loc);
842
843 if (loc.location == kLocPhysReg) {
844 if (!regClassMatches(regClass, loc.lowReg)) {
845 /* Wrong register class. Realloc, copy and transfer ownership */
Ben Cheng5d90c202009-11-22 23:31:11 -0800846 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
847 dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700848 copyRegInfo(cUnit, newReg, loc.lowReg);
849 clobberReg(cUnit, loc.lowReg);
850 loc.lowReg = newReg;
851 }
852 return loc;
853 }
854
855 assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
856
Ben Cheng5d90c202009-11-22 23:31:11 -0800857 newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
Bill Buzbee1465db52009-09-23 17:17:35 -0700858 loc.lowReg = newReg;
859
860 if (update) {
861 loc.location = kLocPhysReg;
862 markRegLive(cUnit, loc.lowReg, loc.sRegLow);
863 }
864 return loc;
865}
866
Bill Buzbee1465db52009-09-23 17:17:35 -0700867static inline int getDestSSAName(MIR *mir, int num)
868{
869 assert(mir->ssaRep->numDefs > num);
870 return mir->ssaRep->defs[num];
871}
872
873// Get the LocRecord associated with an SSA name use.
Ben Cheng5d90c202009-11-22 23:31:11 -0800874extern RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
Bill Buzbee1465db52009-09-23 17:17:35 -0700875{
876 RegLocation loc = cUnit->regLocation[SREG(cUnit, getSrcSSAName(mir, num))];
877 loc.fp = cUnit->regLocation[getSrcSSAName(mir, num)].fp;
878 loc.wide = false;
879 return loc;
880}
881
882// Get the LocRecord associated with an SSA name def.
Ben Cheng5d90c202009-11-22 23:31:11 -0800883extern RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
Bill Buzbee1465db52009-09-23 17:17:35 -0700884{
885 RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
886 loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
887 loc.wide = false;
888 return loc;
889}
890
891static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
892 int low, int high, bool isSrc)
893{
894 RegLocation lowLoc;
895 RegLocation highLoc;
896 /* Copy loc record for low word and patch in data from high word */
897 if (isSrc) {
898 lowLoc = getSrcLoc(cUnit, mir, low);
899 highLoc = getSrcLoc(cUnit, mir, high);
900 } else {
901 lowLoc = getDestLoc(cUnit, mir, low);
902 highLoc = getDestLoc(cUnit, mir, high);
903 }
904 /* Avoid this case by either promoting both or neither. */
905 assert(lowLoc.location == highLoc.location);
906 if (lowLoc.location == kLocPhysReg) {
907 /* This case shouldn't happen if we've named correctly */
908 assert(lowLoc.fp == highLoc.fp);
909 }
910 lowLoc.wide = true;
911 lowLoc.highReg = highLoc.lowReg;
912 return lowLoc;
913}
Ben Cheng5d90c202009-11-22 23:31:11 -0800914
915extern RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee1465db52009-09-23 17:17:35 -0700916 int low, int high)
917{
918 return getLocWide(cUnit, mir, low, high, false);
919}
920
Ben Cheng5d90c202009-11-22 23:31:11 -0800921extern RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee1465db52009-09-23 17:17:35 -0700922 int low, int high)
923{
924 return getLocWide(cUnit, mir, low, high, true);
925}
926
Ben Cheng5d90c202009-11-22 23:31:11 -0800927extern RegLocation getReturnLocWide(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700928{
929 RegLocation res = LOC_C_RETURN_WIDE;
930 clobberReg(cUnit, r0);
931 clobberReg(cUnit, r1);
932 markRegInUse(cUnit, r0);
933 markRegInUse(cUnit, r1);
934 markRegPair(cUnit, res.lowReg, res.highReg);
935 return res;
936}
937
Ben Cheng5d90c202009-11-22 23:31:11 -0800938extern RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700939{
940 RegLocation res = LOC_C_RETURN_WIDE;
941 res.lowReg = r2;
942 res.highReg = r3;
943 clobberReg(cUnit, r2);
944 clobberReg(cUnit, r3);
945 markRegInUse(cUnit, r2);
946 markRegInUse(cUnit, r3);
947 markRegPair(cUnit, res.lowReg, res.highReg);
948 return res;
949}
950
Ben Cheng5d90c202009-11-22 23:31:11 -0800951extern RegLocation getReturnLoc(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700952{
953 RegLocation res = LOC_C_RETURN;
954 clobberReg(cUnit, r0);
955 markRegInUse(cUnit, r0);
956 return res;
957}
958
Ben Cheng5d90c202009-11-22 23:31:11 -0800959extern RegLocation getReturnLocAlt(CompilationUnit *cUnit)
Bill Buzbee1465db52009-09-23 17:17:35 -0700960{
961 RegLocation res = LOC_C_RETURN;
962 res.lowReg = r1;
963 clobberReg(cUnit, r1);
964 markRegInUse(cUnit, r1);
965 return res;
966}
967
968/* Kill the corresponding bit in the null-checked register list */
Ben Cheng5d90c202009-11-22 23:31:11 -0800969extern void killNullCheckedLocation(CompilationUnit *cUnit,
Bill Buzbee1465db52009-09-23 17:17:35 -0700970 RegLocation loc)
971{
972 if (loc.location != kLocRetval) {
973 assert(loc.sRegLow != INVALID_SREG);
974 dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
975 if (loc.wide) {
976 assert(hiSReg(loc.sRegLow) != INVALID_SREG);
977 dvmClearBit(cUnit->regPool->nullCheckedRegs, hiSReg(loc.sRegLow));
978 }
979 }
980}
Ben Cheng5d90c202009-11-22 23:31:11 -0800981
982extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
983 int reg1, int reg2)
984{
985 flushRegWide(cUnit, reg1, reg2);
986}
987
988extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
989{
990 flushReg(cUnit, reg);
991}