blob: 7f4cd5e242479f7aff8e8ec5a58cf7d4fa9f4b48 [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
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25#include "mips_lir.h"
26
Brian Carlstrom7940e442013-07-12 13:46:57 -070027namespace art {
28
buzbee2700f7e2014-03-07 09:46:20 -080029static int core_regs[] = {rZERO, rAT, rV0, rV1, rA0, rA1, rA2, rA3,
30 rT0, rT1, rT2, rT3, rT4, rT5, rT6, rT7,
31 rS0, rS1, rS2, rS3, rS4, rS5, rS6, rS7, rT8,
32 rT9, rK0, rK1, rGP, rSP, rFP, rRA};
33static int ReservedRegs[] = {rZERO, rAT, rS0, rS1, rK0, rK1, rGP, rSP,
34 rRA};
35static int core_temps[] = {rV0, rV1, rA0, rA1, rA2, rA3, rT0, rT1, rT2,
36 rT3, rT4, rT5, rT6, rT7, rT8};
37static int FpRegs[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
38 rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
39static int fp_temps[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
40 rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
Brian Carlstrom7940e442013-07-12 13:46:57 -070041
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070042RegLocation MipsMir2Lir::LocCReturn() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000043 return mips_loc_c_return;
Brian Carlstrom7940e442013-07-12 13:46:57 -070044}
45
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070046RegLocation MipsMir2Lir::LocCReturnWide() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000047 return mips_loc_c_return_wide;
Brian Carlstrom7940e442013-07-12 13:46:57 -070048}
49
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070050RegLocation MipsMir2Lir::LocCReturnFloat() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000051 return mips_loc_c_return_float;
Brian Carlstrom7940e442013-07-12 13:46:57 -070052}
53
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070054RegLocation MipsMir2Lir::LocCReturnDouble() {
Bill Buzbee00e1ec62014-02-27 23:44:13 +000055 return mips_loc_c_return_double;
Brian Carlstrom7940e442013-07-12 13:46:57 -070056}
57
58// Return a target-dependent special register.
buzbee2700f7e2014-03-07 09:46:20 -080059RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
60 int res_reg = RegStorage::kInvalidRegVal;
Brian Carlstrom7940e442013-07-12 13:46:57 -070061 switch (reg) {
buzbee2700f7e2014-03-07 09:46:20 -080062 case kSelf: res_reg = rMIPS_SELF; break;
63 case kSuspend: res_reg = rMIPS_SUSPEND; break;
64 case kLr: res_reg = rMIPS_LR; break;
65 case kPc: res_reg = rMIPS_PC; break;
66 case kSp: res_reg = rMIPS_SP; break;
67 case kArg0: res_reg = rMIPS_ARG0; break;
68 case kArg1: res_reg = rMIPS_ARG1; break;
69 case kArg2: res_reg = rMIPS_ARG2; break;
70 case kArg3: res_reg = rMIPS_ARG3; break;
71 case kFArg0: res_reg = rMIPS_FARG0; break;
72 case kFArg1: res_reg = rMIPS_FARG1; break;
73 case kFArg2: res_reg = rMIPS_FARG2; break;
74 case kFArg3: res_reg = rMIPS_FARG3; break;
75 case kRet0: res_reg = rMIPS_RET0; break;
76 case kRet1: res_reg = rMIPS_RET1; break;
77 case kInvokeTgt: res_reg = rMIPS_INVOKE_TGT; break;
78 case kHiddenArg: res_reg = rT0; break;
79 case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
80 case kCount: res_reg = rMIPS_COUNT; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 }
buzbee2700f7e2014-03-07 09:46:20 -080082 return RegStorage::Solo32(res_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070083}
84
buzbee2700f7e2014-03-07 09:46:20 -080085RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080086 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
87 switch (arg_num) {
88 case 0:
buzbee2700f7e2014-03-07 09:46:20 -080089 return rs_rMIPS_ARG1;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080090 case 1:
buzbee2700f7e2014-03-07 09:46:20 -080091 return rs_rMIPS_ARG2;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080092 case 2:
buzbee2700f7e2014-03-07 09:46:20 -080093 return rs_rMIPS_ARG3;
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080094 default:
buzbee2700f7e2014-03-07 09:46:20 -080095 return RegStorage::InvalidReg();
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080096 }
97}
98
Brian Carlstrom7940e442013-07-12 13:46:57 -070099// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700100int MipsMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700101 return MIPS_S2D(low_reg, high_reg);
102}
103
104// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700105uint32_t MipsMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106 return MIPS_FP_REG_MASK;
107}
108
109// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700110bool MipsMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
112}
113
114/*
115 * Decode the register id.
116 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700117uint64_t MipsMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118 uint64_t seed;
119 int shift;
120 int reg_id;
121
122
123 reg_id = reg & 0x1f;
124 /* Each double register is equal to a pair of single-precision FP registers */
125 seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
126 /* FP register starts at bit position 16 */
127 shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
128 /* Expand the double register id into single offset */
129 shift += reg_id;
130 return (seed << shift);
131}
132
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700133uint64_t MipsMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 return ENCODE_MIPS_REG_PC;
135}
136
137
buzbeeb48819d2013-09-14 16:15:25 -0700138void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700140 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700141
142 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 if (flags & REG_DEF_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700144 lir->u.m.def_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700145 }
146
147 if (flags & REG_USE_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700148 lir->u.m.use_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 }
150
151 if (flags & REG_DEF_LR) {
buzbeeb48819d2013-09-14 16:15:25 -0700152 lir->u.m.def_mask |= ENCODE_MIPS_REG_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 }
buzbee9da5c102014-03-28 12:59:18 -0700154
155 if (flags & REG_DEF_HI) {
156 lir->u.m.def_mask |= ENCODE_MIPS_REG_HI;
157 }
158
159 if (flags & REG_DEF_LO) {
160 lir->u.m.def_mask |= ENCODE_MIPS_REG_LO;
161 }
162
163 if (flags & REG_USE_HI) {
164 lir->u.m.use_mask |= ENCODE_MIPS_REG_HI;
165 }
166
167 if (flags & REG_USE_LO) {
168 lir->u.m.use_mask |= ENCODE_MIPS_REG_LO;
169 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170}
171
172/* For dumping instructions */
173#define MIPS_REG_COUNT 32
174static const char *mips_reg_name[MIPS_REG_COUNT] = {
175 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
176 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
177 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
178 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
179};
180
181/*
182 * Interpret a format string and build a string no longer than size
183 * See format key in Assemble.c.
184 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700185std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700186 std::string buf;
187 int i;
188 const char *fmt_end = &fmt[strlen(fmt)];
189 char tbuf[256];
190 char nc;
191 while (fmt < fmt_end) {
192 int operand;
193 if (*fmt == '!') {
194 fmt++;
195 DCHECK_LT(fmt, fmt_end);
196 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700197 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 strcpy(tbuf, "!");
199 } else {
200 DCHECK_LT(fmt, fmt_end);
201 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
202 operand = lir->operands[nc-'0'];
203 switch (*fmt++) {
204 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700205 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700206 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700207 tbuf[i] += operand & 1;
208 operand >>= 1;
209 }
210 break;
211 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800212 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700213 break;
214 case 'S':
215 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800216 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 break;
218 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800219 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 break;
221 case 'M':
222 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800223 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 break;
225 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800226 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 break;
228 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800229 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 break;
231 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800232 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 break;
234 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800235 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
236 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
237 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700238 break;
239 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800240 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 break;
242 case 'u': {
243 int offset_1 = lir->operands[0];
244 int offset_2 = NEXT_LIR(lir)->operands[0];
245 uintptr_t target =
246 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
247 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800248 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700249 break;
250 }
251
252 /* Nothing to print for BLX_2 */
253 case 'v':
254 strcpy(tbuf, "see above");
255 break;
256 case 'r':
257 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
258 strcpy(tbuf, mips_reg_name[operand]);
259 break;
260 case 'N':
261 // Placeholder for delay slot handling
262 strcpy(tbuf, "; nop");
263 break;
264 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700265 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700266 break;
267 }
268 buf += tbuf;
269 }
270 } else {
271 buf += *fmt++;
272 }
273 }
274 return buf;
275}
276
277// FIXME: need to redo resource maps for MIPS - fix this at that time
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700278void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 char buf[256];
280 buf[0] = 0;
281
282 if (mask == ENCODE_ALL) {
283 strcpy(buf, "all");
284 } else {
285 char num[8];
286 int i;
287
288 for (i = 0; i < kMipsRegEnd; i++) {
289 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800290 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 strcat(buf, num);
292 }
293 }
294
295 if (mask & ENCODE_CCODE) {
296 strcat(buf, "cc ");
297 }
298 if (mask & ENCODE_FP_STATUS) {
299 strcat(buf, "fpcc ");
300 }
301 /* Memory bits */
302 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800303 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
304 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
305 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 }
307 if (mask & ENCODE_LITERAL) {
308 strcat(buf, "lit ");
309 }
310
311 if (mask & ENCODE_HEAP_REF) {
312 strcat(buf, "heap ");
313 }
314 if (mask & ENCODE_MUST_NOT_ALIAS) {
315 strcat(buf, "noalias ");
316 }
317 }
318 if (buf[0]) {
319 LOG(INFO) << prefix << ": " << buf;
320 }
321}
322
323/*
324 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
325 * instructions might call out to C/assembly helper functions. Until
326 * machinery is in place, always spill lr.
327 */
328
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700329void MipsMir2Lir::AdjustSpillMask() {
buzbee2700f7e2014-03-07 09:46:20 -0800330 core_spill_mask_ |= (1 << rRA);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 num_core_spills_++;
332}
333
334/*
335 * Mark a callee-save fp register as promoted. Note that
336 * vpush/vpop uses contiguous register lists so we must
337 * include any holes in the mask. Associate holes with
338 * Dalvik register INVALID_VREG (0xFFFFU).
339 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700340void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 LOG(FATAL) << "No support yet for promoted FP regs";
342}
343
buzbee2700f7e2014-03-07 09:46:20 -0800344void MipsMir2Lir::FlushRegWide(RegStorage reg) {
345 RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
346 RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 DCHECK(info1 && info2 && info1->pair && info2->pair &&
348 (info1->partner == info2->reg) &&
349 (info2->partner == info1->reg));
350 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
351 if (!(info1->is_temp && info2->is_temp)) {
352 /* Should not happen. If it does, there's a problem in eval_loc */
353 LOG(FATAL) << "Long half-temp, half-promoted";
354 }
355
356 info1->dirty = false;
357 info2->dirty = false;
358 if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
359 info1 = info2;
360 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
buzbee2700f7e2014-03-07 09:46:20 -0800361 StoreBaseDispWide(rs_rMIPS_SP, VRegOffset(v_reg),
362 RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 }
364}
365
buzbee2700f7e2014-03-07 09:46:20 -0800366void MipsMir2Lir::FlushReg(RegStorage reg) {
367 DCHECK(!reg.IsPair());
368 RegisterInfo* info = GetRegInfo(reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700369 if (info->live && info->dirty) {
370 info->dirty = false;
371 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
buzbee695d13a2014-04-19 13:32:20 -0700372 Store32Disp(rs_rMIPS_SP, VRegOffset(v_reg), reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700373 }
374}
375
376/* Give access to the target-dependent FP register encoding to common code */
377bool MipsMir2Lir::IsFpReg(int reg) {
378 return MIPS_FPREG(reg);
379}
380
buzbee2700f7e2014-03-07 09:46:20 -0800381bool MipsMir2Lir::IsFpReg(RegStorage reg) {
382 return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
383}
384
Brian Carlstrom7940e442013-07-12 13:46:57 -0700385/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000386void MipsMir2Lir::ClobberCallerSave() {
buzbee2700f7e2014-03-07 09:46:20 -0800387 Clobber(rZERO);
388 Clobber(rAT);
389 Clobber(rV0);
390 Clobber(rV1);
391 Clobber(rA0);
392 Clobber(rA1);
393 Clobber(rA2);
394 Clobber(rA3);
395 Clobber(rT0);
396 Clobber(rT1);
397 Clobber(rT2);
398 Clobber(rT3);
399 Clobber(rT4);
400 Clobber(rT5);
401 Clobber(rT6);
402 Clobber(rT7);
403 Clobber(rT8);
404 Clobber(rT9);
405 Clobber(rK0);
406 Clobber(rK1);
407 Clobber(rGP);
408 Clobber(rFP);
409 Clobber(rRA);
410 Clobber(rF0);
411 Clobber(rF1);
412 Clobber(rF2);
413 Clobber(rF3);
414 Clobber(rF4);
415 Clobber(rF5);
416 Clobber(rF6);
417 Clobber(rF7);
418 Clobber(rF8);
419 Clobber(rF9);
420 Clobber(rF10);
421 Clobber(rF11);
422 Clobber(rF12);
423 Clobber(rF13);
424 Clobber(rF14);
425 Clobber(rF15);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700426}
427
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700428RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
430 RegLocation res = LocCReturnWide();
431 return res;
432}
433
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700434RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
436 RegLocation res = LocCReturn();
437 return res;
438}
439
Brian Carlstrom7940e442013-07-12 13:46:57 -0700440/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700441void MipsMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 LockTemp(rMIPS_ARG0);
443 LockTemp(rMIPS_ARG1);
444 LockTemp(rMIPS_ARG2);
445 LockTemp(rMIPS_ARG3);
446}
447
448/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700449void MipsMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 FreeTemp(rMIPS_ARG0);
451 FreeTemp(rMIPS_ARG1);
452 FreeTemp(rMIPS_ARG2);
453 FreeTemp(rMIPS_ARG3);
454}
455
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700456void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457#if ANDROID_SMP != 0
458 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
459#endif
460}
461
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000462// Alloc a pair of core registers, or a double.
463RegStorage MipsMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 int high_reg;
465 int low_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466
467 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
buzbee2700f7e2014-03-07 09:46:20 -0800468 return AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 }
470
buzbee2700f7e2014-03-07 09:46:20 -0800471 low_reg = AllocTemp().GetReg();
472 high_reg = AllocTemp().GetReg();
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000473 return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474}
475
buzbee2700f7e2014-03-07 09:46:20 -0800476RegStorage MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700477 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 return AllocTempFloat();
479}
480 return AllocTemp();
481}
482
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700483void MipsMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
485 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
486 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
487 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
488 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700489 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000490 kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 reg_pool_->num_core_regs = num_regs;
492 reg_pool_->core_regs = static_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000493 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 reg_pool_->num_fp_regs = num_fp_regs;
495 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000496 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700497 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
498 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
499 // Keep special registers from being allocated
500 for (int i = 0; i < num_reserved; i++) {
501 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700502 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700503 continue;
504 }
505 MarkInUse(ReservedRegs[i]);
506 }
507 // Mark temp regs - all others not in use can be used for promotion
508 for (int i = 0; i < num_temps; i++) {
509 MarkTemp(core_temps[i]);
510 }
511 for (int i = 0; i < num_fp_temps; i++) {
512 MarkTemp(fp_temps[i]);
513 }
514}
515
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700516void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
buzbee2700f7e2014-03-07 09:46:20 -0800517 DCHECK(rl_keep.wide);
518 DCHECK(rl_free.wide);
519 if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
520 (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
521 (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
522 (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
523 // No overlap, free.
524 FreeTemp(rl_free.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700525 }
526}
527/*
528 * In the Arm code a it is typical to use the link register
529 * to hold the target address. However, for Mips we must
530 * ensure that all branch instructions can be restarted if
531 * there is a trap in the shadow. Allocate a temp register.
532 */
Ian Rogersdd7624d2014-03-14 17:43:00 -0700533RegStorage MipsMir2Lir::LoadHelper(ThreadOffset<4> offset) {
buzbee695d13a2014-04-19 13:32:20 -0700534 // NOTE: native pointer.
buzbee2700f7e2014-03-07 09:46:20 -0800535 LoadWordDisp(rs_rMIPS_SELF, offset.Int32Value(), rs_rT9);
536 return rs_rT9;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537}
538
Dave Allisonb373e092014-02-20 16:06:36 -0800539LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
buzbee2700f7e2014-03-07 09:46:20 -0800540 RegStorage tmp = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700541 // NOTE: native pointer.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700542 LoadWordDisp(rs_rMIPS_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
Dave Allisonb373e092014-02-20 16:06:36 -0800543 LIR *inst = LoadWordDisp(tmp, 0, tmp);
544 FreeTemp(tmp);
545 return inst;
546}
547
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700548void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700549 if (num_core_spills_ == 0) {
550 return;
551 }
552 uint32_t mask = core_spill_mask_;
553 int offset = num_core_spills_ * 4;
buzbee2700f7e2014-03-07 09:46:20 -0800554 OpRegImm(kOpSub, rs_rSP, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700555 for (int reg = 0; mask; mask >>= 1, reg++) {
556 if (mask & 0x1) {
557 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700558 Store32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 }
560 }
561}
562
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700563void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700564 if (num_core_spills_ == 0) {
565 return;
566 }
567 uint32_t mask = core_spill_mask_;
568 int offset = frame_size_;
569 for (int reg = 0; mask; mask >>= 1, reg++) {
570 if (mask & 0x1) {
571 offset -= 4;
buzbee695d13a2014-04-19 13:32:20 -0700572 Load32Disp(rs_rMIPS_SP, offset, RegStorage::Solo32(reg));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700573 }
574 }
buzbee2700f7e2014-03-07 09:46:20 -0800575 OpRegImm(kOpAdd, rs_rSP, frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700576}
577
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700578bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700579 return (lir->opcode == kMipsB);
580}
581
582MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
583 : Mir2Lir(cu, mir_graph, arena) {
584 for (int i = 0; i < kMipsLast; i++) {
585 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
586 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
587 << " is wrong: expecting " << i << ", seeing "
588 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
589 }
590 }
591}
592
593Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
594 ArenaAllocator* const arena) {
595 return new MipsMir2Lir(cu, mir_graph, arena);
596}
597
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700598uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700599 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 return MipsMir2Lir::EncodingMap[opcode].flags;
601}
602
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700603const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700604 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605 return MipsMir2Lir::EncodingMap[opcode].name;
606}
607
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700608const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700609 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700610 return MipsMir2Lir::EncodingMap[opcode].fmt;
611}
612
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700613} // namespace art