blob: 1aee06c89ae2df4f2c751cb85982444d9645bbd7 [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"
18#include "dex/compiler_internals.h"
19#include "dex/quick/mir_to_lir-inl.h"
20#include "mips_lir.h"
21
22#include <string>
23
24namespace art {
25
26static int core_regs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
27 r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
28 r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
29 r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
30static int ReservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
31 r_RA};
32static int core_temps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
33 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8};
34static int FpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
35 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
36static int fp_temps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
37 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
38
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070039RegLocation MipsMir2Lir::LocCReturn() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070040 RegLocation res = MIPS_LOC_C_RETURN;
41 return res;
42}
43
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070044RegLocation MipsMir2Lir::LocCReturnWide() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070045 RegLocation res = MIPS_LOC_C_RETURN_WIDE;
46 return res;
47}
48
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070049RegLocation MipsMir2Lir::LocCReturnFloat() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 RegLocation res = MIPS_LOC_C_RETURN_FLOAT;
51 return res;
52}
53
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070054RegLocation MipsMir2Lir::LocCReturnDouble() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 RegLocation res = MIPS_LOC_C_RETURN_DOUBLE;
56 return res;
57}
58
59// Return a target-dependent special register.
60int MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
61 int res = INVALID_REG;
62 switch (reg) {
63 case kSelf: res = rMIPS_SELF; break;
64 case kSuspend: res = rMIPS_SUSPEND; break;
65 case kLr: res = rMIPS_LR; break;
66 case kPc: res = rMIPS_PC; break;
67 case kSp: res = rMIPS_SP; break;
68 case kArg0: res = rMIPS_ARG0; break;
69 case kArg1: res = rMIPS_ARG1; break;
70 case kArg2: res = rMIPS_ARG2; break;
71 case kArg3: res = rMIPS_ARG3; break;
72 case kFArg0: res = rMIPS_FARG0; break;
73 case kFArg1: res = rMIPS_FARG1; break;
74 case kFArg2: res = rMIPS_FARG2; break;
75 case kFArg3: res = rMIPS_FARG3; break;
76 case kRet0: res = rMIPS_RET0; break;
77 case kRet1: res = rMIPS_RET1; break;
78 case kInvokeTgt: res = rMIPS_INVOKE_TGT; break;
Jeff Hao88474b42013-10-23 16:24:40 -070079 case kHiddenArg: res = r_T0; break;
80 case kHiddenFpArg: res = INVALID_REG; break;
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 case kCount: res = rMIPS_COUNT; break;
82 }
83 return res;
84}
85
86// Create a double from a pair of singles.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070087int MipsMir2Lir::S2d(int low_reg, int high_reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070088 return MIPS_S2D(low_reg, high_reg);
89}
90
91// Return mask to strip off fp reg flags and bias.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070092uint32_t MipsMir2Lir::FpRegMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -070093 return MIPS_FP_REG_MASK;
94}
95
96// True if both regs single, both core or both double.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070097bool MipsMir2Lir::SameRegType(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070098 return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
99}
100
101/*
102 * Decode the register id.
103 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700104uint64_t MipsMir2Lir::GetRegMaskCommon(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700105 uint64_t seed;
106 int shift;
107 int reg_id;
108
109
110 reg_id = reg & 0x1f;
111 /* Each double register is equal to a pair of single-precision FP registers */
112 seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
113 /* FP register starts at bit position 16 */
114 shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
115 /* Expand the double register id into single offset */
116 shift += reg_id;
117 return (seed << shift);
118}
119
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700120uint64_t MipsMir2Lir::GetPCUseDefEncoding() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 return ENCODE_MIPS_REG_PC;
122}
123
124
buzbeeb48819d2013-09-14 16:15:25 -0700125void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126 DCHECK_EQ(cu_->instruction_set, kMips);
buzbeeb48819d2013-09-14 16:15:25 -0700127 DCHECK(!lir->flags.use_def_invalid);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128
129 // Mips-specific resource map setup here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 if (flags & REG_DEF_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700131 lir->u.m.def_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 }
133
134 if (flags & REG_USE_SP) {
buzbeeb48819d2013-09-14 16:15:25 -0700135 lir->u.m.use_mask |= ENCODE_MIPS_REG_SP;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 }
137
138 if (flags & REG_DEF_LR) {
buzbeeb48819d2013-09-14 16:15:25 -0700139 lir->u.m.def_mask |= ENCODE_MIPS_REG_LR;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 }
141}
142
143/* For dumping instructions */
144#define MIPS_REG_COUNT 32
145static const char *mips_reg_name[MIPS_REG_COUNT] = {
146 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
147 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
148 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
149 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
150};
151
152/*
153 * Interpret a format string and build a string no longer than size
154 * See format key in Assemble.c.
155 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700156std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 std::string buf;
158 int i;
159 const char *fmt_end = &fmt[strlen(fmt)];
160 char tbuf[256];
161 char nc;
162 while (fmt < fmt_end) {
163 int operand;
164 if (*fmt == '!') {
165 fmt++;
166 DCHECK_LT(fmt, fmt_end);
167 nc = *fmt++;
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700168 if (nc == '!') {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700169 strcpy(tbuf, "!");
170 } else {
171 DCHECK_LT(fmt, fmt_end);
172 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
173 operand = lir->operands[nc-'0'];
174 switch (*fmt++) {
175 case 'b':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700176 strcpy(tbuf, "0000");
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700177 for (i = 3; i >= 0; i--) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 tbuf[i] += operand & 1;
179 operand >>= 1;
180 }
181 break;
182 case 's':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800183 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700184 break;
185 case 'S':
186 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
Ian Rogers988e6ea2014-01-08 11:30:50 -0800187 snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 break;
189 case 'h':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800190 snprintf(tbuf, arraysize(tbuf), "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700191 break;
192 case 'M':
193 case 'd':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800194 snprintf(tbuf, arraysize(tbuf), "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700195 break;
196 case 'D':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800197 snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 break;
199 case 'E':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800200 snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 break;
202 case 'F':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800203 snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 break;
205 case 't':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800206 snprintf(tbuf, arraysize(tbuf), "0x%08x (L%p)",
207 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 2),
208 lir->target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209 break;
210 case 'T':
Ian Rogers988e6ea2014-01-08 11:30:50 -0800211 snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 break;
213 case 'u': {
214 int offset_1 = lir->operands[0];
215 int offset_2 = NEXT_LIR(lir)->operands[0];
216 uintptr_t target =
217 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
218 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
Ian Rogers988e6ea2014-01-08 11:30:50 -0800219 snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 break;
221 }
222
223 /* Nothing to print for BLX_2 */
224 case 'v':
225 strcpy(tbuf, "see above");
226 break;
227 case 'r':
228 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
229 strcpy(tbuf, mips_reg_name[operand]);
230 break;
231 case 'N':
232 // Placeholder for delay slot handling
233 strcpy(tbuf, "; nop");
234 break;
235 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700236 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 break;
238 }
239 buf += tbuf;
240 }
241 } else {
242 buf += *fmt++;
243 }
244 }
245 return buf;
246}
247
248// FIXME: need to redo resource maps for MIPS - fix this at that time
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700249void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 char buf[256];
251 buf[0] = 0;
252
253 if (mask == ENCODE_ALL) {
254 strcpy(buf, "all");
255 } else {
256 char num[8];
257 int i;
258
259 for (i = 0; i < kMipsRegEnd; i++) {
260 if (mask & (1ULL << i)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800261 snprintf(num, arraysize(num), "%d ", i);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 strcat(buf, num);
263 }
264 }
265
266 if (mask & ENCODE_CCODE) {
267 strcat(buf, "cc ");
268 }
269 if (mask & ENCODE_FP_STATUS) {
270 strcat(buf, "fpcc ");
271 }
272 /* Memory bits */
273 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
Ian Rogers988e6ea2014-01-08 11:30:50 -0800274 snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
275 DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
276 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700277 }
278 if (mask & ENCODE_LITERAL) {
279 strcat(buf, "lit ");
280 }
281
282 if (mask & ENCODE_HEAP_REF) {
283 strcat(buf, "heap ");
284 }
285 if (mask & ENCODE_MUST_NOT_ALIAS) {
286 strcat(buf, "noalias ");
287 }
288 }
289 if (buf[0]) {
290 LOG(INFO) << prefix << ": " << buf;
291 }
292}
293
294/*
295 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
296 * instructions might call out to C/assembly helper functions. Until
297 * machinery is in place, always spill lr.
298 */
299
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700300void MipsMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 core_spill_mask_ |= (1 << r_RA);
302 num_core_spills_++;
303}
304
305/*
306 * Mark a callee-save fp register as promoted. Note that
307 * vpush/vpop uses contiguous register lists so we must
308 * include any holes in the mask. Associate holes with
309 * Dalvik register INVALID_VREG (0xFFFFU).
310 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700311void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 LOG(FATAL) << "No support yet for promoted FP regs";
313}
314
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700315void MipsMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700316 RegisterInfo* info1 = GetRegInfo(reg1);
317 RegisterInfo* info2 = GetRegInfo(reg2);
318 DCHECK(info1 && info2 && info1->pair && info2->pair &&
319 (info1->partner == info2->reg) &&
320 (info2->partner == info1->reg));
321 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
322 if (!(info1->is_temp && info2->is_temp)) {
323 /* Should not happen. If it does, there's a problem in eval_loc */
324 LOG(FATAL) << "Long half-temp, half-promoted";
325 }
326
327 info1->dirty = false;
328 info2->dirty = false;
329 if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
330 info1 = info2;
331 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
332 StoreBaseDispWide(rMIPS_SP, VRegOffset(v_reg), info1->reg, info1->partner);
333 }
334}
335
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700336void MipsMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 RegisterInfo* info = GetRegInfo(reg);
338 if (info->live && info->dirty) {
339 info->dirty = false;
340 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
341 StoreBaseDisp(rMIPS_SP, VRegOffset(v_reg), reg, kWord);
342 }
343}
344
345/* Give access to the target-dependent FP register encoding to common code */
346bool MipsMir2Lir::IsFpReg(int reg) {
347 return MIPS_FPREG(reg);
348}
349
350/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000351void MipsMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 Clobber(r_ZERO);
353 Clobber(r_AT);
354 Clobber(r_V0);
355 Clobber(r_V1);
356 Clobber(r_A0);
357 Clobber(r_A1);
358 Clobber(r_A2);
359 Clobber(r_A3);
360 Clobber(r_T0);
361 Clobber(r_T1);
362 Clobber(r_T2);
363 Clobber(r_T3);
364 Clobber(r_T4);
365 Clobber(r_T5);
366 Clobber(r_T6);
367 Clobber(r_T7);
368 Clobber(r_T8);
369 Clobber(r_T9);
370 Clobber(r_K0);
371 Clobber(r_K1);
372 Clobber(r_GP);
373 Clobber(r_FP);
374 Clobber(r_RA);
375 Clobber(r_F0);
376 Clobber(r_F1);
377 Clobber(r_F2);
378 Clobber(r_F3);
379 Clobber(r_F4);
380 Clobber(r_F5);
381 Clobber(r_F6);
382 Clobber(r_F7);
383 Clobber(r_F8);
384 Clobber(r_F9);
385 Clobber(r_F10);
386 Clobber(r_F11);
387 Clobber(r_F12);
388 Clobber(r_F13);
389 Clobber(r_F14);
390 Clobber(r_F15);
391}
392
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700393RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700394 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
395 RegLocation res = LocCReturnWide();
396 return res;
397}
398
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700399RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700400 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
401 RegLocation res = LocCReturn();
402 return res;
403}
404
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700406void MipsMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407 LockTemp(rMIPS_ARG0);
408 LockTemp(rMIPS_ARG1);
409 LockTemp(rMIPS_ARG2);
410 LockTemp(rMIPS_ARG3);
411}
412
413/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700414void MipsMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 FreeTemp(rMIPS_ARG0);
416 FreeTemp(rMIPS_ARG1);
417 FreeTemp(rMIPS_ARG2);
418 FreeTemp(rMIPS_ARG3);
419}
420
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700421void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422#if ANDROID_SMP != 0
423 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
424#endif
425}
426
427/*
428 * Alloc a pair of core registers, or a double. Low reg in low byte,
429 * high reg in next byte.
430 */
431int MipsMir2Lir::AllocTypedTempPair(bool fp_hint,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700432 int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 int high_reg;
434 int low_reg;
435 int res = 0;
436
437 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
438 low_reg = AllocTempDouble();
439 high_reg = low_reg + 1;
440 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
441 return res;
442 }
443
444 low_reg = AllocTemp();
445 high_reg = AllocTemp();
446 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
447 return res;
448}
449
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700450int MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
451 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 return AllocTempFloat();
453}
454 return AllocTemp();
455}
456
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700457void MipsMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
459 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
460 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
461 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
462 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700463 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
464 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 reg_pool_->num_core_regs = num_regs;
466 reg_pool_->core_regs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700467 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700468 reg_pool_->num_fp_regs = num_fp_regs;
469 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700470 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
472 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
473 // Keep special registers from being allocated
474 for (int i = 0; i < num_reserved; i++) {
475 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700476 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 continue;
478 }
479 MarkInUse(ReservedRegs[i]);
480 }
481 // Mark temp regs - all others not in use can be used for promotion
482 for (int i = 0; i < num_temps; i++) {
483 MarkTemp(core_temps[i]);
484 }
485 for (int i = 0; i < num_fp_temps; i++) {
486 MarkTemp(fp_temps[i]);
487 }
488}
489
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700490void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
492 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
493 // No overlap, free both
494 FreeTemp(rl_free.low_reg);
495 FreeTemp(rl_free.high_reg);
496 }
497}
498/*
499 * In the Arm code a it is typical to use the link register
500 * to hold the target address. However, for Mips we must
501 * ensure that all branch instructions can be restarted if
502 * there is a trap in the shadow. Allocate a temp register.
503 */
Ian Rogers468532e2013-08-05 10:56:33 -0700504int MipsMir2Lir::LoadHelper(ThreadOffset offset) {
505 LoadWordDisp(rMIPS_SELF, offset.Int32Value(), r_T9);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 return r_T9;
507}
508
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700509void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 if (num_core_spills_ == 0) {
511 return;
512 }
513 uint32_t mask = core_spill_mask_;
514 int offset = num_core_spills_ * 4;
515 OpRegImm(kOpSub, rMIPS_SP, offset);
516 for (int reg = 0; mask; mask >>= 1, reg++) {
517 if (mask & 0x1) {
518 offset -= 4;
519 StoreWordDisp(rMIPS_SP, offset, reg);
520 }
521 }
522}
523
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700524void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700525 if (num_core_spills_ == 0) {
526 return;
527 }
528 uint32_t mask = core_spill_mask_;
529 int offset = frame_size_;
530 for (int reg = 0; mask; mask >>= 1, reg++) {
531 if (mask & 0x1) {
532 offset -= 4;
533 LoadWordDisp(rMIPS_SP, offset, reg);
534 }
535 }
536 OpRegImm(kOpAdd, rMIPS_SP, frame_size_);
537}
538
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700539bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700540 return (lir->opcode == kMipsB);
541}
542
543MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
544 : Mir2Lir(cu, mir_graph, arena) {
545 for (int i = 0; i < kMipsLast; i++) {
546 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
547 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
548 << " is wrong: expecting " << i << ", seeing "
549 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
550 }
551 }
552}
553
554Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
555 ArenaAllocator* const arena) {
556 return new MipsMir2Lir(cu, mir_graph, arena);
557}
558
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700559uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700560 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700561 return MipsMir2Lir::EncodingMap[opcode].flags;
562}
563
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700564const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700565 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566 return MipsMir2Lir::EncodingMap[opcode].name;
567}
568
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700569const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700570 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700571 return MipsMir2Lir::EncodingMap[opcode].fmt;
572}
573
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700574} // namespace art