blob: 7100a285a604cc9ff7980df6f3d9509293877086 [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
Andreas Gampe53c913b2014-08-12 23:19:23 -070023#include "backend_arm.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024#include "dex/compiler_internals.h"
25#include "dex/quick/mir_to_lir-inl.h"
26
27namespace art {
28
Wei Jin04f4d8a2014-05-29 18:04:29 -070029#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010030static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070031 {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
32 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Wei Jin04f4d8a2014-05-29 18:04:29 -070033#else
34static constexpr RegStorage core_regs_arr[] =
35 {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
36 rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
37#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010038static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070039 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
40 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
41 rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
42 rs_fr31};
Vladimir Marko089142c2014-06-05 10:57:05 +010043static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070044 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
45 rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
Wei Jin04f4d8a2014-05-29 18:04:29 -070046#ifdef ARM_R4_SUSPEND_FLAG
Vladimir Marko089142c2014-06-05 10:57:05 +010047static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070048 {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
Vladimir Marko089142c2014-06-05 10:57:05 +010049static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
Wei Jin04f4d8a2014-05-29 18:04:29 -070050#else
51static constexpr RegStorage reserved_regs_arr[] =
52 {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
53static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
54#endif
Vladimir Marko089142c2014-06-05 10:57:05 +010055static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070056 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
57 rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
Vladimir Marko089142c2014-06-05 10:57:05 +010058static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070059 {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
60
Vladimir Marko089142c2014-06-05 10:57:05 +010061static constexpr ArrayRef<const RegStorage> empty_pool;
62static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
63static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
64static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
65static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
66static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
67static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
68static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070069
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070070RegLocation ArmMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000071 return arm_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070072}
73
buzbeea0cd2d72014-06-01 09:33:49 -070074RegLocation ArmMir2Lir::LocCReturnRef() {
75 return arm_loc_c_return;
76}
77
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070078RegLocation ArmMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000079 return arm_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070080}
81
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070082RegLocation ArmMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000083 return arm_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070084}
85
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070086RegLocation ArmMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000087 return arm_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070088}
89
90// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080091RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
Zheng Xu5667fdb2014-10-23 18:29:55 +080092 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070093 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070094 case kSelf: res_reg = rs_rARM_SELF; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070095#ifdef ARM_R4_SUSPEND_FLAG
buzbee091cc402014-03-31 10:14:40 -070096 case kSuspend: res_reg = rs_rARM_SUSPEND; break;
Wei Jin04f4d8a2014-05-29 18:04:29 -070097#else
98 case kSuspend: res_reg = RegStorage::InvalidReg(); break;
99#endif
buzbee091cc402014-03-31 10:14:40 -0700100 case kLr: res_reg = rs_rARM_LR; break;
101 case kPc: res_reg = rs_rARM_PC; break;
102 case kSp: res_reg = rs_rARM_SP; break;
103 case kArg0: res_reg = rs_r0; break;
104 case kArg1: res_reg = rs_r1; break;
105 case kArg2: res_reg = rs_r2; break;
106 case kArg3: res_reg = rs_r3; break;
Zheng Xu5667fdb2014-10-23 18:29:55 +0800107 case kFArg0: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r0 : rs_fr0; break;
108 case kFArg1: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r1 : rs_fr1; break;
109 case kFArg2: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r2 : rs_fr2; break;
110 case kFArg3: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r3 : rs_fr3; break;
111 case kFArg4: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr4; break;
112 case kFArg5: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr5; break;
113 case kFArg6: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr6; break;
114 case kFArg7: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr7; break;
115 case kFArg8: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr8; break;
116 case kFArg9: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr9; break;
117 case kFArg10: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr10; break;
118 case kFArg11: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr11; break;
119 case kFArg12: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr12; break;
120 case kFArg13: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr13; break;
121 case kFArg14: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr14; break;
122 case kFArg15: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr15; break;
buzbee091cc402014-03-31 10:14:40 -0700123 case kRet0: res_reg = rs_r0; break;
124 case kRet1: res_reg = rs_r1; break;
125 case kInvokeTgt: res_reg = rs_rARM_LR; break;
126 case kHiddenArg: res_reg = rs_r12; break;
127 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
128 case kCount: res_reg = RegStorage::InvalidReg(); break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700129 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 }
buzbee091cc402014-03-31 10:14:40 -0700131 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132}
133
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134/*
135 * Decode the register id.
136 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100137ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
138 return GetRegMaskArm(reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139}
140
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100141constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) {
142 return reg.IsDouble()
143 /* Each double register is equal to a pair of single-precision FP registers */
144 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0)
145 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum());
146}
147
148constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
149 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
150}
151
152constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
153 return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
154}
155
156ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
157 return ResourceMask::Bit(kArmRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158}
159
buzbeeb48819d2013-09-14 16:15:25 -0700160// Thumb2 specific setup. TODO: inline?:
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100161void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
162 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 DCHECK_EQ(cu_->instruction_set, kThumb2);
buzbeeb48819d2013-09-14 16:15:25 -0700164 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166 int opcode = lir->opcode;
167
buzbeeb48819d2013-09-14 16:15:25 -0700168 // These flags are somewhat uncommon - bypass if we can.
169 if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
170 REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
171 REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
172 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100173 def_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175
buzbeeb48819d2013-09-14 16:15:25 -0700176 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100177 use_mask->SetBit(kArmRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 }
buzbeeb48819d2013-09-14 16:15:25 -0700179
180 if (flags & REG_DEF_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100181 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700182 }
buzbeeb48819d2013-09-14 16:15:25 -0700183
184 if (flags & REG_DEF_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100185 def_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700186 }
187
188 if (flags & REG_DEF_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100189 def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700190 }
191
192 if (flags & REG_DEF_FPCS_LIST2) {
193 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100194 SetupRegMask(def_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700195 }
196 }
197
198 if (flags & REG_USE_PC) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100199 use_mask->SetBit(kArmRegPC);
buzbeeb48819d2013-09-14 16:15:25 -0700200 }
201
202 /* Conservatively treat the IT block */
203 if (flags & IS_IT) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100204 *def_mask = kEncodeAll;
buzbeeb48819d2013-09-14 16:15:25 -0700205 }
206
207 if (flags & REG_USE_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100208 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700209 }
210
211 if (flags & REG_USE_LIST1) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100212 use_mask->SetBits(EncodeArmRegList(lir->operands[1]));
buzbeeb48819d2013-09-14 16:15:25 -0700213 }
214
215 if (flags & REG_USE_FPCS_LIST0) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100216 use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
buzbeeb48819d2013-09-14 16:15:25 -0700217 }
218
219 if (flags & REG_USE_FPCS_LIST2) {
220 for (int i = 0; i < lir->operands[2]; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100221 SetupRegMask(use_mask, lir->operands[1] + i);
buzbeeb48819d2013-09-14 16:15:25 -0700222 }
223 }
224 /* Fixup for kThumbPush/lr and kThumbPop/pc */
225 if (opcode == kThumbPush || opcode == kThumbPop) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100226 constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8);
227 if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) {
228 use_mask->ClearBits(r8Mask);
229 use_mask->SetBit(kArmRegLR);
230 } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) {
231 def_mask->ClearBits(r8Mask);
232 def_mask->SetBit(kArmRegPC);;
buzbeeb48819d2013-09-14 16:15:25 -0700233 }
234 }
235 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100236 def_mask->SetBit(kArmRegLR);
buzbeeb48819d2013-09-14 16:15:25 -0700237 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700238 }
239}
240
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700241ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 ArmConditionCode res;
243 switch (ccode) {
244 case kCondEq: res = kArmCondEq; break;
245 case kCondNe: res = kArmCondNe; break;
246 case kCondCs: res = kArmCondCs; break;
247 case kCondCc: res = kArmCondCc; break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000248 case kCondUlt: res = kArmCondCc; break;
249 case kCondUge: res = kArmCondCs; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 case kCondMi: res = kArmCondMi; break;
251 case kCondPl: res = kArmCondPl; break;
252 case kCondVs: res = kArmCondVs; break;
253 case kCondVc: res = kArmCondVc; break;
254 case kCondHi: res = kArmCondHi; break;
255 case kCondLs: res = kArmCondLs; break;
256 case kCondGe: res = kArmCondGe; break;
257 case kCondLt: res = kArmCondLt; break;
258 case kCondGt: res = kArmCondGt; break;
259 case kCondLe: res = kArmCondLe; break;
260 case kCondAl: res = kArmCondAl; break;
261 case kCondNv: res = kArmCondNv; break;
262 default:
263 LOG(FATAL) << "Bad condition code " << ccode;
264 res = static_cast<ArmConditionCode>(0); // Quiet gcc
265 }
266 return res;
267}
268
269static const char* core_reg_names[16] = {
270 "r0",
271 "r1",
272 "r2",
273 "r3",
274 "r4",
275 "r5",
276 "r6",
277 "r7",
278 "r8",
279 "rSELF",
280 "r10",
281 "r11",
282 "r12",
283 "sp",
284 "lr",
285 "pc",
286};
287
288
289static const char* shift_names[4] = {
290 "lsl",
291 "lsr",
292 "asr",
293 "ror"};
294
295/* Decode and print a ARM register name */
Ian Rogers988e6ea2014-01-08 11:30:50 -0800296static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 int i;
298 bool printed = false;
299 buf[0] = 0;
300 for (i = 0; i < 16; i++, vector >>= 1) {
301 if (vector & 0x1) {
302 int reg_id = i;
303 if (opcode == kThumbPush && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700304 reg_id = rs_rARM_LR.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 } else if (opcode == kThumbPop && i == 8) {
buzbee091cc402014-03-31 10:14:40 -0700306 reg_id = rs_rARM_PC.GetRegNum();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 }
308 if (printed) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800309 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 } else {
311 printed = true;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800312 snprintf(buf, buf_size, "r%d", reg_id);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 }
314 }
315 }
316 return buf;
317}
318
Ian Rogers988e6ea2014-01-08 11:30:50 -0800319static char* DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
320 snprintf(buf, buf_size, "s%d", base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321 for (int i = 1; i < count; i++) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800322 snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700323 }
324 return buf;
325}
326
buzbee0d829482013-10-11 15:24:55 -0700327static int32_t ExpandImmediate(int value) {
328 int32_t mode = (value & 0xf00) >> 8;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 uint32_t bits = value & 0xff;
330 switch (mode) {
331 case 0:
332 return bits;
333 case 1:
334 return (bits << 16) | bits;
335 case 2:
336 return (bits << 24) | (bits << 8);
337 case 3:
338 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
339 default:
340 break;
341 }
342 bits = (bits | 0x80) << 24;
343 return bits >> (((value & 0xf80) >> 7) - 8);
344}
345
Brian Carlstromb1eba212013-07-17 18:07:19 -0700346const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
347 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348/*
349 * Interpret a format string and build a string no longer than size
350 * See format key in Assemble.c.
351 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700352std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 std::string buf;
354 int i;
355 const char* fmt_end = &fmt[strlen(fmt)];
356 char tbuf[256];
357 const char* name;
358 char nc;
359 while (fmt < fmt_end) {
360 int operand;
361 if (*fmt == '!') {
362 fmt++;
363 DCHECK_LT(fmt, fmt_end);
364 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700365 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 strcpy(tbuf, "!");
367 } else {
368 DCHECK_LT(fmt, fmt_end);
369 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
370 operand = lir->operands[nc-'0'];
371 switch (*fmt++) {
372 case 'H':
373 if (operand != 0) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800374 snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700375 } else {
Brian Carlstromb1eba212013-07-17 18:07:19 -0700376 strcpy(tbuf, "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 }
378 break;
379 case 'B':
380 switch (operand) {
381 case kSY:
382 name = "sy";
383 break;
384 case kST:
385 name = "st";
386 break;
387 case kISH:
388 name = "ish";
389 break;
390 case kISHST:
391 name = "ishst";
392 break;
393 case kNSH:
394 name = "nsh";
395 break;
396 case kNSHST:
397 name = "shst";
398 break;
399 default:
400 name = "DecodeError2";
401 break;
402 }
403 strcpy(tbuf, name);
404 break;
405 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700406 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700407 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700408 tbuf[i] += operand & 1;
409 operand >>= 1;
410 }
411 break;
412 case 'n':
413 operand = ~ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800414 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 break;
416 case 'm':
417 operand = ExpandImmediate(operand);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800418 snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700419 break;
420 case 's':
buzbee091cc402014-03-31 10:14:40 -0700421 snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 break;
423 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700424 snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700425 break;
426 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800427 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 break;
429 case 'M':
430 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800431 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 break;
433 case 'C':
buzbee091cc402014-03-31 10:14:40 -0700434 operand = RegStorage::RegNum(operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 DCHECK_LT(operand, static_cast<int>(
436 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
Ian Rogers988e6ea2014-01-08 11:30:50 -0800437 snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 break;
439 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800440 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700441 break;
442 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800443 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 break;
445 case 'c':
446 strcpy(tbuf, cc_names[operand]);
447 break;
448 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800449 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
450 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 lir->target);
452 break;
Vladimir Markof4da6752014-08-01 19:04:18 +0100453 case 'T':
454 snprintf(tbuf, arraysize(tbuf), "%s", PrettyMethod(
455 static_cast<uint32_t>(lir->operands[1]),
456 *reinterpret_cast<const DexFile*>(UnwrapPointer(lir->operands[2]))).c_str());
457 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 case 'u': {
459 int offset_1 = lir->operands[0];
460 int offset_2 = NEXT_LIR(lir)->operands[0];
461 uintptr_t target =
462 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
463 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
464 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800465 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 break;
467 }
468
469 /* Nothing to print for BLX_2 */
470 case 'v':
471 strcpy(tbuf, "see above");
472 break;
473 case 'R':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800474 DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 break;
476 case 'P':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800477 DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 break;
479 case 'Q':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800480 DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 break;
482 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700483 strcpy(tbuf, "DecodeError1");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 break;
485 }
486 buf += tbuf;
487 }
488 } else {
489 buf += *fmt++;
490 }
491 }
492 return buf;
493}
494
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100495void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 char buf[256];
497 buf[0] = 0;
498
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100499 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 strcpy(buf, "all");
501 } else {
502 char num[8];
503 int i;
504
505 for (i = 0; i < kArmRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100506 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800507 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700508 strcat(buf, num);
509 }
510 }
511
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100512 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 strcat(buf, "cc ");
514 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100515 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 strcat(buf, "fpcc ");
517 }
518
519 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100520 if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800521 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
522 DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
523 DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100525 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526 strcat(buf, "lit ");
527 }
528
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100529 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 strcat(buf, "heap ");
531 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100532 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700533 strcat(buf, "noalias ");
534 }
535 }
536 if (buf[0]) {
537 LOG(INFO) << prefix << ": " << buf;
538 }
539}
540
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700541bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700542 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
543}
544
Vladimir Marko674744e2014-04-24 15:18:26 +0100545RegisterClass 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)
Vladimir Markof4da6752014-08-01 19:04:18 +0100557 : Mir2Lir(cu, mir_graph, arena),
558 call_method_insns_(arena->Adapter()) {
559 call_method_insns_.reserve(100);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 // Sanity check - make sure encoding map lines up.
561 for (int i = 0; i < kArmLast; i++) {
562 if (ArmMir2Lir::EncodingMap[i].opcode != i) {
563 LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
564 << " is wrong: expecting " << i << ", seeing "
565 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
566 }
567 }
568}
569
570Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
571 ArenaAllocator* const arena) {
572 return new ArmMir2Lir(cu, mir_graph, arena);
573}
574
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700575void ArmMir2Lir::CompilerInitializeRegAlloc() {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100576 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
577 sp_regs, dp_regs,
578 reserved_regs, empty_pool /* reserved64 */,
579 core_temps, empty_pool /* core64_temps */,
580 sp_temps, dp_temps));
Dave Allisonf6b65c12014-04-01 17:45:18 -0700581
buzbee091cc402014-03-31 10:14:40 -0700582 // Target-specific adjustments.
583
584 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100585 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700586 int sp_reg_num = info->GetReg().GetRegNum();
587 int dp_reg_num = sp_reg_num >> 1;
588 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
589 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
590 // Double precision register's master storage should refer to itself.
591 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
592 // Redirect single precision's master storage to master.
593 info->SetMaster(dp_reg_info);
594 // Singles should show a single 32-bit mask bit, at first referring to the low half.
buzbee85089dd2014-05-25 15:10:52 -0700595 DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700596 if (sp_reg_num & 1) {
buzbee85089dd2014-05-25 15:10:52 -0700597 // For odd singles, change to use the high word of the backing double.
598 info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
buzbee091cc402014-03-31 10:14:40 -0700599 }
600 }
601
Wei Jin04f4d8a2014-05-29 18:04:29 -0700602#ifdef ARM_R4_SUSPEND_FLAG
Dave Allison83252962014-04-03 16:33:48 -0700603 // TODO: re-enable this when we can safely save r4 over the suspension code path.
604 bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
buzbee091cc402014-03-31 10:14:40 -0700605 if (no_suspend) {
606 GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607 }
Wei Jin04f4d8a2014-05-29 18:04:29 -0700608#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609
buzbee091cc402014-03-31 10:14:40 -0700610 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
611 // TODO: adjust when we roll to hard float calling convention.
612 reg_pool_->next_core_reg_ = 2;
613 reg_pool_->next_sp_reg_ = 0;
614 reg_pool_->next_dp_reg_ = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615}
616
Brian Carlstrom7940e442013-07-12 13:46:57 -0700617/*
618 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
619 * instructions might call out to C/assembly helper functions. Until
620 * machinery is in place, always spill lr.
621 */
622
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700623void ArmMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700624 core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700625 num_core_spills_++;
626}
627
628/*
629 * Mark a callee-save fp register as promoted. Note that
630 * vpush/vpop uses contiguous register lists so we must
631 * include any holes in the mask. Associate holes with
632 * Dalvik register INVALID_VREG (0xFFFFU).
633 */
buzbee091cc402014-03-31 10:14:40 -0700634void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
635 DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
636 int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 // Ensure fp_vmap_table is large enough
638 int table_size = fp_vmap_table_.size();
buzbee091cc402014-03-31 10:14:40 -0700639 for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 fp_vmap_table_.push_back(INVALID_VREG);
641 }
642 // Add the current mapping
buzbee091cc402014-03-31 10:14:40 -0700643 fp_vmap_table_[adjusted_reg_num] = v_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644 // Size of fp_vmap_table is high-water mark, use to set mask
645 num_fp_spills_ = fp_vmap_table_.size();
646 fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
647}
648
buzbee091cc402014-03-31 10:14:40 -0700649void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
650 // TEMP: perform as 2 singles.
651 int reg_num = reg.GetRegNum() << 1;
652 RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
653 RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
654 MarkPreservedSingle(v_reg, lo);
655 MarkPreservedSingle(v_reg + 1, hi);
buzbee2700f7e2014-03-07 09:46:20 -0800656}
657
Brian Carlstrom7940e442013-07-12 13:46:57 -0700658/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000659void ArmMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700660 // TODO: rework this - it's gotten even more ugly.
661 Clobber(rs_r0);
662 Clobber(rs_r1);
663 Clobber(rs_r2);
664 Clobber(rs_r3);
665 Clobber(rs_r12);
666 Clobber(rs_r14lr);
667 Clobber(rs_fr0);
668 Clobber(rs_fr1);
669 Clobber(rs_fr2);
670 Clobber(rs_fr3);
671 Clobber(rs_fr4);
672 Clobber(rs_fr5);
673 Clobber(rs_fr6);
674 Clobber(rs_fr7);
675 Clobber(rs_fr8);
676 Clobber(rs_fr9);
677 Clobber(rs_fr10);
678 Clobber(rs_fr11);
679 Clobber(rs_fr12);
680 Clobber(rs_fr13);
681 Clobber(rs_fr14);
682 Clobber(rs_fr15);
683 Clobber(rs_dr0);
684 Clobber(rs_dr1);
685 Clobber(rs_dr2);
686 Clobber(rs_dr3);
687 Clobber(rs_dr4);
688 Clobber(rs_dr5);
689 Clobber(rs_dr6);
690 Clobber(rs_dr7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700691}
692
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700693RegLocation ArmMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700694 RegLocation res = LocCReturnWide();
buzbee091cc402014-03-31 10:14:40 -0700695 res.reg.SetLowReg(rs_r2.GetReg());
696 res.reg.SetHighReg(rs_r3.GetReg());
697 Clobber(rs_r2);
698 Clobber(rs_r3);
699 MarkInUse(rs_r2);
700 MarkInUse(rs_r3);
701 MarkWide(res.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700702 return res;
703}
704
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700705RegLocation ArmMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706 RegLocation res = LocCReturn();
buzbee091cc402014-03-31 10:14:40 -0700707 res.reg.SetReg(rs_r1.GetReg());
708 Clobber(rs_r1);
709 MarkInUse(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700710 return res;
711}
712
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700714void ArmMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700715 LockTemp(rs_r0);
716 LockTemp(rs_r1);
717 LockTemp(rs_r2);
718 LockTemp(rs_r3);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800719 if (!kArm32QuickCodeUseSoftFloat) {
720 LockTemp(rs_fr0);
721 LockTemp(rs_fr1);
722 LockTemp(rs_fr2);
723 LockTemp(rs_fr3);
724 LockTemp(rs_fr4);
725 LockTemp(rs_fr5);
726 LockTemp(rs_fr6);
727 LockTemp(rs_fr7);
728 LockTemp(rs_fr8);
729 LockTemp(rs_fr9);
730 LockTemp(rs_fr10);
731 LockTemp(rs_fr11);
732 LockTemp(rs_fr12);
733 LockTemp(rs_fr13);
734 LockTemp(rs_fr14);
735 LockTemp(rs_fr15);
736 LockTemp(rs_dr0);
737 LockTemp(rs_dr1);
738 LockTemp(rs_dr2);
739 LockTemp(rs_dr3);
740 LockTemp(rs_dr4);
741 LockTemp(rs_dr5);
742 LockTemp(rs_dr6);
743 LockTemp(rs_dr7);
744 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700745}
746
747/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700748void ArmMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700749 FreeTemp(rs_r0);
750 FreeTemp(rs_r1);
751 FreeTemp(rs_r2);
752 FreeTemp(rs_r3);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800753 if (!kArm32QuickCodeUseSoftFloat) {
754 FreeTemp(rs_fr0);
755 FreeTemp(rs_fr1);
756 FreeTemp(rs_fr2);
757 FreeTemp(rs_fr3);
758 FreeTemp(rs_fr4);
759 FreeTemp(rs_fr5);
760 FreeTemp(rs_fr6);
761 FreeTemp(rs_fr7);
762 FreeTemp(rs_fr8);
763 FreeTemp(rs_fr9);
764 FreeTemp(rs_fr10);
765 FreeTemp(rs_fr11);
766 FreeTemp(rs_fr12);
767 FreeTemp(rs_fr13);
768 FreeTemp(rs_fr14);
769 FreeTemp(rs_fr15);
770 FreeTemp(rs_dr0);
771 FreeTemp(rs_dr1);
772 FreeTemp(rs_dr2);
773 FreeTemp(rs_dr3);
774 FreeTemp(rs_dr4);
775 FreeTemp(rs_dr5);
776 FreeTemp(rs_dr6);
777 FreeTemp(rs_dr7);
778 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700779}
780
Andreas Gampe98430592014-07-27 19:44:50 -0700781RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
782 LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR);
buzbee2700f7e2014-03-07 09:46:20 -0800783 return rs_rARM_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700784}
785
Dave Allisonb373e092014-02-20 16:06:36 -0800786LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800787 RegStorage tmp = rs_r0;
buzbee695d13a2014-04-19 13:32:20 -0700788 Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
789 LIR* load2 = Load32Disp(tmp, 0, tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800790 return load2;
791}
792
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700793uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700794 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700795 return ArmMir2Lir::EncodingMap[opcode].flags;
796}
797
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700798const char* ArmMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700799 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700800 return ArmMir2Lir::EncodingMap[opcode].name;
801}
802
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700803const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700804 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700805 return ArmMir2Lir::EncodingMap[opcode].fmt;
806}
807
buzbee091cc402014-03-31 10:14:40 -0700808/*
809 * Somewhat messy code here. We want to allocate a pair of contiguous
810 * physical single-precision floating point registers starting with
811 * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
812 * has already been allocated - try to fit if possible. Fail to
813 * allocate if we can't meet the requirements for the pair of
814 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
815 */
816// TODO: needs rewrite to support non-backed 64-bit float regs.
817RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
818 RegStorage res;
819 int v_reg = mir_graph_->SRegToVReg(s_reg);
820 int p_map_idx = SRegToPMap(s_reg);
821 if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
822 // Upper reg is already allocated. Can we fit?
buzbeeb5860fb2014-06-21 15:31:01 -0700823 int high_reg = promotion_map_[p_map_idx+1].fp_reg;
buzbee091cc402014-03-31 10:14:40 -0700824 if ((high_reg & 1) == 0) {
825 // High reg is even - fail.
826 return res; // Invalid.
827 }
828 // Is the low reg of the pair free?
829 // FIXME: rework.
830 RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
831 if (p->InUse() || p->IsTemp()) {
832 // Already allocated or not preserved - fail.
833 return res; // Invalid.
834 }
835 // OK - good to go.
836 res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
837 p->MarkInUse();
838 MarkPreservedSingle(v_reg, p->GetReg());
839 } else {
840 /*
841 * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
842 * different underlying physical registers.
843 */
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100844 for (RegisterInfo* info : reg_pool_->dp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700845 if (!info->IsTemp() && !info->InUse()) {
846 res = info->GetReg();
847 info->MarkInUse();
848 MarkPreservedDouble(v_reg, info->GetReg());
849 break;
850 }
851 }
852 }
853 if (res.Valid()) {
buzbee85089dd2014-05-25 15:10:52 -0700854 RegisterInfo* info = GetRegInfo(res);
buzbee091cc402014-03-31 10:14:40 -0700855 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700856 promotion_map_[p_map_idx].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700857 info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700858 promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
buzbeeb5860fb2014-06-21 15:31:01 -0700859 promotion_map_[p_map_idx+1].fp_reg =
buzbee85089dd2014-05-25 15:10:52 -0700860 info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
buzbee091cc402014-03-31 10:14:40 -0700861 }
862 return res;
863}
864
buzbeeb5860fb2014-06-21 15:31:01 -0700865// Reserve a callee-save sp single register.
866RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
867 RegStorage res;
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100868 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbeeb5860fb2014-06-21 15:31:01 -0700869 if (!info->IsTemp() && !info->InUse()) {
870 res = info->GetReg();
871 int p_map_idx = SRegToPMap(s_reg);
872 int v_reg = mir_graph_->SRegToVReg(s_reg);
873 GetRegInfo(res)->MarkInUse();
874 MarkPreservedSingle(v_reg, res);
875 promotion_map_[p_map_idx].fp_location = kLocPhysReg;
876 promotion_map_[p_map_idx].fp_reg = res.GetReg();
877 break;
878 }
879 }
880 return res;
881}
882
Vladimir Markof4da6752014-08-01 19:04:18 +0100883void ArmMir2Lir::InstallLiteralPools() {
884 // PC-relative calls to methods.
885 patches_.reserve(call_method_insns_.size());
886 for (LIR* p : call_method_insns_) {
887 DCHECK_EQ(p->opcode, kThumb2Bl);
888 uint32_t target_method_idx = p->operands[1];
889 const DexFile* target_dex_file =
890 reinterpret_cast<const DexFile*>(UnwrapPointer(p->operands[2]));
891
892 patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
893 target_dex_file, target_method_idx));
894 }
895
896 // And do the normal processing.
897 Mir2Lir::InstallLiteralPools();
898}
899
Zheng Xu5667fdb2014-10-23 18:29:55 +0800900RegStorage ArmMir2Lir::InToRegStorageArmMapper::GetNextReg(bool is_double_or_float, bool is_wide) {
901 const RegStorage coreArgMappingToPhysicalReg[] =
902 {rs_r1, rs_r2, rs_r3};
903 const int coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
904 const RegStorage fpArgMappingToPhysicalReg[] =
905 {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
906 rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
907 const uint32_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
908 COMPILE_ASSERT(fpArgMappingToPhysicalRegSize % 2 == 0, knum_of_fp_arg_regs_not_even);
909
910 if (kArm32QuickCodeUseSoftFloat) {
911 is_double_or_float = false; // Regard double as long, float as int.
912 is_wide = false; // Map long separately.
913 }
914
915 RegStorage result = RegStorage::InvalidReg();
916 if (is_double_or_float) {
917 // TODO: Remove "cur_fp_double_reg_ % 2 != 0" when we return double as double.
918 if (is_wide || cur_fp_double_reg_ % 2 != 0) {
919 cur_fp_double_reg_ = std::max(cur_fp_double_reg_, RoundUp(cur_fp_reg_, 2));
920 if (cur_fp_double_reg_ < fpArgMappingToPhysicalRegSize) {
921 // TODO: Replace by following code in the branch when FlushIns() support 64-bit registers.
922 // result = RegStorage::MakeRegPair(fpArgMappingToPhysicalReg[cur_fp_double_reg_],
923 // fpArgMappingToPhysicalReg[cur_fp_double_reg_ + 1]);
924 // result = As64BitFloatReg(result);
925 // cur_fp_double_reg_ += 2;
926 result = fpArgMappingToPhysicalReg[cur_fp_double_reg_];
927 cur_fp_double_reg_++;
928 }
929 } else {
930 // TODO: Remove the check when we return double as double.
931 DCHECK_EQ(cur_fp_double_reg_ % 2, 0U);
932 if (cur_fp_reg_ % 2 == 0) {
933 cur_fp_reg_ = std::max(cur_fp_double_reg_, cur_fp_reg_);
934 }
935 if (cur_fp_reg_ < fpArgMappingToPhysicalRegSize) {
936 result = fpArgMappingToPhysicalReg[cur_fp_reg_];
937 cur_fp_reg_++;
938 }
939 }
940 } else {
941 if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
942 result = coreArgMappingToPhysicalReg[cur_core_reg_++];
943 // TODO: Enable following code when FlushIns() support 64-bit registers.
944 // if (is_wide && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
945 // result = RegStorage::MakeRegPair(result, coreArgMappingToPhysicalReg[cur_core_reg_++]);
946 // }
947 }
948 }
949 return result;
950}
951
952RegStorage ArmMir2Lir::InToRegStorageMapping::Get(int in_position) const {
953 DCHECK(IsInitialized());
954 auto res = mapping_.find(in_position);
955 return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
956}
957
958void ArmMir2Lir::InToRegStorageMapping::Initialize(RegLocation* arg_locs, int count,
959 InToRegStorageMapper* mapper) {
960 DCHECK(mapper != nullptr);
961 max_mapped_in_ = -1;
962 is_there_stack_mapped_ = false;
963 for (int in_position = 0; in_position < count; in_position++) {
964 RegStorage reg = mapper->GetNextReg(arg_locs[in_position].fp,
965 arg_locs[in_position].wide);
966 if (reg.Valid()) {
967 mapping_[in_position] = reg;
968 // TODO: Enable the following code when FlushIns() support 64-bit argument registers.
969 // if (arg_locs[in_position].wide) {
970 // if (reg.Is32Bit()) {
971 // // As it is a split long, the hi-part is on stack.
972 // is_there_stack_mapped_ = true;
973 // }
974 // // We covered 2 v-registers, so skip the next one
975 // in_position++;
976 // }
977 max_mapped_in_ = std::max(max_mapped_in_, in_position);
978 } else {
979 is_there_stack_mapped_ = true;
980 }
981 }
982 initialized_ = true;
983}
984
985// TODO: Should be able to return long, double registers.
986// Need check some common code as it will break some assumption.
987RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
988 if (!in_to_reg_storage_mapping_.IsInitialized()) {
989 int start_vreg = mir_graph_->GetFirstInVR();
990 RegLocation* arg_locs = &mir_graph_->reg_location_[start_vreg];
991
992 InToRegStorageArmMapper mapper;
993 in_to_reg_storage_mapping_.Initialize(arg_locs, mir_graph_->GetNumOfInVRs(), &mapper);
994 }
995 return in_to_reg_storage_mapping_.Get(arg_num);
996}
997
998int ArmMir2Lir::GenDalvikArgsNoRange(CallInfo* info,
999 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
1000 const MethodReference& target_method,
1001 uint32_t vtable_idx, uintptr_t direct_code,
1002 uintptr_t direct_method, InvokeType type, bool skip_this) {
1003 if (kArm32QuickCodeUseSoftFloat) {
1004 return Mir2Lir::GenDalvikArgsNoRange(info, call_state, pcrLabel, next_call_insn, target_method,
1005 vtable_idx, direct_code, direct_method, type, skip_this);
1006 } else {
1007 return GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method, vtable_idx,
1008 direct_code, direct_method, type, skip_this);
1009 }
1010}
1011
1012int ArmMir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
1013 LIR** pcrLabel, NextCallInsn next_call_insn,
1014 const MethodReference& target_method,
1015 uint32_t vtable_idx, uintptr_t direct_code,
1016 uintptr_t direct_method, InvokeType type, bool skip_this) {
1017 if (kArm32QuickCodeUseSoftFloat) {
1018 return Mir2Lir::GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method,
1019 vtable_idx, direct_code, direct_method, type, skip_this);
1020 }
1021
1022 // TODO: Rework the implementation when argument register can be long or double.
1023
1024 /* If no arguments, just return */
1025 if (info->num_arg_words == 0) {
1026 return call_state;
1027 }
1028
1029 const int start_index = skip_this ? 1 : 0;
1030
1031 InToRegStorageArmMapper mapper;
1032 InToRegStorageMapping in_to_reg_storage_mapping;
1033 in_to_reg_storage_mapping.Initialize(info->args, info->num_arg_words, &mapper);
1034 const int last_mapped_in = in_to_reg_storage_mapping.GetMaxMappedIn();
1035 int regs_left_to_pass_via_stack = info->num_arg_words - (last_mapped_in + 1);
1036
1037 // First of all, check whether it makes sense to use bulk copying.
1038 // Bulk copying is done only for the range case.
1039 // TODO: make a constant instead of 2
1040 if (info->is_range && regs_left_to_pass_via_stack >= 2) {
1041 // Scan the rest of the args - if in phys_reg flush to memory
1042 for (int next_arg = last_mapped_in + 1; next_arg < info->num_arg_words;) {
1043 RegLocation loc = info->args[next_arg];
1044 if (loc.wide) {
1045 // TODO: Only flush hi-part.
1046 if (loc.high_word) {
1047 loc = info->args[--next_arg];
1048 }
1049 loc = UpdateLocWide(loc);
1050 if (loc.location == kLocPhysReg) {
1051 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1052 StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
1053 }
1054 next_arg += 2;
1055 } else {
1056 loc = UpdateLoc(loc);
1057 if (loc.location == kLocPhysReg) {
1058 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1059 if (loc.ref) {
1060 StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
1061 } else {
1062 StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32,
1063 kNotVolatile);
1064 }
1065 }
1066 next_arg++;
1067 }
1068 }
1069
1070 // The rest can be copied together
1071 int start_offset = SRegOffset(info->args[last_mapped_in + 1].s_reg_low);
1072 int outs_offset = StackVisitor::GetOutVROffset(last_mapped_in + 1,
1073 cu_->instruction_set);
1074
1075 int current_src_offset = start_offset;
1076 int current_dest_offset = outs_offset;
1077
1078 // Only davik regs are accessed in this loop; no next_call_insn() calls.
1079 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1080 while (regs_left_to_pass_via_stack > 0) {
1081 /*
1082 * TODO: Improve by adding block copy for large number of arguments. This
1083 * should be done, if possible, as a target-depending helper. For now, just
1084 * copy a Dalvik vreg at a time.
1085 */
1086 // Moving 32-bits via general purpose register.
1087 size_t bytes_to_move = sizeof(uint32_t);
1088
1089 // Instead of allocating a new temp, simply reuse one of the registers being used
1090 // for argument passing.
1091 RegStorage temp = TargetReg(kArg3, kNotWide);
1092
1093 // Now load the argument VR and store to the outs.
1094 Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
1095 Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
1096
1097 current_src_offset += bytes_to_move;
1098 current_dest_offset += bytes_to_move;
1099 regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
1100 }
1101 DCHECK_EQ(regs_left_to_pass_via_stack, 0);
1102 }
1103
1104 // Now handle rest not registers if they are
1105 if (in_to_reg_storage_mapping.IsThereStackMapped()) {
1106 RegStorage regWide = TargetReg(kArg2, kWide);
1107 for (int i = start_index; i <= last_mapped_in + regs_left_to_pass_via_stack; i++) {
1108 RegLocation rl_arg = info->args[i];
1109 rl_arg = UpdateRawLoc(rl_arg);
1110 RegStorage reg = in_to_reg_storage_mapping.Get(i);
1111 // TODO: Only pass split wide hi-part via stack.
1112 if (!reg.Valid() || rl_arg.wide) {
1113 int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
1114
1115 {
1116 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1117 if (rl_arg.wide) {
1118 if (rl_arg.location == kLocPhysReg) {
1119 StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
1120 } else {
1121 LoadValueDirectWideFixed(rl_arg, regWide);
1122 StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile);
1123 }
1124 } else {
1125 if (rl_arg.location == kLocPhysReg) {
1126 if (rl_arg.ref) {
1127 StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
1128 } else {
1129 StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
1130 }
1131 } else {
1132 if (rl_arg.ref) {
1133 RegStorage regSingle = TargetReg(kArg2, kRef);
1134 LoadValueDirectFixed(rl_arg, regSingle);
1135 StoreRefDisp(TargetPtrReg(kSp), out_offset, regSingle, kNotVolatile);
1136 } else {
1137 RegStorage regSingle = TargetReg(kArg2, kNotWide);
1138 LoadValueDirectFixed(rl_arg, regSingle);
1139 StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile);
1140 }
1141 }
1142 }
1143 }
1144
1145 call_state = next_call_insn(cu_, info, call_state, target_method,
1146 vtable_idx, direct_code, direct_method, type);
1147 }
1148 if (rl_arg.wide) {
1149 i++;
1150 }
1151 }
1152 }
1153
1154 // Finish with mapped registers
1155 for (int i = start_index; i <= last_mapped_in; i++) {
1156 RegLocation rl_arg = info->args[i];
1157 rl_arg = UpdateRawLoc(rl_arg);
1158 RegStorage reg = in_to_reg_storage_mapping.Get(i);
1159 if (reg.Valid()) {
1160 if (reg.Is64Bit()) {
1161 LoadValueDirectWideFixed(rl_arg, reg);
1162 } else {
1163 // TODO: Only split long should be the case we need to care about.
1164 if (rl_arg.wide) {
1165 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1166 int high_word = rl_arg.high_word ? 1 : 0;
1167 rl_arg = high_word ? info->args[i - 1] : rl_arg;
1168 if (rl_arg.location == kLocPhysReg) {
1169 RegStorage rs_arg = rl_arg.reg;
1170 if (rs_arg.IsDouble() && rs_arg.Is64BitSolo()) {
1171 rs_arg = As64BitFloatRegPair(rs_arg);
1172 }
1173 RegStorage rs_arg_low = rs_arg.GetLow();
1174 RegStorage rs_arg_high = rs_arg.GetHigh();
1175 OpRegCopy(reg, high_word ? rs_arg_high : rs_arg_low);
1176 } else {
1177 Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low + high_word), reg);
1178 }
1179 } else {
1180 LoadValueDirectFixed(rl_arg, reg);
1181 }
1182 }
1183 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
1184 direct_code, direct_method, type);
1185 }
1186 if (reg.Is64Bit()) {
1187 i++;
1188 }
1189 }
1190
1191 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
1192 direct_code, direct_method, type);
1193 if (pcrLabel) {
1194 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
1195 *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
1196 } else {
1197 *pcrLabel = nullptr;
1198 // In lieu of generating a check for kArg1 being null, we need to
1199 // perform a load when doing implicit checks.
1200 RegStorage tmp = AllocTemp();
1201 Load32Disp(TargetReg(kArg1, kRef), 0, tmp);
1202 MarkPossibleNullPointerException(info->opt_flags);
1203 FreeTemp(tmp);
1204 }
1205 }
1206 return call_state;
1207}
1208
Brian Carlstrom7940e442013-07-12 13:46:57 -07001209} // namespace art