blob: f48290d6f779692f95628a9be347c8d0b9a65371 [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
Matteo Franchin43ec8732014-03-31 15:00:14 +010017#include "codegen_arm64.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080018
19#include "arm64_lir.h"
20#include "base/logging.h"
Matteo Franchin43ec8732014-03-31 15:00:14 +010021#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070022#include "dex/reg_storage_eq.h"
Matteo Franchin43ec8732014-03-31 15:00:14 +010023
24namespace art {
25
Matteo Franchine45fb9e2014-05-06 10:10:30 +010026/* This file contains codegen for the A64 ISA. */
Matteo Franchin43ec8732014-03-31 15:00:14 +010027
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010028int32_t Arm64Mir2Lir::EncodeImmSingle(uint32_t bits) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010029 /*
30 * Valid values will have the form:
31 *
32 * aBbb.bbbc.defg.h000.0000.0000.0000.0000
33 *
34 * where B = not(b). In other words, if b == 1, then B == 0 and viceversa.
35 */
36
37 // bits[19..0] are cleared.
38 if ((bits & 0x0007ffff) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010039 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010040
41 // bits[29..25] are all set or all cleared.
42 uint32_t b_pattern = (bits >> 16) & 0x3e00;
43 if (b_pattern != 0 && b_pattern != 0x3e00)
44 return -1;
45
46 // bit[30] and bit[29] are opposite.
47 if (((bits ^ (bits << 1)) & 0x40000000) == 0)
48 return -1;
49
50 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
51 // bit7: a000.0000
52 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
53 // bit6: 0b00.0000
54 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
55 // bit5_to_0: 00cd.efgh
56 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
57 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010058}
59
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010060int32_t Arm64Mir2Lir::EncodeImmDouble(uint64_t bits) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010061 /*
62 * Valid values will have the form:
63 *
64 * aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
65 * 0000.0000.0000.0000.0000.0000.0000.0000
66 *
67 * where B = not(b).
68 */
69
70 // bits[47..0] are cleared.
71 if ((bits & UINT64_C(0xffffffffffff)) != 0)
Matteo Franchin43ec8732014-03-31 15:00:14 +010072 return -1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +010073
74 // bits[61..54] are all set or all cleared.
75 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
76 if (b_pattern != 0 && b_pattern != 0x3fc0)
77 return -1;
78
79 // bit[62] and bit[61] are opposite.
80 if (((bits ^ (bits << 1)) & UINT64_C(0x4000000000000000)) == 0)
81 return -1;
82
83 // bit7: a000.0000
84 uint32_t bit7 = ((bits >> 63) & 0x1) << 7;
85 // bit6: 0b00.0000
86 uint32_t bit6 = ((bits >> 61) & 0x1) << 6;
87 // bit5_to_0: 00cd.efgh
88 uint32_t bit5_to_0 = (bits >> 48) & 0x3f;
89 return (bit7 | bit6 | bit5_to_0);
Matteo Franchin43ec8732014-03-31 15:00:14 +010090}
91
Serban Constantinescu63999682014-07-15 17:44:21 +010092size_t Arm64Mir2Lir::GetLoadStoreSize(LIR* lir) {
93 bool opcode_is_wide = IS_WIDE(lir->opcode);
Matteo Franchin4163c532014-07-15 15:20:27 +010094 A64Opcode opcode = UNWIDE(lir->opcode);
Serban Constantinescu63999682014-07-15 17:44:21 +010095 DCHECK(!IsPseudoLirOp(opcode));
Matteo Franchin4163c532014-07-15 15:20:27 +010096 const A64EncodingMap *encoder = &EncodingMap[opcode];
Serban Constantinescu63999682014-07-15 17:44:21 +010097 uint32_t bits = opcode_is_wide ? encoder->xskeleton : encoder->wskeleton;
98 return (bits >> 30);
99}
100
101size_t Arm64Mir2Lir::GetInstructionOffset(LIR* lir) {
102 size_t offset = lir->operands[2];
103 uint64_t check_flags = GetTargetInstFlags(lir->opcode);
104 DCHECK((check_flags & IS_LOAD) || (check_flags & IS_STORE));
105 if (check_flags & SCALED_OFFSET_X0) {
106 DCHECK(check_flags & IS_TERTIARY_OP);
107 offset = offset * (1 << GetLoadStoreSize(lir));
108 }
109 return offset;
110}
111
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100112LIR* Arm64Mir2Lir::LoadFPConstantValue(RegStorage r_dest, int32_t value) {
113 DCHECK(r_dest.IsSingle());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100114 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100115 return NewLIR2(kA64Fmov2sw, r_dest.GetReg(), rwzr);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100116 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100117 int32_t encoded_imm = EncodeImmSingle((uint32_t)value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100118 if (encoded_imm >= 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100119 return NewLIR2(kA64Fmov2fI, r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100120 }
121 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100122
Matteo Franchin43ec8732014-03-31 15:00:14 +0100123 LIR* data_target = ScanLiteralPool(literal_list_, value, 0);
124 if (data_target == NULL) {
Andreas Gampef9879272014-06-18 23:19:07 -0700125 // Wide, as we need 8B alignment.
126 data_target = AddWideData(&literal_list_, value, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100127 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100128
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100129 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100130 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kA64Ldr2fp,
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100131 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100132 AppendLIR(load_pc_rel);
133 return load_pc_rel;
134}
135
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100136LIR* Arm64Mir2Lir::LoadFPConstantValueWide(RegStorage r_dest, int64_t value) {
137 DCHECK(r_dest.IsDouble());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100138 if (value == 0) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100139 return NewLIR2(kA64Fmov2Sx, r_dest.GetReg(), rxzr);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100140 } else {
141 int32_t encoded_imm = EncodeImmDouble(value);
142 if (encoded_imm >= 0) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100143 return NewLIR2(WIDE(kA64Fmov2fI), r_dest.GetReg(), encoded_imm);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100144 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100145 }
146
147 // No short form - load from the literal pool.
148 int32_t val_lo = Low32Bits(value);
149 int32_t val_hi = High32Bits(value);
150 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
151 if (data_target == NULL) {
152 data_target = AddWideData(&literal_list_, val_lo, val_hi);
153 }
154
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100155 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
Matteo Franchin4163c532014-07-15 15:20:27 +0100156 LIR* load_pc_rel = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2fp),
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100157 r_dest.GetReg(), 0, 0, 0, 0, data_target);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100158 AppendLIR(load_pc_rel);
159 return load_pc_rel;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100160}
161
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100162static int CountLeadingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100163 return (is_wide) ? __builtin_clzll(value) : __builtin_clz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100164}
Matteo Franchin43ec8732014-03-31 15:00:14 +0100165
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100166static int CountTrailingZeros(bool is_wide, uint64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100167 return (is_wide) ? __builtin_ctzll(value) : __builtin_ctz((uint32_t)value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100168}
169
170static int CountSetBits(bool is_wide, uint64_t value) {
171 return ((is_wide) ?
Zheng Xue2eb29e2014-06-12 10:22:33 +0800172 __builtin_popcountll(value) : __builtin_popcount((uint32_t)value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100173}
174
175/**
176 * @brief Try encoding an immediate in the form required by logical instructions.
177 *
178 * @param is_wide Whether @p value is a 64-bit (as opposed to 32-bit) value.
179 * @param value An integer to be encoded. This is interpreted as 64-bit if @p is_wide is true and as
180 * 32-bit if @p is_wide is false.
181 * @return A non-negative integer containing the encoded immediate or -1 if the encoding failed.
182 * @note This is the inverse of Arm64Mir2Lir::DecodeLogicalImmediate().
183 */
184int Arm64Mir2Lir::EncodeLogicalImmediate(bool is_wide, uint64_t value) {
185 unsigned n, imm_s, imm_r;
186
187 // Logical immediates are encoded using parameters n, imm_s and imm_r using
188 // the following table:
189 //
190 // N imms immr size S R
191 // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
192 // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
193 // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
194 // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
195 // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
196 // 0 11110s xxxxxr 2 UInt(s) UInt(r)
197 // (s bits must not be all set)
198 //
199 // A pattern is constructed of size bits, where the least significant S+1
200 // bits are set. The pattern is rotated right by R, and repeated across a
201 // 32 or 64-bit value, depending on destination register width.
202 //
203 // To test if an arbitary immediate can be encoded using this scheme, an
204 // iterative algorithm is used.
205 //
206
207 // 1. If the value has all set or all clear bits, it can't be encoded.
208 if (value == 0 || value == ~UINT64_C(0) ||
209 (!is_wide && (uint32_t)value == ~UINT32_C(0))) {
210 return -1;
211 }
212
213 unsigned lead_zero = CountLeadingZeros(is_wide, value);
214 unsigned lead_one = CountLeadingZeros(is_wide, ~value);
215 unsigned trail_zero = CountTrailingZeros(is_wide, value);
216 unsigned trail_one = CountTrailingZeros(is_wide, ~value);
217 unsigned set_bits = CountSetBits(is_wide, value);
218
219 // The fixed bits in the immediate s field.
220 // If width == 64 (X reg), start at 0xFFFFFF80.
221 // If width == 32 (W reg), start at 0xFFFFFFC0, as the iteration for 64-bit
222 // widths won't be executed.
223 unsigned width = (is_wide) ? 64 : 32;
224 int imm_s_fixed = (is_wide) ? -128 : -64;
225 int imm_s_mask = 0x3f;
226
227 for (;;) {
228 // 2. If the value is two bits wide, it can be encoded.
229 if (width == 2) {
230 n = 0;
231 imm_s = 0x3C;
232 imm_r = (value & 3) - 1;
233 break;
234 }
235
236 n = (width == 64) ? 1 : 0;
237 imm_s = ((imm_s_fixed | (set_bits - 1)) & imm_s_mask);
238 if ((lead_zero + set_bits) == width) {
239 imm_r = 0;
240 } else {
241 imm_r = (lead_zero > 0) ? (width - trail_zero) : lead_one;
242 }
243
244 // 3. If the sum of leading zeros, trailing zeros and set bits is
245 // equal to the bit width of the value, it can be encoded.
246 if (lead_zero + trail_zero + set_bits == width) {
247 break;
248 }
249
250 // 4. If the sum of leading ones, trailing ones and unset bits in the
251 // value is equal to the bit width of the value, it can be encoded.
252 if (lead_one + trail_one + (width - set_bits) == width) {
253 break;
254 }
255
256 // 5. If the most-significant half of the bitwise value is equal to
257 // the least-significant half, return to step 2 using the
258 // least-significant half of the value.
259 uint64_t mask = (UINT64_C(1) << (width >> 1)) - 1;
260 if ((value & mask) == ((value >> (width >> 1)) & mask)) {
261 width >>= 1;
262 set_bits >>= 1;
263 imm_s_fixed >>= 1;
264 continue;
265 }
266
267 // 6. Otherwise, the value can't be encoded.
268 return -1;
269 }
270
271 return (n << 12 | imm_r << 6 | imm_s);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100272}
273
Matteo Franchinc763e352014-07-04 12:53:27 +0100274// Maximum number of instructions to use for encoding the immediate.
275static const int max_num_ops_per_const_load = 2;
276
277/**
278 * @brief Return the number of fast halfwords in the given uint64_t integer.
279 * @details The input integer is split into 4 halfwords (bits 0-15, 16-31, 32-47, 48-63). The
280 * number of fast halfwords (halfwords that are either 0 or 0xffff) is returned. See below for
281 * a more accurate description.
282 * @param value The input 64-bit integer.
283 * @return Return @c retval such that (retval & 0x7) is the maximum between n and m, where n is
284 * the number of halfwords with all bits unset (0) and m is the number of halfwords with all bits
285 * set (0xffff). Additionally (retval & 0x8) is set when m > n.
286 */
287static int GetNumFastHalfWords(uint64_t value) {
288 unsigned int num_0000_halfwords = 0;
289 unsigned int num_ffff_halfwords = 0;
290 for (int shift = 0; shift < 64; shift += 16) {
291 uint16_t halfword = static_cast<uint16_t>(value >> shift);
292 if (halfword == 0)
293 num_0000_halfwords++;
294 else if (halfword == UINT16_C(0xffff))
295 num_ffff_halfwords++;
296 }
297 if (num_0000_halfwords >= num_ffff_halfwords) {
298 DCHECK_LE(num_0000_halfwords, 4U);
299 return num_0000_halfwords;
300 } else {
301 DCHECK_LE(num_ffff_halfwords, 4U);
302 return num_ffff_halfwords | 0x8;
303 }
304}
305
306// The InexpensiveConstantXXX variants below are used in the promotion algorithm to determine how a
307// constant is considered for promotion. If the constant is "inexpensive" then the promotion
308// algorithm will give it a low priority for promotion, even when it is referenced many times in
309// the code.
310
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700311bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value ATTRIBUTE_UNUSED) {
Matteo Franchinc763e352014-07-04 12:53:27 +0100312 // A 32-bit int can always be loaded with 2 instructions (and without using the literal pool).
313 // We therefore return true and give it a low priority for promotion.
314 return true;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100315}
316
317bool Arm64Mir2Lir::InexpensiveConstantFloat(int32_t value) {
318 return EncodeImmSingle(value) >= 0;
319}
320
321bool Arm64Mir2Lir::InexpensiveConstantLong(int64_t value) {
Matteo Franchinc763e352014-07-04 12:53:27 +0100322 int num_slow_halfwords = 4 - (GetNumFastHalfWords(value) & 0x7);
323 if (num_slow_halfwords <= max_num_ops_per_const_load) {
324 return true;
325 }
326 return (EncodeLogicalImmediate(/*is_wide=*/true, value) >= 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100327}
328
329bool Arm64Mir2Lir::InexpensiveConstantDouble(int64_t value) {
330 return EncodeImmDouble(value) >= 0;
331}
332
Matteo Franchinc763e352014-07-04 12:53:27 +0100333// The InexpensiveConstantXXX variants below are used to determine which A64 instructions to use
334// when one of the operands is an immediate (e.g. register version or immediate version of add).
335
336bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcode) {
337 switch (opcode) {
338 case Instruction::IF_EQ:
339 case Instruction::IF_NE:
340 case Instruction::IF_LT:
341 case Instruction::IF_GE:
342 case Instruction::IF_GT:
343 case Instruction::IF_LE:
344 case Instruction::ADD_INT:
345 case Instruction::ADD_INT_2ADDR:
346 case Instruction::SUB_INT:
347 case Instruction::SUB_INT_2ADDR:
348 // The code below is consistent with the implementation of OpRegRegImm().
349 {
buzbeeb504d2f2014-09-26 15:09:06 -0700350 uint32_t abs_value = (value == INT_MIN) ? value : std::abs(value);
Matteo Franchinc763e352014-07-04 12:53:27 +0100351 if (abs_value < 0x1000) {
352 return true;
353 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
354 return true;
355 }
356 return false;
357 }
358 case Instruction::SHL_INT:
359 case Instruction::SHL_INT_2ADDR:
360 case Instruction::SHR_INT:
361 case Instruction::SHR_INT_2ADDR:
362 case Instruction::USHR_INT:
363 case Instruction::USHR_INT_2ADDR:
364 return true;
365 case Instruction::AND_INT:
366 case Instruction::AND_INT_2ADDR:
367 case Instruction::AND_INT_LIT16:
368 case Instruction::AND_INT_LIT8:
369 case Instruction::OR_INT:
370 case Instruction::OR_INT_2ADDR:
371 case Instruction::OR_INT_LIT16:
372 case Instruction::OR_INT_LIT8:
373 case Instruction::XOR_INT:
374 case Instruction::XOR_INT_2ADDR:
375 case Instruction::XOR_INT_LIT16:
376 case Instruction::XOR_INT_LIT8:
377 if (value == 0 || value == INT32_C(-1)) {
378 return true;
379 }
380 return (EncodeLogicalImmediate(/*is_wide=*/false, value) >= 0);
381 default:
382 return false;
383 }
384}
385
Matteo Franchin43ec8732014-03-31 15:00:14 +0100386/*
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100387 * Load a immediate using one single instruction when possible; otherwise
388 * use a pair of movz and movk instructions.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100389 *
390 * No additional register clobbering operation performed. Use this version when
391 * 1) r_dest is freshly returned from AllocTemp or
392 * 2) The codegen is under fixed register usage
393 */
394LIR* Arm64Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
395 LIR* res;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100396
397 if (r_dest.IsFloat()) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100398 return LoadFPConstantValue(r_dest, value);
399 }
400
401 if (r_dest.Is64Bit()) {
402 return LoadConstantWide(r_dest, value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100403 }
404
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100405 // Loading SP/ZR with an immediate is not supported.
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100406 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
407 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100408
409 // Compute how many movk, movz instructions are needed to load the value.
410 uint16_t high_bits = High16Bits(value);
411 uint16_t low_bits = Low16Bits(value);
412
413 bool low_fast = ((uint16_t)(low_bits + 1) <= 1);
414 bool high_fast = ((uint16_t)(high_bits + 1) <= 1);
415
416 if (LIKELY(low_fast || high_fast)) {
417 // 1 instruction is enough to load the immediate.
418 if (LIKELY(low_bits == high_bits)) {
419 // Value is either 0 or -1: we can just use wzr.
Matteo Franchin4163c532014-07-15 15:20:27 +0100420 A64Opcode opcode = LIKELY(low_bits == 0) ? kA64Mov2rr : kA64Mvn2rr;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100421 res = NewLIR2(opcode, r_dest.GetReg(), rwzr);
422 } else {
423 uint16_t uniform_bits, useful_bits;
424 int shift;
425
426 if (LIKELY(high_fast)) {
427 shift = 0;
428 uniform_bits = high_bits;
429 useful_bits = low_bits;
430 } else {
431 shift = 1;
432 uniform_bits = low_bits;
433 useful_bits = high_bits;
434 }
435
436 if (UNLIKELY(uniform_bits != 0)) {
437 res = NewLIR3(kA64Movn3rdM, r_dest.GetReg(), ~useful_bits, shift);
438 } else {
439 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), useful_bits, shift);
440 }
441 }
442 } else {
443 // movk, movz require 2 instructions. Try detecting logical immediates.
444 int log_imm = EncodeLogicalImmediate(/*is_wide=*/false, value);
445 if (log_imm >= 0) {
446 res = NewLIR3(kA64Orr3Rrl, r_dest.GetReg(), rwzr, log_imm);
447 } else {
448 // Use 2 instructions.
449 res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), low_bits, 0);
450 NewLIR3(kA64Movk3rdM, r_dest.GetReg(), high_bits, 1);
451 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100452 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100453
Matteo Franchin43ec8732014-03-31 15:00:14 +0100454 return res;
455}
456
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100457// TODO: clean up the names. LoadConstantWide() should really be LoadConstantNoClobberWide().
458LIR* Arm64Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100459 if (r_dest.IsFloat()) {
460 return LoadFPConstantValueWide(r_dest, value);
461 }
462
463 DCHECK(r_dest.Is64Bit());
464
465 // Loading SP/ZR with an immediate is not supported.
466 DCHECK(!A64_REG_IS_SP(r_dest.GetReg()));
467 DCHECK(!A64_REG_IS_ZR(r_dest.GetReg()));
468
469 if (LIKELY(value == INT64_C(0) || value == INT64_C(-1))) {
470 // value is either 0 or -1: we can just use xzr.
Matteo Franchin4163c532014-07-15 15:20:27 +0100471 A64Opcode opcode = LIKELY(value == 0) ? WIDE(kA64Mov2rr) : WIDE(kA64Mvn2rr);
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100472 return NewLIR2(opcode, r_dest.GetReg(), rxzr);
473 }
474
475 // At least one in value's halfwords is not 0x0, nor 0xffff: find out how many.
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100476 uint64_t uvalue = static_cast<uint64_t>(value);
Matteo Franchinc763e352014-07-04 12:53:27 +0100477 int num_fast_halfwords = GetNumFastHalfWords(uvalue);
478 int num_slow_halfwords = 4 - (num_fast_halfwords & 0x7);
479 bool more_ffff_halfwords = (num_fast_halfwords & 0x8) != 0;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100480
Matteo Franchinc763e352014-07-04 12:53:27 +0100481 if (num_slow_halfwords > 1) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100482 // A single movz/movn is not enough. Try the logical immediate route.
483 int log_imm = EncodeLogicalImmediate(/*is_wide=*/true, value);
484 if (log_imm >= 0) {
485 return NewLIR3(WIDE(kA64Orr3Rrl), r_dest.GetReg(), rxzr, log_imm);
486 }
487 }
488
Matteo Franchinc763e352014-07-04 12:53:27 +0100489 if (num_slow_halfwords <= max_num_ops_per_const_load) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100490 // We can encode the number using a movz/movn followed by one or more movk.
Matteo Franchin4163c532014-07-15 15:20:27 +0100491 A64Opcode op;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100492 uint16_t background;
493 LIR* res = nullptr;
494
495 // Decide whether to use a movz or a movn.
Matteo Franchinc763e352014-07-04 12:53:27 +0100496 if (more_ffff_halfwords) {
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100497 op = WIDE(kA64Movn3rdM);
498 background = 0xffff;
Matteo Franchinc763e352014-07-04 12:53:27 +0100499 } else {
500 op = WIDE(kA64Movz3rdM);
501 background = 0;
Matteo Franchinc41e6dc2014-06-13 19:16:28 +0100502 }
503
504 // Emit the first instruction (movz, movn).
505 int shift;
506 for (shift = 0; shift < 4; shift++) {
507 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
508 if (halfword != background) {
509 res = NewLIR3(op, r_dest.GetReg(), halfword ^ background, shift);
510 break;
511 }
512 }
513
514 // Emit the movk instructions.
515 for (shift++; shift < 4; shift++) {
516 uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4));
517 if (halfword != background) {
518 NewLIR3(WIDE(kA64Movk3rdM), r_dest.GetReg(), halfword, shift);
519 }
520 }
521 return res;
522 }
523
524 // Use the literal pool.
525 int32_t val_lo = Low32Bits(value);
526 int32_t val_hi = High32Bits(value);
527 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
528 if (data_target == NULL) {
529 data_target = AddWideData(&literal_list_, val_lo, val_hi);
530 }
531
532 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
533 LIR *res = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp),
534 r_dest.GetReg(), 0, 0, 0, 0, data_target);
535 AppendLIR(res);
536 return res;
537}
538
Matteo Franchin43ec8732014-03-31 15:00:14 +0100539LIR* Arm64Mir2Lir::OpUnconditionalBranch(LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100540 LIR* res = NewLIR1(kA64B1t, 0 /* offset to be patched during assembly */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100541 res->target = target;
542 return res;
543}
544
545LIR* Arm64Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100546 LIR* branch = NewLIR2(kA64B2ct, ArmConditionEncoding(cc),
547 0 /* offset to be patched */);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100548 branch->target = target;
549 return branch;
550}
551
552LIR* Arm64Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100553 A64Opcode opcode = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100554 switch (op) {
555 case kOpBlx:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100556 opcode = kA64Blr1x;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100557 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100558 default:
559 LOG(FATAL) << "Bad opcode " << op;
560 }
561 return NewLIR1(opcode, r_dest_src.GetReg());
562}
563
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100564LIR* Arm64Mir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100565 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100566 CHECK_EQ(r_dest_src1.Is64Bit(), r_src2.Is64Bit());
Matteo Franchin4163c532014-07-15 15:20:27 +0100567 A64Opcode opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100568
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100569 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100570 case kOpCmn:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100571 opcode = kA64Cmn3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100572 break;
573 case kOpCmp:
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100574 opcode = kA64Cmp3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100575 break;
576 case kOpMov:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100577 opcode = kA64Mov2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100578 break;
579 case kOpMvn:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100580 opcode = kA64Mvn2rr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100581 break;
582 case kOpNeg:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100583 opcode = kA64Neg3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100584 break;
585 case kOpTst:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100586 opcode = kA64Tst3rro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100587 break;
588 case kOpRev:
589 DCHECK_EQ(shift, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100590 // Binary, but rm is encoded twice.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100591 return NewLIR2(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100592 break;
593 case kOpRevsh:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100594 // Binary, but rm is encoded twice.
Zheng Xua3fe7422014-07-09 14:03:15 +0800595 NewLIR2(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg());
596 // "sxth r1, r2" is "sbfm r1, r2, #0, #15"
597 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100598 break;
599 case kOp2Byte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100600 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
601 // "sbfx r1, r2, #imm1, #imm2" is "sbfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
602 // For now we use sbfm directly.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100603 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 7);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100604 case kOp2Short:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100605 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
606 // For now we use sbfm rather than its alias, sbfx.
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100607 return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100608 case kOp2Char:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100609 // "ubfx r1, r2, #imm1, #imm2" is "ubfm r1, r2, #imm1, #(imm1 + imm2 - 1)".
610 // For now we use ubfm directly.
611 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100612 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100613 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100614 return OpRegRegRegShift(op, r_dest_src1, r_dest_src1, r_src2, shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100615 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100616
Matteo Franchin43ec8732014-03-31 15:00:14 +0100617 DCHECK(!IsPseudoLirOp(opcode));
618 if (EncodingMap[opcode].flags & IS_BINARY_OP) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100619 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100620 return NewLIR2(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100621 } else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100622 A64EncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100623 if (kind == kFmtShift) {
624 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100625 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100626 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100627
628 LOG(FATAL) << "Unexpected encoding operand count";
629 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100630}
631
Zheng Xucedee472014-07-01 09:53:22 +0800632LIR* Arm64Mir2Lir::OpRegRegExtend(OpKind op, RegStorage r_dest_src1, RegStorage r_src2,
633 A64RegExtEncodings ext, uint8_t amount) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100634 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
635 A64Opcode opcode = kA64Brk1d;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100636
637 switch (op) {
638 case kOpCmn:
639 opcode = kA64Cmn3Rre;
640 break;
641 case kOpCmp:
642 opcode = kA64Cmp3Rre;
643 break;
Zheng Xucedee472014-07-01 09:53:22 +0800644 case kOpAdd:
645 // Note: intentional fallthrough
646 case kOpSub:
647 return OpRegRegRegExtend(op, r_dest_src1, r_dest_src1, r_src2, ext, amount);
648 break;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100649 default:
650 LOG(FATAL) << "Bad Opcode: " << opcode;
651 break;
652 }
653
654 DCHECK(!IsPseudoLirOp(opcode));
655 if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100656 A64EncodingKind kind = EncodingMap[opcode].field_loc[2].kind;
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100657 if (kind == kFmtExtend) {
Zheng Xucedee472014-07-01 09:53:22 +0800658 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(),
659 EncodeExtend(ext, amount));
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100660 }
661 }
662
663 LOG(FATAL) << "Unexpected encoding operand count";
664 return NULL;
665}
666
Matteo Franchin43ec8732014-03-31 15:00:14 +0100667LIR* Arm64Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100668 /* RegReg operations with SP in first parameter need extended register instruction form.
Zheng Xucedee472014-07-01 09:53:22 +0800669 * Only CMN, CMP, ADD & SUB instructions are implemented.
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100670 */
Zheng Xubaa7c882014-06-30 14:26:50 +0800671 if (r_dest_src1 == rs_sp) {
Zheng Xucedee472014-07-01 09:53:22 +0800672 return OpRegRegExtend(op, r_dest_src1, r_src2, kA64Uxtx, 0);
Stuart Monteithf8ec48e2014-06-06 17:05:08 +0100673 } else {
674 return OpRegRegShift(op, r_dest_src1, r_src2, ENCODE_NO_SHIFT);
675 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100676}
677
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700678LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
679 MoveType move_type) {
680 UNUSED(r_dest, r_base, offset, move_type);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100681 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700682 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100683}
684
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700685LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src,
686 MoveType move_type) {
687 UNUSED(r_base, offset, r_src, move_type);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100688 UNIMPLEMENTED(FATAL);
689 return nullptr;
690}
691
692LIR* Arm64Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700693 UNUSED(op, cc, r_dest, r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100694 LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700695 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100696}
697
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100698LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
699 RegStorage r_src2, int shift) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100700 A64Opcode opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100701
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100702 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100703 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100704 opcode = kA64Add4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100705 break;
706 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100707 opcode = kA64Sub4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100708 break;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100709 // case kOpRsub:
710 // opcode = kA64RsubWWW;
711 // break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100712 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100713 opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100714 break;
715 case kOpAnd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100716 opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100717 break;
718 case kOpXor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100719 opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100720 break;
721 case kOpMul:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100722 opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100723 break;
724 case kOpDiv:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100725 opcode = kA64Sdiv3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100726 break;
727 case kOpOr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100728 opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100729 break;
730 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100731 opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100732 break;
733 case kOpLsl:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100734 opcode = kA64Lsl3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100735 break;
736 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100737 opcode = kA64Lsr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100738 break;
739 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100740 opcode = kA64Asr3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100741 break;
742 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100743 opcode = kA64Ror3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100744 break;
745 default:
746 LOG(FATAL) << "Bad opcode: " << op;
747 break;
748 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100749
750 // The instructions above belong to two kinds:
751 // - 4-operands instructions, where the last operand is a shift/extend immediate,
752 // - 3-operands instructions with no shift/extend.
Matteo Franchin4163c532014-07-15 15:20:27 +0100753 A64Opcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100754 CHECK_EQ(r_dest.Is64Bit(), r_src1.Is64Bit());
755 CHECK_EQ(r_dest.Is64Bit(), r_src2.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100756 if (EncodingMap[opcode].flags & IS_QUAD_OP) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +0100757 DCHECK(!IsExtendEncoding(shift));
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100758 return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), shift);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100759 } else {
760 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100761 DCHECK_EQ(shift, ENCODE_NO_SHIFT);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100762 return NewLIR3(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100763 }
764}
765
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700766LIR* Arm64Mir2Lir::OpRegRegRegExtend(OpKind op, RegStorage r_dest, RegStorage r_src1,
767 RegStorage r_src2, A64RegExtEncodings ext, uint8_t amount) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100768 A64Opcode opcode = kA64Brk1d;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700769
770 switch (op) {
771 case kOpAdd:
772 opcode = kA64Add4RRre;
773 break;
774 case kOpSub:
775 opcode = kA64Sub4RRre;
776 break;
777 default:
Ian Rogers2c4257b2014-10-24 14:20:06 -0700778 UNIMPLEMENTED(FATAL) << "Unimplemented opcode: " << op;
779 UNREACHABLE();
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700780 }
Matteo Franchin4163c532014-07-15 15:20:27 +0100781 A64Opcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700782
783 if (r_dest.Is64Bit()) {
784 CHECK(r_src1.Is64Bit());
785
786 // dest determines whether the op is wide or not. Up-convert src2 when necessary.
787 // Note: this is not according to aarch64 specifications, but our encoding.
788 if (!r_src2.Is64Bit()) {
789 r_src2 = As64BitReg(r_src2);
790 }
791 } else {
792 CHECK(!r_src1.Is64Bit());
793 CHECK(!r_src2.Is64Bit());
794 }
795
796 // Sanity checks.
797 // 1) Amount is in the range 0..4
798 CHECK_LE(amount, 4);
799
800 return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(),
801 EncodeExtend(ext, amount));
802}
803
Matteo Franchin43ec8732014-03-31 15:00:14 +0100804LIR* Arm64Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100805 return OpRegRegRegShift(op, r_dest, r_src1, r_src2, ENCODE_NO_SHIFT);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100806}
807
808LIR* Arm64Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800809 return OpRegRegImm64(op, r_dest, r_src1, static_cast<int64_t>(value));
810}
811
812LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100813 LIR* res;
814 bool neg = (value < 0);
buzbeeb504d2f2014-09-26 15:09:06 -0700815 uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
Matteo Franchin4163c532014-07-15 15:20:27 +0100816 A64Opcode opcode = kA64Brk1d;
817 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinc763e352014-07-04 12:53:27 +0100818 bool is_logical = false;
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100819 bool is_wide = r_dest.Is64Bit();
Matteo Franchin4163c532014-07-15 15:20:27 +0100820 A64Opcode wide = (is_wide) ? WIDE(0) : UNWIDE(0);
Andreas Gampe9f975bf2014-06-18 17:45:32 -0700821 int info = 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100822
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100823 switch (op) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100824 case kOpLsl: {
825 // "lsl w1, w2, #imm" is an alias of "ubfm w1, w2, #(-imm MOD 32), #(31-imm)"
Zheng Xu2d41a652014-06-09 11:05:31 +0800826 // and "lsl x1, x2, #imm" of "ubfm x1, x2, #(-imm MOD 64), #(63-imm)".
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100827 // For now, we just use ubfm directly.
Zheng Xu2d41a652014-06-09 11:05:31 +0800828 int max_value = (is_wide) ? 63 : 31;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100829 return NewLIR4(kA64Ubfm4rrdd | wide, r_dest.GetReg(), r_src1.GetReg(),
Zheng Xu2d41a652014-06-09 11:05:31 +0800830 (-value) & max_value, max_value - value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100831 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100832 case kOpLsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100833 return NewLIR3(kA64Lsr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100834 case kOpAsr:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100835 return NewLIR3(kA64Asr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100836 case kOpRor:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100837 // "ror r1, r2, #imm" is an alias of "extr r1, r2, r2, #imm".
838 // For now, we just use extr directly.
839 return NewLIR4(kA64Extr4rrrd | wide, r_dest.GetReg(), r_src1.GetReg(), r_src1.GetReg(),
840 value);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100841 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100842 neg = !neg;
Ian Rogersfc787ec2014-10-09 21:56:44 -0700843 FALLTHROUGH_INTENDED;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100844 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100845 // Add and sub below read/write sp rather than xzr.
846 if (abs_value < 0x1000) {
847 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
848 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value, 0);
849 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
850 opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT;
851 return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100852 } else {
Vladimir Marko903989d2014-07-01 17:21:18 +0100853 alt_opcode = (op == kOpAdd) ? kA64Add4RRre : kA64Sub4RRre;
Andreas Gampe47b31aa2014-06-19 01:10:07 -0700854 info = EncodeExtend(is_wide ? kA64Uxtx : kA64Uxtw, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100855 }
856 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100857 case kOpAdc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100858 alt_opcode = kA64Adc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100859 break;
860 case kOpSbc:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100861 alt_opcode = kA64Sbc3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100862 break;
863 case kOpOr:
Matteo Franchinc763e352014-07-04 12:53:27 +0100864 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100865 opcode = kA64Orr3Rrl;
866 alt_opcode = kA64Orr4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100867 break;
868 case kOpAnd:
Matteo Franchinc763e352014-07-04 12:53:27 +0100869 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100870 opcode = kA64And3Rrl;
871 alt_opcode = kA64And4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100872 break;
873 case kOpXor:
Matteo Franchinc763e352014-07-04 12:53:27 +0100874 is_logical = true;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100875 opcode = kA64Eor3Rrl;
876 alt_opcode = kA64Eor4rrro;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100877 break;
878 case kOpMul:
879 // TUNING: power of 2, shift & add
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100880 alt_opcode = kA64Mul3rrr;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100881 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100882 default:
883 LOG(FATAL) << "Bad opcode: " << op;
884 }
885
Matteo Franchinc763e352014-07-04 12:53:27 +0100886 if (is_logical) {
887 int log_imm = EncodeLogicalImmediate(is_wide, value);
888 if (log_imm >= 0) {
889 return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
Zheng Xue2eb29e2014-06-12 10:22:33 +0800890 } else {
Matteo Franchinc763e352014-07-04 12:53:27 +0100891 // When the immediate is either 0 or ~0, the logical operation can be trivially reduced
892 // to a - possibly negated - assignment.
893 if (value == 0) {
894 switch (op) {
895 case kOpOr:
896 case kOpXor:
897 // Or/Xor by zero reduces to an assignment.
898 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), r_src1.GetReg());
899 default:
900 // And by zero reduces to a `mov rdest, xzr'.
901 DCHECK(op == kOpAnd);
902 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), (is_wide) ? rxzr : rwzr);
903 }
904 } else if (value == INT64_C(-1)
905 || (!is_wide && static_cast<uint32_t>(value) == ~UINT32_C(0))) {
906 switch (op) {
907 case kOpAnd:
908 // And by -1 reduces to an assignment.
909 return NewLIR2(kA64Mov2rr | wide, r_dest.GetReg(), r_src1.GetReg());
910 case kOpXor:
911 // Xor by -1 reduces to an `mvn rdest, rsrc'.
912 return NewLIR2(kA64Mvn2rr | wide, r_dest.GetReg(), r_src1.GetReg());
913 default:
914 // Or by -1 reduces to a `mvn rdest, xzr'.
915 DCHECK(op == kOpOr);
916 return NewLIR2(kA64Mvn2rr | wide, r_dest.GetReg(), (is_wide) ? rxzr : rwzr);
917 }
918 }
Zheng Xue2eb29e2014-06-12 10:22:33 +0800919 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100920 }
Matteo Franchinc763e352014-07-04 12:53:27 +0100921
922 RegStorage r_scratch;
923 if (is_wide) {
924 r_scratch = AllocTempWide();
925 LoadConstantWide(r_scratch, value);
926 } else {
927 r_scratch = AllocTemp();
928 LoadConstant(r_scratch, value);
929 }
930 if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
931 res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info);
932 else
933 res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
934 FreeTemp(r_scratch);
935 return res;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100936}
937
Matteo Franchin43ec8732014-03-31 15:00:14 +0100938LIR* Arm64Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100939 return OpRegImm64(op, r_dest_src1, static_cast<int64_t>(value));
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100940}
941
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100942LIR* Arm64Mir2Lir::OpRegImm64(OpKind op, RegStorage r_dest_src1, int64_t value) {
Matteo Franchin4163c532014-07-15 15:20:27 +0100943 A64Opcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0);
944 A64Opcode opcode = kA64Brk1d;
945 A64Opcode neg_opcode = kA64Brk1d;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100946 bool shift;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100947 bool neg = (value < 0);
buzbeeb504d2f2014-09-26 15:09:06 -0700948 uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100949
950 if (LIKELY(abs_value < 0x1000)) {
951 // abs_value is a 12-bit immediate.
952 shift = false;
953 } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
954 // abs_value is a shifted 12-bit immediate.
955 shift = true;
956 abs_value >>= 12;
Zheng Xue2eb29e2014-06-12 10:22:33 +0800957 } else if (LIKELY(abs_value < 0x1000000 && (op == kOpAdd || op == kOpSub))) {
958 // Note: It is better to use two ADD/SUB instead of loading a number to a temp register.
959 // This works for both normal registers and SP.
960 // For a frame size == 0x2468, it will be encoded as:
961 // sub sp, #0x2000
962 // sub sp, #0x468
963 if (neg) {
964 op = (op == kOpAdd) ? kOpSub : kOpAdd;
965 }
966 OpRegImm64(op, r_dest_src1, abs_value & (~INT64_C(0xfff)));
967 return OpRegImm64(op, r_dest_src1, abs_value & 0xfff);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100968 } else {
Zheng Xue2eb29e2014-06-12 10:22:33 +0800969 RegStorage r_tmp;
970 LIR* res;
971 if (IS_WIDE(wide)) {
972 r_tmp = AllocTempWide();
973 res = LoadConstantWide(r_tmp, value);
974 } else {
975 r_tmp = AllocTemp();
976 res = LoadConstant(r_tmp, value);
977 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100978 OpRegReg(op, r_dest_src1, r_tmp);
979 FreeTemp(r_tmp);
980 return res;
981 }
982
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100983 switch (op) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100984 case kOpAdd:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100985 neg_opcode = kA64Sub4RRdT;
986 opcode = kA64Add4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100987 break;
988 case kOpSub:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100989 neg_opcode = kA64Add4RRdT;
990 opcode = kA64Sub4RRdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100991 break;
992 case kOpCmp:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100993 neg_opcode = kA64Cmn3RdT;
994 opcode = kA64Cmp3RdT;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100995 break;
996 default:
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100997 LOG(FATAL) << "Bad op-kind in OpRegImm: " << op;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100998 break;
999 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001000
1001 if (UNLIKELY(neg))
1002 opcode = neg_opcode;
1003
1004 if (EncodingMap[opcode].flags & IS_QUAD_OP)
1005 return NewLIR4(opcode | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), abs_value,
1006 (shift) ? 1 : 0);
1007 else
1008 return NewLIR3(opcode | wide, r_dest_src1.GetReg(), abs_value, (shift) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001009}
1010
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001011int Arm64Mir2Lir::EncodeShift(int shift_type, int amount) {
Zheng Xucedee472014-07-01 09:53:22 +08001012 DCHECK_EQ(shift_type & 0x3, shift_type);
1013 DCHECK_EQ(amount & 0x3f, amount);
Matteo Franchinc61b3c92014-06-18 11:52:47 +01001014 return ((shift_type & 0x3) << 7) | (amount & 0x3f);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001015}
1016
1017int Arm64Mir2Lir::EncodeExtend(int extend_type, int amount) {
Zheng Xucedee472014-07-01 09:53:22 +08001018 DCHECK_EQ(extend_type & 0x7, extend_type);
1019 DCHECK_EQ(amount & 0x7, amount);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001020 return (1 << 6) | ((extend_type & 0x7) << 3) | (amount & 0x7);
1021}
1022
1023bool Arm64Mir2Lir::IsExtendEncoding(int encoded_value) {
1024 return ((1 << 6) & encoded_value) != 0;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001025}
1026
1027LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001028 int scale, OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001029 LIR* load;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001030 int expected_scale = 0;
Matteo Franchin4163c532014-07-15 15:20:27 +01001031 A64Opcode opcode = kA64Brk1d;
Andreas Gampe4b537a82014-06-30 22:24:53 -07001032 r_base = Check64BitReg(r_base);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001033
1034 // TODO(Arm64): The sign extension of r_index should be carried out by using an extended
1035 // register offset load (rather than doing the sign extension in a separate instruction).
1036 if (r_index.Is32Bit()) {
1037 // Assemble: ``sxtw xN, wN''.
1038 r_index = As64BitReg(r_index);
1039 NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31);
1040 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001041
1042 if (r_dest.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001043 if (r_dest.IsDouble()) {
1044 DCHECK(size == k64 || size == kDouble);
1045 expected_scale = 3;
Matteo Franchin4163c532014-07-15 15:20:27 +01001046 opcode = WIDE(kA64Ldr4fXxG);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001047 } else {
1048 DCHECK(r_dest.IsSingle());
1049 DCHECK(size == k32 || size == kSingle);
1050 expected_scale = 2;
1051 opcode = kA64Ldr4fXxG;
1052 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001053
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001054 DCHECK(scale == 0 || scale == expected_scale);
1055 return NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
1056 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001057 }
1058
1059 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001060 case kDouble:
1061 case kWord:
1062 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001063 r_dest = Check64BitReg(r_dest);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001064 opcode = WIDE(kA64Ldr4rXxG);
1065 expected_scale = 3;
1066 break;
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001067 case kReference:
Andreas Gampef6815702015-01-20 09:53:48 -08001068 r_dest = As32BitReg(r_dest);
1069 FALLTHROUGH_INTENDED;
1070 case kSingle: // Intentional fall-through.
1071 case k32:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001072 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001073 opcode = kA64Ldr4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001074 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001075 break;
1076 case kUnsignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001077 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001078 opcode = kA64Ldrh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001079 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001080 break;
1081 case kSignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001082 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001083 opcode = kA64Ldrsh4rXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001084 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001085 break;
1086 case kUnsignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001087 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001088 opcode = kA64Ldrb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001089 break;
1090 case kSignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001091 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001092 opcode = kA64Ldrsb3rXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001093 break;
1094 default:
1095 LOG(FATAL) << "Bad size: " << size;
1096 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001097
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001098 if (UNLIKELY(expected_scale == 0)) {
1099 // This is a tertiary op (e.g. ldrb, ldrsb), it does not not support scale.
1100 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001101 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001102 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001103 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001104 DCHECK(scale == 0 || scale == expected_scale);
1105 load = NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(),
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001106 (scale != 0) ? 1 : 0);
1107 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001108
1109 return load;
1110}
1111
1112LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001113 int scale, OpSize size) {
1114 LIR* store;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001115 int expected_scale = 0;
Matteo Franchin4163c532014-07-15 15:20:27 +01001116 A64Opcode opcode = kA64Brk1d;
Andreas Gampe4b537a82014-06-30 22:24:53 -07001117 r_base = Check64BitReg(r_base);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +01001118
1119 // TODO(Arm64): The sign extension of r_index should be carried out by using an extended
1120 // register offset store (rather than doing the sign extension in a separate instruction).
1121 if (r_index.Is32Bit()) {
1122 // Assemble: ``sxtw xN, wN''.
1123 r_index = As64BitReg(r_index);
1124 NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31);
1125 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001126
1127 if (r_src.IsFloat()) {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001128 if (r_src.IsDouble()) {
1129 DCHECK(size == k64 || size == kDouble);
1130 expected_scale = 3;
Matteo Franchin4163c532014-07-15 15:20:27 +01001131 opcode = WIDE(kA64Str4fXxG);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001132 } else {
1133 DCHECK(r_src.IsSingle());
1134 DCHECK(size == k32 || size == kSingle);
1135 expected_scale = 2;
1136 opcode = kA64Str4fXxG;
1137 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001138
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001139 DCHECK(scale == 0 || scale == expected_scale);
1140 return NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
1141 (scale != 0) ? 1 : 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001142 }
1143
1144 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001145 case kDouble: // Intentional fall-trough.
1146 case kWord: // Intentional fall-trough.
1147 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001148 r_src = Check64BitReg(r_src);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001149 opcode = WIDE(kA64Str4rXxG);
1150 expected_scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001151 break;
Matteo Franchin255e0142014-07-04 13:50:41 +01001152 case kReference:
Andreas Gampef6815702015-01-20 09:53:48 -08001153 r_src = As32BitReg(r_src);
1154 FALLTHROUGH_INTENDED;
1155 case kSingle: // Intentional fall-trough.
1156 case k32:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001157 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001158 opcode = kA64Str4rXxG;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001159 expected_scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001160 break;
1161 case kUnsignedHalf:
Matteo Franchin43ec8732014-03-31 15:00:14 +01001162 case kSignedHalf:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001163 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001164 opcode = kA64Strh4wXxd;
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001165 expected_scale = 1;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001166 break;
1167 case kUnsignedByte:
Matteo Franchin43ec8732014-03-31 15:00:14 +01001168 case kSignedByte:
Andreas Gampe4b537a82014-06-30 22:24:53 -07001169 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001170 opcode = kA64Strb3wXx;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001171 break;
1172 default:
1173 LOG(FATAL) << "Bad size: " << size;
1174 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001175
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001176 if (UNLIKELY(expected_scale == 0)) {
1177 // This is a tertiary op (e.g. strb), it does not not support scale.
1178 DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001179 DCHECK_EQ(scale, 0);
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001180 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001181 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001182 store = NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(),
1183 (scale != 0) ? 1 : 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001184 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001185
1186 return store;
1187}
1188
1189/*
1190 * Load value from base + displacement. Optionally perform null check
1191 * on base (which must have an associated s_reg and MIR). If not
1192 * performing null check, incoming MIR can be null.
1193 */
1194LIR* Arm64Mir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Vladimir Marko3bf7c602014-05-07 14:55:43 +01001195 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001196 LIR* load = NULL;
Matteo Franchin4163c532014-07-15 15:20:27 +01001197 A64Opcode opcode = kA64Brk1d;
1198 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001199 int scale = 0;
1200
Matteo Franchin43ec8732014-03-31 15:00:14 +01001201 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001202 case kDouble: // Intentional fall-through.
1203 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001204 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001205 r_dest = Check64BitReg(r_dest);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001206 scale = 3;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001207 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001208 DCHECK(r_dest.IsDouble());
Matteo Franchin4163c532014-07-15 15:20:27 +01001209 opcode = WIDE(kA64Ldr3fXD);
1210 alt_opcode = WIDE(kA64Ldur3fXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001211 } else {
Matteo Franchin0955f7e2014-05-23 17:32:52 +01001212 opcode = WIDE(kA64Ldr3rXD);
1213 alt_opcode = WIDE(kA64Ldur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001214 }
1215 break;
Matteo Franchin255e0142014-07-04 13:50:41 +01001216 case kReference:
Andreas Gampef6815702015-01-20 09:53:48 -08001217 r_dest = As32BitReg(r_dest);
1218 FALLTHROUGH_INTENDED;
1219 case kSingle: // Intentional fall-through.
1220 case k32:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001221 r_dest = Check32BitReg(r_dest);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001222 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001223 if (r_dest.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001224 DCHECK(r_dest.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001225 opcode = kA64Ldr3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001226 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001227 opcode = kA64Ldr3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001228 }
1229 break;
1230 case kUnsignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001231 scale = 1;
1232 opcode = kA64Ldrh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001233 break;
1234 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001235 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001236 opcode = kA64Ldrsh3rXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001237 break;
1238 case kUnsignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001239 opcode = kA64Ldrb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001240 break;
1241 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001242 opcode = kA64Ldrsb3rXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001243 break;
1244 default:
1245 LOG(FATAL) << "Bad size: " << size;
1246 }
1247
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001248 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1249 int scaled_disp = displacement >> scale;
1250 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1251 // Can use scaled load.
1252 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), scaled_disp);
1253 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1254 // Can use unscaled load.
1255 load = NewLIR3(alt_opcode, r_dest.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001256 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001257 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001258 // TODO: cleaner support for index/displacement registers? Not a reference, but must match width.
1259 RegStorage r_scratch = AllocTempWide();
1260 LoadConstantWide(r_scratch, displacement);
Andreas Gampe582f5412015-01-20 18:06:47 -08001261 load = LoadBaseIndexed(r_base, r_scratch,
1262 (size == kReference) ? As64BitReg(r_dest) : r_dest,
1263 0, size);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001264 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
Matteo Franchin43ec8732014-03-31 15:00:14 +01001290LIR* Arm64Mir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001291 OpSize size) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001292 LIR* store = NULL;
Matteo Franchin4163c532014-07-15 15:20:27 +01001293 A64Opcode opcode = kA64Brk1d;
1294 A64Opcode alt_opcode = kA64Brk1d;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001295 int scale = 0;
1296
Matteo Franchin43ec8732014-03-31 15:00:14 +01001297 switch (size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001298 case kDouble: // Intentional fall-through.
1299 case kWord: // Intentional fall-through.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001300 case k64:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001301 r_src = Check64BitReg(r_src);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001302 scale = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001303 if (r_src.IsFloat()) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001304 DCHECK(r_src.IsDouble());
Matteo Franchin4163c532014-07-15 15:20:27 +01001305 opcode = WIDE(kA64Str3fXD);
1306 alt_opcode = WIDE(kA64Stur3fXd);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001307 } else {
Matteo Franchin4163c532014-07-15 15:20:27 +01001308 opcode = WIDE(kA64Str3rXD);
1309 alt_opcode = WIDE(kA64Stur3rXd);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001310 }
1311 break;
Matteo Franchin255e0142014-07-04 13:50:41 +01001312 case kReference:
Andreas Gampef6815702015-01-20 09:53:48 -08001313 r_src = As32BitReg(r_src);
1314 FALLTHROUGH_INTENDED;
1315 case kSingle: // Intentional fall-through.
1316 case k32:
Andreas Gampe3c12c512014-06-24 18:46:29 +00001317 r_src = Check32BitReg(r_src);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001318 scale = 2;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001319 if (r_src.IsFloat()) {
1320 DCHECK(r_src.IsSingle());
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001321 opcode = kA64Str3fXD;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001322 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001323 opcode = kA64Str3rXD;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001324 }
1325 break;
1326 case kUnsignedHalf:
1327 case kSignedHalf:
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001328 scale = 1;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001329 opcode = kA64Strh3wXF;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001330 break;
1331 case kUnsignedByte:
1332 case kSignedByte:
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001333 opcode = kA64Strb3wXd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001334 break;
1335 default:
1336 LOG(FATAL) << "Bad size: " << size;
1337 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001338
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001339 bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0;
1340 int scaled_disp = displacement >> scale;
1341 if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) {
1342 // Can use scaled store.
1343 store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), scaled_disp);
1344 } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) {
1345 // Can use unscaled store.
1346 store = NewLIR3(alt_opcode, r_src.GetReg(), r_base.GetReg(), displacement);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001347 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001348 // Use long sequence.
buzbee33ae5582014-06-12 14:56:32 -07001349 RegStorage r_scratch = AllocTempWide();
1350 LoadConstantWide(r_scratch, displacement);
Andreas Gampe582f5412015-01-20 18:06:47 -08001351 store = StoreBaseIndexed(r_base, r_scratch,
1352 (size == kReference) ? As64BitReg(r_src) : r_src,
1353 0, size);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001354 FreeTemp(r_scratch);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001355 }
1356
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001357 // TODO: In future, may need to differentiate Dalvik & spill accesses.
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001358 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001359 DCHECK_EQ(r_base, rs_sp);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001360 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
Matteo Franchin43ec8732014-03-31 15:00:14 +01001361 }
1362 return store;
1363}
1364
Andreas Gampe3c12c512014-06-24 18:46:29 +00001365LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
1366 OpSize size, VolatileKind is_volatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001367 // TODO: This should generate a release store and no barriers.
Andreas Gampe3c12c512014-06-24 18:46:29 +00001368 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001369 // Ensure that prior accesses become visible to other threads first.
1370 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001371 }
1372
Vladimir Marko674744e2014-04-24 15:18:26 +01001373 // StoreBaseDisp() will emit correct insn for atomic store on arm64
1374 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
Andreas Gampe3c12c512014-06-24 18:46:29 +00001375
1376 LIR* store = StoreBaseDispBody(r_base, displacement, r_src, size);
1377
1378 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001379 // Preserve order with respect to any subsequent volatile loads.
1380 // We need StoreLoad, but that generally requires the most expensive barrier.
1381 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001382 }
1383
1384 return store;
Vladimir Marko674744e2014-04-24 15:18:26 +01001385}
1386
Matteo Franchin43ec8732014-03-31 15:00:14 +01001387LIR* Arm64Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001388 UNUSED(r_dest, r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001389 LOG(FATAL) << "Unexpected use of OpFpRegCopy for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001390 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +01001391}
1392
Matteo Franchin43ec8732014-03-31 15:00:14 +01001393LIR* Arm64Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001394 UNUSED(op, r_base, disp);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001395 LOG(FATAL) << "Unexpected use of OpMem for Arm64";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001396 UNREACHABLE();
Matteo Franchin43ec8732014-03-31 15:00:14 +01001397}
1398
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001399LIR* Arm64Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt,
1400 QuickEntrypointEnum trampoline ATTRIBUTE_UNUSED) {
1401 // The address of the trampoline is already loaded into r_tgt.
Andreas Gampe98430592014-07-27 19:44:50 -07001402 return OpReg(op, r_tgt);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001403}
1404
1405} // namespace art