blob: 4af3d0713ad21a357ddf4fe7a6599a91e04c37ce [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 Arm-specific register alloction support.
19 */
20
21#include "../../CompilerUtility.h"
22#include "../../CompilerIR.h"
23#include "../..//Dataflow.h"
24#include "ArmLIR.h"
25#include "Codegen.h"
26#include "../Ralloc.h"
27
28/*
29 * Placeholder routine until we do proper register allocation.
30 */
31
32typedef struct RefCounts {
33 int count;
34 int sReg;
35 bool doubleStart; // Starting vReg for a double
36} RefCounts;
37
buzbeee9a72f62011-09-04 17:59:07 -070038/* USE SSA names to count references of base Dalvik vRegs. */
buzbeeed3e9302011-09-23 17:34:19 -070039STATIC void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
buzbee67bc2362011-10-11 18:08:40 -070040 RefCounts* coreCounts, RefCounts* fpCounts)
buzbee67bf8852011-08-17 17:51:35 -070041{
42 MIR* mir;
43 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
44 bb->blockType != kExitBlock)
45 return;
46
47 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
48 SSARepresentation *ssaRep = mir->ssaRep;
49 if (ssaRep) {
buzbee67bc2362011-10-11 18:08:40 -070050 for (int i = 0; i < ssaRep->numDefs;) {
51 RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
52 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
53 int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
54 if (loc.defined) {
55 counts[vReg].count++;
buzbee3ea4ec52011-08-22 17:37:19 -070056 }
buzbee67bc2362011-10-11 18:08:40 -070057 if (loc.wide) {
58 if (loc.defined) {
59 if (loc.fp) {
60 counts[vReg].doubleStart = true;
61 }
62 counts[vReg+1].count++;
63 }
64 i += 2;
65 } else {
66 i++;
buzbee3ea4ec52011-08-22 17:37:19 -070067 }
buzbee67bf8852011-08-17 17:51:35 -070068 }
buzbee67bc2362011-10-11 18:08:40 -070069 for (int i = 0; i < ssaRep->numUses;) {
70 RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
71 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
72 int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
73 if (loc.defined) {
74 counts[vReg].count++;
buzbee67bf8852011-08-17 17:51:35 -070075 }
buzbee67bc2362011-10-11 18:08:40 -070076 if (loc.wide) {
77 if (loc.defined) {
78 if (loc.fp) {
79 counts[vReg].doubleStart = true;
80 }
81 counts[vReg+1].count++;
82 }
83 i += 2;
84 } else {
85 i++;
buzbee67bf8852011-08-17 17:51:35 -070086 }
87 }
88 }
89 }
90}
91
92/* qsort callback function, sort descending */
buzbeeed3e9302011-09-23 17:34:19 -070093STATIC int sortCounts(const void *val1, const void *val2)
buzbee67bf8852011-08-17 17:51:35 -070094{
95 const RefCounts* op1 = (const RefCounts*)val1;
96 const RefCounts* op2 = (const RefCounts*)val2;
97 return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
98}
99
buzbeeed3e9302011-09-23 17:34:19 -0700100STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
buzbee67bf8852011-08-17 17:51:35 -0700101{
102 LOG(INFO) << msg;
103 for (int i = 0; i < size; i++) {
104 LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
105 }
106}
107
108/*
109 * Note: some portions of this code required even if the kPromoteRegs
110 * optimization is disabled.
111 */
112extern void oatDoPromotion(CompilationUnit* cUnit)
113{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700114 int numRegs = cUnit->method->NumRegisters();
buzbee67bf8852011-08-17 17:51:35 -0700115
116 /*
buzbee67bf8852011-08-17 17:51:35 -0700117 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
118 * instructions might call out to C/assembly helper functions. Until
119 * machinery is in place, always spill lr.
120 */
121 cUnit->coreSpillMask |= (1 << rLR);
buzbeebbaf8942011-10-02 13:08:29 -0700122 cUnit->numCoreSpills++;
buzbee67bf8852011-08-17 17:51:35 -0700123 /*
124 * Simple hack for testing register allocation. Just do a static
125 * count of the uses of Dalvik registers. Note that we examine
126 * the SSA names, but count based on original Dalvik register name.
127 * Count refs separately based on type in order to give allocation
128 * preference to fp doubles - which must be allocated sequential
129 * physical single fp registers started with an even-numbered
130 * reg.
131 */
132 RefCounts *coreRegs = (RefCounts *)
133 oatNew(sizeof(RefCounts) * numRegs, true);
134 RefCounts *fpRegs = (RefCounts *)
135 oatNew(sizeof(RefCounts) * numRegs, true);
136 for (int i = 0; i < numRegs; i++) {
137 coreRegs[i].sReg = fpRegs[i].sReg = i;
138 }
139 GrowableListIterator iterator;
140 oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
141 while (true) {
142 BasicBlock* bb;
143 bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
144 if (bb == NULL) break;
buzbee67bc2362011-10-11 18:08:40 -0700145 countRefs(cUnit, bb, coreRegs, fpRegs);
buzbee67bf8852011-08-17 17:51:35 -0700146 }
147
148 /*
149 * Ideally, we'd allocate doubles starting with an even-numbered
150 * register. Bias the counts to try to allocate any vreg that's
151 * used as the start of a pair first.
152 */
153 for (int i = 0; i < numRegs; i++) {
154 if (fpRegs[i].doubleStart) {
155 fpRegs[i].count *= 2;
156 }
157 }
158
159 // Sort the count arrays
160 qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
161 qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
162
buzbee67bc2362011-10-11 18:08:40 -0700163 if (cUnit->printMe) {
164 dumpCounts(coreRegs, numRegs, "Core regs after sort");
165 dumpCounts(fpRegs, numRegs, "Fp regs after sort");
166 }
167
buzbee67bf8852011-08-17 17:51:35 -0700168 if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
169 // Promote fpRegs
170 for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
buzbee67bc2362011-10-11 18:08:40 -0700171 if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
buzbee67bf8852011-08-17 17:51:35 -0700172 int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
173 fpRegs[i].doubleStart);
174 if (reg < 0) {
buzbee67bc2362011-10-11 18:08:40 -0700175 break; // No more left
buzbee67bf8852011-08-17 17:51:35 -0700176 }
177 }
178 }
179
180 // Promote core regs
181 for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700182 if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
183 kLocPhysReg) {
buzbee67bf8852011-08-17 17:51:35 -0700184 int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
185 if (reg < 0) {
186 break; // No more left
187 }
188 }
189 }
190 }
191
192 // Now, update SSA names to new home locations
193 for (int i = 0; i < cUnit->numSSARegs; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700194 RegLocation *curr = &cUnit->regLocation[i];
buzbee67bc2362011-10-11 18:08:40 -0700195 int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
196 if (!curr->wide) {
197 if (curr->fp) {
198 if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
199 curr->location = kLocPhysReg;
200 curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
201 curr->home = true;
buzbee67bf8852011-08-17 17:51:35 -0700202 }
buzbee67bc2362011-10-11 18:08:40 -0700203 } else {
204 if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
205 curr->location = kLocPhysReg;
206 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
207 curr->home = true;
208 }
buzbee67bf8852011-08-17 17:51:35 -0700209 }
buzbee67bc2362011-10-11 18:08:40 -0700210 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700211 } else {
buzbee67bc2362011-10-11 18:08:40 -0700212 if (curr->highWord) {
213 continue;
214 }
215 if (curr->fp) {
216 if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
217 (cUnit->promotionMap[baseVReg+1].fpLocation ==
218 kLocPhysReg)) {
219 int lowReg = cUnit->promotionMap[baseVReg].fpReg;
220 int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
221 // Doubles require pair of singles starting at even reg
222 if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
223 curr->location = kLocPhysReg;
224 curr->lowReg = lowReg;
225 curr->highReg = highReg;
226 curr->home = true;
buzbee67bf8852011-08-17 17:51:35 -0700227 }
buzbee67bf8852011-08-17 17:51:35 -0700228 }
buzbee67bc2362011-10-11 18:08:40 -0700229 } else {
230 if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
231 && (cUnit->promotionMap[baseVReg+1].coreLocation ==
232 kLocPhysReg)) {
233 curr->location = kLocPhysReg;
234 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
235 curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
236 curr->home = true;
237 }
buzbee67bf8852011-08-17 17:51:35 -0700238 }
239 }
240 }
241}
242
buzbee67bc2362011-10-11 18:08:40 -0700243/* Returns sp-relative offset in bytes for a VReg */
244extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
buzbee67bf8852011-08-17 17:51:35 -0700245{
buzbee67bc2362011-10-11 18:08:40 -0700246 return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
247 cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
buzbee67bf8852011-08-17 17:51:35 -0700248}
249
buzbee67bc2362011-10-11 18:08:40 -0700250/* Returns sp-relative offset in bytes for a SReg */
251extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
252{
253 return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
254}
255
256
buzbeec41e5b52011-09-23 12:46:19 -0700257/* Return sp-relative offset in bytes using Method* */
258extern int oatVRegOffsetFromMethod(Method* method, int reg)
259{
260 int numIns = method->NumIns();
261 int numRegs = method->NumRegisters() - numIns;
262 int numOuts = method->NumOuts();
263 int numSpills = __builtin_popcount(method->GetCoreSpillMask()) +
264 __builtin_popcount(method->GetFpSpillMask());
265 int numPadding = (STACK_ALIGN_WORDS -
266 (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
267 int regsOffset = (numOuts + numPadding + 1) * 4;
268 int insOffset = method->GetFrameSizeInBytes() + 4;
269 return (reg < numRegs) ? regsOffset + (reg << 2) :
270 insOffset + ((reg - numRegs) << 2);
271}
buzbee67bf8852011-08-17 17:51:35 -0700272
273/* Clobber all regs that might be used by an external C call */
buzbee6181f792011-09-29 11:14:04 -0700274extern void oatClobberCalleeSave(CompilationUnit *cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700275{
276 oatClobber(cUnit, r0);
277 oatClobber(cUnit, r1);
278 oatClobber(cUnit, r2);
279 oatClobber(cUnit, r3);
280 oatClobber(cUnit, r12);
281 oatClobber(cUnit, r14lr);
282}
283
buzbee67bf8852011-08-17 17:51:35 -0700284extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
285{
286 RegLocation res = LOC_C_RETURN_WIDE;
287 oatClobber(cUnit, r0);
288 oatClobber(cUnit, r1);
289 oatMarkInUse(cUnit, r0);
290 oatMarkInUse(cUnit, r1);
291 oatMarkPair(cUnit, res.lowReg, res.highReg);
292 return res;
293}
294
295extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
296{
297 RegLocation res = LOC_C_RETURN_WIDE;
298 res.lowReg = r2;
299 res.highReg = r3;
300 oatClobber(cUnit, r2);
301 oatClobber(cUnit, r3);
302 oatMarkInUse(cUnit, r2);
303 oatMarkInUse(cUnit, r3);
304 oatMarkPair(cUnit, res.lowReg, res.highReg);
305 return res;
306}
307
308extern RegLocation oatGetReturn(CompilationUnit* cUnit)
309{
310 RegLocation res = LOC_C_RETURN;
311 oatClobber(cUnit, r0);
312 oatMarkInUse(cUnit, r0);
313 return res;
314}
315
316extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
317{
318 RegLocation res = LOC_C_RETURN;
319 res.lowReg = r1;
320 oatClobber(cUnit, r1);
321 oatMarkInUse(cUnit, r1);
322 return res;
323}
buzbee68253262011-10-07 14:02:25 -0700324
325extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
326{
327 return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
328 : &cUnit->regPool->coreRegs[reg];
329}