blob: 9c4426f74689a7bb05c0a6acce9ff578d14a051f [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "codegen_mips.h"
Ian Rogers107c31e2014-01-23 20:55:29 -080018
19#include <inttypes.h>
20
21#include <string>
22
Andreas Gampe53c913b2014-08-12 23:19:23 -070023#include "backend_mips.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024#include "dex/compiler_internals.h"
25#include "dex/quick/mir_to_lir-inl.h"
26#include "mips_lir.h"
27
Brian Carlstrom7940e442013-07-12 13:46:57 -070028namespace art {
29
Vladimir Marko089142c2014-06-05 10:57:05 +010030static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070031 {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
32 rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
33 rs_rS6, rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP, rs_rRA};
Vladimir Marko089142c2014-06-05 10:57:05 +010034static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070035 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
36 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Vladimir Marko089142c2014-06-05 10:57:05 +010037static constexpr RegStorage dp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070038 {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
Vladimir Marko089142c2014-06-05 10:57:05 +010039static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070040 {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
Vladimir Marko089142c2014-06-05 10:57:05 +010041static constexpr RegStorage core_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070042 {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
43 rs_rT5, rs_rT6, rs_rT7, rs_rT8};
Vladimir Marko089142c2014-06-05 10:57:05 +010044static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070045 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
46 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Vladimir Marko089142c2014-06-05 10:57:05 +010047static constexpr RegStorage dp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070048 {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
49
Vladimir Marko089142c2014-06-05 10:57:05 +010050static constexpr ArrayRef<const RegStorage> empty_pool;
51static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
52static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
53static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
54static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
55static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
56static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
57static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070058
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070059RegLocation MipsMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000060 return mips_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070061}
62
buzbeea0cd2d72014-06-01 09:33:49 -070063RegLocation MipsMir2Lir::LocCReturnRef() {
64 return mips_loc_c_return;
65}
66
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070067RegLocation MipsMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000068 return mips_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070069}
70
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070071RegLocation MipsMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000072 return mips_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070073}
74
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070075RegLocation MipsMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000076 return mips_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070077}
78
Douglas Leung2db3e262014-06-25 16:02:55 -070079// Convert k64BitSolo into k64BitPair
80RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
81 DCHECK(reg.IsDouble());
82 int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
83 return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
84}
85
Brian Carlstrom7940e442013-07-12 13:46:57 -070086// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080087RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070088 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -070090 case kSelf: res_reg = rs_rMIPS_SELF; break;
91 case kSuspend: res_reg = rs_rMIPS_SUSPEND; break;
92 case kLr: res_reg = rs_rMIPS_LR; break;
93 case kPc: res_reg = rs_rMIPS_PC; break;
94 case kSp: res_reg = rs_rMIPS_SP; break;
95 case kArg0: res_reg = rs_rMIPS_ARG0; break;
96 case kArg1: res_reg = rs_rMIPS_ARG1; break;
97 case kArg2: res_reg = rs_rMIPS_ARG2; break;
98 case kArg3: res_reg = rs_rMIPS_ARG3; break;
99 case kFArg0: res_reg = rs_rMIPS_FARG0; break;
100 case kFArg1: res_reg = rs_rMIPS_FARG1; break;
101 case kFArg2: res_reg = rs_rMIPS_FARG2; break;
102 case kFArg3: res_reg = rs_rMIPS_FARG3; break;
103 case kRet0: res_reg = rs_rMIPS_RET0; break;
104 case kRet1: res_reg = rs_rMIPS_RET1; break;
105 case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
106 case kHiddenArg: res_reg = rs_rT0; break;
107 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
108 case kCount: res_reg = rs_rMIPS_COUNT; break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700109 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110 }
buzbee091cc402014-03-31 10:14:40 -0700111 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700112}
113
buzbee2700f7e2014-03-07 09:46:20 -0800114RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800115 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
116 switch (arg_num) {
117 case 0:
buzbee2700f7e2014-03-07 09:46:20 -0800118 return rs_rMIPS_ARG1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800119 case 1:
buzbee2700f7e2014-03-07 09:46:20 -0800120 return rs_rMIPS_ARG2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800121 case 2:
buzbee2700f7e2014-03-07 09:46:20 -0800122 return rs_rMIPS_ARG3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800123 default:
buzbee2700f7e2014-03-07 09:46:20 -0800124 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800125 }
126}
127
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128/*
129 * Decode the register id.
130 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100131ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
132 return reg.IsDouble()
133 /* Each double register is equal to a pair of single-precision FP registers */
Douglas Leung2db3e262014-06-25 16:02:55 -0700134#if (FR_BIT == 0)
135 ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
136#else
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100137 ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
Douglas Leung2db3e262014-06-25 16:02:55 -0700138#endif
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100139 : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140}
141
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100142ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
143 return ResourceMask::Bit(kMipsRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700144}
145
146
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100147void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
148 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700150 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151
152 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100154 def_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 }
156
157 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100158 use_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159 }
160
161 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100162 def_mask->SetBit(kMipsRegLR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 }
buzbee9da5c102014-03-28 12:59:18 -0700164
165 if (flags & REG_DEF_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100166 def_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700167 }
168
169 if (flags & REG_DEF_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100170 def_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700171 }
172
173 if (flags & REG_USE_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100174 use_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700175 }
176
177 if (flags & REG_USE_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100178 use_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700179 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700180}
181
182/* For dumping instructions */
183#define MIPS_REG_COUNT 32
184static const char *mips_reg_name[MIPS_REG_COUNT] = {
185 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
186 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
187 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
188 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
189};
190
191/*
192 * Interpret a format string and build a string no longer than size
193 * See format key in Assemble.c.
194 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700195std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700196 std::string buf;
197 int i;
198 const char *fmt_end = &fmt[strlen(fmt)];
199 char tbuf[256];
200 char nc;
201 while (fmt < fmt_end) {
202 int operand;
203 if (*fmt == '!') {
204 fmt++;
205 DCHECK_LT(fmt, fmt_end);
206 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700207 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 strcpy(tbuf, "!");
209 } else {
210 DCHECK_LT(fmt, fmt_end);
211 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
212 operand = lir->operands[nc-'0'];
213 switch (*fmt++) {
214 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700215 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700216 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 tbuf[i] += operand & 1;
218 operand >>= 1;
219 }
220 break;
221 case 's':
buzbee091cc402014-03-31 10:14:40 -0700222 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700223 break;
224 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700225 DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
226 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 break;
228 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800229 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 break;
231 case 'M':
232 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800233 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 break;
235 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800236 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 break;
238 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800239 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 break;
241 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800242 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 break;
244 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800245 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
246 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
247 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 break;
249 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800250 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 break;
252 case 'u': {
253 int offset_1 = lir->operands[0];
254 int offset_2 = NEXT_LIR(lir)->operands[0];
255 uintptr_t target =
256 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
257 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800258 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 break;
260 }
261
262 /* Nothing to print for BLX_2 */
263 case 'v':
264 strcpy(tbuf, "see above");
265 break;
266 case 'r':
267 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
268 strcpy(tbuf, mips_reg_name[operand]);
269 break;
270 case 'N':
271 // Placeholder for delay slot handling
272 strcpy(tbuf, "; nop");
273 break;
274 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700275 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700276 break;
277 }
278 buf += tbuf;
279 }
280 } else {
281 buf += *fmt++;
282 }
283 }
284 return buf;
285}
286
287// FIXME: need to redo resource maps for MIPS - fix this at that time
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100288void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 char buf[256];
290 buf[0] = 0;
291
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100292 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 strcpy(buf, "all");
294 } else {
295 char num[8];
296 int i;
297
298 for (i = 0; i < kMipsRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100299 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800300 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 strcat(buf, num);
302 }
303 }
304
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100305 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 strcat(buf, "cc ");
307 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100308 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 strcat(buf, "fpcc ");
310 }
311 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100312 if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800313 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
314 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
315 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700316 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100317 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700318 strcat(buf, "lit ");
319 }
320
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100321 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700322 strcat(buf, "heap ");
323 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100324 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 strcat(buf, "noalias ");
326 }
327 }
328 if (buf[0]) {
329 LOG(INFO) << prefix << ": " << buf;
330 }
331}
332
333/*
334 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
335 * instructions might call out to C/assembly helper functions. Until
336 * machinery is in place, always spill lr.
337 */
338
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700339void MipsMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700340 core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 num_core_spills_++;
342}
343
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000345void MipsMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700346 Clobber(rs_rZERO);
347 Clobber(rs_rAT);
348 Clobber(rs_rV0);
349 Clobber(rs_rV1);
350 Clobber(rs_rA0);
351 Clobber(rs_rA1);
352 Clobber(rs_rA2);
353 Clobber(rs_rA3);
354 Clobber(rs_rT0);
355 Clobber(rs_rT1);
356 Clobber(rs_rT2);
357 Clobber(rs_rT3);
358 Clobber(rs_rT4);
359 Clobber(rs_rT5);
360 Clobber(rs_rT6);
361 Clobber(rs_rT7);
362 Clobber(rs_rT8);
363 Clobber(rs_rT9);
364 Clobber(rs_rK0);
365 Clobber(rs_rK1);
366 Clobber(rs_rGP);
367 Clobber(rs_rFP);
368 Clobber(rs_rRA);
369 Clobber(rs_rF0);
370 Clobber(rs_rF1);
371 Clobber(rs_rF2);
372 Clobber(rs_rF3);
373 Clobber(rs_rF4);
374 Clobber(rs_rF5);
375 Clobber(rs_rF6);
376 Clobber(rs_rF7);
377 Clobber(rs_rF8);
378 Clobber(rs_rF9);
379 Clobber(rs_rF10);
380 Clobber(rs_rF11);
381 Clobber(rs_rF12);
382 Clobber(rs_rF13);
383 Clobber(rs_rF14);
384 Clobber(rs_rF15);
385 Clobber(rs_rD0);
386 Clobber(rs_rD1);
387 Clobber(rs_rD2);
388 Clobber(rs_rD3);
389 Clobber(rs_rD4);
390 Clobber(rs_rD5);
391 Clobber(rs_rD6);
392 Clobber(rs_rD7);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700393}
394
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700395RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
397 RegLocation res = LocCReturnWide();
398 return res;
399}
400
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700401RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
403 RegLocation res = LocCReturn();
404 return res;
405}
406
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700408void MipsMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700409 LockTemp(rs_rMIPS_ARG0);
410 LockTemp(rs_rMIPS_ARG1);
411 LockTemp(rs_rMIPS_ARG2);
412 LockTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413}
414
415/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700416void MipsMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700417 FreeTemp(rs_rMIPS_ARG0);
418 FreeTemp(rs_rMIPS_ARG1);
419 FreeTemp(rs_rMIPS_ARG2);
420 FreeTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421}
422
Andreas Gampeb14329f2014-05-15 11:16:06 -0700423bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424#if ANDROID_SMP != 0
425 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
Andreas Gampeb14329f2014-05-15 11:16:06 -0700426 return true;
427#else
428 return false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429#endif
430}
431
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700432void MipsMir2Lir::CompilerInitializeRegAlloc() {
buzbeeb01bf152014-05-13 15:59:07 -0700433 reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
434 dp_regs, reserved_regs, empty_pool /* reserved64 */,
435 core_temps, empty_pool /* core64_temps */, sp_temps,
436 dp_temps);
buzbee091cc402014-03-31 10:14:40 -0700437
438 // Target-specific adjustments.
439
440 // Alias single precision floats to appropriate half of overlapping double.
441 GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
442 for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
443 int sp_reg_num = info->GetReg().GetRegNum();
Douglas Leung2db3e262014-06-25 16:02:55 -0700444#if (FR_BIT == 0)
445 int dp_reg_num = sp_reg_num & ~1;
446#else
buzbee091cc402014-03-31 10:14:40 -0700447 int dp_reg_num = sp_reg_num >> 1;
Douglas Leung2db3e262014-06-25 16:02:55 -0700448#endif
buzbee091cc402014-03-31 10:14:40 -0700449 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
450 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
451 // Double precision register's master storage should refer to itself.
452 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
453 // Redirect single precision's master storage to master.
454 info->SetMaster(dp_reg_info);
455 // Singles should show a single 32-bit mask bit, at first referring to the low half.
456 DCHECK_EQ(info->StorageMask(), 0x1U);
457 if (sp_reg_num & 1) {
458 // For odd singles, change to user the high word of the backing double.
459 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 }
buzbee091cc402014-03-31 10:14:40 -0700462
463 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
464 // TODO: adjust when we roll to hard float calling convention.
465 reg_pool_->next_core_reg_ = 2;
466 reg_pool_->next_sp_reg_ = 2;
Douglas Leung2db3e262014-06-25 16:02:55 -0700467#if (FR_BIT == 0)
468 reg_pool_->next_dp_reg_ = 2;
469#else
buzbee091cc402014-03-31 10:14:40 -0700470 reg_pool_->next_dp_reg_ = 1;
Douglas Leung2db3e262014-06-25 16:02:55 -0700471#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472}
473
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474/*
475 * In the Arm code a it is typical to use the link register
476 * to hold the target address. However, for Mips we must
477 * ensure that all branch instructions can be restarted if
478 * there is a trap in the shadow. Allocate a temp register.
479 */
Andreas Gampe98430592014-07-27 19:44:50 -0700480RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700481 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700482 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800483 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484}
485
Dave Allisonb373e092014-02-20 16:06:36 -0800486LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800487 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700488 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700489 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800490 LIR *inst = LoadWordDisp(tmp, 0, tmp);
491 FreeTemp(tmp);
492 return inst;
493}
494
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700495LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
496 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
497 DCHECK(r_dest.IsPair());
498 ClobberCallerSave();
499 LockCallTemps(); // Using fixed registers
500 RegStorage reg_ptr = TargetReg(kArg0);
501 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700502 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700503 LIR *ret = OpReg(kOpBlx, r_tgt);
504 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
505 OpRegCopyWide(r_dest, reg_ret);
506 return ret;
507}
508
509LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
510 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
511 DCHECK(r_src.IsPair());
512 ClobberCallerSave();
513 LockCallTemps(); // Using fixed registers
514 RegStorage temp_ptr = AllocTemp();
515 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
516 RegStorage temp_value = AllocTempWide();
517 OpRegCopyWide(temp_value, r_src);
518 RegStorage reg_ptr = TargetReg(kArg0);
519 OpRegCopy(reg_ptr, temp_ptr);
520 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
521 OpRegCopyWide(reg_value, temp_value);
522 FreeTemp(temp_ptr);
523 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700524 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700525 return OpReg(kOpBlx, r_tgt);
526}
527
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700528void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700529 if (num_core_spills_ == 0) {
530 return;
531 }
532 uint32_t mask = core_spill_mask_;
533 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800534 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 for (int reg = 0; mask; mask >>= 1, reg++) {
536 if (mask & 0x1) {
537 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700538 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700539 }
540 }
541}
542
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700543void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700544 if (num_core_spills_ == 0) {
545 return;
546 }
547 uint32_t mask = core_spill_mask_;
548 int offset = frame_size_;
549 for (int reg = 0; mask; mask >>= 1, reg++) {
550 if (mask & 0x1) {
551 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700552 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 }
554 }
buzbee2700f7e2014-03-07 09:46:20 -0800555 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556}
557
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700558bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 return (lir->opcode == kMipsB);
560}
561
Vladimir Marko674744e2014-04-24 15:18:26 +0100562RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700563 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700564 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700565 // Smaller aligned load/store is atomic for both core and fp registers.
566 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700567 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700568 }
569 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100570 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
571 return RegClassBySize(size);
572}
573
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
575 : Mir2Lir(cu, mir_graph, arena) {
576 for (int i = 0; i < kMipsLast; i++) {
577 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
578 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
579 << " is wrong: expecting " << i << ", seeing "
580 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
581 }
582 }
583}
584
585Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
586 ArenaAllocator* const arena) {
587 return new MipsMir2Lir(cu, mir_graph, arena);
588}
589
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700590uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700591 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700592 return MipsMir2Lir::EncodingMap[opcode].flags;
593}
594
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700595const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700596 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 return MipsMir2Lir::EncodingMap[opcode].name;
598}
599
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700600const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700601 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 return MipsMir2Lir::EncodingMap[opcode].fmt;
603}
604
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700605} // namespace art