blob: efa130c65d875982d25514293e6e830f4b8e662e [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);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700448}
449
Ian Rogersd582fa42014-11-05 23:46:43 -0800450bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
451 if (cu_->GetInstructionSetFeatures()->IsSmp()) {
452 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
453 return true;
454 } else {
455 return false;
456 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457}
458
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700459void MipsMir2Lir::CompilerInitializeRegAlloc() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800460 const bool fpu_is_32bit =
461 cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100462 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800463 sp_regs,
464 fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100465 reserved_regs, empty_pool /* reserved64 */,
466 core_temps, empty_pool /* core64_temps */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800467 sp_temps,
468 fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
buzbee091cc402014-03-31 10:14:40 -0700469
470 // Target-specific adjustments.
471
472 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100473 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700474 int sp_reg_num = info->GetReg().GetRegNum();
Ian Rogersd582fa42014-11-05 23:46:43 -0800475 int dp_reg_num;
476 if (fpu_is_32bit) {
477 dp_reg_num = sp_reg_num & ~1;
478 } else {
479 dp_reg_num = sp_reg_num >> 1;
480 }
buzbee091cc402014-03-31 10:14:40 -0700481 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
482 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
483 // Double precision register's master storage should refer to itself.
484 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
485 // Redirect single precision's master storage to master.
486 info->SetMaster(dp_reg_info);
487 // Singles should show a single 32-bit mask bit, at first referring to the low half.
488 DCHECK_EQ(info->StorageMask(), 0x1U);
489 if (sp_reg_num & 1) {
490 // For odd singles, change to user the high word of the backing double.
491 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700492 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700493 }
buzbee091cc402014-03-31 10:14:40 -0700494
495 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
496 // TODO: adjust when we roll to hard float calling convention.
497 reg_pool_->next_core_reg_ = 2;
498 reg_pool_->next_sp_reg_ = 2;
Ian Rogersd582fa42014-11-05 23:46:43 -0800499 if (fpu_is_32bit) {
500 reg_pool_->next_dp_reg_ = 2;
501 } else {
502 reg_pool_->next_dp_reg_ = 1;
503 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504}
505
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506/*
507 * In the Arm code a it is typical to use the link register
508 * to hold the target address. However, for Mips we must
509 * ensure that all branch instructions can be restarted if
510 * there is a trap in the shadow. Allocate a temp register.
511 */
Andreas Gampe98430592014-07-27 19:44:50 -0700512RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700513 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700514 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800515 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516}
517
Dave Allisonb373e092014-02-20 16:06:36 -0800518LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800519 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700520 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700521 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800522 LIR *inst = LoadWordDisp(tmp, 0, tmp);
523 FreeTemp(tmp);
524 return inst;
525}
526
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700527LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
528 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
529 DCHECK(r_dest.IsPair());
530 ClobberCallerSave();
531 LockCallTemps(); // Using fixed registers
532 RegStorage reg_ptr = TargetReg(kArg0);
533 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700534 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700535 LIR *ret = OpReg(kOpBlx, r_tgt);
536 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
537 OpRegCopyWide(r_dest, reg_ret);
538 return ret;
539}
540
541LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
542 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
543 DCHECK(r_src.IsPair());
544 ClobberCallerSave();
545 LockCallTemps(); // Using fixed registers
546 RegStorage temp_ptr = AllocTemp();
547 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
548 RegStorage temp_value = AllocTempWide();
549 OpRegCopyWide(temp_value, r_src);
550 RegStorage reg_ptr = TargetReg(kArg0);
551 OpRegCopy(reg_ptr, temp_ptr);
552 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
553 OpRegCopyWide(reg_value, temp_value);
554 FreeTemp(temp_ptr);
555 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700556 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700557 return OpReg(kOpBlx, r_tgt);
558}
559
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700560void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700561 if (num_core_spills_ == 0) {
562 return;
563 }
564 uint32_t mask = core_spill_mask_;
565 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800566 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 for (int reg = 0; mask; mask >>= 1, reg++) {
568 if (mask & 0x1) {
569 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700570 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700571 }
572 }
573}
574
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700575void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700576 if (num_core_spills_ == 0) {
577 return;
578 }
579 uint32_t mask = core_spill_mask_;
580 int offset = frame_size_;
581 for (int reg = 0; mask; mask >>= 1, reg++) {
582 if (mask & 0x1) {
583 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700584 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700585 }
586 }
buzbee2700f7e2014-03-07 09:46:20 -0800587 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588}
589
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700590bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700591 return (lir->opcode == kMipsB);
592}
593
Vladimir Marko674744e2014-04-24 15:18:26 +0100594RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700595 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700596 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700597 // Smaller aligned load/store is atomic for both core and fp registers.
598 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700599 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700600 }
601 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100602 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
603 return RegClassBySize(size);
604}
605
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
Serguei Katkov717a3e42014-11-13 17:19:42 +0600607 : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608 for (int i = 0; i < kMipsLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700609 DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
610 << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
611 << " is wrong: expecting " << i << ", seeing "
612 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613 }
614}
615
616Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
617 ArenaAllocator* const arena) {
618 return new MipsMir2Lir(cu, mir_graph, arena);
619}
620
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700621uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700622 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 return MipsMir2Lir::EncodingMap[opcode].flags;
624}
625
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700626const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700627 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700628 return MipsMir2Lir::EncodingMap[opcode].name;
629}
630
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700631const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700632 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700633 return MipsMir2Lir::EncodingMap[opcode].fmt;
634}
635
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700636} // namespace art