blob: fb6ad30ba7e53e13bc540d696683d6a875825682 [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080017namespace art {
18
buzbee67bf8852011-08-17 17:51:35 -070019/*
20 * This file contains codegen and support common to all supported
21 * ARM variants. It is included by:
22 *
23 * Codegen-$(TARGET_ARCH_VARIANT).c
24 *
25 * which combines this common code with specific support found in the
26 * applicable directory below this one.
27 */
28
29/* Track exercised opcodes */
30static int opcodeCoverage[kNumPackedOpcodes];
31
buzbeeed3e9302011-09-23 17:34:19 -070032STATIC void setMemRefType(ArmLIR* lir, bool isLoad, int memType)
buzbee67bf8852011-08-17 17:51:35 -070033{
34 u8 *maskPtr;
35 u8 mask = ENCODE_MEM;;
buzbeeed3e9302011-09-23 17:34:19 -070036 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
buzbee67bf8852011-08-17 17:51:35 -070037 if (isLoad) {
38 maskPtr = &lir->useMask;
39 } else {
40 maskPtr = &lir->defMask;
41 }
42 /* Clear out the memref flags */
43 *maskPtr &= ~mask;
44 /* ..and then add back the one we need */
45 switch(memType) {
46 case kLiteral:
buzbeeed3e9302011-09-23 17:34:19 -070047 DCHECK(isLoad);
buzbee67bf8852011-08-17 17:51:35 -070048 *maskPtr |= ENCODE_LITERAL;
49 break;
50 case kDalvikReg:
51 *maskPtr |= ENCODE_DALVIK_REG;
52 break;
53 case kHeapRef:
54 *maskPtr |= ENCODE_HEAP_REF;
55 break;
56 case kMustNotAlias:
57 /* Currently only loads can be marked as kMustNotAlias */
buzbeeed3e9302011-09-23 17:34:19 -070058 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
buzbee67bf8852011-08-17 17:51:35 -070059 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
60 break;
61 default:
62 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
63 }
64}
65
66/*
67 * Mark load/store instructions that access Dalvik registers through r5FP +
68 * offset.
69 */
buzbeeed3e9302011-09-23 17:34:19 -070070STATIC void annotateDalvikRegAccess(ArmLIR* lir, int regId, bool isLoad)
buzbee67bf8852011-08-17 17:51:35 -070071{
72 setMemRefType(lir, isLoad, kDalvikReg);
73
74 /*
75 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
76 * access.
77 */
78 lir->aliasInfo = regId;
79 if (DOUBLEREG(lir->operands[0])) {
80 lir->aliasInfo |= 0x80000000;
81 }
82}
83
84/*
85 * Decode the register id.
86 */
buzbeeed3e9302011-09-23 17:34:19 -070087STATIC inline u8 getRegMaskCommon(int reg)
buzbee67bf8852011-08-17 17:51:35 -070088{
89 u8 seed;
90 int shift;
91 int regId = reg & 0x1f;
92
93 /*
94 * Each double register is equal to a pair of single-precision FP registers
95 */
96 seed = DOUBLEREG(reg) ? 3 : 1;
97 /* FP register starts at bit position 16 */
98 shift = FPREG(reg) ? kFPReg0 : 0;
99 /* Expand the double register id into single offset */
100 shift += regId;
101 return (seed << shift);
102}
103
104/*
105 * Mark the corresponding bit(s).
106 */
buzbeeed3e9302011-09-23 17:34:19 -0700107STATIC inline void setupRegMask(u8* mask, int reg)
buzbee67bf8852011-08-17 17:51:35 -0700108{
109 *mask |= getRegMaskCommon(reg);
110}
111
112/*
113 * Set up the proper fields in the resource mask
114 */
buzbeeed3e9302011-09-23 17:34:19 -0700115STATIC void setupResourceMasks(ArmLIR* lir)
buzbee67bf8852011-08-17 17:51:35 -0700116{
117 int opcode = lir->opcode;
118 int flags;
119
120 if (opcode <= 0) {
121 lir->useMask = lir->defMask = 0;
122 return;
123 }
124
125 flags = EncodingMap[lir->opcode].flags;
126
buzbee5abfa3e2012-01-31 17:01:43 -0800127 if (flags & NEEDS_FIXUP) {
128 lir->flags.pcRelFixup = true;
129 }
130
buzbee67bf8852011-08-17 17:51:35 -0700131 /* Set up the mask for resources that are updated */
132 if (flags & (IS_LOAD | IS_STORE)) {
133 /* Default to heap - will catch specialized classes later */
134 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
135 }
136
137 /*
138 * Conservatively assume the branch here will call out a function that in
139 * turn will trash everything.
140 */
141 if (flags & IS_BRANCH) {
142 lir->defMask = lir->useMask = ENCODE_ALL;
143 return;
144 }
145
146 if (flags & REG_DEF0) {
147 setupRegMask(&lir->defMask, lir->operands[0]);
148 }
149
150 if (flags & REG_DEF1) {
151 setupRegMask(&lir->defMask, lir->operands[1]);
152 }
153
154 if (flags & REG_DEF_SP) {
155 lir->defMask |= ENCODE_REG_SP;
156 }
157
158 if (flags & REG_DEF_LR) {
159 lir->defMask |= ENCODE_REG_LR;
160 }
161
162 if (flags & REG_DEF_LIST0) {
163 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
164 }
165
166 if (flags & REG_DEF_LIST1) {
167 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
168 }
169
170 if (flags & REG_DEF_FPCS_LIST0) {
171 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
172 }
173
buzbeef48e9712011-09-15 17:54:28 -0700174 if (flags & REG_DEF_FPCS_LIST2) {
175 for (int i = 0; i < lir->operands[2]; i++) {
176 setupRegMask(&lir->defMask, lir->operands[1] + i);
177 }
178 }
179
buzbee67bf8852011-08-17 17:51:35 -0700180 if (flags & SETS_CCODES) {
181 lir->defMask |= ENCODE_CCODE;
182 }
183
184 /* Conservatively treat the IT block */
185 if (flags & IS_IT) {
186 lir->defMask = ENCODE_ALL;
187 }
188
189 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
190 int i;
191
192 for (i = 0; i < 4; i++) {
193 if (flags & (1 << (kRegUse0 + i))) {
194 setupRegMask(&lir->useMask, lir->operands[i]);
195 }
196 }
197 }
198
199 if (flags & REG_USE_PC) {
200 lir->useMask |= ENCODE_REG_PC;
201 }
202
203 if (flags & REG_USE_SP) {
204 lir->useMask |= ENCODE_REG_SP;
205 }
206
207 if (flags & REG_USE_LIST0) {
208 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
209 }
210
211 if (flags & REG_USE_LIST1) {
212 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
213 }
214
215 if (flags & REG_USE_FPCS_LIST0) {
216 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
217 }
218
219 if (flags & REG_USE_FPCS_LIST2) {
buzbeef48e9712011-09-15 17:54:28 -0700220 for (int i = 0; i < lir->operands[2]; i++) {
221 setupRegMask(&lir->useMask, lir->operands[1] + i);
222 }
buzbee67bf8852011-08-17 17:51:35 -0700223 }
224
225 if (flags & USES_CCODES) {
226 lir->useMask |= ENCODE_CCODE;
227 }
228
229 /* Fixup for kThumbPush/lr and kThumbPop/pc */
230 if (opcode == kThumbPush || opcode == kThumbPop) {
231 u8 r8Mask = getRegMaskCommon(r8);
232 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
233 lir->useMask &= ~r8Mask;
234 lir->useMask |= ENCODE_REG_LR;
235 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
236 lir->defMask &= ~r8Mask;
237 lir->defMask |= ENCODE_REG_PC;
238 }
239 }
240}
241
242/*
buzbee67bf8852011-08-17 17:51:35 -0700243 * The following are building blocks to construct low-level IRs with 0 - 4
244 * operands.
245 */
buzbeeed3e9302011-09-23 17:34:19 -0700246STATIC ArmLIR* newLIR0(CompilationUnit* cUnit, ArmOpcode opcode)
buzbee67bf8852011-08-17 17:51:35 -0700247{
buzbeeba938cb2012-02-03 14:47:55 -0800248 ArmLIR* insn = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbeeed3e9302011-09-23 17:34:19 -0700249 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbee67bf8852011-08-17 17:51:35 -0700250 insn->opcode = opcode;
251 setupResourceMasks(insn);
252 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
253 oatAppendLIR(cUnit, (LIR*) insn);
254 return insn;
255}
256
buzbeeed3e9302011-09-23 17:34:19 -0700257STATIC ArmLIR* newLIR1(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700258 int dest)
259{
buzbeeba938cb2012-02-03 14:47:55 -0800260 ArmLIR* insn = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbeeed3e9302011-09-23 17:34:19 -0700261 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbee67bf8852011-08-17 17:51:35 -0700262 insn->opcode = opcode;
263 insn->operands[0] = dest;
264 setupResourceMasks(insn);
265 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
266 oatAppendLIR(cUnit, (LIR*) insn);
267 return insn;
268}
269
buzbeeed3e9302011-09-23 17:34:19 -0700270STATIC ArmLIR* newLIR2(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700271 int dest, int src1)
272{
buzbeeba938cb2012-02-03 14:47:55 -0800273 ArmLIR* insn = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbeeed3e9302011-09-23 17:34:19 -0700274 DCHECK(isPseudoOpcode(opcode) ||
buzbee67bf8852011-08-17 17:51:35 -0700275 (EncodingMap[opcode].flags & IS_BINARY_OP));
276 insn->opcode = opcode;
277 insn->operands[0] = dest;
278 insn->operands[1] = src1;
279 setupResourceMasks(insn);
280 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
281 oatAppendLIR(cUnit, (LIR*) insn);
282 return insn;
283}
284
buzbeeed3e9302011-09-23 17:34:19 -0700285STATIC ArmLIR* newLIR3(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700286 int dest, int src1, int src2)
287{
buzbeeba938cb2012-02-03 14:47:55 -0800288 ArmLIR* insn = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700289 DCHECK(isPseudoOpcode(opcode) ||
290 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
291 << (int)opcode << " "
Ian Rogersa3760aa2011-11-14 14:32:37 -0800292 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700293 << cUnit->currentDalvikOffset;
buzbee67bf8852011-08-17 17:51:35 -0700294 insn->opcode = opcode;
295 insn->operands[0] = dest;
296 insn->operands[1] = src1;
297 insn->operands[2] = src2;
298 setupResourceMasks(insn);
299 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
300 oatAppendLIR(cUnit, (LIR*) insn);
301 return insn;
302}
303
304#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
buzbeeed3e9302011-09-23 17:34:19 -0700305STATIC ArmLIR* newLIR4(CompilationUnit* cUnit, ArmOpcode opcode,
buzbee67bf8852011-08-17 17:51:35 -0700306 int dest, int src1, int src2, int info)
307{
buzbeeba938cb2012-02-03 14:47:55 -0800308 ArmLIR* insn = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbeeed3e9302011-09-23 17:34:19 -0700309 DCHECK(isPseudoOpcode(opcode) ||
buzbee67bf8852011-08-17 17:51:35 -0700310 (EncodingMap[opcode].flags & IS_QUAD_OP));
311 insn->opcode = opcode;
312 insn->operands[0] = dest;
313 insn->operands[1] = src1;
314 insn->operands[2] = src2;
315 insn->operands[3] = info;
316 setupResourceMasks(insn);
317 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
318 oatAppendLIR(cUnit, (LIR*) insn);
319 return insn;
320}
321#endif
322
323/*
324 * Search the existing constants in the literal pool for an exact or close match
325 * within specified delta (greater or equal to 0).
326 */
buzbeeed3e9302011-09-23 17:34:19 -0700327STATIC ArmLIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
buzbee67bf8852011-08-17 17:51:35 -0700328{
329 while (dataTarget) {
330 if (((unsigned) (value - ((ArmLIR* ) dataTarget)->operands[0])) <=
331 delta)
332 return (ArmLIR* ) dataTarget;
333 dataTarget = dataTarget->next;
334 }
335 return NULL;
336}
337
buzbee03fa2632011-09-20 17:10:57 -0700338/* Search the existing constants in the literal pool for an exact wide match */
buzbeeed3e9302011-09-23 17:34:19 -0700339STATIC ArmLIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
buzbee03fa2632011-09-20 17:10:57 -0700340{
341 bool loMatch = false;
342 LIR* loTarget = NULL;
343 while (dataTarget) {
344 if (loMatch && (((ArmLIR*)dataTarget)->operands[0] == valHi)) {
345 return (ArmLIR*)loTarget;
346 }
347 loMatch = false;
348 if (((ArmLIR*)dataTarget)->operands[0] == valLo) {
349 loMatch = true;
350 loTarget = dataTarget;
351 }
352 dataTarget = dataTarget->next;
353 }
354 return NULL;
355}
356
buzbee67bf8852011-08-17 17:51:35 -0700357/*
358 * The following are building blocks to insert constants into the pool or
359 * instruction streams.
360 */
361
362/* Add a 32-bit constant either in the constant pool or mixed with code */
buzbeeed3e9302011-09-23 17:34:19 -0700363STATIC ArmLIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
buzbee67bf8852011-08-17 17:51:35 -0700364 int value)
365{
366 /* Add the constant to the literal pool */
367 if (constantListP) {
buzbeeba938cb2012-02-03 14:47:55 -0800368 ArmLIR* newValue = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true,
369 kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700370 newValue->operands[0] = value;
371 newValue->generic.next = *constantListP;
372 *constantListP = (LIR*) newValue;
373 return newValue;
374 } else {
375 /* Add the constant in the middle of code stream */
376 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
377 newLIR1(cUnit, kArm16BitData, (value >> 16));
378 }
379 return NULL;
380}
381
buzbee03fa2632011-09-20 17:10:57 -0700382/* Add a 64-bit constant to the constant pool or mixed with code */
buzbeeed3e9302011-09-23 17:34:19 -0700383STATIC ArmLIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
buzbee03fa2632011-09-20 17:10:57 -0700384 int valLo, int valHi)
385{
386 ArmLIR* res;
387 //NOTE: hard-coded little endian
388 if (constantListP == NULL) {
389 res = addWordData(cUnit, NULL, valLo);
390 addWordData(cUnit, NULL, valHi);
391 } else {
392 // Insert high word into list first
393 addWordData(cUnit, constantListP, valHi);
394 res = addWordData(cUnit, constantListP, valLo);
395 }
396 return res;
397}
398
buzbee67bf8852011-08-17 17:51:35 -0700399/*
400 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
401 * blocks.
402 */
buzbeeed3e9302011-09-23 17:34:19 -0700403STATIC void genBarrier(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700404{
405 ArmLIR* barrier = newLIR0(cUnit, kArmPseudoBarrier);
406 /* Mark all resources as being clobbered */
407 barrier->defMask = -1;
408}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800409
410} // namespace art