| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1 | /* | 
 | 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" | 
| buzbee | b5860fb | 2014-06-21 15:31:01 -0700 | [diff] [blame] | 20 | #include "dex/reg_storage_eq.h" | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 21 |  | 
 | 22 | namespace art { | 
 | 23 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 24 | /* This file contains codegen for the A64 ISA. */ | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 25 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 26 | static int32_t EncodeImmSingle(uint32_t bits) { | 
 | 27 |   /* | 
 | 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 Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 37 |     return -1; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 38 |  | 
 | 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 Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 56 | } | 
 | 57 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 58 | static int32_t EncodeImmDouble(uint64_t bits) { | 
 | 59 |   /* | 
 | 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 Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 70 |     return -1; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 71 |  | 
 | 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 Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 88 | } | 
 | 89 |  | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 90 | LIR* Arm64Mir2Lir::LoadFPConstantValue(RegStorage r_dest, int32_t value) { | 
 | 91 |   DCHECK(r_dest.IsSingle()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 92 |   if (value == 0) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 93 |     return NewLIR2(kA64Fmov2sw, r_dest.GetReg(), rwzr); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 94 |   } else { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 95 |     int32_t encoded_imm = EncodeImmSingle((uint32_t)value); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 96 |     if (encoded_imm >= 0) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 97 |       return NewLIR2(kA64Fmov2fI, r_dest.GetReg(), encoded_imm); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 98 |     } | 
 | 99 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 100 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 101 |   LIR* data_target = ScanLiteralPool(literal_list_, value, 0); | 
 | 102 |   if (data_target == NULL) { | 
| Andreas Gampe | f987927 | 2014-06-18 23:19:07 -0700 | [diff] [blame] | 103 |     // Wide, as we need 8B alignment. | 
 | 104 |     data_target = AddWideData(&literal_list_, value, 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 105 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 106 |  | 
| Vladimir Marko | 8dea81c | 2014-06-06 14:50:36 +0100 | [diff] [blame] | 107 |   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 108 |   LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kA64Ldr2fp, | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 109 |                             r_dest.GetReg(), 0, 0, 0, 0, data_target); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 110 |   AppendLIR(load_pc_rel); | 
 | 111 |   return load_pc_rel; | 
 | 112 | } | 
 | 113 |  | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 114 | LIR* Arm64Mir2Lir::LoadFPConstantValueWide(RegStorage r_dest, int64_t value) { | 
 | 115 |   DCHECK(r_dest.IsDouble()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 116 |   if (value == 0) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 117 |     return NewLIR2(kA64Fmov2Sx, r_dest.GetReg(), rxzr); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 118 |   } else { | 
 | 119 |     int32_t encoded_imm = EncodeImmDouble(value); | 
 | 120 |     if (encoded_imm >= 0) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 121 |       return NewLIR2(FWIDE(kA64Fmov2fI), r_dest.GetReg(), encoded_imm); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 122 |     } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 123 |   } | 
 | 124 |  | 
 | 125 |   // No short form - load from the literal pool. | 
 | 126 |   int32_t val_lo = Low32Bits(value); | 
 | 127 |   int32_t val_hi = High32Bits(value); | 
 | 128 |   LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi); | 
 | 129 |   if (data_target == NULL) { | 
 | 130 |     data_target = AddWideData(&literal_list_, val_lo, val_hi); | 
 | 131 |   } | 
 | 132 |  | 
| Vladimir Marko | 8dea81c | 2014-06-06 14:50:36 +0100 | [diff] [blame] | 133 |   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 134 |   LIR* load_pc_rel = RawLIR(current_dalvik_offset_, FWIDE(kA64Ldr2fp), | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 135 |                             r_dest.GetReg(), 0, 0, 0, 0, data_target); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 136 |   AppendLIR(load_pc_rel); | 
 | 137 |   return load_pc_rel; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 138 | } | 
 | 139 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 140 | static int CountLeadingZeros(bool is_wide, uint64_t value) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 141 |   return (is_wide) ? __builtin_clzll(value) : __builtin_clz((uint32_t)value); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 142 | } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 143 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 144 | static int CountTrailingZeros(bool is_wide, uint64_t value) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 145 |   return (is_wide) ? __builtin_ctzll(value) : __builtin_ctz((uint32_t)value); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 146 | } | 
 | 147 |  | 
 | 148 | static int CountSetBits(bool is_wide, uint64_t value) { | 
 | 149 |   return ((is_wide) ? | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 150 |           __builtin_popcountll(value) : __builtin_popcount((uint32_t)value)); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 151 | } | 
 | 152 |  | 
 | 153 | /** | 
 | 154 |  * @brief Try encoding an immediate in the form required by logical instructions. | 
 | 155 |  * | 
 | 156 |  * @param is_wide Whether @p value is a 64-bit (as opposed to 32-bit) value. | 
 | 157 |  * @param value An integer to be encoded. This is interpreted as 64-bit if @p is_wide is true and as | 
 | 158 |  *   32-bit if @p is_wide is false. | 
 | 159 |  * @return A non-negative integer containing the encoded immediate or -1 if the encoding failed. | 
 | 160 |  * @note This is the inverse of Arm64Mir2Lir::DecodeLogicalImmediate(). | 
 | 161 |  */ | 
 | 162 | int Arm64Mir2Lir::EncodeLogicalImmediate(bool is_wide, uint64_t value) { | 
 | 163 |   unsigned n, imm_s, imm_r; | 
 | 164 |  | 
 | 165 |   // Logical immediates are encoded using parameters n, imm_s and imm_r using | 
 | 166 |   // the following table: | 
 | 167 |   // | 
 | 168 |   //  N   imms    immr    size        S             R | 
 | 169 |   //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr) | 
 | 170 |   //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr) | 
 | 171 |   //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr) | 
 | 172 |   //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr) | 
 | 173 |   //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr) | 
 | 174 |   //  0  11110s  xxxxxr     2    UInt(s)       UInt(r) | 
 | 175 |   // (s bits must not be all set) | 
 | 176 |   // | 
 | 177 |   // A pattern is constructed of size bits, where the least significant S+1 | 
 | 178 |   // bits are set. The pattern is rotated right by R, and repeated across a | 
 | 179 |   // 32 or 64-bit value, depending on destination register width. | 
 | 180 |   // | 
 | 181 |   // To test if an arbitary immediate can be encoded using this scheme, an | 
 | 182 |   // iterative algorithm is used. | 
 | 183 |   // | 
 | 184 |  | 
 | 185 |   // 1. If the value has all set or all clear bits, it can't be encoded. | 
 | 186 |   if (value == 0 || value == ~UINT64_C(0) || | 
 | 187 |       (!is_wide && (uint32_t)value == ~UINT32_C(0))) { | 
 | 188 |     return -1; | 
 | 189 |   } | 
 | 190 |  | 
 | 191 |   unsigned lead_zero  = CountLeadingZeros(is_wide, value); | 
 | 192 |   unsigned lead_one   = CountLeadingZeros(is_wide, ~value); | 
 | 193 |   unsigned trail_zero = CountTrailingZeros(is_wide, value); | 
 | 194 |   unsigned trail_one  = CountTrailingZeros(is_wide, ~value); | 
 | 195 |   unsigned set_bits   = CountSetBits(is_wide, value); | 
 | 196 |  | 
 | 197 |   // The fixed bits in the immediate s field. | 
 | 198 |   // If width == 64 (X reg), start at 0xFFFFFF80. | 
 | 199 |   // If width == 32 (W reg), start at 0xFFFFFFC0, as the iteration for 64-bit | 
 | 200 |   // widths won't be executed. | 
 | 201 |   unsigned width = (is_wide) ? 64 : 32; | 
 | 202 |   int imm_s_fixed = (is_wide) ? -128 : -64; | 
 | 203 |   int imm_s_mask = 0x3f; | 
 | 204 |  | 
 | 205 |   for (;;) { | 
 | 206 |     // 2. If the value is two bits wide, it can be encoded. | 
 | 207 |     if (width == 2) { | 
 | 208 |       n = 0; | 
 | 209 |       imm_s = 0x3C; | 
 | 210 |       imm_r = (value & 3) - 1; | 
 | 211 |       break; | 
 | 212 |     } | 
 | 213 |  | 
 | 214 |     n = (width == 64) ? 1 : 0; | 
 | 215 |     imm_s = ((imm_s_fixed | (set_bits - 1)) & imm_s_mask); | 
 | 216 |     if ((lead_zero + set_bits) == width) { | 
 | 217 |       imm_r = 0; | 
 | 218 |     } else { | 
 | 219 |       imm_r = (lead_zero > 0) ? (width - trail_zero) : lead_one; | 
 | 220 |     } | 
 | 221 |  | 
 | 222 |     // 3. If the sum of leading zeros, trailing zeros and set bits is | 
 | 223 |     //    equal to the bit width of the value, it can be encoded. | 
 | 224 |     if (lead_zero + trail_zero + set_bits == width) { | 
 | 225 |       break; | 
 | 226 |     } | 
 | 227 |  | 
 | 228 |     // 4. If the sum of leading ones, trailing ones and unset bits in the | 
 | 229 |     //    value is equal to the bit width of the value, it can be encoded. | 
 | 230 |     if (lead_one + trail_one + (width - set_bits) == width) { | 
 | 231 |       break; | 
 | 232 |     } | 
 | 233 |  | 
 | 234 |     // 5. If the most-significant half of the bitwise value is equal to | 
 | 235 |     //    the least-significant half, return to step 2 using the | 
 | 236 |     //    least-significant half of the value. | 
 | 237 |     uint64_t mask = (UINT64_C(1) << (width >> 1)) - 1; | 
 | 238 |     if ((value & mask) == ((value >> (width >> 1)) & mask)) { | 
 | 239 |       width >>= 1; | 
 | 240 |       set_bits >>= 1; | 
 | 241 |       imm_s_fixed >>= 1; | 
 | 242 |       continue; | 
 | 243 |     } | 
 | 244 |  | 
 | 245 |     // 6. Otherwise, the value can't be encoded. | 
 | 246 |     return -1; | 
 | 247 |   } | 
 | 248 |  | 
 | 249 |   return (n << 12 | imm_r << 6 | imm_s); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 250 | } | 
 | 251 |  | 
 | 252 | bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 253 |   return false;  // (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 254 | } | 
 | 255 |  | 
 | 256 | bool Arm64Mir2Lir::InexpensiveConstantFloat(int32_t value) { | 
 | 257 |   return EncodeImmSingle(value) >= 0; | 
 | 258 | } | 
 | 259 |  | 
 | 260 | bool Arm64Mir2Lir::InexpensiveConstantLong(int64_t value) { | 
 | 261 |   return InexpensiveConstantInt(High32Bits(value)) && InexpensiveConstantInt(Low32Bits(value)); | 
 | 262 | } | 
 | 263 |  | 
 | 264 | bool Arm64Mir2Lir::InexpensiveConstantDouble(int64_t value) { | 
 | 265 |   return EncodeImmDouble(value) >= 0; | 
 | 266 | } | 
 | 267 |  | 
 | 268 | /* | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 269 |  * Load a immediate using one single instruction when possible; otherwise | 
 | 270 |  * use a pair of movz and movk instructions. | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 271 |  * | 
 | 272 |  * No additional register clobbering operation performed. Use this version when | 
 | 273 |  * 1) r_dest is freshly returned from AllocTemp or | 
 | 274 |  * 2) The codegen is under fixed register usage | 
 | 275 |  */ | 
 | 276 | LIR* Arm64Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) { | 
 | 277 |   LIR* res; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 278 |  | 
 | 279 |   if (r_dest.IsFloat()) { | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 280 |     return LoadFPConstantValue(r_dest, value); | 
 | 281 |   } | 
 | 282 |  | 
 | 283 |   if (r_dest.Is64Bit()) { | 
 | 284 |     return LoadConstantWide(r_dest, value); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 285 |   } | 
 | 286 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 287 |   // Loading SP/ZR with an immediate is not supported. | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 288 |   DCHECK(!A64_REG_IS_SP(r_dest.GetReg())); | 
 | 289 |   DCHECK(!A64_REG_IS_ZR(r_dest.GetReg())); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 290 |  | 
 | 291 |   // Compute how many movk, movz instructions are needed to load the value. | 
 | 292 |   uint16_t high_bits = High16Bits(value); | 
 | 293 |   uint16_t low_bits = Low16Bits(value); | 
 | 294 |  | 
 | 295 |   bool low_fast = ((uint16_t)(low_bits + 1) <= 1); | 
 | 296 |   bool high_fast = ((uint16_t)(high_bits + 1) <= 1); | 
 | 297 |  | 
 | 298 |   if (LIKELY(low_fast || high_fast)) { | 
 | 299 |     // 1 instruction is enough to load the immediate. | 
 | 300 |     if (LIKELY(low_bits == high_bits)) { | 
 | 301 |       // Value is either 0 or -1: we can just use wzr. | 
 | 302 |       ArmOpcode opcode = LIKELY(low_bits == 0) ? kA64Mov2rr : kA64Mvn2rr; | 
 | 303 |       res = NewLIR2(opcode, r_dest.GetReg(), rwzr); | 
 | 304 |     } else { | 
 | 305 |       uint16_t uniform_bits, useful_bits; | 
 | 306 |       int shift; | 
 | 307 |  | 
 | 308 |       if (LIKELY(high_fast)) { | 
 | 309 |         shift = 0; | 
 | 310 |         uniform_bits = high_bits; | 
 | 311 |         useful_bits = low_bits; | 
 | 312 |       } else { | 
 | 313 |         shift = 1; | 
 | 314 |         uniform_bits = low_bits; | 
 | 315 |         useful_bits = high_bits; | 
 | 316 |       } | 
 | 317 |  | 
 | 318 |       if (UNLIKELY(uniform_bits != 0)) { | 
 | 319 |         res = NewLIR3(kA64Movn3rdM, r_dest.GetReg(), ~useful_bits, shift); | 
 | 320 |       } else { | 
 | 321 |         res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), useful_bits, shift); | 
 | 322 |       } | 
 | 323 |     } | 
 | 324 |   } else { | 
 | 325 |     // movk, movz require 2 instructions. Try detecting logical immediates. | 
 | 326 |     int log_imm = EncodeLogicalImmediate(/*is_wide=*/false, value); | 
 | 327 |     if (log_imm >= 0) { | 
 | 328 |       res = NewLIR3(kA64Orr3Rrl, r_dest.GetReg(), rwzr, log_imm); | 
 | 329 |     } else { | 
 | 330 |       // Use 2 instructions. | 
 | 331 |       res = NewLIR3(kA64Movz3rdM, r_dest.GetReg(), low_bits, 0); | 
 | 332 |       NewLIR3(kA64Movk3rdM, r_dest.GetReg(), high_bits, 1); | 
 | 333 |     } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 334 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 335 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 336 |   return res; | 
 | 337 | } | 
 | 338 |  | 
