blob: 9f616b836756b1bcf48a110b014ba93b47d221d9 [file] [log] [blame]
Ben Chenge9695e52009-06-16 16:11:47 -07001/*
2 * Copyright (C) 2009 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 "vm/compiler/CompilerInternals.h"
Bill Buzbee89efc3d2009-07-28 11:22:22 -070019#include "ArmLIR.h"
Ben Cheng5d90c202009-11-22 23:31:11 -080020#include "Codegen.h"
Ben Chenge9695e52009-06-16 16:11:47 -070021
Ben Chengd7d426a2009-09-22 11:23:36 -070022#define DEBUG_OPT(X)
23
Bill Buzbee7ea0f642009-08-10 17:06:51 -070024ArmLIR* dvmCompilerGenCopy(CompilationUnit *cUnit, int rDest, int rSrc);
25
26/* Is this a Dalvik register access? */
27static inline bool isDalvikLoad(ArmLIR *lir)
28{
Bill Buzbee1f748632010-03-02 16:14:41 -080029 return (lir->useMask != ENCODE_ALL) && (lir->useMask & ENCODE_DALVIK_REG);
30}
31
32/* Is this a load from the literal pool? */
33static inline bool isLiteralLoad(ArmLIR *lir)
34{
35 return (lir->useMask != ENCODE_ALL) && (lir->useMask & ENCODE_LITERAL);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070036}
37
38static inline bool isDalvikStore(ArmLIR *lir)
39{
Bill Buzbee1f748632010-03-02 16:14:41 -080040 return (lir->defMask != ENCODE_ALL) && (lir->defMask & ENCODE_DALVIK_REG);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070041}
42
Ben Chenga4aaf682009-09-30 22:53:44 -070043static inline bool isDalvikRegisterClobbered(ArmLIR *lir1, ArmLIR *lir2)
Bill Buzbee270c1d62009-08-13 16:58:07 -070044{
Ben Chengd7d426a2009-09-22 11:23:36 -070045 int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
46 int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
47 int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
48 int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
49
Ben Chenga4aaf682009-09-30 22:53:44 -070050 return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
Bill Buzbee270c1d62009-08-13 16:58:07 -070051}
Ben Chengd7d426a2009-09-22 11:23:36 -070052
53static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
54 const char *optimization)
55{
56 LOGD("************ %s ************", optimization);
57 dvmDumpLIRInsn((LIR *) thisLIR, 0);
58 dvmDumpLIRInsn((LIR *) checkLIR, 0);
59}
60
Ben Chenge9695e52009-06-16 16:11:47 -070061/*
62 * Perform a pass of top-down walk to
63 * 1) Eliminate redundant loads and stores
64 * 2) Sink stores to latest possible slot
65 */
66static void applyLoadStoreElimination(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -070067 ArmLIR *headLIR,
68 ArmLIR *tailLIR)
Ben Chenge9695e52009-06-16 16:11:47 -070069{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070070 ArmLIR *thisLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070071
72 cUnit->optRound++;
73 for (thisLIR = headLIR;
74 thisLIR != tailLIR;
75 thisLIR = NEXT_LIR(thisLIR)) {
76 /* Skip newly added instructions */
77 if (thisLIR->age >= cUnit->optRound) {
78 continue;
79 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -070080 if (isDalvikStore(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -070081 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
82 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chenge9695e52009-06-16 16:11:47 -070083 int nativeRegId = thisLIR->operands[0];
Bill Buzbee89efc3d2009-07-28 11:22:22 -070084 ArmLIR *checkLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070085 int sinkDistance = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -070086 /*
87 * Add r15 (pc) to the mask to prevent this instruction
Ben Chengd7d426a2009-09-22 11:23:36 -070088 * from sinking past branch instructions. Unset the Dalvik register
89 * bit when checking with native resource constraints.
Ben Chengdcf3e5d2009-09-11 13:42:05 -070090 */
Ben Chengd7d426a2009-09-22 11:23:36 -070091 u8 stopMask = (ENCODE_REG_PC | thisLIR->useMask) &
92 ~ENCODE_DALVIK_REG;
Ben Chenge9695e52009-06-16 16:11:47 -070093
94 for (checkLIR = NEXT_LIR(thisLIR);
95 checkLIR != tailLIR;
96 checkLIR = NEXT_LIR(checkLIR)) {
97
98 /* Check if a Dalvik register load is redundant */
Bill Buzbee7ea0f642009-08-10 17:06:51 -070099 if (isDalvikLoad(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700100 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
101 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chenge9695e52009-06-16 16:11:47 -0700102 /* Insert a move to replace the load */
103 if (checkLIR->operands[0] != nativeRegId) {
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700104 ArmLIR *moveLIR;
Ben Cheng5d90c202009-11-22 23:31:11 -0800105 moveLIR = dvmCompilerRegCopyNoInsert(
106 cUnit, checkLIR->operands[0], nativeRegId);
Ben Chenge9695e52009-06-16 16:11:47 -0700107 /*
108 * Insertion is guaranteed to succeed since checkLIR
109 * is never the first LIR on the list
110 */
111 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
112 (LIR *) moveLIR);
113 }
114 checkLIR->isNop = true;
115 continue;
116
Ben Chengd7d426a2009-09-22 11:23:36 -0700117 /*
118 * Found a true output dependency - nuke the previous store.
119 * The register type doesn't matter here.
120 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700121 } else if (isDalvikStore(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700122 (checkLIR->aliasInfo == thisLIR->aliasInfo)) {
Ben Chenge9695e52009-06-16 16:11:47 -0700123 thisLIR->isNop = true;
124 break;
125 /* Find out the latest slot that the store can be sunk into */
126 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700127 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700128 bool stopHere = (NEXT_LIR(checkLIR) == tailLIR);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700129
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700130 /* Store data is clobbered */
Ben Chengd7d426a2009-09-22 11:23:36 -0700131 stopHere |= ((stopMask & checkLIR->defMask) != 0);
132
133 /* Store data partially clobbers the Dalvik register */
134 if (stopHere == false &&
135 ((checkLIR->useMask | checkLIR->defMask) &
136 ENCODE_DALVIK_REG)) {
Ben Chenga4aaf682009-09-30 22:53:44 -0700137 stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
Ben Chengd7d426a2009-09-22 11:23:36 -0700138 }
Ben Chenge9695e52009-06-16 16:11:47 -0700139
140 /* Found a new place to put the store - move it here */
141 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700142 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
143 "SINK STORE"));
Ben Chenge9695e52009-06-16 16:11:47 -0700144 /* The store can be sunk for at least one cycle */
145 if (sinkDistance != 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700146 ArmLIR *newStoreLIR =
147 dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700148 *newStoreLIR = *thisLIR;
149 newStoreLIR->age = cUnit->optRound;
150 /*
151 * Insertion is guaranteed to succeed since checkLIR
152 * is never the first LIR on the list
153 */
154 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
155 (LIR *) newStoreLIR);
156 thisLIR->isNop = true;
157 }
158 break;
159 }
160
161 /*
162 * Saw a real instruction that the store can be sunk after
163 */
164 if (!isPseudoOpCode(checkLIR->opCode)) {
165 sinkDistance++;
166 }
167 }
168 }
169 }
170 }
171}
172
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700173static void applyLoadHoisting(CompilationUnit *cUnit,
174 ArmLIR *headLIR,
175 ArmLIR *tailLIR)
176{
177 ArmLIR *thisLIR;
Bill Buzbee1f748632010-03-02 16:14:41 -0800178 /*
179 * Don't want to hoist in front of first load following a barrier (or
180 * first instruction of the block.
181 */
182 bool firstLoad = true;
183 int maxHoist = dvmCompilerTargetOptHint(kMaxHoistDistance);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700184
185 cUnit->optRound++;
186 for (thisLIR = headLIR;
187 thisLIR != tailLIR;
188 thisLIR = NEXT_LIR(thisLIR)) {
189 /* Skip newly added instructions */
190 if (thisLIR->age >= cUnit->optRound ||
191 thisLIR->isNop == true) {
192 continue;
193 }
Bill Buzbee1f748632010-03-02 16:14:41 -0800194
195 if (firstLoad && (EncodingMap[thisLIR->opCode].flags & IS_LOAD)) {
196 /*
197 * Ensure nothing will be hoisted in front of this load because
198 * it's result will likely be needed soon.
199 */
200 thisLIR->defMask |= ENCODE_MEM_USE;
201 firstLoad = false;
202 }
203
204 firstLoad |= (thisLIR->defMask == ENCODE_ALL);
205
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700206 if (isDalvikLoad(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700207 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
208 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700209 int nativeRegId = thisLIR->operands[0];
210 ArmLIR *checkLIR;
211 int hoistDistance = 0;
Ben Chengd7d426a2009-09-22 11:23:36 -0700212 u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
Bill Buzbee1f748632010-03-02 16:14:41 -0800213 ~ENCODE_FRAME_REF;
214 u8 stopDefMask = thisLIR->defMask & ~ENCODE_FRAME_REF;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700215
Ben Chengd7d426a2009-09-22 11:23:36 -0700216 /* First check if the load can be completely elinimated */
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700217 for (checkLIR = PREV_LIR(thisLIR);
218 checkLIR != headLIR;
219 checkLIR = PREV_LIR(checkLIR)) {
220
221 if (checkLIR->isNop) continue;
222
Ben Chengd7d426a2009-09-22 11:23:36 -0700223 /*
224 * Check if the Dalvik register is previously accessed
225 * with exactly the same type.
226 */
227 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
228 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
229 (checkLIR->operands[0] == nativeRegId)) {
230 /*
231 * If it is previously accessed but with a different type,
232 * the search will terminate later at the point checking
233 * for partially overlapping stores.
234 */
235 thisLIR->isNop = true;
236 break;
237 }
238
239 /*
240 * No earlier use/def can reach this load if:
241 * 1) Head instruction is reached
242 * 2) load target register is clobbered
243 * 3) A branch is seen (stopUseMask has the PC bit set).
244 */
245 if ((checkLIR == headLIR) ||
246 (stopUseMask | stopDefMask) & checkLIR->defMask) {
247 break;
248 }
249
250 /* Store data partially clobbers the Dalvik register */
251 if (isDalvikStore(checkLIR) &&
Ben Chenga4aaf682009-09-30 22:53:44 -0700252 isDalvikRegisterClobbered(thisLIR, checkLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700253 break;
254 }
255 }
256
257 /* The load has been eliminated */
258 if (thisLIR->isNop) continue;
259
260 /*
261 * The load cannot be eliminated. See if it can be hoisted to an
262 * earlier spot.
263 */
264 for (checkLIR = PREV_LIR(thisLIR);
265 /* empty by intention */;
266 checkLIR = PREV_LIR(checkLIR)) {
267
268 if (checkLIR->isNop) continue;
269
Bill Buzbee1f748632010-03-02 16:14:41 -0800270 /*
271 * Check if the "thisLIR" load is redundant
272 * NOTE: At one point, we also triggered if the checkLIR
273 * instruction was a load. However, that tended to insert
274 * a load/use dependency because the full scheduler is
275 * not yet complete. When it is, we chould also trigger
276 * on loads.
277 */
278 if (isDalvikStore(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700279 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
280 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700281 /* Insert a move to replace the load */
282 if (checkLIR->operands[0] != nativeRegId) {
283 ArmLIR *moveLIR;
Ben Cheng5d90c202009-11-22 23:31:11 -0800284 moveLIR = dvmCompilerRegCopyNoInsert(
285 cUnit, nativeRegId, checkLIR->operands[0]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700286 /*
287 * Convert *thisLIR* load into a move
288 */
289 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
290 (LIR *) moveLIR);
291 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700292 thisLIR->isNop = true;
293 break;
294
295 /* Find out if the load can be yanked past the checkLIR */
296 } else {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700297 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700298 bool stopHere = (checkLIR == headLIR);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700299
300 /* Base address is clobbered by checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700301 stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700302
303 /* Load target clobbers use/def in checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700304 stopHere |= ((stopDefMask &
305 (checkLIR->useMask | checkLIR->defMask)) != 0);
306
307 /* Store data partially clobbers the Dalvik register */
308 if (stopHere == false &&
309 (checkLIR->defMask & ENCODE_DALVIK_REG)) {
Ben Chenga4aaf682009-09-30 22:53:44 -0700310 stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
Ben Chengd7d426a2009-09-22 11:23:36 -0700311 }
312
313 /*
314 * Stop at an earlier Dalvik load if the offset of checkLIR
315 * is not less than thisLIR
316 *
317 * Experiments show that doing
318 *
319 * ldr r1, [r5, #16]
320 * ldr r0, [r5, #20]
321 *
322 * is much faster than
323 *
324 * ldr r0, [r5, #20]
325 * ldr r1, [r5, #16]
326 */
327 if (isDalvikLoad(checkLIR)) {
328 int dRegId2 =
329 DECODE_ALIAS_INFO_REG(checkLIR->aliasInfo);
330 if (dRegId2 <= dRegId) {
331 stopHere = true;
332 }
333 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700334
Bill Buzbee1f748632010-03-02 16:14:41 -0800335 /* Don't go too far */
336 stopHere |= (hoistDistance >= maxHoist);
337
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700338 /* Found a new place to put the load - move it here */
339 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700340 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
341 "HOIST LOAD"));
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700342 /* The store can be hoisted for at least one cycle */
343 if (hoistDistance != 0) {
344 ArmLIR *newLoadLIR =
345 dvmCompilerNew(sizeof(ArmLIR), true);
346 *newLoadLIR = *thisLIR;
347 newLoadLIR->age = cUnit->optRound;
348 /*
349 * Insertion is guaranteed to succeed since checkLIR
350 * is never the first LIR on the list
351 */
352 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
353 (LIR *) newLoadLIR);
354 thisLIR->isNop = true;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700355 }
356 break;
357 }
358
359 /*
Ben Chengd7d426a2009-09-22 11:23:36 -0700360 * Saw a real instruction that hosting the load is
361 * beneficial
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700362 */
363 if (!isPseudoOpCode(checkLIR->opCode)) {
364 hoistDistance++;
365 }
366 }
367 }
Bill Buzbee1f748632010-03-02 16:14:41 -0800368 } else if (isLiteralLoad(thisLIR)) {
369 int litVal = thisLIR->aliasInfo;
370 int nativeRegId = thisLIR->operands[0];
371 ArmLIR *checkLIR;
372 int hoistDistance = 0;
373 u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
374 ~ENCODE_LITPOOL_REF;
375 u8 stopDefMask = thisLIR->defMask & ~ENCODE_LITPOOL_REF;
376
377 /* First check if the load can be completely elinimated */
378 for (checkLIR = PREV_LIR(thisLIR);
379 checkLIR != headLIR;
380 checkLIR = PREV_LIR(checkLIR)) {
381
382 if (checkLIR->isNop) continue;
383
384 /* Reloading same literal into same tgt reg? Eliminate if so */
385 if (isLiteralLoad(checkLIR) &&
386 (checkLIR->aliasInfo == litVal) &&
387 (checkLIR->operands[0] == nativeRegId)) {
388 thisLIR->isNop = true;
389 break;
390 }
391
392 /*
393 * No earlier use/def can reach this load if:
394 * 1) Head instruction is reached
395 * 2) load target register is clobbered
396 * 3) A branch is seen (stopUseMask has the PC bit set).
397 */
398 if ((checkLIR == headLIR) ||
399 (stopUseMask | stopDefMask) & checkLIR->defMask) {
400 break;
401 }
402 }
403
404 /* The load has been eliminated */
405 if (thisLIR->isNop) continue;
406
407 /*
408 * The load cannot be eliminated. See if it can be hoisted to an
409 * earlier spot.
410 */
411 for (checkLIR = PREV_LIR(thisLIR);
412 /* empty by intention */;
413 checkLIR = PREV_LIR(checkLIR)) {
414
415 if (checkLIR->isNop) continue;
416
417 /*
418 * TUNING: once a full scheduler exists, check here
419 * for conversion of a redundant load into a copy similar
420 * to the way redundant loads are handled above.
421 */
422
423 /* Find out if the load can be yanked past the checkLIR */
424
425 /* Last instruction reached */
426 bool stopHere = (checkLIR == headLIR);
427
428 /* Base address is clobbered by checkLIR */
429 stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
430
431 /* Load target clobbers use/def in checkLIR */
432 stopHere |= ((stopDefMask &
433 (checkLIR->useMask | checkLIR->defMask)) != 0);
434
435 /* Avoid re-ordering literal pool loads */
436 stopHere |= isLiteralLoad(checkLIR);
437
438 /* Don't go too far */
439 stopHere |= (hoistDistance >= maxHoist);
440
441 /* Found a new place to put the load - move it here */
442 if (stopHere == true) {
443 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
444 "HOIST LOAD"));
445 /* The store can be hoisted for at least one cycle */
446 if (hoistDistance != 0) {
447 ArmLIR *newLoadLIR =
448 dvmCompilerNew(sizeof(ArmLIR), true);
449 *newLoadLIR = *thisLIR;
450 newLoadLIR->age = cUnit->optRound;
451 /*
452 * Insertion is guaranteed to succeed since checkLIR
453 * is never the first LIR on the list
454 */
455 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
456 (LIR *) newLoadLIR);
457 thisLIR->isNop = true;
458 }
459 break;
460 }
461
462 /*
463 * Saw a real instruction that hosting the load is
464 * beneficial
465 */
466 if (!isPseudoOpCode(checkLIR->opCode)) {
467 hoistDistance++;
468 }
469 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700470 }
471 }
472}
473
Ben Chenge9695e52009-06-16 16:11:47 -0700474void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
475 LIR *tailLIR)
476{
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700477 if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
478 applyLoadStoreElimination(cUnit, (ArmLIR *) headLIR,
479 (ArmLIR *) tailLIR);
480 }
481 if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
482 applyLoadHoisting(cUnit, (ArmLIR *) headLIR, (ArmLIR *) tailLIR);
483 }
Ben Chenge9695e52009-06-16 16:11:47 -0700484}