blob: 8574ffd5411302e6d4f137c438617e9cbd3b0bcd [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() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000089 return mips_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070090}
91
Douglas Leung2db3e262014-06-25 16:02:55 -070092// Convert k64BitSolo into k64BitPair
93RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -080094 DCHECK(reg.IsDouble());
95 int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
96 return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
Douglas Leung2db3e262014-06-25 16:02:55 -070097}
98
Brian Carlstrom7940e442013-07-12 13:46:57 -070099// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -0800100RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
buzbee091cc402014-03-31 10:14:40 -0700101 RegStorage res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102 switch (reg) {
buzbee091cc402014-03-31 10:14:40 -0700103 case kSelf: res_reg = rs_rMIPS_SELF; break;
104 case kSuspend: res_reg = rs_rMIPS_SUSPEND; break;
105 case kLr: res_reg = rs_rMIPS_LR; break;
106 case kPc: res_reg = rs_rMIPS_PC; break;
107 case kSp: res_reg = rs_rMIPS_SP; break;
108 case kArg0: res_reg = rs_rMIPS_ARG0; break;
109 case kArg1: res_reg = rs_rMIPS_ARG1; break;
110 case kArg2: res_reg = rs_rMIPS_ARG2; break;
111 case kArg3: res_reg = rs_rMIPS_ARG3; break;
112 case kFArg0: res_reg = rs_rMIPS_FARG0; break;
113 case kFArg1: res_reg = rs_rMIPS_FARG1; break;
114 case kFArg2: res_reg = rs_rMIPS_FARG2; break;
115 case kFArg3: res_reg = rs_rMIPS_FARG3; break;
116 case kRet0: res_reg = rs_rMIPS_RET0; break;
117 case kRet1: res_reg = rs_rMIPS_RET1; break;
118 case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
119 case kHiddenArg: res_reg = rs_rT0; break;
120 case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
121 case kCount: res_reg = rs_rMIPS_COUNT; break;
Dmitry Petrochenko58994cd2014-05-17 01:02:18 +0700122 default: res_reg = RegStorage::InvalidReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700123 }
buzbee091cc402014-03-31 10:14:40 -0700124 return res_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125}
126
Serguei Katkov717a3e42014-11-13 17:19:42 +0600127RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
128 const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
129 const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
130
131 RegStorage result = RegStorage::InvalidReg();
132 if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
133 result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
134 arg.IsRef() ? kRef : kNotWide);
135 if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
136 result = RegStorage::MakeRegPair(
137 result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
138 }
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800139 }
Serguei Katkov717a3e42014-11-13 17:19:42 +0600140 return result;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800141}
142
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143/*
144 * Decode the register id.
145 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100146ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
Ian Rogersd582fa42014-11-05 23:46:43 -0800147 if (reg.IsDouble()) {
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800148 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
149 ->Is32BitFloatingPoint()) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800150 return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
151 } else {
152 return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
153 }
154 } else if (reg.IsSingle()) {
155 return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
156 } else {
157 return ResourceMask::Bit(reg.GetRegNum());
158 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159}
160
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100161ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
162 return ResourceMask::Bit(kMipsRegPC);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163}
164
165
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100166void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
167 ResourceMask* use_mask, ResourceMask* def_mask) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700168 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700169 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170
171 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 if (flags & REG_DEF_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100173 def_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 }
175
176 if (flags & REG_USE_SP) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100177 use_mask->SetBit(kMipsRegSP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 }
179
180 if (flags & REG_DEF_LR) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100181 def_mask->SetBit(kMipsRegLR);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700182 }
buzbee9da5c102014-03-28 12:59:18 -0700183
184 if (flags & REG_DEF_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100185 def_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700186 }
187
188 if (flags & REG_DEF_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100189 def_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700190 }
191
192 if (flags & REG_USE_HI) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100193 use_mask->SetBit(kMipsRegHI);
buzbee9da5c102014-03-28 12:59:18 -0700194 }
195
196 if (flags & REG_USE_LO) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100197 use_mask->SetBit(kMipsRegLO);
buzbee9da5c102014-03-28 12:59:18 -0700198 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199}
200
201/* For dumping instructions */
202#define MIPS_REG_COUNT 32
203static const char *mips_reg_name[MIPS_REG_COUNT] = {
204 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
205 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
206 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
207 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
208};
209
210/*
211 * Interpret a format string and build a string no longer than size
212 * See format key in Assemble.c.
213 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700214std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 std::string buf;
216 int i;
217 const char *fmt_end = &fmt[strlen(fmt)];
218 char tbuf[256];
219 char nc;
220 while (fmt < fmt_end) {
221 int operand;
222 if (*fmt == '!') {
223 fmt++;
224 DCHECK_LT(fmt, fmt_end);
225 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700226 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 strcpy(tbuf, "!");
228 } else {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800229 DCHECK_LT(fmt, fmt_end);
230 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
231 operand = lir->operands[nc-'0'];
232 switch (*fmt++) {
233 case 'b':
234 strcpy(tbuf, "0000");
235 for (i = 3; i >= 0; i--) {
236 tbuf[i] += operand & 1;
237 operand >>= 1;
238 }
239 break;
240 case 's':
241 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
242 break;
243 case 'S':
244 DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
245 snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
246 break;
247 case 'h':
248 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
249 break;
250 case 'M':
251 case 'd':
252 snprintf(tbuf, arraysize(tbuf), "%d", operand);
253 break;
254 case 'D':
255 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
256 break;
257 case 'E':
258 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
259 break;
260 case 'F':
261 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
262 break;
263 case 't':
264 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
265 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
266 lir->target);
267 break;
268 case 'T':
269 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
270 break;
271 case 'u': {
272 int offset_1 = lir->operands[0];
273 int offset_2 = NEXT_LIR(lir)->operands[0];
274 uintptr_t target =
275 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
276 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
277 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
278 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 }
280
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800281 /* Nothing to print for BLX_2 */
282 case 'v':
283 strcpy(tbuf, "see above");
284 break;
285 case 'r':
286 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
287 strcpy(tbuf, mips_reg_name[operand]);
288 break;
289 case 'N':
290 // Placeholder for delay slot handling
291 strcpy(tbuf, "; nop");
292 break;
293 default:
294 strcpy(tbuf, "DecodeError");
295 break;
296 }
297 buf += tbuf;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 }
299 } else {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800300 buf += *fmt++;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 }
302 }
303 return buf;
304}
305
306// FIXME: need to redo resource maps for MIPS - fix this at that time
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100307void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 char buf[256];
309 buf[0] = 0;
310
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100311 if (mask.Equals(kEncodeAll)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 strcpy(buf, "all");
313 } else {
314 char num[8];
315 int i;
316
317 for (i = 0; i < kMipsRegEnd; i++) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100318 if (mask.HasBit(i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800319 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320 strcat(buf, num);
321 }
322 }
323
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100324 if (mask.HasBit(ResourceMask::kCCode)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 strcat(buf, "cc ");
326 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100327 if (mask.HasBit(ResourceMask::kFPStatus)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 strcat(buf, "fpcc ");
329 }
330 /* Memory bits */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100331 if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800332 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
333 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
334 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100336 if (mask.HasBit(ResourceMask::kLiteral)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 strcat(buf, "lit ");
338 }
339
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100340 if (mask.HasBit(ResourceMask::kHeapRef)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 strcat(buf, "heap ");
342 }
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100343 if (mask.HasBit(ResourceMask::kMustNotAlias)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344 strcat(buf, "noalias ");
345 }
346 }
347 if (buf[0]) {
348 LOG(INFO) << prefix << ": " << buf;
349 }
350}
351
352/*
353 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
354 * instructions might call out to C/assembly helper functions. Until
355 * machinery is in place, always spill lr.
356 */
357
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700358void MipsMir2Lir::AdjustSpillMask() {
buzbee091cc402014-03-31 10:14:40 -0700359 core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360 num_core_spills_++;
361}
362
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000364void MipsMir2Lir::ClobberCallerSave() {
buzbee091cc402014-03-31 10:14:40 -0700365 Clobber(rs_rZERO);
366 Clobber(rs_rAT);
367 Clobber(rs_rV0);
368 Clobber(rs_rV1);
369 Clobber(rs_rA0);
370 Clobber(rs_rA1);
371 Clobber(rs_rA2);
372 Clobber(rs_rA3);
373 Clobber(rs_rT0);
374 Clobber(rs_rT1);
375 Clobber(rs_rT2);
376 Clobber(rs_rT3);
377 Clobber(rs_rT4);
378 Clobber(rs_rT5);
379 Clobber(rs_rT6);
380 Clobber(rs_rT7);
381 Clobber(rs_rT8);
382 Clobber(rs_rT9);
383 Clobber(rs_rK0);
384 Clobber(rs_rK1);
385 Clobber(rs_rGP);
386 Clobber(rs_rFP);
387 Clobber(rs_rRA);
388 Clobber(rs_rF0);
389 Clobber(rs_rF1);
390 Clobber(rs_rF2);
391 Clobber(rs_rF3);
392 Clobber(rs_rF4);
393 Clobber(rs_rF5);
394 Clobber(rs_rF6);
395 Clobber(rs_rF7);
396 Clobber(rs_rF8);
397 Clobber(rs_rF9);
398 Clobber(rs_rF10);
399 Clobber(rs_rF11);
400 Clobber(rs_rF12);
401 Clobber(rs_rF13);
402 Clobber(rs_rF14);
403 Clobber(rs_rF15);
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800404 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
405 ->Is32BitFloatingPoint()) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800406 Clobber(rs_rD0_fr0);
407 Clobber(rs_rD1_fr0);
408 Clobber(rs_rD2_fr0);
409 Clobber(rs_rD3_fr0);
410 Clobber(rs_rD4_fr0);
411 Clobber(rs_rD5_fr0);
412 Clobber(rs_rD6_fr0);
413 Clobber(rs_rD7_fr0);
414 } else {
415 Clobber(rs_rD0_fr1);
416 Clobber(rs_rD1_fr1);
417 Clobber(rs_rD2_fr1);
418 Clobber(rs_rD3_fr1);
419 Clobber(rs_rD4_fr1);
420 Clobber(rs_rD5_fr1);
421 Clobber(rs_rD6_fr1);
422 Clobber(rs_rD7_fr1);
423 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424}
425
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700426RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
428 RegLocation res = LocCReturnWide();
429 return res;
430}
431
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700432RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
434 RegLocation res = LocCReturn();
435 return res;
436}
437
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700439void MipsMir2Lir::LockCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700440 LockTemp(rs_rMIPS_ARG0);
441 LockTemp(rs_rMIPS_ARG1);
442 LockTemp(rs_rMIPS_ARG2);
443 LockTemp(rs_rMIPS_ARG3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444}
445
446/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700447void MipsMir2Lir::FreeCallTemps() {
buzbee091cc402014-03-31 10:14:40 -0700448 FreeTemp(rs_rMIPS_ARG0);
449 FreeTemp(rs_rMIPS_ARG1);
450 FreeTemp(rs_rMIPS_ARG2);
451 FreeTemp(rs_rMIPS_ARG3);
Vladimir Markobfe400b2014-12-19 19:27:26 +0000452 FreeTemp(TargetReg(kHiddenArg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453}
454
Ian Rogersd582fa42014-11-05 23:46:43 -0800455bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800456 if (cu_->compiler_driver->GetInstructionSetFeatures()->IsSmp()) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800457 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
458 return true;
459 } else {
460 return false;
461 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700462}
463
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700464void MipsMir2Lir::CompilerInitializeRegAlloc() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800465 const bool fpu_is_32bit =
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800466 cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
467 ->Is32BitFloatingPoint();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100468 reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800469 sp_regs,
470 fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100471 reserved_regs, empty_pool /* reserved64 */,
472 core_temps, empty_pool /* core64_temps */,
Ian Rogersd582fa42014-11-05 23:46:43 -0800473 sp_temps,
474 fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
buzbee091cc402014-03-31 10:14:40 -0700475
476 // Target-specific adjustments.
477
478 // Alias single precision floats to appropriate half of overlapping double.
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100479 for (RegisterInfo* info : reg_pool_->sp_regs_) {
buzbee091cc402014-03-31 10:14:40 -0700480 int sp_reg_num = info->GetReg().GetRegNum();
Ian Rogersd582fa42014-11-05 23:46:43 -0800481 int dp_reg_num;
482 if (fpu_is_32bit) {
483 dp_reg_num = sp_reg_num & ~1;
484 } else {
485 dp_reg_num = sp_reg_num >> 1;
486 }
buzbee091cc402014-03-31 10:14:40 -0700487 RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
488 RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
489 // Double precision register's master storage should refer to itself.
490 DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
491 // Redirect single precision's master storage to master.
492 info->SetMaster(dp_reg_info);
493 // Singles should show a single 32-bit mask bit, at first referring to the low half.
494 DCHECK_EQ(info->StorageMask(), 0x1U);
495 if (sp_reg_num & 1) {
496 // For odd singles, change to user the high word of the backing double.
497 info->SetStorageMask(0x2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700499 }
buzbee091cc402014-03-31 10:14:40 -0700500
501 // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
502 // TODO: adjust when we roll to hard float calling convention.
503 reg_pool_->next_core_reg_ = 2;
504 reg_pool_->next_sp_reg_ = 2;
Ian Rogersd582fa42014-11-05 23:46:43 -0800505 if (fpu_is_32bit) {
506 reg_pool_->next_dp_reg_ = 2;
507 } else {
508 reg_pool_->next_dp_reg_ = 1;
509 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510}
511
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512/*
513 * In the Arm code a it is typical to use the link register
514 * to hold the target address. However, for Mips we must
515 * ensure that all branch instructions can be restarted if
516 * there is a trap in the shadow. Allocate a temp register.
517 */
Andreas Gampe98430592014-07-27 19:44:50 -0700518RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
buzbee695d13a2014-04-19 13:32:20 -0700519 // NOTE: native pointer.
Andreas Gampe98430592014-07-27 19:44:50 -0700520 LoadWordDisp(rs_rMIPS_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rT9);
buzbee2700f7e2014-03-07 09:46:20 -0800521 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522}
523
Dave Allisonb373e092014-02-20 16:06:36 -0800524LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800525 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700526 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700527 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800528 LIR *inst = LoadWordDisp(tmp, 0, tmp);
529 FreeTemp(tmp);
530 return inst;
531}
532
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700533LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
534 DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadStore().
535 DCHECK(r_dest.IsPair());
536 ClobberCallerSave();
537 LockCallTemps(); // Using fixed registers
538 RegStorage reg_ptr = TargetReg(kArg0);
539 OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
Andreas Gampe98430592014-07-27 19:44:50 -0700540 RegStorage r_tgt = LoadHelper(kQuickA64Load);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700541 LIR *ret = OpReg(kOpBlx, r_tgt);
542 RegStorage reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
543 OpRegCopyWide(r_dest, reg_ret);
544 return ret;
545}
546
547LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
548 DCHECK(!r_src.IsFloat()); // See RegClassForFieldLoadStore().
549 DCHECK(r_src.IsPair());
550 ClobberCallerSave();
551 LockCallTemps(); // Using fixed registers
552 RegStorage temp_ptr = AllocTemp();
553 OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
554 RegStorage temp_value = AllocTempWide();
555 OpRegCopyWide(temp_value, r_src);
556 RegStorage reg_ptr = TargetReg(kArg0);
557 OpRegCopy(reg_ptr, temp_ptr);
558 RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
559 OpRegCopyWide(reg_value, temp_value);
560 FreeTemp(temp_ptr);
561 FreeTemp(temp_value);
Andreas Gampe98430592014-07-27 19:44:50 -0700562 RegStorage r_tgt = LoadHelper(kQuickA64Store);
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700563 return OpReg(kOpBlx, r_tgt);
564}
565
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700566void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 if (num_core_spills_ == 0) {
568 return;
569 }
570 uint32_t mask = core_spill_mask_;
571 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800572 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700573 for (int reg = 0; mask; mask >>= 1, reg++) {
574 if (mask & 0x1) {
575 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700576 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 }
578 }
579}
580
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700581void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 if (num_core_spills_ == 0) {
583 return;
584 }
585 uint32_t mask = core_spill_mask_;
586 int offset = frame_size_;
587 for (int reg = 0; mask; mask >>= 1, reg++) {
588 if (mask & 0x1) {
589 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700590 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700591 }
592 }
buzbee2700f7e2014-03-07 09:46:20 -0800593 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594}
595
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700596bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 return (lir->opcode == kMipsB);
598}
599
Vladimir Marko674744e2014-04-24 15:18:26 +0100600RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700601 if (UNLIKELY(is_volatile)) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700602 // On Mips, atomic 64-bit load/store requires a core register.
Douglas Leung2db3e262014-06-25 16:02:55 -0700603 // Smaller aligned load/store is atomic for both core and fp registers.
604 if (size == k64 || size == kDouble) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700605 return kCoreReg;
Douglas Leung2db3e262014-06-25 16:02:55 -0700606 }
607 }
Vladimir Marko674744e2014-04-24 15:18:26 +0100608 // TODO: Verify that both core and fp registers are suitable for smaller sizes.
609 return RegClassBySize(size);
610}
611
Brian Carlstrom7940e442013-07-12 13:46:57 -0700612MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
Serguei Katkov717a3e42014-11-13 17:19:42 +0600613 : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614 for (int i = 0; i < kMipsLast; i++) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700615 DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
616 << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
617 << " is wrong: expecting " << i << ", seeing "
618 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700619 }
620}
621
622Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
623 ArenaAllocator* const arena) {
624 return new MipsMir2Lir(cu, mir_graph, arena);
625}
626
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700627uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700628 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700629 return MipsMir2Lir::EncodingMap[opcode].flags;
630}
631
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700632const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700633 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700634 return MipsMir2Lir::EncodingMap[opcode].name;
635}
636
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700637const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700638 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639 return MipsMir2Lir::EncodingMap[opcode].fmt;
640}
641
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700642} // namespace art