blob: 3b30cde0d44c4aa0ade6c4fd4c5db5b427a245a8 [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 */
buzbee091cc402014-03-31 10:14:40 -0700138uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 uint64_t seed;
140 int shift;
buzbee091cc402014-03-31 10:14:40 -0700141 int reg_id = reg.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142 /* Each double register is equal to a pair of single-precision FP registers */
buzbee091cc402014-03-31 10:14:40 -0700143 if (reg.IsDouble()) {
144 seed = 0x3;
145 reg_id = reg_id << 1;
146 } else {
147 seed = 1;
148 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 /* FP register starts at bit position 16 */
buzbee091cc402014-03-31 10:14:40 -0700150 shift = reg.IsFloat() ? kArmFPReg0 : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 /* Expand the double register id into single offset */
152 shift += reg_id;
153 return (seed << shift);
154}
155
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700156uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 return ENCODE_ARM_REG_PC;
158}
159
buzbeeb48819d2013-09-14 16:15:25 -0700160// Thumb2 specific setup. TODO: inline?:
161void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700163 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 int opcode = lir->opcode;
166
buzbeeb48819d2013-09-14 16:15:25 -0700167 // These flags are somewhat uncommon - bypass if we can.
168 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
169 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
170 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
171 if (flags & REG_DEF_SP) {
172 lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174
buzbeeb48819d2013-09-14 16:15:25 -0700175 if (flags & REG_USE_SP) {
176 lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 }
buzbeeb48819d2013-09-14 16:15:25 -0700178
179 if (flags & REG_DEF_LIST0) {
180 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700181 }
buzbeeb48819d2013-09-14 16:15:25 -0700182
183 if (flags & REG_DEF_LIST1) {
184 lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
185 }
186
187 if (flags & REG_DEF_FPCS_LIST0) {
188 lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
189 }
190
191 if (flags & REG_DEF_FPCS_LIST2) {
192 for (int i = 0; i < lir->operands[2]; i++) {
193 SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
194 }
195 }
196
197 if (flags & REG_USE_PC) {
198 lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
199 }
200
201 /* Conservatively treat the IT block */
202 if (flags & IS_IT) {
203 lir->u.m.def_mask = ENCODE_ALL;
204 }
205
206 if (flags & REG_USE_LIST0) {
207 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
208 }
209
210 if (flags & REG_USE_LIST1) {
211 lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
212 }
213
214 if (flags & REG_USE_FPCS_LIST0) {
215 lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
216 }
217
218 if (flags & REG_USE_FPCS_LIST2) {
219 for (int i = 0; i < lir->operands[2]; i++) {
220 SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
221 }
222 }
223 /* Fixup for kThumbPush/lr and kThumbPop/pc */
224 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbee091cc402014-03-31 10:14:40 -0700225 uint64_t r8Mask = GetRegMaskCommon(rs_r8);
buzbeeb48819d2013-09-14 16:15:25 -0700226 if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
227 lir->u.m.use_mask &= ~r8Mask;
228 lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
229 } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
230 lir->u.m.def_mask &= ~r8Mask;
231 lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
232 }
233 }
234 if (flags & REG_DEF_LR) {
235 lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
236 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 }
238}
239
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700240ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 ArmConditionCode res;
242 switch (ccode) {
243 case kCondEq: res = kArmCondEq; break;
244 case kCondNe: res = kArmCondNe; break;
245 case kCondCs: res = kArmCondCs; break;
246 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000247 case kCondUlt: res = kArmCondCc; break;
248 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700249 case kCondMi: res = kArmCondMi; break;
250 case kCondPl: res = kArmCondPl; break;
251 case kCondVs: res = kArmCondVs; break;
252 case kCondVc: res = kArmCondVc; break;
253 case kCondHi: res = kArmCondHi; break;
254 case kCondLs: res = kArmCondLs; break;
255 case kCondGe: res = kArmCondGe; break;
256 case kCondLt: res = kArmCondLt; break;
257 case kCondGt: res = kArmCondGt; break;
258 case kCondLe: res = kArmCondLe; break;
259 case kCondAl: res = kArmCondAl; break;
260 case kCondNv: res = kArmCondNv; break;
261 default:
262 LOG(FATAL) << "Bad condition code " << ccode;
263 res = static_cast<ArmConditionCode>(0); // Quiet gcc
264 }
265 return res;
266}
267
268static const char* core_reg_names[16] = {
269 "r0",
270 "r1",
271 "r2",
272 "r3",
273 "r4",
274 "r5",
275 "r6",
276 "r7",
277 "r8",
278 "rSELF",
279 "r10",
280 "r11",
281 "r12",
282 "sp",
283 "lr",
284 "pc",
285};
286
287
288static const char* shift_names[4] = {
289 "lsl",
290 "lsr",
291 "asr",
292 "ror"};
293
294/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800295static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 int i;
297 bool printed = false;
298 buf[0] = 0;
299 for (i = 0; i < 16; i++, vector >>= 1) {
300 if (vector & 0x1) {
301 int reg_id = i;
302 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700303 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700304 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700305 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 }
307 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800308 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 } else {
310 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800311 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 }
313 }
314 }
315 return buf;
316}
317
Ian Rogers988e6ea2014-01-08 11:30:50 -0800318static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
319 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800321 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700322 }
323 return buf;
324}
325
buzbee0d829482013-10-11 15:24:55 -0700326static int32_t ExpandImmediate(int value) {
327 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 uint32_t bits = value & 0xff;
329 switch (mode) {
330 case 0:
331 return bits;
332 case 1:
333 return (bits << 16) | bits;
334 case 2:
335 return (bits << 24) | (bits << 8);
336 case 3:
337 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
338 default:
339 break;
340 }
341 bits = (bits | 0x80) << 24;
342 return bits >> (((value & 0xf80) >> 7) - 8);
343}
344
Brian Carlstromb1eba212013-07-17 18:07:19 -0700345const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
346 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347/*
348 * Interpret a format string and build a string no longer than size
349 * See format key in Assemble.c.
350 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700351std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 std::string buf;
353 int i;
354 const char* fmt_end = &fmt[strlen(fmt)];
355 char tbuf[256];
356 const char* name;
357 char nc;
358 while (fmt < fmt_end) {
359 int operand;
360 if (*fmt == '!') {
361 fmt++;
362 DCHECK_LT(fmt, fmt_end);
363 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700364 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 strcpy(tbuf, "!");
366 } else {
367 DCHECK_LT(fmt, fmt_end);
368 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
369 operand = lir->operands[nc-'0'];
370 switch (*fmt++) {
371 case 'H':
372 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800373 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700374 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700375 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 }
377 break;
378 case 'B':
379 switch (operand) {
380 case kSY:
381 name = "sy";
382 break;
383 case kST:
384 name = "st";
385 break;
386 case kISH:
387 name = "ish";
388 break;
389 case kISHST:
390 name = "ishst";
391 break;
392 case kNSH:
393 name = "nsh";
394 break;
395 case kNSHST:
396 name = "shst";
397 break;
398 default:
399 name = "DecodeError2";
400 break;
401 }
402 strcpy(tbuf, name);
403 break;
404 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700405 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700406 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 tbuf[i] += operand & 1;
408 operand >>= 1;
409 }
410 break;
411 case 'n':
412 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800413 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 break;
415 case 'm':
416 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800417 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418 break;
419 case 's':
buzbee091cc402014-03-31 10:14:40 -0700420 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 break;
422 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700423 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 break;
425 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800426 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 break;
428 case 'M':
429 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800430 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700431 break;
432 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700433 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434 DCHECK_LT(operand, static_cast<int>(
435 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800436 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 break;
438 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800439 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700440 break;
441 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800442 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700443 break;
444 case 'c':
445 strcpy(tbuf, cc_names[operand]);
446 break;
447 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800448 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
449 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 lir->target);
451 break;
452 case 'u': {
453 int offset_1 = lir->operands[0];
454 int offset_2 = NEXT_LIR(lir)->operands[0];
455 uintptr_t target =
456 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
457 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
458 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800459 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 break;
461 }
462
463 /* Nothing to print for BLX_2 */
464 case 'v':
465 strcpy(tbuf, "see above");
466 break;
467 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800468 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 break;
470 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800471 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 break;
473 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800474 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 break;
476 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700477 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 break;
479 }
480 buf += tbuf;
481 }
482 } else {
483 buf += *fmt++;
484 }
485 }
486 return buf;
487}
488
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700489void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700490 char buf[256];
491 buf[0] = 0;
492
493 if (mask == ENCODE_ALL) {
494 strcpy(buf, "all");
495 } else {
496 char num[8];
497 int i;
498
499 for (i = 0; i < kArmRegEnd; i++) {
500 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800501 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 strcat(buf, num);
503 }
504 }
505
506 if (mask & ENCODE_CCODE) {
507 strcat(buf, "cc ");
508 }
509 if (mask & ENCODE_FP_STATUS) {
510 strcat(buf, "fpcc ");
511 }
512
513 /* Memory bits */
514 if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800515 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
516 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
517 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700518 }
519 if (mask & ENCODE_LITERAL) {
520 strcat(buf, "lit ");
521 }
522
523 if (mask & ENCODE_HEAP_REF) {
524 strcat(buf, "heap ");
525 }
526 if (mask & ENCODE_MUST_NOT_ALIAS) {
527 strcat(buf, "noalias ");
528 }
529 }
530 if (buf[0]) {
531 LOG(INFO) << prefix << ": " << buf;
532 }
533}
534
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700535bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700536 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
537}
538
Vladimir Marko674744e2014-04-24 15:18:26 +0100539bool ArmMir2Lir::SupportsVolatileLoadStore(OpSize size) {
540 return true;
541}
542
543RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
544 if (UNLIKELY(is_volatile)) {
545 // On arm, atomic 64-bit load/store requires a core register pair.
546 // Smaller aligned load/store is atomic for both core and fp registers.
547 if (size == k64 || size == kDouble) {
548 return kCoreReg;
549 }
550 }
551 return RegClassBySize(size);
552}
553
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
555 : Mir2Lir(cu, mir_graph, arena) {
556 // Sanity check - make sure encoding map lines up.
557 for (int i = 0; i < kArmLast; i++) {
558 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
559 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
560 << " is wrong: expecting " << i << ", seeing "
561 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
562 }
563 }
564}
565
566Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
567 ArenaAllocator* const arena) {
568 return new ArmMir2Lir(cu, mir_graph, arena);
569}
570
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700571void ArmMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700572 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
573 dp_regs, reserved_regs, empty_pool /* reserved64 */,
574 core_temps, empty_pool /* core64_temps */, sp_temps,
575 dp_temps);
Dave Allisonf6b65c12014-04-01 17:45:18 -0700576
buzbee091cc402014-03-31 10:14:40 -0700577 // Target-specific adjustments.
578
579 // Alias single precision floats to appropriate half of overlapping double.
580 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
581 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
582 int sp_reg_num = info->GetReg().GetRegNum();
583 int dp_reg_num = sp_reg_num >> 1;
584 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
585 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
586 // Double precision register's master storage should refer to itself.
587 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
588 // Redirect single precision's master storage to master.
589 info->SetMaster(dp_reg_info);
590 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700591 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700592 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700593 // For odd singles, change to use the high word of the backing double.
594 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700595 }
596 }
597
Wei Jin04f4d8a2014-05-29 18:04:29 -0700598#ifdef ARM_R4_SUSPEND_FLAG
Dave Allison83252962014-04-03 16:33:48 -0700599 // TODO: re-enable this when we can safely save r4 over the suspension code path.
600 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700601 if (no_suspend) {
602 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700603 }
Wei Jin04f4d8a2014-05-29 18:04:29 -0700604#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605
buzbee091cc402014-03-31 10:14:40 -0700606 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
607 // TODO: adjust when we roll to hard float calling convention.
608 reg_pool_->next_core_reg_ = 2;
609 reg_pool_->next_sp_reg_ = 0;
610 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611}
612
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613/*
614 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
615 * instructions might call out to C/assembly helper functions. Until
616 * machinery is in place, always spill lr.
617 */
618
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700619void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700620 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 num_core_spills_++;
622}
623
624/*
625 * Mark a callee-save fp register as promoted. Note that
626 * vpush/vpop uses contiguous register lists so we must
627 * include any holes in the mask. Associate holes with
628 * Dalvik register INVALID_VREG (0xFFFFU).
629 */
buzbee091cc402014-03-31 10:14:40 -0700630void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
631 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
632 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700633 // Ensure fp_vmap_table is large enough
634 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700635 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700636 fp_vmap_table_.push_back(INVALID_VREG);
637 }
638 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700639 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 // Size of fp_vmap_table is high-water mark, use to set mask
641 num_fp_spills_ = fp_vmap_table_.size();
642 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
643}
644
buzbee091cc402014-03-31 10:14:40 -0700645void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
646 // TEMP: perform as 2 singles.
647 int reg_num = reg.GetRegNum() << 1;
648 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
649 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
650 MarkPreservedSingle(v_reg, lo);
651 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800652}
653
Brian Carlstrom7940e442013-07-12 13:46:57 -0700654/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000655void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700656 // TODO: rework this - it's gotten even more ugly.
657 Clobber(rs_r0);
658 Clobber(rs_r1);
659 Clobber(rs_r2);
660 Clobber(rs_r3);
661 Clobber(rs_r12);
662 Clobber(rs_r14lr);
663 Clobber(rs_fr0);
664 Clobber(rs_fr1);
665 Clobber(rs_fr2);
666 Clobber(rs_fr3);
667 Clobber(rs_fr4);
668 Clobber(rs_fr5);
669 Clobber(rs_fr6);
670 Clobber(rs_fr7);
671 Clobber(rs_fr8);
672 Clobber(rs_fr9);
673 Clobber(rs_fr10);
674 Clobber(rs_fr11);
675 Clobber(rs_fr12);
676 Clobber(rs_fr13);
677 Clobber(rs_fr14);
678 Clobber(rs_fr15);
679 Clobber(rs_dr0);
680 Clobber(rs_dr1);
681 Clobber(rs_dr2);
682 Clobber(rs_dr3);
683 Clobber(rs_dr4);
684 Clobber(rs_dr5);
685 Clobber(rs_dr6);
686 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687}
688
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700689RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700691 res.reg.SetLowReg(rs_r2.GetReg());
692 res.reg.SetHighReg(rs_r3.GetReg());
693 Clobber(rs_r2);
694 Clobber(rs_r3);
695 MarkInUse(rs_r2);
696 MarkInUse(rs_r3);
697 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698 return res;
699}
700
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700701RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700702 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700703 res.reg.SetReg(rs_r1.GetReg());
704 Clobber(rs_r1);
705 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706 return res;
707}
708
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700710void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700711 LockTemp(rs_r0);
712 LockTemp(rs_r1);
713 LockTemp(rs_r2);
714 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700715}
716
717/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700718void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700719 FreeTemp(rs_r0);
720 FreeTemp(rs_r1);
721 FreeTemp(rs_r2);
722 FreeTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700723}
724
Ian Rogersdd7624d2014-03-14 17:43:00 -0700725RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee2700f7e2014-03-07 09:46:20 -0800726 LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
727 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728}
729
Andreas Gampe2f244e92014-05-08 03:35:25 -0700730RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
731 UNIMPLEMENTED(FATAL) << "Should not be called.";
732 return RegStorage::InvalidReg();
733}
734
Dave Allisonb373e092014-02-20 16:06:36 -0800735LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800736 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700737 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
738 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800739 return load2;
740}
741
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700742uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700743 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700744 return ArmMir2Lir::EncodingMap[opcode].flags;
745}
746
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700747const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700748 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700749 return ArmMir2Lir::EncodingMap[opcode].name;
750}
751
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700752const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700753 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700754 return ArmMir2Lir::EncodingMap[opcode].fmt;
755}
756
buzbee091cc402014-03-31 10:14:40 -0700757/*
758 * Somewhat messy code here. We want to allocate a pair of contiguous
759 * physical single-precision floating point registers starting with
760 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
761 * has already been allocated - try to fit if possible. Fail to
762 * allocate if we can't meet the requirements for the pair of
763 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
764 */
765// TODO: needs rewrite to support non-backed 64-bit float regs.
766RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
767 RegStorage res;
768 int v_reg = mir_graph_->SRegToVReg(s_reg);
769 int p_map_idx = SRegToPMap(s_reg);
770 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
771 // Upper reg is already allocated. Can we fit?
772 int high_reg = promotion_map_[p_map_idx+1].FpReg;
773 if ((high_reg & 1) == 0) {
774 // High reg is even - fail.
775 return res; // Invalid.
776 }
777 // Is the low reg of the pair free?
778 // FIXME: rework.
779 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
780 if (p->InUse() || p->IsTemp()) {
781 // Already allocated or not preserved - fail.
782 return res; // Invalid.
783 }
784 // OK - good to go.
785 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
786 p->MarkInUse();
787 MarkPreservedSingle(v_reg, p->GetReg());
788 } else {
789 /*
790 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
791 * different underlying physical registers.
792 */
793 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
794 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
795 if (!info->IsTemp() && !info->InUse()) {
796 res = info->GetReg();
797 info->MarkInUse();
798 MarkPreservedDouble(v_reg, info->GetReg());
799 break;
800 }
801 }
802 }
803 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700804 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700805 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700806 promotion_map_[p_map_idx].FpReg =
807 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700808 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbee85089dd2014-05-25 15:10:52 -0700809 promotion_map_[p_map_idx+1].FpReg =
810 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700811 }
812 return res;
813}
814
Brian Carlstrom7940e442013-07-12 13:46:57 -0700815} // namespace art