blob: 1dd009b4e83eae7eafb2965ab4042cf3f4e994a2 [file] [log] [blame]
Bill Buzbee9bc3df32009-07-30 10:52:29 -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/*
18 * This file contains codegen for the Thumb ISA and is intended to be
19 * includes by:and support common to all supported
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25#include "Codegen.h"
26
27/* Routines which must be supplied here */
28static void loadConstant(CompilationUnit *cUnit, int rDest, int value);
29static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr);
30static void genConditionalBranch(CompilationUnit *cUnit,
31 ArmConditionCode cond,
32 ArmLIR *target);
33static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
34static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
35 int rDestHi);
36static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
37 int vDest, int rScratch);
38static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int vDest);
39static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
40static void loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
41 int rDest);
42static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
43 int rScratch);
44static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
45 ArmConditionCode cond, int reg,
46 int checkValue, int dOffset,
47 ArmLIR *pcrLabel);
48
49/*****************************************************************************/
50
51/*
52 * Support for register allocation
53 */
54
55/* non-existent register */
56#define vNone (-1)
57
58/* get the next register in r0..r3 in a round-robin fashion */
59#define NEXT_REG(reg) ((reg + 1) & 3)
60/*
61 * The following are utility routines to help maintain the RegisterScoreboard
62 * state to facilitate register renaming.
63 */
64
65/* Reset the tracker to unknown state */
66static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
67{
68 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
69
70 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
71 registerScoreboard->liveDalvikReg = vNone;
72 registerScoreboard->nativeReg = vNone;
73 registerScoreboard->nativeRegHi = vNone;
74}
75
76/* Kill the corresponding bit in the null-checked register list */
77static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
78{
79 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
80}
81
82/* The Dalvik register pair held in native registers have changed */
83static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
84 int vReg, int mRegLo, int mRegHi)
85{
86 cUnit->registerScoreboard.liveDalvikReg = vReg;
87 cUnit->registerScoreboard.nativeReg = mRegLo;
88 cUnit->registerScoreboard.nativeRegHi = mRegHi;
89 cUnit->registerScoreboard.isWide = true;
90}
91
92/* The Dalvik register held in a native register has changed */
93static inline void updateLiveRegister(CompilationUnit *cUnit,
94 int vReg, int mReg)
95{
96 cUnit->registerScoreboard.liveDalvikReg = vReg;
97 cUnit->registerScoreboard.nativeReg = mReg;
98 cUnit->registerScoreboard.isWide = false;
99}
100
101/*
102 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
103 * the lifetime of cached Dalvik value in a native register.
104 */
105static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
106 bool isWide)
107{
108 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
109
110 /* No live value - suggest to use r0 */
111 if (registerScoreboard->liveDalvikReg == vNone)
112 return r0;
113
114 /* Reuse the previously used native reg */
115 if (registerScoreboard->liveDalvikReg == vSrc) {
116 if (isWide != true) {
117 return registerScoreboard->nativeReg;
118 } else {
119 /* Return either r0 or r2 */
120 return (registerScoreboard->nativeReg + 1) & 2;
121 }
122 }
123
124 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
125 if (isWide) {
126 return (registerScoreboard->nativeReg + 2) & 2;
127 } else {
128 return (registerScoreboard->nativeReg + 1) & 3;
129 }
130
131}
132
133/*****************************************************************************/
134
135/*
136 * Load a immediate using a shortcut if possible; otherwise
137 * grab from the per-translation literal pool
138 */
139static void loadConstant(CompilationUnit *cUnit, int rDest, int value)
140{
141 /* See if the value can be constructed cheaply */
142 if ((value >= 0) && (value <= 255)) {
143 newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
144 return;
145 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
146 newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
147 newLIR2(cUnit, THUMB_MVN, rDest, rDest);
148 return;
149 }
150 /* No shortcut - go ahead and use literal pool */
151 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
152 if (dataTarget == NULL) {
153 dataTarget = addWordData(cUnit, value, false);
154 }
155 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
156 loadPcRel->opCode = THUMB_LDR_PC_REL;
157 loadPcRel->generic.target = (LIR *) dataTarget;
158 loadPcRel->operands[0] = rDest;
159 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
160
161 /*
162 * To save space in the constant pool, we use the ADD_RRI8 instruction to
163 * add up to 255 to an existing constant value.
164 */
165 if (dataTarget->operands[0] != value) {
166 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
167 }
168}
169
170/* Export the Dalvik PC assicated with an instruction to the StackSave area */
171static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
172{
173 int offset = offsetof(StackSaveArea, xtra.currentPc);
174 loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
175 newLIR2(cUnit, THUMB_MOV_RR, rAddr, rFP);
176 newLIR2(cUnit, THUMB_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
177 newLIR3(cUnit, THUMB_STR_RRI5, rDPC, rAddr, 0);
178}
179
180/* Generate conditional branch instructions */
181static void genConditionalBranch(CompilationUnit *cUnit,
182 ArmConditionCode cond,
183 ArmLIR *target)
184{
185 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
186 branch->generic.target = (LIR *) target;
187}
188
189/* Generate unconditional branch instructions */
190static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
191{
192 ArmLIR *branch = newLIR0(cUnit, THUMB_B_UNCOND);
193 branch->generic.target = (LIR *) target;
194 return branch;
195}
196
197/*
198 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
199 * rDestHi
200 */
201static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
202 int rDestHi)
203{
204 /* Use reg + imm5*4 to load the values if possible */
205 if (vSrc <= 30) {
206 newLIR3(cUnit, THUMB_LDR_RRI5, rDestLo, rFP, vSrc);
207 newLIR3(cUnit, THUMB_LDR_RRI5, rDestHi, rFP, vSrc+1);
208 } else {
209 if (vSrc <= 64) {
210 /* Sneak 4 into the base address first */
211 newLIR3(cUnit, THUMB_ADD_RRI3, rDestLo, rFP, 4);
212 newLIR2(cUnit, THUMB_ADD_RI8, rDestLo, (vSrc-1)*4);
213 } else {
214 /* Offset too far from rFP */
215 loadConstant(cUnit, rDestLo, vSrc*4);
216 newLIR3(cUnit, THUMB_ADD_RRR, rDestLo, rFP, rDestLo);
217 }
218 assert(rDestLo < rDestHi);
219 newLIR2(cUnit, THUMB_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
220 }
221}
222
223/*
224 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
225 * vDest+1
226 */
227static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
228 int vDest, int rScratch)
229{
230 killNullCheckedRegister(cUnit, vDest);
231 killNullCheckedRegister(cUnit, vDest+1);
232 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
233
234 /* Use reg + imm5*4 to store the values if possible */
235 if (vDest <= 30) {
236 newLIR3(cUnit, THUMB_STR_RRI5, rSrcLo, rFP, vDest);
237 newLIR3(cUnit, THUMB_STR_RRI5, rSrcHi, rFP, vDest+1);
238 } else {
239 if (vDest <= 64) {
240 /* Sneak 4 into the base address first */
241 newLIR3(cUnit, THUMB_ADD_RRI3, rScratch, rFP, 4);
242 newLIR2(cUnit, THUMB_ADD_RI8, rScratch, (vDest-1)*4);
243 } else {
244 /* Offset too far from rFP */
245 loadConstant(cUnit, rScratch, vDest*4);
246 newLIR3(cUnit, THUMB_ADD_RRR, rScratch, rFP, rScratch);
247 }
248 assert(rSrcLo < rSrcHi);
249 newLIR2(cUnit, THUMB_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
250 }
251}
252
253/* Load the address of a Dalvik register on the frame */
254static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
255{
256 /* RRI3 can add up to 7 */
257 if (vSrc <= 1) {
258 newLIR3(cUnit, THUMB_ADD_RRI3, rDest, rFP, vSrc*4);
259 } else if (vSrc <= 64) {
260 /* Sneak 4 into the base address first */
261 newLIR3(cUnit, THUMB_ADD_RRI3, rDest, rFP, 4);
262 newLIR2(cUnit, THUMB_ADD_RI8, rDest, (vSrc-1)*4);
263 } else {
264 loadConstant(cUnit, rDest, vSrc*4);
265 newLIR3(cUnit, THUMB_ADD_RRR, rDest, rFP, rDest);
266 }
267}
268
269/* Load a float from a Dalvik register */
270static void loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
271{
272 assert(vSrc <= 255); // FIXME - temp limit to 1st 256
273 newLIR3(cUnit, THUMB2_VLDRS, rDest, rFP, vSrc);
274}
275
276/* Store a float to a Dalvik register */
277static void storeFloat(CompilationUnit *cUnit, int rSrc, int vDest,
278 int rScratch)
279{
280 assert(vSrc <= 255); // FIXME - temp limit to 1st 256
281 newLIR3(cUnit, THUMB2_VSTRS, rSrc, rFP, vDest);
282}
283
284/* Load a double from a Dalvik register */
285static void loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
286{
287 assert(vSrc <= 255); // FIXME - temp limit to 1st 256
288 newLIR3(cUnit, THUMB2_VLDRD, rDest, rFP, vSrc);
289}
290
291/* Store a double to a Dalvik register */
292static void storeDouble(CompilationUnit *cUnit, int rSrc, int vDest,
293 int rScratch)
294{
295 assert(vSrc <= 255); // FIXME - temp limit to 1st 256
296 newLIR3(cUnit, THUMB2_VSTRD, rSrc, rFP, vDest);
297}
298
299
300/* Load a single value from rFP[src] and store them into rDest */
301static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
302{
303 /* Use reg + imm5*4 to load the value if possible */
304 if (vSrc <= 31) {
305 newLIR3(cUnit, THUMB_LDR_RRI5, rDest, rFP, vSrc);
306 } else {
307 loadConstant(cUnit, rDest, vSrc*4);
308 newLIR3(cUnit, THUMB_LDR_RRR, rDest, rFP, rDest);
309 }
310}
311
312/* Load a word at base + displacement. Displacement must be word multiple */
313static void loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
314 int rDest)
315{
316 assert((displacement & 0x3) == 0);
317 /* Can it fit in a RRI5? */
318 if (displacement < 128) {
319 newLIR3(cUnit, THUMB_LDR_RRI5, rDest, rBase, displacement >> 2);
320 } else {
321 loadConstant(cUnit, rDest, displacement);
322 newLIR3(cUnit, THUMB_LDR_RRR, rDest, rBase, rDest);
323 }
324}
325
326/* Store a value from rSrc to vDest */
327static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
328 int rScratch)
329{
330 killNullCheckedRegister(cUnit, vDest);
331 updateLiveRegister(cUnit, vDest, rSrc);
332
333 /* Use reg + imm5*4 to store the value if possible */
334 if (vDest <= 31) {
335 newLIR3(cUnit, THUMB_STR_RRI5, rSrc, rFP, vDest);
336 } else {
337 loadConstant(cUnit, rScratch, vDest*4);
338 newLIR3(cUnit, THUMB_STR_RRR, rSrc, rFP, rScratch);
339 }
340}
341
342/*
343 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
344 * satisfies.
345 */
346static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
347 ArmConditionCode cond, int reg,
348 int checkValue, int dOffset,
349 ArmLIR *pcrLabel)
350{
351 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
352 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
353 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
354}