blob: 4e903828130f92f77234e5bd10fe2f33892bc96f [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#include "Dalvik.h"
18#include "CompilerInternals.h"
19#include "Dataflow.h"
20#include "codegen/Ralloc.h"
21
buzbeeed3e9302011-09-23 17:34:19 -070022STATIC bool setFp(CompilationUnit* cUnit, int index, bool isFP) {
buzbee03fa2632011-09-20 17:10:57 -070023 bool change = false;
buzbee67bc2362011-10-11 18:08:40 -070024 if (cUnit->regLocation[index].highWord) {
25 return change;
26 }
buzbee03fa2632011-09-20 17:10:57 -070027 if (isFP && !cUnit->regLocation[index].fp) {
28 cUnit->regLocation[index].fp = true;
buzbee67bc2362011-10-11 18:08:40 -070029 cUnit->regLocation[index].defined = true;
30 change = true;
31 }
32 return change;
33}
34
35STATIC bool setCore(CompilationUnit* cUnit, int index, bool isCore) {
36 bool change = false;
37 if (cUnit->regLocation[index].highWord) {
38 return change;
39 }
40 if (isCore && !cUnit->regLocation[index].defined) {
41 cUnit->regLocation[index].core = true;
42 cUnit->regLocation[index].defined = true;
buzbee03fa2632011-09-20 17:10:57 -070043 change = true;
44 }
45 return change;
46}
47
buzbeec0ecd652011-09-25 18:11:54 -070048STATIC bool remapNames(CompilationUnit* cUnit, BasicBlock* bb)
49{
50 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
51 bb->blockType != kExitBlock)
52 return false;
53
54 for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
55 SSARepresentation *ssaRep = mir->ssaRep;
56 if (ssaRep) {
57 for (int i = 0; i < ssaRep->numUses; i++) {
58 ssaRep->uses[i] = cUnit->phiAliasMap[ssaRep->uses[i]];
59 }
60 for (int i = 0; i < ssaRep->numDefs; i++) {
61 ssaRep->defs[i] = cUnit->phiAliasMap[ssaRep->defs[i]];
62 }
63 }
64 }
65 return false;
66}
67
buzbee769fde12012-01-05 17:35:23 -080068// Try to find the next move result which might have an FP target
69STATIC SSARepresentation* findMoveResult(MIR* mir)
70{
71 SSARepresentation* res = NULL;
72 for (; mir; mir = mir->next) {
73 if ((mir->dalvikInsn.opcode == OP_MOVE_RESULT) ||
74 (mir->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
75 res = mir->ssaRep;
76 break;
77 }
78 }
79 return res;
80}
81
buzbee67bf8852011-08-17 17:51:35 -070082/*
buzbee03fa2632011-09-20 17:10:57 -070083 * Infer types and sizes. We don't need to track change on sizes,
84 * as it doesn't propagate. We're guaranteed at least one pass through
85 * the cfg.
buzbee67bf8852011-08-17 17:51:35 -070086 */
buzbeeed3e9302011-09-23 17:34:19 -070087STATIC bool inferTypeAndSize(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -070088{
89 MIR *mir;
buzbee03fa2632011-09-20 17:10:57 -070090 bool changed = false; // Did anything change?
91
92 if (bb->dataFlowInfo == NULL) return false;
buzbee67bf8852011-08-17 17:51:35 -070093 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock)
buzbee03fa2632011-09-20 17:10:57 -070094 return false;
buzbee67bf8852011-08-17 17:51:35 -070095
96 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
97 SSARepresentation *ssaRep = mir->ssaRep;
98 if (ssaRep) {
buzbee03fa2632011-09-20 17:10:57 -070099 int attrs = oatDataFlowAttributes[mir->dalvikInsn.opcode];
buzbee67bc2362011-10-11 18:08:40 -0700100
101 // Handle defs
102 if (attrs & (DF_DA | DF_DA_WIDE)) {
103 if (attrs & DF_CORE_A) {
104 changed |= setCore(cUnit, ssaRep->defs[0], true);
105 }
106 if (attrs & DF_DA_WIDE) {
107 cUnit->regLocation[ssaRep->defs[0]].wide = true;
108 cUnit->regLocation[ssaRep->defs[1]].highWord = true;
109 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->defs[0])+1,
110 oatS2VReg(cUnit, ssaRep->defs[1]));
111 }
112 }
113
114 // Handles uses
buzbee03fa2632011-09-20 17:10:57 -0700115 int next = 0;
buzbee67bc2362011-10-11 18:08:40 -0700116 if (attrs & (DF_UA | DF_UA_WIDE)) {
117 if (attrs & DF_CORE_A) {
118 changed |= setCore(cUnit, ssaRep->uses[next], true);
119 }
120 if (attrs & DF_UA_WIDE) {
121 cUnit->regLocation[ssaRep->uses[next]].wide = true;
122 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
123 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
124 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
125 next += 2;
126 } else {
127 next++;
128 }
buzbee67bf8852011-08-17 17:51:35 -0700129 }
buzbee67bc2362011-10-11 18:08:40 -0700130 if (attrs & (DF_UB | DF_UB_WIDE)) {
131 if (attrs & DF_CORE_B) {
132 changed |= setCore(cUnit, ssaRep->uses[next], true);
133 }
134 if (attrs & DF_UB_WIDE) {
135 cUnit->regLocation[ssaRep->uses[next]].wide = true;
136 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
137 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
138 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
139 next += 2;
140 } else {
141 next++;
142 }
buzbee03fa2632011-09-20 17:10:57 -0700143 }
buzbee67bc2362011-10-11 18:08:40 -0700144 if (attrs & (DF_UC | DF_UC_WIDE)) {
145 if (attrs & DF_CORE_C) {
146 changed |= setCore(cUnit, ssaRep->uses[next], true);
147 }
148 if (attrs & DF_UC_WIDE) {
149 cUnit->regLocation[ssaRep->uses[next]].wide = true;
150 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
151 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
152 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
153 }
buzbee03fa2632011-09-20 17:10:57 -0700154 }
buzbeeed3e9302011-09-23 17:34:19 -0700155
buzbee769fde12012-01-05 17:35:23 -0800156 // Special-case handling for format 35c/3rc invokes
157 Opcode opcode = mir->dalvikInsn.opcode;
158 int flags = (opcode >= kNumPackedOpcodes) ? 0 :
buzbeeed3e9302011-09-23 17:34:19 -0700159 dexGetFlagsFromOpcode(opcode);
160 if ((flags & kInstrInvoke) &&
161 (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
162 DCHECK_EQ(next, 0);
163 int target_idx = mir->dalvikInsn.vB;
164 const char* shorty =
165 oatGetShortyFromTargetIdx(cUnit, target_idx);
buzbee769fde12012-01-05 17:35:23 -0800166 // Handle result type if floating point
167 if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
168 // Find move-result that consumes this result
169 SSARepresentation* tgtRep = findMoveResult(mir->next);
170 // Might be in next basic block
171 if (!tgtRep) {
172 tgtRep = findMoveResult(bb->fallThrough->firstMIRInsn);
173 }
174 // Result might not be used at all, so no move-result
175 if (tgtRep) {
176 tgtRep->fpDef[0] = true;
177 changed |= setFp(cUnit, tgtRep->defs[0], true);
178 if (shorty[0] == 'D') {
179 tgtRep->fpDef[1] = true;
180 changed |= setFp(cUnit, tgtRep->defs[1], true);
181 }
182 }
183 }
buzbeeed3e9302011-09-23 17:34:19 -0700184 int numUses = mir->dalvikInsn.vA;
185 // If this is a non-static invoke, skip implicit "this"
186 if (((mir->dalvikInsn.opcode != OP_INVOKE_STATIC) &&
187 (mir->dalvikInsn.opcode != OP_INVOKE_STATIC_RANGE))) {
buzbee67bc2362011-10-11 18:08:40 -0700188 cUnit->regLocation[ssaRep->uses[next]].defined = true;
189 cUnit->regLocation[ssaRep->uses[next]].core = true;
buzbeeed3e9302011-09-23 17:34:19 -0700190 next++;
191 }
192 uint32_t cpos = 1;
193 if (strlen(shorty) > 1) {
194 for (int i = next; i < numUses;) {
195 DCHECK_LT(cpos, strlen(shorty));
196 switch(shorty[cpos++]) {
197 case 'D':
198 ssaRep->fpUse[i] = true;
199 ssaRep->fpUse[i+1] = true;
200 cUnit->regLocation[ssaRep->uses[i]].wide = true;
buzbee67bc2362011-10-11 18:08:40 -0700201 cUnit->regLocation[ssaRep->uses[i+1]].highWord
202 = true;
203 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[i])+1,
204 oatS2VReg(cUnit, ssaRep->uses[i+1]));
buzbeeed3e9302011-09-23 17:34:19 -0700205 i++;
206 break;
207 case 'J':
208 cUnit->regLocation[ssaRep->uses[i]].wide = true;
buzbee67bc2362011-10-11 18:08:40 -0700209 cUnit->regLocation[ssaRep->uses[i+1]].highWord
210 = true;
211 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[i])+1,
212 oatS2VReg(cUnit, ssaRep->uses[i+1]));
213 changed |= setCore(cUnit, ssaRep->uses[i],true);
buzbeeed3e9302011-09-23 17:34:19 -0700214 i++;
215 break;
216 case 'F':
217 ssaRep->fpUse[i] = true;
218 break;
219 default:
buzbee67bc2362011-10-11 18:08:40 -0700220 changed |= setCore(cUnit,ssaRep->uses[i], true);
buzbeeed3e9302011-09-23 17:34:19 -0700221 break;
222 }
223 i++;
224 }
225 }
226 }
227
buzbee03fa2632011-09-20 17:10:57 -0700228 for (int i=0; ssaRep->fpUse && i< ssaRep->numUses; i++) {
229 if (ssaRep->fpUse[i])
230 changed |= setFp(cUnit, ssaRep->uses[i], true);
231 }
232 for (int i=0; ssaRep->fpDef && i< ssaRep->numDefs; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700233 if (ssaRep->fpDef[i])
buzbee03fa2632011-09-20 17:10:57 -0700234 changed |= setFp(cUnit, ssaRep->defs[i], true);
235 }
236 // Special-case handling for moves & Phi
237 if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
buzbee67bc2362011-10-11 18:08:40 -0700238 // If any of our inputs or outputs is defined, set all
239 bool definedFP = false;
240 bool definedCore = false;
241 definedFP |= (cUnit->regLocation[ssaRep->defs[0]].defined &&
242 cUnit->regLocation[ssaRep->defs[0]].fp);
243 definedCore |= (cUnit->regLocation[ssaRep->defs[0]].defined &&
244 cUnit->regLocation[ssaRep->defs[0]].core);
buzbee03fa2632011-09-20 17:10:57 -0700245 for (int i = 0; i < ssaRep->numUses; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700246 definedFP |= (cUnit->regLocation[ssaRep->uses[i]].defined &&
247 cUnit->regLocation[ssaRep->uses[i]].fp);
248 definedCore |= (cUnit->regLocation[ssaRep->uses[i]].defined
249 && cUnit->regLocation[ssaRep->uses[i]].core);
buzbee03fa2632011-09-20 17:10:57 -0700250 }
buzbee23d5bc92011-10-31 12:41:02 -0700251 /*
252 * TODO: cleaner fix
253 * We don't normally expect to see a Dalvik register
254 * definition used both as a floating point and core
255 * value. However, the instruction rewriting that occurs
256 * during verification can eliminate some type information,
257 * leaving us confused. The real fix here is either to
258 * add explicit type information to Dalvik byte codes,
259 * or to recognize OP_THROW_VERIFICATION_ERROR as
260 * an unconditional branch and support dead code elimination.
261 * As a workaround we can detect this situation and
262 * disable register promotion (which is the only thing that
263 * relies on distinctions between core and fp usages.
264 */
265 if ((definedFP && definedCore) &&
266 ((cUnit->disableOpt & (1 << kPromoteRegs)) == 0)) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800267 LOG(WARNING) << art::PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
buzbee23d5bc92011-10-31 12:41:02 -0700268 << " op at block " << bb->id
269 << " has both fp and core uses for same def.";
270 cUnit->disableOpt |= (1 << kPromoteRegs);
271 }
buzbee67bc2362011-10-11 18:08:40 -0700272 changed |= setFp(cUnit, ssaRep->defs[0], definedFP);
273 changed |= setCore(cUnit, ssaRep->defs[0], definedCore);
buzbee03fa2632011-09-20 17:10:57 -0700274 for (int i = 0; i < ssaRep->numUses; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700275 changed |= setFp(cUnit, ssaRep->uses[i], definedFP);
276 changed |= setCore(cUnit, ssaRep->uses[i], definedCore);
buzbee03fa2632011-09-20 17:10:57 -0700277 }
buzbee67bf8852011-08-17 17:51:35 -0700278 }
279 }
280 }
buzbee03fa2632011-09-20 17:10:57 -0700281 return changed;
buzbee67bf8852011-08-17 17:51:35 -0700282}
283
284static const char* storageName[] = {" Frame ", "PhysReg", " Spill "};
285
buzbeedfd3d702011-08-28 12:56:51 -0700286void oatDumpRegLocTable(RegLocation* table, int count)
buzbee67bf8852011-08-17 17:51:35 -0700287{
288 for (int i = 0; i < count; i++) {
289 char buf[100];
buzbee67bc2362011-10-11 18:08:40 -0700290 snprintf(buf, 100, "Loc[%02d] : %s, %c %c %c %c %c %c%d %c%d S%d",
buzbee67bf8852011-08-17 17:51:35 -0700291 i, storageName[table[i].location], table[i].wide ? 'W' : 'N',
buzbee67bc2362011-10-11 18:08:40 -0700292 table[i].defined ? 'D' : 'U', table[i].fp ? 'F' : 'C',
293 table[i].highWord ? 'H' : 'L', table[i].home ? 'h' : 't',
294 FPREG(table[i].lowReg) ? 's' : 'r', table[i].lowReg & FP_REG_MASK,
295 FPREG(table[i].highReg) ? 's' : 'r', table[i].highReg & FP_REG_MASK,
296 table[i].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700297 LOG(INFO) << buf;
298 }
299}
300
buzbee67bc2362011-10-11 18:08:40 -0700301static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0,
302 INVALID_REG, INVALID_REG, INVALID_SREG};
buzbee67bf8852011-08-17 17:51:35 -0700303
304/*
305 * Simple register allocation. Some Dalvik virtual registers may
306 * be promoted to physical registers. Most of the work for temp
307 * allocation is done on the fly. We also do some initilization and
308 * type inference here.
309 */
310void oatSimpleRegAlloc(CompilationUnit* cUnit)
311{
312 int i;
313 RegLocation* loc;
314
315 /* Allocate the location map */
316 loc = (RegLocation*)oatNew(cUnit->numSSARegs * sizeof(*loc), true);
317 for (i=0; i< cUnit->numSSARegs; i++) {
318 loc[i] = freshLoc;
319 loc[i].sRegLow = i;
320 }
321 cUnit->regLocation = loc;
322
buzbee67bc2362011-10-11 18:08:40 -0700323 /* Allocation the promotion map */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800324 int numRegs = cUnit->numDalvikRegisters;
325 cUnit->promotionMap =
326 (PromotionMap*)oatNew(numRegs * sizeof(cUnit->promotionMap[0]), true);
buzbee67bc2362011-10-11 18:08:40 -0700327
buzbeee9a72f62011-09-04 17:59:07 -0700328 /* Add types of incoming arguments based on signature */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800329 int numIns = cUnit->numIns;
buzbeee9a72f62011-09-04 17:59:07 -0700330 if (numIns > 0) {
331 int sReg = numRegs - numIns;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800332 if ((cUnit->access_flags & art::kAccStatic) == 0) {
333 // For non-static, skip past "this"
buzbee67bc2362011-10-11 18:08:40 -0700334 cUnit->regLocation[sReg].defined = true;
335 cUnit->regLocation[sReg].core = true;
buzbeee9a72f62011-09-04 17:59:07 -0700336 sReg++;
337 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800338 const char* shorty = cUnit->shorty;
339 int shorty_len = strlen(shorty);
340 for (int i = 1; i < shorty_len; i++) {
341 switch(shorty[i]) {
buzbee67bc2362011-10-11 18:08:40 -0700342 case 'D':
343 cUnit->regLocation[sReg].wide = true;
344 cUnit->regLocation[sReg+1].highWord = true;
345 DCHECK_EQ(oatS2VReg(cUnit, sReg)+1,
346 oatS2VReg(cUnit, sReg+1));
347 cUnit->regLocation[sReg].fp = true;
348 cUnit->regLocation[sReg].defined = true;
349 sReg++;
350 break;
351 case 'J':
352 cUnit->regLocation[sReg].wide = true;
353 cUnit->regLocation[sReg+1].highWord = true;
354 DCHECK_EQ(oatS2VReg(cUnit, sReg)+1,
355 oatS2VReg(cUnit, sReg+1));
356 cUnit->regLocation[sReg].core = true;
357 cUnit->regLocation[sReg].defined = true;
358 sReg++;
359 break;
360 case 'F':
361 cUnit->regLocation[sReg].fp = true;
362 cUnit->regLocation[sReg].defined = true;
363 break;
364 default:
365 cUnit->regLocation[sReg].core = true;
366 cUnit->regLocation[sReg].defined = true;
367 break;
buzbeee9a72f62011-09-04 17:59:07 -0700368 }
369 sReg++;
370 }
371 }
372
buzbeec0ecd652011-09-25 18:11:54 -0700373 /* Remap names */
374 oatDataFlowAnalysisDispatcher(cUnit, remapNames,
375 kPreOrderDFSTraversal,
376 false /* isIterative */);
377
buzbee03fa2632011-09-20 17:10:57 -0700378 /* Do type & size inference pass */
379 oatDataFlowAnalysisDispatcher(cUnit, inferTypeAndSize,
380 kPreOrderDFSTraversal,
381 true /* isIterative */);
buzbee67bf8852011-08-17 17:51:35 -0700382
383 /*
384 * Set the sRegLow field to refer to the pre-SSA name of the
385 * base Dalvik virtual register. Once we add a better register
386 * allocator, remove this remapping.
387 */
388 for (i=0; i < cUnit->numSSARegs; i++) {
389 cUnit->regLocation[i].sRegLow =
390 DECODE_REG(oatConvertSSARegToDalvik(cUnit, loc[i].sRegLow));
391 }
392
393 cUnit->coreSpillMask = 0;
394 cUnit->fpSpillMask = 0;
buzbeebbaf8942011-10-02 13:08:29 -0700395 cUnit->numCoreSpills = 0;
buzbee67bf8852011-08-17 17:51:35 -0700396
397 oatDoPromotion(cUnit);
398
399 if (cUnit->printMe && !(cUnit->disableOpt & (1 << kPromoteRegs))) {
400 LOG(INFO) << "After Promotion";
buzbeedfd3d702011-08-28 12:56:51 -0700401 oatDumpRegLocTable(cUnit->regLocation, cUnit->numSSARegs);
buzbee67bf8852011-08-17 17:51:35 -0700402 }
403
404 /* Figure out the frame size */
buzbee67bf8852011-08-17 17:51:35 -0700405 cUnit->numPadding = (STACK_ALIGN_WORDS -
buzbeebbaf8942011-10-02 13:08:29 -0700406 (cUnit->numCoreSpills + cUnit->numFPSpills + cUnit->numRegs +
buzbee67bf8852011-08-17 17:51:35 -0700407 cUnit->numOuts + 2)) & (STACK_ALIGN_WORDS-1);
buzbeebbaf8942011-10-02 13:08:29 -0700408 cUnit->frameSize = (cUnit->numCoreSpills + cUnit->numFPSpills +
409 cUnit->numRegs + cUnit->numOuts +
buzbee67bf8852011-08-17 17:51:35 -0700410 cUnit->numPadding + 2) * 4;
411 cUnit->insOffset = cUnit->frameSize + 4;
412 cUnit->regsOffset = (cUnit->numOuts + cUnit->numPadding + 1) * 4;
buzbee67bf8852011-08-17 17:51:35 -0700413}