blob: 77fb23baad818b38b98f1edbf352fda3b0b56de9 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 "../CompilerUtility.h"
26#include "../CompilerIR.h"
27#include "../Dataflow.h"
28#include "Ralloc.h"
29
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080030namespace art {
31
buzbee67bf8852011-08-17 17:51:35 -070032#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
33/*
34 * Get the "real" sreg number associated with an sReg slot. In general,
35 * sReg values passed through codegen are the SSA names created by
36 * dataflow analysis and refer to slot numbers in the cUnit->regLocation
37 * array. However, renaming is accomplished by simply replacing RegLocation
38 * entries in the cUnit->reglocation[] array. Therefore, when location
39 * records for operands are first created, we need to ask the locRecord
40 * identified by the dataflow pass what it's new name is.
41 */
42
43/*
44 * Free all allocated temps in the temp pools. Note that this does
45 * not affect the "liveness" of a temp register, which will stay
46 * live until it is either explicitly killed or reallocated.
47 */
48extern void oatResetRegPool(CompilationUnit* cUnit)
49{
50 int i;
51 for (i=0; i < cUnit->regPool->numCoreRegs; i++) {
52 if (cUnit->regPool->coreRegs[i].isTemp)
53 cUnit->regPool->coreRegs[i].inUse = false;
54 }
55 for (i=0; i < cUnit->regPool->numFPRegs; i++) {
56 if (cUnit->regPool->FPRegs[i].isTemp)
57 cUnit->regPool->FPRegs[i].inUse = false;
58 }
59}
60
buzbeee3acd072012-02-25 17:03:10 -080061 /*
62 * Set up temp & preserved register pools specialized by target.
63 * Note: numRegs may be zero.
64 */
buzbee67bf8852011-08-17 17:51:35 -070065extern void oatInitPool(RegisterInfo* regs, int* regNums, int num)
66{
67 int i;
68 for (i=0; i < num; i++) {
69 regs[i].reg = regNums[i];
70 regs[i].inUse = false;
71 regs[i].isTemp = false;
72 regs[i].pair = false;
73 regs[i].live = false;
74 regs[i].dirty = false;
75 regs[i].sReg = INVALID_SREG;
76 }
77}
78
buzbeeed3e9302011-09-23 17:34:19 -070079STATIC void dumpRegPool(RegisterInfo* p, int numRegs)
buzbee67bf8852011-08-17 17:51:35 -070080{
81 int i;
82 LOG(INFO) << "================================================";
83 for (i=0; i < numRegs; i++ ){
84 char buf[100];
85 snprintf(buf, 100,
86 "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
87 p[i].reg, p[i].isTemp, p[i].inUse, p[i].pair, p[i].partner,
88 p[i].live, p[i].dirty, p[i].sReg,(int)p[i].defStart,
89 (int)p[i].defEnd);
90 LOG(INFO) << buf;
91 }
92 LOG(INFO) << "================================================";
93}
94
buzbee6181f792011-09-29 11:14:04 -070095void oatDumpCoreRegPool(CompilationUnit* cUnit)
96{
97 dumpRegPool(cUnit->regPool->coreRegs, cUnit->regPool->numCoreRegs);
98}
99
100void oatDumpFpRegPool(CompilationUnit* cUnit)
101{
102 dumpRegPool(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs);
103}
104
buzbee67bf8852011-08-17 17:51:35 -0700105/* Mark a temp register as dead. Does not affect allocation state. */
buzbee5abfa3e2012-01-31 17:01:43 -0800106static inline void clobberBody(CompilationUnit *cUnit, RegisterInfo* p)
buzbee67bf8852011-08-17 17:51:35 -0700107{
buzbee68253262011-10-07 14:02:25 -0700108 if (p->isTemp) {
109 DCHECK(!(p->live && p->dirty)) << "Live & dirty temp in clobber";
110 p->live = false;
111 p->sReg = INVALID_SREG;
112 p->defStart = NULL;
113 p->defEnd = NULL;
114 if (p->pair) {
115 p->pair = false;
116 oatClobber(cUnit, p->partner);
117 }
buzbee67bf8852011-08-17 17:51:35 -0700118 }
119}
120
buzbee5abfa3e2012-01-31 17:01:43 -0800121/* Mark a temp register as dead. Does not affect allocation state. */
122void oatClobber(CompilationUnit* cUnit, int reg)
123{
124 clobberBody(cUnit, oatGetRegInfo(cUnit, reg));
125}
126
buzbeeed3e9302011-09-23 17:34:19 -0700127STATIC void clobberSRegBody(RegisterInfo* p, int numRegs, int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700128{
129 int i;
130 for (i=0; i< numRegs; i++) {
131 if (p[i].sReg == sReg) {
132 if (p[i].isTemp) {
133 p[i].live = false;
134 }
135 p[i].defStart = NULL;
136 p[i].defEnd = NULL;
137 }
138 }
139}
140
141/* Clobber any temp associated with an sReg. Could be in either class */
142extern void oatClobberSReg(CompilationUnit* cUnit, int sReg)
143{
144 clobberSRegBody(cUnit->regPool->coreRegs, cUnit->regPool->numCoreRegs,
145 sReg);
146 clobberSRegBody(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs,
147 sReg);
148}
149
150/* Reserve a callee-save register. Return -1 if none available */
151extern int oatAllocPreservedCoreReg(CompilationUnit* cUnit, int sReg)
152{
153 int res = -1;
154 RegisterInfo* coreRegs = cUnit->regPool->coreRegs;
155 for (int i = 0; i < cUnit->regPool->numCoreRegs; i++) {
156 if (!coreRegs[i].isTemp && !coreRegs[i].inUse) {
157 res = coreRegs[i].reg;
158 coreRegs[i].inUse = true;
159 cUnit->coreSpillMask |= (1 << res);
buzbeec41e5b52011-09-23 12:46:19 -0700160 cUnit->coreVmapTable.push_back(sReg);
buzbeebbaf8942011-10-02 13:08:29 -0700161 cUnit->numCoreSpills++;
buzbee67bc2362011-10-11 18:08:40 -0700162 // Should be promoting based on initial sReg set
163 DCHECK_EQ(sReg, oatS2VReg(cUnit, sReg));
164 cUnit->promotionMap[sReg].coreLocation = kLocPhysReg;
165 cUnit->promotionMap[sReg].coreReg = res;
buzbee67bf8852011-08-17 17:51:35 -0700166 break;
167 }
168 }
169 return res;
170}
171
172/*
173 * Reserve a callee-save fp single register. Try to fullfill request for
174 * even/odd allocation, but go ahead and allocate anything if not
175 * available. If nothing's available, return -1.
176 */
buzbeeed3e9302011-09-23 17:34:19 -0700177STATIC int allocPreservedSingle(CompilationUnit* cUnit, int sReg, bool even)
buzbee67bf8852011-08-17 17:51:35 -0700178{
179 int res = -1;
180 RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
181 for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
182 if (!FPRegs[i].isTemp && !FPRegs[i].inUse &&
183 ((FPRegs[i].reg & 0x1) == 0) == even) {
184 res = FPRegs[i].reg;
185 FPRegs[i].inUse = true;
buzbee67bc2362011-10-11 18:08:40 -0700186 // Should be promoting based on initial sReg set
187 DCHECK_EQ(sReg, oatS2VReg(cUnit, sReg));
buzbeee3acd072012-02-25 17:03:10 -0800188 oatMarkPreservedSingle(cUnit, sReg, res);
buzbee67bc2362011-10-11 18:08:40 -0700189 cUnit->promotionMap[sReg].fpLocation = kLocPhysReg;
190 cUnit->promotionMap[sReg].fpReg = res;
buzbee67bf8852011-08-17 17:51:35 -0700191 break;
192 }
193 }
194 return res;
195}
196
197/*
198 * Somewhat messy code here. We want to allocate a pair of contiguous
199 * physical single-precision floating point registers starting with
200 * an even numbered reg. It is possible that the paired sReg (sReg+1)
201 * has already been allocated - try to fit if possible. Fail to
202 * allocate if we can't meet the requirements for the pair of
203 * sReg<=sX[even] & (sReg+1)<= sX+1.
204 */
buzbeeed3e9302011-09-23 17:34:19 -0700205STATIC int allocPreservedDouble(CompilationUnit* cUnit, int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700206{
207 int res = -1; // Assume failure
buzbee67bc2362011-10-11 18:08:40 -0700208 // Should be promoting based on initial sReg set
209 DCHECK_EQ(sReg, oatS2VReg(cUnit, sReg));
210 if (cUnit->promotionMap[sReg+1].fpLocation == kLocPhysReg) {
buzbee67bf8852011-08-17 17:51:35 -0700211 // Upper reg is already allocated. Can we fit?
buzbee67bc2362011-10-11 18:08:40 -0700212 int highReg = cUnit->promotionMap[sReg+1].fpReg;
buzbee67bf8852011-08-17 17:51:35 -0700213 if ((highReg & 1) == 0) {
214 // High reg is even - fail.
215 return res;
216 }
217 // Is the low reg of the pair free?
buzbee68253262011-10-07 14:02:25 -0700218 RegisterInfo* p = oatGetRegInfo(cUnit, highReg-1);
buzbee67bf8852011-08-17 17:51:35 -0700219 if (p->inUse || p->isTemp) {
220 // Already allocated or not preserved - fail.
221 return res;
222 }
223 // OK - good to go.
224 res = p->reg;
225 p->inUse = true;
buzbeeed3e9302011-09-23 17:34:19 -0700226 DCHECK_EQ((res & 1), 0);
buzbeee3acd072012-02-25 17:03:10 -0800227 oatMarkPreservedSingle(cUnit, sReg, res);
buzbee67bf8852011-08-17 17:51:35 -0700228 } else {
229 RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
230 for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
231 if (!FPRegs[i].isTemp && !FPRegs[i].inUse &&
232 ((FPRegs[i].reg & 0x1) == 0x0) &&
233 !FPRegs[i+1].isTemp && !FPRegs[i+1].inUse &&
234 ((FPRegs[i+1].reg & 0x1) == 0x1) &&
235 (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
236 res = FPRegs[i].reg;
237 FPRegs[i].inUse = true;
buzbeee3acd072012-02-25 17:03:10 -0800238 oatMarkPreservedSingle(cUnit, sReg, res);
buzbee67bf8852011-08-17 17:51:35 -0700239 FPRegs[i+1].inUse = true;
buzbeebbaf8942011-10-02 13:08:29 -0700240 DCHECK_EQ(res + 1, FPRegs[i+1].reg);
buzbeee3acd072012-02-25 17:03:10 -0800241 oatMarkPreservedSingle(cUnit, sReg+1, res+1);
buzbee67bf8852011-08-17 17:51:35 -0700242 break;
243 }
244 }
245 }
246 if (res != -1) {
buzbee67bc2362011-10-11 18:08:40 -0700247 cUnit->promotionMap[sReg].fpLocation = kLocPhysReg;
248 cUnit->promotionMap[sReg].fpReg = res;
249 cUnit->promotionMap[sReg+1].fpLocation = kLocPhysReg;
250 cUnit->promotionMap[sReg+1].fpReg = res + 1;
buzbee67bf8852011-08-17 17:51:35 -0700251 }
252 return res;
253}
254
255
256/*
257 * Reserve a callee-save fp register. If this register can be used
258 * as the first of a double, attempt to allocate an even pair of fp
259 * single regs (but if can't still attempt to allocate a single, preferring
260 * first to allocate an odd register.
261 */
262extern int oatAllocPreservedFPReg(CompilationUnit* cUnit, int sReg,
263 bool doubleStart)
264{
265 int res = -1;
266 if (doubleStart) {
267 res = allocPreservedDouble(cUnit, sReg);
buzbee67bf8852011-08-17 17:51:35 -0700268 }
269 if (res == -1) {
270 res = allocPreservedSingle(cUnit, sReg, false /* try odd # */);
271 }
272 if (res == -1)
273 res = allocPreservedSingle(cUnit, sReg, true /* try even # */);
274 return res;
275}
276
buzbeeed3e9302011-09-23 17:34:19 -0700277STATIC int allocTempBody(CompilationUnit* cUnit, RegisterInfo* p, int numRegs,
buzbee67bf8852011-08-17 17:51:35 -0700278 int* nextTemp, bool required)
279{
280 int i;
281 int next = *nextTemp;
282 for (i=0; i< numRegs; i++) {
283 if (next >= numRegs)
284 next = 0;
285 if (p[next].isTemp && !p[next].inUse && !p[next].live) {
286 oatClobber(cUnit, p[next].reg);
287 p[next].inUse = true;
288 p[next].pair = false;
289 *nextTemp = next + 1;
290 return p[next].reg;
291 }
292 next++;
293 }
294 next = *nextTemp;
295 for (i=0; i< numRegs; i++) {
296 if (next >= numRegs)
297 next = 0;
298 if (p[next].isTemp && !p[next].inUse) {
299 oatClobber(cUnit, p[next].reg);
300 p[next].inUse = true;
301 p[next].pair = false;
302 *nextTemp = next + 1;
303 return p[next].reg;
304 }
305 next++;
306 }
307 if (required) {
buzbee6181f792011-09-29 11:14:04 -0700308 oatCodegenDump(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700309 dumpRegPool(cUnit->regPool->coreRegs,
310 cUnit->regPool->numCoreRegs);
311 LOG(FATAL) << "No free temp registers";
312 }
313 return -1; // No register available
314}
315
316//REDO: too many assumptions.
317extern int oatAllocTempDouble(CompilationUnit* cUnit)
318{
319 RegisterInfo* p = cUnit->regPool->FPRegs;
320 int numRegs = cUnit->regPool->numFPRegs;
buzbeea50638b2011-11-02 15:15:06 -0700321 /* Start looking at an even reg */
322 int next = cUnit->regPool->nextFPReg & ~0x1;
buzbee67bf8852011-08-17 17:51:35 -0700323
buzbeea50638b2011-11-02 15:15:06 -0700324 // First try to avoid allocating live registers
325 for (int i=0; i < numRegs; i+=2) {
buzbee67bf8852011-08-17 17:51:35 -0700326 if (next >= numRegs)
327 next = 0;
328 if ((p[next].isTemp && !p[next].inUse && !p[next].live) &&
329 (p[next+1].isTemp && !p[next+1].inUse && !p[next+1].live)) {
330 oatClobber(cUnit, p[next].reg);
331 oatClobber(cUnit, p[next+1].reg);
332 p[next].inUse = true;
333 p[next+1].inUse = true;
buzbeeed3e9302011-09-23 17:34:19 -0700334 DCHECK_EQ((p[next].reg+1), p[next+1].reg);
335 DCHECK_EQ((p[next].reg & 0x1), 0);
buzbeea50638b2011-11-02 15:15:06 -0700336 cUnit->regPool->nextFPReg = next + 2;
337 if (cUnit->regPool->nextFPReg >= numRegs) {
338 cUnit->regPool->nextFPReg = 0;
339 }
buzbee67bf8852011-08-17 17:51:35 -0700340 return p[next].reg;
341 }
342 next += 2;
343 }
buzbeea50638b2011-11-02 15:15:06 -0700344 next = cUnit->regPool->nextFPReg & ~0x1;
345
346 // No choice - find a pair and kill it.
347 for (int i=0; i < numRegs; i+=2) {
buzbee67bf8852011-08-17 17:51:35 -0700348 if (next >= numRegs)
349 next = 0;
350 if (p[next].isTemp && !p[next].inUse && p[next+1].isTemp &&
351 !p[next+1].inUse) {
352 oatClobber(cUnit, p[next].reg);
353 oatClobber(cUnit, p[next+1].reg);
354 p[next].inUse = true;
355 p[next+1].inUse = true;
buzbeeed3e9302011-09-23 17:34:19 -0700356 DCHECK_EQ((p[next].reg+1), p[next+1].reg);
357 DCHECK_EQ((p[next].reg & 0x1), 0);
buzbeea50638b2011-11-02 15:15:06 -0700358 cUnit->regPool->nextFPReg = next + 2;
359 if (cUnit->regPool->nextFPReg >= numRegs) {
360 cUnit->regPool->nextFPReg = 0;
361 }
buzbee67bf8852011-08-17 17:51:35 -0700362 return p[next].reg;
363 }
364 next += 2;
365 }
buzbee6181f792011-09-29 11:14:04 -0700366 LOG(FATAL) << "No free temp registers (pair)";
buzbee67bf8852011-08-17 17:51:35 -0700367 return -1;
368}
369
370/* Return a temp if one is available, -1 otherwise */
371extern int oatAllocFreeTemp(CompilationUnit* cUnit)
372{
373 return allocTempBody(cUnit, cUnit->regPool->coreRegs,
374 cUnit->regPool->numCoreRegs,
375 &cUnit->regPool->nextCoreReg, true);
376}
377
378extern int oatAllocTemp(CompilationUnit* cUnit)
379{
380 return allocTempBody(cUnit, cUnit->regPool->coreRegs,
381 cUnit->regPool->numCoreRegs,
382 &cUnit->regPool->nextCoreReg, true);
383}
384
385extern int oatAllocTempFloat(CompilationUnit* cUnit)
386{
387 return allocTempBody(cUnit, cUnit->regPool->FPRegs,
388 cUnit->regPool->numFPRegs,
389 &cUnit->regPool->nextFPReg, true);
390}
391
buzbeeed3e9302011-09-23 17:34:19 -0700392STATIC RegisterInfo* allocLiveBody(RegisterInfo* p, int numRegs, int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700393{
394 int i;
395 if (sReg == -1)
396 return NULL;
397 for (i=0; i < numRegs; i++) {
398 if (p[i].live && (p[i].sReg == sReg)) {
399 if (p[i].isTemp)
400 p[i].inUse = true;
401 return &p[i];
402 }
403 }
404 return NULL;
405}
406
buzbeeed3e9302011-09-23 17:34:19 -0700407STATIC RegisterInfo* allocLive(CompilationUnit* cUnit, int sReg,
buzbee67bf8852011-08-17 17:51:35 -0700408 int regClass)
409{
410 RegisterInfo* res = NULL;
411 switch(regClass) {
412 case kAnyReg:
413 res = allocLiveBody(cUnit->regPool->FPRegs,
414 cUnit->regPool->numFPRegs, sReg);
415 if (res)
416 break;
417 /* Intentional fallthrough */
418 case kCoreReg:
419 res = allocLiveBody(cUnit->regPool->coreRegs,
420 cUnit->regPool->numCoreRegs, sReg);
421 break;
422 case kFPReg:
423 res = allocLiveBody(cUnit->regPool->FPRegs,
424 cUnit->regPool->numFPRegs, sReg);
425 break;
426 default:
427 LOG(FATAL) << "Invalid register type";
428 }
429 return res;
430}
431
432extern void oatFreeTemp(CompilationUnit* cUnit, int reg)
433{
434 RegisterInfo* p = cUnit->regPool->coreRegs;
435 int numRegs = cUnit->regPool->numCoreRegs;
436 int i;
437 for (i=0; i< numRegs; i++) {
438 if (p[i].reg == reg) {
439 if (p[i].isTemp) {
440 p[i].inUse = false;
441 }
442 p[i].pair = false;
443 return;
444 }
445 }
446 p = cUnit->regPool->FPRegs;
447 numRegs = cUnit->regPool->numFPRegs;
448 for (i=0; i< numRegs; i++) {
449 if (p[i].reg == reg) {
450 if (p[i].isTemp) {
451 p[i].inUse = false;
452 }
453 p[i].pair = false;
454 return;
455 }
456 }
457 LOG(FATAL) << "Tried to free a non-existant temp: r" << reg;
458}
459
460extern RegisterInfo* oatIsLive(CompilationUnit* cUnit, int reg)
461{
462 RegisterInfo* p = cUnit->regPool->coreRegs;
463 int numRegs = cUnit->regPool->numCoreRegs;
464 int i;
465 for (i=0; i< numRegs; i++) {
466 if (p[i].reg == reg) {
467 return p[i].live ? &p[i] : NULL;
468 }
469 }
470 p = cUnit->regPool->FPRegs;
471 numRegs = cUnit->regPool->numFPRegs;
472 for (i=0; i< numRegs; i++) {
473 if (p[i].reg == reg) {
474 return p[i].live ? &p[i] : NULL;
475 }
476 }
477 return NULL;
478}
479
480extern RegisterInfo* oatIsTemp(CompilationUnit* cUnit, int reg)
481{
buzbee68253262011-10-07 14:02:25 -0700482 RegisterInfo* p = oatGetRegInfo(cUnit, reg);
buzbee67bf8852011-08-17 17:51:35 -0700483 return (p->isTemp) ? p : NULL;
484}
485
buzbeeb29e4d12011-09-26 15:05:48 -0700486extern RegisterInfo* oatIsPromoted(CompilationUnit* cUnit, int reg)
487{
buzbee68253262011-10-07 14:02:25 -0700488 RegisterInfo* p = oatGetRegInfo(cUnit, reg);
buzbeeb29e4d12011-09-26 15:05:48 -0700489 return (p->isTemp) ? NULL : p;
490}
491
buzbee67bf8852011-08-17 17:51:35 -0700492extern bool oatIsDirty(CompilationUnit* cUnit, int reg)
493{
buzbee68253262011-10-07 14:02:25 -0700494 RegisterInfo* p = oatGetRegInfo(cUnit, reg);
buzbee67bf8852011-08-17 17:51:35 -0700495 return p->dirty;
496}
497
498/*
499 * Similar to oatAllocTemp(), but forces the allocation of a specific
500 * register. No check is made to see if the register was previously
501 * allocated. Use with caution.
502 */
503extern void oatLockTemp(CompilationUnit* cUnit, int reg)
504{
505 RegisterInfo* p = cUnit->regPool->coreRegs;
506 int numRegs = cUnit->regPool->numCoreRegs;
507 int i;
508 for (i=0; i< numRegs; i++) {
509 if (p[i].reg == reg) {
buzbeeed3e9302011-09-23 17:34:19 -0700510 DCHECK(p[i].isTemp);
buzbee67bf8852011-08-17 17:51:35 -0700511 p[i].inUse = true;
512 p[i].live = false;
513 return;
514 }
515 }
516 p = cUnit->regPool->FPRegs;
517 numRegs = cUnit->regPool->numFPRegs;
518 for (i=0; i< numRegs; i++) {
519 if (p[i].reg == reg) {
buzbeeed3e9302011-09-23 17:34:19 -0700520 DCHECK(p[i].isTemp);
buzbee67bf8852011-08-17 17:51:35 -0700521 p[i].inUse = true;
522 p[i].live = false;
523 return;
524 }
525 }
526 LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg;
527}
528
buzbee5abfa3e2012-01-31 17:01:43 -0800529static inline void resetDefBody(RegisterInfo* p)
buzbee67bf8852011-08-17 17:51:35 -0700530{
buzbee67bf8852011-08-17 17:51:35 -0700531 p->defStart = NULL;
532 p->defEnd = NULL;
533}
534
buzbee5abfa3e2012-01-31 17:01:43 -0800535extern void oatResetDef(CompilationUnit* cUnit, int reg)
536{
537 resetDefBody(oatGetRegInfo(cUnit, reg));
538}
539
buzbeeed3e9302011-09-23 17:34:19 -0700540STATIC void nullifyRange(CompilationUnit* cUnit, LIR *start, LIR *finish,
buzbee67bf8852011-08-17 17:51:35 -0700541 int sReg1, int sReg2)
542{
543 if (start && finish) {
544 LIR *p;
buzbeeed3e9302011-09-23 17:34:19 -0700545 DCHECK_EQ(sReg1, sReg2);
buzbee67bf8852011-08-17 17:51:35 -0700546 for (p = start; ;p = p->next) {
buzbeee3acd072012-02-25 17:03:10 -0800547 oatNopLIR(p);
buzbee67bf8852011-08-17 17:51:35 -0700548 if (p == finish)
549 break;
550 }
551 }
552}
553
554/*
555 * Mark the beginning and end LIR of a def sequence. Note that
556 * on entry start points to the LIR prior to the beginning of the
557 * sequence.
558 */
559extern void oatMarkDef(CompilationUnit* cUnit, RegLocation rl,
560 LIR *start, LIR *finish)
561{
buzbeeed3e9302011-09-23 17:34:19 -0700562 DCHECK(!rl.wide);
563 DCHECK(start && start->next);
564 DCHECK(finish);
buzbee68253262011-10-07 14:02:25 -0700565 RegisterInfo* p = oatGetRegInfo(cUnit, rl.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700566 p->defStart = start->next;
567 p->defEnd = finish;
568}
569
570/*
571 * Mark the beginning and end LIR of a def sequence. Note that
572 * on entry start points to the LIR prior to the beginning of the
573 * sequence.
574 */
575extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl,
576 LIR *start, LIR *finish)
577{
buzbeeed3e9302011-09-23 17:34:19 -0700578 DCHECK(rl.wide);
579 DCHECK(start && start->next);
580 DCHECK(finish);
buzbee68253262011-10-07 14:02:25 -0700581 RegisterInfo* p = oatGetRegInfo(cUnit, rl.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700582 oatResetDef(cUnit, rl.highReg); // Only track low of pair
583 p->defStart = start->next;
584 p->defEnd = finish;
585}
586
587extern RegLocation oatWideToNarrow(CompilationUnit* cUnit,
588 RegLocation rl)
589{
buzbeeed3e9302011-09-23 17:34:19 -0700590 DCHECK(rl.wide);
buzbee67bf8852011-08-17 17:51:35 -0700591 if (rl.location == kLocPhysReg) {
buzbee68253262011-10-07 14:02:25 -0700592 RegisterInfo* infoLo = oatGetRegInfo(cUnit, rl.lowReg);
593 RegisterInfo* infoHi = oatGetRegInfo(cUnit, rl.highReg);
buzbee0c7f26d2011-09-07 12:28:51 -0700594 if (infoLo->isTemp) {
595 infoLo->pair = false;
596 infoLo->defStart = NULL;
597 infoLo->defEnd = NULL;
buzbee67bf8852011-08-17 17:51:35 -0700598 }
buzbee0c7f26d2011-09-07 12:28:51 -0700599 if (infoHi->isTemp) {
600 infoHi->pair = false;
601 infoHi->defStart = NULL;
602 infoHi->defEnd = NULL;
buzbee67bf8852011-08-17 17:51:35 -0700603 }
buzbee67bf8852011-08-17 17:51:35 -0700604 }
605 rl.wide = false;
606 return rl;
607}
608
609extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl)
610{
buzbeeed3e9302011-09-23 17:34:19 -0700611 DCHECK(!rl.wide);
buzbee6181f792011-09-29 11:14:04 -0700612 RegisterInfo* p = oatIsTemp(cUnit, rl.lowReg);
613 if (p && !(cUnit->disableOpt & (1 << kSuppressLoads))) {
buzbeeed3e9302011-09-23 17:34:19 -0700614 DCHECK(!p->pair);
buzbee67bf8852011-08-17 17:51:35 -0700615 nullifyRange(cUnit, p->defStart, p->defEnd,
616 p->sReg, rl.sRegLow);
617 }
618 oatResetDef(cUnit, rl.lowReg);
619}
620
621extern void oatResetDefLocWide(CompilationUnit* cUnit, RegLocation rl)
622{
buzbeeed3e9302011-09-23 17:34:19 -0700623 DCHECK(rl.wide);
buzbee6181f792011-09-29 11:14:04 -0700624 RegisterInfo* pLow = oatIsTemp(cUnit, rl.lowReg);
625 RegisterInfo* pHigh = oatIsTemp(cUnit, rl.highReg);
626 if (pLow && !(cUnit->disableOpt & (1 << kSuppressLoads))) {
627 DCHECK(pLow->pair);
628 nullifyRange(cUnit, pLow->defStart, pLow->defEnd,
629 pLow->sReg, rl.sRegLow);
630 }
631 if (pHigh && !(cUnit->disableOpt & (1 << kSuppressLoads))) {
632 DCHECK(pHigh->pair);
buzbee67bf8852011-08-17 17:51:35 -0700633 }
634 oatResetDef(cUnit, rl.lowReg);
635 oatResetDef(cUnit, rl.highReg);
636}
637
638extern void oatResetDefTracking(CompilationUnit* cUnit)
639{
640 int i;
641 for (i=0; i< cUnit->regPool->numCoreRegs; i++) {
buzbee5abfa3e2012-01-31 17:01:43 -0800642 resetDefBody(&cUnit->regPool->coreRegs[i]);
buzbee67bf8852011-08-17 17:51:35 -0700643 }
644 for (i=0; i< cUnit->regPool->numFPRegs; i++) {
buzbee5abfa3e2012-01-31 17:01:43 -0800645 resetDefBody(&cUnit->regPool->FPRegs[i]);
buzbee67bf8852011-08-17 17:51:35 -0700646 }
647}
648
649extern void oatClobberAllRegs(CompilationUnit* cUnit)
650{
651 int i;
652 for (i=0; i< cUnit->regPool->numCoreRegs; i++) {
buzbee5abfa3e2012-01-31 17:01:43 -0800653 clobberBody(cUnit, &cUnit->regPool->coreRegs[i]);
buzbee67bf8852011-08-17 17:51:35 -0700654 }
655 for (i=0; i< cUnit->regPool->numFPRegs; i++) {
buzbee5abfa3e2012-01-31 17:01:43 -0800656 clobberBody(cUnit, &cUnit->regPool->FPRegs[i]);
buzbee67bf8852011-08-17 17:51:35 -0700657 }
658}
659
buzbee67bf8852011-08-17 17:51:35 -0700660// Make sure nothing is live and dirty
buzbeeed3e9302011-09-23 17:34:19 -0700661STATIC void flushAllRegsBody(CompilationUnit* cUnit, RegisterInfo* info,
buzbee67bf8852011-08-17 17:51:35 -0700662 int numRegs)
663{
664 int i;
665 for (i=0; i < numRegs; i++) {
666 if (info[i].live && info[i].dirty) {
667 if (info[i].pair) {
668 oatFlushRegWide(cUnit, info[i].reg, info[i].partner);
669 } else {
670 oatFlushReg(cUnit, info[i].reg);
671 }
672 }
673 }
674}
675
676extern void oatFlushAllRegs(CompilationUnit* cUnit)
677{
678 flushAllRegsBody(cUnit, cUnit->regPool->coreRegs,
679 cUnit->regPool->numCoreRegs);
680 flushAllRegsBody(cUnit, cUnit->regPool->FPRegs,
681 cUnit->regPool->numFPRegs);
682 oatClobberAllRegs(cUnit);
683}
684
685
686//TUNING: rewrite all of this reg stuff. Probably use an attribute table
buzbeeed3e9302011-09-23 17:34:19 -0700687STATIC bool regClassMatches(int regClass, int reg)
buzbee67bf8852011-08-17 17:51:35 -0700688{
689 if (regClass == kAnyReg) {
690 return true;
691 } else if (regClass == kCoreReg) {
buzbeee3acd072012-02-25 17:03:10 -0800692 return !oatIsFpReg(reg);
buzbee67bf8852011-08-17 17:51:35 -0700693 } else {
buzbeee3acd072012-02-25 17:03:10 -0800694 return oatIsFpReg(reg);
buzbee67bf8852011-08-17 17:51:35 -0700695 }
696}
697
698extern void oatMarkLive(CompilationUnit* cUnit, int reg, int sReg)
699{
buzbee68253262011-10-07 14:02:25 -0700700 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
buzbee67bf8852011-08-17 17:51:35 -0700701 if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
702 return; /* already live */
703 } else if (sReg != INVALID_SREG) {
704 oatClobberSReg(cUnit, sReg);
705 if (info->isTemp) {
706 info->live = true;
707 }
708 } else {
709 /* Can't be live if no associated sReg */
buzbeeed3e9302011-09-23 17:34:19 -0700710 DCHECK(info->isTemp);
buzbee67bf8852011-08-17 17:51:35 -0700711 info->live = false;
712 }
713 info->sReg = sReg;
714}
715
716extern void oatMarkTemp(CompilationUnit* cUnit, int reg)
717{
buzbee68253262011-10-07 14:02:25 -0700718 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
buzbee67bf8852011-08-17 17:51:35 -0700719 info->isTemp = true;
720}
721
buzbee9e0f9b02011-08-24 15:32:46 -0700722extern void oatUnmarkTemp(CompilationUnit* cUnit, int reg)
723{
buzbee68253262011-10-07 14:02:25 -0700724 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
buzbee9e0f9b02011-08-24 15:32:46 -0700725 info->isTemp = false;
726}
727
buzbee67bf8852011-08-17 17:51:35 -0700728extern void oatMarkPair(CompilationUnit* cUnit, int lowReg, int highReg)
729{
buzbee68253262011-10-07 14:02:25 -0700730 RegisterInfo* infoLo = oatGetRegInfo(cUnit, lowReg);
731 RegisterInfo* infoHi = oatGetRegInfo(cUnit, highReg);
buzbee67bf8852011-08-17 17:51:35 -0700732 infoLo->pair = infoHi->pair = true;
733 infoLo->partner = highReg;
734 infoHi->partner = lowReg;
735}
736
737extern void oatMarkClean(CompilationUnit* cUnit, RegLocation loc)
738{
buzbee68253262011-10-07 14:02:25 -0700739 RegisterInfo* info = oatGetRegInfo(cUnit, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700740 info->dirty = false;
741 if (loc.wide) {
buzbee68253262011-10-07 14:02:25 -0700742 info = oatGetRegInfo(cUnit, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700743 info->dirty = false;
744 }
745}
746
747extern void oatMarkDirty(CompilationUnit* cUnit, RegLocation loc)
748{
749 if (loc.home) {
750 // If already home, can't be dirty
751 return;
752 }
buzbee68253262011-10-07 14:02:25 -0700753 RegisterInfo* info = oatGetRegInfo(cUnit, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700754 info->dirty = true;
755 if (loc.wide) {
buzbee68253262011-10-07 14:02:25 -0700756 info = oatGetRegInfo(cUnit, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700757 info->dirty = true;
758 }
759}
760
761extern void oatMarkInUse(CompilationUnit* cUnit, int reg)
762{
buzbee68253262011-10-07 14:02:25 -0700763 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
buzbee67bf8852011-08-17 17:51:35 -0700764 info->inUse = true;
765}
766
buzbeeed3e9302011-09-23 17:34:19 -0700767STATIC void copyRegInfo(CompilationUnit* cUnit, int newReg, int oldReg)
buzbee67bf8852011-08-17 17:51:35 -0700768{
buzbee68253262011-10-07 14:02:25 -0700769 RegisterInfo* newInfo = oatGetRegInfo(cUnit, newReg);
770 RegisterInfo* oldInfo = oatGetRegInfo(cUnit, oldReg);
buzbeeec5adf32011-09-11 15:25:43 -0700771 // Target temp status must not change
772 bool isTemp = newInfo->isTemp;
buzbee67bf8852011-08-17 17:51:35 -0700773 *newInfo = *oldInfo;
buzbeeec5adf32011-09-11 15:25:43 -0700774 // Restore target's temp status
775 newInfo->isTemp = isTemp;
buzbee67bf8852011-08-17 17:51:35 -0700776 newInfo->reg = newReg;
777}
778
779/*
780 * Return an updated location record with current in-register status.
781 * If the value lives in live temps, reflect that fact. No code
buzbeeb29e4d12011-09-26 15:05:48 -0700782 * is generated. If the live value is part of an older pair,
buzbee67bf8852011-08-17 17:51:35 -0700783 * clobber both low and high.
784 * TUNING: clobbering both is a bit heavy-handed, but the alternative
785 * is a bit complex when dealing with FP regs. Examine code to see
786 * if it's worthwhile trying to be more clever here.
787 */
788
789extern RegLocation oatUpdateLoc(CompilationUnit* cUnit, RegLocation loc)
790{
buzbeeed3e9302011-09-23 17:34:19 -0700791 DCHECK(!loc.wide);
buzbee6181f792011-09-29 11:14:04 -0700792 DCHECK(oatCheckCorePoolSanity(cUnit));
buzbee67bf8852011-08-17 17:51:35 -0700793 if (loc.location == kLocDalvikFrame) {
794 RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
795 if (infoLo) {
796 if (infoLo->pair) {
797 oatClobber(cUnit, infoLo->reg);
798 oatClobber(cUnit, infoLo->partner);
buzbee58f92742011-10-01 11:22:17 -0700799 oatFreeTemp(cUnit, infoLo->reg);
buzbee67bf8852011-08-17 17:51:35 -0700800 } else {
801 loc.lowReg = infoLo->reg;
802 loc.location = kLocPhysReg;
803 }
804 }
805 }
806
807 return loc;
808}
809
buzbee6181f792011-09-29 11:14:04 -0700810bool oatCheckCorePoolSanity(CompilationUnit* cUnit)
811{
812 for (static int i = 0; i < cUnit->regPool->numCoreRegs; i++) {
813 if (cUnit->regPool->coreRegs[i].pair) {
814 static int myReg = cUnit->regPool->coreRegs[i].reg;
815 static int mySreg = cUnit->regPool->coreRegs[i].sReg;
816 static int partnerReg = cUnit->regPool->coreRegs[i].partner;
buzbee68253262011-10-07 14:02:25 -0700817 static RegisterInfo* partner = oatGetRegInfo(cUnit, partnerReg);
buzbee6181f792011-09-29 11:14:04 -0700818 DCHECK(partner != NULL);
819 DCHECK(partner->pair);
820 DCHECK_EQ(myReg, partner->partner);
821 static int partnerSreg = partner->sReg;
822 if (mySreg == INVALID_SREG) {
823 DCHECK_EQ(partnerSreg, INVALID_SREG);
824 } else {
825 int diff = mySreg - partnerSreg;
826 DCHECK((diff == -1) || (diff == 1));
827 }
828 }
829 if (!cUnit->regPool->coreRegs[i].live) {
830 DCHECK(cUnit->regPool->coreRegs[i].defStart == NULL);
831 DCHECK(cUnit->regPool->coreRegs[i].defEnd == NULL);
832 }
833 }
834 return true;
835}
836
buzbee67bf8852011-08-17 17:51:35 -0700837/* see comments for updateLoc */
838extern RegLocation oatUpdateLocWide(CompilationUnit* cUnit,
839 RegLocation loc)
840{
buzbeeed3e9302011-09-23 17:34:19 -0700841 DCHECK(loc.wide);
buzbee6181f792011-09-29 11:14:04 -0700842 DCHECK(oatCheckCorePoolSanity(cUnit));
buzbee67bf8852011-08-17 17:51:35 -0700843 if (loc.location == kLocDalvikFrame) {
844 // Are the dalvik regs already live in physical registers?
845 RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
846 RegisterInfo* infoHi = allocLive(cUnit,
847 oatSRegHi(loc.sRegLow), kAnyReg);
848 bool match = true;
849 match = match && (infoLo != NULL);
850 match = match && (infoHi != NULL);
851 // Are they both core or both FP?
buzbeee3acd072012-02-25 17:03:10 -0800852 match = match && (oatIsFpReg(infoLo->reg) == oatIsFpReg(infoHi->reg));
buzbee67bf8852011-08-17 17:51:35 -0700853 // If a pair of floating point singles, are they properly aligned?
buzbeee3acd072012-02-25 17:03:10 -0800854 if (match && oatIsFpReg(infoLo->reg)) {
buzbee67bf8852011-08-17 17:51:35 -0700855 match &= ((infoLo->reg & 0x1) == 0);
856 match &= ((infoHi->reg - infoLo->reg) == 1);
857 }
858 // If previously used as a pair, it is the same pair?
859 if (match && (infoLo->pair || infoHi->pair)) {
860 match = (infoLo->pair == infoHi->pair);
861 match &= ((infoLo->reg == infoHi->partner) &&
862 (infoHi->reg == infoLo->partner));
863 }
864 if (match) {
865 // Can reuse - update the register usage info
866 loc.lowReg = infoLo->reg;
867 loc.highReg = infoHi->reg;
868 loc.location = kLocPhysReg;
869 oatMarkPair(cUnit, loc.lowReg, loc.highReg);
buzbeee3acd072012-02-25 17:03:10 -0800870 DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
buzbee67bf8852011-08-17 17:51:35 -0700871 return loc;
872 }
buzbee58f92742011-10-01 11:22:17 -0700873 // Can't easily reuse - clobber and free any overlaps
buzbee67bf8852011-08-17 17:51:35 -0700874 if (infoLo) {
875 oatClobber(cUnit, infoLo->reg);
buzbee58f92742011-10-01 11:22:17 -0700876 oatFreeTemp(cUnit, infoLo->reg);
buzbee67bf8852011-08-17 17:51:35 -0700877 if (infoLo->pair)
878 oatClobber(cUnit, infoLo->partner);
879 }
880 if (infoHi) {
881 oatClobber(cUnit, infoHi->reg);
buzbee58f92742011-10-01 11:22:17 -0700882 oatFreeTemp(cUnit, infoHi->reg);
buzbee67bf8852011-08-17 17:51:35 -0700883 if (infoHi->pair)
884 oatClobber(cUnit, infoHi->partner);
885 }
886 }
887 return loc;
888}
889
buzbeeed3e9302011-09-23 17:34:19 -0700890
891/* For use in cases we don't know (or care) width */
892extern RegLocation oatUpdateRawLoc(CompilationUnit* cUnit,
893 RegLocation loc)
894{
895 if (loc.wide)
896 return oatUpdateLocWide(cUnit, loc);
897 else
898 return oatUpdateLoc(cUnit, loc);
899}
900
901STATIC RegLocation evalLocWide(CompilationUnit* cUnit, RegLocation loc,
buzbee67bf8852011-08-17 17:51:35 -0700902 int regClass, bool update)
903{
buzbeeed3e9302011-09-23 17:34:19 -0700904 DCHECK(loc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700905 int newRegs;
906 int lowReg;
907 int highReg;
908
909 loc = oatUpdateLocWide(cUnit, loc);
910
911 /* If already in registers, we can assume proper form. Right reg class? */
912 if (loc.location == kLocPhysReg) {
buzbeee3acd072012-02-25 17:03:10 -0800913 DCHECK_EQ(oatIsFpReg(loc.lowReg), oatIsFpReg(loc.highReg));
914 DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
buzbee67bf8852011-08-17 17:51:35 -0700915 if (!regClassMatches(regClass, loc.lowReg)) {
916 /* Wrong register class. Reallocate and copy */
917 newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
918 lowReg = newRegs & 0xff;
919 highReg = (newRegs >> 8) & 0xff;
920 oatRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
921 loc.highReg);
922 copyRegInfo(cUnit, lowReg, loc.lowReg);
923 copyRegInfo(cUnit, highReg, loc.highReg);
924 oatClobber(cUnit, loc.lowReg);
925 oatClobber(cUnit, loc.highReg);
926 loc.lowReg = lowReg;
927 loc.highReg = highReg;
928 oatMarkPair(cUnit, loc.lowReg, loc.highReg);
buzbeee3acd072012-02-25 17:03:10 -0800929 DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
buzbee67bf8852011-08-17 17:51:35 -0700930 }
931 return loc;
932 }
933
buzbeeed3e9302011-09-23 17:34:19 -0700934 DCHECK_NE(loc.sRegLow, INVALID_SREG);
935 DCHECK_NE(oatSRegHi(loc.sRegLow), INVALID_SREG);
buzbee67bf8852011-08-17 17:51:35 -0700936
937 newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
938 loc.lowReg = newRegs & 0xff;
939 loc.highReg = (newRegs >> 8) & 0xff;
940
941 oatMarkPair(cUnit, loc.lowReg, loc.highReg);
942 if (update) {
943 loc.location = kLocPhysReg;
944 oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
945 oatMarkLive(cUnit, loc.highReg, oatSRegHi(loc.sRegLow));
946 }
buzbeee3acd072012-02-25 17:03:10 -0800947 DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
buzbee67bf8852011-08-17 17:51:35 -0700948 return loc;
949}
950
951extern RegLocation oatEvalLoc(CompilationUnit* cUnit, RegLocation loc,
952 int regClass, bool update)
953{
954 int newReg;
955
956 if (loc.wide)
957 return evalLocWide(cUnit, loc, regClass, update);
958
959 loc = oatUpdateLoc(cUnit, loc);
960
961 if (loc.location == kLocPhysReg) {
962 if (!regClassMatches(regClass, loc.lowReg)) {
963 /* Wrong register class. Realloc, copy and transfer ownership */
964 newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass);
965 oatRegCopy(cUnit, newReg, loc.lowReg);
966 copyRegInfo(cUnit, newReg, loc.lowReg);
967 oatClobber(cUnit, loc.lowReg);
968 loc.lowReg = newReg;
969 }
970 return loc;
971 }
972
buzbeeed3e9302011-09-23 17:34:19 -0700973 DCHECK_NE(loc.sRegLow, INVALID_SREG);
buzbee67bf8852011-08-17 17:51:35 -0700974
975 newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass);
976 loc.lowReg = newReg;
977
978 if (update) {
979 loc.location = kLocPhysReg;
980 oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
981 }
982 return loc;
983}
984
985extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir, int num)
986{
buzbeee9a72f62011-09-04 17:59:07 -0700987 RegLocation res = cUnit->regLocation[mir->ssaRep->defs[num]];
buzbeeed3e9302011-09-23 17:34:19 -0700988 DCHECK(!res.wide);
buzbeee9a72f62011-09-04 17:59:07 -0700989 return res;
buzbee67bf8852011-08-17 17:51:35 -0700990}
991extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num)
992{
buzbeee9a72f62011-09-04 17:59:07 -0700993 RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
buzbeeed3e9302011-09-23 17:34:19 -0700994 DCHECK(!res.wide);
buzbeee9a72f62011-09-04 17:59:07 -0700995 return res;
996}
997extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num)
998{
999 RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
1000 return res;
buzbee67bf8852011-08-17 17:51:35 -07001001}
1002extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir,
1003 int low, int high)
1004{
buzbeee9a72f62011-09-04 17:59:07 -07001005 RegLocation res = cUnit->regLocation[mir->ssaRep->defs[low]];
buzbeeed3e9302011-09-23 17:34:19 -07001006 DCHECK(res.wide);
buzbeee9a72f62011-09-04 17:59:07 -07001007 return res;
buzbee67bf8852011-08-17 17:51:35 -07001008}
1009
1010extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir,
1011 int low, int high)
1012{
buzbeee9a72f62011-09-04 17:59:07 -07001013 RegLocation res = cUnit->regLocation[mir->ssaRep->uses[low]];
buzbeeed3e9302011-09-23 17:34:19 -07001014 DCHECK(res.wide);
buzbeee9a72f62011-09-04 17:59:07 -07001015 return res;
buzbee67bf8852011-08-17 17:51:35 -07001016}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001017
buzbeee3acd072012-02-25 17:03:10 -08001018/* USE SSA names to count references of base Dalvik vRegs. */
1019void oatCountRefs(CompilationUnit *cUnit, BasicBlock* bb,
1020 RefCounts* coreCounts, RefCounts* fpCounts)
1021{
1022 MIR* mir;
1023 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
1024 bb->blockType != kExitBlock)
1025 return;
1026
1027 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1028 SSARepresentation *ssaRep = mir->ssaRep;
1029 if (ssaRep) {
1030 for (int i = 0; i < ssaRep->numDefs;) {
1031 RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
1032 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
1033 int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
1034 if (loc.defined) {
1035 counts[vReg].count++;
1036 }
1037 if (loc.wide) {
1038 if (loc.defined) {
1039 if (loc.fp) {
1040 counts[vReg].doubleStart = true;
1041 }
1042 counts[vReg+1].count++;
1043 }
1044 i += 2;
1045 } else {
1046 i++;
1047 }
1048 }
1049 for (int i = 0; i < ssaRep->numUses;) {
1050 RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
1051 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
1052 int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
1053 if (loc.defined) {
1054 counts[vReg].count++;
1055 }
1056 if (loc.wide) {
1057 if (loc.defined) {
1058 if (loc.fp) {
1059 counts[vReg].doubleStart = true;
1060 }
1061 counts[vReg+1].count++;
1062 }
1063 i += 2;
1064 } else {
1065 i++;
1066 }
1067 }
1068 }
1069 }
1070}
1071
1072/* qsort callback function, sort descending */
1073int oatSortCounts(const void *val1, const void *val2)
1074{
1075 const RefCounts* op1 = (const RefCounts*)val1;
1076 const RefCounts* op2 = (const RefCounts*)val2;
1077 return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
1078}
1079
1080void oatDumpCounts(const RefCounts* arr, int size, const char* msg)
1081{
1082 LOG(INFO) << msg;
1083 for (int i = 0; i < size; i++) {
1084 LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
1085 }
1086}
1087
1088/*
1089 * Note: some portions of this code required even if the kPromoteRegs
1090 * optimization is disabled.
1091 */
1092extern void oatDoPromotion(CompilationUnit* cUnit)
1093{
1094 int numRegs = cUnit->numDalvikRegisters;
1095
1096 // Allow target code to add any special registers
1097 oatAdjustSpillMask(cUnit);
1098
1099 /*
1100 * Simple register promotion. Just do a static count of the uses
1101 * of Dalvik registers. Note that we examine the SSA names, but
1102 * count based on original Dalvik register name. Count refs
1103 * separately based on type in order to give allocation
1104 * preference to fp doubles - which must be allocated sequential
1105 * physical single fp registers started with an even-numbered
1106 * reg.
1107 * TUNING: replace with linear scan once we have the ability
1108 * to describe register live ranges for GC.
1109 */
1110 RefCounts *coreRegs = (RefCounts *)
1111 oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
1112 RefCounts *fpRegs = (RefCounts *)
1113 oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
1114 for (int i = 0; i < numRegs; i++) {
1115 coreRegs[i].sReg = fpRegs[i].sReg = i;
1116 }
1117 GrowableListIterator iterator;
1118 oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
1119 while (true) {
1120 BasicBlock* bb;
1121 bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
1122 if (bb == NULL) break;
1123 oatCountRefs(cUnit, bb, coreRegs, fpRegs);
1124 }
1125
1126 /*
1127 * Ideally, we'd allocate doubles starting with an even-numbered
1128 * register. Bias the counts to try to allocate any vreg that's
1129 * used as the start of a pair first.
1130 */
1131 for (int i = 0; i < numRegs; i++) {
1132 if (fpRegs[i].doubleStart) {
1133 fpRegs[i].count *= 2;
1134 }
1135 }
1136
1137 // Sort the count arrays
1138 qsort(coreRegs, numRegs, sizeof(RefCounts), oatSortCounts);
1139 qsort(fpRegs, numRegs, sizeof(RefCounts), oatSortCounts);
1140
1141 if (cUnit->printMe) {
1142 oatDumpCounts(coreRegs, numRegs, "Core regs after sort");
1143 oatDumpCounts(fpRegs, numRegs, "Fp regs after sort");
1144 }
1145
1146 if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
1147 // Promote fpRegs
1148 for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
1149 if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
1150 if (fpRegs[i].sReg >= cUnit->numRegs) {
1151 // don't promote arg regs
1152 continue;
1153 }
1154 int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
1155 fpRegs[i].doubleStart);
1156 if (reg < 0) {
1157 break; // No more left
1158 }
1159 }
1160 }
1161
1162 // Promote core regs
1163 for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
1164 if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
1165 kLocPhysReg) {
1166 if (coreRegs[i].sReg >= cUnit->numRegs) {
1167 // don't promote arg regs
1168 continue;
1169 }
1170 int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
1171 if (reg < 0) {
1172 break; // No more left
1173 }
1174 }
1175 }
1176 }
1177
1178 // Now, update SSA names to new home locations
1179 for (int i = 0; i < cUnit->numSSARegs; i++) {
1180 RegLocation *curr = &cUnit->regLocation[i];
1181 int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
1182 if (!curr->wide) {
1183 if (curr->fp) {
1184 if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
1185 curr->location = kLocPhysReg;
1186 curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
1187 curr->home = true;
1188 }
1189 } else {
1190 if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
1191 curr->location = kLocPhysReg;
1192 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
1193 curr->home = true;
1194 }
1195 }
1196 curr->highReg = INVALID_REG;
1197 } else {
1198 if (curr->highWord) {
1199 continue;
1200 }
1201 if (curr->fp) {
1202 if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
1203 (cUnit->promotionMap[baseVReg+1].fpLocation ==
1204 kLocPhysReg)) {
1205 int lowReg = cUnit->promotionMap[baseVReg].fpReg;
1206 int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
1207 // Doubles require pair of singles starting at even reg
1208 if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
1209 curr->location = kLocPhysReg;
1210 curr->lowReg = lowReg;
1211 curr->highReg = highReg;
1212 curr->home = true;
1213 }
1214 }
1215 } else {
1216 if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
1217 && (cUnit->promotionMap[baseVReg+1].coreLocation ==
1218 kLocPhysReg)) {
1219 curr->location = kLocPhysReg;
1220 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
1221 curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
1222 curr->home = true;
1223 }
1224 }
1225 }
1226 }
1227}
1228
1229/* Returns sp-relative offset in bytes for a VReg */
1230extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
1231{
1232 return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
1233 cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
1234}
1235
1236/* Returns sp-relative offset in bytes for a SReg */
1237extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
1238{
1239 return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
1240}
1241
1242
1243/* Return sp-relative offset in bytes using Method* */
1244extern int oatVRegOffset(const DexFile::CodeItem* code_item,
1245 uint32_t core_spills, uint32_t fp_spills,
1246 size_t frame_size, int reg)
1247{
1248 int numIns = code_item->ins_size_;
1249 int numRegs = code_item->registers_size_ - numIns;
1250 int numOuts = code_item->outs_size_;
1251 int numSpills = __builtin_popcount(core_spills) +
1252 __builtin_popcount(fp_spills);
1253 int numPadding = (STACK_ALIGN_WORDS -
1254 (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
1255 int regsOffset = (numOuts + numPadding + 1) * 4;
1256 int insOffset = frame_size + 4;
1257 return (reg < numRegs) ? regsOffset + (reg << 2) :
1258 insOffset + ((reg - numRegs) << 2);
1259}
1260
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001261} // namespace art