| Matteo Franchin | c41e6dc | 2014-06-13 19:16:28 +0100 | [diff] [blame] | 339 | // TODO: clean up the names. LoadConstantWide() should really be LoadConstantNoClobberWide(). | 
 | 340 | LIR* Arm64Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) { | 
 | 341 |   // Maximum number of instructions to use for encoding the immediate. | 
 | 342 |   const int max_num_ops = 2; | 
 | 343 |  | 
 | 344 |   if (r_dest.IsFloat()) { | 
 | 345 |     return LoadFPConstantValueWide(r_dest, value); | 
 | 346 |   } | 
 | 347 |  | 
 | 348 |   DCHECK(r_dest.Is64Bit()); | 
 | 349 |  | 
 | 350 |   // Loading SP/ZR with an immediate is not supported. | 
 | 351 |   DCHECK(!A64_REG_IS_SP(r_dest.GetReg())); | 
 | 352 |   DCHECK(!A64_REG_IS_ZR(r_dest.GetReg())); | 
 | 353 |  | 
 | 354 |   if (LIKELY(value == INT64_C(0) || value == INT64_C(-1))) { | 
 | 355 |     // value is either 0 or -1: we can just use xzr. | 
 | 356 |     ArmOpcode opcode = LIKELY(value == 0) ? WIDE(kA64Mov2rr) : WIDE(kA64Mvn2rr); | 
 | 357 |     return NewLIR2(opcode, r_dest.GetReg(), rxzr); | 
 | 358 |   } | 
 | 359 |  | 
 | 360 |   // At least one in value's halfwords is not 0x0, nor 0xffff: find out how many. | 
 | 361 |   int num_0000_halfwords = 0; | 
 | 362 |   int num_ffff_halfwords = 0; | 
 | 363 |   uint64_t uvalue = static_cast<uint64_t>(value); | 
 | 364 |   for (int shift = 0; shift < 64; shift += 16) { | 
 | 365 |     uint16_t halfword = static_cast<uint16_t>(uvalue >> shift); | 
 | 366 |     if (halfword == 0) | 
 | 367 |       num_0000_halfwords++; | 
 | 368 |     else if (halfword == UINT16_C(0xffff)) | 
 | 369 |       num_ffff_halfwords++; | 
 | 370 |   } | 
 | 371 |   int num_fast_halfwords = std::max(num_0000_halfwords, num_ffff_halfwords); | 
 | 372 |  | 
 | 373 |   if (num_fast_halfwords < 3) { | 
 | 374 |     // A single movz/movn is not enough. Try the logical immediate route. | 
 | 375 |     int log_imm = EncodeLogicalImmediate(/*is_wide=*/true, value); | 
 | 376 |     if (log_imm >= 0) { | 
 | 377 |       return NewLIR3(WIDE(kA64Orr3Rrl), r_dest.GetReg(), rxzr, log_imm); | 
 | 378 |     } | 
 | 379 |   } | 
 | 380 |  | 
 | 381 |   if (num_fast_halfwords >= 4 - max_num_ops) { | 
 | 382 |     // We can encode the number using a movz/movn followed by one or more movk. | 
 | 383 |     ArmOpcode op; | 
 | 384 |     uint16_t background; | 
 | 385 |     LIR* res = nullptr; | 
 | 386 |  | 
 | 387 |     // Decide whether to use a movz or a movn. | 
 | 388 |     if (num_0000_halfwords >= num_ffff_halfwords) { | 
 | 389 |       op = WIDE(kA64Movz3rdM); | 
 | 390 |       background = 0; | 
 | 391 |     } else { | 
 | 392 |       op = WIDE(kA64Movn3rdM); | 
 | 393 |       background = 0xffff; | 
 | 394 |     } | 
 | 395 |  | 
 | 396 |     // Emit the first instruction (movz, movn). | 
 | 397 |     int shift; | 
 | 398 |     for (shift = 0; shift < 4; shift++) { | 
 | 399 |       uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4)); | 
 | 400 |       if (halfword != background) { | 
 | 401 |         res = NewLIR3(op, r_dest.GetReg(), halfword ^ background, shift); | 
 | 402 |         break; | 
 | 403 |       } | 
 | 404 |     } | 
 | 405 |  | 
 | 406 |     // Emit the movk instructions. | 
 | 407 |     for (shift++; shift < 4; shift++) { | 
 | 408 |       uint16_t halfword = static_cast<uint16_t>(uvalue >> (shift << 4)); | 
 | 409 |       if (halfword != background) { | 
 | 410 |         NewLIR3(WIDE(kA64Movk3rdM), r_dest.GetReg(), halfword, shift); | 
 | 411 |       } | 
 | 412 |     } | 
 | 413 |     return res; | 
 | 414 |   } | 
 | 415 |  | 
 | 416 |   // Use the literal pool. | 
 | 417 |   int32_t val_lo = Low32Bits(value); | 
 | 418 |   int32_t val_hi = High32Bits(value); | 
 | 419 |   LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi); | 
 | 420 |   if (data_target == NULL) { | 
 | 421 |     data_target = AddWideData(&literal_list_, val_lo, val_hi); | 
 | 422 |   } | 
 | 423 |  | 
 | 424 |   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral); | 
 | 425 |   LIR *res = RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp), | 
 | 426 |                     r_dest.GetReg(), 0, 0, 0, 0, data_target); | 
 | 427 |   AppendLIR(res); | 
 | 428 |   return res; | 
 | 429 | } | 
 | 430 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 431 | LIR* Arm64Mir2Lir::OpUnconditionalBranch(LIR* target) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 432 |   LIR* res = NewLIR1(kA64B1t, 0 /* offset to be patched  during assembly */); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 433 |   res->target = target; | 
 | 434 |   return res; | 
 | 435 | } | 
 | 436 |  | 
 | 437 | LIR* Arm64Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 438 |   LIR* branch = NewLIR2(kA64B2ct, ArmConditionEncoding(cc), | 
 | 439 |                         0 /* offset to be patched */); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 440 |   branch->target = target; | 
 | 441 |   return branch; | 
 | 442 | } | 
 | 443 |  | 
 | 444 | LIR* Arm64Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 445 |   ArmOpcode opcode = kA64Brk1d; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 446 |   switch (op) { | 
 | 447 |     case kOpBlx: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 448 |       opcode = kA64Blr1x; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 449 |       break; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 450 |     // TODO(Arm64): port kThumbBx. | 
 | 451 |     // case kOpBx: | 
 | 452 |     //   opcode = kThumbBx; | 
 | 453 |     //   break; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 454 |     default: | 
 | 455 |       LOG(FATAL) << "Bad opcode " << op; | 
 | 456 |   } | 
 | 457 |   return NewLIR1(opcode, r_dest_src.GetReg()); | 
 | 458 | } | 
 | 459 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 460 | LIR* Arm64Mir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift) { | 
 | 461 |   ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0); | 
 | 462 |   CHECK_EQ(r_dest_src1.Is64Bit(), r_src2.Is64Bit()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 463 |   ArmOpcode opcode = kA64Brk1d; | 
 | 464 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 465 |   switch (op) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 466 |     case kOpCmn: | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 467 |       opcode = kA64Cmn3rro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 468 |       break; | 
 | 469 |     case kOpCmp: | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 470 |       opcode = kA64Cmp3rro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 471 |       break; | 
 | 472 |     case kOpMov: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 473 |       opcode = kA64Mov2rr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 474 |       break; | 
 | 475 |     case kOpMvn: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 476 |       opcode = kA64Mvn2rr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 477 |       break; | 
 | 478 |     case kOpNeg: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 479 |       opcode = kA64Neg3rro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 480 |       break; | 
 | 481 |     case kOpTst: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 482 |       opcode = kA64Tst3rro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 483 |       break; | 
 | 484 |     case kOpRev: | 
 | 485 |       DCHECK_EQ(shift, 0); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 486 |       // Binary, but rm is encoded twice. | 
| Serban Constantinescu | 169489b | 2014-06-11 16:43:35 +0100 | [diff] [blame] | 487 |       return NewLIR2(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 488 |       break; | 
 | 489 |     case kOpRevsh: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 490 |       // Binary, but rm is encoded twice. | 
| Zheng Xu | a3fe742 | 2014-07-09 14:03:15 +0800 | [diff] [blame] | 491 |       NewLIR2(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg()); | 
 | 492 |       // "sxth r1, r2" is "sbfm r1, r2, #0, #15" | 
 | 493 |       return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), 0, 15); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 494 |       break; | 
 | 495 |     case kOp2Byte: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 496 |       DCHECK_EQ(shift, ENCODE_NO_SHIFT); | 
 | 497 |       // "sbfx r1, r2, #imm1, #imm2" is "sbfm r1, r2, #imm1, #(imm1 + imm2 - 1)". | 
 | 498 |       // For now we use sbfm directly. | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 499 |       return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 7); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 500 |     case kOp2Short: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 501 |       DCHECK_EQ(shift, ENCODE_NO_SHIFT); | 
 | 502 |       // For now we use sbfm rather than its alias, sbfx. | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 503 |       return NewLIR4(kA64Sbfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 504 |     case kOp2Char: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 505 |       // "ubfx r1, r2, #imm1, #imm2" is "ubfm r1, r2, #imm1, #(imm1 + imm2 - 1)". | 
 | 506 |       // For now we use ubfm directly. | 
 | 507 |       DCHECK_EQ(shift, ENCODE_NO_SHIFT); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 508 |       return NewLIR4(kA64Ubfm4rrdd | wide, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 15); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 509 |     default: | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 510 |       return OpRegRegRegShift(op, r_dest_src1, r_dest_src1, r_src2, shift); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 511 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 512 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 513 |   DCHECK(!IsPseudoLirOp(opcode)); | 
 | 514 |   if (EncodingMap[opcode].flags & IS_BINARY_OP) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 515 |     DCHECK_EQ(shift, ENCODE_NO_SHIFT); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 516 |     return NewLIR2(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 517 |   } else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 518 |     ArmEncodingKind kind = EncodingMap[opcode].field_loc[2].kind; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 519 |     if (kind == kFmtShift) { | 
 | 520 |       return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), shift); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 521 |     } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 522 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 523 |  | 
 | 524 |   LOG(FATAL) << "Unexpected encoding operand count"; | 
 | 525 |   return NULL; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 526 | } | 
 | 527 |  | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 528 | LIR* Arm64Mir2Lir::OpRegRegExtend(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, | 
 | 529 |                                   A64RegExtEncodings ext, uint8_t amount) { | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 530 |   ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0); | 
 | 531 |   ArmOpcode opcode = kA64Brk1d; | 
 | 532 |  | 
 | 533 |   switch (op) { | 
 | 534 |     case kOpCmn: | 
 | 535 |       opcode = kA64Cmn3Rre; | 
 | 536 |       break; | 
 | 537 |     case kOpCmp: | 
 | 538 |       opcode = kA64Cmp3Rre; | 
 | 539 |       break; | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 540 |     case kOpAdd: | 
 | 541 |       // Note: intentional fallthrough | 
 | 542 |     case kOpSub: | 
 | 543 |       return OpRegRegRegExtend(op, r_dest_src1, r_dest_src1, r_src2, ext, amount); | 
 | 544 |       break; | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 545 |     default: | 
 | 546 |       LOG(FATAL) << "Bad Opcode: " << opcode; | 
 | 547 |       break; | 
 | 548 |   } | 
 | 549 |  | 
 | 550 |   DCHECK(!IsPseudoLirOp(opcode)); | 
 | 551 |   if (EncodingMap[opcode].flags & IS_TERTIARY_OP) { | 
 | 552 |     ArmEncodingKind kind = EncodingMap[opcode].field_loc[2].kind; | 
 | 553 |     if (kind == kFmtExtend) { | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 554 |       return NewLIR3(opcode | wide, r_dest_src1.GetReg(), r_src2.GetReg(), | 
 | 555 |                      EncodeExtend(ext, amount)); | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 556 |     } | 
 | 557 |   } | 
 | 558 |  | 
 | 559 |   LOG(FATAL) << "Unexpected encoding operand count"; | 
 | 560 |   return NULL; | 
 | 561 | } | 
 | 562 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 563 | LIR* Arm64Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) { | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 564 |   /* RegReg operations with SP in first parameter need extended register instruction form. | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 565 |    * Only CMN, CMP, ADD & SUB instructions are implemented. | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 566 |    */ | 
| Zheng Xu | baa7c88 | 2014-06-30 14:26:50 +0800 | [diff] [blame] | 567 |   if (r_dest_src1 == rs_sp) { | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 568 |     return OpRegRegExtend(op, r_dest_src1, r_src2, kA64Uxtx, 0); | 
| Stuart Monteith | f8ec48e | 2014-06-06 17:05:08 +0100 | [diff] [blame] | 569 |   } else { | 
 | 570 |     return OpRegRegShift(op, r_dest_src1, r_src2, ENCODE_NO_SHIFT); | 
 | 571 |   } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 572 | } | 
 | 573 |  | 
 | 574 | LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) { | 
 | 575 |   UNIMPLEMENTED(FATAL); | 
 | 576 |   return nullptr; | 
 | 577 | } | 
 | 578 |  | 
 | 579 | LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) { | 
 | 580 |   UNIMPLEMENTED(FATAL); | 
 | 581 |   return nullptr; | 
 | 582 | } | 
 | 583 |  | 
 | 584 | LIR* Arm64Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 585 |   LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm64"; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 586 |   return NULL; | 
 | 587 | } | 
 | 588 |  | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 589 | LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1, | 
 | 590 |                                     RegStorage r_src2, int shift) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 591 |   ArmOpcode opcode = kA64Brk1d; | 
 | 592 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 593 |   switch (op) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 594 |     case kOpAdd: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 595 |       opcode = kA64Add4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 596 |       break; | 
 | 597 |     case kOpSub: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 598 |       opcode = kA64Sub4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 599 |       break; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 600 |     // case kOpRsub: | 
 | 601 |     //   opcode = kA64RsubWWW; | 
 | 602 |     //   break; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 603 |     case kOpAdc: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 604 |       opcode = kA64Adc3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 605 |       break; | 
 | 606 |     case kOpAnd: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 607 |       opcode = kA64And4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 608 |       break; | 
 | 609 |     case kOpXor: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 610 |       opcode = kA64Eor4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 611 |       break; | 
 | 612 |     case kOpMul: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 613 |       opcode = kA64Mul3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 614 |       break; | 
 | 615 |     case kOpDiv: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 616 |       opcode = kA64Sdiv3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 617 |       break; | 
 | 618 |     case kOpOr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 619 |       opcode = kA64Orr4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 620 |       break; | 
 | 621 |     case kOpSbc: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 622 |       opcode = kA64Sbc3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 623 |       break; | 
 | 624 |     case kOpLsl: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 625 |       opcode = kA64Lsl3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 626 |       break; | 
 | 627 |     case kOpLsr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 628 |       opcode = kA64Lsr3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 629 |       break; | 
 | 630 |     case kOpAsr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 631 |       opcode = kA64Asr3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 632 |       break; | 
 | 633 |     case kOpRor: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 634 |       opcode = kA64Ror3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 635 |       break; | 
 | 636 |     default: | 
 | 637 |       LOG(FATAL) << "Bad opcode: " << op; | 
 | 638 |       break; | 
 | 639 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 640 |  | 
 | 641 |   // The instructions above belong to two kinds: | 
 | 642 |   // - 4-operands instructions, where the last operand is a shift/extend immediate, | 
 | 643 |   // - 3-operands instructions with no shift/extend. | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 644 |   ArmOpcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode; | 
 | 645 |   CHECK_EQ(r_dest.Is64Bit(), r_src1.Is64Bit()); | 
 | 646 |   CHECK_EQ(r_dest.Is64Bit(), r_src2.Is64Bit()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 647 |   if (EncodingMap[opcode].flags & IS_QUAD_OP) { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 648 |     DCHECK(!IsExtendEncoding(shift)); | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 649 |     return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), shift); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 650 |   } else { | 
 | 651 |     DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 652 |     DCHECK_EQ(shift, ENCODE_NO_SHIFT); | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 653 |     return NewLIR3(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 654 |   } | 
 | 655 | } | 
 | 656 |  | 
