blob: 45c7377988a75b9f58292927669c25a7b2369906 [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 for the Thumb ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
buzbeec1f45042011-09-21 16:03:19 -070025static int coreRegs[] = {r0, r1, r2, r3, rSUSPEND, r5, r6, r7, rSELF, r8, r10,
26 r11, r12, rSP, rLR, rPC};
27static int reservedRegs[] = {rSUSPEND, rSELF, rSP, rLR, rPC};
buzbee67bf8852011-08-17 17:51:35 -070028static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
29 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
30 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
31 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
32static int coreTemps[] = {r0, r1, r2, r3, r12};
33static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
34 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
35
buzbeeed3e9302011-09-23 17:34:19 -070036STATIC int encodeImmSingle(int value)
buzbee67bf8852011-08-17 17:51:35 -070037{
38 int res;
39 int bitA = (value & 0x80000000) >> 31;
40 int notBitB = (value & 0x40000000) >> 30;
41 int bitB = (value & 0x20000000) >> 29;
42 int bSmear = (value & 0x3e000000) >> 25;
43 int slice = (value & 0x01f80000) >> 19;
44 int zeroes = (value & 0x0007ffff);
45 if (zeroes != 0)
46 return -1;
47 if (bitB) {
48 if ((notBitB != 0) || (bSmear != 0x1f))
49 return -1;
50 } else {
51 if ((notBitB != 1) || (bSmear != 0x0))
52 return -1;
53 }
54 res = (bitA << 7) | (bitB << 6) | slice;
55 return res;
56}
57
buzbeeed3e9302011-09-23 17:34:19 -070058STATIC ArmLIR* loadFPConstantValue(CompilationUnit* cUnit, int rDest,
buzbee67bf8852011-08-17 17:51:35 -070059 int value)
60{
61 int encodedImm = encodeImmSingle(value);
buzbeeed3e9302011-09-23 17:34:19 -070062 DCHECK(SINGLEREG(rDest));
buzbee67bf8852011-08-17 17:51:35 -070063 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* ) oatNew(sizeof(ArmLIR), true);
71 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
72 loadPcRel->opcode = kThumb2Vldrs;
73 loadPcRel->generic.target = (LIR* ) dataTarget;
74 loadPcRel->operands[0] = rDest;
75 loadPcRel->operands[1] = r15pc;
76 setupResourceMasks(loadPcRel);
77 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -070078 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee67bf8852011-08-17 17:51:35 -070079 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
80 return loadPcRel;
81}
82
buzbeeed3e9302011-09-23 17:34:19 -070083STATIC int leadingZeros(u4 val)
buzbee67bf8852011-08-17 17:51:35 -070084{
85 u4 alt;
86 int n;
87 int count;
88
89 count = 16;
90 n = 32;
91 do {
92 alt = val >> count;
93 if (alt != 0) {
94 n = n - count;
95 val = alt;
96 }
97 count >>= 1;
98 } while (count);
99 return n - val;
100}
101
102/*
103 * Determine whether value can be encoded as a Thumb2 modified
104 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
105 */
buzbeeed3e9302011-09-23 17:34:19 -0700106STATIC int modifiedImmediate(u4 value)
buzbee67bf8852011-08-17 17:51:35 -0700107{
108 int zLeading;
109 int zTrailing;
110 u4 b0 = value & 0xff;
111
112 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
113 if (value <= 0xFF)
114 return b0; // 0:000:a:bcdefgh
115 if (value == ((b0 << 16) | b0))
116 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
117 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
118 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
119 b0 = (value >> 8) & 0xff;
120 if (value == ((b0 << 24) | (b0 << 8)))
121 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
122 /* Can we do it with rotation? */
123 zLeading = leadingZeros(value);
124 zTrailing = 32 - leadingZeros(~value & (value - 1));
125 /* A run of eight or fewer active bits? */
126 if ((zLeading + zTrailing) < 24)
127 return -1; /* No - bail */
128 /* left-justify the constant, discarding msb (known to be 1) */
129 value <<= zLeading + 1;
130 /* Create bcdefgh */
131 value >>= 25;
132 /* Put it all together */
133 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
134}
135
136/*
137 * Load a immediate using a shortcut if possible; otherwise
138 * grab from the per-translation literal pool.
139 *
140 * No additional register clobbering operation performed. Use this version when
141 * 1) rDest is freshly returned from oatAllocTemp or
142 * 2) The codegen is under fixed register usage
143 */
buzbeeed3e9302011-09-23 17:34:19 -0700144STATIC ArmLIR* loadConstantNoClobber(CompilationUnit* cUnit, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700145 int value)
146{
147 ArmLIR* res;
148 int modImm;
149
150 if (FPREG(rDest)) {
151 return loadFPConstantValue(cUnit, rDest, value);
152 }
153
154 /* See if the value can be constructed cheaply */
155 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
156 return newLIR2(cUnit, kThumbMovImm, rDest, value);
157 }
158 /* Check Modified immediate special cases */
159 modImm = modifiedImmediate(value);
160 if (modImm >= 0) {
161 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
162 return res;
163 }
164 modImm = modifiedImmediate(~value);
165 if (modImm >= 0) {
buzbee58f92742011-10-01 11:22:17 -0700166 res = newLIR2(cUnit, kThumb2MvnImm12, rDest, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700167 return res;
168 }
169 /* 16-bit immediate? */
170 if ((value & 0xffff) == value) {
171 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
172 return res;
173 }
174 /* No shortcut - go ahead and use literal pool */
175 ArmLIR* dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
176 if (dataTarget == NULL) {
177 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
178 }
179 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
180 loadPcRel->opcode = kThumb2LdrPcRel12;
181 loadPcRel->generic.target = (LIR* ) dataTarget;
182 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
183 loadPcRel->operands[0] = rDest;
184 setupResourceMasks(loadPcRel);
185 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -0700186 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee67bf8852011-08-17 17:51:35 -0700187 res = loadPcRel;
188 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
189
190 /*
191 * To save space in the constant pool, we use the ADD_RRI8 instruction to
192 * add up to 255 to an existing constant value.
193 */
194 if (dataTarget->operands[0] != value) {
195 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
196 }
197 return res;
198}
199
200/*
201 * Load an immediate value into a fixed or temp register. Target
202 * register is clobbered, and marked inUse.
203 */
buzbeeed3e9302011-09-23 17:34:19 -0700204STATIC ArmLIR* loadConstant(CompilationUnit* cUnit, int rDest, int value)
buzbee67bf8852011-08-17 17:51:35 -0700205{
206 if (oatIsTemp(cUnit, rDest)) {
207 oatClobber(cUnit, rDest);
208 oatMarkInUse(cUnit, rDest);
209 }
210 return loadConstantNoClobber(cUnit, rDest, value);
211}
212
buzbeeed3e9302011-09-23 17:34:19 -0700213STATIC ArmLIR* opNone(CompilationUnit* cUnit, OpKind op)
buzbee67bf8852011-08-17 17:51:35 -0700214{
215 ArmOpcode opcode = kThumbBkpt;
216 switch (op) {
217 case kOpUncondBr:
218 opcode = kThumbBUncond;
219 break;
220 default:
buzbeeed3e9302011-09-23 17:34:19 -0700221 LOG(FATAL) << "Bad opcode " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700222 }
223 return newLIR0(cUnit, opcode);
224}
225
buzbeeed3e9302011-09-23 17:34:19 -0700226STATIC ArmLIR* opCondBranch(CompilationUnit* cUnit, ArmConditionCode cc)
buzbee67bf8852011-08-17 17:51:35 -0700227{
228 return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
229}
230
buzbeeed3e9302011-09-23 17:34:19 -0700231STATIC ArmLIR* opReg(CompilationUnit* cUnit, OpKind op, int rDestSrc)
buzbee67bf8852011-08-17 17:51:35 -0700232{
233 ArmOpcode opcode = kThumbBkpt;
234 switch (op) {
235 case kOpBlx:
236 opcode = kThumbBlxR;
237 break;
238 default:
buzbeeed3e9302011-09-23 17:34:19 -0700239 LOG(FATAL) << "Bad opcode " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700240 }
241 return newLIR1(cUnit, opcode, rDestSrc);
242}
243
buzbeeed3e9302011-09-23 17:34:19 -0700244STATIC ArmLIR* opRegRegShift(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700245 int rSrc2, int shift)
246{
247 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
248 ArmOpcode opcode = kThumbBkpt;
249 switch (op) {
250 case kOpAdc:
251 opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
252 break;
253 case kOpAnd:
254 opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
255 break;
256 case kOpBic:
257 opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
258 break;
259 case kOpCmn:
buzbeeed3e9302011-09-23 17:34:19 -0700260 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700261 opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
262 break;
263 case kOpCmp:
264 if (thumbForm)
265 opcode = kThumbCmpRR;
266 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
267 opcode = kThumbCmpHH;
268 else if ((shift == 0) && LOWREG(rDestSrc1))
269 opcode = kThumbCmpLH;
270 else if (shift == 0)
271 opcode = kThumbCmpHL;
272 else
273 opcode = kThumb2CmpRR;
274 break;
275 case kOpXor:
276 opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
277 break;
278 case kOpMov:
buzbeeed3e9302011-09-23 17:34:19 -0700279 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700280 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
281 opcode = kThumbMovRR;
282 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
283 opcode = kThumbMovRR_H2H;
284 else if (LOWREG(rDestSrc1))
285 opcode = kThumbMovRR_H2L;
286 else
287 opcode = kThumbMovRR_L2H;
288 break;
289 case kOpMul:
buzbeeed3e9302011-09-23 17:34:19 -0700290 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700291 opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
292 break;
293 case kOpMvn:
294 opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
295 break;
296 case kOpNeg:
buzbeeed3e9302011-09-23 17:34:19 -0700297 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700298 opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
299 break;
300 case kOpOr:
301 opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
302 break;
303 case kOpSbc:
304 opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
305 break;
306 case kOpTst:
307 opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
308 break;
309 case kOpLsl:
buzbeeed3e9302011-09-23 17:34:19 -0700310 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700311 opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
312 break;
313 case kOpLsr:
buzbeeed3e9302011-09-23 17:34:19 -0700314 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700315 opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
316 break;
317 case kOpAsr:
buzbeeed3e9302011-09-23 17:34:19 -0700318 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700319 opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
320 break;
321 case kOpRor:
buzbeeed3e9302011-09-23 17:34:19 -0700322 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700323 opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
324 break;
325 case kOpAdd:
326 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
327 break;
328 case kOpSub:
329 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
330 break;
331 case kOp2Byte:
buzbeeed3e9302011-09-23 17:34:19 -0700332 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700333 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
334 case kOp2Short:
buzbeeed3e9302011-09-23 17:34:19 -0700335 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700336 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
337 case kOp2Char:
buzbeeed3e9302011-09-23 17:34:19 -0700338 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700339 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
340 default:
buzbeeed3e9302011-09-23 17:34:19 -0700341 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700342 break;
343 }
buzbeeed3e9302011-09-23 17:34:19 -0700344 DCHECK(opcode >= 0);
buzbee67bf8852011-08-17 17:51:35 -0700345 if (EncodingMap[opcode].flags & IS_BINARY_OP)
346 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
347 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
348 if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
349 return newLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
350 else
351 return newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
352 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
353 return newLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
354 else {
buzbeeed3e9302011-09-23 17:34:19 -0700355 LOG(FATAL) << "Unexpected encoding operand count";
buzbee67bf8852011-08-17 17:51:35 -0700356 return NULL;
357 }
358}
359
buzbeeed3e9302011-09-23 17:34:19 -0700360STATIC ArmLIR* opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700361 int rSrc2)
362{
363 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
364}
365
buzbeeed3e9302011-09-23 17:34:19 -0700366STATIC ArmLIR* opRegRegRegShift(CompilationUnit* cUnit, OpKind op,
buzbee67bf8852011-08-17 17:51:35 -0700367 int rDest, int rSrc1, int rSrc2, int shift)
368{
369 ArmOpcode opcode = kThumbBkpt;
370 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
371 LOWREG(rSrc2);
372 switch (op) {
373 case kOpAdd:
374 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
375 break;
376 case kOpSub:
377 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
378 break;
379 case kOpAdc:
380 opcode = kThumb2AdcRRR;
381 break;
382 case kOpAnd:
383 opcode = kThumb2AndRRR;
384 break;
385 case kOpBic:
386 opcode = kThumb2BicRRR;
387 break;
388 case kOpXor:
389 opcode = kThumb2EorRRR;
390 break;
391 case kOpMul:
buzbeeed3e9302011-09-23 17:34:19 -0700392 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700393 opcode = kThumb2MulRRR;
394 break;
395 case kOpOr:
396 opcode = kThumb2OrrRRR;
397 break;
398 case kOpSbc:
399 opcode = kThumb2SbcRRR;
400 break;
401 case kOpLsl:
buzbeeed3e9302011-09-23 17:34:19 -0700402 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700403 opcode = kThumb2LslRRR;
404 break;
405 case kOpLsr:
buzbeeed3e9302011-09-23 17:34:19 -0700406 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700407 opcode = kThumb2LsrRRR;
408 break;
409 case kOpAsr:
buzbeeed3e9302011-09-23 17:34:19 -0700410 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700411 opcode = kThumb2AsrRRR;
412 break;
413 case kOpRor:
buzbeeed3e9302011-09-23 17:34:19 -0700414 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700415 opcode = kThumb2RorRRR;
416 break;
417 default:
buzbeeed3e9302011-09-23 17:34:19 -0700418 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700419 break;
420 }
buzbeeed3e9302011-09-23 17:34:19 -0700421 DCHECK(opcode >= 0);
buzbee67bf8852011-08-17 17:51:35 -0700422 if (EncodingMap[opcode].flags & IS_QUAD_OP)
423 return newLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
424 else {
buzbeeed3e9302011-09-23 17:34:19 -0700425 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
buzbee67bf8852011-08-17 17:51:35 -0700426 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
427 }
428}
429
buzbeeed3e9302011-09-23 17:34:19 -0700430STATIC ArmLIR* opRegRegReg(CompilationUnit* cUnit, OpKind op, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700431 int rSrc1, int rSrc2)
432{
433 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
434}
435
buzbeeed3e9302011-09-23 17:34:19 -0700436STATIC ArmLIR* opRegRegImm(CompilationUnit* cUnit, OpKind op, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700437 int rSrc1, int value)
438{
439 ArmLIR* res;
440 bool neg = (value < 0);
441 int absValue = (neg) ? -value : value;
442 ArmOpcode opcode = kThumbBkpt;
443 ArmOpcode altOpcode = kThumbBkpt;
444 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
445 int modImm = modifiedImmediate(value);
446 int modImmNeg = modifiedImmediate(-value);
447
448 switch(op) {
449 case kOpLsl:
450 if (allLowRegs)
451 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
452 else
453 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
454 case kOpLsr:
455 if (allLowRegs)
456 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
457 else
458 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
459 case kOpAsr:
460 if (allLowRegs)
461 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
462 else
463 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
464 case kOpRor:
465 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
466 case kOpAdd:
467 if (LOWREG(rDest) && (rSrc1 == r13sp) &&
468 (value <= 1020) && ((value & 0x3)==0)) {
469 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
470 value >> 2);
471 } else if (LOWREG(rDest) && (rSrc1 == r15pc) &&
472 (value <= 1020) && ((value & 0x3)==0)) {
473 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
474 value >> 2);
475 }
buzbee67bf8852011-08-17 17:51:35 -0700476 // Note: intentional fallthrough
477 case kOpSub:
478 if (allLowRegs && ((absValue & 0x7) == absValue)) {
479 if (op == kOpAdd)
480 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
481 else
482 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
483 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
484 } else if ((absValue & 0xff) == absValue) {
485 if (op == kOpAdd)
486 opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
487 else
488 opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
489 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
490 }
491 if (modImmNeg >= 0) {
492 op = (op == kOpAdd) ? kOpSub : kOpAdd;
493 modImm = modImmNeg;
494 }
495 if (op == kOpSub) {
496 opcode = kThumb2SubRRI8;
497 altOpcode = kThumb2SubRRR;
buzbee3b5d3792011-09-20 11:01:40 -0700498 } else {
499 opcode = kThumb2AddRRI8;
500 altOpcode = kThumb2AddRRR;
buzbee67bf8852011-08-17 17:51:35 -0700501 }
502 break;
503 case kOpAdc:
504 opcode = kThumb2AdcRRI8;
505 altOpcode = kThumb2AdcRRR;
506 break;
507 case kOpSbc:
508 opcode = kThumb2SbcRRI8;
509 altOpcode = kThumb2SbcRRR;
510 break;
511 case kOpOr:
512 opcode = kThumb2OrrRRI8;
513 altOpcode = kThumb2OrrRRR;
514 break;
515 case kOpAnd:
516 opcode = kThumb2AndRRI8;
517 altOpcode = kThumb2AndRRR;
518 break;
519 case kOpXor:
520 opcode = kThumb2EorRRI8;
521 altOpcode = kThumb2EorRRR;
522 break;
523 case kOpMul:
524 //TUNING: power of 2, shift & add
525 modImm = -1;
526 altOpcode = kThumb2MulRRR;
527 break;
528 case kOpCmp: {
529 int modImm = modifiedImmediate(value);
530 ArmLIR* res;
531 if (modImm >= 0) {
532 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
533 } else {
534 int rTmp = oatAllocTemp(cUnit);
535 res = loadConstant(cUnit, rTmp, value);
536 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
537 oatFreeTemp(cUnit, rTmp);
538 }
539 return res;
540 }
541 default:
buzbeeed3e9302011-09-23 17:34:19 -0700542 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700543 }
544
545 if (modImm >= 0) {
546 return newLIR3(cUnit, opcode, rDest, rSrc1, modImm);
547 } else {
548 int rScratch = oatAllocTemp(cUnit);
549 loadConstant(cUnit, rScratch, value);
550 if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
551 res = newLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
552 else
553 res = newLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
554 oatFreeTemp(cUnit, rScratch);
555 return res;
556 }
557}
558
559/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
buzbeeed3e9302011-09-23 17:34:19 -0700560STATIC ArmLIR* opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700561 int value)
562{
563 bool neg = (value < 0);
564 int absValue = (neg) ? -value : value;
565 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
566 ArmOpcode opcode = kThumbBkpt;
567 switch (op) {
568 case kOpAdd:
569 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
buzbeeed3e9302011-09-23 17:34:19 -0700570 DCHECK_EQ((value & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700571 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
572 } else if (shortForm) {
573 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
574 }
575 break;
576 case kOpSub:
577 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
buzbeeed3e9302011-09-23 17:34:19 -0700578 DCHECK_EQ((value & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700579 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
580 } else if (shortForm) {
581 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
582 }
583 break;
584 case kOpCmp:
585 if (LOWREG(rDestSrc1) && shortForm)
586 opcode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
587 else if (LOWREG(rDestSrc1))
588 opcode = kThumbCmpRR;
589 else {
590 shortForm = false;
591 opcode = kThumbCmpHL;
592 }
593 break;
594 default:
595 /* Punt to opRegRegImm - if bad case catch it there */
596 shortForm = false;
597 break;
598 }
599 if (shortForm)
600 return newLIR2(cUnit, opcode, rDestSrc1, absValue);
601 else {
602 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
603 }
604}
605
606/*
607 * Determine whether value can be encoded as a Thumb2 floating point
608 * immediate. If not, return -1. If so return encoded 8-bit value.
609 */
buzbeeed3e9302011-09-23 17:34:19 -0700610STATIC int encodeImmDoubleHigh(int value)
buzbee67bf8852011-08-17 17:51:35 -0700611{
612 int res;
613 int bitA = (value & 0x80000000) >> 31;
614 int notBitB = (value & 0x40000000) >> 30;
615 int bitB = (value & 0x20000000) >> 29;
616 int bSmear = (value & 0x3fc00000) >> 22;
617 int slice = (value & 0x003f0000) >> 16;
618 int zeroes = (value & 0x0000ffff);
619 if (zeroes != 0)
620 return -1;
621 if (bitB) {
buzbee03fa2632011-09-20 17:10:57 -0700622 if ((notBitB != 0) || (bSmear != 0xff))
buzbee67bf8852011-08-17 17:51:35 -0700623 return -1;
624 } else {
625 if ((notBitB != 1) || (bSmear != 0x0))
626 return -1;
627 }
628 res = (bitA << 7) | (bitB << 6) | slice;
629 return res;
630}
631
buzbeeed3e9302011-09-23 17:34:19 -0700632STATIC int encodeImmDouble(int valLo, int valHi)
buzbee67bf8852011-08-17 17:51:35 -0700633{
634 int res = -1;
635 if (valLo == 0)
636 res = encodeImmDoubleHigh(valHi);
637 return res;
638}
639
buzbeeed3e9302011-09-23 17:34:19 -0700640STATIC ArmLIR* loadConstantValueWide(CompilationUnit* cUnit, int rDestLo,
buzbee67bf8852011-08-17 17:51:35 -0700641 int rDestHi, int valLo, int valHi)
642{
643 int encodedImm = encodeImmDouble(valLo, valHi);
644 ArmLIR* res;
buzbee03fa2632011-09-20 17:10:57 -0700645 if (FPREG(rDestLo)) {
646 if (encodedImm >= 0) {
647 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
648 encodedImm);
649 } else {
650 ArmLIR* dataTarget = scanLiteralPoolWide(cUnit->literalList, valLo,
651 valHi);
652 if (dataTarget == NULL) {
653 dataTarget = addWideData(cUnit, &cUnit->literalList, valLo,
654 valHi);
655 }
656 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
657 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
658 loadPcRel->opcode = kThumb2Vldrd;
659 loadPcRel->generic.target = (LIR* ) dataTarget;
660 loadPcRel->operands[0] = S2D(rDestLo, rDestHi);
661 loadPcRel->operands[1] = r15pc;
662 setupResourceMasks(loadPcRel);
663 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -0700664 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee03fa2632011-09-20 17:10:57 -0700665 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
666 res = loadPcRel;
667 }
buzbee67bf8852011-08-17 17:51:35 -0700668 } else {
669 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
670 loadConstantNoClobber(cUnit, rDestHi, valHi);
671 }
672 return res;
673}
674
buzbeeed3e9302011-09-23 17:34:19 -0700675STATIC int encodeShift(int code, int amount) {
buzbee67bf8852011-08-17 17:51:35 -0700676 return ((amount & 0x1f) << 2) | code;
677}
678
buzbeeed3e9302011-09-23 17:34:19 -0700679STATIC ArmLIR* loadBaseIndexed(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700680 int rIndex, int rDest, int scale, OpSize size)
681{
682 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
683 ArmLIR* load;
684 ArmOpcode opcode = kThumbBkpt;
685 bool thumbForm = (allLowRegs && (scale == 0));
686 int regPtr;
687
688 if (FPREG(rDest)) {
buzbeeed3e9302011-09-23 17:34:19 -0700689 DCHECK(SINGLEREG(rDest));
690 DCHECK((size == kWord) || (size == kSingle));
buzbee67bf8852011-08-17 17:51:35 -0700691 opcode = kThumb2Vldrs;
692 size = kSingle;
693 } else {
694 if (size == kSingle)
695 size = kWord;
696 }
697
698 switch (size) {
699 case kSingle:
700 regPtr = oatAllocTemp(cUnit);
701 if (scale) {
702 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
703 encodeShift(kArmLsl, scale));
704 } else {
705 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
706 }
707 load = newLIR3(cUnit, opcode, rDest, regPtr, 0);
708 return load;
709 case kWord:
710 opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
711 break;
712 case kUnsignedHalf:
713 opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
714 break;
715 case kSignedHalf:
716 opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
717 break;
718 case kUnsignedByte:
719 opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
720 break;
721 case kSignedByte:
722 opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
723 break;
724 default:
buzbeeed3e9302011-09-23 17:34:19 -0700725 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700726 }
727 if (thumbForm)
728 load = newLIR3(cUnit, opcode, rDest, rBase, rIndex);
729 else
730 load = newLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
731
732 return load;
733}
734
buzbeeed3e9302011-09-23 17:34:19 -0700735STATIC ArmLIR* storeBaseIndexed(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700736 int rIndex, int rSrc, int scale, OpSize size)
737{
738 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
739 ArmLIR* store;
740 ArmOpcode opcode = kThumbBkpt;
741 bool thumbForm = (allLowRegs && (scale == 0));
742 int regPtr;
743
744 if (FPREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700745 DCHECK(SINGLEREG(rSrc));
746 DCHECK((size == kWord) || (size == kSingle));
buzbee67bf8852011-08-17 17:51:35 -0700747 opcode = kThumb2Vstrs;
748 size = kSingle;
749 } else {
750 if (size == kSingle)
751 size = kWord;
752 }
753
754 switch (size) {
755 case kSingle:
756 regPtr = oatAllocTemp(cUnit);
757 if (scale) {
758 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
759 encodeShift(kArmLsl, scale));
760 } else {
761 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
762 }
763 store = newLIR3(cUnit, opcode, rSrc, regPtr, 0);
764 return store;
765 case kWord:
766 opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
767 break;
768 case kUnsignedHalf:
769 case kSignedHalf:
770 opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
771 break;
772 case kUnsignedByte:
773 case kSignedByte:
774 opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
775 break;
776 default:
buzbeeed3e9302011-09-23 17:34:19 -0700777 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700778 }
779 if (thumbForm)
780 store = newLIR3(cUnit, opcode, rSrc, rBase, rIndex);
781 else
782 store = newLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
783
784 return store;
785}
786
787/*
788 * Load value from base + displacement. Optionally perform null check
789 * on base (which must have an associated sReg and MIR). If not
790 * performing null check, incoming MIR can be null.
791 */
buzbeeed3e9302011-09-23 17:34:19 -0700792STATIC ArmLIR* loadBaseDispBody(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700793 int displacement, int rDest, int rDestHi,
794 OpSize size, int sReg)
795{
796 ArmLIR* res;
797 ArmLIR* load;
798 ArmOpcode opcode = kThumbBkpt;
799 bool shortForm = false;
800 bool thumb2Form = (displacement < 4092 && displacement >= 0);
801 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
802 int encodedDisp = displacement;
803
804 switch (size) {
805 case kDouble:
806 case kLong:
807 if (FPREG(rDest)) {
808 if (SINGLEREG(rDest)) {
buzbeeed3e9302011-09-23 17:34:19 -0700809 DCHECK(FPREG(rDestHi));
buzbee67bf8852011-08-17 17:51:35 -0700810 rDest = S2D(rDest, rDestHi);
811 }
812 opcode = kThumb2Vldrd;
813 if (displacement <= 1020) {
814 shortForm = true;
815 encodedDisp >>= 2;
816 }
817 break;
818 } else {
819 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
820 -1, kWord, sReg);
821 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
822 -1, kWord, INVALID_SREG);
823 return res;
824 }
825 case kSingle:
826 case kWord:
827 if (FPREG(rDest)) {
828 opcode = kThumb2Vldrs;
829 if (displacement <= 1020) {
830 shortForm = true;
831 encodedDisp >>= 2;
832 }
833 break;
834 }
835 if (LOWREG(rDest) && (rBase == r15pc) &&
836 (displacement <= 1020) && (displacement >= 0)) {
837 shortForm = true;
838 encodedDisp >>= 2;
839 opcode = kThumbLdrPcRel;
840 } else if (LOWREG(rDest) && (rBase == r13sp) &&
841 (displacement <= 1020) && (displacement >= 0)) {
842 shortForm = true;
843 encodedDisp >>= 2;
844 opcode = kThumbLdrSpRel;
845 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700846 DCHECK_EQ((displacement & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700847 shortForm = true;
848 encodedDisp >>= 2;
849 opcode = kThumbLdrRRI5;
850 } else if (thumb2Form) {
851 shortForm = true;
852 opcode = kThumb2LdrRRI12;
853 }
854 break;
855 case kUnsignedHalf:
856 if (allLowRegs && displacement < 64 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700857 DCHECK_EQ((displacement & 0x1), 0);
buzbee67bf8852011-08-17 17:51:35 -0700858 shortForm = true;
859 encodedDisp >>= 1;
860 opcode = kThumbLdrhRRI5;
861 } else if (displacement < 4092 && displacement >= 0) {
862 shortForm = true;
863 opcode = kThumb2LdrhRRI12;
864 }
865 break;
866 case kSignedHalf:
867 if (thumb2Form) {
868 shortForm = true;
869 opcode = kThumb2LdrshRRI12;
870 }
871 break;
872 case kUnsignedByte:
873 if (allLowRegs && displacement < 32 && displacement >= 0) {
874 shortForm = true;
875 opcode = kThumbLdrbRRI5;
876 } else if (thumb2Form) {
877 shortForm = true;
878 opcode = kThumb2LdrbRRI12;
879 }
880 break;
881 case kSignedByte:
882 if (thumb2Form) {
883 shortForm = true;
884 opcode = kThumb2LdrsbRRI12;
885 }
886 break;
887 default:
buzbeeed3e9302011-09-23 17:34:19 -0700888 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700889 }
890
891 if (shortForm) {
892 load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
893 } else {
894 int regOffset = oatAllocTemp(cUnit);
895 res = loadConstant(cUnit, regOffset, encodedDisp);
896 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
897 oatFreeTemp(cUnit, regOffset);
898 }
899
900 // TODO: in future may need to differentiate Dalvik accesses w/ spills
901 if (rBase == rSP) {
902 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
903 }
904 return load;
905}
906
buzbeeed3e9302011-09-23 17:34:19 -0700907STATIC ArmLIR* loadBaseDisp(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700908 int displacement, int rDest, OpSize size,
909 int sReg)
910{
911 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
912 size, sReg);
913}
914
buzbeeed3e9302011-09-23 17:34:19 -0700915STATIC ArmLIR* loadBaseDispWide(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700916 int displacement, int rDestLo, int rDestHi,
917 int sReg)
918{
919 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
920 kLong, sReg);
921}
922
923
buzbeeed3e9302011-09-23 17:34:19 -0700924STATIC ArmLIR* storeBaseDispBody(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700925 int displacement, int rSrc, int rSrcHi,
926 OpSize size)
927{
928 ArmLIR* res, *store;
929 ArmOpcode opcode = kThumbBkpt;
930 bool shortForm = false;
931 bool thumb2Form = (displacement < 4092 && displacement >= 0);
932 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
933 int encodedDisp = displacement;
934
935 switch (size) {
936 case kLong:
937 case kDouble:
938 if (!FPREG(rSrc)) {
939 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
940 -1, kWord);
941 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
942 -1, kWord);
943 return res;
944 }
945 if (SINGLEREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700946 DCHECK(FPREG(rSrcHi));
buzbee67bf8852011-08-17 17:51:35 -0700947 rSrc = S2D(rSrc, rSrcHi);
948 }
949 opcode = kThumb2Vstrd;
950 if (displacement <= 1020) {
951 shortForm = true;
952 encodedDisp >>= 2;
953 }
954 break;
955 case kSingle:
956 case kWord:
957 if (FPREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700958 DCHECK(SINGLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -0700959 opcode = kThumb2Vstrs;
960 if (displacement <= 1020) {
961 shortForm = true;
962 encodedDisp >>= 2;
963 }
964 break;
965 }
966 if (allLowRegs && displacement < 128 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700967 DCHECK_EQ((displacement & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700968 shortForm = true;
969 encodedDisp >>= 2;
970 opcode = kThumbStrRRI5;
971 } else if (thumb2Form) {
972 shortForm = true;
973 opcode = kThumb2StrRRI12;
974 }
975 break;
976 case kUnsignedHalf:
977 case kSignedHalf:
978 if (allLowRegs && displacement < 64 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700979 DCHECK_EQ((displacement & 0x1), 0);
buzbee67bf8852011-08-17 17:51:35 -0700980 shortForm = true;
981 encodedDisp >>= 1;
982 opcode = kThumbStrhRRI5;
983 } else if (thumb2Form) {
984 shortForm = true;
985 opcode = kThumb2StrhRRI12;
986 }
987 break;
988 case kUnsignedByte:
989 case kSignedByte:
990 if (allLowRegs && displacement < 32 && displacement >= 0) {
991 shortForm = true;
992 opcode = kThumbStrbRRI5;
993 } else if (thumb2Form) {
994 shortForm = true;
995 opcode = kThumb2StrbRRI12;
996 }
997 break;
998 default:
buzbeeed3e9302011-09-23 17:34:19 -0700999 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -07001000 }
1001 if (shortForm) {
1002 store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
1003 } else {
1004 int rScratch = oatAllocTemp(cUnit);
1005 res = loadConstant(cUnit, rScratch, encodedDisp);
1006 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
1007 oatFreeTemp(cUnit, rScratch);
1008 }
1009
1010 // TODO: In future, may need to differentiate Dalvik & spill accesses
1011 if (rBase == rSP) {
1012 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
1013 }
1014 return res;
1015}
1016
buzbeeed3e9302011-09-23 17:34:19 -07001017STATIC ArmLIR* storeBaseDisp(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -07001018 int displacement, int rSrc, OpSize size)
1019{
1020 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1021}
1022
buzbeeed3e9302011-09-23 17:34:19 -07001023STATIC ArmLIR* storeBaseDispWide(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -07001024 int displacement, int rSrcLo, int rSrcHi)
1025{
1026 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1027}
1028
buzbeeed3e9302011-09-23 17:34:19 -07001029STATIC void storePair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
buzbee67bf8852011-08-17 17:51:35 -07001030{
1031 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1032}
1033
buzbeeed3e9302011-09-23 17:34:19 -07001034STATIC void loadPair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
buzbee67bf8852011-08-17 17:51:35 -07001035{
1036 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1037}
1038
1039/*
1040 * Generate a register comparison to an immediate and branch. Caller
1041 * is responsible for setting branch target field.
1042 */
buzbeeed3e9302011-09-23 17:34:19 -07001043STATIC ArmLIR* genCmpImmBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001044 ArmConditionCode cond, int reg,
1045 int checkValue)
1046{
1047 ArmLIR* branch;
1048 int modImm;
1049 if ((LOWREG(reg)) && (checkValue == 0) &&
1050 ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1051 branch = newLIR2(cUnit,
1052 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1053 reg, 0);
1054 } else {
1055 modImm = modifiedImmediate(checkValue);
1056 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1057 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1058 } else if (modImm >= 0) {
1059 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1060 } else {
1061 int tReg = oatAllocTemp(cUnit);
1062 loadConstant(cUnit, tReg, checkValue);
1063 opRegReg(cUnit, kOpCmp, reg, tReg);
1064 }
1065 branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1066 }
1067 return branch;
1068}
1069
buzbeeed3e9302011-09-23 17:34:19 -07001070STATIC ArmLIR* fpRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001071{
1072 ArmLIR* res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1073 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1074 res->operands[0] = rDest;
1075 res->operands[1] = rSrc;
1076 if (rDest == rSrc) {
1077 res->flags.isNop = true;
1078 } else {
buzbeeed3e9302011-09-23 17:34:19 -07001079 DCHECK_EQ(DOUBLEREG(rDest), DOUBLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -07001080 if (DOUBLEREG(rDest)) {
1081 res->opcode = kThumb2Vmovd;
1082 } else {
1083 if (SINGLEREG(rDest)) {
1084 res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1085 } else {
buzbeeed3e9302011-09-23 17:34:19 -07001086 DCHECK(SINGLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -07001087 res->opcode = kThumb2Fmrs;
1088 }
1089 }
1090 res->operands[0] = rDest;
1091 res->operands[1] = rSrc;
1092 }
1093 setupResourceMasks(res);
1094 return res;
1095}
1096
buzbeeed3e9302011-09-23 17:34:19 -07001097STATIC ArmLIR* genRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001098{
1099 ArmLIR* res;
1100 ArmOpcode opcode;
1101 if (FPREG(rDest) || FPREG(rSrc))
1102 return fpRegCopy(cUnit, rDest, rSrc);
1103 res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1104 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1105 if (LOWREG(rDest) && LOWREG(rSrc))
1106 opcode = kThumbMovRR;
1107 else if (!LOWREG(rDest) && !LOWREG(rSrc))
1108 opcode = kThumbMovRR_H2H;
1109 else if (LOWREG(rDest))
1110 opcode = kThumbMovRR_H2L;
1111 else
1112 opcode = kThumbMovRR_L2H;
1113
1114 res->operands[0] = rDest;
1115 res->operands[1] = rSrc;
1116 res->opcode = opcode;
1117 setupResourceMasks(res);
1118 if (rDest == rSrc) {
1119 res->flags.isNop = true;
1120 }
1121 return res;
1122}
1123
buzbeeed3e9302011-09-23 17:34:19 -07001124STATIC ArmLIR* genRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001125{
1126 ArmLIR* res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1127 oatAppendLIR(cUnit, (LIR*)res);
1128 return res;
1129}
1130
buzbeeed3e9302011-09-23 17:34:19 -07001131STATIC void genRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
buzbee67bf8852011-08-17 17:51:35 -07001132 int srcLo, int srcHi)
1133{
1134 bool destFP = FPREG(destLo) && FPREG(destHi);
1135 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
buzbeeed3e9302011-09-23 17:34:19 -07001136 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
1137 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
buzbee67bf8852011-08-17 17:51:35 -07001138 if (destFP) {
1139 if (srcFP) {
1140 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1141 } else {
1142 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1143 }
1144 } else {
1145 if (srcFP) {
1146 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1147 } else {
1148 // Handle overlap
1149 if (srcHi == destLo) {
1150 genRegCopy(cUnit, destHi, srcHi);
1151 genRegCopy(cUnit, destLo, srcLo);
1152 } else {
1153 genRegCopy(cUnit, destLo, srcLo);
1154 genRegCopy(cUnit, destHi, srcHi);
1155 }
1156 }
1157 }
1158}