blob: b7fb2f45125284b430b180ce35012b455368ee51 [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 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.
59int MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
60 int res = INVALID_REG;
61 switch (reg) {
62 case kSelf: res = rMIPS_SELF; break;
63 case kSuspend: res = rMIPS_SUSPEND; break;
64 case kLr: res = rMIPS_LR; break;
65 case kPc: res = rMIPS_PC; break;
66 case kSp: res = rMIPS_SP; break;
67 case kArg0: res = rMIPS_ARG0; break;
68 case kArg1: res = rMIPS_ARG1; break;
69 case kArg2: res = rMIPS_ARG2; break;
70 case kArg3: res = rMIPS_ARG3; break;
71 case kFArg0: res = rMIPS_FARG0; break;
72 case kFArg1: res = rMIPS_FARG1; break;
73 case kFArg2: res = rMIPS_FARG2; break;
74 case kFArg3: res = rMIPS_FARG3; break;
75 case kRet0: res = rMIPS_RET0; break;
76 case kRet1: res = rMIPS_RET1; break;
77 case kInvokeTgt: res = rMIPS_INVOKE_TGT; break;
Jeff Hao88474b42013-10-23 16:24:40 -070078 case kHiddenArg: res = r_T0; break;
79 case kHiddenFpArg: res = INVALID_REG; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 case kCount: res = rMIPS_COUNT; break;
81 }
82 return res;
83}
84
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -080085int MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
86 // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
87 switch (arg_num) {
88 case 0:
89 return rMIPS_ARG1;
90 case 1:
91 return rMIPS_ARG2;
92 case 2:
93 return rMIPS_ARG3;
94 default:
95 return INVALID_REG;
96 }
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 }
154}
155
156/* For dumping instructions */
157#define MIPS_REG_COUNT 32
158static const char *mips_reg_name[MIPS_REG_COUNT] = {
159 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
160 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
161 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
162 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
163};
164
165/*
166 * Interpret a format string and build a string no longer than size
167 * See format key in Assemble.c.
168 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700169std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170 std::string buf;
171 int i;
172 const char *fmt_end = &fmt[strlen(fmt)];
173 char tbuf[256];
174 char nc;
175 while (fmt < fmt_end) {
176 int operand;
177 if (*fmt == '!') {
178 fmt++;
179 DCHECK_LT(fmt, fmt_end);
180 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700181 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700182 strcpy(tbuf, "!");
183 } else {
184 DCHECK_LT(fmt, fmt_end);
185 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
186 operand = lir->operands[nc-'0'];
187 switch (*fmt++) {
188 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700189 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700190 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700191 tbuf[i] += operand & 1;
192 operand >>= 1;
193 }
194 break;
195 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800196 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 break;
198 case 'S':
199 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
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 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800203 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 break;
205 case 'M':
206 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800207 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 break;
209 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800210 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700211 break;
212 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800213 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 break;
215 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800216 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 break;
218 case 't':
Ian Rogers107c31e2014-01-23 20:55:29 -0800219 snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
220 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
221 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222 break;
223 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800224 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700225 break;
226 case 'u': {
227 int offset_1 = lir->operands[0];
228 int offset_2 = NEXT_LIR(lir)->operands[0];
229 uintptr_t target =
230 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
231 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800232 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 break;
234 }
235
236 /* Nothing to print for BLX_2 */
237 case 'v':
238 strcpy(tbuf, "see above");
239 break;
240 case 'r':
241 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
242 strcpy(tbuf, mips_reg_name[operand]);
243 break;
244 case 'N':
245 // Placeholder for delay slot handling
246 strcpy(tbuf, "; nop");
247 break;
248 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700249 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 break;
251 }
252 buf += tbuf;
253 }
254 } else {
255 buf += *fmt++;
256 }
257 }
258 return buf;
259}
260
261// FIXME: need to redo resource maps for MIPS - fix this at that time
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700262void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700263 char buf[256];
264 buf[0] = 0;
265
266 if (mask == ENCODE_ALL) {
267 strcpy(buf, "all");
268 } else {
269 char num[8];
270 int i;
271
272 for (i = 0; i < kMipsRegEnd; i++) {
273 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800274 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 strcat(buf, num);
276 }
277 }
278
279 if (mask & ENCODE_CCODE) {
280 strcat(buf, "cc ");
281 }
282 if (mask & ENCODE_FP_STATUS) {
283 strcat(buf, "fpcc ");
284 }
285 /* Memory bits */
286 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800287 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
288 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
289 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 }
291 if (mask & ENCODE_LITERAL) {
292 strcat(buf, "lit ");
293 }
294
295 if (mask & ENCODE_HEAP_REF) {
296 strcat(buf, "heap ");
297 }
298 if (mask & ENCODE_MUST_NOT_ALIAS) {
299 strcat(buf, "noalias ");
300 }
301 }
302 if (buf[0]) {
303 LOG(INFO) << prefix << ": " << buf;
304 }
305}
306
307/*
308 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
309 * instructions might call out to C/assembly helper functions. Until
310 * machinery is in place, always spill lr.
311 */
312
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700313void MipsMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 core_spill_mask_ |= (1 << r_RA);
315 num_core_spills_++;
316}
317
318/*
319 * Mark a callee-save fp register as promoted. Note that
320 * vpush/vpop uses contiguous register lists so we must
321 * include any holes in the mask. Associate holes with
322 * Dalvik register INVALID_VREG (0xFFFFU).
323 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700324void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 LOG(FATAL) << "No support yet for promoted FP regs";
326}
327
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700328void MipsMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 RegisterInfo* info1 = GetRegInfo(reg1);
330 RegisterInfo* info2 = GetRegInfo(reg2);
331 DCHECK(info1 && info2 && info1->pair && info2->pair &&
332 (info1->partner == info2->reg) &&
333 (info2->partner == info1->reg));
334 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
335 if (!(info1->is_temp && info2->is_temp)) {
336 /* Should not happen. If it does, there's a problem in eval_loc */
337 LOG(FATAL) << "Long half-temp, half-promoted";
338 }
339
340 info1->dirty = false;
341 info2->dirty = false;
342 if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
343 info1 = info2;
344 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
345 StoreBaseDispWide(rMIPS_SP, VRegOffset(v_reg), info1->reg, info1->partner);
346 }
347}
348
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700349void MipsMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 RegisterInfo* info = GetRegInfo(reg);
351 if (info->live && info->dirty) {
352 info->dirty = false;
353 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
354 StoreBaseDisp(rMIPS_SP, VRegOffset(v_reg), reg, kWord);
355 }
356}
357
358/* Give access to the target-dependent FP register encoding to common code */
359bool MipsMir2Lir::IsFpReg(int reg) {
360 return MIPS_FPREG(reg);
361}
362
363/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000364void MipsMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 Clobber(r_ZERO);
366 Clobber(r_AT);
367 Clobber(r_V0);
368 Clobber(r_V1);
369 Clobber(r_A0);
370 Clobber(r_A1);
371 Clobber(r_A2);
372 Clobber(r_A3);
373 Clobber(r_T0);
374 Clobber(r_T1);
375 Clobber(r_T2);
376 Clobber(r_T3);
377 Clobber(r_T4);
378 Clobber(r_T5);
379 Clobber(r_T6);
380 Clobber(r_T7);
381 Clobber(r_T8);
382 Clobber(r_T9);
383 Clobber(r_K0);
384 Clobber(r_K1);
385 Clobber(r_GP);
386 Clobber(r_FP);
387 Clobber(r_RA);
388 Clobber(r_F0);
389 Clobber(r_F1);
390 Clobber(r_F2);
391 Clobber(r_F3);
392 Clobber(r_F4);
393 Clobber(r_F5);
394 Clobber(r_F6);
395 Clobber(r_F7);
396 Clobber(r_F8);
397 Clobber(r_F9);
398 Clobber(r_F10);
399 Clobber(r_F11);
400 Clobber(r_F12);
401 Clobber(r_F13);
402 Clobber(r_F14);
403 Clobber(r_F15);
404}
405
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700406RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
408 RegLocation res = LocCReturnWide();
409 return res;
410}
411
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700412RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
414 RegLocation res = LocCReturn();
415 return res;
416}
417
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700419void MipsMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 LockTemp(rMIPS_ARG0);
421 LockTemp(rMIPS_ARG1);
422 LockTemp(rMIPS_ARG2);
423 LockTemp(rMIPS_ARG3);
424}
425
426/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700427void MipsMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 FreeTemp(rMIPS_ARG0);
429 FreeTemp(rMIPS_ARG1);
430 FreeTemp(rMIPS_ARG2);
431 FreeTemp(rMIPS_ARG3);
432}
433
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700434void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435#if ANDROID_SMP != 0
436 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
437#endif
438}
439
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000440// Alloc a pair of core registers, or a double.
441RegStorage MipsMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 int high_reg;
443 int low_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444
445 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
446 low_reg = AllocTempDouble();
447 high_reg = low_reg + 1;
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000448 return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 }
450
451 low_reg = AllocTemp();
452 high_reg = AllocTemp();
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000453 return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700454}
455
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700456int MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
457 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 return AllocTempFloat();
459}
460 return AllocTemp();
461}
462
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700463void MipsMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
465 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
466 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
467 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
468 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700469 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000470 kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 reg_pool_->num_core_regs = num_regs;
472 reg_pool_->core_regs = static_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000473 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474 reg_pool_->num_fp_regs = num_fp_regs;
475 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000476 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
478 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
479 // Keep special registers from being allocated
480 for (int i = 0; i < num_reserved; i++) {
481 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700482 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 continue;
484 }
485 MarkInUse(ReservedRegs[i]);
486 }
487 // Mark temp regs - all others not in use can be used for promotion
488 for (int i = 0; i < num_temps; i++) {
489 MarkTemp(core_temps[i]);
490 }
491 for (int i = 0; i < num_fp_temps; i++) {
492 MarkTemp(fp_temps[i]);
493 }
494}
495
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700496void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000497 if ((rl_free.reg.GetReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetReg() != rl_keep.reg.GetHighReg()) &&
498 (rl_free.reg.GetHighReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700499 // No overlap, free both
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000500 FreeTemp(rl_free.reg.GetReg());
501 FreeTemp(rl_free.reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 }
503}
504/*
505 * In the Arm code a it is typical to use the link register
506 * to hold the target address. However, for Mips we must
507 * ensure that all branch instructions can be restarted if
508 * there is a trap in the shadow. Allocate a temp register.
509 */
Ian Rogers468532e2013-08-05 10:56:33 -0700510int MipsMir2Lir::LoadHelper(ThreadOffset offset) {
511 LoadWordDisp(rMIPS_SELF, offset.Int32Value(), r_T9);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 return r_T9;
513}
514
Dave Allisonb373e092014-02-20 16:06:36 -0800515LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
516 int tmp = AllocTemp();
517 LoadWordDisp(rMIPS_SELF, Thread::ThreadSuspendTriggerOffset().Int32Value(), tmp);
518 LIR *inst = LoadWordDisp(tmp, 0, tmp);
519 FreeTemp(tmp);
520 return inst;
521}
522
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700523void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524 if (num_core_spills_ == 0) {
525 return;
526 }
527 uint32_t mask = core_spill_mask_;
528 int offset = num_core_spills_ * 4;
529 OpRegImm(kOpSub, rMIPS_SP, offset);
530 for (int reg = 0; mask; mask >>= 1, reg++) {
531 if (mask & 0x1) {
532 offset -= 4;
533 StoreWordDisp(rMIPS_SP, offset, reg);
534 }
535 }
536}
537
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700538void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700539 if (num_core_spills_ == 0) {
540 return;
541 }
542 uint32_t mask = core_spill_mask_;
543 int offset = frame_size_;
544 for (int reg = 0; mask; mask >>= 1, reg++) {
545 if (mask & 0x1) {
546 offset -= 4;
547 LoadWordDisp(rMIPS_SP, offset, reg);
548 }
549 }
550 OpRegImm(kOpAdd, rMIPS_SP, frame_size_);
551}
552
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700553bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 return (lir->opcode == kMipsB);
555}
556
557MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
558 : Mir2Lir(cu, mir_graph, arena) {
559 for (int i = 0; i < kMipsLast; i++) {
560 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
561 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
562 << " is wrong: expecting " << i << ", seeing "
563 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
564 }
565 }
566}
567
568Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
569 ArenaAllocator* const arena) {
570 return new MipsMir2Lir(cu, mir_graph, arena);
571}
572
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700573uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700574 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700575 return MipsMir2Lir::EncodingMap[opcode].flags;
576}
577
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700578const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700579 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700580 return MipsMir2Lir::EncodingMap[opcode].name;
581}
582
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700583const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700584 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700585 return MipsMir2Lir::EncodingMap[opcode].fmt;
586}
587
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700588} // namespace art