| Andreas Gampe | 47b31aa | 2014-06-19 01:10:07 -0700 | [diff] [blame] | 657 | LIR* Arm64Mir2Lir::OpRegRegRegExtend(OpKind op, RegStorage r_dest, RegStorage r_src1, | 
 | 658 |                                      RegStorage r_src2, A64RegExtEncodings ext, uint8_t amount) { | 
 | 659 |   ArmOpcode opcode = kA64Brk1d; | 
 | 660 |  | 
 | 661 |   switch (op) { | 
 | 662 |     case kOpAdd: | 
 | 663 |       opcode = kA64Add4RRre; | 
 | 664 |       break; | 
 | 665 |     case kOpSub: | 
 | 666 |       opcode = kA64Sub4RRre; | 
 | 667 |       break; | 
 | 668 |     default: | 
 | 669 |       LOG(FATAL) << "Unimplemented opcode: " << op; | 
 | 670 |       break; | 
 | 671 |   } | 
 | 672 |   ArmOpcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode; | 
 | 673 |  | 
 | 674 |   if (r_dest.Is64Bit()) { | 
 | 675 |     CHECK(r_src1.Is64Bit()); | 
 | 676 |  | 
 | 677 |     // dest determines whether the op is wide or not. Up-convert src2 when necessary. | 
 | 678 |     // Note: this is not according to aarch64 specifications, but our encoding. | 
 | 679 |     if (!r_src2.Is64Bit()) { | 
 | 680 |       r_src2 = As64BitReg(r_src2); | 
 | 681 |     } | 
 | 682 |   } else { | 
 | 683 |     CHECK(!r_src1.Is64Bit()); | 
 | 684 |     CHECK(!r_src2.Is64Bit()); | 
 | 685 |   } | 
 | 686 |  | 
 | 687 |   // Sanity checks. | 
 | 688 |   //    1) Amount is in the range 0..4 | 
 | 689 |   CHECK_LE(amount, 4); | 
 | 690 |  | 
 | 691 |   return NewLIR4(widened_opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), | 
 | 692 |                  EncodeExtend(ext, amount)); | 
 | 693 | } | 
 | 694 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 695 | LIR* Arm64Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) { | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 696 |   return OpRegRegRegShift(op, r_dest, r_src1, r_src2, ENCODE_NO_SHIFT); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 697 | } | 
 | 698 |  | 
 | 699 | LIR* Arm64Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) { | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 700 |   return OpRegRegImm64(op, r_dest, r_src1, static_cast<int64_t>(value)); | 
 | 701 | } | 
 | 702 |  | 
 | 703 | LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 704 |   LIR* res; | 
 | 705 |   bool neg = (value < 0); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 706 |   int64_t abs_value = (neg) ? -value : value; | 
 | 707 |   ArmOpcode opcode = kA64Brk1d; | 
 | 708 |   ArmOpcode alt_opcode = kA64Brk1d; | 
 | 709 |   int32_t log_imm = -1; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 710 |   bool is_wide = r_dest.Is64Bit(); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 711 |   ArmOpcode wide = (is_wide) ? WIDE(0) : UNWIDE(0); | 
