blob: 869706fbe06ccf5b98bc334c893d33e9ae1bf9f1 [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':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700183 sprintf(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);
Brian Carlstromb1eba212013-07-17 18:07:19 -0700187 sprintf(tbuf, "$f%d", operand & MIPS_FP_REG_MASK);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 break;
189 case 'h':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700190 sprintf(tbuf, "%04x", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700191 break;
192 case 'M':
193 case 'd':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700194 sprintf(tbuf, "%d", operand);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700195 break;
196 case 'D':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700197 sprintf(tbuf, "%d", operand+1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 break;
199 case 'E':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700200 sprintf(tbuf, "%d", operand*4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 break;
202 case 'F':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700203 sprintf(tbuf, "%d", operand*2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 break;
205 case 't':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700206 sprintf(tbuf, "0x%08x (L%p)", reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
Brian Carlstrom7940e442013-07-12 13:46:57 -0700207 (operand << 2), lir->target);
208 break;
209 case 'T':
Brian Carlstromb1eba212013-07-17 18:07:19 -0700210 sprintf(tbuf, "0x%08x", operand << 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700211 break;
212 case 'u': {
213 int offset_1 = lir->operands[0];
214 int offset_2 = NEXT_LIR(lir)->operands[0];
215 uintptr_t target =
216 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
217 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
218 sprintf(tbuf, "%p", reinterpret_cast<void*>(target));
219 break;
220 }
221
222 /* Nothing to print for BLX_2 */
223 case 'v':
224 strcpy(tbuf, "see above");
225 break;
226 case 'r':
227 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
228 strcpy(tbuf, mips_reg_name[operand]);
229 break;
230 case 'N':
231 // Placeholder for delay slot handling
232 strcpy(tbuf, "; nop");
233 break;
234 default:
Brian Carlstromb1eba212013-07-17 18:07:19 -0700235 strcpy(tbuf, "DecodeError");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 break;
237 }
238 buf += tbuf;
239 }
240 } else {
241 buf += *fmt++;
242 }
243 }
244 return buf;
245}
246
247// FIXME: need to redo resource maps for MIPS - fix this at that time
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700248void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700249 char buf[256];
250 buf[0] = 0;
251
252 if (mask == ENCODE_ALL) {
253 strcpy(buf, "all");
254 } else {
255 char num[8];
256 int i;
257
258 for (i = 0; i < kMipsRegEnd; i++) {
259 if (mask & (1ULL << i)) {
260 sprintf(num, "%d ", i);
261 strcat(buf, num);
262 }
263 }
264
265 if (mask & ENCODE_CCODE) {
266 strcat(buf, "cc ");
267 }
268 if (mask & ENCODE_FP_STATUS) {
269 strcat(buf, "fpcc ");
270 }
271 /* Memory bits */
272 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
buzbeeb48819d2013-09-14 16:15:25 -0700273 sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
274 DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 }
276 if (mask & ENCODE_LITERAL) {
277 strcat(buf, "lit ");
278 }
279
280 if (mask & ENCODE_HEAP_REF) {
281 strcat(buf, "heap ");
282 }
283 if (mask & ENCODE_MUST_NOT_ALIAS) {
284 strcat(buf, "noalias ");
285 }
286 }
287 if (buf[0]) {
288 LOG(INFO) << prefix << ": " << buf;
289 }
290}
291
292/*
293 * TUNING: is true leaf? Can't just use METHOD_IS_LEAF to determine as some
294 * instructions might call out to C/assembly helper functions. Until
295 * machinery is in place, always spill lr.
296 */
297
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700298void MipsMir2Lir::AdjustSpillMask() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700299 core_spill_mask_ |= (1 << r_RA);
300 num_core_spills_++;
301}
302
303/*
304 * Mark a callee-save fp register as promoted. Note that
305 * vpush/vpop uses contiguous register lists so we must
306 * include any holes in the mask. Associate holes with
307 * Dalvik register INVALID_VREG (0xFFFFU).
308 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700309void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 LOG(FATAL) << "No support yet for promoted FP regs";
311}
312
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700313void MipsMir2Lir::FlushRegWide(int reg1, int reg2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 RegisterInfo* info1 = GetRegInfo(reg1);
315 RegisterInfo* info2 = GetRegInfo(reg2);
316 DCHECK(info1 && info2 && info1->pair && info2->pair &&
317 (info1->partner == info2->reg) &&
318 (info2->partner == info1->reg));
319 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
320 if (!(info1->is_temp && info2->is_temp)) {
321 /* Should not happen. If it does, there's a problem in eval_loc */
322 LOG(FATAL) << "Long half-temp, half-promoted";
323 }
324
325 info1->dirty = false;
326 info2->dirty = false;
327 if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
328 info1 = info2;
329 int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
330 StoreBaseDispWide(rMIPS_SP, VRegOffset(v_reg), info1->reg, info1->partner);
331 }
332}
333
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700334void MipsMir2Lir::FlushReg(int reg) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 RegisterInfo* info = GetRegInfo(reg);
336 if (info->live && info->dirty) {
337 info->dirty = false;
338 int v_reg = mir_graph_->SRegToVReg(info->s_reg);
339 StoreBaseDisp(rMIPS_SP, VRegOffset(v_reg), reg, kWord);
340 }
341}
342
343/* Give access to the target-dependent FP register encoding to common code */
344bool MipsMir2Lir::IsFpReg(int reg) {
345 return MIPS_FPREG(reg);
346}
347
348/* Clobber all regs that might be used by an external C call */
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000349void MipsMir2Lir::ClobberCallerSave() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 Clobber(r_ZERO);
351 Clobber(r_AT);
352 Clobber(r_V0);
353 Clobber(r_V1);
354 Clobber(r_A0);
355 Clobber(r_A1);
356 Clobber(r_A2);
357 Clobber(r_A3);
358 Clobber(r_T0);
359 Clobber(r_T1);
360 Clobber(r_T2);
361 Clobber(r_T3);
362 Clobber(r_T4);
363 Clobber(r_T5);
364 Clobber(r_T6);
365 Clobber(r_T7);
366 Clobber(r_T8);
367 Clobber(r_T9);
368 Clobber(r_K0);
369 Clobber(r_K1);
370 Clobber(r_GP);
371 Clobber(r_FP);
372 Clobber(r_RA);
373 Clobber(r_F0);
374 Clobber(r_F1);
375 Clobber(r_F2);
376 Clobber(r_F3);
377 Clobber(r_F4);
378 Clobber(r_F5);
379 Clobber(r_F6);
380 Clobber(r_F7);
381 Clobber(r_F8);
382 Clobber(r_F9);
383 Clobber(r_F10);
384 Clobber(r_F11);
385 Clobber(r_F12);
386 Clobber(r_F13);
387 Clobber(r_F14);
388 Clobber(r_F15);
389}
390
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700391RegLocation MipsMir2Lir::GetReturnWideAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
393 RegLocation res = LocCReturnWide();
394 return res;
395}
396
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700397RegLocation MipsMir2Lir::GetReturnAlt() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
399 RegLocation res = LocCReturn();
400 return res;
401}
402
Brian Carlstrom7940e442013-07-12 13:46:57 -0700403/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700404void MipsMir2Lir::LockCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 LockTemp(rMIPS_ARG0);
406 LockTemp(rMIPS_ARG1);
407 LockTemp(rMIPS_ARG2);
408 LockTemp(rMIPS_ARG3);
409}
410
411/* To be used when explicitly managing register use */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700412void MipsMir2Lir::FreeCallTemps() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 FreeTemp(rMIPS_ARG0);
414 FreeTemp(rMIPS_ARG1);
415 FreeTemp(rMIPS_ARG2);
416 FreeTemp(rMIPS_ARG3);
417}
418
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700419void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420#if ANDROID_SMP != 0
421 NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
422#endif
423}
424
425/*
426 * Alloc a pair of core registers, or a double. Low reg in low byte,
427 * high reg in next byte.
428 */
429int MipsMir2Lir::AllocTypedTempPair(bool fp_hint,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700430 int reg_class) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700431 int high_reg;
432 int low_reg;
433 int res = 0;
434
435 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
436 low_reg = AllocTempDouble();
437 high_reg = low_reg + 1;
438 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
439 return res;
440 }
441
442 low_reg = AllocTemp();
443 high_reg = AllocTemp();
444 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
445 return res;
446}
447
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700448int MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
449 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 return AllocTempFloat();
451}
452 return AllocTemp();
453}
454
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700455void MipsMir2Lir::CompilerInitializeRegAlloc() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700456 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
457 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
458 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
459 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
460 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700461 reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
462 ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463 reg_pool_->num_core_regs = num_regs;
464 reg_pool_->core_regs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700465 (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 reg_pool_->num_fp_regs = num_fp_regs;
467 reg_pool_->FPRegs = static_cast<RegisterInfo*>
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700468 (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
470 CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
471 // Keep special registers from being allocated
472 for (int i = 0; i < num_reserved; i++) {
473 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700474 // To measure cost of suspend check
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 continue;
476 }
477 MarkInUse(ReservedRegs[i]);
478 }
479 // Mark temp regs - all others not in use can be used for promotion
480 for (int i = 0; i < num_temps; i++) {
481 MarkTemp(core_temps[i]);
482 }
483 for (int i = 0; i < num_fp_temps; i++) {
484 MarkTemp(fp_temps[i]);
485 }
486}
487
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700488void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
490 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
491 // No overlap, free both
492 FreeTemp(rl_free.low_reg);
493 FreeTemp(rl_free.high_reg);
494 }
495}
496/*
497 * In the Arm code a it is typical to use the link register
498 * to hold the target address. However, for Mips we must
499 * ensure that all branch instructions can be restarted if
500 * there is a trap in the shadow. Allocate a temp register.
501 */
Ian Rogers468532e2013-08-05 10:56:33 -0700502int MipsMir2Lir::LoadHelper(ThreadOffset offset) {
503 LoadWordDisp(rMIPS_SELF, offset.Int32Value(), r_T9);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504 return r_T9;
505}
506
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700507void MipsMir2Lir::SpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700508 if (num_core_spills_ == 0) {
509 return;
510 }
511 uint32_t mask = core_spill_mask_;
512 int offset = num_core_spills_ * 4;
513 OpRegImm(kOpSub, rMIPS_SP, offset);
514 for (int reg = 0; mask; mask >>= 1, reg++) {
515 if (mask & 0x1) {
516 offset -= 4;
517 StoreWordDisp(rMIPS_SP, offset, reg);
518 }
519 }
520}
521
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700522void MipsMir2Lir::UnSpillCoreRegs() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700523 if (num_core_spills_ == 0) {
524 return;
525 }
526 uint32_t mask = core_spill_mask_;
527 int offset = frame_size_;
528 for (int reg = 0; mask; mask >>= 1, reg++) {
529 if (mask & 0x1) {
530 offset -= 4;
531 LoadWordDisp(rMIPS_SP, offset, reg);
532 }
533 }
534 OpRegImm(kOpAdd, rMIPS_SP, frame_size_);
535}
536
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700537bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538 return (lir->opcode == kMipsB);
539}
540
541MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
542 : Mir2Lir(cu, mir_graph, arena) {
543 for (int i = 0; i < kMipsLast; i++) {
544 if (MipsMir2Lir::EncodingMap[i].opcode != i) {
545 LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
546 << " is wrong: expecting " << i << ", seeing "
547 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
548 }
549 }
550}
551
552Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
553 ArenaAllocator* const arena) {
554 return new MipsMir2Lir(cu, mir_graph, arena);
555}
556
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700557uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700558 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 return MipsMir2Lir::EncodingMap[opcode].flags;
560}
561
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700562const char* MipsMir2Lir::GetTargetInstName(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700563 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700564 return MipsMir2Lir::EncodingMap[opcode].name;
565}
566
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700567const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
buzbee409fe942013-10-11 10:49:56 -0700568 DCHECK(!IsPseudoLirOp(opcode));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 return MipsMir2Lir::EncodingMap[opcode].fmt;
570}
571
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700572} // namespace art