1 /*
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:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25 static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
26 static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
27 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
28
encodeImmSingle(int value)29 static int encodeImmSingle(int value)
30 {
31 int res;
32 int bitA = (value & 0x80000000) >> 31;
33 int notBitB = (value & 0x40000000) >> 30;
34 int bitB = (value & 0x20000000) >> 29;
35 int bSmear = (value & 0x3e000000) >> 25;
36 int slice = (value & 0x01f80000) >> 19;
37 int zeroes = (value & 0x0007ffff);
38 if (zeroes != 0)
39 return -1;
40 if (bitB) {
41 if ((notBitB != 0) || (bSmear != 0x1f))
42 return -1;
43 } else {
44 if ((notBitB != 1) || (bSmear != 0x0))
45 return -1;
46 }
47 res = (bitA << 7) | (bitB << 6) | slice;
48 return res;
49 }
50
loadFPConstantValue(CompilationUnit * cUnit,int rDest,int value)51 static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
52 int value)
53 {
54 int encodedImm = encodeImmSingle(value);
55 assert(SINGLEREG(rDest));
56 if (value == 0) {
57 // TODO: we need better info about the target CPU. a vector exclusive or
58 // would probably be better here if we could rely on its existance.
59 // Load an immediate +2.0 (which encodes to 0)
60 newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, 0);
61 // +0.0 = +2.0 - +2.0
62 return newLIR3(cUnit, kThumb2Vsubs, rDest, rDest, rDest);
63 } else if (encodedImm >= 0) {
64 return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
65 }
66 ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
67 if (dataTarget == NULL) {
68 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
69 }
70 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
71 loadPcRel->opcode = kThumb2Vldrs;
72 loadPcRel->generic.target = (LIR *) dataTarget;
73 loadPcRel->operands[0] = rDest;
74 loadPcRel->operands[1] = r15pc;
75 setupResourceMasks(loadPcRel);
76 setMemRefType(loadPcRel, true, kLiteral);
77 loadPcRel->aliasInfo = dataTarget->operands[0];
78 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
79 return loadPcRel;
80 }
81
leadingZeros(u4 val)82 static int leadingZeros(u4 val)
83 {
84 u4 alt;
85 int n;
86 int count;
87
88 count = 16;
89 n = 32;
90 do {
91 alt = val >> count;
92 if (alt != 0) {
93 n = n - count;
94 val = alt;
95 }
96 count >>= 1;
97 } while (count);
98 return n - val;
99 }
100
101 /*
102 * Determine whether value can be encoded as a Thumb2 modified
103 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
104 */
modifiedImmediate(u4 value)105 static int modifiedImmediate(u4 value)
106 {
107 int zLeading;
108 int zTrailing;
109 u4 b0 = value & 0xff;
110
111 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
112 if (value <= 0xFF)
113 return b0; // 0:000:a:bcdefgh
114 if (value == ((b0 << 16) | b0))
115 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
116 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
117 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
118 b0 = (value >> 8) & 0xff;
119 if (value == ((b0 << 24) | (b0 << 8)))
120 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
121 /* Can we do it with rotation? */
122 zLeading = leadingZeros(value);
123 zTrailing = 32 - leadingZeros(~value & (value - 1));
124 /* A run of eight or fewer active bits? */
125 if ((zLeading + zTrailing) < 24)
126 return -1; /* No - bail */
127 /* left-justify the constant, discarding msb (known to be 1) */
128 value <<= zLeading + 1;
129 /* Create bcdefgh */
130 value >>= 25;
131 /* Put it all together */
132 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
133 }
134
135 /*
136 * Load a immediate using a shortcut if possible; otherwise
137 * grab from the per-translation literal pool.
138 *
139 * No additional register clobbering operation performed. Use this version when
140 * 1) rDest is freshly returned from dvmCompilerAllocTemp or
141 * 2) The codegen is under fixed register usage
142 */
loadConstantNoClobber(CompilationUnit * cUnit,int rDest,int value)143 static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
144 int value)
145 {
146 ArmLIR *res;
147 int modImm;
148
149 if (FPREG(rDest)) {
150 return loadFPConstantValue(cUnit, rDest, value);
151 }
152
153 /* See if the value can be constructed cheaply */
154 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
155 return newLIR2(cUnit, kThumbMovImm, rDest, value);
156 }
157 /* Check Modified immediate special cases */
158 modImm = modifiedImmediate(value);
159 if (modImm >= 0) {
160 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
161 return res;
162 }
163 modImm = modifiedImmediate(~value);
164 if (modImm >= 0) {
165 res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
166 return res;
167 }
168 /* 16-bit immediate? */
169 if ((value & 0xffff) == value) {
170 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
171 return res;
172 }
173 /* No shortcut - go ahead and use literal pool */
174 ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
175 if (dataTarget == NULL) {
176 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
177 }
178 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
179 loadPcRel->opcode = kThumb2LdrPcRel12;
180 loadPcRel->generic.target = (LIR *) dataTarget;
181 loadPcRel->operands[0] = rDest;
182 setupResourceMasks(loadPcRel);
183 setMemRefType(loadPcRel, true, kLiteral);
184 loadPcRel->aliasInfo = dataTarget->operands[0];
185 res = loadPcRel;
186 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
187
188 /*
189 * To save space in the constant pool, we use the ADD_RRI8 instruction to
190 * add up to 255 to an existing constant value.
191 */
192 if (dataTarget->operands[0] != value) {
193 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
194 }
195 return res;
196 }
197
198 /*
199 * Load an immediate value into a fixed or temp register. Target
200 * register is clobbered, and marked inUse.
201 */
loadConstant(CompilationUnit * cUnit,int rDest,int value)202 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
203 {
204 if (dvmCompilerIsTemp(cUnit, rDest)) {
205 dvmCompilerClobber(cUnit, rDest);
206 dvmCompilerMarkInUse(cUnit, rDest);
207 }
208 return loadConstantNoClobber(cUnit, rDest, value);
209 }
210
211 /*
212 * Load a class pointer value into a fixed or temp register. Target
213 * register is clobbered, and marked inUse.
214 */
loadClassPointer(CompilationUnit * cUnit,int rDest,int value)215 static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
216 {
217 ArmLIR *res;
218 cUnit->hasClassLiterals = true;
219 if (dvmCompilerIsTemp(cUnit, rDest)) {
220 dvmCompilerClobber(cUnit, rDest);
221 dvmCompilerMarkInUse(cUnit, rDest);
222 }
223 ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0);
224 if (dataTarget == NULL) {
225 dataTarget = addWordData(cUnit, &cUnit->classPointerList, value);
226 /* Counts the number of class pointers in this translation */
227 cUnit->numClassPointers++;
228 }
229 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
230 loadPcRel->opcode = kThumb2LdrPcRel12;
231 loadPcRel->generic.target = (LIR *) dataTarget;
232 loadPcRel->operands[0] = rDest;
233 setupResourceMasks(loadPcRel);
234 setMemRefType(loadPcRel, true, kLiteral);
235 loadPcRel->aliasInfo = dataTarget->operands[0];
236 res = loadPcRel;
237 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
238 return res;
239 }
240
opNone(CompilationUnit * cUnit,OpKind op)241 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
242 {
243 ArmOpcode opcode = kThumbBkpt;
244 switch (op) {
245 case kOpUncondBr:
246 opcode = kThumbBUncond;
247 break;
248 default:
249 assert(0);
250 }
251 return newLIR0(cUnit, opcode);
252 }
253
opCondBranch(CompilationUnit * cUnit,ArmConditionCode cc)254 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
255 {
256 return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
257 }
258
opImm(CompilationUnit * cUnit,OpKind op,int value)259 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
260 {
261 ArmOpcode opcode = kThumbBkpt;
262 switch (op) {
263 case kOpPush: {
264 if ((value & 0xff00) == 0) {
265 opcode = kThumbPush;
266 } else if ((value & 0xff00) == (1 << r14lr)) {
267 /* Thumb push can handle lr, which is encoded by bit 8 */
268 opcode = kThumbPush;
269 value = (value & 0xff) | (1<<8);
270 } else {
271 opcode = kThumb2Push;
272 }
273 break;
274 }
275 case kOpPop: {
276 if ((value & 0xff00) == 0) {
277 opcode = kThumbPop;
278 } else if ((value & 0xff00) == (1 << r15pc)) {
279 /* Thumb pop can handle pc, which is encoded by bit 8 */
280 opcode = kThumbPop;
281 value = (value & 0xff) | (1<<8);
282 } else {
283 opcode = kThumb2Pop;
284 }
285 break;
286 }
287 default:
288 assert(0);
289 }
290 return newLIR1(cUnit, opcode, value);
291 }
292
opReg(CompilationUnit * cUnit,OpKind op,int rDestSrc)293 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
294 {
295 ArmOpcode opcode = kThumbBkpt;
296 switch (op) {
297 case kOpBlx:
298 opcode = kThumbBlxR;
299 break;
300 default:
301 assert(0);
302 }
303 return newLIR1(cUnit, opcode, rDestSrc);
304 }
305
opRegRegShift(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int rSrc2,int shift)306 static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
307 int rSrc2, int shift)
308 {
309 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
310 ArmOpcode opcode = kThumbBkpt;
311 switch (op) {
312 case kOpAdc:
313 opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
314 break;
315 case kOpAnd:
316 opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
317 break;
318 case kOpBic:
319 opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
320 break;
321 case kOpCmn:
322 assert(shift == 0);
323 opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
324 break;
325 case kOpCmp:
326 if (thumbForm)
327 opcode = kThumbCmpRR;
328 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
329 opcode = kThumbCmpHH;
330 else if ((shift == 0) && LOWREG(rDestSrc1))
331 opcode = kThumbCmpLH;
332 else if (shift == 0)
333 opcode = kThumbCmpHL;
334 else
335 opcode = kThumb2CmpRR;
336 break;
337 case kOpXor:
338 opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
339 break;
340 case kOpMov:
341 assert(shift == 0);
342 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
343 opcode = kThumbMovRR;
344 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
345 opcode = kThumbMovRR_H2H;
346 else if (LOWREG(rDestSrc1))
347 opcode = kThumbMovRR_H2L;
348 else
349 opcode = kThumbMovRR_L2H;
350 break;
351 case kOpMul:
352 assert(shift == 0);
353 opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
354 break;
355 case kOpMvn:
356 opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
357 break;
358 case kOpNeg:
359 assert(shift == 0);
360 opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
361 break;
362 case kOpOr:
363 opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
364 break;
365 case kOpSbc:
366 opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
367 break;
368 case kOpTst:
369 opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
370 break;
371 case kOpLsl:
372 assert(shift == 0);
373 opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
374 break;
375 case kOpLsr:
376 assert(shift == 0);
377 opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
378 break;
379 case kOpAsr:
380 assert(shift == 0);
381 opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
382 break;
383 case kOpRor:
384 assert(shift == 0);
385 opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
386 break;
387 case kOpAdd:
388 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
389 break;
390 case kOpSub:
391 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
392 break;
393 case kOp2Byte:
394 assert(shift == 0);
395 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
396 case kOp2Short:
397 assert(shift == 0);
398 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
399 case kOp2Char:
400 assert(shift == 0);
401 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
402 default:
403 assert(0);
404 break;
405 }
406 assert(opcode >= 0);
407 if (EncodingMap[opcode].flags & IS_BINARY_OP)
408 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
409 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
410 if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
411 return newLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
412 else
413 return newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
414 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
415 return newLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
416 else {
417 assert(0);
418 return NULL;
419 }
420 }
421
opRegReg(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int rSrc2)422 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
423 int rSrc2)
424 {
425 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
426 }
427
opRegRegRegShift(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int rSrc2,int shift)428 static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
429 int rDest, int rSrc1, int rSrc2, int shift)
430 {
431 ArmOpcode opcode = kThumbBkpt;
432 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
433 LOWREG(rSrc2);
434 switch (op) {
435 case kOpAdd:
436 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
437 break;
438 case kOpSub:
439 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
440 break;
441 case kOpAdc:
442 opcode = kThumb2AdcRRR;
443 break;
444 case kOpAnd:
445 opcode = kThumb2AndRRR;
446 break;
447 case kOpBic:
448 opcode = kThumb2BicRRR;
449 break;
450 case kOpXor:
451 opcode = kThumb2EorRRR;
452 break;
453 case kOpMul:
454 assert(shift == 0);
455 opcode = kThumb2MulRRR;
456 break;
457 case kOpOr:
458 opcode = kThumb2OrrRRR;
459 break;
460 case kOpSbc:
461 opcode = kThumb2SbcRRR;
462 break;
463 case kOpLsl:
464 assert(shift == 0);
465 opcode = kThumb2LslRRR;
466 break;
467 case kOpLsr:
468 assert(shift == 0);
469 opcode = kThumb2LsrRRR;
470 break;
471 case kOpAsr:
472 assert(shift == 0);
473 opcode = kThumb2AsrRRR;
474 break;
475 case kOpRor:
476 assert(shift == 0);
477 opcode = kThumb2RorRRR;
478 break;
479 default:
480 assert(0);
481 break;
482 }
483 assert(opcode >= 0);
484 if (EncodingMap[opcode].flags & IS_QUAD_OP)
485 return newLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
486 else {
487 assert(EncodingMap[opcode].flags & IS_TERTIARY_OP);
488 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
489 }
490 }
491
opRegRegReg(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int rSrc2)492 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
493 int rSrc1, int rSrc2)
494 {
495 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
496 }
497
opRegRegImm(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int value)498 static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
499 int rSrc1, int value)
500 {
501 ArmLIR *res;
502 bool neg = (value < 0);
503 int absValue = (neg) ? -value : value;
504 ArmOpcode opcode = kThumbBkpt;
505 ArmOpcode altOpcode = kThumbBkpt;
506 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
507 int modImm = modifiedImmediate(value);
508 int modImmNeg = modifiedImmediate(-value);
509
510 switch(op) {
511 case kOpLsl:
512 if (allLowRegs)
513 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
514 else
515 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
516 case kOpLsr:
517 if (allLowRegs)
518 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
519 else
520 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
521 case kOpAsr:
522 if (allLowRegs)
523 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
524 else
525 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
526 case kOpRor:
527 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
528 case kOpAdd:
529 if (LOWREG(rDest) && (rSrc1 == r13sp) &&
530 (value <= 1020) && ((value & 0x3)==0)) {
531 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
532 value >> 2);
533 } else if (LOWREG(rDest) && (rSrc1 == r15pc) &&
534 (value <= 1020) && ((value & 0x3)==0)) {
535 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
536 value >> 2);
537 }
538 opcode = kThumb2AddRRI8;
539 altOpcode = kThumb2AddRRR;
540 // Note: intentional fallthrough
541 case kOpSub:
542 if (allLowRegs && ((absValue & 0x7) == absValue)) {
543 if (op == kOpAdd)
544 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
545 else
546 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
547 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
548 } else if ((absValue & 0xff) == absValue) {
549 if (op == kOpAdd)
550 opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
551 else
552 opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
553 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
554 }
555 if (modImmNeg >= 0) {
556 op = (op == kOpAdd) ? kOpSub : kOpAdd;
557 modImm = modImmNeg;
558 }
559 if (op == kOpSub) {
560 opcode = kThumb2SubRRI8;
561 altOpcode = kThumb2SubRRR;
562 }
563 break;
564 case kOpAdc:
565 opcode = kThumb2AdcRRI8;
566 altOpcode = kThumb2AdcRRR;
567 break;
568 case kOpSbc:
569 opcode = kThumb2SbcRRI8;
570 altOpcode = kThumb2SbcRRR;
571 break;
572 case kOpOr:
573 opcode = kThumb2OrrRRI8;
574 altOpcode = kThumb2OrrRRR;
575 break;
576 case kOpAnd:
577 opcode = kThumb2AndRRI8;
578 altOpcode = kThumb2AndRRR;
579 break;
580 case kOpXor:
581 opcode = kThumb2EorRRI8;
582 altOpcode = kThumb2EorRRR;
583 break;
584 case kOpMul:
585 //TUNING: power of 2, shift & add
586 modImm = -1;
587 altOpcode = kThumb2MulRRR;
588 break;
589 case kOpCmp: {
590 int modImm = modifiedImmediate(value);
591 ArmLIR *res;
592 if (modImm >= 0) {
593 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
594 } else {
595 int rTmp = dvmCompilerAllocTemp(cUnit);
596 res = loadConstant(cUnit, rTmp, value);
597 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
598 dvmCompilerFreeTemp(cUnit, rTmp);
599 }
600 return res;
601 }
602 default:
603 assert(0);
604 }
605
606 if (modImm >= 0) {
607 return newLIR3(cUnit, opcode, rDest, rSrc1, modImm);
608 } else {
609 int rScratch = dvmCompilerAllocTemp(cUnit);
610 loadConstant(cUnit, rScratch, value);
611 if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
612 res = newLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
613 else
614 res = newLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
615 dvmCompilerFreeTemp(cUnit, rScratch);
616 return res;
617 }
618 }
619
620 /* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
opRegImm(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int value)621 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
622 int value)
623 {
624 bool neg = (value < 0);
625 int absValue = (neg) ? -value : value;
626 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
627 ArmOpcode opcode = kThumbBkpt;
628 switch (op) {
629 case kOpAdd:
630 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
631 assert((value & 0x3) == 0);
632 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
633 } else if (shortForm) {
634 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
635 }
636 break;
637 case kOpSub:
638 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
639 assert((value & 0x3) == 0);
640 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
641 } else if (shortForm) {
642 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
643 }
644 break;
645 case kOpCmp:
646 if (LOWREG(rDestSrc1) && shortForm)
647 opcode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
648 else if (LOWREG(rDestSrc1))
649 opcode = kThumbCmpRR;
650 else {
651 shortForm = false;
652 opcode = kThumbCmpHL;
653 }
654 break;
655 default:
656 /* Punt to opRegRegImm - if bad case catch it there */
657 shortForm = false;
658 break;
659 }
660 if (shortForm)
661 return newLIR2(cUnit, opcode, rDestSrc1, absValue);
662 else {
663 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
664 }
665 }
666
667 /*
668 * Determine whether value can be encoded as a Thumb2 floating point
669 * immediate. If not, return -1. If so return encoded 8-bit value.
670 */
encodeImmDoubleHigh(int value)671 static int encodeImmDoubleHigh(int value)
672 {
673 int res;
674 int bitA = (value & 0x80000000) >> 31;
675 int notBitB = (value & 0x40000000) >> 30;
676 int bitB = (value & 0x20000000) >> 29;
677 int bSmear = (value & 0x3fc00000) >> 22;
678 int slice = (value & 0x003f0000) >> 16;
679 int zeroes = (value & 0x0000ffff);
680 if (zeroes != 0)
681 return -1;
682 if (bitB) {
683 if ((notBitB != 0) || (bSmear != 0x1f))
684 return -1;
685 } else {
686 if ((notBitB != 1) || (bSmear != 0x0))
687 return -1;
688 }
689 res = (bitA << 7) | (bitB << 6) | slice;
690 return res;
691 }
692
encodeImmDouble(int valLo,int valHi)693 static int encodeImmDouble(int valLo, int valHi)
694 {
695 int res = -1;
696 if (valLo == 0)
697 res = encodeImmDoubleHigh(valHi);
698 return res;
699 }
700
loadConstantValueWide(CompilationUnit * cUnit,int rDestLo,int rDestHi,int valLo,int valHi)701 static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
702 int rDestHi, int valLo, int valHi)
703 {
704 int encodedImm = encodeImmDouble(valLo, valHi);
705 ArmLIR *res;
706 int targetReg = S2D(rDestLo, rDestHi);
707 if (FPREG(rDestLo)) {
708 if ((valLo == 0) && (valHi == 0)) {
709 // TODO: we need better info about the target CPU. a vector
710 // exclusive or would probably be better here if we could rely on
711 // its existance.
712 // Load an immediate +2.0 (which encodes to 0)
713 newLIR2(cUnit, kThumb2Vmovd_IMM8, targetReg, 0);
714 // +0.0 = +2.0 - +2.0
715 res = newLIR3(cUnit, kThumb2Vsubd, targetReg, targetReg, targetReg);
716 } else if (encodedImm >= 0) {
717 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, targetReg, encodedImm);
718 } else {
719 ArmLIR* dataTarget = scanLiteralPoolWide(cUnit->literalList, valLo, valHi);
720 if (dataTarget == NULL) {
721 dataTarget = addWideData(cUnit, &cUnit->literalList, valLo, valHi);
722 }
723 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
724 loadPcRel->opcode = kThumb2Vldrd;
725 loadPcRel->generic.target = (LIR *) dataTarget;
726 loadPcRel->operands[0] = targetReg;
727 loadPcRel->operands[1] = r15pc;
728 setupResourceMasks(loadPcRel);
729 setMemRefType(loadPcRel, true, kLiteral);
730 // TODO: rework literal load disambiguation to more cleanly handle 64-bit loads
731 loadPcRel->aliasInfo = (uintptr_t)dataTarget;
732 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
733 res = loadPcRel;
734 }
735 } else {
736 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
737 loadConstantNoClobber(cUnit, rDestHi, valHi);
738 }
739 return res;
740 }
741
encodeShift(int code,int amount)742 static int encodeShift(int code, int amount) {
743 return ((amount & 0x1f) << 2) | code;
744 }
745
loadBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rDest,int scale,OpSize size)746 static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
747 int rIndex, int rDest, int scale, OpSize size)
748 {
749 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
750 ArmLIR *load;
751 ArmOpcode opcode = kThumbBkpt;
752 bool thumbForm = (allLowRegs && (scale == 0));
753 int regPtr;
754
755 if (FPREG(rDest)) {
756 assert(SINGLEREG(rDest));
757 assert((size == kWord) || (size == kSingle));
758 opcode = kThumb2Vldrs;
759 size = kSingle;
760 } else {
761 if (size == kSingle)
762 size = kWord;
763 }
764
765 switch (size) {
766 case kSingle:
767 regPtr = dvmCompilerAllocTemp(cUnit);
768 if (scale) {
769 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
770 encodeShift(kArmLsl, scale));
771 } else {
772 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
773 }
774 load = newLIR3(cUnit, opcode, rDest, regPtr, 0);
775 #if defined(WITH_SELF_VERIFICATION)
776 if (cUnit->heapMemOp)
777 load->flags.insertWrapper = true;
778 #endif
779 return load;
780 case kWord:
781 opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
782 break;
783 case kUnsignedHalf:
784 opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
785 break;
786 case kSignedHalf:
787 opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
788 break;
789 case kUnsignedByte:
790 opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
791 break;
792 case kSignedByte:
793 opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
794 break;
795 default:
796 assert(0);
797 }
798 if (thumbForm)
799 load = newLIR3(cUnit, opcode, rDest, rBase, rIndex);
800 else
801 load = newLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
802
803 #if defined(WITH_SELF_VERIFICATION)
804 if (cUnit->heapMemOp)
805 load->flags.insertWrapper = true;
806 #endif
807 return load;
808 }
809
storeBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rSrc,int scale,OpSize size)810 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
811 int rIndex, int rSrc, int scale, OpSize size)
812 {
813 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
814 ArmLIR *store;
815 ArmOpcode opcode = kThumbBkpt;
816 bool thumbForm = (allLowRegs && (scale == 0));
817 int regPtr;
818
819 if (FPREG(rSrc)) {
820 assert(SINGLEREG(rSrc));
821 assert((size == kWord) || (size == kSingle));
822 opcode = kThumb2Vstrs;
823 size = kSingle;
824 } else {
825 if (size == kSingle)
826 size = kWord;
827 }
828
829 switch (size) {
830 case kSingle:
831 regPtr = dvmCompilerAllocTemp(cUnit);
832 if (scale) {
833 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
834 encodeShift(kArmLsl, scale));
835 } else {
836 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
837 }
838 store = newLIR3(cUnit, opcode, rSrc, regPtr, 0);
839 #if defined(WITH_SELF_VERIFICATION)
840 if (cUnit->heapMemOp)
841 store->flags.insertWrapper = true;
842 #endif
843 return store;
844 case kWord:
845 opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
846 break;
847 case kUnsignedHalf:
848 case kSignedHalf:
849 opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
850 break;
851 case kUnsignedByte:
852 case kSignedByte:
853 opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
854 break;
855 default:
856 assert(0);
857 }
858 if (thumbForm)
859 store = newLIR3(cUnit, opcode, rSrc, rBase, rIndex);
860 else
861 store = newLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
862
863 #if defined(WITH_SELF_VERIFICATION)
864 if (cUnit->heapMemOp)
865 store->flags.insertWrapper = true;
866 #endif
867 return store;
868 }
869
870 /*
871 * Load value from base + displacement. Optionally perform null check
872 * on base (which must have an associated sReg and MIR). If not
873 * performing null check, incoming MIR can be null.
874 */
loadBaseDispBody(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,int rDestHi,OpSize size,int sReg)875 static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
876 int displacement, int rDest, int rDestHi,
877 OpSize size, int sReg)
878 {
879 ArmLIR *res, *load;
880 ArmOpcode opcode = kThumbBkpt;
881 bool shortForm = false;
882 bool thumb2Form = (displacement < 4092 && displacement >= 0);
883 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
884 int encodedDisp = displacement;
885
886 switch (size) {
887 case kDouble:
888 case kLong:
889 if (FPREG(rDest)) {
890 if (SINGLEREG(rDest)) {
891 assert(FPREG(rDestHi));
892 rDest = S2D(rDest, rDestHi);
893 }
894 opcode = kThumb2Vldrd;
895 if (displacement <= 1020) {
896 shortForm = true;
897 encodedDisp >>= 2;
898 }
899 break;
900 } else {
901 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
902 -1, kWord, sReg);
903 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
904 -1, kWord, INVALID_SREG);
905 return res;
906 }
907 case kSingle:
908 case kWord:
909 if (FPREG(rDest)) {
910 opcode = kThumb2Vldrs;
911 if (displacement <= 1020) {
912 shortForm = true;
913 encodedDisp >>= 2;
914 }
915 break;
916 }
917 if (LOWREG(rDest) && (rBase == r15pc) &&
918 (displacement <= 1020) && (displacement >= 0)) {
919 shortForm = true;
920 encodedDisp >>= 2;
921 opcode = kThumbLdrPcRel;
922 } else if (LOWREG(rDest) && (rBase == r13sp) &&
923 (displacement <= 1020) && (displacement >= 0)) {
924 shortForm = true;
925 encodedDisp >>= 2;
926 opcode = kThumbLdrSpRel;
927 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
928 assert((displacement & 0x3) == 0);
929 shortForm = true;
930 encodedDisp >>= 2;
931 opcode = kThumbLdrRRI5;
932 } else if (thumb2Form) {
933 shortForm = true;
934 opcode = kThumb2LdrRRI12;
935 }
936 break;
937 case kUnsignedHalf:
938 if (allLowRegs && displacement < 64 && displacement >= 0) {
939 assert((displacement & 0x1) == 0);
940 shortForm = true;
941 encodedDisp >>= 1;
942 opcode = kThumbLdrhRRI5;
943 } else if (displacement < 4092 && displacement >= 0) {
944 shortForm = true;
945 opcode = kThumb2LdrhRRI12;
946 }
947 break;
948 case kSignedHalf:
949 if (thumb2Form) {
950 shortForm = true;
951 opcode = kThumb2LdrshRRI12;
952 }
953 break;
954 case kUnsignedByte:
955 if (allLowRegs && displacement < 32 && displacement >= 0) {
956 shortForm = true;
957 opcode = kThumbLdrbRRI5;
958 } else if (thumb2Form) {
959 shortForm = true;
960 opcode = kThumb2LdrbRRI12;
961 }
962 break;
963 case kSignedByte:
964 if (thumb2Form) {
965 shortForm = true;
966 opcode = kThumb2LdrsbRRI12;
967 }
968 break;
969 default:
970 assert(0);
971 }
972
973 if (shortForm) {
974 load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
975 } else {
976 int regOffset = dvmCompilerAllocTemp(cUnit);
977 res = loadConstant(cUnit, regOffset, encodedDisp);
978 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
979 dvmCompilerFreeTemp(cUnit, regOffset);
980 }
981
982 if (rBase == r5FP) {
983 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
984 }
985 #if defined(WITH_SELF_VERIFICATION)
986 if (cUnit->heapMemOp)
987 load->flags.insertWrapper = true;
988 #endif
989 return load;
990 }
991
loadBaseDisp(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,OpSize size,int sReg)992 static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
993 int displacement, int rDest, OpSize size,
994 int sReg)
995 {
996 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
997 size, sReg);
998 }
999
loadBaseDispWide(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDestLo,int rDestHi,int sReg)1000 static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
1001 int displacement, int rDestLo, int rDestHi,
1002 int sReg)
1003 {
1004 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
1005 kLong, sReg);
1006 }
1007
1008
storeBaseDispBody(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,int rSrcHi,OpSize size)1009 static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
1010 int displacement, int rSrc, int rSrcHi,
1011 OpSize size)
1012 {
1013 ArmLIR *res, *store;
1014 ArmOpcode opcode = kThumbBkpt;
1015 bool shortForm = false;
1016 bool thumb2Form = (displacement < 4092 && displacement >= 0);
1017 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
1018 int encodedDisp = displacement;
1019
1020 switch (size) {
1021 case kLong:
1022 case kDouble:
1023 if (!FPREG(rSrc)) {
1024 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
1025 -1, kWord);
1026 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
1027 -1, kWord);
1028 return res;
1029 }
1030 if (SINGLEREG(rSrc)) {
1031 assert(FPREG(rSrcHi));
1032 rSrc = S2D(rSrc, rSrcHi);
1033 }
1034 opcode = kThumb2Vstrd;
1035 if (displacement <= 1020) {
1036 shortForm = true;
1037 encodedDisp >>= 2;
1038 }
1039 break;
1040 case kSingle:
1041 case kWord:
1042 if (FPREG(rSrc)) {
1043 assert(SINGLEREG(rSrc));
1044 opcode = kThumb2Vstrs;
1045 if (displacement <= 1020) {
1046 shortForm = true;
1047 encodedDisp >>= 2;
1048 }
1049 break;
1050 }
1051 if (allLowRegs && displacement < 128 && displacement >= 0) {
1052 assert((displacement & 0x3) == 0);
1053 shortForm = true;
1054 encodedDisp >>= 2;
1055 opcode = kThumbStrRRI5;
1056 } else if (thumb2Form) {
1057 shortForm = true;
1058 opcode = kThumb2StrRRI12;
1059 }
1060 break;
1061 case kUnsignedHalf:
1062 case kSignedHalf:
1063 if (allLowRegs && displacement < 64 && displacement >= 0) {
1064 assert((displacement & 0x1) == 0);
1065 shortForm = true;
1066 encodedDisp >>= 1;
1067 opcode = kThumbStrhRRI5;
1068 } else if (thumb2Form) {
1069 shortForm = true;
1070 opcode = kThumb2StrhRRI12;
1071 }
1072 break;
1073 case kUnsignedByte:
1074 case kSignedByte:
1075 if (allLowRegs && displacement < 32 && displacement >= 0) {
1076 shortForm = true;
1077 opcode = kThumbStrbRRI5;
1078 } else if (thumb2Form) {
1079 shortForm = true;
1080 opcode = kThumb2StrbRRI12;
1081 }
1082 break;
1083 default:
1084 assert(0);
1085 }
1086 if (shortForm) {
1087 store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
1088 } else {
1089 int rScratch = dvmCompilerAllocTemp(cUnit);
1090 res = loadConstant(cUnit, rScratch, encodedDisp);
1091 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
1092 dvmCompilerFreeTemp(cUnit, rScratch);
1093 }
1094
1095 if (rBase == r5FP) {
1096 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
1097 }
1098 #if defined(WITH_SELF_VERIFICATION)
1099 if (cUnit->heapMemOp)
1100 store->flags.insertWrapper = true;
1101 #endif
1102 return res;
1103 }
1104
storeBaseDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,OpSize size)1105 static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
1106 int displacement, int rSrc, OpSize size)
1107 {
1108 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1109 }
1110
storeBaseDispWide(CompilationUnit * cUnit,int rBase,int displacement,int rSrcLo,int rSrcHi)1111 static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
1112 int displacement, int rSrcLo, int rSrcHi)
1113 {
1114 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1115 }
1116
loadMultiple(CompilationUnit * cUnit,int rBase,int rMask)1117 static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1118 {
1119 ArmLIR *res;
1120 genBarrier(cUnit);
1121 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1122 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
1123 } else {
1124 res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
1125 }
1126 #if defined(WITH_SELF_VERIFICATION)
1127 if (cUnit->heapMemOp)
1128 res->flags.insertWrapper = true;
1129 #endif
1130 genBarrier(cUnit);
1131 return res;
1132 }
1133
storeMultiple(CompilationUnit * cUnit,int rBase,int rMask)1134 static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1135 {
1136 ArmLIR *res;
1137 genBarrier(cUnit);
1138 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1139 res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
1140 } else {
1141 res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
1142 }
1143 #if defined(WITH_SELF_VERIFICATION)
1144 if (cUnit->heapMemOp)
1145 res->flags.insertWrapper = true;
1146 #endif
1147 genBarrier(cUnit);
1148 return res;
1149 }
1150
storePair(CompilationUnit * cUnit,int base,int lowReg,int highReg)1151 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1152 {
1153 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1154 }
1155
loadPair(CompilationUnit * cUnit,int base,int lowReg,int highReg)1156 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1157 {
1158 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1159 }
1160
1161 /*
1162 * Generate a register comparison to an immediate and branch. Caller
1163 * is responsible for setting branch target field.
1164 */
genCmpImmBranch(CompilationUnit * cUnit,ArmConditionCode cond,int reg,int checkValue)1165 static ArmLIR *genCmpImmBranch(CompilationUnit *cUnit,
1166 ArmConditionCode cond, int reg,
1167 int checkValue)
1168 {
1169 ArmLIR *branch;
1170 int modImm;
1171 if ((LOWREG(reg)) && (checkValue == 0) &&
1172 ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1173 branch = newLIR2(cUnit,
1174 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1175 reg, 0);
1176 } else {
1177 modImm = modifiedImmediate(checkValue);
1178 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1179 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1180 } else if (modImm >= 0) {
1181 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1182 } else {
1183 int tReg = dvmCompilerAllocTemp(cUnit);
1184 loadConstant(cUnit, tReg, checkValue);
1185 opRegReg(cUnit, kOpCmp, reg, tReg);
1186 }
1187 branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1188 }
1189 return branch;
1190 }
1191
fpRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)1192 static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1193 {
1194 ArmLIR* res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
1195 res->operands[0] = rDest;
1196 res->operands[1] = rSrc;
1197 if (rDest == rSrc) {
1198 res->flags.isNop = true;
1199 } else {
1200 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
1201 if (DOUBLEREG(rDest)) {
1202 res->opcode = kThumb2Vmovd;
1203 } else {
1204 if (SINGLEREG(rDest)) {
1205 res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1206 } else {
1207 assert(SINGLEREG(rSrc));
1208 res->opcode = kThumb2Fmrs;
1209 }
1210 }
1211 res->operands[0] = rDest;
1212 res->operands[1] = rSrc;
1213 }
1214 setupResourceMasks(res);
1215 return res;
1216 }
1217
genRegCopyNoInsert(CompilationUnit * cUnit,int rDest,int rSrc)1218 static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
1219 {
1220 ArmLIR* res;
1221 ArmOpcode opcode;
1222 if (FPREG(rDest) || FPREG(rSrc))
1223 return fpRegCopy(cUnit, rDest, rSrc);
1224 res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
1225 if (LOWREG(rDest) && LOWREG(rSrc))
1226 opcode = kThumbMovRR;
1227 else if (!LOWREG(rDest) && !LOWREG(rSrc))
1228 opcode = kThumbMovRR_H2H;
1229 else if (LOWREG(rDest))
1230 opcode = kThumbMovRR_H2L;
1231 else
1232 opcode = kThumbMovRR_L2H;
1233
1234 res->operands[0] = rDest;
1235 res->operands[1] = rSrc;
1236 res->opcode = opcode;
1237 setupResourceMasks(res);
1238 if (rDest == rSrc) {
1239 res->flags.isNop = true;
1240 }
1241 return res;
1242 }
1243
genRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)1244 static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1245 {
1246 ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1247 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1248 return res;
1249 }
1250
genRegCopyWide(CompilationUnit * cUnit,int destLo,int destHi,int srcLo,int srcHi)1251 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
1252 int srcLo, int srcHi)
1253 {
1254 bool destFP = FPREG(destLo) && FPREG(destHi);
1255 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
1256 assert(FPREG(srcLo) == FPREG(srcHi));
1257 assert(FPREG(destLo) == FPREG(destHi));
1258 if (destFP) {
1259 if (srcFP) {
1260 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1261 } else {
1262 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1263 }
1264 } else {
1265 if (srcFP) {
1266 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1267 } else {
1268 // Handle overlap
1269 if (srcHi == destLo) {
1270 genRegCopy(cUnit, destHi, srcHi);
1271 genRegCopy(cUnit, destLo, srcLo);
1272 } else {
1273 genRegCopy(cUnit, destLo, srcLo);
1274 genRegCopy(cUnit, destHi, srcHi);
1275 }
1276 }
1277 }
1278 }
1279
1280 #if defined(WITH_SELF_VERIFICATION)
genSelfVerificationPreBranch(CompilationUnit * cUnit,ArmLIR * origLIR)1281 static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
1282 ArmLIR *origLIR) {
1283 ArmLIR *push = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
1284 push->opcode = kThumbPush;
1285 /* Thumb push can handle LR (encoded at bit 8) */
1286 push->operands[0] = (1 << r5FP | 1 << 8);
1287 setupResourceMasks(push);
1288 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) push);
1289 }
1290
genSelfVerificationPostBranch(CompilationUnit * cUnit,ArmLIR * origLIR)1291 static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
1292 ArmLIR *origLIR) {
1293 ArmLIR *pop = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
1294 /* Thumb pop cannot store into LR - use Thumb2 here */
1295 pop->opcode = kThumb2Pop;
1296 pop->operands[0] = (1 << r5FP | 1 << r14lr);
1297 setupResourceMasks(pop);
1298 dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) pop);
1299 }
1300 #endif
1301