| Andreas Gampe | 9f975bf | 2014-06-18 17:45:32 -0700 | [diff] [blame] | 712 |   int info = 0; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 713 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 714 |   switch (op) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 715 |     case kOpLsl: { | 
 | 716 |       // "lsl w1, w2, #imm" is an alias of "ubfm w1, w2, #(-imm MOD 32), #(31-imm)" | 
| Zheng Xu | 2d41a65 | 2014-06-09 11:05:31 +0800 | [diff] [blame] | 717 |       // and "lsl x1, x2, #imm" of "ubfm x1, x2, #(-imm MOD 64), #(63-imm)". | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 718 |       // For now, we just use ubfm directly. | 
| Zheng Xu | 2d41a65 | 2014-06-09 11:05:31 +0800 | [diff] [blame] | 719 |       int max_value = (is_wide) ? 63 : 31; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 720 |       return NewLIR4(kA64Ubfm4rrdd | wide, r_dest.GetReg(), r_src1.GetReg(), | 
| Zheng Xu | 2d41a65 | 2014-06-09 11:05:31 +0800 | [diff] [blame] | 721 |                      (-value) & max_value, max_value - value); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 722 |     } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 723 |     case kOpLsr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 724 |       return NewLIR3(kA64Lsr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 725 |     case kOpAsr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 726 |       return NewLIR3(kA64Asr3rrd | wide, r_dest.GetReg(), r_src1.GetReg(), value); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 727 |     case kOpRor: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 728 |       // "ror r1, r2, #imm" is an alias of "extr r1, r2, r2, #imm". | 
 | 729 |       // For now, we just use extr directly. | 
 | 730 |       return NewLIR4(kA64Extr4rrrd | wide, r_dest.GetReg(), r_src1.GetReg(), r_src1.GetReg(), | 
 | 731 |                      value); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 732 |     case kOpAdd: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 733 |       neg = !neg; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 734 |       // Note: intentional fallthrough | 
 | 735 |     case kOpSub: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 736 |       // Add and sub below read/write sp rather than xzr. | 
 | 737 |       if (abs_value < 0x1000) { | 
 | 738 |         opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT; | 
 | 739 |         return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value, 0); | 
 | 740 |       } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) { | 
 | 741 |         opcode = (neg) ? kA64Add4RRdT : kA64Sub4RRdT; | 
 | 742 |         return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 743 |       } else { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 744 |         log_imm = -1; | 
| Vladimir Marko | 903989d | 2014-07-01 17:21:18 +0100 | [diff] [blame] | 745 |         alt_opcode = (op == kOpAdd) ? kA64Add4RRre : kA64Sub4RRre; | 
| Andreas Gampe | 47b31aa | 2014-06-19 01:10:07 -0700 | [diff] [blame] | 746 |         info = EncodeExtend(is_wide ? kA64Uxtx : kA64Uxtw, 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 747 |       } | 
 | 748 |       break; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 749 |     // case kOpRsub: | 
 | 750 |     //   opcode = kThumb2RsubRRI8M; | 
 | 751 |     //   alt_opcode = kThumb2RsubRRR; | 
 | 752 |     //   break; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 753 |     case kOpAdc: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 754 |       log_imm = -1; | 
 | 755 |       alt_opcode = kA64Adc3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 756 |       break; | 
 | 757 |     case kOpSbc: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 758 |       log_imm = -1; | 
 | 759 |       alt_opcode = kA64Sbc3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 760 |       break; | 
 | 761 |     case kOpOr: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 762 |       log_imm = EncodeLogicalImmediate(is_wide, value); | 
 | 763 |       opcode = kA64Orr3Rrl; | 
 | 764 |       alt_opcode = kA64Orr4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 765 |       break; | 
 | 766 |     case kOpAnd: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 767 |       log_imm = EncodeLogicalImmediate(is_wide, value); | 
 | 768 |       opcode = kA64And3Rrl; | 
 | 769 |       alt_opcode = kA64And4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 770 |       break; | 
 | 771 |     case kOpXor: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 772 |       log_imm = EncodeLogicalImmediate(is_wide, value); | 
 | 773 |       opcode = kA64Eor3Rrl; | 
 | 774 |       alt_opcode = kA64Eor4rrro; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 775 |       break; | 
 | 776 |     case kOpMul: | 
 | 777 |       // TUNING: power of 2, shift & add | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 778 |       log_imm = -1; | 
 | 779 |       alt_opcode = kA64Mul3rrr; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 780 |       break; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 781 |     default: | 
 | 782 |       LOG(FATAL) << "Bad opcode: " << op; | 
 | 783 |   } | 
 | 784 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 785 |   if (log_imm >= 0) { | 
 | 786 |     return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 787 |   } else { | 
| Andreas Gampe | 9f975bf | 2014-06-18 17:45:32 -0700 | [diff] [blame] | 788 |     RegStorage r_scratch; | 
| Andreas Gampe | 47b31aa | 2014-06-19 01:10:07 -0700 | [diff] [blame] | 789 |     if (is_wide) { | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 790 |       r_scratch = AllocTempWide(); | 
 | 791 |       LoadConstantWide(r_scratch, value); | 
 | 792 |     } else { | 
 | 793 |       r_scratch = AllocTemp(); | 
 | 794 |       LoadConstant(r_scratch, value); | 
 | 795 |     } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 796 |     if (EncodingMap[alt_opcode].flags & IS_QUAD_OP) | 
| Andreas Gampe | 9f975bf | 2014-06-18 17:45:32 -0700 | [diff] [blame] | 797 |       res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 798 |     else | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 799 |       res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 800 |     FreeTemp(r_scratch); | 
 | 801 |     return res; | 
 | 802 |   } | 
 | 803 | } | 
 | 804 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 805 | LIR* Arm64Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) { | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 806 |   return OpRegImm64(op, r_dest_src1, static_cast<int64_t>(value)); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 807 | } | 
 | 808 |  | 
