blob: a193a7c7f9d4ae7f9753f5c9020fac8befa3ee59 [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/*
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080018 * This file contains Arm-specific register allocation support.
buzbee67bf8852011-08-17 17:51:35 -070019 */
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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080028namespace art {
29
buzbee67bf8852011-08-17 17:51:35 -070030/*
31 * Placeholder routine until we do proper register allocation.
32 */
33
34typedef struct RefCounts {
35 int count;
36 int sReg;
37 bool doubleStart; // Starting vReg for a double
38} RefCounts;
39
buzbeee9a72f62011-09-04 17:59:07 -070040/* USE SSA names to count references of base Dalvik vRegs. */
buzbeeed3e9302011-09-23 17:34:19 -070041STATIC void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
buzbee67bc2362011-10-11 18:08:40 -070042 RefCounts* coreCounts, RefCounts* fpCounts)
buzbee67bf8852011-08-17 17:51:35 -070043{
44 MIR* mir;
45 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
46 bb->blockType != kExitBlock)
47 return;
48
49 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
50 SSARepresentation *ssaRep = mir->ssaRep;
51 if (ssaRep) {
buzbee67bc2362011-10-11 18:08:40 -070052 for (int i = 0; i < ssaRep->numDefs;) {
53 RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
54 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
55 int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
56 if (loc.defined) {
57 counts[vReg].count++;
buzbee3ea4ec52011-08-22 17:37:19 -070058 }
buzbee67bc2362011-10-11 18:08:40 -070059 if (loc.wide) {
60 if (loc.defined) {
61 if (loc.fp) {
62 counts[vReg].doubleStart = true;
63 }
64 counts[vReg+1].count++;
65 }
66 i += 2;
67 } else {
68 i++;
buzbee3ea4ec52011-08-22 17:37:19 -070069 }
buzbee67bf8852011-08-17 17:51:35 -070070 }
buzbee67bc2362011-10-11 18:08:40 -070071 for (int i = 0; i < ssaRep->numUses;) {
72 RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
73 RefCounts* counts = loc.fp ? fpCounts : coreCounts;
74 int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
75 if (loc.defined) {
76 counts[vReg].count++;
buzbee67bf8852011-08-17 17:51:35 -070077 }
buzbee67bc2362011-10-11 18:08:40 -070078 if (loc.wide) {
79 if (loc.defined) {
80 if (loc.fp) {
81 counts[vReg].doubleStart = true;
82 }
83 counts[vReg+1].count++;
84 }
85 i += 2;
86 } else {
87 i++;
buzbee67bf8852011-08-17 17:51:35 -070088 }
89 }
90 }
91 }
92}
93
94/* qsort callback function, sort descending */
buzbeeed3e9302011-09-23 17:34:19 -070095STATIC int sortCounts(const void *val1, const void *val2)
buzbee67bf8852011-08-17 17:51:35 -070096{
97 const RefCounts* op1 = (const RefCounts*)val1;
98 const RefCounts* op2 = (const RefCounts*)val2;
99 return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
100}
101
buzbeeed3e9302011-09-23 17:34:19 -0700102STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
buzbee67bf8852011-08-17 17:51:35 -0700103{
104 LOG(INFO) << msg;
105 for (int i = 0; i < size; i++) {
106 LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
107 }
108}
109
110/*
111 * Note: some portions of this code required even if the kPromoteRegs
112 * optimization is disabled.
113 */
114extern void oatDoPromotion(CompilationUnit* cUnit)
115{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800116 int numRegs = cUnit->numDalvikRegisters;
buzbee67bf8852011-08-17 17:51:35 -0700117
118 /*
buzbee67bf8852011-08-17 17:51:35 -0700119 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
120 * instructions might call out to C/assembly helper functions. Until
121 * machinery is in place, always spill lr.
122 */
123 cUnit->coreSpillMask |= (1 << rLR);
buzbeebbaf8942011-10-02 13:08:29 -0700124 cUnit->numCoreSpills++;
buzbee67bf8852011-08-17 17:51:35 -0700125 /*
126 * Simple hack for testing register allocation. Just do a static
127 * count of the uses of Dalvik registers. Note that we examine
128 * the SSA names, but count based on original Dalvik register name.
129 * Count refs separately based on type in order to give allocation
130 * preference to fp doubles - which must be allocated sequential
131 * physical single fp registers started with an even-numbered
132 * reg.
133 */
134 RefCounts *coreRegs = (RefCounts *)
135 oatNew(sizeof(RefCounts) * numRegs, true);
136 RefCounts *fpRegs = (RefCounts *)
137 oatNew(sizeof(RefCounts) * numRegs, true);
138 for (int i = 0; i < numRegs; i++) {
139 coreRegs[i].sReg = fpRegs[i].sReg = i;
140 }
141 GrowableListIterator iterator;
142 oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
143 while (true) {
144 BasicBlock* bb;
145 bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
146 if (bb == NULL) break;
buzbee67bc2362011-10-11 18:08:40 -0700147 countRefs(cUnit, bb, coreRegs, fpRegs);
buzbee67bf8852011-08-17 17:51:35 -0700148 }
149
150 /*
151 * Ideally, we'd allocate doubles starting with an even-numbered
152 * register. Bias the counts to try to allocate any vreg that's
153 * used as the start of a pair first.
154 */
155 for (int i = 0; i < numRegs; i++) {
156 if (fpRegs[i].doubleStart) {
157 fpRegs[i].count *= 2;
158 }
159 }
160
161 // Sort the count arrays
162 qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
163 qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
164
buzbee67bc2362011-10-11 18:08:40 -0700165 if (cUnit->printMe) {
166 dumpCounts(coreRegs, numRegs, "Core regs after sort");
167 dumpCounts(fpRegs, numRegs, "Fp regs after sort");
168 }
169
buzbee67bf8852011-08-17 17:51:35 -0700170 if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
171 // Promote fpRegs
172 for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
buzbee67bc2362011-10-11 18:08:40 -0700173 if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
buzbeea50638b2011-11-02 15:15:06 -0700174 if (fpRegs[i].sReg >= cUnit->numRegs) {
175 // don't promote arg regs
176 continue;
177 }
buzbee67bf8852011-08-17 17:51:35 -0700178 int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
179 fpRegs[i].doubleStart);
180 if (reg < 0) {
buzbee67bc2362011-10-11 18:08:40 -0700181 break; // No more left
buzbee67bf8852011-08-17 17:51:35 -0700182 }
183 }
184 }
185
186 // Promote core regs
187 for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700188 if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
189 kLocPhysReg) {
buzbeea50638b2011-11-02 15:15:06 -0700190 if (coreRegs[i].sReg >= cUnit->numRegs) {
191 // don't promote arg regs
192 continue;
193 }
buzbee67bf8852011-08-17 17:51:35 -0700194 int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
195 if (reg < 0) {
196 break; // No more left
197 }
198 }
199 }
200 }
201
202 // Now, update SSA names to new home locations
203 for (int i = 0; i < cUnit->numSSARegs; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700204 RegLocation *curr = &cUnit->regLocation[i];
buzbee67bc2362011-10-11 18:08:40 -0700205 int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
206 if (!curr->wide) {
207 if (curr->fp) {
208 if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
209 curr->location = kLocPhysReg;
210 curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
211 curr->home = true;
buzbee67bf8852011-08-17 17:51:35 -0700212 }
buzbee67bc2362011-10-11 18:08:40 -0700213 } else {
214 if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
215 curr->location = kLocPhysReg;
216 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
217 curr->home = true;
218 }
buzbee67bf8852011-08-17 17:51:35 -0700219 }
buzbee67bc2362011-10-11 18:08:40 -0700220 curr->highReg = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700221 } else {
buzbee67bc2362011-10-11 18:08:40 -0700222 if (curr->highWord) {
223 continue;
224 }
225 if (curr->fp) {
226 if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
227 (cUnit->promotionMap[baseVReg+1].fpLocation ==
228 kLocPhysReg)) {
229 int lowReg = cUnit->promotionMap[baseVReg].fpReg;
230 int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
231 // Doubles require pair of singles starting at even reg
232 if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
233 curr->location = kLocPhysReg;
234 curr->lowReg = lowReg;
235 curr->highReg = highReg;
236 curr->home = true;
buzbee67bf8852011-08-17 17:51:35 -0700237 }
buzbee67bf8852011-08-17 17:51:35 -0700238 }
buzbee67bc2362011-10-11 18:08:40 -0700239 } else {
240 if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
241 && (cUnit->promotionMap[baseVReg+1].coreLocation ==
242 kLocPhysReg)) {
243 curr->location = kLocPhysReg;
244 curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
245 curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
246 curr->home = true;
247 }
buzbee67bf8852011-08-17 17:51:35 -0700248 }
249 }
250 }
251}
252
buzbee67bc2362011-10-11 18:08:40 -0700253/* Returns sp-relative offset in bytes for a VReg */
254extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
buzbee67bf8852011-08-17 17:51:35 -0700255{
buzbee67bc2362011-10-11 18:08:40 -0700256 return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
257 cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
buzbee67bf8852011-08-17 17:51:35 -0700258}
259
buzbee67bc2362011-10-11 18:08:40 -0700260/* Returns sp-relative offset in bytes for a SReg */
261extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
262{
263 return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
264}
265
266
buzbeec41e5b52011-09-23 12:46:19 -0700267/* Return sp-relative offset in bytes using Method* */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800268extern int oatVRegOffset(const DexFile::CodeItem* code_item,
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800269 uint32_t core_spills, uint32_t fp_spills,
270 size_t frame_size, int reg)
buzbeec41e5b52011-09-23 12:46:19 -0700271{
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800272 int numIns = code_item->ins_size_;
273 int numRegs = code_item->registers_size_ - numIns;
274 int numOuts = code_item->outs_size_;
275 int numSpills = __builtin_popcount(core_spills) +
276 __builtin_popcount(fp_spills);
buzbeec41e5b52011-09-23 12:46:19 -0700277 int numPadding = (STACK_ALIGN_WORDS -
278 (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
279 int regsOffset = (numOuts + numPadding + 1) * 4;
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800280 int insOffset = frame_size + 4;
buzbeec41e5b52011-09-23 12:46:19 -0700281 return (reg < numRegs) ? regsOffset + (reg << 2) :
282 insOffset + ((reg - numRegs) << 2);
283}
buzbee67bf8852011-08-17 17:51:35 -0700284
285/* Clobber all regs that might be used by an external C call */
buzbee6181f792011-09-29 11:14:04 -0700286extern void oatClobberCalleeSave(CompilationUnit *cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700287{
288 oatClobber(cUnit, r0);
289 oatClobber(cUnit, r1);
290 oatClobber(cUnit, r2);
291 oatClobber(cUnit, r3);
292 oatClobber(cUnit, r12);
293 oatClobber(cUnit, r14lr);
294}
295
buzbee67bf8852011-08-17 17:51:35 -0700296extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
297{
298 RegLocation res = LOC_C_RETURN_WIDE;
299 oatClobber(cUnit, r0);
300 oatClobber(cUnit, r1);
301 oatMarkInUse(cUnit, r0);
302 oatMarkInUse(cUnit, r1);
303 oatMarkPair(cUnit, res.lowReg, res.highReg);
304 return res;
305}
306
307extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
308{
309 RegLocation res = LOC_C_RETURN_WIDE;
310 res.lowReg = r2;
311 res.highReg = r3;
312 oatClobber(cUnit, r2);
313 oatClobber(cUnit, r3);
314 oatMarkInUse(cUnit, r2);
315 oatMarkInUse(cUnit, r3);
316 oatMarkPair(cUnit, res.lowReg, res.highReg);
317 return res;
318}
319
320extern RegLocation oatGetReturn(CompilationUnit* cUnit)
321{
322 RegLocation res = LOC_C_RETURN;
323 oatClobber(cUnit, r0);
324 oatMarkInUse(cUnit, r0);
325 return res;
326}
327
328extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
329{
330 RegLocation res = LOC_C_RETURN;
331 res.lowReg = r1;
332 oatClobber(cUnit, r1);
333 oatMarkInUse(cUnit, r1);
334 return res;
335}
buzbee68253262011-10-07 14:02:25 -0700336
337extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
338{
339 return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
340 : &cUnit->regPool->coreRegs[reg];
341}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800342
343} // namespace art