blob: ed8a5b2ab375ba2fe99e91127f4e092ab2cc4736 [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,
buzbee67bf8852011-08-17 17:51:35 -070040 RefCounts* counts, bool fp)
41{
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) {
50 int i;
51 int attrs = oatDataFlowAttributes[mir->dalvikInsn.opcode];
52 if (fp) {
53 // Mark 1st reg of double pairs
54 int first = 0;
55 int sReg;
56 if ((attrs & (DF_DA_WIDE|DF_FP_A)) == (DF_DA_WIDE|DF_FP_A)) {
57 sReg = DECODE_REG(
58 oatConvertSSARegToDalvik(cUnit, ssaRep->defs[0]));
59 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070060 }
buzbee67bf8852011-08-17 17:51:35 -070061 if ((attrs & (DF_UA_WIDE|DF_FP_A)) == (DF_UA_WIDE|DF_FP_A)) {
62 sReg = DECODE_REG(
63 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
64 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070065 }
66 if (attrs & DF_UA_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070067 first += 2;
68 }
69 if ((attrs & (DF_UB_WIDE|DF_FP_B)) == (DF_UB_WIDE|DF_FP_B)) {
70 sReg = DECODE_REG(
71 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
72 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070073 }
74 if (attrs & DF_UB_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070075 first += 2;
76 }
77 if ((attrs & (DF_UC_WIDE|DF_FP_C)) == (DF_UC_WIDE|DF_FP_C)) {
78 sReg = DECODE_REG(
79 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
80 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070081 }
buzbee67bf8852011-08-17 17:51:35 -070082 }
83 for (i=0; i< ssaRep->numUses; i++) {
84 int origSreg = DECODE_REG(
85 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[i]));
buzbeeed3e9302011-09-23 17:34:19 -070086 DCHECK_LT(origSreg, cUnit->method->NumRegisters());
buzbee67bf8852011-08-17 17:51:35 -070087 bool fpUse = ssaRep->fpUse ? ssaRep->fpUse[i] : false;
88 if (fp == fpUse) {
89 counts[origSreg].count++;
90 }
91 }
92 for (i=0; i< ssaRep->numDefs; i++) {
93 if (attrs & DF_SETS_CONST) {
94 // CONST opcodes are untyped - don't pollute the counts
95 continue;
96 }
97 int origSreg = DECODE_REG(
98 oatConvertSSARegToDalvik(cUnit, ssaRep->defs[i]));
buzbeeed3e9302011-09-23 17:34:19 -070099 DCHECK_LT(origSreg, cUnit->method->NumRegisters());
buzbee67bf8852011-08-17 17:51:35 -0700100 bool fpDef = ssaRep->fpDef ? ssaRep->fpDef[i] : false;
101 if (fp == fpDef) {
102 counts[origSreg].count++;
103 }
104 }
105 }
106 }
107}
108
109/* qsort callback function, sort descending */
buzbeeed3e9302011-09-23 17:34:19 -0700110STATIC int sortCounts(const void *val1, const void *val2)
buzbee67bf8852011-08-17 17:51:35 -0700111{
112 const RefCounts* op1 = (const RefCounts*)val1;
113 const RefCounts* op2 = (const RefCounts*)val2;
114 return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
115}
116
buzbeeed3e9302011-09-23 17:34:19 -0700117STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
buzbee67bf8852011-08-17 17:51:35 -0700118{
119 LOG(INFO) << msg;
120 for (int i = 0; i < size; i++) {
121 LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
122 }
123}
124
125/*
126 * Note: some portions of this code required even if the kPromoteRegs
127 * optimization is disabled.
128 */
129extern void oatDoPromotion(CompilationUnit* cUnit)
130{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700131 int numRegs = cUnit->method->NumRegisters();
buzbee67bf8852011-08-17 17:51:35 -0700132
133 /*
buzbee67bf8852011-08-17 17:51:35 -0700134 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
135 * instructions might call out to C/assembly helper functions. Until
136 * machinery is in place, always spill lr.
137 */
138 cUnit->coreSpillMask |= (1 << rLR);
buzbeebbaf8942011-10-02 13:08:29 -0700139 cUnit->numCoreSpills++;
buzbee67bf8852011-08-17 17:51:35 -0700140 /*
141 * Simple hack for testing register allocation. Just do a static
142 * count of the uses of Dalvik registers. Note that we examine
143 * the SSA names, but count based on original Dalvik register name.
144 * Count refs separately based on type in order to give allocation
145 * preference to fp doubles - which must be allocated sequential
146 * physical single fp registers started with an even-numbered
147 * reg.
148 */
149 RefCounts *coreRegs = (RefCounts *)
150 oatNew(sizeof(RefCounts) * numRegs, true);
151 RefCounts *fpRegs = (RefCounts *)
152 oatNew(sizeof(RefCounts) * numRegs, true);
153 for (int i = 0; i < numRegs; i++) {
154 coreRegs[i].sReg = fpRegs[i].sReg = i;
155 }
156 GrowableListIterator iterator;
157 oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
158 while (true) {
159 BasicBlock* bb;
160 bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
161 if (bb == NULL) break;
162 countRefs(cUnit, bb, coreRegs, false);
163 countRefs(cUnit, bb, fpRegs, true);
164 }
165
166 /*
167 * Ideally, we'd allocate doubles starting with an even-numbered
168 * register. Bias the counts to try to allocate any vreg that's
169 * used as the start of a pair first.
170 */
171 for (int i = 0; i < numRegs; i++) {
172 if (fpRegs[i].doubleStart) {
173 fpRegs[i].count *= 2;
174 }
175 }
176
177 // Sort the count arrays
178 qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
179 qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
180
buzbee67bf8852011-08-17 17:51:35 -0700181 if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
182 // Promote fpRegs
183 for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
184 if (cUnit->regLocation[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
185 int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
186 fpRegs[i].doubleStart);
187 if (reg < 0) {
188 break; // No more left
189 }
190 }
191 }
192
193 // Promote core regs
194 for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
195 if (cUnit->regLocation[i].location != kLocPhysReg) {
196 int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
197 if (reg < 0) {
198 break; // No more left
199 }
200 }
201 }
202 }
203
204 // Now, update SSA names to new home locations
205 for (int i = 0; i < cUnit->numSSARegs; i++) {
206 int baseSreg = cUnit->regLocation[i].sRegLow;
207 RegLocation *base = &cUnit->regLocation[baseSreg];
208 RegLocation *baseNext = &cUnit->regLocation[baseSreg+1];
209 RegLocation *curr = &cUnit->regLocation[i];
210 if (curr->fp) {
211 /* Single or double, check fpLocation of base */
212 if (base->fpLocation == kLocPhysReg) {
213 if (curr->wide) {
214 /* TUNING: consider alignment during allocation */
buzbeedfd3d702011-08-28 12:56:51 -0700215 if ((base->fpLowReg & 1) ||
216 (baseNext->fpLocation != kLocPhysReg)) {
217 /* Half-promoted or bad alignment - demote */
218 curr->location = kLocDalvikFrame;
219 curr->lowReg = INVALID_REG;
220 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700221 continue;
222 }
223 curr->highReg = baseNext->fpLowReg;
224 }
225 curr->location = kLocPhysReg;
226 curr->lowReg = base->fpLowReg;
227 curr->home = true;
228 }
229 } else {
230 /* Core or wide */
231 if (base->location == kLocPhysReg) {
232 if (curr->wide) {
233 /* Make sure upper half is also in reg or skip */
234 if (baseNext->location != kLocPhysReg) {
buzbeedfd3d702011-08-28 12:56:51 -0700235 /* Only half promoted; demote to frame */
236 curr->location = kLocDalvikFrame;
237 curr->lowReg = INVALID_REG;
238 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700239 continue;
240 }
241 curr->highReg = baseNext->lowReg;
242 }
243 curr->location = kLocPhysReg;
244 curr->lowReg = base->lowReg;
245 curr->home = true;
246 }
247 }
248 }
249}
250
251/* Returns sp-relative offset in bytes */
252extern int oatVRegOffset(CompilationUnit* cUnit, int reg)
253{
254 return (reg < cUnit->numRegs) ? cUnit->regsOffset + (reg << 2) :
255 cUnit->insOffset + ((reg - cUnit->numRegs) << 2);
256}
257
buzbeec41e5b52011-09-23 12:46:19 -0700258/* Return sp-relative offset in bytes using Method* */
259extern int oatVRegOffsetFromMethod(Method* method, int reg)
260{
261 int numIns = method->NumIns();
262 int numRegs = method->NumRegisters() - numIns;
263 int numOuts = method->NumOuts();
264 int numSpills = __builtin_popcount(method->GetCoreSpillMask()) +
265 __builtin_popcount(method->GetFpSpillMask());
266 int numPadding = (STACK_ALIGN_WORDS -
267 (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
268 int regsOffset = (numOuts + numPadding + 1) * 4;
269 int insOffset = method->GetFrameSizeInBytes() + 4;
270 return (reg < numRegs) ? regsOffset + (reg << 2) :
271 insOffset + ((reg - numRegs) << 2);
272}
buzbee67bf8852011-08-17 17:51:35 -0700273
274/* Clobber all regs that might be used by an external C call */
buzbee6181f792011-09-29 11:14:04 -0700275extern void oatClobberCalleeSave(CompilationUnit *cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700276{
277 oatClobber(cUnit, r0);
278 oatClobber(cUnit, r1);
279 oatClobber(cUnit, r2);
280 oatClobber(cUnit, r3);
281 oatClobber(cUnit, r12);
282 oatClobber(cUnit, r14lr);
283}
284
buzbee67bf8852011-08-17 17:51:35 -0700285extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
286{
287 RegLocation res = LOC_C_RETURN_WIDE;
288 oatClobber(cUnit, r0);
289 oatClobber(cUnit, r1);
290 oatMarkInUse(cUnit, r0);
291 oatMarkInUse(cUnit, r1);
292 oatMarkPair(cUnit, res.lowReg, res.highReg);
293 return res;
294}
295
296extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
297{
298 RegLocation res = LOC_C_RETURN_WIDE;
299 res.lowReg = r2;
300 res.highReg = r3;
301 oatClobber(cUnit, r2);
302 oatClobber(cUnit, r3);
303 oatMarkInUse(cUnit, r2);
304 oatMarkInUse(cUnit, r3);
305 oatMarkPair(cUnit, res.lowReg, res.highReg);
306 return res;
307}
308
309extern RegLocation oatGetReturn(CompilationUnit* cUnit)
310{
311 RegLocation res = LOC_C_RETURN;
312 oatClobber(cUnit, r0);
313 oatMarkInUse(cUnit, r0);
314 return res;
315}
316
317extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
318{
319 RegLocation res = LOC_C_RETURN;
320 res.lowReg = r1;
321 oatClobber(cUnit, r1);
322 oatMarkInUse(cUnit, r1);
323 return res;
324}
buzbee68253262011-10-07 14:02:25 -0700325
326extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
327{
328 return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
329 : &cUnit->regPool->coreRegs[reg];
330}