| Serban Constantinescu | ed65c5e | 2014-05-22 15:10:18 +0100 | [diff] [blame] | 809 | LIR* Arm64Mir2Lir::OpRegImm64(OpKind op, RegStorage r_dest_src1, int64_t value) { | 
 | 810 |   ArmOpcode wide = (r_dest_src1.Is64Bit()) ? WIDE(0) : UNWIDE(0); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 811 |   ArmOpcode opcode = kA64Brk1d; | 
 | 812 |   ArmOpcode neg_opcode = kA64Brk1d; | 
 | 813 |   bool shift; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 814 |   bool neg = (value < 0); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 815 |   uint64_t abs_value = (neg) ? -value : value; | 
 | 816 |  | 
 | 817 |   if (LIKELY(abs_value < 0x1000)) { | 
 | 818 |     // abs_value is a 12-bit immediate. | 
 | 819 |     shift = false; | 
 | 820 |   } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) { | 
 | 821 |     // abs_value is a shifted 12-bit immediate. | 
 | 822 |     shift = true; | 
 | 823 |     abs_value >>= 12; | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 824 |   } else if (LIKELY(abs_value < 0x1000000 && (op == kOpAdd || op == kOpSub))) { | 
 | 825 |     // Note: It is better to use two ADD/SUB instead of loading a number to a temp register. | 
 | 826 |     // This works for both normal registers and SP. | 
 | 827 |     // For a frame size == 0x2468, it will be encoded as: | 
 | 828 |     //   sub sp, #0x2000 | 
 | 829 |     //   sub sp, #0x468 | 
 | 830 |     if (neg) { | 
 | 831 |       op = (op == kOpAdd) ? kOpSub : kOpAdd; | 
 | 832 |     } | 
 | 833 |     OpRegImm64(op, r_dest_src1, abs_value & (~INT64_C(0xfff))); | 
 | 834 |     return OpRegImm64(op, r_dest_src1, abs_value & 0xfff); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 835 |   } else { | 
| Zheng Xu | e2eb29e | 2014-06-12 10:22:33 +0800 | [diff] [blame] | 836 |     RegStorage r_tmp; | 
 | 837 |     LIR* res; | 
 | 838 |     if (IS_WIDE(wide)) { | 
 | 839 |       r_tmp = AllocTempWide(); | 
 | 840 |       res = LoadConstantWide(r_tmp, value); | 
 | 841 |     } else { | 
 | 842 |       r_tmp = AllocTemp(); | 
 | 843 |       res = LoadConstant(r_tmp, value); | 
 | 844 |     } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 845 |     OpRegReg(op, r_dest_src1, r_tmp); | 
 | 846 |     FreeTemp(r_tmp); | 
 | 847 |     return res; | 
 | 848 |   } | 
 | 849 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 850 |   switch (op) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 851 |     case kOpAdd: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 852 |       neg_opcode = kA64Sub4RRdT; | 
 | 853 |       opcode = kA64Add4RRdT; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 854 |       break; | 
 | 855 |     case kOpSub: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 856 |       neg_opcode = kA64Add4RRdT; | 
 | 857 |       opcode = kA64Sub4RRdT; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 858 |       break; | 
 | 859 |     case kOpCmp: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 860 |       neg_opcode = kA64Cmn3RdT; | 
 | 861 |       opcode = kA64Cmp3RdT; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 862 |       break; | 
 | 863 |     default: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 864 |       LOG(FATAL) << "Bad op-kind in OpRegImm: " << op; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 865 |       break; | 
 | 866 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 867 |  | 
 | 868 |   if (UNLIKELY(neg)) | 
 | 869 |     opcode = neg_opcode; | 
 | 870 |  | 
 | 871 |   if (EncodingMap[opcode].flags & IS_QUAD_OP) | 
 | 872 |     return NewLIR4(opcode | wide, r_dest_src1.GetReg(), r_dest_src1.GetReg(), abs_value, | 
 | 873 |                    (shift) ? 1 : 0); | 
 | 874 |   else | 
 | 875 |     return NewLIR3(opcode | wide, r_dest_src1.GetReg(), abs_value, (shift) ? 1 : 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 876 | } | 
 | 877 |  | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 878 | int Arm64Mir2Lir::EncodeShift(int shift_type, int amount) { | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 879 |   DCHECK_EQ(shift_type & 0x3, shift_type); | 
 | 880 |   DCHECK_EQ(amount & 0x3f, amount); | 
| Matteo Franchin | c61b3c9 | 2014-06-18 11:52:47 +0100 | [diff] [blame] | 881 |   return ((shift_type & 0x3) << 7) | (amount & 0x3f); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 882 | } | 
 | 883 |  | 
 | 884 | int Arm64Mir2Lir::EncodeExtend(int extend_type, int amount) { | 
| Zheng Xu | cedee47 | 2014-07-01 09:53:22 +0800 | [diff] [blame^] | 885 |   DCHECK_EQ(extend_type & 0x7, extend_type); | 
 | 886 |   DCHECK_EQ(amount & 0x7, amount); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 887 |   return  (1 << 6) | ((extend_type & 0x7) << 3) | (amount & 0x7); | 
 | 888 | } | 
 | 889 |  | 
 | 890 | bool Arm64Mir2Lir::IsExtendEncoding(int encoded_value) { | 
 | 891 |   return ((1 << 6) & encoded_value) != 0; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 892 | } | 
 | 893 |  | 
 | 894 | LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 895 |                                    int scale, OpSize size) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 896 |   LIR* load; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 897 |   int expected_scale = 0; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 898 |   ArmOpcode opcode = kA64Brk1d; | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 899 |   r_base = Check64BitReg(r_base); | 
