blob: 4a2768c02dbb4cbeaef88f27b2ff9b3f3694fae2 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
27/* Track exercised opcodes */
28static int opcodeCoverage[kNumPackedOpcodes];
29
buzbeeed3e9302011-09-23 17:34:19 -070030STATIC void setMemRefType(ArmLIR* lir, bool isLoad, int memType)
buzbee67bf8852011-08-17 17:51:35 -070031{
32 u8 *maskPtr;
33 u8 mask = ENCODE_MEM;;
buzbeeed3e9302011-09-23 17:34:19 -070034 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
buzbee67bf8852011-08-17 17:51:35 -070035 if (isLoad) {
36 maskPtr = &lir->useMask;
37 } else {
38 maskPtr = &lir->defMask;
39 }
40 /* Clear out the memref flags */
41 *maskPtr &= ~mask;
42 /* ..and then add back the one we need */
43 switch(memType) {
44 case kLiteral:
buzbeeed3e9302011-09-23 17:34:19 -070045 DCHECK(isLoad);
buzbee67bf8852011-08-17 17:51:35 -070046 *maskPtr |= ENCODE_LITERAL;
47 break;
48 case kDalvikReg:
49 *maskPtr |= ENCODE_DALVIK_REG;
50 break;
51 case kHeapRef:
52 *maskPtr |= ENCODE_HEAP_REF;
53 break;
54 case kMustNotAlias:
55 /* Currently only loads can be marked as kMustNotAlias */
buzbeeed3e9302011-09-23 17:34:19 -070056 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
buzbee67bf8852011-08-17 17:51:35 -070057 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
58 break;
59 default:
60 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
61 }
62}
63
64/*
65 * Mark load/store instructions that access Dalvik registers through r5FP +
66 * offset.
67 */
buzbeeed3e9302011-09-23 17:34:19 -070068STATIC void annotateDalvikRegAccess(ArmLIR* lir, int regId, bool isLoad)
buzbee67bf8852011-08-17 17:51:35 -070069{
70 setMemRefType(lir, isLoad, kDalvikReg);
71
72 /*
73 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
74 * access.
75 */
76 lir->aliasInfo = regId;
77 if (DOUBLEREG(lir->operands[0])) {
78 lir->aliasInfo |= 0x80000000;
79 }
80}
81
82/*
83 * Decode the register id.
84 */
buzbeeed3e9302011-09-23 17:34:19 -070085STATIC inline u8 getRegMaskCommon(int reg)
buzbee67bf8852011-08-17 17:51:35 -070086{
87 u8 seed;
88 int shift;
89 int regId = reg & 0x1f;
90
91 /*
92 * Each double register is equal to a pair of single-precision FP registers
93 */
94 seed = DOUBLEREG(reg) ? 3 : 1;
95 /* FP register starts at bit position 16 */
96 shift = FPREG(reg) ? kFPReg0 : 0;
97 /* Expand the double register id into single offset */
98 shift += regId;
99 return (seed << shift);
100}
101
102/*
103 * Mark the corresponding bit(s).
104 */
buzbeeed3e9302011-09-23 17:34:19 -0700105STATIC inline void setupRegMask(u8* mask, int reg)
buzbee67bf8852011-08-17 17:51:35 -0700106{
107 *mask |= getRegMaskCommon(reg);
108}
109
110/*
111 * Set up the proper fields in the resource mask
112 */
buzbeeed3e9302011-09-23 17:34:19 -0700113STATIC void setupResourceMasks(ArmLIR* lir)
buzbee67bf8852011-08-17 17:51:35 -0700114{
115 int opcode = lir->opcode;
116 int flags;
117
118 if (opcode <= 0) {
119 lir->useMask = lir->defMask = 0;
120 return;
121 }
122
123 flags = EncodingMap[lir->opcode].flags;
124
125 /* Set up the mask for resources that are updated */
126 if (flags & (IS_LOAD | IS_STORE)) {
127 /* Default to heap - will catch specialized classes later */
128 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
129 }
130
131 /*
132 * Conservatively assume the branch here will call out a function that in
133 * turn will trash everything.
134 */
135 if (flags & IS_BRANCH) {
136 lir->defMask = lir->useMask = ENCODE_ALL;
137 return;
138 }
139
140 if (flags & REG_DEF0) {
141 setupRegMask(&lir->defMask, lir->operands[0]);
142 }
143
144 if (flags & REG_DEF1) {
145 setupRegMask(&lir->defMask, lir->operands[1]);
146 }
147
148 if (flags & REG_DEF_SP) {
149 lir->defMask |= ENCODE_REG_SP;
150 }
151
152 if (flags & REG_DEF_LR) {
153 lir->defMask |= ENCODE_REG_LR;
154 }
155
156 if (flags & REG_DEF_LIST0) {
157 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
158 }
159
160 if (flags & REG_DEF_LIST1) {
161 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
162 }
163
164 if (flags & REG_DEF_FPCS_LIST0) {
165 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
166 }
167
buzbeef48e9712011-09-15 17:54:28 -0700168 if (flags & REG_DEF_FPCS_LIST2) {
169 for (int i = 0; i < lir->operands[2]; i++) {
170 setupRegMask(&lir->defMask, lir->operands[1] + i);
171 }
172 }
173
buzbee67bf8852011-08-17 17:51:35 -0700174 if (flags & SETS_CCODES) {
175 lir->defMask |= ENCODE_CCODE;
176 }
177
178 /* Conservatively treat the IT block */
179 if (flags & IS_IT) {
180 lir->defMask = ENCODE_ALL;
181 }
182
183 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
184 int i;
185
186 for (i = 0; i < 4; i++) {
187 if (flags & (1 << (kRegUse0 + i))) {
188 setupRegMask(&lir->useMask, lir->operands[i]);
189 }
190 }
191 }
192
193 if (flags & REG_USE_PC) {
194 lir->useMask |= ENCODE_REG_PC;
195 }
196
197 if (flags & REG_USE_SP) {
198 lir->useMask |= ENCODE_REG_SP;
199 }
200
201 if (flags & REG_USE_LIST0) {
202 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
203 }
204
205 if (flags & REG_USE_LIST1) {
206 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
207 }
208
209 if (flags & REG_USE_FPCS_LIST0) {
210 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
211 }
212
213 if (flags & REG_USE_FPCS_LIST2) {
buzbeef48e9712011-09-15 17:54:28 -0700214 for (int i = 0; i < lir->operands[2]; i++) {
215 setupRegMask(&lir->useMask, lir->operands[1] + i);
216 }
buzbee67bf8852011-08-17 17:51:35 -0700217 }
218
219 if (flags & USES_CCODES) {
220 lir->useMask |= ENCODE_CCODE;
221 }
222
223 /* Fixup for kThumbPush/lr and kThumbPop/pc */
224 if (opcode == kThumbPush || opcode == kThumbPop) {
225 u8 r8Mask = getRegMaskCommon(r8);
226 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
227 lir->useMask &= ~r8Mask;
228 lir->useMask |= ENCODE_REG_LR;
229 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
230 lir->defMask &= ~r8Mask;
231 lir->defMask |= ENCODE_REG_PC;
232 }
233 }
234}
235
236/*
buzbee67bf8852011-08-17 17:51:35 -0700237 * The following are building blocks to construct low-level IRs with 0 - 4
238 * operands.
239 */
buzbeeed3e9302011-09-23 17:34:19 -0700240STATIC ArmLIR* newLIR0(CompilationUnit* cUnit, ArmOpcode opcode)
buzbee67bf8852011-08-17 17:51:35 -0700241{
242 ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
buzbeeed3e9302011-09-23 17:34:19 -0700243 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbee67bf8852011-08-17 17:51:35 -0700244 insn->opcode = opcode;
245 setupResourceMasks(insn);
246 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
247 oatAppendLIR(cUnit, (LIR*) insn);
248 return insn;
249}
250
buzbeeed3e9302011-09-23 17:34:19 -0700251STATIC ArmLIR* newLIR1(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700252 int dest)
253{
254 ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
buzbeeed3e9302011-09-23 17:34:19 -0700255 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbee67bf8852011-08-17 17:51:35 -0700256 insn->opcode = opcode;
257 insn->operands[0] = dest;
258 setupResourceMasks(insn);
259 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
260 oatAppendLIR(cUnit, (LIR*) insn);
261 return insn;
262}
263
buzbeeed3e9302011-09-23 17:34:19 -0700264STATIC ArmLIR* newLIR2(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700265 int dest, int src1)
266{
267 ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
buzbeeed3e9302011-09-23 17:34:19 -0700268 DCHECK(isPseudoOpcode(opcode) ||
buzbee67bf8852011-08-17 17:51:35 -0700269 (EncodingMap[opcode].flags & IS_BINARY_OP));
270 insn->opcode = opcode;
271 insn->operands[0] = dest;
272 insn->operands[1] = src1;
273 setupResourceMasks(insn);
274 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
275 oatAppendLIR(cUnit, (LIR*) insn);
276 return insn;
277}
278
buzbeeed3e9302011-09-23 17:34:19 -0700279STATIC ArmLIR* newLIR3(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700280 int dest, int src1, int src2)
281{
282 ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700283 DCHECK(isPseudoOpcode(opcode) ||
284 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
285 << (int)opcode << " "
286 << PrettyMethod(cUnit->method) << " "
287 << cUnit->currentDalvikOffset;
buzbee67bf8852011-08-17 17:51:35 -0700288 insn->opcode = opcode;
289 insn->operands[0] = dest;
290 insn->operands[1] = src1;
291 insn->operands[2] = src2;
292 setupResourceMasks(insn);
293 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
294 oatAppendLIR(cUnit, (LIR*) insn);
295 return insn;
296}
297
298#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
buzbeeed3e9302011-09-23 17:34:19 -0700299STATIC ArmLIR* newLIR4(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700300 int dest, int src1, int src2, int info)
301{
302 ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
buzbeeed3e9302011-09-23 17:34:19 -0700303 DCHECK(isPseudoOpcode(opcode) ||
buzbee67bf8852011-08-17 17:51:35 -0700304 (EncodingMap[opcode].flags & IS_QUAD_OP));
305 insn->opcode = opcode;
306 insn->operands[0] = dest;
307 insn->operands[1] = src1;
308 insn->operands[2] = src2;
309 insn->operands[3] = info;
310 setupResourceMasks(insn);
311 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
312 oatAppendLIR(cUnit, (LIR*) insn);
313 return insn;
314}
315#endif
316
317/*
318 * Search the existing constants in the literal pool for an exact or close match
319 * within specified delta (greater or equal to 0).
320 */
buzbeeed3e9302011-09-23 17:34:19 -0700321STATIC ArmLIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
buzbee67bf8852011-08-17 17:51:35 -0700322{
323 while (dataTarget) {
324 if (((unsigned) (value - ((ArmLIR* ) dataTarget)->operands[0])) <=
325 delta)
326 return (ArmLIR* ) dataTarget;
327 dataTarget = dataTarget->next;
328 }
329 return NULL;
330}
331
buzbee03fa2632011-09-20 17:10:57 -0700332/* Search the existing constants in the literal pool for an exact wide match */
buzbeeed3e9302011-09-23 17:34:19 -0700333STATIC ArmLIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
buzbee03fa2632011-09-20 17:10:57 -0700334{
335 bool loMatch = false;
336 LIR* loTarget = NULL;
337 while (dataTarget) {
338 if (loMatch && (((ArmLIR*)dataTarget)->operands[0] == valHi)) {
339 return (ArmLIR*)loTarget;
340 }
341 loMatch = false;
342 if (((ArmLIR*)dataTarget)->operands[0] == valLo) {
343 loMatch = true;
344 loTarget = dataTarget;
345 }
346 dataTarget = dataTarget->next;
347 }
348 return NULL;
349}
350
buzbee67bf8852011-08-17 17:51:35 -0700351/*
352 * The following are building blocks to insert constants into the pool or
353 * instruction streams.
354 */
355
356/* Add a 32-bit constant either in the constant pool or mixed with code */
buzbeeed3e9302011-09-23 17:34:19 -0700357STATIC ArmLIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
buzbee67bf8852011-08-17 17:51:35 -0700358 int value)
359{
360 /* Add the constant to the literal pool */
361 if (constantListP) {
362 ArmLIR* newValue = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
363 newValue->operands[0] = value;
364 newValue->generic.next = *constantListP;
365 *constantListP = (LIR*) newValue;
366 return newValue;
367 } else {
368 /* Add the constant in the middle of code stream */
369 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
370 newLIR1(cUnit, kArm16BitData, (value >> 16));
371 }
372 return NULL;
373}
374
buzbee03fa2632011-09-20 17:10:57 -0700375/* Add a 64-bit constant to the constant pool or mixed with code */
buzbeeed3e9302011-09-23 17:34:19 -0700376STATIC ArmLIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
buzbee03fa2632011-09-20 17:10:57 -0700377 int valLo, int valHi)
378{
379 ArmLIR* res;
380 //NOTE: hard-coded little endian
381 if (constantListP == NULL) {
382 res = addWordData(cUnit, NULL, valLo);
383 addWordData(cUnit, NULL, valHi);
384 } else {
385 // Insert high word into list first
386 addWordData(cUnit, constantListP, valHi);
387 res = addWordData(cUnit, constantListP, valLo);
388 }
389 return res;
390}
391
buzbee67bf8852011-08-17 17:51:35 -0700392/*
393 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
394 * blocks.
395 */
buzbeeed3e9302011-09-23 17:34:19 -0700396STATIC void genBarrier(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700397{
398 ArmLIR* barrier = newLIR0(cUnit, kArmPseudoBarrier);
399 /* Mark all resources as being clobbered */
400 barrier->defMask = -1;
401}