blob: 86f692f750a198242d0a9ade7d9c7418a5f22630 [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 Chenge9695e52009-06-16 16:11:47 -070020
Ben Chengd7d426a2009-09-22 11:23:36 -070021#define DEBUG_OPT(X)
22
Bill Buzbee7ea0f642009-08-10 17:06:51 -070023ArmLIR* dvmCompilerGenCopy(CompilationUnit *cUnit, int rDest, int rSrc);
24
25/* Is this a Dalvik register access? */
26static inline bool isDalvikLoad(ArmLIR *lir)
27{
Ben Chengd7d426a2009-09-22 11:23:36 -070028 return (lir->useMask != ~0ULL) && (lir->useMask & ENCODE_DALVIK_REG);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070029}
30
31static inline bool isDalvikStore(ArmLIR *lir)
32{
Ben Chengd7d426a2009-09-22 11:23:36 -070033 return (lir->defMask != ~0ULL) && (lir->defMask & ENCODE_DALVIK_REG);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070034}
35
Ben Chenga4aaf682009-09-30 22:53:44 -070036static inline bool isDalvikRegisterClobbered(ArmLIR *lir1, ArmLIR *lir2)
Bill Buzbee270c1d62009-08-13 16:58:07 -070037{
Ben Chengd7d426a2009-09-22 11:23:36 -070038 int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
39 int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
40 int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
41 int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
42
Ben Chenga4aaf682009-09-30 22:53:44 -070043 return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
Bill Buzbee270c1d62009-08-13 16:58:07 -070044}
Ben Chengd7d426a2009-09-22 11:23:36 -070045
46static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
47 const char *optimization)
48{
49 LOGD("************ %s ************", optimization);
50 dvmDumpLIRInsn((LIR *) thisLIR, 0);
51 dvmDumpLIRInsn((LIR *) checkLIR, 0);
52}
53
Ben Chenge9695e52009-06-16 16:11:47 -070054/*
55 * Perform a pass of top-down walk to
56 * 1) Eliminate redundant loads and stores
57 * 2) Sink stores to latest possible slot
58 */
59static void applyLoadStoreElimination(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -070060 ArmLIR *headLIR,
61 ArmLIR *tailLIR)
Ben Chenge9695e52009-06-16 16:11:47 -070062{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070063 ArmLIR *thisLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070064
65 cUnit->optRound++;
66 for (thisLIR = headLIR;
67 thisLIR != tailLIR;
68 thisLIR = NEXT_LIR(thisLIR)) {
69 /* Skip newly added instructions */
70 if (thisLIR->age >= cUnit->optRound) {
71 continue;
72 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -070073 if (isDalvikStore(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -070074 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
75 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chenge9695e52009-06-16 16:11:47 -070076 int nativeRegId = thisLIR->operands[0];
Bill Buzbee89efc3d2009-07-28 11:22:22 -070077 ArmLIR *checkLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070078 int sinkDistance = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -070079 /*
80 * Add r15 (pc) to the mask to prevent this instruction
Ben Chengd7d426a2009-09-22 11:23:36 -070081 * from sinking past branch instructions. Unset the Dalvik register
82 * bit when checking with native resource constraints.
Ben Chengdcf3e5d2009-09-11 13:42:05 -070083 */
Ben Chengd7d426a2009-09-22 11:23:36 -070084 u8 stopMask = (ENCODE_REG_PC | thisLIR->useMask) &
85 ~ENCODE_DALVIK_REG;
Ben Chenge9695e52009-06-16 16:11:47 -070086
87 for (checkLIR = NEXT_LIR(thisLIR);
88 checkLIR != tailLIR;
89 checkLIR = NEXT_LIR(checkLIR)) {
90
91 /* Check if a Dalvik register load is redundant */
Bill Buzbee7ea0f642009-08-10 17:06:51 -070092 if (isDalvikLoad(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -070093 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
94 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chenge9695e52009-06-16 16:11:47 -070095 /* Insert a move to replace the load */
96 if (checkLIR->operands[0] != nativeRegId) {
Bill Buzbee7ea0f642009-08-10 17:06:51 -070097 ArmLIR *moveLIR;
98 moveLIR = dvmCompilerRegCopy(cUnit,
99 checkLIR->operands[0],
100 nativeRegId);
Ben Chenge9695e52009-06-16 16:11:47 -0700101 /*
102 * Insertion is guaranteed to succeed since checkLIR
103 * is never the first LIR on the list
104 */
105 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
106 (LIR *) moveLIR);
107 }
108 checkLIR->isNop = true;
109 continue;
110
Ben Chengd7d426a2009-09-22 11:23:36 -0700111 /*
112 * Found a true output dependency - nuke the previous store.
113 * The register type doesn't matter here.
114 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700115 } else if (isDalvikStore(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700116 (checkLIR->aliasInfo == thisLIR->aliasInfo)) {
Ben Chenge9695e52009-06-16 16:11:47 -0700117 thisLIR->isNop = true;
118 break;
119 /* Find out the latest slot that the store can be sunk into */
120 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700121 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700122 bool stopHere = (NEXT_LIR(checkLIR) == tailLIR);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700123
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700124 /* Store data is clobbered */
Ben Chengd7d426a2009-09-22 11:23:36 -0700125 stopHere |= ((stopMask & checkLIR->defMask) != 0);
126
127 /* Store data partially clobbers the Dalvik register */
128 if (stopHere == false &&
129 ((checkLIR->useMask | checkLIR->defMask) &
130 ENCODE_DALVIK_REG)) {
Ben Chenga4aaf682009-09-30 22:53:44 -0700131 stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
Ben Chengd7d426a2009-09-22 11:23:36 -0700132 }
Ben Chenge9695e52009-06-16 16:11:47 -0700133
134 /* Found a new place to put the store - move it here */
135 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700136 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
137 "SINK STORE"));
Ben Chenge9695e52009-06-16 16:11:47 -0700138 /* The store can be sunk for at least one cycle */
139 if (sinkDistance != 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700140 ArmLIR *newStoreLIR =
141 dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700142 *newStoreLIR = *thisLIR;
143 newStoreLIR->age = cUnit->optRound;
144 /*
145 * Insertion is guaranteed to succeed since checkLIR
146 * is never the first LIR on the list
147 */
148 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
149 (LIR *) newStoreLIR);
150 thisLIR->isNop = true;
151 }
152 break;
153 }
154
155 /*
156 * Saw a real instruction that the store can be sunk after
157 */
158 if (!isPseudoOpCode(checkLIR->opCode)) {
159 sinkDistance++;
160 }
161 }
162 }
163 }
164 }
165}
166
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700167static void applyLoadHoisting(CompilationUnit *cUnit,
168 ArmLIR *headLIR,
169 ArmLIR *tailLIR)
170{
171 ArmLIR *thisLIR;
172
173 cUnit->optRound++;
174 for (thisLIR = headLIR;
175 thisLIR != tailLIR;
176 thisLIR = NEXT_LIR(thisLIR)) {
177 /* Skip newly added instructions */
178 if (thisLIR->age >= cUnit->optRound ||
179 thisLIR->isNop == true) {
180 continue;
181 }
182 if (isDalvikLoad(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700183 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
184 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700185 int nativeRegId = thisLIR->operands[0];
186 ArmLIR *checkLIR;
187 int hoistDistance = 0;
Ben Chengd7d426a2009-09-22 11:23:36 -0700188 u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
189 ~ENCODE_DALVIK_REG;
190 u8 stopDefMask = thisLIR->defMask & ~ENCODE_DALVIK_REG;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700191
Ben Chengd7d426a2009-09-22 11:23:36 -0700192 /* First check if the load can be completely elinimated */
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700193 for (checkLIR = PREV_LIR(thisLIR);
194 checkLIR != headLIR;
195 checkLIR = PREV_LIR(checkLIR)) {
196
197 if (checkLIR->isNop) continue;
198
Ben Chengd7d426a2009-09-22 11:23:36 -0700199 /*
200 * Check if the Dalvik register is previously accessed
201 * with exactly the same type.
202 */
203 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
204 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
205 (checkLIR->operands[0] == nativeRegId)) {
206 /*
207 * If it is previously accessed but with a different type,
208 * the search will terminate later at the point checking
209 * for partially overlapping stores.
210 */
211 thisLIR->isNop = true;
212 break;
213 }
214
215 /*
216 * No earlier use/def can reach this load if:
217 * 1) Head instruction is reached
218 * 2) load target register is clobbered
219 * 3) A branch is seen (stopUseMask has the PC bit set).
220 */
221 if ((checkLIR == headLIR) ||
222 (stopUseMask | stopDefMask) & checkLIR->defMask) {
223 break;
224 }
225
226 /* Store data partially clobbers the Dalvik register */
227 if (isDalvikStore(checkLIR) &&
Ben Chenga4aaf682009-09-30 22:53:44 -0700228 isDalvikRegisterClobbered(thisLIR, checkLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700229 break;
230 }
231 }
232
233 /* The load has been eliminated */
234 if (thisLIR->isNop) continue;
235
236 /*
237 * The load cannot be eliminated. See if it can be hoisted to an
238 * earlier spot.
239 */
240 for (checkLIR = PREV_LIR(thisLIR);
241 /* empty by intention */;
242 checkLIR = PREV_LIR(checkLIR)) {
243
244 if (checkLIR->isNop) continue;
245
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700246 /* Check if the current load is redundant */
247 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700248 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
249 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700250 /* Insert a move to replace the load */
251 if (checkLIR->operands[0] != nativeRegId) {
252 ArmLIR *moveLIR;
253 moveLIR = dvmCompilerRegCopy(cUnit,
254 nativeRegId,
255 checkLIR->operands[0]);
256 /*
257 * Convert *thisLIR* load into a move
258 */
259 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
260 (LIR *) moveLIR);
261 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700262 thisLIR->isNop = true;
263 break;
264
265 /* Find out if the load can be yanked past the checkLIR */
266 } else {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700267 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700268 bool stopHere = (checkLIR == headLIR);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700269
270 /* Base address is clobbered by checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700271 stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700272
273 /* Load target clobbers use/def in checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700274 stopHere |= ((stopDefMask &
275 (checkLIR->useMask | checkLIR->defMask)) != 0);
276
277 /* Store data partially clobbers the Dalvik register */
278 if (stopHere == false &&
279 (checkLIR->defMask & ENCODE_DALVIK_REG)) {
Ben Chenga4aaf682009-09-30 22:53:44 -0700280 stopHere = isDalvikRegisterClobbered(thisLIR, checkLIR);
Ben Chengd7d426a2009-09-22 11:23:36 -0700281 }
282
283 /*
284 * Stop at an earlier Dalvik load if the offset of checkLIR
285 * is not less than thisLIR
286 *
287 * Experiments show that doing
288 *
289 * ldr r1, [r5, #16]
290 * ldr r0, [r5, #20]
291 *
292 * is much faster than
293 *
294 * ldr r0, [r5, #20]
295 * ldr r1, [r5, #16]
296 */
297 if (isDalvikLoad(checkLIR)) {
298 int dRegId2 =
299 DECODE_ALIAS_INFO_REG(checkLIR->aliasInfo);
300 if (dRegId2 <= dRegId) {
301 stopHere = true;
302 }
303 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700304
305 /* Found a new place to put the load - move it here */
306 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700307 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
308 "HOIST LOAD"));
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700309 /* The store can be hoisted for at least one cycle */
310 if (hoistDistance != 0) {
311 ArmLIR *newLoadLIR =
312 dvmCompilerNew(sizeof(ArmLIR), true);
313 *newLoadLIR = *thisLIR;
314 newLoadLIR->age = cUnit->optRound;
315 /*
316 * Insertion is guaranteed to succeed since checkLIR
317 * is never the first LIR on the list
318 */
319 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
320 (LIR *) newLoadLIR);
321 thisLIR->isNop = true;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700322 }
323 break;
324 }
325
326 /*
Ben Chengd7d426a2009-09-22 11:23:36 -0700327 * Saw a real instruction that hosting the load is
328 * beneficial
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700329 */
330 if (!isPseudoOpCode(checkLIR->opCode)) {
331 hoistDistance++;
332 }
333 }
334 }
335 }
336 }
337}
338
Ben Chenge9695e52009-06-16 16:11:47 -0700339void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
340 LIR *tailLIR)
341{
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700342 if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
343 applyLoadStoreElimination(cUnit, (ArmLIR *) headLIR,
344 (ArmLIR *) tailLIR);
345 }
346 if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
347 applyLoadHoisting(cUnit, (ArmLIR *) headLIR, (ArmLIR *) tailLIR);
348 }
Ben Chenge9695e52009-06-16 16:11:47 -0700349}