blob: 224e8f21f265fcdfbea4dcd5cda1df47feeb9847 [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
29static int core_regs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
30 r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
31 r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
32 r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
33static int ReservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
34 r_RA};
35static int core_temps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
36 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8};
37static int FpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
38 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
39static int fp_temps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
40 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
41
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070042RegLocation MipsMir2Lir::LocCReturn() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000043 RegLocation res = MIPS_LOC_C_RETURN;
44 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070045}
46
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070047RegLocation MipsMir2Lir::LocCReturnWide() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000048 RegLocation res = MIPS_LOC_C_RETURN_WIDE;
49 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070050}
51
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070052RegLocation MipsMir2Lir::LocCReturnFloat() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000053 RegLocation res = MIPS_LOC_C_RETURN_FLOAT;
54 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070055}
56
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070057RegLocation MipsMir2Lir::LocCReturnDouble() {
Bill Buzbee86ec5202014-02-26 19:03:09 +000058 RegLocation res = MIPS_LOC_C_RETURN_DOUBLE;
59 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -070060}
61
62// Return a target-dependent special register.
63int MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
64 int res = INVALID_REG;
65 switch (reg) {
66 case kSelf: res = rMIPS_SELF; break;
67 case kSuspend: res = rMIPS_SUSPEND; break;
68 case kLr: res = rMIPS_LR; break;
69 case kPc: res = rMIPS_PC; break;
70 case kSp: res = rMIPS_SP; break;
71 case kArg0: res = rMIPS_ARG0; break;
72 case kArg1: res = rMIPS_ARG1; break;
73 case kArg2: res = rMIPS_ARG2; break;
74 case kArg3: res = rMIPS_ARG3; break;
75 case kFArg0: res = rMIPS_FARG0; break;
76 case kFArg1: res = rMIPS_FARG1; break;
77 case kFArg2: res = rMIPS_FARG2; break;
78 case kFArg3: res = rMIPS_FARG3; break;
79 case kRet0: res = rMIPS_RET0; break;
80 case kRet1: res = rMIPS_RET1; break;
81 case kInvokeTgt: res = rMIPS_INVOKE_TGT; break;
Jeff Hao88474b42013-10-23 16:24:40 -070082 case kHiddenArg: res = r_T0; break;
83 case kHiddenFpArg: res = INVALID_REG; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070084 case kCount: res = rMIPS_COUNT; break;
85 }
86 return res;
87}
88
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080089int MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
90 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
91 switch (arg_num) {
92 case 0:
93 return rMIPS_ARG1;
94 case 1:
95 return rMIPS_ARG2;
96 case 2:
97 return rMIPS_ARG3;
98 default:
99 return INVALID_REG;
100 }
101}
102
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700104int MipsMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700105 return MIPS_S2D(low_reg, high_reg);
106}
107
108// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700109uint32_t MipsMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110 return MIPS_FP_REG_MASK;
111}
112
113// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700114bool MipsMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
116}
117
118/*
119 * Decode the register id.
120 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700121uint64_t MipsMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 uint64_t seed;
123 int shift;
124 int reg_id;
125
126
127 reg_id = reg & 0x1f;
128 /* Each double register is equal to a pair of single-precision FP registers */
129 seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
130 /* FP register starts at bit position 16 */
131 shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
132 /* Expand the double register id into single offset */
133 shift += reg_id;
134 return (seed << shift);
135}
136
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700137uint64_t MipsMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 return ENCODE_MIPS_REG_PC;
139}
140
141
buzbeeb48819d2013-09-14 16:15:25 -0700142void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700144 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700145
146 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147 if (flags & REG_DEF_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700148 lir->u.m.def_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 }
150
151 if (flags & REG_USE_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700152 lir->u.m.use_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 }
154
155 if (flags & REG_DEF_LR) {
buzbeeb48819d2013-09-14 16:15:25 -0700156 lir->u.m.def_mask |= ENCODE_MIPS_REG_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 }
158}
159
160/* For dumping instructions */
161#define MIPS_REG_COUNT 32
162static const char *mips_reg_name[MIPS_REG_COUNT] = {
163 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
164 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
165 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
166 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
167};
168
169/*
170 * Interpret a format string and build a string no longer than size
171 * See format key in Assemble.c.
172 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700173std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 std::string buf;
175 int i;
176 const char *fmt_end = &fmt[strlen(fmt)];
177 char tbuf[256];
178 char nc;
179 while (fmt < fmt_end) {
180 int operand;
181 if (*fmt == '!') {
182 fmt++;
183 DCHECK_LT(fmt, fmt_end);
184 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700185 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700186 strcpy(tbuf, "!");
187 } else {
188 DCHECK_LT(fmt, fmt_end);
189 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
190 operand = lir->operands[nc-'0'];
191 switch (*fmt++) {
192 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700193 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700194 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700195 tbuf[i] += operand & 1;
196 operand >>= 1;
197 }
198 break;
199 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800200 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 break;
202 case 'S':
203 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800204 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 break;
206 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800207 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 break;
209 case 'M':
210 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800211 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 break;
213 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800214 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 break;
216 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800217 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 break;
219 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800220 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221 break;
222 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800223 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
224 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
225 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700226 break;
227 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800228 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700229 break;
230 case 'u': {
231 int offset_1 = lir->operands[0];
232 int offset_2 = NEXT_LIR(lir)->operands[0];
233 uintptr_t target =
234 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
235 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800236 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 break;
238 }
239
240 /* Nothing to print for BLX_2 */
241 case 'v':
242 strcpy(tbuf, "see above");
243 break;
244 case 'r':
245 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
246 strcpy(tbuf, mips_reg_name[operand]);
247 break;
248 case 'N':
249 // Placeholder for delay slot handling
250 strcpy(tbuf, "; nop");
251 break;
252 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700253 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 break;
255 }
256 buf += tbuf;
257 }
258 } else {
259 buf += *fmt++;
260 }
261 }
262 return buf;
263}
264
265// FIXME: need to redo resource maps for MIPS - fix this at that time
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700266void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700267 char buf[256];
268 buf[0] = 0;
269
270 if (mask == ENCODE_ALL) {
271 strcpy(buf, "all");
272 } else {
273 char num[8];
274 int i;
275
276 for (i = 0; i < kMipsRegEnd; i++) {
277 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800278 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 strcat(buf, num);
280 }
281 }
282
283 if (mask & ENCODE_CCODE) {
284 strcat(buf, "cc ");
285 }
286 if (mask & ENCODE_FP_STATUS) {
287 strcat(buf, "fpcc ");
288 }
289 /* Memory bits */
290 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800291 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
292 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
293 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700294 }
295 if (mask & ENCODE_LITERAL) {
296 strcat(buf, "lit ");
297 }
298
299 if (mask & ENCODE_HEAP_REF) {
300 strcat(buf, "heap ");
301 }
302 if (mask & ENCODE_MUST_NOT_ALIAS) {
303 strcat(buf, "noalias ");
304 }
305 }
306 if (buf[0]) {
307 LOG(INFO) << prefix << ": " << buf;
308 }
309}
310
311/*
312 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
313 * instructions might call out to C/assembly helper functions. Until
314 * machinery is in place, always spill lr.
315 */
316
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700317void MipsMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700318 core_spill_mask_ |= (1 << r_RA);
319 num_core_spills_++;
320}
321
322/*
323 * Mark a callee-save fp register as promoted. Note that
324 * vpush/vpop uses contiguous register lists so we must
325 * include any holes in the mask. Associate holes with
326 * Dalvik register INVALID_VREG (0xFFFFU).
327 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700328void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 LOG(FATAL) << "No support yet for promoted FP regs";
330}
331
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700332void MipsMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700333 RegisterInfo* info1 = GetRegInfo(reg1);
334 RegisterInfo* info2 = GetRegInfo(reg2);
335 DCHECK(info1 && info2 && info1->pair && info2->pair &&
336 (info1->partner == info2->reg) &&
337 (info2->partner == info1->reg));
338 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
339 if (!(info1->is_temp && info2->is_temp)) {
340 /* Should not happen. If it does, there's a problem in eval_loc */
341 LOG(FATAL) << "Long half-temp, half-promoted";
342 }
343
344 info1->dirty = false;
345 info2->dirty = false;
346 if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
347 info1 = info2;
348 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
349 StoreBaseDispWide(rMIPS_SP, VRegOffset(v_reg), info1->reg, info1->partner);
350 }
351}
352
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700353void MipsMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 RegisterInfo* info = GetRegInfo(reg);
355 if (info->live && info->dirty) {
356 info->dirty = false;
357 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
358 StoreBaseDisp(rMIPS_SP, VRegOffset(v_reg), reg, kWord);
359 }
360}
361
362/* Give access to the target-dependent FP register encoding to common code */
363bool MipsMir2Lir::IsFpReg(int reg) {
364 return MIPS_FPREG(reg);
365}
366
367/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000368void MipsMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700369 Clobber(r_ZERO);
370 Clobber(r_AT);
371 Clobber(r_V0);
372 Clobber(r_V1);
373 Clobber(r_A0);
374 Clobber(r_A1);
375 Clobber(r_A2);
376 Clobber(r_A3);
377 Clobber(r_T0);
378 Clobber(r_T1);
379 Clobber(r_T2);
380 Clobber(r_T3);
381 Clobber(r_T4);
382 Clobber(r_T5);
383 Clobber(r_T6);
384 Clobber(r_T7);
385 Clobber(r_T8);
386 Clobber(r_T9);
387 Clobber(r_K0);
388 Clobber(r_K1);
389 Clobber(r_GP);
390 Clobber(r_FP);
391 Clobber(r_RA);
392 Clobber(r_F0);
393 Clobber(r_F1);
394 Clobber(r_F2);
395 Clobber(r_F3);
396 Clobber(r_F4);
397 Clobber(r_F5);
398 Clobber(r_F6);
399 Clobber(r_F7);
400 Clobber(r_F8);
401 Clobber(r_F9);
402 Clobber(r_F10);
403 Clobber(r_F11);
404 Clobber(r_F12);
405 Clobber(r_F13);
406 Clobber(r_F14);
407 Clobber(r_F15);
408}
409
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700410RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700411 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
412 RegLocation res = LocCReturnWide();
413 return res;
414}
415
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700416RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
418 RegLocation res = LocCReturn();
419 return res;
420}
421
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700423void MipsMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 LockTemp(rMIPS_ARG0);
425 LockTemp(rMIPS_ARG1);
426 LockTemp(rMIPS_ARG2);
427 LockTemp(rMIPS_ARG3);
428}
429
430/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700431void MipsMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 FreeTemp(rMIPS_ARG0);
433 FreeTemp(rMIPS_ARG1);
434 FreeTemp(rMIPS_ARG2);
435 FreeTemp(rMIPS_ARG3);
436}
437
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700438void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439#if ANDROID_SMP != 0
440 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
441#endif
442}
443
Bill Buzbee86ec5202014-02-26 19:03:09 +0000444/*
445 * Alloc a pair of core registers, or a double. Low reg in low byte,
446 * high reg in next byte.
447 */
448int MipsMir2Lir::AllocTypedTempPair(bool fp_hint,
449 int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 int high_reg;
451 int low_reg;
Bill Buzbee86ec5202014-02-26 19:03:09 +0000452 int res = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453
454 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
455 low_reg = AllocTempDouble();
456 high_reg = low_reg + 1;
Bill Buzbee86ec5202014-02-26 19:03:09 +0000457 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
458 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 }
460
461 low_reg = AllocTemp();
462 high_reg = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000463 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
464 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465}
466
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700467int MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
468 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 return AllocTempFloat();
470}
471 return AllocTemp();
472}
473
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700474void MipsMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
476 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
477 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
478 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
479 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700480 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
481 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482 reg_pool_->num_core_regs = num_regs;
483 reg_pool_->core_regs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700484 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700485 reg_pool_->num_fp_regs = num_fp_regs;
486 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700487 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700488 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
489 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
490 // Keep special registers from being allocated
491 for (int i = 0; i < num_reserved; i++) {
492 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700493 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 continue;
495 }
496 MarkInUse(ReservedRegs[i]);
497 }
498 // Mark temp regs - all others not in use can be used for promotion
499 for (int i = 0; i < num_temps; i++) {
500 MarkTemp(core_temps[i]);
501 }
502 for (int i = 0; i < num_fp_temps; i++) {
503 MarkTemp(fp_temps[i]);
504 }
505}
506
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700507void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000508 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
509 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 // No overlap, free both
Bill Buzbee86ec5202014-02-26 19:03:09 +0000511 FreeTemp(rl_free.low_reg);
512 FreeTemp(rl_free.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 }
514}
515/*
516 * In the Arm code a it is typical to use the link register
517 * to hold the target address. However, for Mips we must
518 * ensure that all branch instructions can be restarted if
519 * there is a trap in the shadow. Allocate a temp register.
520 */
Ian Rogers468532e2013-08-05 10:56:33 -0700521int MipsMir2Lir::LoadHelper(ThreadOffset offset) {
522 LoadWordDisp(rMIPS_SELF, offset.Int32Value(), r_T9);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700523 return r_T9;
524}
525
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700526void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 if (num_core_spills_ == 0) {
528 return;
529 }
530 uint32_t mask = core_spill_mask_;
531 int offset = num_core_spills_ * 4;
532 OpRegImm(kOpSub, rMIPS_SP, offset);
533 for (int reg = 0; mask; mask >>= 1, reg++) {
534 if (mask & 0x1) {
535 offset -= 4;
536 StoreWordDisp(rMIPS_SP, offset, reg);
537 }
538 }
539}
540
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700541void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700542 if (num_core_spills_ == 0) {
543 return;
544 }
545 uint32_t mask = core_spill_mask_;
546 int offset = frame_size_;
547 for (int reg = 0; mask; mask >>= 1, reg++) {
548 if (mask & 0x1) {
549 offset -= 4;
550 LoadWordDisp(rMIPS_SP, offset, reg);
551 }
552 }
553 OpRegImm(kOpAdd, rMIPS_SP, frame_size_);
554}
555
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700556bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700557 return (lir->opcode == kMipsB);
558}
559
560MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
561 : Mir2Lir(cu, mir_graph, arena) {
562 for (int i = 0; i < kMipsLast; i++) {
563 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
564 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
565 << " is wrong: expecting " << i << ", seeing "
566 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
567 }
568 }
569}
570
571Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
572 ArenaAllocator* const arena) {
573 return new MipsMir2Lir(cu, mir_graph, arena);
574}
575
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700576uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700577 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578 return MipsMir2Lir::EncodingMap[opcode].flags;
579}
580
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700581const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700582 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700583 return MipsMir2Lir::EncodingMap[opcode].name;
584}
585
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700586const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700587 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588 return MipsMir2Lir::EncodingMap[opcode].fmt;
589}
590
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700591} // namespace art