blob: fbc0e26f1da34258c10b4c1e6ad89e37685e8915 [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
Bill Buzbee7ea0f642009-08-10 17:06:51 -070021ArmLIR* dvmCompilerGenCopy(CompilationUnit *cUnit, int rDest, int rSrc);
22
23/* Is this a Dalvik register access? */
24static inline bool isDalvikLoad(ArmLIR *lir)
25{
26 return ((lir->operands[1] == rFP) &&
27 ((lir->opCode == THUMB_LDR_RRI5) ||
28 (lir->opCode == THUMB2_LDR_RRI12) ||
29 (lir->opCode == THUMB2_VLDRS) ||
30 (lir->opCode == THUMB2_VLDRD)));
31}
32
33static inline bool isDalvikStore(ArmLIR *lir)
34{
35 return ((lir->operands[1] == rFP) &&
36 ((lir->opCode == THUMB_STR_RRI5) ||
37 (lir->opCode == THUMB2_STR_RRI12) ||
38 (lir->opCode == THUMB2_VSTRS) ||
39 (lir->opCode == THUMB2_VSTRD)));
40}
41
Bill Buzbee270c1d62009-08-13 16:58:07 -070042/* Double regs overlap float regs. Return true if collision */
43static bool regClobber(int reg1, int reg2)
44{
45 int reg1a, reg1b;
46 int reg2a, reg2b;
47 if (!FPREG(reg1) || !FPREG(reg2))
48 return (reg1 == reg2);
49 if (DOUBLEREG(reg1)) {
50 reg1a = reg1 & FP_REG_MASK;
51 reg1b = reg1a + 1;
52 } else {
53 reg1a = reg1b = reg1 & FP_REG_MASK;
54 }
55 if (DOUBLEREG(reg2)) {
56 reg2a = reg2 & FP_REG_MASK;
57 reg2b = reg2a + 1;
58 } else {
59 reg2a = reg2b = reg2 & FP_REG_MASK;
60 }
61 return (reg1a == reg2a) || (reg1a == reg2b) ||
62 (reg1b == reg2a) || (reg1b == reg2b);
63}
Ben Chenge9695e52009-06-16 16:11:47 -070064/*
65 * Perform a pass of top-down walk to
66 * 1) Eliminate redundant loads and stores
67 * 2) Sink stores to latest possible slot
68 */
69static void applyLoadStoreElimination(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -070070 ArmLIR *headLIR,
71 ArmLIR *tailLIR)
Ben Chenge9695e52009-06-16 16:11:47 -070072{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070073 ArmLIR *thisLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070074
75 cUnit->optRound++;
76 for (thisLIR = headLIR;
77 thisLIR != tailLIR;
78 thisLIR = NEXT_LIR(thisLIR)) {
79 /* Skip newly added instructions */
80 if (thisLIR->age >= cUnit->optRound) {
81 continue;
82 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -070083 if (isDalvikStore(thisLIR)) {
Ben Chenge9695e52009-06-16 16:11:47 -070084 int dRegId = thisLIR->operands[2];
85 int nativeRegId = thisLIR->operands[0];
Bill Buzbee89efc3d2009-07-28 11:22:22 -070086 ArmLIR *checkLIR;
Ben Chenge9695e52009-06-16 16:11:47 -070087 int sinkDistance = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -070088 /*
89 * Add r15 (pc) to the mask to prevent this instruction
90 * from sinking past branch instructions.
91 */
92 u8 stopMask = ENCODE_GP_REG(rpc) | thisLIR->useMask;
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) &&
100 checkLIR->operands[2] == dRegId ) {
101 if (FPREG(nativeRegId) != FPREG(checkLIR->operands[0])) {
102 break; // TODO: handle gen<=>float copies
103 }
Ben Chenge9695e52009-06-16 16:11:47 -0700104 /* Insert a move to replace the load */
105 if (checkLIR->operands[0] != nativeRegId) {
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700106 ArmLIR *moveLIR;
107 moveLIR = dvmCompilerRegCopy(cUnit,
108 checkLIR->operands[0],
109 nativeRegId);
Ben Chenge9695e52009-06-16 16:11:47 -0700110 /*
111 * Insertion is guaranteed to succeed since checkLIR
112 * is never the first LIR on the list
113 */
114 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
115 (LIR *) moveLIR);
116 }
117 checkLIR->isNop = true;
118 continue;
119
120 /* Found a true output dependency - nuke the previous store */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700121 } else if (isDalvikStore(checkLIR) &&
Ben Chenge9695e52009-06-16 16:11:47 -0700122 checkLIR->operands[2] == dRegId) {
123 thisLIR->isNop = true;
124 break;
125 /* Find out the latest slot that the store can be sunk into */
126 } else {
127 bool stopHere = false;
128
129 /* Last instruction reached */
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700130 stopHere |= NEXT_LIR(checkLIR) == tailLIR;
Ben Chenge9695e52009-06-16 16:11:47 -0700131
Ben Chenge9695e52009-06-16 16:11:47 -0700132 /*
133 * Conservatively assume there is a memory dependency
134 * for st/ld multiples and reg+reg address mode
135 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700136 stopHere |= checkLIR->opCode == THUMB_STMIA ||
137 checkLIR->opCode == THUMB_LDMIA ||
138 checkLIR->opCode == THUMB_STR_RRR ||
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700139 checkLIR->opCode == THUMB_LDR_RRR ||
Bill Buzbee270c1d62009-08-13 16:58:07 -0700140 checkLIR->opCode == THUMB2_STR_RRR ||
141 checkLIR->opCode == THUMB2_LDR_RRR ||
142 checkLIR->opCode == THUMB2_STMIA ||
143 checkLIR->opCode == THUMB2_LDMIA ||
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700144 checkLIR->opCode == THUMB2_VLDRD ||
145 checkLIR->opCode == THUMB2_VSTRD;
Ben Chenge9695e52009-06-16 16:11:47 -0700146
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700147
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700148 /* Store data is clobbered */
149 stopHere |= (stopMask & checkLIR->defMask) != 0;
Ben Chenge9695e52009-06-16 16:11:47 -0700150
151 /* Found a new place to put the store - move it here */
152 if (stopHere == true) {
Ben Chenge9695e52009-06-16 16:11:47 -0700153 /* The store can be sunk for at least one cycle */
154 if (sinkDistance != 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700155 ArmLIR *newStoreLIR =
156 dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700157 *newStoreLIR = *thisLIR;
158 newStoreLIR->age = cUnit->optRound;
159 /*
160 * Insertion is guaranteed to succeed since checkLIR
161 * is never the first LIR on the list
162 */
163 dvmCompilerInsertLIRBefore((LIR *) checkLIR,
164 (LIR *) newStoreLIR);
165 thisLIR->isNop = true;
166 }
167 break;
168 }
169
170 /*
171 * Saw a real instruction that the store can be sunk after
172 */
173 if (!isPseudoOpCode(checkLIR->opCode)) {
174 sinkDistance++;
175 }
176 }
177 }
178 }
179 }
180}
181
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700182static void applyLoadHoisting(CompilationUnit *cUnit,
183 ArmLIR *headLIR,
184 ArmLIR *tailLIR)
185{
186 ArmLIR *thisLIR;
187
188 cUnit->optRound++;
189 for (thisLIR = headLIR;
190 thisLIR != tailLIR;
191 thisLIR = NEXT_LIR(thisLIR)) {
192 /* Skip newly added instructions */
193 if (thisLIR->age >= cUnit->optRound ||
194 thisLIR->isNop == true) {
195 continue;
196 }
197 if (isDalvikLoad(thisLIR)) {
198 int dRegId = thisLIR->operands[2];
199 int nativeRegId = thisLIR->operands[0];
200 ArmLIR *checkLIR;
201 int hoistDistance = 0;
202 u8 stopUseMask = ENCODE_GP_REG(rpc) | thisLIR->useMask;
203 u8 stopDefMask = thisLIR->defMask;
204
205 for (checkLIR = PREV_LIR(thisLIR);
206 checkLIR != headLIR;
207 checkLIR = PREV_LIR(checkLIR)) {
208
209 if (checkLIR->isNop) continue;
210
211 /* Check if the current load is redundant */
212 if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
213 checkLIR->operands[2] == dRegId ) {
214 if (FPREG(nativeRegId) != FPREG(checkLIR->operands[0])) {
215 break; // TODO: handle gen<=>float copies
216 }
217 /* Insert a move to replace the load */
218 if (checkLIR->operands[0] != nativeRegId) {
219 ArmLIR *moveLIR;
220 moveLIR = dvmCompilerRegCopy(cUnit,
221 nativeRegId,
222 checkLIR->operands[0]);
223 /*
224 * Convert *thisLIR* load into a move
225 */
226 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
227 (LIR *) moveLIR);
228 }
229 cUnit->printMe = true;
230 thisLIR->isNop = true;
231 break;
232
233 /* Find out if the load can be yanked past the checkLIR */
234 } else {
235 bool stopHere = false;
236
237 /* Last instruction reached */
238 stopHere |= PREV_LIR(checkLIR) == headLIR;
239
240 /*
241 * Conservatively assume there is a memory dependency
242 * for st/ld multiples and reg+reg address mode
243 */
244 stopHere |= checkLIR->opCode == THUMB_STMIA ||
245 checkLIR->opCode == THUMB_LDMIA ||
246 checkLIR->opCode == THUMB_STR_RRR ||
247 checkLIR->opCode == THUMB_LDR_RRR ||
248 checkLIR->opCode == THUMB2_STR_RRR ||
249 checkLIR->opCode == THUMB2_LDR_RRR ||
250 checkLIR->opCode == THUMB2_STMIA ||
251 checkLIR->opCode == THUMB2_LDMIA ||
252 checkLIR->opCode == THUMB2_VLDRD ||
253 checkLIR->opCode == THUMB2_VSTRD;
254
255 /* Base address is clobbered by checkLIR */
256 stopHere |= (stopUseMask & checkLIR->defMask) != 0;
257
258 /* Load target clobbers use/def in checkLIR */
259 stopHere |= (stopDefMask &
260 (checkLIR->useMask | checkLIR->defMask)) != 0;
261
262 /* Found a new place to put the load - move it here */
263 if (stopHere == true) {
264 /* The store can be hoisted for at least one cycle */
265 if (hoistDistance != 0) {
266 ArmLIR *newLoadLIR =
267 dvmCompilerNew(sizeof(ArmLIR), true);
268 *newLoadLIR = *thisLIR;
269 newLoadLIR->age = cUnit->optRound;
270 /*
271 * Insertion is guaranteed to succeed since checkLIR
272 * is never the first LIR on the list
273 */
274 dvmCompilerInsertLIRAfter((LIR *) checkLIR,
275 (LIR *) newLoadLIR);
276 thisLIR->isNop = true;
277 cUnit->printMe = true;
278 }
279 break;
280 }
281
282 /*
283 * Saw a real instruction that the store can be sunk after
284 */
285 if (!isPseudoOpCode(checkLIR->opCode)) {
286 hoistDistance++;
287 }
288 }
289 }
290 }
291 }
292}
293
Ben Chenge9695e52009-06-16 16:11:47 -0700294void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
295 LIR *tailLIR)
296{
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700297 if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
298 applyLoadStoreElimination(cUnit, (ArmLIR *) headLIR,
299 (ArmLIR *) tailLIR);
300 }
301 if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
302 applyLoadHoisting(cUnit, (ArmLIR *) headLIR, (ArmLIR *) tailLIR);
303 }
Ben Chenge9695e52009-06-16 16:11:47 -0700304}