| Serban Constantinescu | 63fe93d | 2014-06-30 17:10:28 +0100 | [diff] [blame] | 900 |  | 
 | 901 |   // TODO(Arm64): The sign extension of r_index should be carried out by using an extended | 
 | 902 |   //   register offset load (rather than doing the sign extension in a separate instruction). | 
 | 903 |   if (r_index.Is32Bit()) { | 
 | 904 |     // Assemble: ``sxtw xN, wN''. | 
 | 905 |     r_index = As64BitReg(r_index); | 
 | 906 |     NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31); | 
 | 907 |   } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 908 |  | 
 | 909 |   if (r_dest.IsFloat()) { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 910 |     if (r_dest.IsDouble()) { | 
 | 911 |       DCHECK(size == k64 || size == kDouble); | 
 | 912 |       expected_scale = 3; | 
 | 913 |       opcode = FWIDE(kA64Ldr4fXxG); | 
 | 914 |     } else { | 
 | 915 |       DCHECK(r_dest.IsSingle()); | 
 | 916 |       DCHECK(size == k32 || size == kSingle); | 
 | 917 |       expected_scale = 2; | 
 | 918 |       opcode = kA64Ldr4fXxG; | 
 | 919 |     } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 920 |  | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 921 |     DCHECK(scale == 0 || scale == expected_scale); | 
 | 922 |     return NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), | 
 | 923 |                    (scale != 0) ? 1 : 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 924 |   } | 
 | 925 |  | 
 | 926 |   switch (size) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 927 |     case kDouble: | 
 | 928 |     case kWord: | 
 | 929 |     case k64: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 930 |       r_dest = Check64BitReg(r_dest); | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 931 |       opcode = WIDE(kA64Ldr4rXxG); | 
 | 932 |       expected_scale = 3; | 
 | 933 |       break; | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 934 |     case kSingle:     // Intentional fall-through. | 
 | 935 |     case k32:         // Intentional fall-through. | 
| Serban Constantinescu | 63fe93d | 2014-06-30 17:10:28 +0100 | [diff] [blame] | 936 |     case kReference: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 937 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 938 |       opcode = kA64Ldr4rXxG; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 939 |       expected_scale = 2; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 940 |       break; | 
 | 941 |     case kUnsignedHalf: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 942 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 943 |       opcode = kA64Ldrh4wXxd; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 944 |       expected_scale = 1; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 945 |       break; | 
 | 946 |     case kSignedHalf: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 947 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 948 |       opcode = kA64Ldrsh4rXxd; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 949 |       expected_scale = 1; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 950 |       break; | 
 | 951 |     case kUnsignedByte: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 952 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 953 |       opcode = kA64Ldrb3wXx; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 954 |       break; | 
 | 955 |     case kSignedByte: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 956 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 957 |       opcode = kA64Ldrsb3rXx; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 958 |       break; | 
 | 959 |     default: | 
 | 960 |       LOG(FATAL) << "Bad size: " << size; | 
 | 961 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 962 |  | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 963 |   if (UNLIKELY(expected_scale == 0)) { | 
 | 964 |     // This is a tertiary op (e.g. ldrb, ldrsb), it does not not support scale. | 
 | 965 |     DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 966 |     DCHECK_EQ(scale, 0); | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 967 |     load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 968 |   } else { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 969 |     DCHECK(scale == 0 || scale == expected_scale); | 
 | 970 |     load = NewLIR4(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 971 |                    (scale != 0) ? 1 : 0); | 
 | 972 |   } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 973 |  | 
 | 974 |   return load; | 
 | 975 | } | 
 | 976 |  | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 977 | LIR* Arm64Mir2Lir::LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, | 
 | 978 |                                   int scale) { | 
 | 979 |   return LoadBaseIndexed(r_base, r_index, As32BitReg(r_dest), scale, kReference); | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 980 | } | 
 | 981 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 982 | LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 983 |                                     int scale, OpSize size) { | 
 | 984 |   LIR* store; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 985 |   int expected_scale = 0; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 986 |   ArmOpcode opcode = kA64Brk1d; | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 987 |   r_base = Check64BitReg(r_base); | 
| Serban Constantinescu | 63fe93d | 2014-06-30 17:10:28 +0100 | [diff] [blame] | 988 |  | 
 | 989 |   // TODO(Arm64): The sign extension of r_index should be carried out by using an extended | 
 | 990 |   //   register offset store (rather than doing the sign extension in a separate instruction). | 
 | 991 |   if (r_index.Is32Bit()) { | 
 | 992 |     // Assemble: ``sxtw xN, wN''. | 
 | 993 |     r_index = As64BitReg(r_index); | 
 | 994 |     NewLIR4(WIDE(kA64Sbfm4rrdd), r_index.GetReg(), r_index.GetReg(), 0, 31); | 
 | 995 |   } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 996 |  | 
 | 997 |   if (r_src.IsFloat()) { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 998 |     if (r_src.IsDouble()) { | 
 | 999 |       DCHECK(size == k64 || size == kDouble); | 
 | 1000 |       expected_scale = 3; | 
 | 1001 |       opcode = FWIDE(kA64Str4fXxG); | 
 | 1002 |     } else { | 
 | 1003 |       DCHECK(r_src.IsSingle()); | 
 | 1004 |       DCHECK(size == k32 || size == kSingle); | 
 | 1005 |       expected_scale = 2; | 
 | 1006 |       opcode = kA64Str4fXxG; | 
 | 1007 |     } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1008 |  | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1009 |     DCHECK(scale == 0 || scale == expected_scale); | 
 | 1010 |     return NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(), | 
 | 1011 |                    (scale != 0) ? 1 : 0); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1012 |   } | 
 | 1013 |  | 
 | 1014 |   switch (size) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1015 |     case kDouble:     // Intentional fall-trough. | 
 | 1016 |     case kWord:       // Intentional fall-trough. | 
 | 1017 |     case k64: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1018 |       r_src = Check64BitReg(r_src); | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1019 |       opcode = WIDE(kA64Str4rXxG); | 
 | 1020 |       expected_scale = 3; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1021 |       break; | 
 | 1022 |     case kSingle:     // Intentional fall-trough. | 
 | 1023 |     case k32:         // Intentional fall-trough. | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 1024 |     case kReference: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1025 |       r_src = Check32BitReg(r_src); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1026 |       opcode = kA64Str4rXxG; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1027 |       expected_scale = 2; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1028 |       break; | 
 | 1029 |     case kUnsignedHalf: | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1030 |     case kSignedHalf: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 1031 |       r_src = Check32BitReg(r_src); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1032 |       opcode = kA64Strh4wXxd; | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1033 |       expected_scale = 1; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1034 |       break; | 
 | 1035 |     case kUnsignedByte: | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1036 |     case kSignedByte: | 
