blob: c22ba04e080ceee3a58a1bbf4339abf6157e09e1 [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
Serguei Katkov717a3e42014-11-13 17:19:42 +0600125RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
126 const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
127 const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
128
129 RegStorage result = RegStorage::InvalidReg();
130 if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
131 result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
132 arg.IsRef() ? kRef : kNotWide);
133 if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
134 result = RegStorage::MakeRegPair(
135 result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
136 }
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800137 }
Serguei Katkov717a3e42014-11-13 17:19:42 +0600138 return result;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800139}
140
Brian Carlstrom7940e442013-07-12 13:46:57 -0700141/*
142 * Decode the register id.
143 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100144ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
Ian Rogersd582fa42014-11-05 23:46:43 -0800145 if (reg.IsDouble()) {
146 if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
147 return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
148 } else {
149 return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
150 }
151 } else if (reg.IsSingle()) {
152 return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
153 } else {
154 return ResourceMask::Bit(reg.GetRegNum());
155 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156}
157
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100158ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
159 return ResourceMask::Bit(kMipsRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160}
161
162
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100163void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
164 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700166 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167
168 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700169 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100170 def_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700171 }
172
173 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100174 use_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175 }
176
177 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100178 def_mask->SetBit(kMipsRegLR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700179 }
buzbee9da5c102014-03-28 12:59:18 -0700180
181 if (flags & REG_DEF_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100182 def_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700183 }
184
185 if (flags & REG_DEF_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100186 def_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700187 }
188
189 if (flags & REG_USE_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100190 use_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700191 }
192
193 if (flags & REG_USE_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100194 use_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700195 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700196}
197
198/* For dumping instructions */
199#define MIPS_REG_COUNT 32
200static const char *mips_reg_name[MIPS_REG_COUNT] = {
201 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
202 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
203 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
204 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
205};
206
207/*
208 * Interpret a format string and build a string no longer than size
209 * See format key in Assemble.c.
210 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700211std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 std::string buf;
213 int i;
214 const char *fmt_end = &fmt[strlen(fmt)];
215 char tbuf[256];
216 char nc;
217 while (fmt < fmt_end) {
218 int operand;
219 if (*fmt == '!') {
220 fmt++;
221 DCHECK_LT(fmt, fmt_end);
222 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700223 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 strcpy(tbuf, "!");
225 } else {
226 DCHECK_LT(fmt, fmt_end);
227 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
228 operand = lir->operands[nc-'0'];
229 switch (*fmt++) {
230 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700231 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700232 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 tbuf[i] += operand & 1;
234 operand >>= 1;
235 }
236 break;
237 case 's':
buzbee091cc402014-03-31 10:14:40 -0700238 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 break;
240 case 'S':
buzbee091cc402014-03-31 10:14:40 -0700241 DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
242 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 break;
244 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800245 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 break;
247 case 'M':
248 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800249 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 break;
251 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800252 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700253 break;
254 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800255 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700256 break;
257 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800258 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 break;
260 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800261 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
262 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
263 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 break;
265 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800266 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700267 break;
268 case 'u': {
269 int offset_1 = lir->operands[0];
270 int offset_2 = NEXT_LIR(lir)->operands[0];
271 uintptr_t target =
272 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
273 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800274 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 break;
276 }
277
278 /* Nothing to print for BLX_2 */
279 case 'v':
280 strcpy(tbuf, "see above");
281 break;
282 case 'r':
283 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
284 strcpy(tbuf, mips_reg_name[operand]);
285 break;
286 case 'N':
287 // Placeholder for delay slot handling
288 strcpy(tbuf, "; nop");
289 break;
290 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700291 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700292 break;
293 }
294 buf += tbuf;
295 }
296 } else {
297 buf += *fmt++;
298 }
299 }
300 return buf;
301}
302
303// FIXME: need to redo resource maps for MIPS - fix this at that time
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100304void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 char buf[256];
306 buf[0] = 0;
307
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100308 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 strcpy(buf, "all");
310 } else {
311 char num[8];
312 int i;
313
314 for (i = 0; i < kMipsRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100315 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800316 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 strcat(buf, num);
318 }
319 }
320
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100321 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700322 strcat(buf, "cc ");
323 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100324 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 strcat(buf, "fpcc ");
326 }
327 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100328 if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800329 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
330 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
331 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700332 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100333 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 strcat(buf, "lit ");
335 }
336
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100337 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 strcat(buf, "heap ");
339 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100340 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 strcat(buf, "noalias ");
342 }
343 }
344 if (buf[0]) {
345 LOG(INFO) << prefix << ": " << buf;
346 }
347}
348
349/*
350 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
351 * instructions might call out to C/assembly helper functions. Until
352 * machinery is in place, always spill lr.
353 */
354
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700355void MipsMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700356 core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 num_core_spills_++;
358}
359
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000361void MipsMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700362 Clobber(rs_rZERO);
363 Clobber(rs_rAT);
364 Clobber(rs_rV0);
365 Clobber(rs_rV1);
366 Clobber(rs_rA0);
367 Clobber(rs_rA1);
368 Clobber(rs_rA2);
369 Clobber(rs_rA3);
370 Clobber(rs_rT0);
371 Clobber(rs_rT1);
372 Clobber(rs_rT2);
373 Clobber(rs_rT3);
374 Clobber(rs_rT4);
375 Clobber(rs_rT5);
376 Clobber(rs_rT6);
377 Clobber(rs_rT7);
378 Clobber(rs_rT8);
379 Clobber(rs_rT9);
380 Clobber(rs_rK0);
381 Clobber(rs_rK1);
382 Clobber(rs_rGP);
383 Clobber(rs_rFP);
384 Clobber(rs_rRA);
385 Clobber(rs_rF0);
386 Clobber(rs_rF1);
387 Clobber(rs_rF2);
388 Clobber(rs_rF3);
389 Clobber(rs_rF4);
390 Clobber(rs_rF5);
391 Clobber(rs_rF6);
392 Clobber(rs_rF7);
393 Clobber(rs_rF8);
394 Clobber(rs_rF9);
395 Clobber(rs_rF10);
396 Clobber(rs_rF11);
397 Clobber(rs_rF12);
398 Clobber(rs_rF13);
399 Clobber(rs_rF14);
400 Clobber(rs_rF15);
Ian Rogersd582fa42014-11-05 23:46:43 -0800401 if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
402 Clobber(rs_rD0_fr0);
403 Clobber(rs_rD1_fr0);
404 Clobber(rs_rD2_fr0);
405 Clobber(rs_rD3_fr0);
406 Clobber(rs_rD4_fr0);
407 Clobber(rs_rD5_fr0);
408 Clobber(rs_rD6_fr0);
409 Clobber(rs_rD7_fr0);
410 } else {
411 Clobber(rs_rD0_fr1);
412 Clobber(rs_rD1_fr1);
413 Clobber(rs_rD2_fr1);
414 Clobber(rs_rD3_fr1);
415 Clobber(rs_rD4_fr1);
416 Clobber(rs_rD5_fr1);
417 Clobber(rs_rD6_fr1);
418 Clobber(rs_rD7_fr1);
419 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420}
421
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700422RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
424 RegLocation res = LocCReturnWide();
425 return res;
426}
427
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700428RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
430 RegLocation res = LocCReturn();
431 return res;
432}
433
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700435void MipsMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700436 LockTemp(rs_rMIPS_ARG0);
437 LockTemp(rs_rMIPS_ARG1);
438 LockTemp(rs_rMIPS_ARG2);
439 LockTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700440}
441
442/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700443void MipsMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700444 FreeTemp(rs_rMIPS_ARG0);
445 FreeTemp(rs_rMIPS_ARG1);
446 FreeTemp(rs_rMIPS_ARG2);
447 FreeTemp(rs_rMIPS_ARG3);
Vladimir Markobfe400b2014-12-19 19:27:26 +0000448 FreeTemp(TargetReg(kHiddenArg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449}
450
Ian Rogersd582fa42014-11-05 23:46:43 -0800451bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
452 if (cu_->GetInstructionSetFeatures()->IsSmp()) {
453 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
454 return true;
455 } else {
456 return false;
457 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458}
459
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700460void MipsMir2Lir::CompilerInitializeRegAlloc() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800461 const bool fpu_is_32bit =
462 cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100463 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800464 sp_regs,
465 fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100466 reserved_regs, empty_pool /* reserved64 */,
467 core_temps, empty_pool /* core64_temps */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800468 sp_temps,
469 fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
buzbee091cc402014-03-31 10:14:40 -0700470
471 // Target-specific adjustments.
472
473 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100474 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700475 int sp_reg_num = info->GetReg().GetRegNum();
Ian Rogersd582fa42014-11-05 23:46:43 -0800476 int dp_reg_num;
477 if (fpu_is_32bit) {
478 dp_reg_num = sp_reg_num & ~1;
479 } else {
480 dp_reg_num = sp_reg_num >> 1;
481 }
buzbee091cc402014-03-31 10:14:40 -0700482 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
483 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
484 // Double precision register's master storage should refer to itself.
485 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
486 // Redirect single precision's master storage to master.
487 info->SetMaster(dp_reg_info);
488 // Singles should show a single 32-bit mask bit, at first referring to the low half.
489 DCHECK_EQ(info->StorageMask(), 0x1U);
490 if (sp_reg_num & 1) {
491 // For odd singles, change to user the high word of the backing double.
492 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700493 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 }
buzbee091cc402014-03-31 10:14:40 -0700495
496 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
497 // TODO: adjust when we roll to hard float calling convention.
498 reg_pool_->next_core_reg_ = 2;
499 reg_pool_->next_sp_reg_ = 2;
Ian Rogersd582fa42014-11-05 23:46:43 -0800500 if (fpu_is_32bit) {
501 reg_pool_->next_dp_reg_ = 2;
502 } else {
503 reg_pool_->next_dp_reg_ = 1;
504 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700505}
506
Brian Carlstrom7940e442013-07-12 13:46:57 -0700507/*
508 * In the Arm code a it is typical to use the link register
509 * to hold the target address. However, for Mips we must
510 * ensure that all branch instructions can be restarted if
511 * there is a trap in the shadow. Allocate a temp register.
512 */
Andreas Gampe98430592014-07-27 19:44:50 -0700513RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700514 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700515 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800516 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517}
518
Dave Allisonb373e092014-02-20 16:06:36 -0800519LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800520 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700521 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700522 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800523 LIR *inst = LoadWordDisp(tmp, 0, tmp);
524 FreeTemp(tmp);
525 return inst;
526}
527
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700528LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
529 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
530 DCHECK(r_dest.IsPair());
531 ClobberCallerSave();
532 LockCallTemps(); // Using fixed registers
533 RegStorage reg_ptr = TargetReg(kArg0);
534 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700535 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700536 LIR *ret = OpReg(kOpBlx, r_tgt);
537 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
538 OpRegCopyWide(r_dest, reg_ret);
539 return ret;
540}
541
542LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
543 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
544 DCHECK(r_src.IsPair());
545 ClobberCallerSave();
546 LockCallTemps(); // Using fixed registers
547 RegStorage temp_ptr = AllocTemp();
548 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
549 RegStorage temp_value = AllocTempWide();
550 OpRegCopyWide(temp_value, r_src);
551 RegStorage reg_ptr = TargetReg(kArg0);
552 OpRegCopy(reg_ptr, temp_ptr);
553 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
554 OpRegCopyWide(reg_value, temp_value);
555 FreeTemp(temp_ptr);
556 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700557 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700558 return OpReg(kOpBlx, r_tgt);
559}
560
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700561void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700562 if (num_core_spills_ == 0) {
563 return;
564 }
565 uint32_t mask = core_spill_mask_;
566 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800567 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700568 for (int reg = 0; mask; mask >>= 1, reg++) {
569 if (mask & 0x1) {
570 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700571 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700572 }
573 }
574}
575
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700576void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 if (num_core_spills_ == 0) {
578 return;
579 }
580 uint32_t mask = core_spill_mask_;
581 int offset = frame_size_;
582 for (int reg = 0; mask; mask >>= 1, reg++) {
583 if (mask & 0x1) {
584 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700585 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586 }
587 }
buzbee2700f7e2014-03-07 09:46:20 -0800588 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589}
590
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700591bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700592 return (lir->opcode == kMipsB);
593}
594
Vladimir Marko674744e2014-04-24 15:18:26 +0100595RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700596 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700597 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700598 // Smaller aligned load/store is atomic for both core and fp registers.
599 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700600 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700601 }
602 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100603 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
604 return RegClassBySize(size);
605}
606
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
Serguei Katkov717a3e42014-11-13 17:19:42 +0600608 : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609 for (int i = 0; i < kMipsLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700610 DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
611 << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
612 << " is wrong: expecting " << i << ", seeing "
613 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614 }
615}
616
617Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
618 ArenaAllocator* const arena) {
619 return new MipsMir2Lir(cu, mir_graph, arena);
620}
621
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700622uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700623 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624 return MipsMir2Lir::EncodingMap[opcode].flags;
625}
626
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700627const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700628 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700629 return MipsMir2Lir::EncodingMap[opcode].name;
630}
631
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700632const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700633 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700634 return MipsMir2Lir::EncodingMap[opcode].fmt;
635}
636
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700637} // namespace art