blob: 78a6df8a1cb0f580d6dc76106bcc933747665882 [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"
buzbeeb5860fb2014-06-21 15:31:01 -070020#include "dex/reg_storage_eq.h"
Matteo Franchin43ec8732014-03-31 15:00:14 +010021
22namespace art {
23
Matteo Franchine45fb9e2014-05-06 10:10:30 +010024/* This file contains codegen for the A64 ISA. */
Matteo Franchin43ec8732014-03-31 15:00:14 +010025
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010026int32_t Arm64Mir2Lir::EncodeImmSingle(uint32_t bits) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010027 /*
28 * Valid values will have the form:
29 *
30 * aBbb.bbbc.defg.h000.0000.0000.0000.0000
31 *
32 * where B = not(b). In other words, if b == 1, then B == 0 and viceversa.
33 */
34
35 // bits[19..0] are cleared.
36 if ((bits & 0x0007ffff) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010037 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010038
39 // bits[29..25] are all set or all cleared.
40 uint32_t b_pattern = (bits >> 16) & 0x3e00;
41 if (b_pattern != 0 && b_pattern != 0x3e00)
42 return -1;
43
44 // bit[30] and bit[29] are opposite.
45 if (((bits ^ (bits << 1)) & 0x40000000) == 0)
46 return -1;
47
48 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
49 // bit7: a000.0000
50 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
51 // bit6: 0b00.0000
52 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
53 // bit5_to_0: 00cd.efgh
54 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
55 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010056}
57
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010058int32_t Arm64Mir2Lir::EncodeImmDouble(uint64_t bits) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010059 /*
60 * Valid values will have the form:
61 *
62 * aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
63 * 0000.0000.0000.0000.0000.0000.0000.0000
64 *
65 * where B = not(b).
66 */
67
68 // bits[47..0] are cleared.
69 if ((bits & UINT64_C(0xffffffffffff)) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010070 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010071
72 // bits[61..54] are all set or all cleared.
73 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
74 if (b_pattern != 0 && b_pattern != 0x3fc0)
75 return -1;
76
77 // bit[62] and bit[61] are opposite.
78 if (((bits ^ (bits << 1)) & UINT64_C(0x4000000000000000)) == 0)
79 return -1;
80
81 // bit7: a000.0000
82 uint32_t bit7 = ((bits >> 63) & 0x1) << 7;
83 // bit6: 0b00.0000
84 uint32_t bit6 = ((bits >> 61) & 0x1) << 6;
85 // bit5_to_0: 00cd.efgh
86 uint32_t bit5_to_0 = (bits >> 48) & 0x3f;
87 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010088}
89
Serban Constantinescu63999682014-07-15 17:44:21 +010090size_t Arm64Mir2Lir::GetLoadStoreSize(LIR* lir) {
91 bool opcode_is_wide = IS_WIDE(lir->opcode);
Matteo Franchin4163c532014-07-15 15:20:27 +010092 A64Opcode opcode = UNWIDE(lir->opcode);
Serban Constantinescu63999682014-07-15 17:44:21 +010093 DCHECK(!IsPseudoLirOp(opcode));
Matteo Franchin4163c532014-07-15 15:20:27 +010094 const A64EncodingMap *encoder = &EncodingMap[opcode];
Serban Constantinescu63999682014-07-15 17:44:21 +010095 uint32_t bits = opcode_is_wide ? encoder->xskeleton : encoder->wskeleton;
96 return (bits >> 30);
97}
98
99size_t Arm64Mir2Lir::GetInstructionOffset(LIR* lir) {
100 size_t offset = lir->operands[2];
101 uint64_t check_flags = GetTargetInstFlags(lir->opcode);
102 DCHECK((check_flags & IS_LOAD) || (check_flags & IS_STORE));
103 if (check_flags & SCALED_OFFSET_X0) {
104 DCHECK(check_flags & IS_TERTIARY_OP);
105 offset = offset * (1 << GetLoadStoreSize(lir));
106 }
107 return offset;
108}
109
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100110LIR* Arm64Mir2Lir::LoadFPConstantValue(RegStorage r_dest, int32_t value) {
111 DCHECK(r_dest.IsSingle());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100112 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100113 return NewLIR2(kA64Fmov2sw, r_dest.GetReg(), rwzr);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100114 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100115 int32_t encoded_imm = EncodeImmSingle((uint32_t)value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100116 if (encoded_imm >= 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100117 return NewLIR2(kA64Fmov2fI, r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100118 }
119 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100120
Matteo Franchin43ec8732014-03-31 15:00:14 +0100121 LIR* data_target = ScanLiteralPool(literal_list_, value, 0);
122 if (data_target == NULL) {
Andreas Gampef9879272014-06-18 23:19:07 -0700123 // Wide, as we need 8B alignment.
124 data_target = AddWideData(&literal_list_, value, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100125 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100126
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100127 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100128 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kA64Ldr2fp,
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100129 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100130 AppendLIR(load_pc_rel);
131 return load_pc_rel;
132}
133
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100134LIR* Arm64Mir2Lir::LoadFPConstantValueWide(RegStorage r_dest, int64_t value) {
135 DCHECK(r_dest.IsDouble());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100136 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100137 return NewLIR2(kA64Fmov2Sx, r_dest.GetReg(), rxzr);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100138 } else {
139 int32_t encoded_imm = EncodeImmDouble(value);
140 if (encoded_imm >= 0) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100141 return NewLIR2(WIDE(kA64Fmov2fI), r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100142 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100143 }
144
145 // No short form - load from the literal pool.
146 int32_t val_lo = Low32Bits(value);
147 int32_t val_hi = High32Bits(value);
148 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
149 if (data_target == NULL) {
150 data_target = AddWideData(&literal_list_, val_lo, val_hi);
151 }
152
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100153 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchin4163c532014-07-15 15:20:27 +0100154 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2fp),
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100155 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100156 AppendLIR(load_pc_rel);
157 return load_pc_rel;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100158}
159
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100160static int CountLeadingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100161 return (is_wide) ? __builtin_clzll(value) : __builtin_clz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100162}
Matteo Franchin43ec8732014-03-31 15:00:14 +0100163
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100164static int CountTrailingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100165 return (is_wide) ? __builtin_ctzll(value) : __builtin_ctz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100166}
167
168static int CountSetBits(bool is_wide, uint64_t value) {
169 return ((is_wide) ?
Zheng Xue2eb29e2014-06-12 10:22:33 +0800170 __builtin_popcountll(value) : __builtin_popcount((uint32_t)value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100171}
172
173/**
174 * @brief Try encoding an immediate in the form required by logical instructions.
175 *
176 * @param is_wide Whether @p value is a 64-bit (as opposed to 32-bit) value.
177 * @param value An integer to be encoded. This is interpreted as 64-bit if @p is_wide is true and as
178 * 32-bit if @p is_wide is false.
179 * @return A non-negative integer containing the encoded immediate or -1 if the encoding failed.
180 * @note This is the inverse of Arm64Mir2Lir::DecodeLogicalImmediate().
181 */
182int Arm64Mir2Lir::EncodeLogicalImmediate(bool is_wide, uint64_t value) {
183 unsigned n, imm_s, imm_r;
184
185 // Logical immediates are encoded using parameters n, imm_s and imm_r using
186 // the following table:
187 //
188 // N imms immr size S R
189 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
190 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
191 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
192 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
193 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
194 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
195 // (s bits must not be all set)
196 //
197 // A pattern is constructed of size bits, where the least significant S+1
198 // bits are set. The pattern is rotated right by R, and repeated across a
199 // 32 or 64-bit value, depending on destination register width.
200 //
201 // To test if an arbitary immediate can be encoded using this scheme, an
202 // iterative algorithm is used.
203 //
204
205 // 1. If the value has all set or all clear bits, it can't be encoded.
206 if (value == 0 || value == ~UINT64_C(0) ||
207 (!is_wide && (uint32_t)value == ~UINT32_C(0))) {
208 return -1;
209 }
210
211 unsigned lead_zero = CountLeadingZeros(is_wide, value);
212 unsigned lead_one = CountLeadingZeros(is_wide, ~value);
213 unsigned trail_zero = CountTrailingZeros(is_wide, value);
214 unsigned trail_one = CountTrailingZeros(is_wide, ~value);
215 unsigned set_bits = CountSetBits(is_wide, value);
216
217 // The fixed bits in the immediate s field.
218 // If width == 64 (X reg), start at 0xFFFFFF80.
219 // If width == 32 (W reg), start at 0xFFFFFFC0, as the iteration for 64-bit
220 // widths won't be executed.
221 unsigned width = (is_wide) ? 64 : 32;
222 int imm_s_fixed = (is_wide) ? -128 : -64;
223 int imm_s_mask = 0x3f;
224
225 for (;;) {
226 // 2. If the value is two bits wide, it can be encoded.
227 if (width == 2) {
228 n = 0;
229 imm_s = 0x3C;
230 imm_r = (value & 3) - 1;
231 break;
232 }
233
234 n = (width == 64) ? 1 : 0;
235 imm_s = ((imm_s_fixed | (set_bits - 1)) & imm_s_mask);
236 if ((lead_zero + set_bits) == width) {
237 imm_r = 0;
238 } else {
239 imm_r = (lead_zero > 0) ? (width - trail_zero) : lead_one;
240 }
241
242 // 3. If the sum of leading zeros, trailing zeros and set bits is
243 // equal to the bit width of the value, it can be encoded.
244 if (lead_zero + trail_zero + set_bits == width) {
245 break;
246 }
247
248 // 4. If the sum of leading ones, trailing ones and unset bits in the
249 // value is equal to the bit width of the value, it can be encoded.
250 if (lead_one + trail_one + (width - set_bits) == width) {
251 break;
252 }
253
254 // 5. If the most-significant half of the bitwise value is equal to
255 // the least-significant half, return to step 2 using the
256 // least-significant half of the value.
257 uint64_t mask = (UINT64_C(1) << (width >> 1)) - 1;
258 if ((value & mask) == ((value >> (width >> 1)) & mask)) {
259 width >>= 1;
260 set_bits >>= 1;
261 imm_s_fixed >>= 1;
262 continue;
263 }
264
265 // 6. Otherwise, the value can't be encoded.
266 return -1;
267 }
268
269 return (n << 12 | imm_r << 6 | imm_s);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100270}
271
Matteo Franchinc763e352014-07-04 12:53:27 +0100272// Maximum number of instructions to use for encoding the immediate.
273static const int max_num_ops_per_const_load = 2;
274
275/**
276 * @brief Return the number of fast halfwords in the given uint64_t integer.
277 * @details The input integer is split into 4 halfwords (bits 0-15, 16-31, 32-47, 48-63). The
278 * number of fast halfwords (halfwords that are either 0 or 0xffff) is returned. See below for
279 * a more accurate description.
280 * @param value The input 64-bit integer.
281 * @return Return @c retval such that (retval & 0x7) is the maximum between n and m, where n is
282 * the number of halfwords with all bits unset (0) and m is the number of halfwords with all bits
283 * set (0xffff). Additionally (retval & 0x8) is set when m > n.
284 */
285static int GetNumFastHalfWords(uint64_t value) {
286 unsigned int num_0000_halfwords = 0;
287 unsigned int num_ffff_halfwords = 0;
288 for (int shift = 0; shift < 64; shift += 16) {
289 uint16_t halfword = static_cast<uint16_t>(value >> shift);
290 if (halfword == 0)
291 num_0000_halfwords++;
292 else if (halfword == UINT16_C(0xffff))
293 num_ffff_halfwords++;
294 }
295 if (num_0000_halfwords >= num_ffff_halfwords) {
296 DCHECK_LE(num_0000_halfwords, 4U);
297 return num_0000_halfwords;
298 } else {
299 DCHECK_LE(num_ffff_halfwords, 4U);
300 return num_ffff_halfwords | 0x8;
301 }
302}
303
304// The InexpensiveConstantXXX variants below are used in the promotion algorithm to determine how a
305// constant is considered for promotion. If the constant is "inexpensive" then the promotion
306// algorithm will give it a low priority for promotion, even when it is referenced many times in
307// the code.
308
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700309bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value ATTRIBUTE_UNUSED) {
Matteo Franchinc763e352014-07-04 12:53:27 +0100310 // A 32-bit int can always be loaded with 2 instructions (and without using the literal pool).
311 // We therefore return true and give it a low priority for promotion.
312 return true;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100313}
314
315bool Arm64Mir2Lir::InexpensiveConstantFloat(int32_t value) {
316 return EncodeImmSingle(value) >= 0;
317}
318
319bool Arm64Mir2Lir::InexpensiveConstantLong(int64_t value) {
Matteo Franchinc763e352014-07-04 12:53:27 +0100320 int num_slow_halfwords = 4 - (GetNumFastHalfWords(value) & 0x7);
321 if (num_slow_halfwords <= max_num_ops_per_const_load) {
322 return true;
323 }
324 return (EncodeLogicalImmediate(/*is_wide=*/true, value) >= 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100325}
326
327bool Arm64Mir2Lir::InexpensiveConstantDouble(int64_t value) {
328 return EncodeImmDouble(value) >= 0;
329}
330
Matteo Franchinc763e352014-07-04 12:53:27 +0100331// The InexpensiveConstantXXX variants below are used to determine which A64 instructions to use
332// when one of the operands is an immediate (e.g. register version or immediate version of add).
333
334bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcode) {
335 switch (opcode) {
336 case Instruction::IF_EQ:
337 case Instruction::IF_NE:
338 case Instruction::IF_LT:
339 case Instruction::IF_GE:
340 case Instruction::IF_GT:
341 case Instruction::IF_LE:
342 case Instruction::ADD_INT:
343 case Instruction::ADD_INT_2ADDR:
344 case Instruction::SUB_INT:
345 case Instruction::SUB_INT_2ADDR:
346 // The code below is consistent with the implementation of OpRegRegImm().
347 {
buzbeeb504d2f2014-09-26 15:09:06 -0700348 uint32_t abs_value = (value == INT_MIN) ? value : std::abs(value);
Matteo Franchinc763e352014-07-04 12:53:27 +0100349 if (abs_value < 0x1000) {
350 return true;
351 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
352 return true;
353 }
354 return false;
355 }
356 case Instruction::SHL_INT:
357 case Instruction::SHL_INT_2ADDR:
358 case Instruction::SHR_INT:
359 case Instruction::SHR_INT_2ADDR:
360 case Instruction::USHR_INT:
361 case Instruction::USHR_INT_2ADDR:
362 return true;
363 case Instruction::AND_INT:
364 case Instruction::AND_INT_2ADDR:
365 case Instruction::AND_INT_LIT16:
366 case Instruction::AND_INT_LIT8:
367 case Instruction::OR_INT:
368 case Instruction::OR_INT_2ADDR:
369 case Instruction::OR_INT_LIT16:
370 case Instruction::OR_INT_LIT8:
371 case Instruction::XOR_INT:
372 case Instruction::XOR_INT_2ADDR:
373 case Instruction::XOR_INT_LIT16:
374 case Instruction::XOR_INT_LIT8:
375 if (value == 0 || value == INT32_C(-1)) {
376 return true;
377 }
378 return (EncodeLogicalImmediate(/*is_wide=*/false, value) >= 0);
379 default:
380 return false;
381 }
382}
383
Matteo Franchin43ec8732014-03-31 15:00:14 +0100384/*
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100385 * Load a immediate using one single instruction when possible; otherwise
386 * use a pair of movz and movk instructions.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100387 *
388 * No additional register clobbering operation performed. Use this version when
389 * 1) r_dest is freshly returned from AllocTemp or
390 * 2) The codegen is under fixed register usage
391 */
392LIR* Arm64Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
393 LIR* res;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100394
395 if (r_dest.IsFloat()) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100396 return LoadFPConstantValue(r_dest, value);
397 }
398
399 if (r_dest.Is64Bit()) {
400 return LoadConstantWide(r_dest, value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100401 }
402
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100403 // Loading SP/ZR with an immediate is not supported.
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100404 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
405 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100406
407 // Compute how many movk, movz instructions are needed to load the value.
408 uint16_t high_bits = High16Bits(value);
409 uint16_t low_bits = Low16Bits(value);
410
411 bool low_fast = ((uint16_t)(low_bits + 1) <= 1);
412 bool high_fast = ((uint16_t)(high_bits + 1) <= 1);
413
414 if (LIKELY(low_fast || high_fast)) {
415 // 1 instruction is enough to load the immediate.
416 if (LIKELY(low_bits == high_bits)) {
417 // Value is either 0 or -1: we can just use wzr.
Matteo Franchin4163c532014-07-15 15:20:27 +0100418 A64Opcode opcode = LIKELY(low_bits == 0) ? kA64Mov2rr : kA64Mvn2rr;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100419 res = NewLIR2(opcode, r_dest.GetReg(), rwzr);
420 } else {
421 uint16_t uniform_bits, useful_bits;
422 int shift;
423
424 if (LIKELY(high_fast)) {
425 shift = 0;
426 uniform_bits = high_bits;
427 useful_bits = low_bits;
428 } else {
429 shift = 1;
430 uniform_bits = low_bits;
431 useful_bits = high_bits;
432 }
433
434 if (UNLIKELY(uniform_bits != 0)) {
435 res = NewLIR3(kA64Movn3rdM, r_dest.GetReg(), ~useful_bits, shift);
436 } else {
437 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), useful_bits, shift);
438 }
439 }
440 } else {
441 // movk, movz require 2 instructions. Try detecting logical immediates.
442 int log_imm = EncodeLogicalImmediate(/*is_wide=*/false, value);
443 if (log_imm >= 0) {
444 res = NewLIR3(kA64Orr3Rrl, r_dest.GetReg(), rwzr, log_imm);
445 } else {
446 // Use 2 instructions.
447 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), low_bits, 0);
448 NewLIR3(kA64Movk3rdM, r_dest.GetReg(), high_bits, 1);
449 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100450 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100451
Matteo Franchin43ec8732014-03-31 15:00:14 +0100452 return res;
453}
454
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100455// TODO: clean up the names. LoadConstantWide() should really be LoadConstantNoClobberWide().
456LIR* Arm64Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100457 if (r_dest.IsFloat()) {
458 return LoadFPConstantValueWide(r_dest, value);
459 }
460
461 DCHECK(r_dest.Is64Bit());
462
463 // Loading SP/ZR with an immediate is not supported.
464 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
465 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
466
467 if (LIKELY(value == INT64_C(0) || value == INT64_C(-1))) {
468 // value is either 0 or -1: we can just use xzr.
Matteo Franchin4163c532014-07-15 15:20:27 +0100469 A64Opcode opcode = LIKELY(value == 0) ? WIDE(kA64Mov2rr) : WIDE(kA64Mvn2rr);
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100470 return NewLIR2(opcode, r_dest.GetReg(), rxzr);
471 }
472
473 // At least one in value's halfwords is not 0x0, nor 0xffff: find out how many.
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100474 uint64_t uvalue = static_cast<uint64_t>(value);
Matteo Franchinc763e352014-07-04 12:53:27 +0100475 int num_fast_halfwords = GetNumFastHalfWords(uvalue);
476 int num_slow_halfwords = 4 - (num_fast_halfwords & 0x7);
477 bool more_ffff_halfwords = (num_fast_halfwords & 0x8) != 0;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100478
Matteo Franchinc763e352014-07-04 12:53:27 +0100479 if (num_slow_halfwords > 1) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100480 // A single movz/movn is not enough. Try the logical immediate route.
481 int log_imm = EncodeLogicalImmediate(/*is_wide=*/true, value);
482 if (log_imm >= 0) {
483 return NewLIR3(WIDE(kA64Orr3Rrl), r_dest.GetReg(), rxzr, log_imm);
484 }
485 }
486
Matteo Franchinc763e352014-07-04 12:53:27 +0100487 if (num_slow_halfwords <= max_num_ops_per_const_load) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100488 // We can encode the number using a movz/movn followed by one or more movk.
Matteo Franchin4163c532014-07-15 15:20:27 +0100489 A64Opcode op;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100490 uint16_t background;
491 LIR* res = nullptr;
492
493 // Decide whether to use a movz or a movn.
Matteo Franchinc763e352014-07-04 12:53:27 +0100494 if (more_ffff_halfwords) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100495 op = WIDE(kA64Movn3rdM);
496 background = 0xffff;
Matteo Franchinc763e352014-07-04 12:53:27 +0100497 } else {
498 op = WIDE(kA64Movz3rdM);
499 background = 0;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100500 }
501
502 // Emit the first instruction (movz, movn).
503 int shift;
504 for (shift = 0; shift < 4; shift++) {
505 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
506 if (halfword != background) {
507 res = NewLIR3(op, r_dest.GetReg(), halfword ^ background, shift);
508 break;
509 }
510 }
511
512 // Emit the movk instructions.
513 for (shift++; shift < 4; shift++) {
514 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
515 if (halfword != background) {
516 NewLIR3(WIDE(kA64Movk3rdM), r_dest.GetReg(), halfword, shift);
517 }
518 }
519 return res;
520 }
521
522 // Use the literal pool.
523 int32_t val_lo = Low32Bits(value);
524 int32_t val_hi = High32Bits(value);
525 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
526 if (data_target == NULL) {
527 data_target = AddWideData(&literal_list_, val_lo, val_hi);
528 }
529
530 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
531 LIR *res = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp),
532 r_dest.GetReg(), 0, 0, 0, 0, data_target);
533 AppendLIR(res);
534 return res;
535}
536
Matteo Franchin43ec8732014-03-31 15:00:14 +0100537LIR* Arm64Mir2Lir::OpUnconditionalBranch(LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100538 LIR* res = NewLIR1(kA64B1t, 0 /* offset to be patched during assembly */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100539 res->target = target;
540 return res;
541}
542
543LIR* Arm64Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100544 LIR* branch = NewLIR2(kA64B2ct, ArmConditionEncoding(cc),
545 0 /* offset to be patched */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100546 branch->target = target;
547 return branch;
548}
549
550LIR* Arm64Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100551 A64Opcode opcode = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100552 switch (op) {
553 case kOpBlx:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100554 opcode = kA64Blr1x;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100555 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100556 default:
557 LOG(FATAL) << "Bad opcode " << op;
558 }
559 return NewLIR1(opcode, r_dest_src.GetReg());
560}
561
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100562LIR* Arm64Mir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100563 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100564 CHECK_EQ(r_dest_src1.Is64Bit(), r_src2.Is64Bit());
Matteo Franchin4163c532014-07-15 15:20:27 +0100565 A64Opcode opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100566
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100567 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100568 case kOpCmn:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100569 opcode = kA64Cmn3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100570 break;
571 case kOpCmp:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100572 opcode = kA64Cmp3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100573 break;
574 case kOpMov:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100575 opcode = kA64Mov2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100576 break;
577 case kOpMvn:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100578 opcode = kA64Mvn2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100579 break;
580 case kOpNeg:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100581 opcode = kA64Neg3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100582 break;
583 case kOpTst:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100584 opcode = kA64Tst3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100585 break;
586 case kOpRev:
587 DCHECK_EQ(shift, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100588 // Binary, but rm is encoded twice.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100589 return NewLIR2(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100590 break;
591 case kOpRevsh:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100592 // Binary, but rm is encoded twice.
Zheng Xua3fe7422014-07-09 14:03:15 +0800593 NewLIR2(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
594 // "sxth r1, r2" is "sbfm r1, r2, #0, #15"
595 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100596 break;
597 case kOp2Byte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100598 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
599 // "sbfx r1, r2, #imm1, #imm2" is "sbfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
600 // For now we use sbfm directly.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100601 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 7);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100602 case kOp2Short:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100603 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
604 // For now we use sbfm rather than its alias, sbfx.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100605 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100606 case kOp2Char:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100607 // "ubfx r1, r2, #imm1, #imm2" is "ubfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
608 // For now we use ubfm directly.
609 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100610 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100611 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100612 return OpRegRegRegShift(op, r_dest_src1, r_dest_src1, r_src2, shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100613 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100614
Matteo Franchin43ec8732014-03-31 15:00:14 +0100615 DCHECK(!IsPseudoLirOp(opcode));
616 if (EncodingMap[opcode].flags & IS_BINARY_OP) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100617 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100618 return NewLIR2(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100619 } else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100620 A64EncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100621 if (kind == kFmtShift) {
622 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100623 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100624 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100625
626 LOG(FATAL) << "Unexpected encoding operand count";
627 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100628}
629
Zheng Xucedee472014-07-01 09:53:22 +0800630LIR* Arm64Mir2Lir::OpRegRegExtend(OpKind op, RegStorage r_dest_src1, RegStorage r_src2,
631 A64RegExtEncodings ext, uint8_t amount) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100632 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
633 A64Opcode opcode = kA64Brk1d;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100634
635 switch (op) {
636 case kOpCmn:
637 opcode = kA64Cmn3Rre;
638 break;
639 case kOpCmp:
640 opcode = kA64Cmp3Rre;
641 break;
Zheng Xucedee472014-07-01 09:53:22 +0800642 case kOpAdd:
643 // Note: intentional fallthrough
644 case kOpSub:
645 return OpRegRegRegExtend(op, r_dest_src1, r_dest_src1, r_src2, ext, amount);
646 break;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100647 default:
648 LOG(FATAL) << "Bad Opcode: " << opcode;
649 break;
650 }
651
652 DCHECK(!IsPseudoLirOp(opcode));
653 if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100654 A64EncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100655 if (kind == kFmtExtend) {
Zheng Xucedee472014-07-01 09:53:22 +0800656 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(),
657 EncodeExtend(ext, amount));
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100658 }
659 }
660
661 LOG(FATAL) << "Unexpected encoding operand count";
662 return NULL;
663}
664
Matteo Franchin43ec8732014-03-31 15:00:14 +0100665LIR* Arm64Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100666 /* RegReg operations with SP in first parameter need extended register instruction form.
Zheng Xucedee472014-07-01 09:53:22 +0800667 * Only CMN, CMP, ADD & SUB instructions are implemented.
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100668 */
Zheng Xubaa7c882014-06-30 14:26:50 +0800669 if (r_dest_src1 == rs_sp) {
Zheng Xucedee472014-07-01 09:53:22 +0800670 return OpRegRegExtend(op, r_dest_src1, r_src2, kA64Uxtx, 0);
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100671 } else {
672 return OpRegRegShift(op, r_dest_src1, r_src2, ENCODE_NO_SHIFT);
673 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100674}
675
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700676LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
677 MoveType move_type) {
678 UNUSED(r_dest, r_base, offset, move_type);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100679 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700680 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100681}
682
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700683LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src,
684 MoveType move_type) {
685 UNUSED(r_base, offset, r_src, move_type);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100686 UNIMPLEMENTED(FATAL);
687 return nullptr;
688}
689
690LIR* Arm64Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700691 UNUSED(op, cc, r_dest, r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100692 LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700693 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100694}
695
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100696LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
697 RegStorage r_src2, int shift) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100698 A64Opcode opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100699
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100700 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100701 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100702 opcode = kA64Add4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100703 break;
704 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100705 opcode = kA64Sub4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100706 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100707 // case kOpRsub:
708 // opcode = kA64RsubWWW;
709 // break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100710 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100711 opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100712 break;
713 case kOpAnd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100714 opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100715 break;
716 case kOpXor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100717 opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100718 break;
719 case kOpMul:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100720 opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100721 break;
722 case kOpDiv:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100723 opcode = kA64Sdiv3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100724 break;
725 case kOpOr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100726 opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100727 break;
728 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100729 opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100730 break;
731 case kOpLsl:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100732 opcode = kA64Lsl3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100733 break;
734 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100735 opcode = kA64Lsr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100736 break;
737 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100738 opcode = kA64Asr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100739 break;
740 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100741 opcode = kA64Ror3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100742 break;
743 default:
744 LOG(FATAL) << "Bad opcode: " << op;
745 break;
746 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100747
748 // The instructions above belong to two kinds:
749 // - 4-operands instructions, where the last operand is a shift/extend immediate,
750 // - 3-operands instructions with no shift/extend.
Matteo Franchin4163c532014-07-15 15:20:27 +0100751 A64Opcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100752 CHECK_EQ(r_dest.Is64Bit(), r_src1.Is64Bit());
753 CHECK_EQ(r_dest.Is64Bit(), r_src2.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100754 if (EncodingMap[opcode].flags & IS_QUAD_OP) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100755 DCHECK(!IsExtendEncoding(shift));
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100756 return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100757 } else {
758 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100759 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100760 return NewLIR3(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100761 }
762}
763
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700764LIR* Arm64Mir2Lir::OpRegRegRegExtend(OpKind op, RegStorage r_dest, RegStorage r_src1,
765 RegStorage r_src2, A64RegExtEncodings ext, uint8_t amount) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100766 A64Opcode opcode = kA64Brk1d;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700767
768 switch (op) {
769 case kOpAdd:
770 opcode = kA64Add4RRre;
771 break;
772 case kOpSub:
773 opcode = kA64Sub4RRre;
774 break;
775 default:
Ian Rogers2c4257b2014-10-24 14:20:06 -0700776 UNIMPLEMENTED(FATAL) << "Unimplemented opcode: " << op;
777 UNREACHABLE();
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700778 }
Matteo Franchin4163c532014-07-15 15:20:27 +0100779 A64Opcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700780
781 if (r_dest.Is64Bit()) {
782 CHECK(r_src1.Is64Bit());
783
784 // dest determines whether the op is wide or not. Up-convert src2 when necessary.
785 // Note: this is not according to aarch64 specifications, but our encoding.
786 if (!r_src2.Is64Bit()) {
787 r_src2 = As64BitReg(r_src2);
788 }
789 } else {
790 CHECK(!r_src1.Is64Bit());
791 CHECK(!r_src2.Is64Bit());
792 }
793
794 // Sanity checks.
795 // 1) Amount is in the range 0..4
796 CHECK_LE(amount, 4);
797
798 return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(),
799 EncodeExtend(ext, amount));
800}
801
Matteo Franchin43ec8732014-03-31 15:00:14 +0100802LIR* Arm64Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100803 return OpRegRegRegShift(op, r_dest, r_src1, r_src2, ENCODE_NO_SHIFT);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100804}
805
806LIR* Arm64Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800807 return OpRegRegImm64(op, r_dest, r_src1, static_cast<int64_t>(value));
808}
809
810LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100811 LIR* res;
812 bool neg = (value < 0);
buzbeeb504d2f2014-09-26 15:09:06 -0700813 uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
Matteo Franchin4163c532014-07-15 15:20:27 +0100814 A64Opcode opcode = kA64Brk1d;
815 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinc763e352014-07-04 12:53:27 +0100816 bool is_logical = false;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100817 bool is_wide = r_dest.Is64Bit();
Matteo Franchin4163c532014-07-15 15:20:27 +0100818 A64Opcode wide = (is_wide) ? WIDE(0) : UNWIDE(0);
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700819 int info = 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100820
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100821 switch (op) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100822 case kOpLsl: {
823 // "lsl w1, w2, #imm" is an alias of "ubfm w1, w2, #(-imm MOD 32), #(31-imm)"
Zheng Xu2d41a652014-06-09 11:05:31 +0800824 // and "lsl x1, x2, #imm" of "ubfm x1, x2, #(-imm MOD 64), #(63-imm)".
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100825 // For now, we just use ubfm directly.
Zheng Xu2d41a652014-06-09 11:05:31 +0800826 int max_value = (is_wide) ? 63 : 31;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100827 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest.GetReg(), r_src1.GetReg(),
Zheng Xu2d41a652014-06-09 11:05:31 +0800828 (-value) & max_value, max_value - value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100829 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100830 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100831 return NewLIR3(kA64Lsr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100832 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100833 return NewLIR3(kA64Asr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100834 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100835 // "ror r1, r2, #imm" is an alias of "extr r1, r2, r2, #imm".
836 // For now, we just use extr directly.
837 return NewLIR4(kA64Extr4rrrd | wide, r_dest.GetReg(), r_src1.GetReg(), r_src1.GetReg(),
838 value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100839 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100840 neg = !neg;
Ian Rogersfc787ec2014-10-09 21:56:44 -0700841 FALLTHROUGH_INTENDED;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100842 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100843 // Add and sub below read/write sp rather than xzr.
844 if (abs_value < 0x1000) {
845 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
846 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value, 0);
847 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
848 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
849 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100850 } else {
Vladimir Marko903989d2014-07-01 17:21:18 +0100851 alt_opcode = (op == kOpAdd) ? kA64Add4RRre : kA64Sub4RRre;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700852 info = EncodeExtend(is_wide ? kA64Uxtx : kA64Uxtw, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100853 }
854 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100855 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100856 alt_opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100857 break;
858 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100859 alt_opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100860 break;
861 case kOpOr:
Matteo Franchinc763e352014-07-04 12:53:27 +0100862 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100863 opcode = kA64Orr3Rrl;
864 alt_opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100865 break;
866 case kOpAnd:
Matteo Franchinc763e352014-07-04 12:53:27 +0100867 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100868 opcode = kA64And3Rrl;
869 alt_opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100870 break;
871 case kOpXor:
Matteo Franchinc763e352014-07-04 12:53:27 +0100872 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100873 opcode = kA64Eor3Rrl;
874 alt_opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100875 break;
876 case kOpMul:
877 // TUNING: power of 2, shift & add
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100878 alt_opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100879 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100880 default:
881 LOG(FATAL) << "Bad opcode: " << op;
882 }
883
Matteo Franchinc763e352014-07-04 12:53:27 +0100884 if (is_logical) {
885 int log_imm = EncodeLogicalImmediate(is_wide, value);
886 if (log_imm >= 0) {
887 return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
Zheng Xue2eb29e2014-06-12 10:22:33 +0800888 } else {
Matteo Franchinc763e352014-07-04 12:53:27 +0100889 // When the immediate is either 0 or ~0, the logical operation can be trivially reduced
890 // to a - possibly negated - assignment.
891 if (value == 0) {
892 switch (op) {
893 case kOpOr:
894 case kOpXor:
895 // Or/Xor by zero reduces to an assignment.
896 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), r_src1.GetReg());
897 default:
898 // And by zero reduces to a `mov rdest, xzr'.
899 DCHECK(op == kOpAnd);
900 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), (is_wide) ? rxzr : rwzr);
901 }
902 } else if (value == INT64_C(-1)
903 || (!is_wide && static_cast<uint32_t>(value) == ~UINT32_C(0))) {
904 switch (op) {
905 case kOpAnd:
906 // And by -1 reduces to an assignment.
907 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), r_src1.GetReg());
908 case kOpXor:
909 // Xor by -1 reduces to an `mvn rdest, rsrc'.
910 return NewLIR2(kA64Mvn2rr | wide, r_dest.GetReg(), r_src1.GetReg());
911 default:
912 // Or by -1 reduces to a `mvn rdest, xzr'.
913 DCHECK(op == kOpOr);
914 return NewLIR2(kA64Mvn2rr | wide, r_dest.GetReg(), (is_wide) ? rxzr : rwzr);
915 }
916 }
Zheng Xue2eb29e2014-06-12 10:22:33 +0800917 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100918 }
Matteo Franchinc763e352014-07-04 12:53:27 +0100919
920 RegStorage r_scratch;
921 if (is_wide) {
922 r_scratch = AllocTempWide();
923 LoadConstantWide(r_scratch, value);
924 } else {
925 r_scratch = AllocTemp();
926 LoadConstant(r_scratch, value);
927 }
928 if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
929 res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info);
930 else
931 res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
932 FreeTemp(r_scratch);
933 return res;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100934}
935
Matteo Franchin43ec8732014-03-31 15:00:14 +0100936LIR* Arm64Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100937 return OpRegImm64(op, r_dest_src1, static_cast<int64_t>(value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100938}
939
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100940LIR* Arm64Mir2Lir::OpRegImm64(OpKind op, RegStorage r_dest_src1, int64_t value) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100941 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
942 A64Opcode opcode = kA64Brk1d;
943 A64Opcode neg_opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100944 bool shift;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100945 bool neg = (value < 0);
buzbeeb504d2f2014-09-26 15:09:06 -0700946 uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100947
948 if (LIKELY(abs_value < 0x1000)) {
949 // abs_value is a 12-bit immediate.
950 shift = false;
951 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
952 // abs_value is a shifted 12-bit immediate.
953 shift = true;
954 abs_value >>= 12;
Zheng Xue2eb29e2014-06-12 10:22:33 +0800955 } else if (LIKELY(abs_value < 0x1000000 && (op == kOpAdd || op == kOpSub))) {
956 // Note: It is better to use two ADD/SUB instead of loading a number to a temp register.
957 // This works for both normal registers and SP.
958 // For a frame size == 0x2468, it will be encoded as:
959 // sub sp, #0x2000
960 // sub sp, #0x468
961 if (neg) {
962 op = (op == kOpAdd) ? kOpSub : kOpAdd;
963 }
964 OpRegImm64(op, r_dest_src1, abs_value & (~INT64_C(0xfff)));
965 return OpRegImm64(op, r_dest_src1, abs_value & 0xfff);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100966 } else {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800967 RegStorage r_tmp;
968 LIR* res;
969 if (IS_WIDE(wide)) {
970 r_tmp = AllocTempWide();
971 res = LoadConstantWide(r_tmp, value);
972 } else {
973 r_tmp = AllocTemp();
974 res = LoadConstant(r_tmp, value);
975 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100976 OpRegReg(op, r_dest_src1, r_tmp);
977 FreeTemp(r_tmp);
978 return res;
979 }
980
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100981 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100982 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100983 neg_opcode = kA64Sub4RRdT;
984 opcode = kA64Add4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100985 break;
986 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100987 neg_opcode = kA64Add4RRdT;
988 opcode = kA64Sub4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100989 break;
990 case kOpCmp:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100991 neg_opcode = kA64Cmn3RdT;
992 opcode = kA64Cmp3RdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100993 break;
994 default:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100995 LOG(FATAL) << "Bad op-kind in OpRegImm: " << op;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100996 break;
997 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100998
999 if (UNLIKELY(neg))
1000 opcode = neg_opcode;
1001
1002 if (EncodingMap[opcode].flags & IS_QUAD_OP)
1003 return NewLIR4(opcode | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), abs_value,
1004 (shift) ? 1 : 0);
1005 else
1006 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), abs_value, (shift) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001007}
1008
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001009int Arm64Mir2Lir::EncodeShift(int shift_type, int amount) {
Zheng Xucedee472014-07-01 09:53:22 +08001010 DCHECK_EQ(shift_type & 0x3, shift_type);
1011 DCHECK_EQ(amount & 0x3f, amount);
Matteo Franchinc61b3c92014-06-18 11:52:47 +01001012 return ((shift_type & 0x3) << 7) | (amount & 0x3f);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001013}
1014
1015int Arm64Mir2Lir::EncodeExtend(int extend_type, int amount) {
Zheng Xucedee472014-07-01 09:53:22 +08001016 DCHECK_EQ(extend_type & 0x7, extend_type);
1017 DCHECK_EQ(amount & 0x7, amount);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001018 return (1 << 6) | ((extend_type & 0x7) << 3) | (amount & 0x7);
1019}
1020
1021bool Arm64Mir2Lir::IsExtendEncoding(int encoded_value) {
1022 return ((1 << 6) & encoded_value) != 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001023}
1024
1025LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001026 int scale, OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001027 LIR* load;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001028 int expected_scale = 0;
Matteo Franchin4163c532014-07-15 15:20:27 +01001029 A64Opcode opcode = kA64Brk1d;
Andreas Gampe4b537a82014-06-30 22:24:53 -07001030 r_base = Check64BitReg(r_base);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001031
1032 // TODO(Arm64): The sign extension of r_index should be carried out by using an extended
1033 // register offset load (rather than doing the sign extension in a separate instruction).
1034 if (r_index.Is32Bit()) {
1035 // Assemble: ``sxtw xN, wN''.
1036 r_index = As64BitReg(r_index);
1037 NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31);
1038 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001039
1040 if (r_dest.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001041 if (r_dest.IsDouble()) {
1042 DCHECK(size == k64 || size == kDouble);
1043 expected_scale = 3;
Matteo Franchin4163c532014-07-15 15:20:27 +01001044 opcode = WIDE(kA64Ldr4fXxG);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001045 } else {
1046 DCHECK(r_dest.IsSingle());
1047 DCHECK(size == k32 || size == kSingle);
1048 expected_scale = 2;
1049 opcode = kA64Ldr4fXxG;
1050 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001051
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001052 DCHECK(scale == 0 || scale == expected_scale);
1053 return NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
1054 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001055 }
1056
1057 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001058 case kDouble:
1059 case kWord:
1060 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001061 r_dest = Check64BitReg(r_dest);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001062 opcode = WIDE(kA64Ldr4rXxG);
1063 expected_scale = 3;
1064 break;
Matteo Franchin255e0142014-07-04 13:50:41 +01001065 case kSingle: // Intentional fall-through.
1066 case k32: // Intentional fall-through.
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001067 case kReference:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001068 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001069 opcode = kA64Ldr4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001070 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001071 break;
1072 case kUnsignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001073 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001074 opcode = kA64Ldrh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001075 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001076 break;
1077 case kSignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001078 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001079 opcode = kA64Ldrsh4rXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001080 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001081 break;
1082 case kUnsignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001083 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001084 opcode = kA64Ldrb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001085 break;
1086 case kSignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001087 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001088 opcode = kA64Ldrsb3rXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001089 break;
1090 default:
1091 LOG(FATAL) << "Bad size: " << size;
1092 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001093
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001094 if (UNLIKELY(expected_scale == 0)) {
1095 // This is a tertiary op (e.g. ldrb, ldrsb), it does not not support scale.
1096 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001097 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001098 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001099 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001100 DCHECK(scale == 0 || scale == expected_scale);
1101 load = NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001102 (scale != 0) ? 1 : 0);
1103 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001104
1105 return load;
1106}
1107
Matteo Franchin255e0142014-07-04 13:50:41 +01001108LIR* Arm64Mir2Lir::LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
1109 int scale) {
1110 return LoadBaseIndexed(r_base, r_index, As32BitReg(r_dest), scale, kReference);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001111}
1112
Matteo Franchin43ec8732014-03-31 15:00:14 +01001113LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001114 int scale, OpSize size) {
1115 LIR* store;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001116 int expected_scale = 0;
Matteo Franchin4163c532014-07-15 15:20:27 +01001117 A64Opcode opcode = kA64Brk1d;
Andreas Gampe4b537a82014-06-30 22:24:53 -07001118 r_base = Check64BitReg(r_base);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001119
1120 // TODO(Arm64): The sign extension of r_index should be carried out by using an extended
1121 // register offset store (rather than doing the sign extension in a separate instruction).
1122 if (r_index.Is32Bit()) {
1123 // Assemble: ``sxtw xN, wN''.
1124 r_index = As64BitReg(r_index);
1125 NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31);
1126 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001127
1128 if (r_src.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001129 if (r_src.IsDouble()) {
1130 DCHECK(size == k64 || size == kDouble);
1131 expected_scale = 3;
Matteo Franchin4163c532014-07-15 15:20:27 +01001132 opcode = WIDE(kA64Str4fXxG);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001133 } else {
1134 DCHECK(r_src.IsSingle());
1135 DCHECK(size == k32 || size == kSingle);
1136 expected_scale = 2;
1137 opcode = kA64Str4fXxG;
1138 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001139
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001140 DCHECK(scale == 0 || scale == expected_scale);
1141 return NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
1142 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001143 }
1144
1145 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001146 case kDouble: // Intentional fall-trough.
1147 case kWord: // Intentional fall-trough.
1148 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001149 r_src = Check64BitReg(r_src);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001150 opcode = WIDE(kA64Str4rXxG);
1151 expected_scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001152 break;
1153 case kSingle: // Intentional fall-trough.
1154 case k32: // Intentional fall-trough.
Matteo Franchin255e0142014-07-04 13:50:41 +01001155 case kReference:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001156 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001157 opcode = kA64Str4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001158 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001159 break;
1160 case kUnsignedHalf:
Matteo Franchin43ec8732014-03-31 15:00:14 +01001161 case kSignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001162 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001163 opcode = kA64Strh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001164 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001165 break;
1166 case kUnsignedByte:
Matteo Franchin43ec8732014-03-31 15:00:14 +01001167 case kSignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001168 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001169 opcode = kA64Strb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001170 break;
1171 default:
1172 LOG(FATAL) << "Bad size: " << size;
1173 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001174
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001175 if (UNLIKELY(expected_scale == 0)) {
1176 // This is a tertiary op (e.g. strb), it does not not support scale.
1177 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001178 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001179 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001180 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001181 store = NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
1182 (scale != 0) ? 1 : 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001183 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001184
1185 return store;
1186}
1187
Matteo Franchin255e0142014-07-04 13:50:41 +01001188LIR* Arm64Mir2Lir::StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
1189 int scale) {
1190 return StoreBaseIndexed(r_base, r_index, As32BitReg(r_src), scale, kReference);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001191}
1192
Matteo Franchin43ec8732014-03-31 15:00:14 +01001193/*
1194 * Load value from base + displacement. Optionally perform null check
1195 * on base (which must have an associated s_reg and MIR). If not
1196 * performing null check, incoming MIR can be null.
1197 */
1198LIR* Arm64Mir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001199 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001200 LIR* load = NULL;
Matteo Franchin4163c532014-07-15 15:20:27 +01001201 A64Opcode opcode = kA64Brk1d;
1202 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001203 int scale = 0;
1204
Matteo Franchin43ec8732014-03-31 15:00:14 +01001205 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001206 case kDouble: // Intentional fall-through.
1207 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001208 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001209 r_dest = Check64BitReg(r_dest);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001210 scale = 3;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001211 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001212 DCHECK(r_dest.IsDouble());
Matteo Franchin4163c532014-07-15 15:20:27 +01001213 opcode = WIDE(kA64Ldr3fXD);
1214 alt_opcode = WIDE(kA64Ldur3fXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001215 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001216 opcode = WIDE(kA64Ldr3rXD);
1217 alt_opcode = WIDE(kA64Ldur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001218 }
1219 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001220 case kSingle: // Intentional fall-through.
1221 case k32: // Intentional fall-trough.
Matteo Franchin255e0142014-07-04 13:50:41 +01001222 case kReference:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001223 r_dest = Check32BitReg(r_dest);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001224 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001225 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001226 DCHECK(r_dest.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001227 opcode = kA64Ldr3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001228 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001229 opcode = kA64Ldr3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001230 }
1231 break;
1232 case kUnsignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001233 scale = 1;
1234 opcode = kA64Ldrh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001235 break;
1236 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001237 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001238 opcode = kA64Ldrsh3rXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001239 break;
1240 case kUnsignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001241 opcode = kA64Ldrb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001242 break;
1243 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001244 opcode = kA64Ldrsb3rXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001245 break;
1246 default:
1247 LOG(FATAL) << "Bad size: " << size;
1248 }
1249
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001250 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1251 int scaled_disp = displacement >> scale;
1252 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1253 // Can use scaled load.
1254 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), scaled_disp);
1255 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1256 // Can use unscaled load.
1257 load = NewLIR3(alt_opcode, r_dest.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001258 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001259 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001260 // TODO: cleaner support for index/displacement registers? Not a reference, but must match width.
1261 RegStorage r_scratch = AllocTempWide();
1262 LoadConstantWide(r_scratch, displacement);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001263 load = LoadBaseIndexed(r_base, r_scratch, r_dest, 0, size);
1264 FreeTemp(r_scratch);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001265 }
1266
1267 // TODO: in future may need to differentiate Dalvik accesses w/ spills
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001268 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001269 DCHECK_EQ(r_base, rs_sp);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001270 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +01001271 }
1272 return load;
1273}
1274
Andreas Gampe3c12c512014-06-24 18:46:29 +00001275LIR* Arm64Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
1276 OpSize size, VolatileKind is_volatile) {
Vladimir Marko674744e2014-04-24 15:18:26 +01001277 // LoadBaseDisp() will emit correct insn for atomic load on arm64
1278 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
Andreas Gampe3c12c512014-06-24 18:46:29 +00001279
1280 LIR* load = LoadBaseDispBody(r_base, displacement, r_dest, size);
1281
1282 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001283 // TODO: This should generate an acquire load instead of the barrier.
1284 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001285 }
1286
1287 return load;
Vladimir Marko674744e2014-04-24 15:18:26 +01001288}
1289
Andreas Gampe3c12c512014-06-24 18:46:29 +00001290LIR* Arm64Mir2Lir::LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest,
1291 VolatileKind is_volatile) {
1292 return LoadBaseDisp(r_base, displacement, As32BitReg(r_dest), kReference, is_volatile);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001293}
1294
Matteo Franchin43ec8732014-03-31 15:00:14 +01001295LIR* Arm64Mir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001296 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001297 LIR* store = NULL;
Matteo Franchin4163c532014-07-15 15:20:27 +01001298 A64Opcode opcode = kA64Brk1d;
1299 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001300 int scale = 0;
1301
Matteo Franchin43ec8732014-03-31 15:00:14 +01001302 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001303 case kDouble: // Intentional fall-through.
1304 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001305 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001306 r_src = Check64BitReg(r_src);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001307 scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001308 if (r_src.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001309 DCHECK(r_src.IsDouble());
Matteo Franchin4163c532014-07-15 15:20:27 +01001310 opcode = WIDE(kA64Str3fXD);
1311 alt_opcode = WIDE(kA64Stur3fXd);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001312 } else {
Matteo Franchin4163c532014-07-15 15:20:27 +01001313 opcode = WIDE(kA64Str3rXD);
1314 alt_opcode = WIDE(kA64Stur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001315 }
1316 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001317 case kSingle: // Intentional fall-through.
1318 case k32: // Intentional fall-trough.
Matteo Franchin255e0142014-07-04 13:50:41 +01001319 case kReference:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001320 r_src = Check32BitReg(r_src);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001321 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001322 if (r_src.IsFloat()) {
1323 DCHECK(r_src.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001324 opcode = kA64Str3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001325 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001326 opcode = kA64Str3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001327 }
1328 break;
1329 case kUnsignedHalf:
1330 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001331 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001332 opcode = kA64Strh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001333 break;
1334 case kUnsignedByte:
1335 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001336 opcode = kA64Strb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001337 break;
1338 default:
1339 LOG(FATAL) << "Bad size: " << size;
1340 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001341
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001342 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1343 int scaled_disp = displacement >> scale;
1344 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1345 // Can use scaled store.
1346 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), scaled_disp);
1347 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1348 // Can use unscaled store.
1349 store = NewLIR3(alt_opcode, r_src.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001350 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001351 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001352 RegStorage r_scratch = AllocTempWide();
1353 LoadConstantWide(r_scratch, displacement);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001354 store = StoreBaseIndexed(r_base, r_scratch, r_src, 0, size);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001355 FreeTemp(r_scratch);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001356 }
1357
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001358 // TODO: In future, may need to differentiate Dalvik & spill accesses.
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001359 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001360 DCHECK_EQ(r_base, rs_sp);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001361 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +01001362 }
1363 return store;
1364}
1365
Andreas Gampe3c12c512014-06-24 18:46:29 +00001366LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
1367 OpSize size, VolatileKind is_volatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001368 // TODO: This should generate a release store and no barriers.
Andreas Gampe3c12c512014-06-24 18:46:29 +00001369 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001370 // Ensure that prior accesses become visible to other threads first.
1371 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001372 }
1373
Vladimir Marko674744e2014-04-24 15:18:26 +01001374 // StoreBaseDisp() will emit correct insn for atomic store on arm64
1375 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
Andreas Gampe3c12c512014-06-24 18:46:29 +00001376
1377 LIR* store = StoreBaseDispBody(r_base, displacement, r_src, size);
1378
1379 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001380 // Preserve order with respect to any subsequent volatile loads.
1381 // We need StoreLoad, but that generally requires the most expensive barrier.
1382 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001383 }
1384
1385 return store;
Vladimir Marko674744e2014-04-24 15:18:26 +01001386}
1387
Andreas Gampe3c12c512014-06-24 18:46:29 +00001388LIR* Arm64Mir2Lir::StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src,
1389 VolatileKind is_volatile) {
1390 return StoreBaseDisp(r_base, displacement, As32BitReg(r_src), kReference, is_volatile);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001391}
1392
Matteo Franchin43ec8732014-03-31 15:00:14 +01001393LIR* Arm64Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001394 UNUSED(r_dest, r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001395 LOG(FATAL) << "Unexpected use of OpFpRegCopy for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001396 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +01001397}
1398
Matteo Franchin43ec8732014-03-31 15:00:14 +01001399LIR* Arm64Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001400 UNUSED(op, r_base, disp);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001401 LOG(FATAL) << "Unexpected use of OpMem for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001402 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +01001403}
1404
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001405LIR* Arm64Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt,
1406 QuickEntrypointEnum trampoline ATTRIBUTE_UNUSED) {
1407 // The address of the trampoline is already loaded into r_tgt.
Andreas Gampe98430592014-07-27 19:44:50 -07001408 return OpReg(op, r_tgt);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001409}
1410
1411} // namespace art