| Andreas Gampe | 4b537a8 | 2014-06-30 22:24:53 -0700 | [diff] [blame] | 1037 |       r_src = Check32BitReg(r_src); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1038 |       opcode = kA64Strb3wXx; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1039 |       break; | 
 | 1040 |     default: | 
 | 1041 |       LOG(FATAL) << "Bad size: " << size; | 
 | 1042 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1043 |  | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1044 |   if (UNLIKELY(expected_scale == 0)) { | 
 | 1045 |     // This is a tertiary op (e.g. strb), it does not not support scale. | 
 | 1046 |     DCHECK_NE(EncodingMap[UNWIDE(opcode)].flags & IS_TERTIARY_OP, 0U); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1047 |     DCHECK_EQ(scale, 0); | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1048 |     store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1049 |   } else { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1050 |     store = NewLIR4(opcode, r_src.GetReg(), r_base.GetReg(), r_index.GetReg(), | 
 | 1051 |                     (scale != 0) ? 1 : 0); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1052 |   } | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1053 |  | 
 | 1054 |   return store; | 
 | 1055 | } | 
 | 1056 |  | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 1057 | LIR* Arm64Mir2Lir::StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, | 
 | 1058 |                                    int scale) { | 
 | 1059 |   return StoreBaseIndexed(r_base, r_index, As32BitReg(r_src), scale, kReference); | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1060 | } | 
 | 1061 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1062 | /* | 
 | 1063 |  * Load value from base + displacement.  Optionally perform null check | 
 | 1064 |  * on base (which must have an associated s_reg and MIR).  If not | 
 | 1065 |  * performing null check, incoming MIR can be null. | 
 | 1066 |  */ | 
 | 1067 | LIR* Arm64Mir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, | 
| Vladimir Marko | 3bf7c60 | 2014-05-07 14:55:43 +0100 | [diff] [blame] | 1068 |                                     OpSize size) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1069 |   LIR* load = NULL; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1070 |   ArmOpcode opcode = kA64Brk1d; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1071 |   ArmOpcode alt_opcode = kA64Brk1d; | 
 | 1072 |   int scale = 0; | 
 | 1073 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1074 |   switch (size) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1075 |     case kDouble:     // Intentional fall-through. | 
 | 1076 |     case kWord:       // Intentional fall-through. | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1077 |     case k64: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1078 |       r_dest = Check64BitReg(r_dest); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1079 |       scale = 3; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1080 |       if (r_dest.IsFloat()) { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1081 |         DCHECK(r_dest.IsDouble()); | 
 | 1082 |         opcode = FWIDE(kA64Ldr3fXD); | 
 | 1083 |         alt_opcode = FWIDE(kA64Ldur3fXd); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1084 |       } else { | 
| Matteo Franchin | 0955f7e | 2014-05-23 17:32:52 +0100 | [diff] [blame] | 1085 |         opcode = WIDE(kA64Ldr3rXD); | 
 | 1086 |         alt_opcode = WIDE(kA64Ldur3rXd); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1087 |       } | 
 | 1088 |       break; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1089 |     case kSingle:     // Intentional fall-through. | 
 | 1090 |     case k32:         // Intentional fall-trough. | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 1091 |     case kReference: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1092 |       r_dest = Check32BitReg(r_dest); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1093 |       scale = 2; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1094 |       if (r_dest.IsFloat()) { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1095 |         DCHECK(r_dest.IsSingle()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1096 |         opcode = kA64Ldr3fXD; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1097 |       } else { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1098 |         opcode = kA64Ldr3rXD; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1099 |       } | 
 | 1100 |       break; | 
 | 1101 |     case kUnsignedHalf: | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1102 |       scale = 1; | 
 | 1103 |       opcode = kA64Ldrh3wXF; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1104 |       break; | 
 | 1105 |     case kSignedHalf: | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1106 |       scale = 1; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1107 |       opcode = kA64Ldrsh3rXF; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1108 |       break; | 
 | 1109 |     case kUnsignedByte: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1110 |       opcode = kA64Ldrb3wXd; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1111 |       break; | 
 | 1112 |     case kSignedByte: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1113 |       opcode = kA64Ldrsb3rXd; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1114 |       break; | 
 | 1115 |     default: | 
 | 1116 |       LOG(FATAL) << "Bad size: " << size; | 
 | 1117 |   } | 
 | 1118 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1119 |   bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0; | 
 | 1120 |   int scaled_disp = displacement >> scale; | 
 | 1121 |   if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) { | 
 | 1122 |     // Can use scaled load. | 
 | 1123 |     load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), scaled_disp); | 
 | 1124 |   } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) { | 
 | 1125 |     // Can use unscaled load. | 
 | 1126 |     load = NewLIR3(alt_opcode, r_dest.GetReg(), r_base.GetReg(), displacement); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1127 |   } else { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1128 |     // Use long sequence. | 
| buzbee | 33ae558 | 2014-06-12 14:56:32 -0700 | [diff] [blame] | 1129 |     // TODO: cleaner support for index/displacement registers?  Not a reference, but must match width. | 
 | 1130 |     RegStorage r_scratch = AllocTempWide(); | 
 | 1131 |     LoadConstantWide(r_scratch, displacement); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1132 |     load = LoadBaseIndexed(r_base, r_scratch, r_dest, 0, size); | 
 | 1133 |     FreeTemp(r_scratch); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1134 |   } | 
 | 1135 |  | 
 | 1136 |   // TODO: in future may need to differentiate Dalvik accesses w/ spills | 
