blob: 9b32a4681b0f6455aaef241d8e8bfb7c97dc26df [file] [log] [blame]
Matteo Franchin43ec8732014-03-31 15:00:14 +01001/*
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 "arm64_lir.h"
18#include "codegen_arm64.h"
19#include "dex/quick/mir_to_lir-inl.h"
20
21namespace art {
22
Matteo Franchine45fb9e2014-05-06 10:10:30 +010023/* This file contains codegen for the A64 ISA. */
Matteo Franchin43ec8732014-03-31 15:00:14 +010024
Matteo Franchine45fb9e2014-05-06 10:10:30 +010025static int32_t EncodeImmSingle(uint32_t bits) {
26 /*
27 * Valid values will have the form:
28 *
29 * aBbb.bbbc.defg.h000.0000.0000.0000.0000
30 *
31 * where B = not(b). In other words, if b == 1, then B == 0 and viceversa.
32 */
33
34 // bits[19..0] are cleared.
35 if ((bits & 0x0007ffff) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010036 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010037
38 // bits[29..25] are all set or all cleared.
39 uint32_t b_pattern = (bits >> 16) & 0x3e00;
40 if (b_pattern != 0 && b_pattern != 0x3e00)
41 return -1;
42
43 // bit[30] and bit[29] are opposite.
44 if (((bits ^ (bits << 1)) & 0x40000000) == 0)
45 return -1;
46
47 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
48 // bit7: a000.0000
49 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
50 // bit6: 0b00.0000
51 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
52 // bit5_to_0: 00cd.efgh
53 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
54 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010055}
56
Matteo Franchine45fb9e2014-05-06 10:10:30 +010057static int32_t EncodeImmDouble(uint64_t bits) {
58 /*
59 * Valid values will have the form:
60 *
61 * aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
62 * 0000.0000.0000.0000.0000.0000.0000.0000
63 *
64 * where B = not(b).
65 */
66
67 // bits[47..0] are cleared.
68 if ((bits & UINT64_C(0xffffffffffff)) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010069 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010070
71 // bits[61..54] are all set or all cleared.
72 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
73 if (b_pattern != 0 && b_pattern != 0x3fc0)
74 return -1;
75
76 // bit[62] and bit[61] are opposite.
77 if (((bits ^ (bits << 1)) & UINT64_C(0x4000000000000000)) == 0)
78 return -1;
79
80 // bit7: a000.0000
81 uint32_t bit7 = ((bits >> 63) & 0x1) << 7;
82 // bit6: 0b00.0000
83 uint32_t bit6 = ((bits >> 61) & 0x1) << 6;
84 // bit5_to_0: 00cd.efgh
85 uint32_t bit5_to_0 = (bits >> 48) & 0x3f;
86 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010087}
88
Matteo Franchinc41e6dc2014-06-13 19:16:28 +010089LIR* Arm64Mir2Lir::LoadFPConstantValue(RegStorage r_dest, int32_t value) {
90 DCHECK(r_dest.IsSingle());
Matteo Franchin43ec8732014-03-31 15:00:14 +010091 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +010092 return NewLIR2(kA64Fmov2sw, r_dest.GetReg(), rwzr);
Matteo Franchin43ec8732014-03-31 15:00:14 +010093 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010094 int32_t encoded_imm = EncodeImmSingle((uint32_t)value);
Matteo Franchin43ec8732014-03-31 15:00:14 +010095 if (encoded_imm >= 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +010096 return NewLIR2(kA64Fmov2fI, r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +010097 }
98 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +010099
Matteo Franchin43ec8732014-03-31 15:00:14 +0100100 LIR* data_target = ScanLiteralPool(literal_list_, value, 0);
101 if (data_target == NULL) {
102 data_target = AddWordData(&literal_list_, value);
103 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100104
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100105 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100106 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kA64Ldr2fp,
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100107 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100108 AppendLIR(load_pc_rel);
109 return load_pc_rel;
110}
111
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100112LIR* Arm64Mir2Lir::LoadFPConstantValueWide(RegStorage r_dest, int64_t value) {
113 DCHECK(r_dest.IsDouble());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100114 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100115 return NewLIR2(kA64Fmov2Sx, r_dest.GetReg(), rxzr);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100116 } else {
117 int32_t encoded_imm = EncodeImmDouble(value);
118 if (encoded_imm >= 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100119 return NewLIR2(FWIDE(kA64Fmov2fI), r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100120 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100121 }
122
123 // No short form - load from the literal pool.
124 int32_t val_lo = Low32Bits(value);
125 int32_t val_hi = High32Bits(value);
126 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
127 if (data_target == NULL) {
128 data_target = AddWideData(&literal_list_, val_lo, val_hi);
129 }
130
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100131 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100132 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, FWIDE(kA64Ldr2fp),
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100133 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100134 AppendLIR(load_pc_rel);
135 return load_pc_rel;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100136}
137
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100138static int CountLeadingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100139 return (is_wide) ? __builtin_clzll(value) : __builtin_clz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100140}
Matteo Franchin43ec8732014-03-31 15:00:14 +0100141
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100142static int CountTrailingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100143 return (is_wide) ? __builtin_ctzll(value) : __builtin_ctz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100144}
145
146static int CountSetBits(bool is_wide, uint64_t value) {
147 return ((is_wide) ?
Zheng Xue2eb29e2014-06-12 10:22:33 +0800148 __builtin_popcountll(value) : __builtin_popcount((uint32_t)value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100149}
150
151/**
152 * @brief Try encoding an immediate in the form required by logical instructions.
153 *
154 * @param is_wide Whether @p value is a 64-bit (as opposed to 32-bit) value.
155 * @param value An integer to be encoded. This is interpreted as 64-bit if @p is_wide is true and as
156 * 32-bit if @p is_wide is false.
157 * @return A non-negative integer containing the encoded immediate or -1 if the encoding failed.
158 * @note This is the inverse of Arm64Mir2Lir::DecodeLogicalImmediate().
159 */
160int Arm64Mir2Lir::EncodeLogicalImmediate(bool is_wide, uint64_t value) {
161 unsigned n, imm_s, imm_r;
162
163 // Logical immediates are encoded using parameters n, imm_s and imm_r using
164 // the following table:
165 //
166 // N imms immr size S R
167 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
168 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
169 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
170 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
171 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
172 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
173 // (s bits must not be all set)
174 //
175 // A pattern is constructed of size bits, where the least significant S+1
176 // bits are set. The pattern is rotated right by R, and repeated across a
177 // 32 or 64-bit value, depending on destination register width.
178 //
179 // To test if an arbitary immediate can be encoded using this scheme, an
180 // iterative algorithm is used.
181 //
182
183 // 1. If the value has all set or all clear bits, it can't be encoded.
184 if (value == 0 || value == ~UINT64_C(0) ||
185 (!is_wide && (uint32_t)value == ~UINT32_C(0))) {
186 return -1;
187 }
188
189 unsigned lead_zero = CountLeadingZeros(is_wide, value);
190 unsigned lead_one = CountLeadingZeros(is_wide, ~value);
191 unsigned trail_zero = CountTrailingZeros(is_wide, value);
192 unsigned trail_one = CountTrailingZeros(is_wide, ~value);
193 unsigned set_bits = CountSetBits(is_wide, value);
194
195 // The fixed bits in the immediate s field.
196 // If width == 64 (X reg), start at 0xFFFFFF80.
197 // If width == 32 (W reg), start at 0xFFFFFFC0, as the iteration for 64-bit
198 // widths won't be executed.
199 unsigned width = (is_wide) ? 64 : 32;
200 int imm_s_fixed = (is_wide) ? -128 : -64;
201 int imm_s_mask = 0x3f;
202
203 for (;;) {
204 // 2. If the value is two bits wide, it can be encoded.
205 if (width == 2) {
206 n = 0;
207 imm_s = 0x3C;
208 imm_r = (value & 3) - 1;
209 break;
210 }
211
212 n = (width == 64) ? 1 : 0;
213 imm_s = ((imm_s_fixed | (set_bits - 1)) & imm_s_mask);
214 if ((lead_zero + set_bits) == width) {
215 imm_r = 0;
216 } else {
217 imm_r = (lead_zero > 0) ? (width - trail_zero) : lead_one;
218 }
219
220 // 3. If the sum of leading zeros, trailing zeros and set bits is
221 // equal to the bit width of the value, it can be encoded.
222 if (lead_zero + trail_zero + set_bits == width) {
223 break;
224 }
225
226 // 4. If the sum of leading ones, trailing ones and unset bits in the
227 // value is equal to the bit width of the value, it can be encoded.
228 if (lead_one + trail_one + (width - set_bits) == width) {
229 break;
230 }
231
232 // 5. If the most-significant half of the bitwise value is equal to
233 // the least-significant half, return to step 2 using the
234 // least-significant half of the value.
235 uint64_t mask = (UINT64_C(1) << (width >> 1)) - 1;
236 if ((value & mask) == ((value >> (width >> 1)) & mask)) {
237 width >>= 1;
238 set_bits >>= 1;
239 imm_s_fixed >>= 1;
240 continue;
241 }
242
243 // 6. Otherwise, the value can't be encoded.
244 return -1;
245 }
246
247 return (n << 12 | imm_r << 6 | imm_s);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100248}
249
250bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100251 return false; // (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100252}
253
254bool Arm64Mir2Lir::InexpensiveConstantFloat(int32_t value) {
255 return EncodeImmSingle(value) >= 0;
256}
257
258bool Arm64Mir2Lir::InexpensiveConstantLong(int64_t value) {
259 return InexpensiveConstantInt(High32Bits(value)) && InexpensiveConstantInt(Low32Bits(value));
260}
261
262bool Arm64Mir2Lir::InexpensiveConstantDouble(int64_t value) {
263 return EncodeImmDouble(value) >= 0;
264}
265
266/*
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100267 * Load a immediate using one single instruction when possible; otherwise
268 * use a pair of movz and movk instructions.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100269 *
270 * No additional register clobbering operation performed. Use this version when
271 * 1) r_dest is freshly returned from AllocTemp or
272 * 2) The codegen is under fixed register usage
273 */
274LIR* Arm64Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
275 LIR* res;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100276
277 if (r_dest.IsFloat()) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100278 return LoadFPConstantValue(r_dest, value);
279 }
280
281 if (r_dest.Is64Bit()) {
282 return LoadConstantWide(r_dest, value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100283 }
284
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100285 // Loading SP/ZR with an immediate is not supported.
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100286 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
287 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100288
289 // Compute how many movk, movz instructions are needed to load the value.
290 uint16_t high_bits = High16Bits(value);
291 uint16_t low_bits = Low16Bits(value);
292
293 bool low_fast = ((uint16_t)(low_bits + 1) <= 1);
294 bool high_fast = ((uint16_t)(high_bits + 1) <= 1);
295
296 if (LIKELY(low_fast || high_fast)) {
297 // 1 instruction is enough to load the immediate.
298 if (LIKELY(low_bits == high_bits)) {
299 // Value is either 0 or -1: we can just use wzr.
300 ArmOpcode opcode = LIKELY(low_bits == 0) ? kA64Mov2rr : kA64Mvn2rr;
301 res = NewLIR2(opcode, r_dest.GetReg(), rwzr);
302 } else {
303 uint16_t uniform_bits, useful_bits;
304 int shift;
305
306 if (LIKELY(high_fast)) {
307 shift = 0;
308 uniform_bits = high_bits;
309 useful_bits = low_bits;
310 } else {
311 shift = 1;
312 uniform_bits = low_bits;
313 useful_bits = high_bits;
314 }
315
316 if (UNLIKELY(uniform_bits != 0)) {
317 res = NewLIR3(kA64Movn3rdM, r_dest.GetReg(), ~useful_bits, shift);
318 } else {
319 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), useful_bits, shift);
320 }
321 }
322 } else {
323 // movk, movz require 2 instructions. Try detecting logical immediates.
324 int log_imm = EncodeLogicalImmediate(/*is_wide=*/false, value);
325 if (log_imm >= 0) {
326 res = NewLIR3(kA64Orr3Rrl, r_dest.GetReg(), rwzr, log_imm);
327 } else {
328 // Use 2 instructions.
329 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), low_bits, 0);
330 NewLIR3(kA64Movk3rdM, r_dest.GetReg(), high_bits, 1);
331 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100332 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100333
Matteo Franchin43ec8732014-03-31 15:00:14 +0100334 return res;
335}
336
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100337// TODO: clean up the names. LoadConstantWide() should really be LoadConstantNoClobberWide().
338LIR* Arm64Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
339 // Maximum number of instructions to use for encoding the immediate.
340 const int max_num_ops = 2;
341
342 if (r_dest.IsFloat()) {
343 return LoadFPConstantValueWide(r_dest, value);
344 }
345
346 DCHECK(r_dest.Is64Bit());
347
348 // Loading SP/ZR with an immediate is not supported.
349 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
350 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
351
352 if (LIKELY(value == INT64_C(0) || value == INT64_C(-1))) {
353 // value is either 0 or -1: we can just use xzr.
354 ArmOpcode opcode = LIKELY(value == 0) ? WIDE(kA64Mov2rr) : WIDE(kA64Mvn2rr);
355 return NewLIR2(opcode, r_dest.GetReg(), rxzr);
356 }
357
358 // At least one in value's halfwords is not 0x0, nor 0xffff: find out how many.
359 int num_0000_halfwords = 0;
360 int num_ffff_halfwords = 0;
361 uint64_t uvalue = static_cast<uint64_t>(value);
362 for (int shift = 0; shift < 64; shift += 16) {
363 uint16_t halfword = static_cast<uint16_t>(uvalue >> shift);
364 if (halfword == 0)
365 num_0000_halfwords++;
366 else if (halfword == UINT16_C(0xffff))
367 num_ffff_halfwords++;
368 }
369 int num_fast_halfwords = std::max(num_0000_halfwords, num_ffff_halfwords);
370
371 if (num_fast_halfwords < 3) {
372 // A single movz/movn is not enough. Try the logical immediate route.
373 int log_imm = EncodeLogicalImmediate(/*is_wide=*/true, value);
374 if (log_imm >= 0) {
375 return NewLIR3(WIDE(kA64Orr3Rrl), r_dest.GetReg(), rxzr, log_imm);
376 }
377 }
378
379 if (num_fast_halfwords >= 4 - max_num_ops) {
380 // We can encode the number using a movz/movn followed by one or more movk.
381 ArmOpcode op;
382 uint16_t background;
383 LIR* res = nullptr;
384
385 // Decide whether to use a movz or a movn.
386 if (num_0000_halfwords >= num_ffff_halfwords) {
387 op = WIDE(kA64Movz3rdM);
388 background = 0;
389 } else {
390 op = WIDE(kA64Movn3rdM);
391 background = 0xffff;
392 }
393
394 // Emit the first instruction (movz, movn).
395 int shift;
396 for (shift = 0; shift < 4; shift++) {
397 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
398 if (halfword != background) {
399 res = NewLIR3(op, r_dest.GetReg(), halfword ^ background, shift);
400 break;
401 }
402 }
403
404 // Emit the movk instructions.
405 for (shift++; shift < 4; shift++) {
406 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
407 if (halfword != background) {
408 NewLIR3(WIDE(kA64Movk3rdM), r_dest.GetReg(), halfword, shift);
409 }
410 }
411 return res;
412 }
413
414 // Use the literal pool.
415 int32_t val_lo = Low32Bits(value);
416 int32_t val_hi = High32Bits(value);
417 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
418 if (data_target == NULL) {
419 data_target = AddWideData(&literal_list_, val_lo, val_hi);
420 }
421
422 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
423 LIR *res = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp),
424 r_dest.GetReg(), 0, 0, 0, 0, data_target);
425 AppendLIR(res);
426 return res;
427}
428
Matteo Franchin43ec8732014-03-31 15:00:14 +0100429LIR* Arm64Mir2Lir::OpUnconditionalBranch(LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100430 LIR* res = NewLIR1(kA64B1t, 0 /* offset to be patched during assembly */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100431 res->target = target;
432 return res;
433}
434
435LIR* Arm64Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100436 LIR* branch = NewLIR2(kA64B2ct, ArmConditionEncoding(cc),
437 0 /* offset to be patched */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100438 branch->target = target;
439 return branch;
440}
441
442LIR* Arm64Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100443 ArmOpcode opcode = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100444 switch (op) {
445 case kOpBlx:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100446 opcode = kA64Blr1x;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100447 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100448 // TODO(Arm64): port kThumbBx.
449 // case kOpBx:
450 // opcode = kThumbBx;
451 // break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100452 default:
453 LOG(FATAL) << "Bad opcode " << op;
454 }
455 return NewLIR1(opcode, r_dest_src.GetReg());
456}
457
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100458LIR* Arm64Mir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift) {
459 ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
460 CHECK_EQ(r_dest_src1.Is64Bit(), r_src2.Is64Bit());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100461 ArmOpcode opcode = kA64Brk1d;
462
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100463 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100464 case kOpCmn:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100465 opcode = kA64Cmn3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100466 break;
467 case kOpCmp:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100468 opcode = kA64Cmp3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100469 break;
470 case kOpMov:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100471 opcode = kA64Mov2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100472 break;
473 case kOpMvn:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100474 opcode = kA64Mvn2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100475 break;
476 case kOpNeg:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100477 opcode = kA64Neg3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100478 break;
479 case kOpTst:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100480 opcode = kA64Tst3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100481 break;
482 case kOpRev:
483 DCHECK_EQ(shift, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100484 // Binary, but rm is encoded twice.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100485 return NewLIR2(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100486 break;
487 case kOpRevsh:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100488 // Binary, but rm is encoded twice.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100489 return NewLIR2(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100490 break;
491 case kOp2Byte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100492 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
493 // "sbfx r1, r2, #imm1, #imm2" is "sbfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
494 // For now we use sbfm directly.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100495 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 7);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100496 case kOp2Short:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100497 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
498 // For now we use sbfm rather than its alias, sbfx.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100499 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100500 case kOp2Char:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100501 // "ubfx r1, r2, #imm1, #imm2" is "ubfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
502 // For now we use ubfm directly.
503 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100504 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100505 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100506 return OpRegRegRegShift(op, r_dest_src1, r_dest_src1, r_src2, shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100507 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100508
Matteo Franchin43ec8732014-03-31 15:00:14 +0100509 DCHECK(!IsPseudoLirOp(opcode));
510 if (EncodingMap[opcode].flags & IS_BINARY_OP) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100511 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100512 return NewLIR2(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100513 } else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100514 ArmEncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100515 if (kind == kFmtShift) {
516 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100517 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100518 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100519
520 LOG(FATAL) << "Unexpected encoding operand count";
521 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100522}
523
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100524LIR* Arm64Mir2Lir::OpRegRegExtend(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int extend) {
525 ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
526 ArmOpcode opcode = kA64Brk1d;
527
528 switch (op) {
529 case kOpCmn:
530 opcode = kA64Cmn3Rre;
531 break;
532 case kOpCmp:
533 opcode = kA64Cmp3Rre;
534 break;
535 default:
536 LOG(FATAL) << "Bad Opcode: " << opcode;
537 break;
538 }
539
540 DCHECK(!IsPseudoLirOp(opcode));
541 if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
542 ArmEncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
543 if (kind == kFmtExtend) {
544 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), extend);
545 }
546 }
547
548 LOG(FATAL) << "Unexpected encoding operand count";
549 return NULL;
550}
551
Matteo Franchin43ec8732014-03-31 15:00:14 +0100552LIR* Arm64Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100553 /* RegReg operations with SP in first parameter need extended register instruction form.
554 * Only CMN and CMP instructions are implemented.
555 */
556 if (r_dest_src1 == rs_rA64_SP) {
557 return OpRegRegExtend(op, r_dest_src1, r_src2, ENCODE_NO_EXTEND);
558 } else {
559 return OpRegRegShift(op, r_dest_src1, r_src2, ENCODE_NO_SHIFT);
560 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100561}
562
563LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) {
564 UNIMPLEMENTED(FATAL);
565 return nullptr;
566}
567
568LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
569 UNIMPLEMENTED(FATAL);
570 return nullptr;
571}
572
573LIR* Arm64Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100574 LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100575 return NULL;
576}
577
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100578LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
579 RegStorage r_src2, int shift) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100580 ArmOpcode opcode = kA64Brk1d;
581
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100582 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100583 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100584 opcode = kA64Add4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100585 break;
586 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100587 opcode = kA64Sub4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100588 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100589 // case kOpRsub:
590 // opcode = kA64RsubWWW;
591 // break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100592 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100593 opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100594 break;
595 case kOpAnd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100596 opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100597 break;
598 case kOpXor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100599 opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100600 break;
601 case kOpMul:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100602 opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100603 break;
604 case kOpDiv:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100605 opcode = kA64Sdiv3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100606 break;
607 case kOpOr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100608 opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100609 break;
610 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100611 opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100612 break;
613 case kOpLsl:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100614 opcode = kA64Lsl3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100615 break;
616 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100617 opcode = kA64Lsr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100618 break;
619 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100620 opcode = kA64Asr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100621 break;
622 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100623 opcode = kA64Ror3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100624 break;
625 default:
626 LOG(FATAL) << "Bad opcode: " << op;
627 break;
628 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100629
630 // The instructions above belong to two kinds:
631 // - 4-operands instructions, where the last operand is a shift/extend immediate,
632 // - 3-operands instructions with no shift/extend.
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100633 ArmOpcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
634 CHECK_EQ(r_dest.Is64Bit(), r_src1.Is64Bit());
635 CHECK_EQ(r_dest.Is64Bit(), r_src2.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100636 if (EncodingMap[opcode].flags & IS_QUAD_OP) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100637 DCHECK(!IsExtendEncoding(shift));
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100638 return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100639 } else {
640 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100641 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100642 return NewLIR3(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100643 }
644}
645
646LIR* Arm64Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100647 return OpRegRegRegShift(op, r_dest, r_src1, r_src2, ENCODE_NO_SHIFT);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100648}
649
650LIR* Arm64Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800651 return OpRegRegImm64(op, r_dest, r_src1, static_cast<int64_t>(value));
652}
653
654LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100655 LIR* res;
656 bool neg = (value < 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100657 int64_t abs_value = (neg) ? -value : value;
658 ArmOpcode opcode = kA64Brk1d;
659 ArmOpcode alt_opcode = kA64Brk1d;
660 int32_t log_imm = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100661 bool is_wide = r_dest.Is64Bit();
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100662 ArmOpcode wide = (is_wide) ? WIDE(0) : UNWIDE(0);
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700663 int info = 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100664
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100665 switch (op) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100666 case kOpLsl: {
667 // "lsl w1, w2, #imm" is an alias of "ubfm w1, w2, #(-imm MOD 32), #(31-imm)"
Zheng Xu2d41a652014-06-09 11:05:31 +0800668 // and "lsl x1, x2, #imm" of "ubfm x1, x2, #(-imm MOD 64), #(63-imm)".
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100669 // For now, we just use ubfm directly.
Zheng Xu2d41a652014-06-09 11:05:31 +0800670 int max_value = (is_wide) ? 63 : 31;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100671 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest.GetReg(), r_src1.GetReg(),
Zheng Xu2d41a652014-06-09 11:05:31 +0800672 (-value) & max_value, max_value - value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100673 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100674 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100675 return NewLIR3(kA64Lsr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100676 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100677 return NewLIR3(kA64Asr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100678 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100679 // "ror r1, r2, #imm" is an alias of "extr r1, r2, r2, #imm".
680 // For now, we just use extr directly.
681 return NewLIR4(kA64Extr4rrrd | wide, r_dest.GetReg(), r_src1.GetReg(), r_src1.GetReg(),
682 value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100683 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100684 neg = !neg;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100685 // Note: intentional fallthrough
686 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100687 // Add and sub below read/write sp rather than xzr.
688 if (abs_value < 0x1000) {
689 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
690 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value, 0);
691 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
692 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
693 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100694 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100695 log_imm = -1;
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700696 alt_opcode = (neg) ? kA64Add4rrre : kA64Sub4rrre;
697 // To make it correct, we need:
698 // 23..21 = 001 = extend
699 // 15..13 = 01x = LSL/UXTW/X / x defines wide or not
700 // 12..10 = 000 = no shift (in case of SP)
701 // => info = 00101x000
702 // => =0x 0 5 (0/8)
703 info = (is_wide ? 8 : 0) | 0x50;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100704 }
705 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100706 // case kOpRsub:
707 // opcode = kThumb2RsubRRI8M;
708 // alt_opcode = kThumb2RsubRRR;
709 // break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100710 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100711 log_imm = -1;
712 alt_opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100713 break;
714 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100715 log_imm = -1;
716 alt_opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100717 break;
718 case kOpOr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100719 log_imm = EncodeLogicalImmediate(is_wide, value);
720 opcode = kA64Orr3Rrl;
721 alt_opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100722 break;
723 case kOpAnd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100724 log_imm = EncodeLogicalImmediate(is_wide, value);
725 opcode = kA64And3Rrl;
726 alt_opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100727 break;
728 case kOpXor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100729 log_imm = EncodeLogicalImmediate(is_wide, value);
730 opcode = kA64Eor3Rrl;
731 alt_opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100732 break;
733 case kOpMul:
734 // TUNING: power of 2, shift & add
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100735 log_imm = -1;
736 alt_opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100737 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100738 default:
739 LOG(FATAL) << "Bad opcode: " << op;
740 }
741
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100742 if (log_imm >= 0) {
743 return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100744 } else {
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700745 RegStorage r_scratch;
Zheng Xue2eb29e2014-06-12 10:22:33 +0800746 if (IS_WIDE(wide)) {
747 r_scratch = AllocTempWide();
748 LoadConstantWide(r_scratch, value);
749 } else {
750 r_scratch = AllocTemp();
751 LoadConstant(r_scratch, value);
752 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100753 if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700754 res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100755 else
Zheng Xue2eb29e2014-06-12 10:22:33 +0800756 res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100757 FreeTemp(r_scratch);
758 return res;
759 }
760}
761
Matteo Franchin43ec8732014-03-31 15:00:14 +0100762LIR* Arm64Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100763 return OpRegImm64(op, r_dest_src1, static_cast<int64_t>(value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100764}
765
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100766LIR* Arm64Mir2Lir::OpRegImm64(OpKind op, RegStorage r_dest_src1, int64_t value) {
767 ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100768 ArmOpcode opcode = kA64Brk1d;
769 ArmOpcode neg_opcode = kA64Brk1d;
770 bool shift;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100771 bool neg = (value < 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100772 uint64_t abs_value = (neg) ? -value : value;
773
774 if (LIKELY(abs_value < 0x1000)) {
775 // abs_value is a 12-bit immediate.
776 shift = false;
777 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
778 // abs_value is a shifted 12-bit immediate.
779 shift = true;
780 abs_value >>= 12;
Zheng Xue2eb29e2014-06-12 10:22:33 +0800781 } else if (LIKELY(abs_value < 0x1000000 && (op == kOpAdd || op == kOpSub))) {
782 // Note: It is better to use two ADD/SUB instead of loading a number to a temp register.
783 // This works for both normal registers and SP.
784 // For a frame size == 0x2468, it will be encoded as:
785 // sub sp, #0x2000
786 // sub sp, #0x468
787 if (neg) {
788 op = (op == kOpAdd) ? kOpSub : kOpAdd;
789 }
790 OpRegImm64(op, r_dest_src1, abs_value & (~INT64_C(0xfff)));
791 return OpRegImm64(op, r_dest_src1, abs_value & 0xfff);
792 } else if (LIKELY(A64_REG_IS_SP(r_dest_src1.GetReg()) && (op == kOpAdd || op == kOpSub))) {
793 // Note: "sub sp, sp, Xm" is not correct on arm64.
794 // We need special instructions for SP.
795 // Also operation on 32-bit SP should be avoided.
796 DCHECK(IS_WIDE(wide));
797 RegStorage r_tmp = AllocTempWide();
798 OpRegRegImm(kOpAdd, r_tmp, r_dest_src1, 0);
799 OpRegImm64(op, r_tmp, value);
800 return OpRegRegImm(kOpAdd, r_dest_src1, r_tmp, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100801 } else {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800802 RegStorage r_tmp;
803 LIR* res;
804 if (IS_WIDE(wide)) {
805 r_tmp = AllocTempWide();
806 res = LoadConstantWide(r_tmp, value);
807 } else {
808 r_tmp = AllocTemp();
809 res = LoadConstant(r_tmp, value);
810 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100811 OpRegReg(op, r_dest_src1, r_tmp);
812 FreeTemp(r_tmp);
813 return res;
814 }
815
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100816 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100817 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100818 neg_opcode = kA64Sub4RRdT;
819 opcode = kA64Add4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100820 break;
821 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100822 neg_opcode = kA64Add4RRdT;
823 opcode = kA64Sub4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100824 break;
825 case kOpCmp:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100826 neg_opcode = kA64Cmn3RdT;
827 opcode = kA64Cmp3RdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100828 break;
829 default:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100830 LOG(FATAL) << "Bad op-kind in OpRegImm: " << op;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100831 break;
832 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100833
834 if (UNLIKELY(neg))
835 opcode = neg_opcode;
836
837 if (EncodingMap[opcode].flags & IS_QUAD_OP)
838 return NewLIR4(opcode | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), abs_value,
839 (shift) ? 1 : 0);
840 else
841 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), abs_value, (shift) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100842}
843
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100844int Arm64Mir2Lir::EncodeShift(int shift_type, int amount) {
845 return ((shift_type & 0x3) << 7) | (amount & 0x1f);
846}
847
848int Arm64Mir2Lir::EncodeExtend(int extend_type, int amount) {
849 return (1 << 6) | ((extend_type & 0x7) << 3) | (amount & 0x7);
850}
851
852bool Arm64Mir2Lir::IsExtendEncoding(int encoded_value) {
853 return ((1 << 6) & encoded_value) != 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100854}
855
856LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100857 int scale, OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100858 LIR* load;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100859 int expected_scale = 0;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100860 ArmOpcode opcode = kA64Brk1d;
buzbee33ae5582014-06-12 14:56:32 -0700861 DCHECK(r_base.Is64Bit());
862 // TODO: need a cleaner handling of index registers here and throughout.
863 if (r_index.Is32Bit()) {
864 r_index = As64BitReg(r_index);
865 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100866
867 if (r_dest.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100868 if (r_dest.IsDouble()) {
869 DCHECK(size == k64 || size == kDouble);
870 expected_scale = 3;
871 opcode = FWIDE(kA64Ldr4fXxG);
872 } else {
873 DCHECK(r_dest.IsSingle());
874 DCHECK(size == k32 || size == kSingle);
875 expected_scale = 2;
876 opcode = kA64Ldr4fXxG;
877 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100878
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100879 DCHECK(scale == 0 || scale == expected_scale);
880 return NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
881 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100882 }
883
884 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100885 case kDouble:
886 case kWord:
887 case k64:
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100888 opcode = WIDE(kA64Ldr4rXxG);
889 expected_scale = 3;
890 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100891 case kSingle:
Matteo Franchin43ec8732014-03-31 15:00:14 +0100892 case k32:
Matteo Franchin43ec8732014-03-31 15:00:14 +0100893 case kReference:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100894 opcode = kA64Ldr4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100895 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100896 break;
897 case kUnsignedHalf:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100898 opcode = kA64Ldrh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100899 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100900 break;
901 case kSignedHalf:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100902 opcode = kA64Ldrsh4rXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100903 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100904 break;
905 case kUnsignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100906 opcode = kA64Ldrb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100907 break;
908 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100909 opcode = kA64Ldrsb3rXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100910 break;
911 default:
912 LOG(FATAL) << "Bad size: " << size;
913 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100914
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100915 if (UNLIKELY(expected_scale == 0)) {
916 // This is a tertiary op (e.g. ldrb, ldrsb), it does not not support scale.
917 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100918 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100919 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100920 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100921 DCHECK(scale == 0 || scale == expected_scale);
922 load = NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100923 (scale != 0) ? 1 : 0);
924 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100925
926 return load;
927}
928
929LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100930 int scale, OpSize size) {
931 LIR* store;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100932 int expected_scale = 0;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100933 ArmOpcode opcode = kA64Brk1d;
buzbee33ae5582014-06-12 14:56:32 -0700934 DCHECK(r_base.Is64Bit());
935 // TODO: need a cleaner handling of index registers here and throughout.
936 if (r_index.Is32Bit()) {
937 r_index = As64BitReg(r_index);
938 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100939
940 if (r_src.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100941 if (r_src.IsDouble()) {
942 DCHECK(size == k64 || size == kDouble);
943 expected_scale = 3;
944 opcode = FWIDE(kA64Str4fXxG);
945 } else {
946 DCHECK(r_src.IsSingle());
947 DCHECK(size == k32 || size == kSingle);
948 expected_scale = 2;
949 opcode = kA64Str4fXxG;
950 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100951
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100952 DCHECK(scale == 0 || scale == expected_scale);
953 return NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
954 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100955 }
956
957 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100958 case kDouble: // Intentional fall-trough.
959 case kWord: // Intentional fall-trough.
960 case k64:
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100961 opcode = WIDE(kA64Str4rXxG);
962 expected_scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100963 break;
964 case kSingle: // Intentional fall-trough.
965 case k32: // Intentional fall-trough.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100966 case kReference:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100967 opcode = kA64Str4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100968 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100969 break;
970 case kUnsignedHalf:
Matteo Franchin43ec8732014-03-31 15:00:14 +0100971 case kSignedHalf:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100972 opcode = kA64Strh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100973 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100974 break;
975 case kUnsignedByte:
Matteo Franchin43ec8732014-03-31 15:00:14 +0100976 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100977 opcode = kA64Strb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100978 break;
979 default:
980 LOG(FATAL) << "Bad size: " << size;
981 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100982
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100983 if (UNLIKELY(expected_scale == 0)) {
984 // This is a tertiary op (e.g. strb), it does not not support scale.
985 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100986 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100987 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100988 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100989 store = NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
990 (scale != 0) ? 1 : 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100991 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100992
993 return store;
994}
995
996/*
997 * Load value from base + displacement. Optionally perform null check
998 * on base (which must have an associated s_reg and MIR). If not
999 * performing null check, incoming MIR can be null.
1000 */
1001LIR* Arm64Mir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001002 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001003 LIR* load = NULL;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001004 ArmOpcode opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001005 ArmOpcode alt_opcode = kA64Brk1d;
1006 int scale = 0;
1007
Matteo Franchin43ec8732014-03-31 15:00:14 +01001008 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001009 case kDouble: // Intentional fall-through.
1010 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001011 case k64:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001012 scale = 3;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001013 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001014 DCHECK(r_dest.IsDouble());
1015 opcode = FWIDE(kA64Ldr3fXD);
1016 alt_opcode = FWIDE(kA64Ldur3fXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001017 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001018 opcode = WIDE(kA64Ldr3rXD);
1019 alt_opcode = WIDE(kA64Ldur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001020 }
1021 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001022 case kSingle: // Intentional fall-through.
1023 case k32: // Intentional fall-trough.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001024 case kReference:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001025 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001026 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001027 DCHECK(r_dest.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001028 opcode = kA64Ldr3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001029 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001030 opcode = kA64Ldr3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001031 }
1032 break;
1033 case kUnsignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001034 scale = 1;
1035 opcode = kA64Ldrh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001036 break;
1037 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001038 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001039 opcode = kA64Ldrsh3rXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001040 break;
1041 case kUnsignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001042 opcode = kA64Ldrb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001043 break;
1044 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001045 opcode = kA64Ldrsb3rXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001046 break;
1047 default:
1048 LOG(FATAL) << "Bad size: " << size;
1049 }
1050
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001051 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1052 int scaled_disp = displacement >> scale;
1053 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1054 // Can use scaled load.
1055 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), scaled_disp);
1056 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1057 // Can use unscaled load.
1058 load = NewLIR3(alt_opcode, r_dest.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001059 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001060 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001061 // TODO: cleaner support for index/displacement registers? Not a reference, but must match width.
1062 RegStorage r_scratch = AllocTempWide();
1063 LoadConstantWide(r_scratch, displacement);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001064 load = LoadBaseIndexed(r_base, r_scratch, r_dest, 0, size);
1065 FreeTemp(r_scratch);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001066 }
1067
1068 // TODO: in future may need to differentiate Dalvik accesses w/ spills
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001069 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
1070 DCHECK(r_base == rs_rA64_SP);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001071 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +01001072 }
1073 return load;
1074}
1075
Vladimir Marko674744e2014-04-24 15:18:26 +01001076LIR* Arm64Mir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
1077 OpSize size) {
1078 // LoadBaseDisp() will emit correct insn for atomic load on arm64
1079 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
1080 return LoadBaseDisp(r_base, displacement, r_dest, size);
1081}
1082
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001083LIR* Arm64Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
1084 OpSize size) {
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001085 return LoadBaseDispBody(r_base, displacement, r_dest, size);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001086}
1087
Matteo Franchin43ec8732014-03-31 15:00:14 +01001088
1089LIR* Arm64Mir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001090 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001091 LIR* store = NULL;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001092 ArmOpcode opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001093 ArmOpcode alt_opcode = kA64Brk1d;
1094 int scale = 0;
1095
Matteo Franchin43ec8732014-03-31 15:00:14 +01001096 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001097 case kDouble: // Intentional fall-through.
1098 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001099 case k64:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001100 scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001101 if (r_src.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001102 DCHECK(r_src.IsDouble());
1103 opcode = FWIDE(kA64Str3fXD);
1104 alt_opcode = FWIDE(kA64Stur3fXd);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001105 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001106 opcode = FWIDE(kA64Str3rXD);
1107 alt_opcode = FWIDE(kA64Stur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001108 }
1109 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001110 case kSingle: // Intentional fall-through.
1111 case k32: // Intentional fall-trough.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001112 case kReference:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001113 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001114 if (r_src.IsFloat()) {
1115 DCHECK(r_src.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001116 opcode = kA64Str3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001117 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001118 opcode = kA64Str3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001119 }
1120 break;
1121 case kUnsignedHalf:
1122 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001123 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001124 opcode = kA64Strh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001125 break;
1126 case kUnsignedByte:
1127 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001128 opcode = kA64Strb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001129 break;
1130 default:
1131 LOG(FATAL) << "Bad size: " << size;
1132 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001133
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001134 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1135 int scaled_disp = displacement >> scale;
1136 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1137 // Can use scaled store.
1138 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), scaled_disp);
1139 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1140 // Can use unscaled store.
1141 store = NewLIR3(alt_opcode, r_src.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001142 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001143 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001144 RegStorage r_scratch = AllocTempWide();
1145 LoadConstantWide(r_scratch, displacement);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001146 store = StoreBaseIndexed(r_base, r_scratch, r_src, 0, size);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001147 FreeTemp(r_scratch);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001148 }
1149
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001150 // TODO: In future, may need to differentiate Dalvik & spill accesses.
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001151 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
1152 DCHECK(r_base == rs_rA64_SP);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001153 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +01001154 }
1155 return store;
1156}
1157
Vladimir Marko674744e2014-04-24 15:18:26 +01001158LIR* Arm64Mir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
1159 OpSize size) {
1160 // StoreBaseDisp() will emit correct insn for atomic store on arm64
1161 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
1162 return StoreBaseDisp(r_base, displacement, r_src, size);
1163}
1164
Matteo Franchin43ec8732014-03-31 15:00:14 +01001165LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
Vladimir Marko674744e2014-04-24 15:18:26 +01001166 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001167 return StoreBaseDispBody(r_base, displacement, r_src, size);
1168}
1169
Matteo Franchin43ec8732014-03-31 15:00:14 +01001170LIR* Arm64Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001171 LOG(FATAL) << "Unexpected use of OpFpRegCopy for Arm64";
1172 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001173}
1174
Andreas Gampe2f244e92014-05-08 03:35:25 -07001175LIR* Arm64Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) {
1176 UNIMPLEMENTED(FATAL) << "Should not be used.";
1177 return nullptr;
1178}
1179
1180LIR* Arm64Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001181 LOG(FATAL) << "Unexpected use of OpThreadMem for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001182 return NULL;
1183}
1184
1185LIR* Arm64Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001186 LOG(FATAL) << "Unexpected use of OpMem for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001187 return NULL;
1188}
1189
1190LIR* Arm64Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001191 int displacement, RegStorage r_src, OpSize size) {
1192 LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001193 return NULL;
1194}
1195
1196LIR* Arm64Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001197 LOG(FATAL) << "Unexpected use of OpRegMem for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001198 return NULL;
1199}
1200
1201LIR* Arm64Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001202 int displacement, RegStorage r_dest, OpSize size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001203 LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001204 return NULL;
1205}
1206
1207} // namespace art