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