| Vladimir Marko | 8dea81c | 2014-06-06 14:50:36 +0100 | [diff] [blame] | 1137 |   if (mem_ref_type_ == ResourceMask::kDalvikReg) { | 
| Zheng Xu | baa7c88 | 2014-06-30 14:26:50 +0800 | [diff] [blame] | 1138 |     DCHECK(r_base == rs_sp); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1139 |     AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1140 |   } | 
 | 1141 |   return load; | 
 | 1142 | } | 
 | 1143 |  | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1144 | LIR* Arm64Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, | 
 | 1145 |                                 OpSize size, VolatileKind is_volatile) { | 
| Vladimir Marko | 674744e | 2014-04-24 15:18:26 +0100 | [diff] [blame] | 1146 |   // LoadBaseDisp() will emit correct insn for atomic load on arm64 | 
 | 1147 |   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore(). | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1148 |  | 
 | 1149 |   LIR* load = LoadBaseDispBody(r_base, displacement, r_dest, size); | 
 | 1150 |  | 
 | 1151 |   if (UNLIKELY(is_volatile == kVolatile)) { | 
| Hans Boehm | 48f5c47 | 2014-06-27 14:50:10 -0700 | [diff] [blame] | 1152 |     // TODO: This should generate an acquire load instead of the barrier. | 
 | 1153 |     GenMemBarrier(kLoadAny); | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1154 |   } | 
 | 1155 |  | 
 | 1156 |   return load; | 
| Vladimir Marko | 674744e | 2014-04-24 15:18:26 +0100 | [diff] [blame] | 1157 | } | 
 | 1158 |  | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1159 | LIR* Arm64Mir2Lir::LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest, | 
 | 1160 |                                VolatileKind is_volatile) { | 
 | 1161 |   return LoadBaseDisp(r_base, displacement, As32BitReg(r_dest), kReference, is_volatile); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1162 | } | 
 | 1163 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1164 | LIR* Arm64Mir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1165 |                                      OpSize size) { | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1166 |   LIR* store = NULL; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1167 |   ArmOpcode opcode = kA64Brk1d; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1168 |   ArmOpcode alt_opcode = kA64Brk1d; | 
 | 1169 |   int scale = 0; | 
 | 1170 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1171 |   switch (size) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1172 |     case kDouble:     // Intentional fall-through. | 
 | 1173 |     case kWord:       // Intentional fall-through. | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1174 |     case k64: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1175 |       r_src = Check64BitReg(r_src); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1176 |       scale = 3; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1177 |       if (r_src.IsFloat()) { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1178 |         DCHECK(r_src.IsDouble()); | 
 | 1179 |         opcode = FWIDE(kA64Str3fXD); | 
 | 1180 |         alt_opcode = FWIDE(kA64Stur3fXd); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1181 |       } else { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1182 |         opcode = FWIDE(kA64Str3rXD); | 
 | 1183 |         alt_opcode = FWIDE(kA64Stur3rXd); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1184 |       } | 
 | 1185 |       break; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1186 |     case kSingle:     // Intentional fall-through. | 
 | 1187 |     case k32:         // Intentional fall-trough. | 
| Matteo Franchin | 255e014 | 2014-07-04 13:50:41 +0100 | [diff] [blame] | 1188 |     case kReference: | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1189 |       r_src = Check32BitReg(r_src); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1190 |       scale = 2; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1191 |       if (r_src.IsFloat()) { | 
 | 1192 |         DCHECK(r_src.IsSingle()); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1193 |         opcode = kA64Str3fXD; | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1194 |       } else { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1195 |         opcode = kA64Str3rXD; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1196 |       } | 
 | 1197 |       break; | 
 | 1198 |     case kUnsignedHalf: | 
 | 1199 |     case kSignedHalf: | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1200 |       scale = 1; | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1201 |       opcode = kA64Strh3wXF; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1202 |       break; | 
 | 1203 |     case kUnsignedByte: | 
 | 1204 |     case kSignedByte: | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1205 |       opcode = kA64Strb3wXd; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1206 |       break; | 
 | 1207 |     default: | 
 | 1208 |       LOG(FATAL) << "Bad size: " << size; | 
 | 1209 |   } | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1210 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1211 |   bool displacement_is_aligned = (displacement & ((1 << scale) - 1)) == 0; | 
 | 1212 |   int scaled_disp = displacement >> scale; | 
 | 1213 |   if (displacement_is_aligned && scaled_disp >= 0 && scaled_disp < 4096) { | 
 | 1214 |     // Can use scaled store. | 
 | 1215 |     store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), scaled_disp); | 
 | 1216 |   } else if (alt_opcode != kA64Brk1d && IS_SIGNED_IMM9(displacement)) { | 
 | 1217 |     // Can use unscaled store. | 
 | 1218 |     store = NewLIR3(alt_opcode, r_src.GetReg(), r_base.GetReg(), displacement); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1219 |   } else { | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1220 |     // Use long sequence. | 
| buzbee | 33ae558 | 2014-06-12 14:56:32 -0700 | [diff] [blame] | 1221 |     RegStorage r_scratch = AllocTempWide(); | 
 | 1222 |     LoadConstantWide(r_scratch, displacement); | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1223 |     store = StoreBaseIndexed(r_base, r_scratch, r_src, 0, size); | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1224 |     FreeTemp(r_scratch); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1225 |   } | 
 | 1226 |  | 
| Matteo Franchin | bc6d197 | 2014-05-13 12:33:28 +0100 | [diff] [blame] | 1227 |   // TODO: In future, may need to differentiate Dalvik & spill accesses. | 
| Vladimir Marko | 8dea81c | 2014-06-06 14:50:36 +0100 | [diff] [blame] | 1228 |   if (mem_ref_type_ == ResourceMask::kDalvikReg) { | 
| Zheng Xu | baa7c88 | 2014-06-30 14:26:50 +0800 | [diff] [blame] | 1229 |     DCHECK(r_base == rs_sp); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1230 |     AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit()); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1231 |   } | 
 | 1232 |   return store; | 
 | 1233 | } | 
 | 1234 |  | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1235 | LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, | 
 | 1236 |                                  OpSize size, VolatileKind is_volatile) { | 
| Hans Boehm | 48f5c47 | 2014-06-27 14:50:10 -0700 | [diff] [blame] | 1237 |   // TODO: This should generate a release store and no barriers. | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1238 |   if (UNLIKELY(is_volatile == kVolatile)) { | 
| Hans Boehm | 48f5c47 | 2014-06-27 14:50:10 -0700 | [diff] [blame] | 1239 |     // Ensure that prior accesses become visible to other threads first. | 
 | 1240 |     GenMemBarrier(kAnyStore); | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1241 |   } | 
 | 1242 |  | 
| Vladimir Marko | 674744e | 2014-04-24 15:18:26 +0100 | [diff] [blame] | 1243 |   // StoreBaseDisp() will emit correct insn for atomic store on arm64 | 
 | 1244 |   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore(). | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1245 |  | 
 | 1246 |   LIR* store = StoreBaseDispBody(r_base, displacement, r_src, size); | 
 | 1247 |  | 
 | 1248 |   if (UNLIKELY(is_volatile == kVolatile)) { | 
| Hans Boehm | 48f5c47 | 2014-06-27 14:50:10 -0700 | [diff] [blame] | 1249 |     // Preserve order with respect to any subsequent volatile loads. | 
 | 1250 |     // We need StoreLoad, but that generally requires the most expensive barrier. | 
 | 1251 |     GenMemBarrier(kAnyAny); | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1252 |   } | 
 | 1253 |  | 
 | 1254 |   return store; | 
| Vladimir Marko | 674744e | 2014-04-24 15:18:26 +0100 | [diff] [blame] | 1255 | } | 
 | 1256 |  | 
| Andreas Gampe | 3c12c51 | 2014-06-24 18:46:29 +0000 | [diff] [blame] | 1257 | LIR* Arm64Mir2Lir::StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src, | 
 | 1258 |                                 VolatileKind is_volatile) { | 
 | 1259 |   return StoreBaseDisp(r_base, displacement, As32BitReg(r_src), kReference, is_volatile); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1260 | } | 
 | 1261 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1262 | LIR* Arm64Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1263 |   LOG(FATAL) << "Unexpected use of OpFpRegCopy for Arm64"; | 
 | 1264 |   return NULL; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1265 | } | 
 | 1266 |  | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1267 | LIR* Arm64Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) { | 
| Matteo Franchin | e45fb9e | 2014-05-06 10:10:30 +0100 | [diff] [blame] | 1268 |   LOG(FATAL) << "Unexpected use of OpMem for Arm64"; | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1269 |   return NULL; | 
 | 1270 | } | 
 | 1271 |  | 
| Andreas Gampe | 9843059 | 2014-07-27 19:44:50 -0700 | [diff] [blame] | 1272 | LIR* Arm64Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) { | 
 | 1273 |   return OpReg(op, r_tgt); | 
| Matteo Franchin | 43ec873 | 2014-03-31 15:00:14 +0100 | [diff] [blame] | 1274 | } | 
 | 1275 |  | 
 | 1276 | }  // namespace art |