blob: ef94bbc3cce8c1526ff35f2f448ff254f4f6ec78 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ian Rogers107c31e2014-01-23 20:55:29 -080017#include "codegen_arm.h"
18
19#include <inttypes.h>
20
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include <string>
22
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25
26namespace art {
27
Wei Jin04f4d8a2014-05-29 18:04:29 -070028#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010029static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070030 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
31 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Wei Jin04f4d8a2014-05-29 18:04:29 -070032#else
33static constexpr RegStorage core_regs_arr[] =
34 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
35 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
36#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010037static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070038 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
39 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
40 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
41 rs_fr31};
Vladimir Marko089142c2014-06-05 10:57:05 +010042static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070043 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
44 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
Wei Jin04f4d8a2014-05-29 18:04:29 -070045#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010046static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070047 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010048static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
Wei Jin04f4d8a2014-05-29 18:04:29 -070049#else
50static constexpr RegStorage reserved_regs_arr[] =
51 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
52static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
53#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010054static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070055 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
56 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010057static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070058 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
59
Vladimir Marko089142c2014-06-05 10:57:05 +010060static constexpr ArrayRef<const RegStorage> empty_pool;
61static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
62static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
63static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
64static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
65static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
66static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
67static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070068
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070069RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000070 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070071}
72
buzbeea0cd2d72014-06-01 09:33:49 -070073RegLocation ArmMir2Lir::LocCReturnRef() {
74 return arm_loc_c_return;
75}
76
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070077RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000078 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070079}
80
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070081RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000082 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070083}
84
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070085RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000086 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070087}
88
89// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080090RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070091 RegStorage res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -070092 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070093 case kSelf: res_reg = rs_rARM_SELF; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070094#ifdef ARM_R4_SUSPEND_FLAG
buzbee091cc402014-03-31 10:14:40 -070095 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070096#else
97 case kSuspend: res_reg = RegStorage::InvalidReg(); break;
98#endif
buzbee091cc402014-03-31 10:14:40 -070099 case kLr: res_reg = rs_rARM_LR; break;
100 case kPc: res_reg = rs_rARM_PC; break;
101 case kSp: res_reg = rs_rARM_SP; break;
102 case kArg0: res_reg = rs_r0; break;
103 case kArg1: res_reg = rs_r1; break;
104 case kArg2: res_reg = rs_r2; break;
105 case kArg3: res_reg = rs_r3; break;
106 case kFArg0: res_reg = rs_r0; break;
107 case kFArg1: res_reg = rs_r1; break;
108 case kFArg2: res_reg = rs_r2; break;
109 case kFArg3: res_reg = rs_r3; break;
110 case kRet0: res_reg = rs_r0; break;
111 case kRet1: res_reg = rs_r1; break;
112 case kInvokeTgt: res_reg = rs_rARM_LR; break;
113 case kHiddenArg: res_reg = rs_r12; break;
114 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
115 case kCount: res_reg = RegStorage::InvalidReg(); break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700116 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 }
buzbee091cc402014-03-31 10:14:40 -0700118 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119}
120
buzbee2700f7e2014-03-07 09:46:20 -0800121RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800122 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
123 switch (arg_num) {
124 case 0:
buzbee091cc402014-03-31 10:14:40 -0700125 return rs_r1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800126 case 1:
buzbee091cc402014-03-31 10:14:40 -0700127 return rs_r2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800128 case 2:
buzbee091cc402014-03-31 10:14:40 -0700129 return rs_r3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800130 default:
buzbee2700f7e2014-03-07 09:46:20 -0800131 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800132 }
133}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135/*
136 * Decode the register id.
137 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100138ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
139 return GetRegMaskArm(reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140}
141
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100142constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) {
143 return reg.IsDouble()
144 /* Each double register is equal to a pair of single-precision FP registers */
145 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0)
146 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum());
147}
148
149constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
150 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
151}
152
153constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
154 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
155}
156
157ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
158 return ResourceMask::Bit(kArmRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159}
160
buzbeeb48819d2013-09-14 16:15:25 -0700161// Thumb2 specific setup. TODO: inline?:
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100162void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
163 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700165 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167 int opcode = lir->opcode;
168
buzbeeb48819d2013-09-14 16:15:25 -0700169 // These flags are somewhat uncommon - bypass if we can.
170 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
171 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
172 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
173 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100174 def_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176
buzbeeb48819d2013-09-14 16:15:25 -0700177 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100178 use_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700179 }
buzbeeb48819d2013-09-14 16:15:25 -0700180
181 if (flags & REG_DEF_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100182 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 }
buzbeeb48819d2013-09-14 16:15:25 -0700184
185 if (flags & REG_DEF_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100186 def_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700187 }
188
189 if (flags & REG_DEF_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100190 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700191 }
192
193 if (flags & REG_DEF_FPCS_LIST2) {
194 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100195 SetupRegMask(def_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700196 }
197 }
198
199 if (flags & REG_USE_PC) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100200 use_mask->SetBit(kArmRegPC);
buzbeeb48819d2013-09-14 16:15:25 -0700201 }
202
203 /* Conservatively treat the IT block */
204 if (flags & IS_IT) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100205 *def_mask = kEncodeAll;
buzbeeb48819d2013-09-14 16:15:25 -0700206 }
207
208 if (flags & REG_USE_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100209 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700210 }
211
212 if (flags & REG_USE_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100213 use_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700214 }
215
216 if (flags & REG_USE_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100217 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700218 }
219
220 if (flags & REG_USE_FPCS_LIST2) {
221 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100222 SetupRegMask(use_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700223 }
224 }
225 /* Fixup for kThumbPush/lr and kThumbPop/pc */
226 if (opcode == kThumbPush || opcode == kThumbPop) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100227 constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8);
228 if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) {
229 use_mask->ClearBits(r8Mask);
230 use_mask->SetBit(kArmRegLR);
231 } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) {
232 def_mask->ClearBits(r8Mask);
233 def_mask->SetBit(kArmRegPC);;
buzbeeb48819d2013-09-14 16:15:25 -0700234 }
235 }
236 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100237 def_mask->SetBit(kArmRegLR);
buzbeeb48819d2013-09-14 16:15:25 -0700238 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 }
240}
241
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700242ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 ArmConditionCode res;
244 switch (ccode) {
245 case kCondEq: res = kArmCondEq; break;
246 case kCondNe: res = kArmCondNe; break;
247 case kCondCs: res = kArmCondCs; break;
248 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000249 case kCondUlt: res = kArmCondCc; break;
250 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 case kCondMi: res = kArmCondMi; break;
252 case kCondPl: res = kArmCondPl; break;
253 case kCondVs: res = kArmCondVs; break;
254 case kCondVc: res = kArmCondVc; break;
255 case kCondHi: res = kArmCondHi; break;
256 case kCondLs: res = kArmCondLs; break;
257 case kCondGe: res = kArmCondGe; break;
258 case kCondLt: res = kArmCondLt; break;
259 case kCondGt: res = kArmCondGt; break;
260 case kCondLe: res = kArmCondLe; break;
261 case kCondAl: res = kArmCondAl; break;
262 case kCondNv: res = kArmCondNv; break;
263 default:
264 LOG(FATAL) << "Bad condition code " << ccode;
265 res = static_cast<ArmConditionCode>(0); // Quiet gcc
266 }
267 return res;
268}
269
270static const char* core_reg_names[16] = {
271 "r0",
272 "r1",
273 "r2",
274 "r3",
275 "r4",
276 "r5",
277 "r6",
278 "r7",
279 "r8",
280 "rSELF",
281 "r10",
282 "r11",
283 "r12",
284 "sp",
285 "lr",
286 "pc",
287};
288
289
290static const char* shift_names[4] = {
291 "lsl",
292 "lsr",
293 "asr",
294 "ror"};
295
296/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800297static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 int i;
299 bool printed = false;
300 buf[0] = 0;
301 for (i = 0; i < 16; i++, vector >>= 1) {
302 if (vector & 0x1) {
303 int reg_id = i;
304 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700305 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700307 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 }
309 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800310 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 } else {
312 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800313 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 }
315 }
316 }
317 return buf;
318}
319
Ian Rogers988e6ea2014-01-08 11:30:50 -0800320static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
321 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700322 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800323 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 }
325 return buf;
326}
327
buzbee0d829482013-10-11 15:24:55 -0700328static int32_t ExpandImmediate(int value) {
329 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 uint32_t bits = value & 0xff;
331 switch (mode) {
332 case 0:
333 return bits;
334 case 1:
335 return (bits << 16) | bits;
336 case 2:
337 return (bits << 24) | (bits << 8);
338 case 3:
339 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
340 default:
341 break;
342 }
343 bits = (bits | 0x80) << 24;
344 return bits >> (((value & 0xf80) >> 7) - 8);
345}
346
Brian Carlstromb1eba212013-07-17 18:07:19 -0700347const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
348 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349/*
350 * Interpret a format string and build a string no longer than size
351 * See format key in Assemble.c.
352 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700353std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 std::string buf;
355 int i;
356 const char* fmt_end = &fmt[strlen(fmt)];
357 char tbuf[256];
358 const char* name;
359 char nc;
360 while (fmt < fmt_end) {
361 int operand;
362 if (*fmt == '!') {
363 fmt++;
364 DCHECK_LT(fmt, fmt_end);
365 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700366 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367 strcpy(tbuf, "!");
368 } else {
369 DCHECK_LT(fmt, fmt_end);
370 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
371 operand = lir->operands[nc-'0'];
372 switch (*fmt++) {
373 case 'H':
374 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800375 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700377 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700378 }
379 break;
380 case 'B':
381 switch (operand) {
382 case kSY:
383 name = "sy";
384 break;
385 case kST:
386 name = "st";
387 break;
388 case kISH:
389 name = "ish";
390 break;
391 case kISHST:
392 name = "ishst";
393 break;
394 case kNSH:
395 name = "nsh";
396 break;
397 case kNSHST:
398 name = "shst";
399 break;
400 default:
401 name = "DecodeError2";
402 break;
403 }
404 strcpy(tbuf, name);
405 break;
406 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700407 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700408 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 tbuf[i] += operand & 1;
410 operand >>= 1;
411 }
412 break;
413 case 'n':
414 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800415 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700416 break;
417 case 'm':
418 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800419 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 break;
421 case 's':
buzbee091cc402014-03-31 10:14:40 -0700422 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 break;
424 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700425 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700426 break;
427 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800428 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 break;
430 case 'M':
431 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800432 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 break;
434 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700435 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 DCHECK_LT(operand, static_cast<int>(
437 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800438 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 break;
440 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800441 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 break;
443 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800444 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 break;
446 case 'c':
447 strcpy(tbuf, cc_names[operand]);
448 break;
449 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800450 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
451 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 lir->target);
453 break;
454 case 'u': {
455 int offset_1 = lir->operands[0];
456 int offset_2 = NEXT_LIR(lir)->operands[0];
457 uintptr_t target =
458 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
459 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
460 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800461 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700462 break;
463 }
464
465 /* Nothing to print for BLX_2 */
466 case 'v':
467 strcpy(tbuf, "see above");
468 break;
469 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800470 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 break;
472 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800473 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474 break;
475 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800476 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 break;
478 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700479 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 break;
481 }
482 buf += tbuf;
483 }
484 } else {
485 buf += *fmt++;
486 }
487 }
488 return buf;
489}
490
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100491void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700492 char buf[256];
493 buf[0] = 0;
494
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100495 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 strcpy(buf, "all");
497 } else {
498 char num[8];
499 int i;
500
501 for (i = 0; i < kArmRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100502 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800503 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504 strcat(buf, num);
505 }
506 }
507
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100508 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700509 strcat(buf, "cc ");
510 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100511 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 strcat(buf, "fpcc ");
513 }
514
515 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100516 if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800517 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
518 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
519 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700520 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100521 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522 strcat(buf, "lit ");
523 }
524
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100525 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526 strcat(buf, "heap ");
527 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100528 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700529 strcat(buf, "noalias ");
530 }
531 }
532 if (buf[0]) {
533 LOG(INFO) << prefix << ": " << buf;
534 }
535}
536
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700537bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
539}
540
Vladimir Marko674744e2014-04-24 15:18:26 +0100541bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
542 return true;
543}
544
545RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
546 if (UNLIKELY(is_volatile)) {
547 // On arm, atomic 64-bit load/store requires a core register pair.
548 // Smaller aligned load/store is atomic for both core and fp registers.
549 if (size == k64 || size == kDouble) {
550 return kCoreReg;
551 }
552 }
553 return RegClassBySize(size);
554}
555
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
557 : Mir2Lir(cu, mir_graph, arena) {
558 // Sanity check - make sure encoding map lines up.
559 for (int i = 0; i < kArmLast; i++) {
560 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
561 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
562 << " is wrong: expecting " << i << ", seeing "
563 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
564 }
565 }
566}
567
568Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
569 ArenaAllocator* const arena) {
570 return new ArmMir2Lir(cu, mir_graph, arena);
571}
572
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700573void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700574 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
575 dp_regs, reserved_regs, empty_pool /* reserved64 */,
576 core_temps, empty_pool /* core64_temps */, sp_temps,
577 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700578
buzbee091cc402014-03-31 10:14:40 -0700579 // Target-specific adjustments.
580
581 // Alias single precision floats to appropriate half of overlapping double.
582 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
583 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
584 int sp_reg_num = info->GetReg().GetRegNum();
585 int dp_reg_num = sp_reg_num >> 1;
586 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
587 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
588 // Double precision register's master storage should refer to itself.
589 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
590 // Redirect single precision's master storage to master.
591 info->SetMaster(dp_reg_info);
592 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700593 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700594 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700595 // For odd singles, change to use the high word of the backing double.
596 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700597 }
598 }
599
Wei Jin04f4d8a2014-05-29 18:04:29 -0700600#ifdef ARM_R4_SUSPEND_FLAG
Dave Allison83252962014-04-03 16:33:48 -0700601 // TODO: re-enable this when we can safely save r4 over the suspension code path.
602 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700603 if (no_suspend) {
604 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605 }
Wei Jin04f4d8a2014-05-29 18:04:29 -0700606#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607
buzbee091cc402014-03-31 10:14:40 -0700608 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
609 // TODO: adjust when we roll to hard float calling convention.
610 reg_pool_->next_core_reg_ = 2;
611 reg_pool_->next_sp_reg_ = 0;
612 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613}
614
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615/*
616 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
617 * instructions might call out to C/assembly helper functions. Until
618 * machinery is in place, always spill lr.
619 */
620
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700621void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700622 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 num_core_spills_++;
624}
625
626/*
627 * Mark a callee-save fp register as promoted. Note that
628 * vpush/vpop uses contiguous register lists so we must
629 * include any holes in the mask. Associate holes with
630 * Dalvik register INVALID_VREG (0xFFFFU).
631 */
buzbee091cc402014-03-31 10:14:40 -0700632void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
633 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
634 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700635 // Ensure fp_vmap_table is large enough
636 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700637 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700638 fp_vmap_table_.push_back(INVALID_VREG);
639 }
640 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700641 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700642 // Size of fp_vmap_table is high-water mark, use to set mask
643 num_fp_spills_ = fp_vmap_table_.size();
644 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
645}
646
buzbee091cc402014-03-31 10:14:40 -0700647void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
648 // TEMP: perform as 2 singles.
649 int reg_num = reg.GetRegNum() << 1;
650 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
651 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
652 MarkPreservedSingle(v_reg, lo);
653 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800654}
655
Brian Carlstrom7940e442013-07-12 13:46:57 -0700656/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000657void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700658 // TODO: rework this - it's gotten even more ugly.
659 Clobber(rs_r0);
660 Clobber(rs_r1);
661 Clobber(rs_r2);
662 Clobber(rs_r3);
663 Clobber(rs_r12);
664 Clobber(rs_r14lr);
665 Clobber(rs_fr0);
666 Clobber(rs_fr1);
667 Clobber(rs_fr2);
668 Clobber(rs_fr3);
669 Clobber(rs_fr4);
670 Clobber(rs_fr5);
671 Clobber(rs_fr6);
672 Clobber(rs_fr7);
673 Clobber(rs_fr8);
674 Clobber(rs_fr9);
675 Clobber(rs_fr10);
676 Clobber(rs_fr11);
677 Clobber(rs_fr12);
678 Clobber(rs_fr13);
679 Clobber(rs_fr14);
680 Clobber(rs_fr15);
681 Clobber(rs_dr0);
682 Clobber(rs_dr1);
683 Clobber(rs_dr2);
684 Clobber(rs_dr3);
685 Clobber(rs_dr4);
686 Clobber(rs_dr5);
687 Clobber(rs_dr6);
688 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700689}
690
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700691RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700692 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700693 res.reg.SetLowReg(rs_r2.GetReg());
694 res.reg.SetHighReg(rs_r3.GetReg());
695 Clobber(rs_r2);
696 Clobber(rs_r3);
697 MarkInUse(rs_r2);
698 MarkInUse(rs_r3);
699 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700700 return res;
701}
702
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700703RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700705 res.reg.SetReg(rs_r1.GetReg());
706 Clobber(rs_r1);
707 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700708 return res;
709}
710
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700712void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700713 LockTemp(rs_r0);
714 LockTemp(rs_r1);
715 LockTemp(rs_r2);
716 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717}
718
719/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700720void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700721 FreeTemp(rs_r0);
722 FreeTemp(rs_r1);
723 FreeTemp(rs_r2);
724 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700725}
726
Ian Rogersdd7624d2014-03-14 17:43:00 -0700727RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800728 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
729 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700730}
731
Andreas Gampe2f244e92014-05-08 03:35:25 -0700732RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
733 UNIMPLEMENTED(FATAL) << "Should not be called.";
734 return RegStorage::InvalidReg();
735}
736
Dave Allisonb373e092014-02-20 16:06:36 -0800737LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800738 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700739 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
740 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800741 return load2;
742}
743
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700744uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700745 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700746 return ArmMir2Lir::EncodingMap[opcode].flags;
747}
748
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700749const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700750 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700751 return ArmMir2Lir::EncodingMap[opcode].name;
752}
753
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700754const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700755 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700756 return ArmMir2Lir::EncodingMap[opcode].fmt;
757}
758
buzbee091cc402014-03-31 10:14:40 -0700759/*
760 * Somewhat messy code here. We want to allocate a pair of contiguous
761 * physical single-precision floating point registers starting with
762 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
763 * has already been allocated - try to fit if possible. Fail to
764 * allocate if we can't meet the requirements for the pair of
765 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
766 */
767// TODO: needs rewrite to support non-backed 64-bit float regs.
768RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
769 RegStorage res;
770 int v_reg = mir_graph_->SRegToVReg(s_reg);
771 int p_map_idx = SRegToPMap(s_reg);
772 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
773 // Upper reg is already allocated. Can we fit?
buzbeeb5860fb2014-06-21 15:31:01 -0700774 int high_reg = promotion_map_[p_map_idx+1].fp_reg;
buzbee091cc402014-03-31 10:14:40 -0700775 if ((high_reg & 1) == 0) {
776 // High reg is even - fail.
777 return res; // Invalid.
778 }
779 // Is the low reg of the pair free?
780 // FIXME: rework.
781 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
782 if (p->InUse() || p->IsTemp()) {
783 // Already allocated or not preserved - fail.
784 return res; // Invalid.
785 }
786 // OK - good to go.
787 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
788 p->MarkInUse();
789 MarkPreservedSingle(v_reg, p->GetReg());
790 } else {
791 /*
792 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
793 * different underlying physical registers.
794 */
795 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
796 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
797 if (!info->IsTemp() && !info->InUse()) {
798 res = info->GetReg();
799 info->MarkInUse();
800 MarkPreservedDouble(v_reg, info->GetReg());
801 break;
802 }
803 }
804 }
805 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700806 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700807 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700808 promotion_map_[p_map_idx].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700809 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700810 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700811 promotion_map_[p_map_idx+1].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700812 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700813 }
814 return res;
815}
816
buzbeeb5860fb2014-06-21 15:31:01 -0700817// Reserve a callee-save sp single register.
818RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
819 RegStorage res;
820 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
821 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
822 if (!info->IsTemp() && !info->InUse()) {
823 res = info->GetReg();
824 int p_map_idx = SRegToPMap(s_reg);
825 int v_reg = mir_graph_->SRegToVReg(s_reg);
826 GetRegInfo(res)->MarkInUse();
827 MarkPreservedSingle(v_reg, res);
828 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
829 promotion_map_[p_map_idx].fp_reg = res.GetReg();
830 break;
831 }
832 }
833 return res;
834}
835
Brian Carlstrom7940e442013-07-12 13:46:57 -0700836} // namespace art