blob: 71fc01410203e992ab5dba3463b4ecce086a1515 [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 Chengd7d426a2009-09-22 11:23:36 -070036static inline bool isDalvikRegisterPartiallyClobbered(ArmLIR *lir1,
37 ArmLIR *lir2)
Bill Buzbee270c1d62009-08-13 16:58:07 -070038{
Ben Chengd7d426a2009-09-22 11:23:36 -070039 int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
40 int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
41 int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
42 int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
43
44 return (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
Bill Buzbee270c1d62009-08-13 16:58:07 -070045}
Ben Chengd7d426a2009-09-22 11:23:36 -070046
47static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
48 const char *optimization)
49{
50 LOGD("************ %s ************", optimization);
51 dvmDumpLIRInsn((LIR *) thisLIR, 0);
52 dvmDumpLIRInsn((LIR *) checkLIR, 0);
53}
54
Ben Chenge9695e52009-06-16 16:11:47 -070055/*
56 * Perform a pass of top-down walk to
57 * 1) Eliminate redundant loads and stores
58 * 2) Sink stores to latest possible slot
59 */
60static void applyLoadStoreElimination(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -070061 ArmLIR *headLIR,
62 ArmLIR *tailLIR)
Ben Chenge9695e52009-06-16 16:11:47 -070063{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070064 ArmLIR *thisLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070065
66 cUnit->optRound++;
67 for (thisLIR = headLIR;
68 thisLIR != tailLIR;
69 thisLIR = NEXT_LIR(thisLIR)) {
70 /* Skip newly added instructions */
71 if (thisLIR->age >= cUnit->optRound) {
72 continue;
73 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -070074 if (isDalvikStore(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -070075 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
76 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chenge9695e52009-06-16 16:11:47 -070077 int nativeRegId = thisLIR->operands[0];
Bill Buzbee89efc3d2009-07-28 11:22:22 -070078 ArmLIR *checkLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070079 int sinkDistance = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -070080 /*
81 * Add r15 (pc) to the mask to prevent this instruction
Ben Chengd7d426a2009-09-22 11:23:36 -070082 * from sinking past branch instructions. Unset the Dalvik register
83 * bit when checking with native resource constraints.
Ben Chengdcf3e5d2009-09-11 13:42:05 -070084 */
Ben Chengd7d426a2009-09-22 11:23:36 -070085 u8 stopMask = (ENCODE_REG_PC | thisLIR->useMask) &
86 ~ENCODE_DALVIK_REG;
Ben Chenge9695e52009-06-16 16:11:47 -070087
88 for (checkLIR = NEXT_LIR(thisLIR);
89 checkLIR != tailLIR;
90 checkLIR = NEXT_LIR(checkLIR)) {
91
92 /* Check if a Dalvik register load is redundant */
Bill Buzbee7ea0f642009-08-10 17:06:51 -070093 if (isDalvikLoad(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -070094 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
95 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chenge9695e52009-06-16 16:11:47 -070096 /* Insert a move to replace the load */
97 if (checkLIR->operands[0] != nativeRegId) {
Bill Buzbee7ea0f642009-08-10 17:06:51 -070098 ArmLIR *moveLIR;
99 moveLIR = dvmCompilerRegCopy(cUnit,
100 checkLIR->operands[0],
101 nativeRegId);
Ben Chenge9695e52009-06-16 16:11:47 -0700102 /*
103 * Insertion is guaranteed to succeed since checkLIR
104 * is never the first LIR on the list
105 */
106 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
107 (LIR *) moveLIR);
108 }
109 checkLIR->isNop = true;
110 continue;
111
Ben Chengd7d426a2009-09-22 11:23:36 -0700112 /*
113 * Found a true output dependency - nuke the previous store.
114 * The register type doesn't matter here.
115 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700116 } else if (isDalvikStore(checkLIR) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700117 (checkLIR->aliasInfo == thisLIR->aliasInfo)) {
Ben Chenge9695e52009-06-16 16:11:47 -0700118 thisLIR->isNop = true;
119 break;
120 /* Find out the latest slot that the store can be sunk into */
121 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700122 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700123 bool stopHere = (NEXT_LIR(checkLIR) == tailLIR);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700124
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700125 /* Store data is clobbered */
Ben Chengd7d426a2009-09-22 11:23:36 -0700126 stopHere |= ((stopMask & checkLIR->defMask) != 0);
127
128 /* Store data partially clobbers the Dalvik register */
129 if (stopHere == false &&
130 ((checkLIR->useMask | checkLIR->defMask) &
131 ENCODE_DALVIK_REG)) {
132 stopHere = isDalvikRegisterPartiallyClobbered(thisLIR,
133 checkLIR);
134 }
Ben Chenge9695e52009-06-16 16:11:47 -0700135
136 /* Found a new place to put the store - move it here */
137 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700138 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
139 "SINK STORE"));
Ben Chenge9695e52009-06-16 16:11:47 -0700140 /* The store can be sunk for at least one cycle */
141 if (sinkDistance != 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700142 ArmLIR *newStoreLIR =
143 dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700144 *newStoreLIR = *thisLIR;
145 newStoreLIR->age = cUnit->optRound;
146 /*
147 * Insertion is guaranteed to succeed since checkLIR
148 * is never the first LIR on the list
149 */
150 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
151 (LIR *) newStoreLIR);
152 thisLIR->isNop = true;
153 }
154 break;
155 }
156
157 /*
158 * Saw a real instruction that the store can be sunk after
159 */
160 if (!isPseudoOpCode(checkLIR->opCode)) {
161 sinkDistance++;
162 }
163 }
164 }
165 }
166 }
167}
168
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700169static void applyLoadHoisting(CompilationUnit *cUnit,
170 ArmLIR *headLIR,
171 ArmLIR *tailLIR)
172{
173 ArmLIR *thisLIR;
174
175 cUnit->optRound++;
176 for (thisLIR = headLIR;
177 thisLIR != tailLIR;
178 thisLIR = NEXT_LIR(thisLIR)) {
179 /* Skip newly added instructions */
180 if (thisLIR->age >= cUnit->optRound ||
181 thisLIR->isNop == true) {
182 continue;
183 }
184 if (isDalvikLoad(thisLIR)) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700185 int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
186 int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700187 int nativeRegId = thisLIR->operands[0];
188 ArmLIR *checkLIR;
189 int hoistDistance = 0;
Ben Chengd7d426a2009-09-22 11:23:36 -0700190 u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
191 ~ENCODE_DALVIK_REG;
192 u8 stopDefMask = thisLIR->defMask & ~ENCODE_DALVIK_REG;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700193
Ben Chengd7d426a2009-09-22 11:23:36 -0700194 /* First check if the load can be completely elinimated */
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700195 for (checkLIR = PREV_LIR(thisLIR);
196 checkLIR != headLIR;
197 checkLIR = PREV_LIR(checkLIR)) {
198
199 if (checkLIR->isNop) continue;
200
Ben Chengd7d426a2009-09-22 11:23:36 -0700201 /*
202 * Check if the Dalvik register is previously accessed
203 * with exactly the same type.
204 */
205 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
206 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
207 (checkLIR->operands[0] == nativeRegId)) {
208 /*
209 * If it is previously accessed but with a different type,
210 * the search will terminate later at the point checking
211 * for partially overlapping stores.
212 */
213 thisLIR->isNop = true;
214 break;
215 }
216
217 /*
218 * No earlier use/def can reach this load if:
219 * 1) Head instruction is reached
220 * 2) load target register is clobbered
221 * 3) A branch is seen (stopUseMask has the PC bit set).
222 */
223 if ((checkLIR == headLIR) ||
224 (stopUseMask | stopDefMask) & checkLIR->defMask) {
225 break;
226 }
227
228 /* Store data partially clobbers the Dalvik register */
229 if (isDalvikStore(checkLIR) &&
230 isDalvikRegisterPartiallyClobbered(thisLIR, checkLIR)) {
231 break;
232 }
233 }
234
235 /* The load has been eliminated */
236 if (thisLIR->isNop) continue;
237
238 /*
239 * The load cannot be eliminated. See if it can be hoisted to an
240 * earlier spot.
241 */
242 for (checkLIR = PREV_LIR(thisLIR);
243 /* empty by intention */;
244 checkLIR = PREV_LIR(checkLIR)) {
245
246 if (checkLIR->isNop) continue;
247
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700248 /* Check if the current load is redundant */
249 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
Ben Chengd7d426a2009-09-22 11:23:36 -0700250 (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
251 (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700252 /* Insert a move to replace the load */
253 if (checkLIR->operands[0] != nativeRegId) {
254 ArmLIR *moveLIR;
255 moveLIR = dvmCompilerRegCopy(cUnit,
256 nativeRegId,
257 checkLIR->operands[0]);
258 /*
259 * Convert *thisLIR* load into a move
260 */
261 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
262 (LIR *) moveLIR);
263 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700264 thisLIR->isNop = true;
265 break;
266
267 /* Find out if the load can be yanked past the checkLIR */
268 } else {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700269 /* Last instruction reached */
Ben Chengd7d426a2009-09-22 11:23:36 -0700270 bool stopHere = (checkLIR == headLIR);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700271
272 /* Base address is clobbered by checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700273 stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700274
275 /* Load target clobbers use/def in checkLIR */
Ben Chengd7d426a2009-09-22 11:23:36 -0700276 stopHere |= ((stopDefMask &
277 (checkLIR->useMask | checkLIR->defMask)) != 0);
278
279 /* Store data partially clobbers the Dalvik register */
280 if (stopHere == false &&
281 (checkLIR->defMask & ENCODE_DALVIK_REG)) {
282 stopHere = isDalvikRegisterPartiallyClobbered(thisLIR,
283 checkLIR);
284 }
285
286 /*
287 * Stop at an earlier Dalvik load if the offset of checkLIR
288 * is not less than thisLIR
289 *
290 * Experiments show that doing
291 *
292 * ldr r1, [r5, #16]
293 * ldr r0, [r5, #20]
294 *
295 * is much faster than
296 *
297 * ldr r0, [r5, #20]
298 * ldr r1, [r5, #16]
299 */
300 if (isDalvikLoad(checkLIR)) {
301 int dRegId2 =
302 DECODE_ALIAS_INFO_REG(checkLIR->aliasInfo);
303 if (dRegId2 <= dRegId) {
304 stopHere = true;
305 }
306 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700307
308 /* Found a new place to put the load - move it here */
309 if (stopHere == true) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700310 DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
311 "HOIST LOAD"));
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700312 /* The store can be hoisted for at least one cycle */
313 if (hoistDistance != 0) {
314 ArmLIR *newLoadLIR =
315 dvmCompilerNew(sizeof(ArmLIR), true);
316 *newLoadLIR = *thisLIR;
317 newLoadLIR->age = cUnit->optRound;
318 /*
319 * Insertion is guaranteed to succeed since checkLIR
320 * is never the first LIR on the list
321 */
322 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
323 (LIR *) newLoadLIR);
324 thisLIR->isNop = true;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700325 }
326 break;
327 }
328
329 /*
Ben Chengd7d426a2009-09-22 11:23:36 -0700330 * Saw a real instruction that hosting the load is
331 * beneficial
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700332 */
333 if (!isPseudoOpCode(checkLIR->opCode)) {
334 hoistDistance++;
335 }
336 }
337 }
338 }
339 }
340}
341
Ben Chenge9695e52009-06-16 16:11:47 -0700342void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
343 LIR *tailLIR)
344{
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700345 if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
346 applyLoadStoreElimination(cUnit, (ArmLIR *) headLIR,
347 (ArmLIR *) tailLIR);
348 }
349 if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
350 applyLoadHoisting(cUnit, (ArmLIR *) headLIR, (ArmLIR *) tailLIR);
351 }
Ben Chenge9695e52009-06-16 16:11:47 -0700352}