blob: c6375eea1e992d2c0daaf30d40bb55c4319f749d [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080022namespace art {
23
buzbeeed3e9302011-09-23 17:34:19 -070024STATIC bool setFp(CompilationUnit* cUnit, int index, bool isFP) {
buzbee03fa2632011-09-20 17:10:57 -070025 bool change = false;
buzbee67bc2362011-10-11 18:08:40 -070026 if (cUnit->regLocation[index].highWord) {
27 return change;
28 }
buzbee03fa2632011-09-20 17:10:57 -070029 if (isFP && !cUnit->regLocation[index].fp) {
30 cUnit->regLocation[index].fp = true;
buzbee67bc2362011-10-11 18:08:40 -070031 cUnit->regLocation[index].defined = true;
32 change = true;
33 }
34 return change;
35}
36
37STATIC bool setCore(CompilationUnit* cUnit, int index, bool isCore) {
38 bool change = false;
39 if (cUnit->regLocation[index].highWord) {
40 return change;
41 }
42 if (isCore && !cUnit->regLocation[index].defined) {
43 cUnit->regLocation[index].core = true;
44 cUnit->regLocation[index].defined = true;
buzbee03fa2632011-09-20 17:10:57 -070045 change = true;
46 }
47 return change;
48}
49
buzbeec0ecd652011-09-25 18:11:54 -070050STATIC bool remapNames(CompilationUnit* cUnit, BasicBlock* bb)
51{
52 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
53 bb->blockType != kExitBlock)
54 return false;
55
56 for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
57 SSARepresentation *ssaRep = mir->ssaRep;
58 if (ssaRep) {
59 for (int i = 0; i < ssaRep->numUses; i++) {
60 ssaRep->uses[i] = cUnit->phiAliasMap[ssaRep->uses[i]];
61 }
62 for (int i = 0; i < ssaRep->numDefs; i++) {
63 ssaRep->defs[i] = cUnit->phiAliasMap[ssaRep->defs[i]];
64 }
65 }
66 }
67 return false;
68}
69
buzbee769fde12012-01-05 17:35:23 -080070// Try to find the next move result which might have an FP target
71STATIC SSARepresentation* findMoveResult(MIR* mir)
72{
73 SSARepresentation* res = NULL;
74 for (; mir; mir = mir->next) {
75 if ((mir->dalvikInsn.opcode == OP_MOVE_RESULT) ||
76 (mir->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
77 res = mir->ssaRep;
78 break;
79 }
80 }
81 return res;
82}
83
buzbee67bf8852011-08-17 17:51:35 -070084/*
buzbee03fa2632011-09-20 17:10:57 -070085 * Infer types and sizes. We don't need to track change on sizes,
86 * as it doesn't propagate. We're guaranteed at least one pass through
87 * the cfg.
buzbee67bf8852011-08-17 17:51:35 -070088 */
buzbeeed3e9302011-09-23 17:34:19 -070089STATIC bool inferTypeAndSize(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -070090{
91 MIR *mir;
buzbee03fa2632011-09-20 17:10:57 -070092 bool changed = false; // Did anything change?
93
94 if (bb->dataFlowInfo == NULL) return false;
buzbee67bf8852011-08-17 17:51:35 -070095 if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock)
buzbee03fa2632011-09-20 17:10:57 -070096 return false;
buzbee67bf8852011-08-17 17:51:35 -070097
98 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
99 SSARepresentation *ssaRep = mir->ssaRep;
100 if (ssaRep) {
buzbee03fa2632011-09-20 17:10:57 -0700101 int attrs = oatDataFlowAttributes[mir->dalvikInsn.opcode];
buzbee67bc2362011-10-11 18:08:40 -0700102
103 // Handle defs
104 if (attrs & (DF_DA | DF_DA_WIDE)) {
105 if (attrs & DF_CORE_A) {
106 changed |= setCore(cUnit, ssaRep->defs[0], true);
107 }
108 if (attrs & DF_DA_WIDE) {
109 cUnit->regLocation[ssaRep->defs[0]].wide = true;
110 cUnit->regLocation[ssaRep->defs[1]].highWord = true;
111 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->defs[0])+1,
112 oatS2VReg(cUnit, ssaRep->defs[1]));
113 }
114 }
115
116 // Handles uses
buzbee03fa2632011-09-20 17:10:57 -0700117 int next = 0;
buzbee67bc2362011-10-11 18:08:40 -0700118 if (attrs & (DF_UA | DF_UA_WIDE)) {
119 if (attrs & DF_CORE_A) {
120 changed |= setCore(cUnit, ssaRep->uses[next], true);
121 }
122 if (attrs & DF_UA_WIDE) {
123 cUnit->regLocation[ssaRep->uses[next]].wide = true;
124 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
125 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
126 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
127 next += 2;
128 } else {
129 next++;
130 }
buzbee67bf8852011-08-17 17:51:35 -0700131 }
buzbee67bc2362011-10-11 18:08:40 -0700132 if (attrs & (DF_UB | DF_UB_WIDE)) {
133 if (attrs & DF_CORE_B) {
134 changed |= setCore(cUnit, ssaRep->uses[next], true);
135 }
136 if (attrs & DF_UB_WIDE) {
137 cUnit->regLocation[ssaRep->uses[next]].wide = true;
138 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
139 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
140 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
141 next += 2;
142 } else {
143 next++;
144 }
buzbee03fa2632011-09-20 17:10:57 -0700145 }
buzbee67bc2362011-10-11 18:08:40 -0700146 if (attrs & (DF_UC | DF_UC_WIDE)) {
147 if (attrs & DF_CORE_C) {
148 changed |= setCore(cUnit, ssaRep->uses[next], true);
149 }
150 if (attrs & DF_UC_WIDE) {
151 cUnit->regLocation[ssaRep->uses[next]].wide = true;
152 cUnit->regLocation[ssaRep->uses[next + 1]].highWord = true;
153 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[next])+1,
154 oatS2VReg(cUnit, ssaRep->uses[next + 1]));
155 }
buzbee03fa2632011-09-20 17:10:57 -0700156 }
buzbeeed3e9302011-09-23 17:34:19 -0700157
buzbee769fde12012-01-05 17:35:23 -0800158 // Special-case handling for format 35c/3rc invokes
159 Opcode opcode = mir->dalvikInsn.opcode;
160 int flags = (opcode >= kNumPackedOpcodes) ? 0 :
buzbeeed3e9302011-09-23 17:34:19 -0700161 dexGetFlagsFromOpcode(opcode);
162 if ((flags & kInstrInvoke) &&
163 (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
164 DCHECK_EQ(next, 0);
165 int target_idx = mir->dalvikInsn.vB;
166 const char* shorty =
167 oatGetShortyFromTargetIdx(cUnit, target_idx);
buzbee769fde12012-01-05 17:35:23 -0800168 // Handle result type if floating point
169 if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
170 // Find move-result that consumes this result
171 SSARepresentation* tgtRep = findMoveResult(mir->next);
172 // Might be in next basic block
173 if (!tgtRep) {
174 tgtRep = findMoveResult(bb->fallThrough->firstMIRInsn);
175 }
176 // Result might not be used at all, so no move-result
177 if (tgtRep) {
178 tgtRep->fpDef[0] = true;
179 changed |= setFp(cUnit, tgtRep->defs[0], true);
180 if (shorty[0] == 'D') {
181 tgtRep->fpDef[1] = true;
182 changed |= setFp(cUnit, tgtRep->defs[1], true);
183 }
184 }
185 }
buzbeeed3e9302011-09-23 17:34:19 -0700186 int numUses = mir->dalvikInsn.vA;
187 // If this is a non-static invoke, skip implicit "this"
188 if (((mir->dalvikInsn.opcode != OP_INVOKE_STATIC) &&
189 (mir->dalvikInsn.opcode != OP_INVOKE_STATIC_RANGE))) {
buzbee67bc2362011-10-11 18:08:40 -0700190 cUnit->regLocation[ssaRep->uses[next]].defined = true;
191 cUnit->regLocation[ssaRep->uses[next]].core = true;
buzbeeed3e9302011-09-23 17:34:19 -0700192 next++;
193 }
194 uint32_t cpos = 1;
195 if (strlen(shorty) > 1) {
196 for (int i = next; i < numUses;) {
197 DCHECK_LT(cpos, strlen(shorty));
198 switch(shorty[cpos++]) {
199 case 'D':
200 ssaRep->fpUse[i] = true;
201 ssaRep->fpUse[i+1] = true;
202 cUnit->regLocation[ssaRep->uses[i]].wide = true;
buzbee67bc2362011-10-11 18:08:40 -0700203 cUnit->regLocation[ssaRep->uses[i+1]].highWord
204 = true;
205 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[i])+1,
206 oatS2VReg(cUnit, ssaRep->uses[i+1]));
buzbeeed3e9302011-09-23 17:34:19 -0700207 i++;
208 break;
209 case 'J':
210 cUnit->regLocation[ssaRep->uses[i]].wide = true;
buzbee67bc2362011-10-11 18:08:40 -0700211 cUnit->regLocation[ssaRep->uses[i+1]].highWord
212 = true;
213 DCHECK_EQ(oatS2VReg(cUnit, ssaRep->uses[i])+1,
214 oatS2VReg(cUnit, ssaRep->uses[i+1]));
215 changed |= setCore(cUnit, ssaRep->uses[i],true);
buzbeeed3e9302011-09-23 17:34:19 -0700216 i++;
217 break;
218 case 'F':
219 ssaRep->fpUse[i] = true;
220 break;
221 default:
buzbee67bc2362011-10-11 18:08:40 -0700222 changed |= setCore(cUnit,ssaRep->uses[i], true);
buzbeeed3e9302011-09-23 17:34:19 -0700223 break;
224 }
225 i++;
226 }
227 }
228 }
229
buzbee03fa2632011-09-20 17:10:57 -0700230 for (int i=0; ssaRep->fpUse && i< ssaRep->numUses; i++) {
231 if (ssaRep->fpUse[i])
232 changed |= setFp(cUnit, ssaRep->uses[i], true);
233 }
234 for (int i=0; ssaRep->fpDef && i< ssaRep->numDefs; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700235 if (ssaRep->fpDef[i])
buzbee03fa2632011-09-20 17:10:57 -0700236 changed |= setFp(cUnit, ssaRep->defs[i], true);
237 }
238 // Special-case handling for moves & Phi
239 if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
buzbee67bc2362011-10-11 18:08:40 -0700240 // If any of our inputs or outputs is defined, set all
241 bool definedFP = false;
242 bool definedCore = false;
243 definedFP |= (cUnit->regLocation[ssaRep->defs[0]].defined &&
244 cUnit->regLocation[ssaRep->defs[0]].fp);
245 definedCore |= (cUnit->regLocation[ssaRep->defs[0]].defined &&
246 cUnit->regLocation[ssaRep->defs[0]].core);
buzbee03fa2632011-09-20 17:10:57 -0700247 for (int i = 0; i < ssaRep->numUses; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700248 definedFP |= (cUnit->regLocation[ssaRep->uses[i]].defined &&
249 cUnit->regLocation[ssaRep->uses[i]].fp);
250 definedCore |= (cUnit->regLocation[ssaRep->uses[i]].defined
251 && cUnit->regLocation[ssaRep->uses[i]].core);
buzbee03fa2632011-09-20 17:10:57 -0700252 }
buzbee23d5bc92011-10-31 12:41:02 -0700253 /*
254 * TODO: cleaner fix
255 * We don't normally expect to see a Dalvik register
256 * definition used both as a floating point and core
257 * value. However, the instruction rewriting that occurs
258 * during verification can eliminate some type information,
259 * leaving us confused. The real fix here is either to
260 * add explicit type information to Dalvik byte codes,
261 * or to recognize OP_THROW_VERIFICATION_ERROR as
262 * an unconditional branch and support dead code elimination.
263 * As a workaround we can detect this situation and
264 * disable register promotion (which is the only thing that
265 * relies on distinctions between core and fp usages.
266 */
267 if ((definedFP && definedCore) &&
268 ((cUnit->disableOpt & (1 << kPromoteRegs)) == 0)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800269 LOG(WARNING) << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
buzbee23d5bc92011-10-31 12:41:02 -0700270 << " op at block " << bb->id
271 << " has both fp and core uses for same def.";
272 cUnit->disableOpt |= (1 << kPromoteRegs);
273 }
buzbee67bc2362011-10-11 18:08:40 -0700274 changed |= setFp(cUnit, ssaRep->defs[0], definedFP);
275 changed |= setCore(cUnit, ssaRep->defs[0], definedCore);
buzbee03fa2632011-09-20 17:10:57 -0700276 for (int i = 0; i < ssaRep->numUses; i++) {
buzbee67bc2362011-10-11 18:08:40 -0700277 changed |= setFp(cUnit, ssaRep->uses[i], definedFP);
278 changed |= setCore(cUnit, ssaRep->uses[i], definedCore);
buzbee03fa2632011-09-20 17:10:57 -0700279 }
buzbee67bf8852011-08-17 17:51:35 -0700280 }
281 }
282 }
buzbee03fa2632011-09-20 17:10:57 -0700283 return changed;
buzbee67bf8852011-08-17 17:51:35 -0700284}
285
286static const char* storageName[] = {" Frame ", "PhysReg", " Spill "};
287
buzbeedfd3d702011-08-28 12:56:51 -0700288void oatDumpRegLocTable(RegLocation* table, int count)
buzbee67bf8852011-08-17 17:51:35 -0700289{
290 for (int i = 0; i < count; i++) {
291 char buf[100];
buzbee67bc2362011-10-11 18:08:40 -0700292 snprintf(buf, 100, "Loc[%02d] : %s, %c %c %c %c %c %c%d %c%d S%d",
buzbee67bf8852011-08-17 17:51:35 -0700293 i, storageName[table[i].location], table[i].wide ? 'W' : 'N',
buzbee67bc2362011-10-11 18:08:40 -0700294 table[i].defined ? 'D' : 'U', table[i].fp ? 'F' : 'C',
295 table[i].highWord ? 'H' : 'L', table[i].home ? 'h' : 't',
296 FPREG(table[i].lowReg) ? 's' : 'r', table[i].lowReg & FP_REG_MASK,
297 FPREG(table[i].highReg) ? 's' : 'r', table[i].highReg & FP_REG_MASK,
298 table[i].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700299 LOG(INFO) << buf;
300 }
301}
302
buzbee67bc2362011-10-11 18:08:40 -0700303static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0,
304 INVALID_REG, INVALID_REG, INVALID_SREG};
buzbee67bf8852011-08-17 17:51:35 -0700305
306/*
307 * Simple register allocation. Some Dalvik virtual registers may
308 * be promoted to physical registers. Most of the work for temp
309 * allocation is done on the fly. We also do some initilization and
310 * type inference here.
311 */
312void oatSimpleRegAlloc(CompilationUnit* cUnit)
313{
314 int i;
315 RegLocation* loc;
316
317 /* Allocate the location map */
318 loc = (RegLocation*)oatNew(cUnit->numSSARegs * sizeof(*loc), true);
319 for (i=0; i< cUnit->numSSARegs; i++) {
320 loc[i] = freshLoc;
321 loc[i].sRegLow = i;
322 }
323 cUnit->regLocation = loc;
324
buzbee67bc2362011-10-11 18:08:40 -0700325 /* Allocation the promotion map */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800326 int numRegs = cUnit->numDalvikRegisters;
327 cUnit->promotionMap =
328 (PromotionMap*)oatNew(numRegs * sizeof(cUnit->promotionMap[0]), true);
buzbee67bc2362011-10-11 18:08:40 -0700329
buzbeee9a72f62011-09-04 17:59:07 -0700330 /* Add types of incoming arguments based on signature */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800331 int numIns = cUnit->numIns;
buzbeee9a72f62011-09-04 17:59:07 -0700332 if (numIns > 0) {
333 int sReg = numRegs - numIns;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800334 if ((cUnit->access_flags & kAccStatic) == 0) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800335 // For non-static, skip past "this"
buzbee67bc2362011-10-11 18:08:40 -0700336 cUnit->regLocation[sReg].defined = true;
337 cUnit->regLocation[sReg].core = true;
buzbeee9a72f62011-09-04 17:59:07 -0700338 sReg++;
339 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800340 const char* shorty = cUnit->shorty;
341 int shorty_len = strlen(shorty);
342 for (int i = 1; i < shorty_len; i++) {
343 switch(shorty[i]) {
buzbee67bc2362011-10-11 18:08:40 -0700344 case 'D':
345 cUnit->regLocation[sReg].wide = true;
346 cUnit->regLocation[sReg+1].highWord = true;
347 DCHECK_EQ(oatS2VReg(cUnit, sReg)+1,
348 oatS2VReg(cUnit, sReg+1));
349 cUnit->regLocation[sReg].fp = true;
350 cUnit->regLocation[sReg].defined = true;
351 sReg++;
352 break;
353 case 'J':
354 cUnit->regLocation[sReg].wide = true;
355 cUnit->regLocation[sReg+1].highWord = true;
356 DCHECK_EQ(oatS2VReg(cUnit, sReg)+1,
357 oatS2VReg(cUnit, sReg+1));
358 cUnit->regLocation[sReg].core = true;
359 cUnit->regLocation[sReg].defined = true;
360 sReg++;
361 break;
362 case 'F':
363 cUnit->regLocation[sReg].fp = true;
364 cUnit->regLocation[sReg].defined = true;
365 break;
366 default:
367 cUnit->regLocation[sReg].core = true;
368 cUnit->regLocation[sReg].defined = true;
369 break;
buzbeee9a72f62011-09-04 17:59:07 -0700370 }
371 sReg++;
372 }
373 }
374
buzbeec0ecd652011-09-25 18:11:54 -0700375 /* Remap names */
376 oatDataFlowAnalysisDispatcher(cUnit, remapNames,
377 kPreOrderDFSTraversal,
378 false /* isIterative */);
379
buzbee03fa2632011-09-20 17:10:57 -0700380 /* Do type & size inference pass */
381 oatDataFlowAnalysisDispatcher(cUnit, inferTypeAndSize,
382 kPreOrderDFSTraversal,
383 true /* isIterative */);
buzbee67bf8852011-08-17 17:51:35 -0700384
385 /*
386 * Set the sRegLow field to refer to the pre-SSA name of the
387 * base Dalvik virtual register. Once we add a better register
388 * allocator, remove this remapping.
389 */
390 for (i=0; i < cUnit->numSSARegs; i++) {
391 cUnit->regLocation[i].sRegLow =
392 DECODE_REG(oatConvertSSARegToDalvik(cUnit, loc[i].sRegLow));
393 }
394
395 cUnit->coreSpillMask = 0;
396 cUnit->fpSpillMask = 0;
buzbeebbaf8942011-10-02 13:08:29 -0700397 cUnit->numCoreSpills = 0;
buzbee67bf8852011-08-17 17:51:35 -0700398
399 oatDoPromotion(cUnit);
400
401 if (cUnit->printMe && !(cUnit->disableOpt & (1 << kPromoteRegs))) {
402 LOG(INFO) << "After Promotion";
buzbeedfd3d702011-08-28 12:56:51 -0700403 oatDumpRegLocTable(cUnit->regLocation, cUnit->numSSARegs);
buzbee67bf8852011-08-17 17:51:35 -0700404 }
405
406 /* Figure out the frame size */
buzbee67bf8852011-08-17 17:51:35 -0700407 cUnit->numPadding = (STACK_ALIGN_WORDS -
buzbeebbaf8942011-10-02 13:08:29 -0700408 (cUnit->numCoreSpills + cUnit->numFPSpills + cUnit->numRegs +
buzbee67bf8852011-08-17 17:51:35 -0700409 cUnit->numOuts + 2)) & (STACK_ALIGN_WORDS-1);
buzbeebbaf8942011-10-02 13:08:29 -0700410 cUnit->frameSize = (cUnit->numCoreSpills + cUnit->numFPSpills +
411 cUnit->numRegs + cUnit->numOuts +
buzbee67bf8852011-08-17 17:51:35 -0700412 cUnit->numPadding + 2) * 4;
413 cUnit->insOffset = cUnit->frameSize + 4;
414 cUnit->regsOffset = (cUnit->numOuts + cUnit->numPadding + 1) * 4;
buzbee67bf8852011-08-17 17:51:35 -0700415}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800416
417} // namespace art