blob: 305a14798a884d2e1cc2eda0d1db33ef154cd236 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -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#include "arm_lir.h"
18#include "codegen_arm.h"
19#include "dex/quick/mir_to_lir-inl.h"
20
21namespace art {
22
23/* This file contains codegen for the Thumb ISA. */
24
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070025static int EncodeImmSingle(int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070026 int res;
27 int bit_a = (value & 0x80000000) >> 31;
28 int not_bit_b = (value & 0x40000000) >> 30;
29 int bit_b = (value & 0x20000000) >> 29;
30 int b_smear = (value & 0x3e000000) >> 25;
31 int slice = (value & 0x01f80000) >> 19;
32 int zeroes = (value & 0x0007ffff);
33 if (zeroes != 0)
34 return -1;
35 if (bit_b) {
36 if ((not_bit_b != 0) || (b_smear != 0x1f))
37 return -1;
38 } else {
39 if ((not_bit_b != 1) || (b_smear != 0x0))
40 return -1;
41 }
42 res = (bit_a << 7) | (bit_b << 6) | slice;
43 return res;
44}
45
46/*
47 * Determine whether value can be encoded as a Thumb2 floating point
48 * immediate. If not, return -1. If so return encoded 8-bit value.
49 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070050static int EncodeImmDouble(int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070051 int res;
52 int bit_a = (value & 0x8000000000000000ll) >> 63;
53 int not_bit_b = (value & 0x4000000000000000ll) >> 62;
54 int bit_b = (value & 0x2000000000000000ll) >> 61;
55 int b_smear = (value & 0x3fc0000000000000ll) >> 54;
56 int slice = (value & 0x003f000000000000ll) >> 48;
57 uint64_t zeroes = (value & 0x0000ffffffffffffll);
58 if (zeroes != 0)
59 return -1;
60 if (bit_b) {
61 if ((not_bit_b != 0) || (b_smear != 0xff))
62 return -1;
63 } else {
64 if ((not_bit_b != 1) || (b_smear != 0x0))
65 return -1;
66 }
67 res = (bit_a << 7) | (bit_b << 6) | slice;
68 return res;
69}
70
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070071LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070072 DCHECK(ARM_SINGLEREG(r_dest));
73 if (value == 0) {
74 // TODO: we need better info about the target CPU. a vector exclusive or
75 // would probably be better here if we could rely on its existance.
76 // Load an immediate +2.0 (which encodes to 0)
77 NewLIR2(kThumb2Vmovs_IMM8, r_dest, 0);
78 // +0.0 = +2.0 - +2.0
79 return NewLIR3(kThumb2Vsubs, r_dest, r_dest, r_dest);
80 } else {
81 int encoded_imm = EncodeImmSingle(value);
82 if (encoded_imm >= 0) {
83 return NewLIR2(kThumb2Vmovs_IMM8, r_dest, encoded_imm);
84 }
85 }
86 LIR* data_target = ScanLiteralPool(literal_list_, value, 0);
87 if (data_target == NULL) {
88 data_target = AddWordData(&literal_list_, value);
89 }
90 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kThumb2Vldrs,
91 r_dest, r15pc, 0, 0, 0, data_target);
92 SetMemRefType(load_pc_rel, true, kLiteral);
93 load_pc_rel->alias_info = reinterpret_cast<uintptr_t>(data_target);
94 AppendLIR(load_pc_rel);
95 return load_pc_rel;
96}
97
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070098static int LeadingZeros(uint32_t val) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 uint32_t alt;
100 int n;
101 int count;
102
103 count = 16;
104 n = 32;
105 do {
106 alt = val >> count;
107 if (alt != 0) {
108 n = n - count;
109 val = alt;
110 }
111 count >>= 1;
112 } while (count);
113 return n - val;
114}
115
116/*
117 * Determine whether value can be encoded as a Thumb2 modified
118 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
119 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700120int ArmMir2Lir::ModifiedImmediate(uint32_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 int z_leading;
122 int z_trailing;
123 uint32_t b0 = value & 0xff;
124
125 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
126 if (value <= 0xFF)
127 return b0; // 0:000:a:bcdefgh
128 if (value == ((b0 << 16) | b0))
129 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
130 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
131 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
132 b0 = (value >> 8) & 0xff;
133 if (value == ((b0 << 24) | (b0 << 8)))
134 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
135 /* Can we do it with rotation? */
136 z_leading = LeadingZeros(value);
137 z_trailing = 32 - LeadingZeros(~value & (value - 1));
138 /* A run of eight or fewer active bits? */
139 if ((z_leading + z_trailing) < 24)
140 return -1; /* No - bail */
141 /* left-justify the constant, discarding msb (known to be 1) */
142 value <<= z_leading + 1;
143 /* Create bcdefgh */
144 value >>= 25;
145 /* Put it all together */
146 return value | ((0x8 + z_leading) << 7); /* [01000..11111]:bcdefgh */
147}
148
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700149bool ArmMir2Lir::InexpensiveConstantInt(int32_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
151}
152
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700153bool ArmMir2Lir::InexpensiveConstantFloat(int32_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700154 return EncodeImmSingle(value) >= 0;
155}
156
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700157bool ArmMir2Lir::InexpensiveConstantLong(int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158 return InexpensiveConstantInt(High32Bits(value)) && InexpensiveConstantInt(Low32Bits(value));
159}
160
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700161bool ArmMir2Lir::InexpensiveConstantDouble(int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 return EncodeImmDouble(value) >= 0;
163}
164
165/*
166 * Load a immediate using a shortcut if possible; otherwise
167 * grab from the per-translation literal pool.
168 *
169 * No additional register clobbering operation performed. Use this version when
170 * 1) r_dest is freshly returned from AllocTemp or
171 * 2) The codegen is under fixed register usage
172 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700173LIR* ArmMir2Lir::LoadConstantNoClobber(int r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 LIR* res;
175 int mod_imm;
176
177 if (ARM_FPREG(r_dest)) {
178 return LoadFPConstantValue(r_dest, value);
179 }
180
181 /* See if the value can be constructed cheaply */
182 if (ARM_LOWREG(r_dest) && (value >= 0) && (value <= 255)) {
183 return NewLIR2(kThumbMovImm, r_dest, value);
184 }
185 /* Check Modified immediate special cases */
186 mod_imm = ModifiedImmediate(value);
187 if (mod_imm >= 0) {
188 res = NewLIR2(kThumb2MovImmShift, r_dest, mod_imm);
189 return res;
190 }
191 mod_imm = ModifiedImmediate(~value);
192 if (mod_imm >= 0) {
193 res = NewLIR2(kThumb2MvnImm12, r_dest, mod_imm);
194 return res;
195 }
196 /* 16-bit immediate? */
197 if ((value & 0xffff) == value) {
198 res = NewLIR2(kThumb2MovImm16, r_dest, value);
199 return res;
200 }
201 /* Do a low/high pair */
202 res = NewLIR2(kThumb2MovImm16, r_dest, Low16Bits(value));
203 NewLIR2(kThumb2MovImm16H, r_dest, High16Bits(value));
204 return res;
205}
206
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700207LIR* ArmMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 LIR* res = NewLIR1(kThumbBUncond, 0 /* offset to be patched during assembly*/);
209 res->target = target;
210 return res;
211}
212
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700213LIR* ArmMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 LIR* branch = NewLIR2(kThumb2BCond, 0 /* offset to be patched */,
215 ArmConditionEncoding(cc));
216 branch->target = target;
217 return branch;
218}
219
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700220LIR* ArmMir2Lir::OpReg(OpKind op, int r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221 ArmOpcode opcode = kThumbBkpt;
222 switch (op) {
223 case kOpBlx:
224 opcode = kThumbBlxR;
225 break;
226 default:
227 LOG(FATAL) << "Bad opcode " << op;
228 }
229 return NewLIR1(opcode, r_dest_src);
230}
231
232LIR* ArmMir2Lir::OpRegRegShift(OpKind op, int r_dest_src1, int r_src2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700233 int shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 bool thumb_form = ((shift == 0) && ARM_LOWREG(r_dest_src1) && ARM_LOWREG(r_src2));
235 ArmOpcode opcode = kThumbBkpt;
236 switch (op) {
237 case kOpAdc:
238 opcode = (thumb_form) ? kThumbAdcRR : kThumb2AdcRRR;
239 break;
240 case kOpAnd:
241 opcode = (thumb_form) ? kThumbAndRR : kThumb2AndRRR;
242 break;
243 case kOpBic:
244 opcode = (thumb_form) ? kThumbBicRR : kThumb2BicRRR;
245 break;
246 case kOpCmn:
247 DCHECK_EQ(shift, 0);
248 opcode = (thumb_form) ? kThumbCmnRR : kThumb2CmnRR;
249 break;
250 case kOpCmp:
251 if (thumb_form)
252 opcode = kThumbCmpRR;
253 else if ((shift == 0) && !ARM_LOWREG(r_dest_src1) && !ARM_LOWREG(r_src2))
254 opcode = kThumbCmpHH;
255 else if ((shift == 0) && ARM_LOWREG(r_dest_src1))
256 opcode = kThumbCmpLH;
257 else if (shift == 0)
258 opcode = kThumbCmpHL;
259 else
260 opcode = kThumb2CmpRR;
261 break;
262 case kOpXor:
263 opcode = (thumb_form) ? kThumbEorRR : kThumb2EorRRR;
264 break;
265 case kOpMov:
266 DCHECK_EQ(shift, 0);
267 if (ARM_LOWREG(r_dest_src1) && ARM_LOWREG(r_src2))
268 opcode = kThumbMovRR;
269 else if (!ARM_LOWREG(r_dest_src1) && !ARM_LOWREG(r_src2))
270 opcode = kThumbMovRR_H2H;
271 else if (ARM_LOWREG(r_dest_src1))
272 opcode = kThumbMovRR_H2L;
273 else
274 opcode = kThumbMovRR_L2H;
275 break;
276 case kOpMul:
277 DCHECK_EQ(shift, 0);
278 opcode = (thumb_form) ? kThumbMul : kThumb2MulRRR;
279 break;
280 case kOpMvn:
281 opcode = (thumb_form) ? kThumbMvn : kThumb2MnvRR;
282 break;
283 case kOpNeg:
284 DCHECK_EQ(shift, 0);
285 opcode = (thumb_form) ? kThumbNeg : kThumb2NegRR;
286 break;
287 case kOpOr:
288 opcode = (thumb_form) ? kThumbOrr : kThumb2OrrRRR;
289 break;
290 case kOpSbc:
291 opcode = (thumb_form) ? kThumbSbc : kThumb2SbcRRR;
292 break;
293 case kOpTst:
294 opcode = (thumb_form) ? kThumbTst : kThumb2TstRR;
295 break;
296 case kOpLsl:
297 DCHECK_EQ(shift, 0);
298 opcode = (thumb_form) ? kThumbLslRR : kThumb2LslRRR;
299 break;
300 case kOpLsr:
301 DCHECK_EQ(shift, 0);
302 opcode = (thumb_form) ? kThumbLsrRR : kThumb2LsrRRR;
303 break;
304 case kOpAsr:
305 DCHECK_EQ(shift, 0);
306 opcode = (thumb_form) ? kThumbAsrRR : kThumb2AsrRRR;
307 break;
308 case kOpRor:
309 DCHECK_EQ(shift, 0);
310 opcode = (thumb_form) ? kThumbRorRR : kThumb2RorRRR;
311 break;
312 case kOpAdd:
313 opcode = (thumb_form) ? kThumbAddRRR : kThumb2AddRRR;
314 break;
315 case kOpSub:
316 opcode = (thumb_form) ? kThumbSubRRR : kThumb2SubRRR;
317 break;
318 case kOp2Byte:
319 DCHECK_EQ(shift, 0);
320 return NewLIR4(kThumb2Sbfx, r_dest_src1, r_src2, 0, 8);
321 case kOp2Short:
322 DCHECK_EQ(shift, 0);
323 return NewLIR4(kThumb2Sbfx, r_dest_src1, r_src2, 0, 16);
324 case kOp2Char:
325 DCHECK_EQ(shift, 0);
326 return NewLIR4(kThumb2Ubfx, r_dest_src1, r_src2, 0, 16);
327 default:
328 LOG(FATAL) << "Bad opcode: " << op;
329 break;
330 }
331 DCHECK_GE(static_cast<int>(opcode), 0);
332 if (EncodingMap[opcode].flags & IS_BINARY_OP)
333 return NewLIR2(opcode, r_dest_src1, r_src2);
334 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
335 if (EncodingMap[opcode].field_loc[2].kind == kFmtShift)
336 return NewLIR3(opcode, r_dest_src1, r_src2, shift);
337 else
338 return NewLIR3(opcode, r_dest_src1, r_dest_src1, r_src2);
339 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
340 return NewLIR4(opcode, r_dest_src1, r_dest_src1, r_src2, shift);
341 else {
342 LOG(FATAL) << "Unexpected encoding operand count";
343 return NULL;
344 }
345}
346
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700347LIR* ArmMir2Lir::OpRegReg(OpKind op, int r_dest_src1, int r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348 return OpRegRegShift(op, r_dest_src1, r_src2, 0);
349}
350
351LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, int r_dest, int r_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700352 int r_src2, int shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 ArmOpcode opcode = kThumbBkpt;
354 bool thumb_form = (shift == 0) && ARM_LOWREG(r_dest) && ARM_LOWREG(r_src1) &&
355 ARM_LOWREG(r_src2);
356 switch (op) {
357 case kOpAdd:
358 opcode = (thumb_form) ? kThumbAddRRR : kThumb2AddRRR;
359 break;
360 case kOpSub:
361 opcode = (thumb_form) ? kThumbSubRRR : kThumb2SubRRR;
362 break;
363 case kOpRsub:
364 opcode = kThumb2RsubRRR;
365 break;
366 case kOpAdc:
367 opcode = kThumb2AdcRRR;
368 break;
369 case kOpAnd:
370 opcode = kThumb2AndRRR;
371 break;
372 case kOpBic:
373 opcode = kThumb2BicRRR;
374 break;
375 case kOpXor:
376 opcode = kThumb2EorRRR;
377 break;
378 case kOpMul:
379 DCHECK_EQ(shift, 0);
380 opcode = kThumb2MulRRR;
381 break;
382 case kOpOr:
383 opcode = kThumb2OrrRRR;
384 break;
385 case kOpSbc:
386 opcode = kThumb2SbcRRR;
387 break;
388 case kOpLsl:
389 DCHECK_EQ(shift, 0);
390 opcode = kThumb2LslRRR;
391 break;
392 case kOpLsr:
393 DCHECK_EQ(shift, 0);
394 opcode = kThumb2LsrRRR;
395 break;
396 case kOpAsr:
397 DCHECK_EQ(shift, 0);
398 opcode = kThumb2AsrRRR;
399 break;
400 case kOpRor:
401 DCHECK_EQ(shift, 0);
402 opcode = kThumb2RorRRR;
403 break;
404 default:
405 LOG(FATAL) << "Bad opcode: " << op;
406 break;
407 }
408 DCHECK_GE(static_cast<int>(opcode), 0);
409 if (EncodingMap[opcode].flags & IS_QUAD_OP)
410 return NewLIR4(opcode, r_dest, r_src1, r_src2, shift);
411 else {
412 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
413 return NewLIR3(opcode, r_dest, r_src1, r_src2);
414 }
415}
416
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700417LIR* ArmMir2Lir::OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418 return OpRegRegRegShift(op, r_dest, r_src1, r_src2, 0);
419}
420
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700421LIR* ArmMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 LIR* res;
423 bool neg = (value < 0);
424 int abs_value = (neg) ? -value : value;
425 ArmOpcode opcode = kThumbBkpt;
426 ArmOpcode alt_opcode = kThumbBkpt;
427 bool all_low_regs = (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src1));
428 int mod_imm = ModifiedImmediate(value);
429 int mod_imm_neg = ModifiedImmediate(-value);
430
431 switch (op) {
432 case kOpLsl:
433 if (all_low_regs)
434 return NewLIR3(kThumbLslRRI5, r_dest, r_src1, value);
435 else
436 return NewLIR3(kThumb2LslRRI5, r_dest, r_src1, value);
437 case kOpLsr:
438 if (all_low_regs)
439 return NewLIR3(kThumbLsrRRI5, r_dest, r_src1, value);
440 else
441 return NewLIR3(kThumb2LsrRRI5, r_dest, r_src1, value);
442 case kOpAsr:
443 if (all_low_regs)
444 return NewLIR3(kThumbAsrRRI5, r_dest, r_src1, value);
445 else
446 return NewLIR3(kThumb2AsrRRI5, r_dest, r_src1, value);
447 case kOpRor:
448 return NewLIR3(kThumb2RorRRI5, r_dest, r_src1, value);
449 case kOpAdd:
450 if (ARM_LOWREG(r_dest) && (r_src1 == r13sp) &&
451 (value <= 1020) && ((value & 0x3)==0)) {
452 return NewLIR3(kThumbAddSpRel, r_dest, r_src1, value >> 2);
453 } else if (ARM_LOWREG(r_dest) && (r_src1 == r15pc) &&
454 (value <= 1020) && ((value & 0x3)==0)) {
455 return NewLIR3(kThumbAddPcRel, r_dest, r_src1, value >> 2);
456 }
457 // Note: intentional fallthrough
458 case kOpSub:
459 if (all_low_regs && ((abs_value & 0x7) == abs_value)) {
460 if (op == kOpAdd)
461 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
462 else
463 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
464 return NewLIR3(opcode, r_dest, r_src1, abs_value);
465 } else if ((abs_value & 0xff) == abs_value) {
466 if (op == kOpAdd)
467 opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
468 else
469 opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
470 return NewLIR3(opcode, r_dest, r_src1, abs_value);
471 }
472 if (mod_imm_neg >= 0) {
473 op = (op == kOpAdd) ? kOpSub : kOpAdd;
474 mod_imm = mod_imm_neg;
475 }
476 if (op == kOpSub) {
477 opcode = kThumb2SubRRI8;
478 alt_opcode = kThumb2SubRRR;
479 } else {
480 opcode = kThumb2AddRRI8;
481 alt_opcode = kThumb2AddRRR;
482 }
483 break;
484 case kOpRsub:
485 opcode = kThumb2RsubRRI8;
486 alt_opcode = kThumb2RsubRRR;
487 break;
488 case kOpAdc:
489 opcode = kThumb2AdcRRI8;
490 alt_opcode = kThumb2AdcRRR;
491 break;
492 case kOpSbc:
493 opcode = kThumb2SbcRRI8;
494 alt_opcode = kThumb2SbcRRR;
495 break;
496 case kOpOr:
497 opcode = kThumb2OrrRRI8;
498 alt_opcode = kThumb2OrrRRR;
499 break;
500 case kOpAnd:
501 opcode = kThumb2AndRRI8;
502 alt_opcode = kThumb2AndRRR;
503 break;
504 case kOpXor:
505 opcode = kThumb2EorRRI8;
506 alt_opcode = kThumb2EorRRR;
507 break;
508 case kOpMul:
509 //TUNING: power of 2, shift & add
510 mod_imm = -1;
511 alt_opcode = kThumb2MulRRR;
512 break;
513 case kOpCmp: {
514 int mod_imm = ModifiedImmediate(value);
515 LIR* res;
516 if (mod_imm >= 0) {
517 res = NewLIR2(kThumb2CmpRI12, r_src1, mod_imm);
518 } else {
519 int r_tmp = AllocTemp();
520 res = LoadConstant(r_tmp, value);
521 OpRegReg(kOpCmp, r_src1, r_tmp);
522 FreeTemp(r_tmp);
523 }
524 return res;
525 }
526 default:
527 LOG(FATAL) << "Bad opcode: " << op;
528 }
529
530 if (mod_imm >= 0) {
531 return NewLIR3(opcode, r_dest, r_src1, mod_imm);
532 } else {
533 int r_scratch = AllocTemp();
534 LoadConstant(r_scratch, value);
535 if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
536 res = NewLIR4(alt_opcode, r_dest, r_src1, r_scratch, 0);
537 else
538 res = NewLIR3(alt_opcode, r_dest, r_src1, r_scratch);
539 FreeTemp(r_scratch);
540 return res;
541 }
542}
543
544/* Handle Thumb-only variants here - otherwise punt to OpRegRegImm */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700545LIR* ArmMir2Lir::OpRegImm(OpKind op, int r_dest_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700546 bool neg = (value < 0);
547 int abs_value = (neg) ? -value : value;
548 bool short_form = (((abs_value & 0xff) == abs_value) && ARM_LOWREG(r_dest_src1));
549 ArmOpcode opcode = kThumbBkpt;
550 switch (op) {
551 case kOpAdd:
Brian Carlstromdf629502013-07-17 22:39:56 -0700552 if (!neg && (r_dest_src1 == r13sp) && (value <= 508)) { /* sp */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 DCHECK_EQ((value & 0x3), 0);
554 return NewLIR1(kThumbAddSpI7, value >> 2);
555 } else if (short_form) {
556 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
557 }
558 break;
559 case kOpSub:
560 if (!neg && (r_dest_src1 == r13sp) && (value <= 508)) { /* sp */
561 DCHECK_EQ((value & 0x3), 0);
562 return NewLIR1(kThumbSubSpI7, value >> 2);
563 } else if (short_form) {
564 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
565 }
566 break;
567 case kOpCmp:
568 if (ARM_LOWREG(r_dest_src1) && short_form)
569 opcode = (short_form) ? kThumbCmpRI8 : kThumbCmpRR;
570 else if (ARM_LOWREG(r_dest_src1))
571 opcode = kThumbCmpRR;
572 else {
573 short_form = false;
574 opcode = kThumbCmpHL;
575 }
576 break;
577 default:
578 /* Punt to OpRegRegImm - if bad case catch it there */
579 short_form = false;
580 break;
581 }
582 if (short_form)
583 return NewLIR2(opcode, r_dest_src1, abs_value);
584 else {
585 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
586 }
587}
588
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700589LIR* ArmMir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700590 LIR* res = NULL;
591 int32_t val_lo = Low32Bits(value);
592 int32_t val_hi = High32Bits(value);
593 int target_reg = S2d(r_dest_lo, r_dest_hi);
594 if (ARM_FPREG(r_dest_lo)) {
595 if ((val_lo == 0) && (val_hi == 0)) {
596 // TODO: we need better info about the target CPU. a vector exclusive or
597 // would probably be better here if we could rely on its existance.
598 // Load an immediate +2.0 (which encodes to 0)
599 NewLIR2(kThumb2Vmovd_IMM8, target_reg, 0);
600 // +0.0 = +2.0 - +2.0
601 res = NewLIR3(kThumb2Vsubd, target_reg, target_reg, target_reg);
602 } else {
603 int encoded_imm = EncodeImmDouble(value);
604 if (encoded_imm >= 0) {
605 res = NewLIR2(kThumb2Vmovd_IMM8, target_reg, encoded_imm);
606 }
607 }
608 } else {
609 if ((InexpensiveConstantInt(val_lo) && (InexpensiveConstantInt(val_hi)))) {
610 res = LoadConstantNoClobber(r_dest_lo, val_lo);
611 LoadConstantNoClobber(r_dest_hi, val_hi);
612 }
613 }
614 if (res == NULL) {
615 // No short form - load from the literal pool.
616 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
617 if (data_target == NULL) {
618 data_target = AddWideData(&literal_list_, val_lo, val_hi);
619 }
620 if (ARM_FPREG(r_dest_lo)) {
621 res = RawLIR(current_dalvik_offset_, kThumb2Vldrd,
622 target_reg, r15pc, 0, 0, 0, data_target);
623 } else {
624 res = RawLIR(current_dalvik_offset_, kThumb2LdrdPcRel8,
625 r_dest_lo, r_dest_hi, r15pc, 0, 0, data_target);
626 }
627 SetMemRefType(res, true, kLiteral);
628 res->alias_info = reinterpret_cast<uintptr_t>(data_target);
629 AppendLIR(res);
630 }
631 return res;
632}
633
634int ArmMir2Lir::EncodeShift(int code, int amount) {
635 return ((amount & 0x1f) << 2) | code;
636}
637
638LIR* ArmMir2Lir::LoadBaseIndexed(int rBase, int r_index, int r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700639 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 bool all_low_regs = ARM_LOWREG(rBase) && ARM_LOWREG(r_index) && ARM_LOWREG(r_dest);
641 LIR* load;
642 ArmOpcode opcode = kThumbBkpt;
643 bool thumb_form = (all_low_regs && (scale == 0));
644 int reg_ptr;
645
646 if (ARM_FPREG(r_dest)) {
647 if (ARM_SINGLEREG(r_dest)) {
648 DCHECK((size == kWord) || (size == kSingle));
649 opcode = kThumb2Vldrs;
650 size = kSingle;
651 } else {
652 DCHECK(ARM_DOUBLEREG(r_dest));
653 DCHECK((size == kLong) || (size == kDouble));
654 DCHECK_EQ((r_dest & 0x1), 0);
655 opcode = kThumb2Vldrd;
656 size = kDouble;
657 }
658 } else {
659 if (size == kSingle)
660 size = kWord;
661 }
662
663 switch (size) {
664 case kDouble: // fall-through
665 case kSingle:
666 reg_ptr = AllocTemp();
667 if (scale) {
668 NewLIR4(kThumb2AddRRR, reg_ptr, rBase, r_index,
669 EncodeShift(kArmLsl, scale));
670 } else {
671 OpRegRegReg(kOpAdd, reg_ptr, rBase, r_index);
672 }
673 load = NewLIR3(opcode, r_dest, reg_ptr, 0);
674 FreeTemp(reg_ptr);
675 return load;
676 case kWord:
677 opcode = (thumb_form) ? kThumbLdrRRR : kThumb2LdrRRR;
678 break;
679 case kUnsignedHalf:
680 opcode = (thumb_form) ? kThumbLdrhRRR : kThumb2LdrhRRR;
681 break;
682 case kSignedHalf:
683 opcode = (thumb_form) ? kThumbLdrshRRR : kThumb2LdrshRRR;
684 break;
685 case kUnsignedByte:
686 opcode = (thumb_form) ? kThumbLdrbRRR : kThumb2LdrbRRR;
687 break;
688 case kSignedByte:
689 opcode = (thumb_form) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
690 break;
691 default:
692 LOG(FATAL) << "Bad size: " << size;
693 }
694 if (thumb_form)
695 load = NewLIR3(opcode, r_dest, rBase, r_index);
696 else
697 load = NewLIR4(opcode, r_dest, rBase, r_index, scale);
698
699 return load;
700}
701
702LIR* ArmMir2Lir::StoreBaseIndexed(int rBase, int r_index, int r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700703 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704 bool all_low_regs = ARM_LOWREG(rBase) && ARM_LOWREG(r_index) && ARM_LOWREG(r_src);
705 LIR* store = NULL;
706 ArmOpcode opcode = kThumbBkpt;
707 bool thumb_form = (all_low_regs && (scale == 0));
708 int reg_ptr;
709
710 if (ARM_FPREG(r_src)) {
711 if (ARM_SINGLEREG(r_src)) {
712 DCHECK((size == kWord) || (size == kSingle));
713 opcode = kThumb2Vstrs;
714 size = kSingle;
715 } else {
716 DCHECK(ARM_DOUBLEREG(r_src));
717 DCHECK((size == kLong) || (size == kDouble));
718 DCHECK_EQ((r_src & 0x1), 0);
719 opcode = kThumb2Vstrd;
720 size = kDouble;
721 }
722 } else {
723 if (size == kSingle)
724 size = kWord;
725 }
726
727 switch (size) {
728 case kDouble: // fall-through
729 case kSingle:
730 reg_ptr = AllocTemp();
731 if (scale) {
732 NewLIR4(kThumb2AddRRR, reg_ptr, rBase, r_index,
733 EncodeShift(kArmLsl, scale));
734 } else {
735 OpRegRegReg(kOpAdd, reg_ptr, rBase, r_index);
736 }
737 store = NewLIR3(opcode, r_src, reg_ptr, 0);
738 FreeTemp(reg_ptr);
739 return store;
740 case kWord:
741 opcode = (thumb_form) ? kThumbStrRRR : kThumb2StrRRR;
742 break;
743 case kUnsignedHalf:
744 case kSignedHalf:
745 opcode = (thumb_form) ? kThumbStrhRRR : kThumb2StrhRRR;
746 break;
747 case kUnsignedByte:
748 case kSignedByte:
749 opcode = (thumb_form) ? kThumbStrbRRR : kThumb2StrbRRR;
750 break;
751 default:
752 LOG(FATAL) << "Bad size: " << size;
753 }
754 if (thumb_form)
755 store = NewLIR3(opcode, r_src, rBase, r_index);
756 else
757 store = NewLIR4(opcode, r_src, rBase, r_index, scale);
758
759 return store;
760}
761
762/*
763 * Load value from base + displacement. Optionally perform null check
764 * on base (which must have an associated s_reg and MIR). If not
765 * performing null check, incoming MIR can be null.
766 */
767LIR* ArmMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700768 int r_dest_hi, OpSize size, int s_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700769 LIR* load = NULL;
770 ArmOpcode opcode = kThumbBkpt;
771 bool short_form = false;
772 bool thumb2Form = (displacement < 4092 && displacement >= 0);
773 bool all_low_regs = (ARM_LOWREG(rBase) && ARM_LOWREG(r_dest));
774 int encoded_disp = displacement;
775 bool is64bit = false;
776 bool already_generated = false;
777 switch (size) {
778 case kDouble:
779 case kLong:
780 is64bit = true;
781 if (ARM_FPREG(r_dest)) {
782 if (ARM_SINGLEREG(r_dest)) {
783 DCHECK(ARM_FPREG(r_dest_hi));
784 r_dest = S2d(r_dest, r_dest_hi);
785 }
786 opcode = kThumb2Vldrd;
787 if (displacement <= 1020) {
788 short_form = true;
789 encoded_disp >>= 2;
790 }
791 break;
792 } else {
793 if (displacement <= 1020) {
794 load = NewLIR4(kThumb2LdrdI8, r_dest, r_dest_hi, rBase, displacement >> 2);
795 } else {
796 load = LoadBaseDispBody(rBase, displacement, r_dest,
797 -1, kWord, s_reg);
798 LoadBaseDispBody(rBase, displacement + 4, r_dest_hi,
799 -1, kWord, INVALID_SREG);
800 }
801 already_generated = true;
802 }
803 case kSingle:
804 case kWord:
805 if (ARM_FPREG(r_dest)) {
806 opcode = kThumb2Vldrs;
807 if (displacement <= 1020) {
808 short_form = true;
809 encoded_disp >>= 2;
810 }
811 break;
812 }
813 if (ARM_LOWREG(r_dest) && (rBase == r15pc) &&
814 (displacement <= 1020) && (displacement >= 0)) {
815 short_form = true;
816 encoded_disp >>= 2;
817 opcode = kThumbLdrPcRel;
818 } else if (ARM_LOWREG(r_dest) && (rBase == r13sp) &&
819 (displacement <= 1020) && (displacement >= 0)) {
820 short_form = true;
821 encoded_disp >>= 2;
822 opcode = kThumbLdrSpRel;
823 } else if (all_low_regs && displacement < 128 && displacement >= 0) {
824 DCHECK_EQ((displacement & 0x3), 0);
825 short_form = true;
826 encoded_disp >>= 2;
827 opcode = kThumbLdrRRI5;
828 } else if (thumb2Form) {
829 short_form = true;
830 opcode = kThumb2LdrRRI12;
831 }
832 break;
833 case kUnsignedHalf:
834 if (all_low_regs && displacement < 64 && displacement >= 0) {
835 DCHECK_EQ((displacement & 0x1), 0);
836 short_form = true;
837 encoded_disp >>= 1;
838 opcode = kThumbLdrhRRI5;
839 } else if (displacement < 4092 && displacement >= 0) {
840 short_form = true;
841 opcode = kThumb2LdrhRRI12;
842 }
843 break;
844 case kSignedHalf:
845 if (thumb2Form) {
846 short_form = true;
847 opcode = kThumb2LdrshRRI12;
848 }
849 break;
850 case kUnsignedByte:
851 if (all_low_regs && displacement < 32 && displacement >= 0) {
852 short_form = true;
853 opcode = kThumbLdrbRRI5;
854 } else if (thumb2Form) {
855 short_form = true;
856 opcode = kThumb2LdrbRRI12;
857 }
858 break;
859 case kSignedByte:
860 if (thumb2Form) {
861 short_form = true;
862 opcode = kThumb2LdrsbRRI12;
863 }
864 break;
865 default:
866 LOG(FATAL) << "Bad size: " << size;
867 }
868
869 if (!already_generated) {
870 if (short_form) {
871 load = NewLIR3(opcode, r_dest, rBase, encoded_disp);
872 } else {
873 int reg_offset = AllocTemp();
874 LoadConstant(reg_offset, encoded_disp);
875 load = LoadBaseIndexed(rBase, reg_offset, r_dest, 0, size);
876 FreeTemp(reg_offset);
877 }
878 }
879
880 // TODO: in future may need to differentiate Dalvik accesses w/ spills
881 if (rBase == rARM_SP) {
882 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, is64bit);
883 }
884 return load;
885}
886
887LIR* ArmMir2Lir::LoadBaseDisp(int rBase, int displacement, int r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700888 OpSize size, int s_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700889 return LoadBaseDispBody(rBase, displacement, r_dest, -1, size, s_reg);
890}
891
892LIR* ArmMir2Lir::LoadBaseDispWide(int rBase, int displacement, int r_dest_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700893 int r_dest_hi, int s_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700894 return LoadBaseDispBody(rBase, displacement, r_dest_lo, r_dest_hi, kLong, s_reg);
895}
896
897
898LIR* ArmMir2Lir::StoreBaseDispBody(int rBase, int displacement,
899 int r_src, int r_src_hi, OpSize size) {
900 LIR* store = NULL;
901 ArmOpcode opcode = kThumbBkpt;
902 bool short_form = false;
903 bool thumb2Form = (displacement < 4092 && displacement >= 0);
904 bool all_low_regs = (ARM_LOWREG(rBase) && ARM_LOWREG(r_src));
905 int encoded_disp = displacement;
906 bool is64bit = false;
907 bool already_generated = false;
908 switch (size) {
909 case kLong:
910 case kDouble:
911 is64bit = true;
912 if (!ARM_FPREG(r_src)) {
913 if (displacement <= 1020) {
914 store = NewLIR4(kThumb2StrdI8, r_src, r_src_hi, rBase, displacement >> 2);
915 } else {
916 store = StoreBaseDispBody(rBase, displacement, r_src, -1, kWord);
917 StoreBaseDispBody(rBase, displacement + 4, r_src_hi, -1, kWord);
918 }
919 already_generated = true;
920 } else {
921 if (ARM_SINGLEREG(r_src)) {
922 DCHECK(ARM_FPREG(r_src_hi));
923 r_src = S2d(r_src, r_src_hi);
924 }
925 opcode = kThumb2Vstrd;
926 if (displacement <= 1020) {
927 short_form = true;
928 encoded_disp >>= 2;
929 }
930 }
931 break;
932 case kSingle:
933 case kWord:
934 if (ARM_FPREG(r_src)) {
935 DCHECK(ARM_SINGLEREG(r_src));
936 opcode = kThumb2Vstrs;
937 if (displacement <= 1020) {
938 short_form = true;
939 encoded_disp >>= 2;
940 }
941 break;
942 }
943 if (ARM_LOWREG(r_src) && (rBase == r13sp) &&
944 (displacement <= 1020) && (displacement >= 0)) {
945 short_form = true;
946 encoded_disp >>= 2;
947 opcode = kThumbStrSpRel;
948 } else if (all_low_regs && displacement < 128 && displacement >= 0) {
949 DCHECK_EQ((displacement & 0x3), 0);
950 short_form = true;
951 encoded_disp >>= 2;
952 opcode = kThumbStrRRI5;
953 } else if (thumb2Form) {
954 short_form = true;
955 opcode = kThumb2StrRRI12;
956 }
957 break;
958 case kUnsignedHalf:
959 case kSignedHalf:
960 if (all_low_regs && displacement < 64 && displacement >= 0) {
961 DCHECK_EQ((displacement & 0x1), 0);
962 short_form = true;
963 encoded_disp >>= 1;
964 opcode = kThumbStrhRRI5;
965 } else if (thumb2Form) {
966 short_form = true;
967 opcode = kThumb2StrhRRI12;
968 }
969 break;
970 case kUnsignedByte:
971 case kSignedByte:
972 if (all_low_regs && displacement < 32 && displacement >= 0) {
973 short_form = true;
974 opcode = kThumbStrbRRI5;
975 } else if (thumb2Form) {
976 short_form = true;
977 opcode = kThumb2StrbRRI12;
978 }
979 break;
980 default:
981 LOG(FATAL) << "Bad size: " << size;
982 }
983 if (!already_generated) {
984 if (short_form) {
985 store = NewLIR3(opcode, r_src, rBase, encoded_disp);
986 } else {
987 int r_scratch = AllocTemp();
988 LoadConstant(r_scratch, encoded_disp);
989 store = StoreBaseIndexed(rBase, r_scratch, r_src, 0, size);
990 FreeTemp(r_scratch);
991 }
992 }
993
994 // TODO: In future, may need to differentiate Dalvik & spill accesses
995 if (rBase == rARM_SP) {
996 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, is64bit);
997 }
998 return store;
999}
1000
1001LIR* ArmMir2Lir::StoreBaseDisp(int rBase, int displacement, int r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001002 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001003 return StoreBaseDispBody(rBase, displacement, r_src, -1, size);
1004}
1005
1006LIR* ArmMir2Lir::StoreBaseDispWide(int rBase, int displacement,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001007 int r_src_lo, int r_src_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001008 return StoreBaseDispBody(rBase, displacement, r_src_lo, r_src_hi, kLong);
1009}
1010
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001011LIR* ArmMir2Lir::OpFpRegCopy(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001012 int opcode;
1013 DCHECK_EQ(ARM_DOUBLEREG(r_dest), ARM_DOUBLEREG(r_src));
1014 if (ARM_DOUBLEREG(r_dest)) {
1015 opcode = kThumb2Vmovd;
1016 } else {
1017 if (ARM_SINGLEREG(r_dest)) {
1018 opcode = ARM_SINGLEREG(r_src) ? kThumb2Vmovs : kThumb2Fmsr;
1019 } else {
1020 DCHECK(ARM_SINGLEREG(r_src));
1021 opcode = kThumb2Fmrs;
1022 }
1023 }
1024 LIR* res = RawLIR(current_dalvik_offset_, opcode, r_dest, r_src);
1025 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
1026 res->flags.is_nop = true;
1027 }
1028 return res;
1029}
1030
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001031LIR* ArmMir2Lir::OpThreadMem(OpKind op, int thread_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001032 LOG(FATAL) << "Unexpected use of OpThreadMem for Arm";
1033 return NULL;
1034}
1035
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001036LIR* ArmMir2Lir::OpMem(OpKind op, int rBase, int disp) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001037 LOG(FATAL) << "Unexpected use of OpMem for Arm";
1038 return NULL;
1039}
1040
1041LIR* ArmMir2Lir::StoreBaseIndexedDisp(int rBase, int r_index, int scale,
1042 int displacement, int r_src, int r_src_hi, OpSize size,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001043 int s_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001044 LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for Arm";
1045 return NULL;
1046}
1047
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001048LIR* ArmMir2Lir::OpRegMem(OpKind op, int r_dest, int rBase, int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001049 LOG(FATAL) << "Unexpected use of OpRegMem for Arm";
1050 return NULL;
1051}
1052
1053LIR* ArmMir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale,
1054 int displacement, int r_dest, int r_dest_hi, OpSize size,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001055 int s_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001056 LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for Arm";
1057 return NULL;
1058}
1059
1060} // namespace art