blob: 185112dbf954278acdde77f6b3ed084227058903 [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"
Brian Carlstrom7940e442013-07-12 13:46:57 -070025#include "dex/compiler_internals.h"
26#include "dex/quick/mir_to_lir-inl.h"
27#include "mips_lir.h"
28
Brian Carlstrom7940e442013-07-12 13:46:57 -070029namespace art {
30
Vladimir Marko089142c2014-06-05 10:57:05 +010031static constexpr RegStorage core_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070032 {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
33 rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
34 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 +010035static constexpr RegStorage sp_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070036 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
37 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Ian Rogersd582fa42014-11-05 23:46:43 -080038static constexpr RegStorage dp_fr0_regs_arr[] =
39 {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
40 rs_rD7_fr0};
41static constexpr RegStorage dp_fr1_regs_arr[] =
42 {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
43 rs_rD7_fr1};
Vladimir Marko089142c2014-06-05 10:57:05 +010044static constexpr RegStorage reserved_regs_arr[] =
buzbee091cc402014-03-31 10:14:40 -070045 {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 +010046static constexpr RegStorage core_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070047 {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
48 rs_rT5, rs_rT6, rs_rT7, rs_rT8};
Vladimir Marko089142c2014-06-05 10:57:05 +010049static constexpr RegStorage sp_temps_arr[] =
buzbee091cc402014-03-31 10:14:40 -070050 {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
51 rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
Ian Rogersd582fa42014-11-05 23:46:43 -080052static constexpr RegStorage dp_fr0_temps_arr[] =
53 {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
54 rs_rD7_fr0};
55static constexpr RegStorage dp_fr1_temps_arr[] =
56 {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
57 rs_rD7_fr1};
buzbee091cc402014-03-31 10:14:40 -070058
Vladimir Marko089142c2014-06-05 10:57:05 +010059static constexpr ArrayRef<const RegStorage> empty_pool;
60static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
61static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
Ian Rogersd582fa42014-11-05 23:46:43 -080062static constexpr ArrayRef<const RegStorage> dp_fr0_regs(dp_fr0_regs_arr);
63static constexpr ArrayRef<const RegStorage> dp_fr1_regs(dp_fr1_regs_arr);
Vladimir Marko089142c2014-06-05 10:57:05 +010064static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
65static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
66static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
Ian Rogersd582fa42014-11-05 23:46:43 -080067static constexpr ArrayRef<const RegStorage> dp_fr0_temps(dp_fr0_temps_arr);
68static constexpr ArrayRef<const RegStorage> dp_fr1_temps(dp_fr1_temps_arr);
Brian Carlstrom7940e442013-07-12 13:46:57 -070069
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070070RegLocation MipsMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000071 return mips_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070072}
73
buzbeea0cd2d72014-06-01 09:33:49 -070074RegLocation MipsMir2Lir::LocCReturnRef() {
75 return mips_loc_c_return;
76}
77
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070078RegLocation MipsMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000079 return mips_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070080}
81
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070082RegLocation MipsMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000083 return mips_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070084}
85
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070086RegLocation MipsMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000087 return mips_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070088}
89
Douglas Leung2db3e262014-06-25 16:02:55 -070090// Convert k64BitSolo into k64BitPair
91RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
92 DCHECK(reg.IsDouble());
93 int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
94 return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
95}
96
Brian Carlstrom7940e442013-07-12 13:46:57 -070097// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080098RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -070099 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700100 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -0700101 case kSelf: res_reg = rs_rMIPS_SELF; break;
102 case kSuspend: res_reg = rs_rMIPS_SUSPEND; break;
103 case kLr: res_reg = rs_rMIPS_LR; break;
104 case kPc: res_reg = rs_rMIPS_PC; break;
105 case kSp: res_reg = rs_rMIPS_SP; break;
106 case kArg0: res_reg = rs_rMIPS_ARG0; break;
107 case kArg1: res_reg = rs_rMIPS_ARG1; break;
108 case kArg2: res_reg = rs_rMIPS_ARG2; break;
109 case kArg3: res_reg = rs_rMIPS_ARG3; break;
110 case kFArg0: res_reg = rs_rMIPS_FARG0; break;
111 case kFArg1: res_reg = rs_rMIPS_FARG1; break;
112 case kFArg2: res_reg = rs_rMIPS_FARG2; break;
113 case kFArg3: res_reg = rs_rMIPS_FARG3; break;
114 case kRet0: res_reg = rs_rMIPS_RET0; break;
115 case kRet1: res_reg = rs_rMIPS_RET1; break;
116 case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
117 case kHiddenArg: res_reg = rs_rT0; break;
118 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
119 case kCount: res_reg = rs_rMIPS_COUNT; break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700120 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 }
buzbee091cc402014-03-31 10:14:40 -0700122 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700123}
124
buzbee2700f7e2014-03-07 09:46:20 -0800125RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800126 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
127 switch (arg_num) {
128 case 0:
buzbee2700f7e2014-03-07 09:46:20 -0800129 return rs_rMIPS_ARG1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800130 case 1:
buzbee2700f7e2014-03-07 09:46:20 -0800131 return rs_rMIPS_ARG2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800132 case 2:
buzbee2700f7e2014-03-07 09:46:20 -0800133 return rs_rMIPS_ARG3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800134 default:
buzbee2700f7e2014-03-07 09:46:20 -0800135 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800136 }
137}
138
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139/*
140 * Decode the register id.
141 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100142ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
Ian Rogersd582fa42014-11-05 23:46:43 -0800143 if (reg.IsDouble()) {
144 if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
145 return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
146 } else {
147 return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
148 }
149 } else if (reg.IsSingle()) {
150 return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
151 } else {
152 return ResourceMask::Bit(reg.GetRegNum());
153 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700154}
155
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100156ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
157 return ResourceMask::Bit(kMipsRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158}
159
160
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100161void MipsMir2Lir::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, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700164 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165
166 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100168 def_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700169 }
170
171 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100172 use_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173 }
174
175 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100176 def_mask->SetBit(kMipsRegLR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 }
buzbee9da5c102014-03-28 12:59:18 -0700178
179 if (flags & REG_DEF_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100180 def_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700181 }
182
183 if (flags & REG_DEF_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100184 def_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700185 }
186
187 if (flags & REG_USE_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100188 use_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700189 }
190
191 if (flags & REG_USE_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100192 use_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700193 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700194}
195
196/* For dumping instructions */
197#define MIPS_REG_COUNT 32
198static const char *mips_reg_name[MIPS_REG_COUNT] = {
199 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
200 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
201 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
202 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
203};
204
205/*
206 * Interpret a format string and build a string no longer than size
207 * See format key in Assemble.c.
208 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700209std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210 std::string buf;
211 int i;
212 const char *fmt_end = &fmt[strlen(fmt)];
213 char tbuf[256];
214 char nc;
215 while (fmt < fmt_end) {
216 int operand;
217 if (*fmt == '!') {
218 fmt++;
219 DCHECK_LT(fmt, fmt_end);
220 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700221 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222 strcpy(tbuf, "!");
223 } else {
224 DCHECK_LT(fmt, fmt_end);
225 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
226 operand = lir->operands[nc-'0'];
227 switch (*fmt++) {
228 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700229 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700230 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 tbuf[i] += operand & 1;
232 operand >>= 1;
233 }
234 break;
235 case 's':
buzbee091cc402014-03-31 10:14:40 -0700236 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 break;
238 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700239 DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
240 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 break;
242 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800243 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700244 break;
245 case 'M':
246 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800247 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 break;
249 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800250 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 break;
252 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800253 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 break;
255 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800256 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700257 break;
258 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800259 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
260 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
261 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 break;
263 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800264 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700265 break;
266 case 'u': {
267 int offset_1 = lir->operands[0];
268 int offset_2 = NEXT_LIR(lir)->operands[0];
269 uintptr_t target =
270 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
271 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800272 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700273 break;
274 }
275
276 /* Nothing to print for BLX_2 */
277 case 'v':
278 strcpy(tbuf, "see above");
279 break;
280 case 'r':
281 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
282 strcpy(tbuf, mips_reg_name[operand]);
283 break;
284 case 'N':
285 // Placeholder for delay slot handling
286 strcpy(tbuf, "; nop");
287 break;
288 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700289 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 break;
291 }
292 buf += tbuf;
293 }
294 } else {
295 buf += *fmt++;
296 }
297 }
298 return buf;
299}
300
301// FIXME: need to redo resource maps for MIPS - fix this at that time
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100302void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 char buf[256];
304 buf[0] = 0;
305
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100306 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 strcpy(buf, "all");
308 } else {
309 char num[8];
310 int i;
311
312 for (i = 0; i < kMipsRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100313 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800314 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700315 strcat(buf, num);
316 }
317 }
318
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100319 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320 strcat(buf, "cc ");
321 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100322 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700323 strcat(buf, "fpcc ");
324 }
325 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100326 if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800327 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
328 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
329 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100331 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700332 strcat(buf, "lit ");
333 }
334
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100335 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700336 strcat(buf, "heap ");
337 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100338 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 strcat(buf, "noalias ");
340 }
341 }
342 if (buf[0]) {
343 LOG(INFO) << prefix << ": " << buf;
344 }
345}
346
347/*
348 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
349 * instructions might call out to C/assembly helper functions. Until
350 * machinery is in place, always spill lr.
351 */
352
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700353void MipsMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700354 core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 num_core_spills_++;
356}
357
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000359void MipsMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700360 Clobber(rs_rZERO);
361 Clobber(rs_rAT);
362 Clobber(rs_rV0);
363 Clobber(rs_rV1);
364 Clobber(rs_rA0);
365 Clobber(rs_rA1);
366 Clobber(rs_rA2);
367 Clobber(rs_rA3);
368 Clobber(rs_rT0);
369 Clobber(rs_rT1);
370 Clobber(rs_rT2);
371 Clobber(rs_rT3);
372 Clobber(rs_rT4);
373 Clobber(rs_rT5);
374 Clobber(rs_rT6);
375 Clobber(rs_rT7);
376 Clobber(rs_rT8);
377 Clobber(rs_rT9);
378 Clobber(rs_rK0);
379 Clobber(rs_rK1);
380 Clobber(rs_rGP);
381 Clobber(rs_rFP);
382 Clobber(rs_rRA);
383 Clobber(rs_rF0);
384 Clobber(rs_rF1);
385 Clobber(rs_rF2);
386 Clobber(rs_rF3);
387 Clobber(rs_rF4);
388 Clobber(rs_rF5);
389 Clobber(rs_rF6);
390 Clobber(rs_rF7);
391 Clobber(rs_rF8);
392 Clobber(rs_rF9);
393 Clobber(rs_rF10);
394 Clobber(rs_rF11);
395 Clobber(rs_rF12);
396 Clobber(rs_rF13);
397 Clobber(rs_rF14);
398 Clobber(rs_rF15);
Ian Rogersd582fa42014-11-05 23:46:43 -0800399 if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
400 Clobber(rs_rD0_fr0);
401 Clobber(rs_rD1_fr0);
402 Clobber(rs_rD2_fr0);
403 Clobber(rs_rD3_fr0);
404 Clobber(rs_rD4_fr0);
405 Clobber(rs_rD5_fr0);
406 Clobber(rs_rD6_fr0);
407 Clobber(rs_rD7_fr0);
408 } else {
409 Clobber(rs_rD0_fr1);
410 Clobber(rs_rD1_fr1);
411 Clobber(rs_rD2_fr1);
412 Clobber(rs_rD3_fr1);
413 Clobber(rs_rD4_fr1);
414 Clobber(rs_rD5_fr1);
415 Clobber(rs_rD6_fr1);
416 Clobber(rs_rD7_fr1);
417 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418}
419
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700420RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
422 RegLocation res = LocCReturnWide();
423 return res;
424}
425
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700426RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
428 RegLocation res = LocCReturn();
429 return res;
430}
431
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700433void MipsMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700434 LockTemp(rs_rMIPS_ARG0);
435 LockTemp(rs_rMIPS_ARG1);
436 LockTemp(rs_rMIPS_ARG2);
437 LockTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438}
439
440/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700441void MipsMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700442 FreeTemp(rs_rMIPS_ARG0);
443 FreeTemp(rs_rMIPS_ARG1);
444 FreeTemp(rs_rMIPS_ARG2);
445 FreeTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446}
447
Ian Rogersd582fa42014-11-05 23:46:43 -0800448bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
449 if (cu_->GetInstructionSetFeatures()->IsSmp()) {
450 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
451 return true;
452 } else {
453 return false;
454 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455}
456
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700457void MipsMir2Lir::CompilerInitializeRegAlloc() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800458 const bool fpu_is_32bit =
459 cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100460 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800461 sp_regs,
462 fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100463 reserved_regs, empty_pool /* reserved64 */,
464 core_temps, empty_pool /* core64_temps */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800465 sp_temps,
466 fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
buzbee091cc402014-03-31 10:14:40 -0700467
468 // Target-specific adjustments.
469
470 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100471 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700472 int sp_reg_num = info->GetReg().GetRegNum();
Ian Rogersd582fa42014-11-05 23:46:43 -0800473 int dp_reg_num;
474 if (fpu_is_32bit) {
475 dp_reg_num = sp_reg_num & ~1;
476 } else {
477 dp_reg_num = sp_reg_num >> 1;
478 }
buzbee091cc402014-03-31 10:14:40 -0700479 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
480 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
481 // Double precision register's master storage should refer to itself.
482 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
483 // Redirect single precision's master storage to master.
484 info->SetMaster(dp_reg_info);
485 // Singles should show a single 32-bit mask bit, at first referring to the low half.
486 DCHECK_EQ(info->StorageMask(), 0x1U);
487 if (sp_reg_num & 1) {
488 // For odd singles, change to user the high word of the backing double.
489 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700490 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 }
buzbee091cc402014-03-31 10:14:40 -0700492
493 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
494 // TODO: adjust when we roll to hard float calling convention.
495 reg_pool_->next_core_reg_ = 2;
496 reg_pool_->next_sp_reg_ = 2;
Ian Rogersd582fa42014-11-05 23:46:43 -0800497 if (fpu_is_32bit) {
498 reg_pool_->next_dp_reg_ = 2;
499 } else {
500 reg_pool_->next_dp_reg_ = 1;
501 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502}
503
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504/*
505 * In the Arm code a it is typical to use the link register
506 * to hold the target address. However, for Mips we must
507 * ensure that all branch instructions can be restarted if
508 * there is a trap in the shadow. Allocate a temp register.
509 */
Andreas Gampe98430592014-07-27 19:44:50 -0700510RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700511 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700512 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800513 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514}
515
Dave Allisonb373e092014-02-20 16:06:36 -0800516LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800517 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700518 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700519 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800520 LIR *inst = LoadWordDisp(tmp, 0, tmp);
521 FreeTemp(tmp);
522 return inst;
523}
524
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700525LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
526 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
527 DCHECK(r_dest.IsPair());
528 ClobberCallerSave();
529 LockCallTemps(); // Using fixed registers
530 RegStorage reg_ptr = TargetReg(kArg0);
531 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700532 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700533 LIR *ret = OpReg(kOpBlx, r_tgt);
534 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
535 OpRegCopyWide(r_dest, reg_ret);
536 return ret;
537}
538
539LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
540 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
541 DCHECK(r_src.IsPair());
542 ClobberCallerSave();
543 LockCallTemps(); // Using fixed registers
544 RegStorage temp_ptr = AllocTemp();
545 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
546 RegStorage temp_value = AllocTempWide();
547 OpRegCopyWide(temp_value, r_src);
548 RegStorage reg_ptr = TargetReg(kArg0);
549 OpRegCopy(reg_ptr, temp_ptr);
550 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
551 OpRegCopyWide(reg_value, temp_value);
552 FreeTemp(temp_ptr);
553 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700554 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700555 return OpReg(kOpBlx, r_tgt);
556}
557
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700558void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 if (num_core_spills_ == 0) {
560 return;
561 }
562 uint32_t mask = core_spill_mask_;
563 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800564 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700565 for (int reg = 0; mask; mask >>= 1, reg++) {
566 if (mask & 0x1) {
567 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700568 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 }
570 }
571}
572
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700573void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574 if (num_core_spills_ == 0) {
575 return;
576 }
577 uint32_t mask = core_spill_mask_;
578 int offset = frame_size_;
579 for (int reg = 0; mask; mask >>= 1, reg++) {
580 if (mask & 0x1) {
581 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700582 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700583 }
584 }
buzbee2700f7e2014-03-07 09:46:20 -0800585 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586}
587
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700588bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589 return (lir->opcode == kMipsB);
590}
591
Vladimir Marko674744e2014-04-24 15:18:26 +0100592RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700593 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700594 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700595 // Smaller aligned load/store is atomic for both core and fp registers.
596 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700597 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700598 }
599 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100600 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
601 return RegClassBySize(size);
602}
603
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
605 : Mir2Lir(cu, mir_graph, arena) {
606 for (int i = 0; i < kMipsLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700607 DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
608 << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
609 << " is wrong: expecting " << i << ", seeing "
610 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611 }
612}
613
614Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
615 ArenaAllocator* const arena) {
616 return new MipsMir2Lir(cu, mir_graph, arena);
617}
618
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700619uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700620 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 return MipsMir2Lir::EncodingMap[opcode].flags;
622}
623
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700624const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700625 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700626 return MipsMir2Lir::EncodingMap[opcode].name;
627}
628
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700629const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700630 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700631 return MipsMir2Lir::EncodingMap[opcode].fmt;
632}
633
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700634} // namespace art