blob: 830f63ac5f3d71dade17df0456b25d2e33e8e54f [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
Ian Rogersd582fa42014-11-05 23:46:43 -080023#include "arch/mips/instruction_set_features_mips.h"
Andreas Gampe53c913b2014-08-12 23:19:23 -070024#include "backend_mips.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080025#include "base/logging.h"
26#include "dex/compiler_ir.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070027#include "dex/quick/mir_to_lir-inl.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080028#include "driver/compiler_driver.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070029#include "mips_lir.h"
30
Brian Carlstrom7940e442013-07-12 13:46:57 -070031namespace art {
32
Vladimir Marko089142c2014-06-05 10:57:05 +010033static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070034 {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
35 rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
36 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 +010037static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070038 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
39 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Ian Rogersd582fa42014-11-05 23:46:43 -080040static constexpr RegStorage dp_fr0_regs_arr[] =
41 {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
42 rs_rD7_fr0};
43static constexpr RegStorage dp_fr1_regs_arr[] =
44 {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
45 rs_rD7_fr1};
Vladimir Marko089142c2014-06-05 10:57:05 +010046static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070047 {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 +010048static constexpr RegStorage core_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070049 {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
50 rs_rT5, rs_rT6, rs_rT7, rs_rT8};
Vladimir Marko089142c2014-06-05 10:57:05 +010051static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070052 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
53 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Ian Rogersd582fa42014-11-05 23:46:43 -080054static constexpr RegStorage dp_fr0_temps_arr[] =
55 {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
56 rs_rD7_fr0};
57static constexpr RegStorage dp_fr1_temps_arr[] =
58 {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
59 rs_rD7_fr1};
buzbee091cc402014-03-31 10:14:40 -070060
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);
Ian Rogersd582fa42014-11-05 23:46:43 -080064static constexpr ArrayRef<const RegStorage> dp_fr0_regs(dp_fr0_regs_arr);
65static constexpr ArrayRef<const RegStorage> dp_fr1_regs(dp_fr1_regs_arr);
Vladimir Marko089142c2014-06-05 10:57:05 +010066static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
67static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
68static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
Ian Rogersd582fa42014-11-05 23:46:43 -080069static constexpr ArrayRef<const RegStorage> dp_fr0_temps(dp_fr0_temps_arr);
70static constexpr ArrayRef<const RegStorage> dp_fr1_temps(dp_fr1_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070071
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070072RegLocation MipsMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000073 return mips_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070074}
75
buzbeea0cd2d72014-06-01 09:33:49 -070076RegLocation MipsMir2Lir::LocCReturnRef() {
77 return mips_loc_c_return;
78}
79
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070080RegLocation MipsMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000081 return mips_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070082}
83
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070084RegLocation MipsMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000085 return mips_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070086}
87
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070088RegLocation MipsMir2Lir::LocCReturnDouble() {
Douglas Leung027f0ff2015-02-27 19:05:03 -080089 if (fpuIs32Bit_) {
90 return mips_loc_c_return_double_fr0;
91 } else {
92 return mips_loc_c_return_double_fr1;
93 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070094}
95
Douglas Leung2db3e262014-06-25 16:02:55 -070096// Convert k64BitSolo into k64BitPair
97RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -080098 DCHECK(reg.IsDouble());
Douglas Leung027f0ff2015-02-27 19:05:03 -080099 DCHECK_EQ(reg.GetRegNum() & 1, 0);
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800100 int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
101 return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
Douglas Leung2db3e262014-06-25 16:02:55 -0700102}
103
Douglas Leung027f0ff2015-02-27 19:05:03 -0800104// Convert 64bit FP (k64BitSolo or k64BitPair) into k32BitSolo.
105// This routine is only used to allow a 64bit FPU to access FP registers 32bits at a time.
106RegStorage MipsMir2Lir::Fp64ToSolo32(RegStorage reg) {
107 DCHECK(!fpuIs32Bit_);
108 DCHECK(reg.IsDouble());
109 DCHECK(!reg.IsPair());
110 int reg_num = reg.GetRegNum() | RegStorage::kFloatingPoint;
111 return RegStorage(RegStorage::k32BitSolo, reg_num);
112}
113
114// Return a target-dependent special register.
115RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg, WideKind wide_kind) {
116 if (wide_kind == kWide) {
117 DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
118 RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
119 TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
120 if (!fpuIs32Bit_ && ret_reg.IsFloat()) {
121 // convert 64BitPair to 64BitSolo for 64bit FPUs.
122 RegStorage low = ret_reg.GetLow();
123 ret_reg = RegStorage::FloatSolo64(low.GetRegNum());
124 }
125 return ret_reg;
126 } else {
127 return TargetReg(reg);
128 }
129}
130
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -0800132RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -0700133 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -0700135 case kSelf: res_reg = rs_rMIPS_SELF; break;
136 case kSuspend: res_reg = rs_rMIPS_SUSPEND; break;
137 case kLr: res_reg = rs_rMIPS_LR; break;
138 case kPc: res_reg = rs_rMIPS_PC; break;
139 case kSp: res_reg = rs_rMIPS_SP; break;
140 case kArg0: res_reg = rs_rMIPS_ARG0; break;
141 case kArg1: res_reg = rs_rMIPS_ARG1; break;
142 case kArg2: res_reg = rs_rMIPS_ARG2; break;
143 case kArg3: res_reg = rs_rMIPS_ARG3; break;
144 case kFArg0: res_reg = rs_rMIPS_FARG0; break;
145 case kFArg1: res_reg = rs_rMIPS_FARG1; break;
146 case kFArg2: res_reg = rs_rMIPS_FARG2; break;
147 case kFArg3: res_reg = rs_rMIPS_FARG3; break;
148 case kRet0: res_reg = rs_rMIPS_RET0; break;
149 case kRet1: res_reg = rs_rMIPS_RET1; break;
150 case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
151 case kHiddenArg: res_reg = rs_rT0; break;
152 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
153 case kCount: res_reg = rs_rMIPS_COUNT; break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700154 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 }
buzbee091cc402014-03-31 10:14:40 -0700156 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157}
158
Serguei Katkov717a3e42014-11-13 17:19:42 +0600159RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
160 const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
161 const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
162
163 RegStorage result = RegStorage::InvalidReg();
164 if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
165 result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
166 arg.IsRef() ? kRef : kNotWide);
167 if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
168 result = RegStorage::MakeRegPair(
169 result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
170 }
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800171 }
Serguei Katkov717a3e42014-11-13 17:19:42 +0600172 return result;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800173}
174
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175/*
176 * Decode the register id.
177 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100178ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
Ian Rogersd582fa42014-11-05 23:46:43 -0800179 if (reg.IsDouble()) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800180 return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
Ian Rogersd582fa42014-11-05 23:46:43 -0800181 } else if (reg.IsSingle()) {
182 return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
183 } else {
184 return ResourceMask::Bit(reg.GetRegNum());
185 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700186}
187
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100188ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
189 return ResourceMask::Bit(kMipsRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700190}
191
192
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100193void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
194 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700195 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700196 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197
198 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100200 def_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 }
202
203 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100204 use_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 }
206
207 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100208 def_mask->SetBit(kMipsRegLR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209 }
buzbee9da5c102014-03-28 12:59:18 -0700210
211 if (flags & REG_DEF_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100212 def_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700213 }
214
215 if (flags & REG_DEF_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100216 def_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700217 }
218
219 if (flags & REG_USE_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100220 use_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700221 }
222
223 if (flags & REG_USE_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100224 use_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700225 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700226}
227
228/* For dumping instructions */
229#define MIPS_REG_COUNT 32
230static const char *mips_reg_name[MIPS_REG_COUNT] = {
231 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
232 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
233 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
234 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
235};
236
237/*
238 * Interpret a format string and build a string no longer than size
239 * See format key in Assemble.c.
240 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700241std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 std::string buf;
243 int i;
244 const char *fmt_end = &fmt[strlen(fmt)];
245 char tbuf[256];
246 char nc;
247 while (fmt < fmt_end) {
248 int operand;
249 if (*fmt == '!') {
250 fmt++;
251 DCHECK_LT(fmt, fmt_end);
252 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700253 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 strcpy(tbuf, "!");
255 } else {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800256 DCHECK_LT(fmt, fmt_end);
257 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
258 operand = lir->operands[nc-'0'];
259 switch (*fmt++) {
260 case 'b':
261 strcpy(tbuf, "0000");
262 for (i = 3; i >= 0; i--) {
263 tbuf[i] += operand & 1;
264 operand >>= 1;
265 }
266 break;
267 case 's':
268 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
269 break;
270 case 'S':
271 DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
272 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
273 break;
274 case 'h':
275 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
276 break;
277 case 'M':
278 case 'd':
279 snprintf(tbuf, arraysize(tbuf), "%d", operand);
280 break;
281 case 'D':
282 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
283 break;
284 case 'E':
285 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
286 break;
287 case 'F':
288 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
289 break;
290 case 't':
291 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
292 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
293 lir->target);
294 break;
295 case 'T':
296 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
297 break;
298 case 'u': {
299 int offset_1 = lir->operands[0];
300 int offset_2 = NEXT_LIR(lir)->operands[0];
301 uintptr_t target =
302 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
303 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
304 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
305 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 }
307
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800308 /* Nothing to print for BLX_2 */
309 case 'v':
310 strcpy(tbuf, "see above");
311 break;
312 case 'r':
313 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
314 strcpy(tbuf, mips_reg_name[operand]);
315 break;
316 case 'N':
317 // Placeholder for delay slot handling
318 strcpy(tbuf, "; nop");
319 break;
320 default:
321 strcpy(tbuf, "DecodeError");
322 break;
323 }
324 buf += tbuf;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 }
326 } else {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800327 buf += *fmt++;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 }
329 }
330 return buf;
331}
332
333// FIXME: need to redo resource maps for MIPS - fix this at that time
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100334void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 char buf[256];
336 buf[0] = 0;
337
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100338 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 strcpy(buf, "all");
340 } else {
341 char num[8];
342 int i;
343
344 for (i = 0; i < kMipsRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100345 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800346 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 strcat(buf, num);
348 }
349 }
350
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100351 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 strcat(buf, "cc ");
353 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100354 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 strcat(buf, "fpcc ");
356 }
357 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100358 if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800359 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
360 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
361 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700362 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100363 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 strcat(buf, "lit ");
365 }
366
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100367 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 strcat(buf, "heap ");
369 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100370 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700371 strcat(buf, "noalias ");
372 }
373 }
374 if (buf[0]) {
375 LOG(INFO) << prefix << ": " << buf;
376 }
377}
378
379/*
380 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
381 * instructions might call out to C/assembly helper functions. Until
382 * machinery is in place, always spill lr.
383 */
384
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700385void MipsMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700386 core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 num_core_spills_++;
388}
389
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000391void MipsMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700392 Clobber(rs_rZERO);
393 Clobber(rs_rAT);
394 Clobber(rs_rV0);
395 Clobber(rs_rV1);
396 Clobber(rs_rA0);
397 Clobber(rs_rA1);
398 Clobber(rs_rA2);
399 Clobber(rs_rA3);
400 Clobber(rs_rT0);
401 Clobber(rs_rT1);
402 Clobber(rs_rT2);
403 Clobber(rs_rT3);
404 Clobber(rs_rT4);
405 Clobber(rs_rT5);
406 Clobber(rs_rT6);
407 Clobber(rs_rT7);
408 Clobber(rs_rT8);
409 Clobber(rs_rT9);
410 Clobber(rs_rK0);
411 Clobber(rs_rK1);
412 Clobber(rs_rGP);
413 Clobber(rs_rFP);
414 Clobber(rs_rRA);
415 Clobber(rs_rF0);
416 Clobber(rs_rF1);
417 Clobber(rs_rF2);
418 Clobber(rs_rF3);
419 Clobber(rs_rF4);
420 Clobber(rs_rF5);
421 Clobber(rs_rF6);
422 Clobber(rs_rF7);
423 Clobber(rs_rF8);
424 Clobber(rs_rF9);
425 Clobber(rs_rF10);
426 Clobber(rs_rF11);
427 Clobber(rs_rF12);
428 Clobber(rs_rF13);
429 Clobber(rs_rF14);
430 Clobber(rs_rF15);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800431 if (fpuIs32Bit_) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800432 Clobber(rs_rD0_fr0);
433 Clobber(rs_rD1_fr0);
434 Clobber(rs_rD2_fr0);
435 Clobber(rs_rD3_fr0);
436 Clobber(rs_rD4_fr0);
437 Clobber(rs_rD5_fr0);
438 Clobber(rs_rD6_fr0);
439 Clobber(rs_rD7_fr0);
440 } else {
441 Clobber(rs_rD0_fr1);
442 Clobber(rs_rD1_fr1);
443 Clobber(rs_rD2_fr1);
444 Clobber(rs_rD3_fr1);
445 Clobber(rs_rD4_fr1);
446 Clobber(rs_rD5_fr1);
447 Clobber(rs_rD6_fr1);
448 Clobber(rs_rD7_fr1);
449 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450}
451
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700452RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
454 RegLocation res = LocCReturnWide();
455 return res;
456}
457
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700458RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
460 RegLocation res = LocCReturn();
461 return res;
462}
463
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700465void MipsMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700466 LockTemp(rs_rMIPS_ARG0);
467 LockTemp(rs_rMIPS_ARG1);
468 LockTemp(rs_rMIPS_ARG2);
469 LockTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700470}
471
472/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700473void MipsMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700474 FreeTemp(rs_rMIPS_ARG0);
475 FreeTemp(rs_rMIPS_ARG1);
476 FreeTemp(rs_rMIPS_ARG2);
477 FreeTemp(rs_rMIPS_ARG3);
Vladimir Markobfe400b2014-12-19 19:27:26 +0000478 FreeTemp(TargetReg(kHiddenArg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479}
480
Ian Rogersd582fa42014-11-05 23:46:43 -0800481bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800482 if (cu_->compiler_driver->GetInstructionSetFeatures()->IsSmp()) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800483 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
484 return true;
485 } else {
486 return false;
487 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700488}
489
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700490void MipsMir2Lir::CompilerInitializeRegAlloc() {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100491 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800492 sp_regs,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800493 fpuIs32Bit_ ? dp_fr0_regs : dp_fr1_regs,
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100494 reserved_regs, empty_pool /* reserved64 */,
495 core_temps, empty_pool /* core64_temps */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800496 sp_temps,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800497 fpuIs32Bit_ ? dp_fr0_temps : dp_fr1_temps));
buzbee091cc402014-03-31 10:14:40 -0700498
499 // Target-specific adjustments.
500
501 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100502 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700503 int sp_reg_num = info->GetReg().GetRegNum();
Douglas Leung027f0ff2015-02-27 19:05:03 -0800504 int dp_reg_num = sp_reg_num & ~1;
buzbee091cc402014-03-31 10:14:40 -0700505 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
506 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
507 // Double precision register's master storage should refer to itself.
508 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
509 // Redirect single precision's master storage to master.
510 info->SetMaster(dp_reg_info);
511 // Singles should show a single 32-bit mask bit, at first referring to the low half.
512 DCHECK_EQ(info->StorageMask(), 0x1U);
513 if (sp_reg_num & 1) {
514 // For odd singles, change to user the high word of the backing double.
515 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517 }
buzbee091cc402014-03-31 10:14:40 -0700518
519 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
520 // TODO: adjust when we roll to hard float calling convention.
521 reg_pool_->next_core_reg_ = 2;
522 reg_pool_->next_sp_reg_ = 2;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800523 reg_pool_->next_dp_reg_ = 2;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524}
525
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526/*
527 * In the Arm code a it is typical to use the link register
528 * to hold the target address. However, for Mips we must
529 * ensure that all branch instructions can be restarted if
530 * there is a trap in the shadow. Allocate a temp register.
531 */
Andreas Gampe98430592014-07-27 19:44:50 -0700532RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700533 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700534 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800535 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700536}
537
Dave Allisonb373e092014-02-20 16:06:36 -0800538LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800539 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700540 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700541 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800542 LIR *inst = LoadWordDisp(tmp, 0, tmp);
543 FreeTemp(tmp);
544 return inst;
545}
546
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700547LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
548 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
549 DCHECK(r_dest.IsPair());
550 ClobberCallerSave();
551 LockCallTemps(); // Using fixed registers
552 RegStorage reg_ptr = TargetReg(kArg0);
553 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700554 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700555 LIR *ret = OpReg(kOpBlx, r_tgt);
556 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
557 OpRegCopyWide(r_dest, reg_ret);
558 return ret;
559}
560
561LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
562 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
563 DCHECK(r_src.IsPair());
564 ClobberCallerSave();
565 LockCallTemps(); // Using fixed registers
566 RegStorage temp_ptr = AllocTemp();
567 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
568 RegStorage temp_value = AllocTempWide();
569 OpRegCopyWide(temp_value, r_src);
570 RegStorage reg_ptr = TargetReg(kArg0);
571 OpRegCopy(reg_ptr, temp_ptr);
572 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
573 OpRegCopyWide(reg_value, temp_value);
574 FreeTemp(temp_ptr);
575 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700576 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700577 return OpReg(kOpBlx, r_tgt);
578}
579
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700580void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700581 if (num_core_spills_ == 0) {
582 return;
583 }
584 uint32_t mask = core_spill_mask_;
585 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800586 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700587 for (int reg = 0; mask; mask >>= 1, reg++) {
588 if (mask & 0x1) {
589 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700590 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700591 }
592 }
593}
594
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700595void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700596 if (num_core_spills_ == 0) {
597 return;
598 }
599 uint32_t mask = core_spill_mask_;
600 int offset = frame_size_;
601 for (int reg = 0; mask; mask >>= 1, reg++) {
602 if (mask & 0x1) {
603 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700604 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605 }
606 }
buzbee2700f7e2014-03-07 09:46:20 -0800607 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608}
609
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700610bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611 return (lir->opcode == kMipsB);
612}
613
Vladimir Marko674744e2014-04-24 15:18:26 +0100614RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700615 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700616 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700617 // Smaller aligned load/store is atomic for both core and fp registers.
618 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700619 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700620 }
621 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100622 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
623 return RegClassBySize(size);
624}
625
Brian Carlstrom7940e442013-07-12 13:46:57 -0700626MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
Douglas Leung027f0ff2015-02-27 19:05:03 -0800627 : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this),
628 isaIsR6_(cu->compiler_driver->GetInstructionSetFeatures()
629 ->AsMipsInstructionSetFeatures()->IsR6()),
630 fpuIs32Bit_(cu->compiler_driver->GetInstructionSetFeatures()
631 ->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 for (int i = 0; i < kMipsLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700633 DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
634 << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
635 << " is wrong: expecting " << i << ", seeing "
636 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 }
638}
639
640Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
641 ArenaAllocator* const arena) {
642 return new MipsMir2Lir(cu, mir_graph, arena);
643}
644
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700645uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700646 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700647 return MipsMir2Lir::EncodingMap[opcode].flags;
648}
649
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700650const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700651 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700652 return MipsMir2Lir::EncodingMap[opcode].name;
653}
654
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700655const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700656 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700657 return MipsMir2Lir::EncodingMap[opcode].fmt;
658}
659
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700660} // namespace art