blob: 78d5267c614928a1fab6b1933bbe670ab113b256 [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
38/*
39 * USE SSA names to count references of base Dalvik vRegs. Also,
40 * mark "wide" in the first of wide SSA locationRec pairs.
41 */
42static void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
43 RefCounts* counts, bool fp)
44{
45 MIR* mir;
46 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
47 bb->blockType != kExitBlock)
48 return;
49
50 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
51 SSARepresentation *ssaRep = mir->ssaRep;
52 if (ssaRep) {
53 int i;
54 int attrs = oatDataFlowAttributes[mir->dalvikInsn.opcode];
55 if (fp) {
56 // Mark 1st reg of double pairs
57 int first = 0;
58 int sReg;
59 if ((attrs & (DF_DA_WIDE|DF_FP_A)) == (DF_DA_WIDE|DF_FP_A)) {
60 sReg = DECODE_REG(
61 oatConvertSSARegToDalvik(cUnit, ssaRep->defs[0]));
62 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070063 }
64 if (attrs & DF_DA_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070065 cUnit->regLocation[ssaRep->defs[0]].wide = true;
66 }
67 if ((attrs & (DF_UA_WIDE|DF_FP_A)) == (DF_UA_WIDE|DF_FP_A)) {
68 sReg = DECODE_REG(
69 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
70 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070071 }
72 if (attrs & DF_UA_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070073 cUnit->regLocation[ssaRep->uses[first]].wide = true;
74 first += 2;
75 }
76 if ((attrs & (DF_UB_WIDE|DF_FP_B)) == (DF_UB_WIDE|DF_FP_B)) {
77 sReg = DECODE_REG(
78 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
79 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070080 }
81 if (attrs & DF_UB_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070082 cUnit->regLocation[ssaRep->uses[first]].wide = true;
83 first += 2;
84 }
85 if ((attrs & (DF_UC_WIDE|DF_FP_C)) == (DF_UC_WIDE|DF_FP_C)) {
86 sReg = DECODE_REG(
87 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[first]));
88 counts[sReg].doubleStart = true;
buzbee3ea4ec52011-08-22 17:37:19 -070089 }
90 if (attrs & DF_UC_WIDE) {
buzbee67bf8852011-08-17 17:51:35 -070091 cUnit->regLocation[ssaRep->uses[first]].wide = true;
92 }
93 }
94 for (i=0; i< ssaRep->numUses; i++) {
95 int origSreg = DECODE_REG(
96 oatConvertSSARegToDalvik(cUnit, ssaRep->uses[i]));
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070097 assert(origSreg < cUnit->method->NumRegisters());
buzbee67bf8852011-08-17 17:51:35 -070098 bool fpUse = ssaRep->fpUse ? ssaRep->fpUse[i] : false;
99 if (fp == fpUse) {
100 counts[origSreg].count++;
101 }
102 }
103 for (i=0; i< ssaRep->numDefs; i++) {
104 if (attrs & DF_SETS_CONST) {
105 // CONST opcodes are untyped - don't pollute the counts
106 continue;
107 }
108 int origSreg = DECODE_REG(
109 oatConvertSSARegToDalvik(cUnit, ssaRep->defs[i]));
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700110 assert(origSreg < cUnit->method->NumRegisters());
buzbee67bf8852011-08-17 17:51:35 -0700111 bool fpDef = ssaRep->fpDef ? ssaRep->fpDef[i] : false;
112 if (fp == fpDef) {
113 counts[origSreg].count++;
114 }
115 }
116 }
117 }
118}
119
120/* qsort callback function, sort descending */
121static int sortCounts(const void *val1, const void *val2)
122{
123 const RefCounts* op1 = (const RefCounts*)val1;
124 const RefCounts* op2 = (const RefCounts*)val2;
125 return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
126}
127
128static void dumpCounts(const RefCounts* arr, int size, const char* msg)
129{
130 LOG(INFO) << msg;
131 for (int i = 0; i < size; i++) {
132 LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
133 }
134}
135
136/*
137 * Note: some portions of this code required even if the kPromoteRegs
138 * optimization is disabled.
139 */
140extern void oatDoPromotion(CompilationUnit* cUnit)
141{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700142 int numRegs = cUnit->method->NumRegisters();
143 int numIns = cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -0700144
145 /*
146 * Because ins don't have explicit definitions, we need to type
147 * them based on the signature.
148 */
149 if (numIns > 0) {
150 int sReg = numRegs - numIns;
buzbeec143c552011-08-20 17:38:58 -0700151 const art::StringPiece& shorty = cUnit->method->GetShorty();
152 for (int i = 1; i < shorty.size(); i++) {
153 char arg = shorty[i];
buzbee67bf8852011-08-17 17:51:35 -0700154 // Is it wide?
155 if ((arg == 'D') || (arg == 'J')) {
156 cUnit->regLocation[sReg].wide = true;
157 cUnit->regLocation[sReg+1].fp = cUnit->regLocation[sReg].fp;
158 sReg++; // Skip to next
159 }
160 sReg++;
161 }
162 }
163 /*
164 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
165 * instructions might call out to C/assembly helper functions. Until
166 * machinery is in place, always spill lr.
167 */
168 cUnit->coreSpillMask |= (1 << rLR);
169 cUnit->numSpills++;
170 /*
171 * Simple hack for testing register allocation. Just do a static
172 * count of the uses of Dalvik registers. Note that we examine
173 * the SSA names, but count based on original Dalvik register name.
174 * Count refs separately based on type in order to give allocation
175 * preference to fp doubles - which must be allocated sequential
176 * physical single fp registers started with an even-numbered
177 * reg.
178 */
179 RefCounts *coreRegs = (RefCounts *)
180 oatNew(sizeof(RefCounts) * numRegs, true);
181 RefCounts *fpRegs = (RefCounts *)
182 oatNew(sizeof(RefCounts) * numRegs, true);
183 for (int i = 0; i < numRegs; i++) {
184 coreRegs[i].sReg = fpRegs[i].sReg = i;
185 }
186 GrowableListIterator iterator;
187 oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
188 while (true) {
189 BasicBlock* bb;
190 bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
191 if (bb == NULL) break;
192 countRefs(cUnit, bb, coreRegs, false);
193 countRefs(cUnit, bb, fpRegs, true);
194 }
195
196 /*
197 * Ideally, we'd allocate doubles starting with an even-numbered
198 * register. Bias the counts to try to allocate any vreg that's
199 * used as the start of a pair first.
200 */
201 for (int i = 0; i < numRegs; i++) {
202 if (fpRegs[i].doubleStart) {
203 fpRegs[i].count *= 2;
204 }
205 }
206
207 // Sort the count arrays
208 qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
209 qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
210
211 // TODO: temp for debugging, too verbose. Remove when unneeded
212 if (cUnit->printMeVerbose) {
213 dumpCounts(coreRegs, numRegs, "coreRegs");
214 dumpCounts(fpRegs, numRegs, "fpRegs");
215 }
216
217 if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
218 // Promote fpRegs
219 for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
220 if (cUnit->regLocation[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
221 int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
222 fpRegs[i].doubleStart);
223 if (reg < 0) {
224 break; // No more left
225 }
226 }
227 }
228
229 // Promote core regs
230 for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
231 if (cUnit->regLocation[i].location != kLocPhysReg) {
232 int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
233 if (reg < 0) {
234 break; // No more left
235 }
236 }
237 }
238 }
239
240 // Now, update SSA names to new home locations
241 for (int i = 0; i < cUnit->numSSARegs; i++) {
242 int baseSreg = cUnit->regLocation[i].sRegLow;
243 RegLocation *base = &cUnit->regLocation[baseSreg];
244 RegLocation *baseNext = &cUnit->regLocation[baseSreg+1];
245 RegLocation *curr = &cUnit->regLocation[i];
246 if (curr->fp) {
247 /* Single or double, check fpLocation of base */
248 if (base->fpLocation == kLocPhysReg) {
249 if (curr->wide) {
250 /* TUNING: consider alignment during allocation */
buzbeedfd3d702011-08-28 12:56:51 -0700251 if ((base->fpLowReg & 1) ||
252 (baseNext->fpLocation != kLocPhysReg)) {
253 /* Half-promoted or bad alignment - demote */
254 curr->location = kLocDalvikFrame;
255 curr->lowReg = INVALID_REG;
256 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700257 continue;
258 }
259 curr->highReg = baseNext->fpLowReg;
260 }
261 curr->location = kLocPhysReg;
262 curr->lowReg = base->fpLowReg;
263 curr->home = true;
264 }
265 } else {
266 /* Core or wide */
267 if (base->location == kLocPhysReg) {
268 if (curr->wide) {
269 /* Make sure upper half is also in reg or skip */
270 if (baseNext->location != kLocPhysReg) {
buzbeedfd3d702011-08-28 12:56:51 -0700271 /* Only half promoted; demote to frame */
272 curr->location = kLocDalvikFrame;
273 curr->lowReg = INVALID_REG;
274 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700275 continue;
276 }
277 curr->highReg = baseNext->lowReg;
278 }
279 curr->location = kLocPhysReg;
280 curr->lowReg = base->lowReg;
281 curr->home = true;
282 }
283 }
284 }
285}
286
287/* Returns sp-relative offset in bytes */
288extern int oatVRegOffset(CompilationUnit* cUnit, int reg)
289{
290 return (reg < cUnit->numRegs) ? cUnit->regsOffset + (reg << 2) :
291 cUnit->insOffset + ((reg - cUnit->numRegs) << 2);
292}
293
294
295/* Clobber all regs that might be used by an external C call */
296extern void oatClobberCallRegs(CompilationUnit *cUnit)
297{
298 oatClobber(cUnit, r0);
299 oatClobber(cUnit, r1);
300 oatClobber(cUnit, r2);
301 oatClobber(cUnit, r3);
302 oatClobber(cUnit, r12);
303 oatClobber(cUnit, r14lr);
304}
305
buzbee67bf8852011-08-17 17:51:35 -0700306extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
307{
308 RegLocation res = LOC_C_RETURN_WIDE;
309 oatClobber(cUnit, r0);
310 oatClobber(cUnit, r1);
311 oatMarkInUse(cUnit, r0);
312 oatMarkInUse(cUnit, r1);
313 oatMarkPair(cUnit, res.lowReg, res.highReg);
314 return res;
315}
316
317extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
318{
319 RegLocation res = LOC_C_RETURN_WIDE;
320 res.lowReg = r2;
321 res.highReg = r3;
322 oatClobber(cUnit, r2);
323 oatClobber(cUnit, r3);
324 oatMarkInUse(cUnit, r2);
325 oatMarkInUse(cUnit, r3);
326 oatMarkPair(cUnit, res.lowReg, res.highReg);
327 return res;
328}
329
330extern RegLocation oatGetReturn(CompilationUnit* cUnit)
331{
332 RegLocation res = LOC_C_RETURN;
333 oatClobber(cUnit, r0);
334 oatMarkInUse(cUnit, r0);
335 return res;
336}
337
338extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
339{
340 RegLocation res = LOC_C_RETURN;
341 res.lowReg = r1;
342 oatClobber(cUnit, r1);
343 oatMarkInUse(cUnit, r1);
344 return res;
345}