blob: ed884b21d4463435a4848de018f28a867857df2f [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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 "../../compiler_internals.h"
18#include "mips_lir.h"
buzbee02031b12012-11-23 09:41:35 -080019#include "codegen_mips.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080020#include "../ralloc_util.h"
21#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080022
23#include <string>
24
25namespace art {
26
buzbeefa57c472012-11-21 12:06:18 -080027static int core_regs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
28 r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
29 r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
30 r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
buzbee52a77fc2012-11-20 19:50:46 -080031static int ReservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
buzbeeefc63692012-11-14 16:31:52 -080032 r_RA};
buzbeefa57c472012-11-21 12:06:18 -080033static int core_temps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
34 r_T3, r_T4, r_T5, r_T6, r_T7, r_T8};
buzbee52a77fc2012-11-20 19:50:46 -080035static int FpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
buzbeeefc63692012-11-14 16:31:52 -080036 r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
buzbeefa57c472012-11-21 12:06:18 -080037static int fp_temps[] = {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};
buzbeeefc63692012-11-14 16:31:52 -080039
buzbee02031b12012-11-23 09:41:35 -080040RegLocation MipsCodegen::LocCReturn()
buzbeeefc63692012-11-14 16:31:52 -080041{
42 RegLocation res = MIPS_LOC_C_RETURN;
43 return res;
44}
45
buzbee02031b12012-11-23 09:41:35 -080046RegLocation MipsCodegen::LocCReturnWide()
buzbeeefc63692012-11-14 16:31:52 -080047{
48 RegLocation res = MIPS_LOC_C_RETURN_WIDE;
49 return res;
50}
51
buzbee02031b12012-11-23 09:41:35 -080052RegLocation MipsCodegen::LocCReturnFloat()
buzbeeefc63692012-11-14 16:31:52 -080053{
54 RegLocation res = MIPS_LOC_C_RETURN_FLOAT;
55 return res;
56}
57
buzbee02031b12012-11-23 09:41:35 -080058RegLocation MipsCodegen::LocCReturnDouble()
buzbeeefc63692012-11-14 16:31:52 -080059{
60 RegLocation res = MIPS_LOC_C_RETURN_DOUBLE;
61 return res;
62}
63
64// Return a target-dependent special register.
buzbee02031b12012-11-23 09:41:35 -080065int MipsCodegen::TargetReg(SpecialTargetRegister reg) {
buzbeeefc63692012-11-14 16:31:52 -080066 int res = INVALID_REG;
67 switch (reg) {
68 case kSelf: res = rMIPS_SELF; break;
69 case kSuspend: res = rMIPS_SUSPEND; break;
70 case kLr: res = rMIPS_LR; break;
71 case kPc: res = rMIPS_PC; break;
72 case kSp: res = rMIPS_SP; break;
73 case kArg0: res = rMIPS_ARG0; break;
74 case kArg1: res = rMIPS_ARG1; break;
75 case kArg2: res = rMIPS_ARG2; break;
76 case kArg3: res = rMIPS_ARG3; break;
77 case kFArg0: res = rMIPS_FARG0; break;
78 case kFArg1: res = rMIPS_FARG1; break;
79 case kFArg2: res = rMIPS_FARG2; break;
80 case kFArg3: res = rMIPS_FARG3; break;
81 case kRet0: res = rMIPS_RET0; break;
82 case kRet1: res = rMIPS_RET1; break;
83 case kInvokeTgt: res = rMIPS_INVOKE_TGT; break;
84 case kCount: res = rMIPS_COUNT; break;
85 }
86 return res;
87}
88
89// Create a double from a pair of singles.
buzbee02031b12012-11-23 09:41:35 -080090int MipsCodegen::S2d(int low_reg, int high_reg)
buzbeeefc63692012-11-14 16:31:52 -080091{
buzbeefa57c472012-11-21 12:06:18 -080092 return MIPS_S2D(low_reg, high_reg);
buzbeeefc63692012-11-14 16:31:52 -080093}
94
buzbeeefc63692012-11-14 16:31:52 -080095// Return mask to strip off fp reg flags and bias.
buzbee02031b12012-11-23 09:41:35 -080096uint32_t MipsCodegen::FpRegMask()
buzbeeefc63692012-11-14 16:31:52 -080097{
98 return MIPS_FP_REG_MASK;
99}
100
101// True if both regs single, both core or both double.
buzbee02031b12012-11-23 09:41:35 -0800102bool MipsCodegen::SameRegType(int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800103{
104 return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
105}
106
107/*
108 * Decode the register id.
109 */
buzbee02031b12012-11-23 09:41:35 -0800110uint64_t MipsCodegen::GetRegMaskCommon(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800111{
buzbeeeaf09bc2012-11-15 14:51:41 -0800112 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800113 int shift;
buzbeefa57c472012-11-21 12:06:18 -0800114 int reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800115
116
buzbeefa57c472012-11-21 12:06:18 -0800117 reg_id = reg & 0x1f;
buzbeeefc63692012-11-14 16:31:52 -0800118 /* Each double register is equal to a pair of single-precision FP registers */
119 seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
120 /* FP register starts at bit position 16 */
121 shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
122 /* Expand the double register id into single offset */
buzbeefa57c472012-11-21 12:06:18 -0800123 shift += reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800124 return (seed << shift);
125}
126
buzbee02031b12012-11-23 09:41:35 -0800127uint64_t MipsCodegen::GetPCUseDefEncoding()
buzbeeefc63692012-11-14 16:31:52 -0800128{
129 return ENCODE_MIPS_REG_PC;
130}
131
132
buzbee02031b12012-11-23 09:41:35 -0800133void MipsCodegen::SetupTargetResourceMasks(CompilationUnit* cu, LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800134{
buzbeefa57c472012-11-21 12:06:18 -0800135 DCHECK_EQ(cu->instruction_set, kMips);
buzbeeefc63692012-11-14 16:31:52 -0800136
137 // Mips-specific resource map setup here.
buzbee02031b12012-11-23 09:41:35 -0800138 uint64_t flags = MipsCodegen::EncodingMap[lir->opcode].flags;
buzbeeefc63692012-11-14 16:31:52 -0800139
140 if (flags & REG_DEF_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800141 lir->def_mask |= ENCODE_MIPS_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800142 }
143
144 if (flags & REG_USE_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800145 lir->use_mask |= ENCODE_MIPS_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800146 }
147
148 if (flags & REG_DEF_LR) {
buzbeefa57c472012-11-21 12:06:18 -0800149 lir->def_mask |= ENCODE_MIPS_REG_LR;
buzbeeefc63692012-11-14 16:31:52 -0800150 }
151}
152
153/* For dumping instructions */
154#define MIPS_REG_COUNT 32
buzbeefa57c472012-11-21 12:06:18 -0800155static const char *mips_reg_name[MIPS_REG_COUNT] = {
buzbeeefc63692012-11-14 16:31:52 -0800156 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
157 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
158 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
159 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
160};
161
162/*
163 * Interpret a format string and build a string no longer than size
164 * See format key in Assemble.c.
165 */
buzbee02031b12012-11-23 09:41:35 -0800166std::string MipsCodegen::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr)
buzbeeefc63692012-11-14 16:31:52 -0800167{
168 std::string buf;
169 int i;
buzbeefa57c472012-11-21 12:06:18 -0800170 const char *fmt_end = &fmt[strlen(fmt)];
buzbeeefc63692012-11-14 16:31:52 -0800171 char tbuf[256];
172 char nc;
buzbeefa57c472012-11-21 12:06:18 -0800173 while (fmt < fmt_end) {
buzbeeefc63692012-11-14 16:31:52 -0800174 int operand;
175 if (*fmt == '!') {
176 fmt++;
buzbeefa57c472012-11-21 12:06:18 -0800177 DCHECK_LT(fmt, fmt_end);
buzbeeefc63692012-11-14 16:31:52 -0800178 nc = *fmt++;
179 if (nc=='!') {
180 strcpy(tbuf, "!");
181 } else {
buzbeefa57c472012-11-21 12:06:18 -0800182 DCHECK_LT(fmt, fmt_end);
buzbeecbd6d442012-11-17 14:11:25 -0800183 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
buzbeeefc63692012-11-14 16:31:52 -0800184 operand = lir->operands[nc-'0'];
185 switch (*fmt++) {
186 case 'b':
187 strcpy(tbuf,"0000");
188 for (i=3; i>= 0; i--) {
189 tbuf[i] += operand & 1;
190 operand >>= 1;
191 }
192 break;
193 case 's':
194 sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK);
195 break;
196 case 'S':
197 DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
198 sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK);
199 break;
200 case 'h':
201 sprintf(tbuf,"%04x", operand);
202 break;
203 case 'M':
204 case 'd':
205 sprintf(tbuf,"%d", operand);
206 break;
207 case 'D':
208 sprintf(tbuf,"%d", operand+1);
209 break;
210 case 'E':
211 sprintf(tbuf,"%d", operand*4);
212 break;
213 case 'F':
214 sprintf(tbuf,"%d", operand*2);
215 break;
216 case 't':
buzbeefa57c472012-11-21 12:06:18 -0800217 sprintf(tbuf,"0x%08x (L%p)", reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
buzbeeefc63692012-11-14 16:31:52 -0800218 (operand << 2), lir->target);
219 break;
220 case 'T':
buzbeecbd6d442012-11-17 14:11:25 -0800221 sprintf(tbuf,"0x%08x", operand << 2);
buzbeeefc63692012-11-14 16:31:52 -0800222 break;
223 case 'u': {
224 int offset_1 = lir->operands[0];
225 int offset_2 = NEXT_LIR(lir)->operands[0];
buzbeecbd6d442012-11-17 14:11:25 -0800226 uintptr_t target =
buzbeefa57c472012-11-21 12:06:18 -0800227 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
buzbeeefc63692012-11-14 16:31:52 -0800228 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
buzbeecbd6d442012-11-17 14:11:25 -0800229 sprintf(tbuf, "%p", reinterpret_cast<void*>(target));
buzbeeefc63692012-11-14 16:31:52 -0800230 break;
231 }
232
233 /* Nothing to print for BLX_2 */
234 case 'v':
235 strcpy(tbuf, "see above");
236 break;
237 case 'r':
238 DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
buzbeefa57c472012-11-21 12:06:18 -0800239 strcpy(tbuf, mips_reg_name[operand]);
buzbeeefc63692012-11-14 16:31:52 -0800240 break;
241 case 'N':
242 // Placeholder for delay slot handling
243 strcpy(tbuf, "; nop");
244 break;
245 default:
246 strcpy(tbuf,"DecodeError");
247 break;
248 }
249 buf += tbuf;
250 }
251 } else {
252 buf += *fmt++;
253 }
254 }
255 return buf;
256}
257
258// FIXME: need to redo resource maps for MIPS - fix this at that time
buzbee02031b12012-11-23 09:41:35 -0800259void MipsCodegen::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *prefix)
buzbeeefc63692012-11-14 16:31:52 -0800260{
261 char buf[256];
262 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800263
264 if (mask == ENCODE_ALL) {
265 strcpy(buf, "all");
266 } else {
267 char num[8];
268 int i;
269
270 for (i = 0; i < kMipsRegEnd; i++) {
271 if (mask & (1ULL << i)) {
272 sprintf(num, "%d ", i);
273 strcat(buf, num);
274 }
275 }
276
277 if (mask & ENCODE_CCODE) {
278 strcat(buf, "cc ");
279 }
280 if (mask & ENCODE_FP_STATUS) {
281 strcat(buf, "fpcc ");
282 }
283 /* Memory bits */
buzbeefa57c472012-11-21 12:06:18 -0800284 if (mips_lir && (mask & ENCODE_DALVIK_REG)) {
285 sprintf(buf + strlen(buf), "dr%d%s", mips_lir->alias_info & 0xffff,
286 (mips_lir->alias_info & 0x80000000) ? "(+1)" : "");
buzbeeefc63692012-11-14 16:31:52 -0800287 }
288 if (mask & ENCODE_LITERAL) {
289 strcat(buf, "lit ");
290 }
291
292 if (mask & ENCODE_HEAP_REF) {
293 strcat(buf, "heap ");
294 }
295 if (mask & ENCODE_MUST_NOT_ALIAS) {
296 strcat(buf, "noalias ");
297 }
298 }
299 if (buf[0]) {
300 LOG(INFO) << prefix << ": " << buf;
301 }
302}
303
304/*
buzbeefa57c472012-11-21 12:06:18 -0800305 * TUNING: is leaf? Can't just use "has_invoke" to determine as some
buzbeeefc63692012-11-14 16:31:52 -0800306 * instructions might call out to C/assembly helper functions. Until
307 * machinery is in place, always spill lr.
308 */
309
buzbee02031b12012-11-23 09:41:35 -0800310void MipsCodegen::AdjustSpillMask(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800311{
buzbeefa57c472012-11-21 12:06:18 -0800312 cu->core_spill_mask |= (1 << r_RA);
313 cu->num_core_spills++;
buzbeeefc63692012-11-14 16:31:52 -0800314}
315
316/*
317 * Mark a callee-save fp register as promoted. Note that
318 * vpush/vpop uses contiguous register lists so we must
319 * include any holes in the mask. Associate holes with
320 * Dalvik register INVALID_VREG (0xFFFFU).
321 */
buzbee02031b12012-11-23 09:41:35 -0800322void MipsCodegen::MarkPreservedSingle(CompilationUnit* cu, int s_reg, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800323{
324 LOG(FATAL) << "No support yet for promoted FP regs";
325}
326
buzbee02031b12012-11-23 09:41:35 -0800327void MipsCodegen::FlushRegWide(CompilationUnit* cu, int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800328{
buzbeefa57c472012-11-21 12:06:18 -0800329 RegisterInfo* info1 = GetRegInfo(cu, reg1);
330 RegisterInfo* info2 = GetRegInfo(cu, reg2);
buzbeeefc63692012-11-14 16:31:52 -0800331 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)) {
buzbeefa57c472012-11-21 12:06:18 -0800335 if (!(info1->is_temp && info2->is_temp)) {
336 /* Should not happen. If it does, there's a problem in eval_loc */
buzbeeefc63692012-11-14 16:31:52 -0800337 LOG(FATAL) << "Long half-temp, half-promoted";
338 }
339
340 info1->dirty = false;
341 info2->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800342 if (SRegToVReg(cu, info2->s_reg) < SRegToVReg(cu, info1->s_reg))
buzbeeefc63692012-11-14 16:31:52 -0800343 info1 = info2;
buzbeefa57c472012-11-21 12:06:18 -0800344 int v_reg = SRegToVReg(cu, info1->s_reg);
345 StoreBaseDispWide(cu, rMIPS_SP, VRegOffset(cu, v_reg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800346 }
347}
348
buzbee02031b12012-11-23 09:41:35 -0800349void MipsCodegen::FlushReg(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800350{
buzbeefa57c472012-11-21 12:06:18 -0800351 RegisterInfo* info = GetRegInfo(cu, reg);
buzbeeefc63692012-11-14 16:31:52 -0800352 if (info->live && info->dirty) {
353 info->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800354 int v_reg = SRegToVReg(cu, info->s_reg);
355 StoreBaseDisp(cu, rMIPS_SP, VRegOffset(cu, v_reg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800356 }
357}
358
359/* Give access to the target-dependent FP register encoding to common code */
buzbee02031b12012-11-23 09:41:35 -0800360bool MipsCodegen::IsFpReg(int reg) {
buzbeeefc63692012-11-14 16:31:52 -0800361 return MIPS_FPREG(reg);
362}
363
buzbeeefc63692012-11-14 16:31:52 -0800364/* Clobber all regs that might be used by an external C call */
buzbee02031b12012-11-23 09:41:35 -0800365void MipsCodegen::ClobberCalleeSave(CompilationUnit *cu)
buzbeeefc63692012-11-14 16:31:52 -0800366{
buzbeefa57c472012-11-21 12:06:18 -0800367 Clobber(cu, r_ZERO);
368 Clobber(cu, r_AT);
369 Clobber(cu, r_V0);
370 Clobber(cu, r_V1);
371 Clobber(cu, r_A0);
372 Clobber(cu, r_A1);
373 Clobber(cu, r_A2);
374 Clobber(cu, r_A3);
375 Clobber(cu, r_T0);
376 Clobber(cu, r_T1);
377 Clobber(cu, r_T2);
378 Clobber(cu, r_T3);
379 Clobber(cu, r_T4);
380 Clobber(cu, r_T5);
381 Clobber(cu, r_T6);
382 Clobber(cu, r_T7);
383 Clobber(cu, r_T8);
384 Clobber(cu, r_T9);
385 Clobber(cu, r_K0);
386 Clobber(cu, r_K1);
387 Clobber(cu, r_GP);
388 Clobber(cu, r_FP);
389 Clobber(cu, r_RA);
390 Clobber(cu, r_F0);
391 Clobber(cu, r_F1);
392 Clobber(cu, r_F2);
393 Clobber(cu, r_F3);
394 Clobber(cu, r_F4);
395 Clobber(cu, r_F5);
396 Clobber(cu, r_F6);
397 Clobber(cu, r_F7);
398 Clobber(cu, r_F8);
399 Clobber(cu, r_F9);
400 Clobber(cu, r_F10);
401 Clobber(cu, r_F11);
402 Clobber(cu, r_F12);
403 Clobber(cu, r_F13);
404 Clobber(cu, r_F14);
405 Clobber(cu, r_F15);
buzbeeefc63692012-11-14 16:31:52 -0800406}
407
buzbee02031b12012-11-23 09:41:35 -0800408RegLocation MipsCodegen::GetReturnWideAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800409{
buzbee52a77fc2012-11-20 19:50:46 -0800410 UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
411 RegLocation res = LocCReturnWide();
buzbeeefc63692012-11-14 16:31:52 -0800412 return res;
413}
414
buzbee02031b12012-11-23 09:41:35 -0800415RegLocation MipsCodegen::GetReturnAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800416{
buzbee52a77fc2012-11-20 19:50:46 -0800417 UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
418 RegLocation res = LocCReturn();
buzbeeefc63692012-11-14 16:31:52 -0800419 return res;
420}
421
buzbee02031b12012-11-23 09:41:35 -0800422RegisterInfo* MipsCodegen::GetRegInfo(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800423{
buzbeefa57c472012-11-21 12:06:18 -0800424 return MIPS_FPREG(reg) ? &cu->reg_pool->FPRegs[reg & MIPS_FP_REG_MASK]
425 : &cu->reg_pool->core_regs[reg];
buzbeeefc63692012-11-14 16:31:52 -0800426}
427
428/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800429void MipsCodegen::LockCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800430{
buzbeefa57c472012-11-21 12:06:18 -0800431 LockTemp(cu, rMIPS_ARG0);
432 LockTemp(cu, rMIPS_ARG1);
433 LockTemp(cu, rMIPS_ARG2);
434 LockTemp(cu, rMIPS_ARG3);
buzbeeefc63692012-11-14 16:31:52 -0800435}
436
437/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800438void MipsCodegen::FreeCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800439{
buzbeefa57c472012-11-21 12:06:18 -0800440 FreeTemp(cu, rMIPS_ARG0);
441 FreeTemp(cu, rMIPS_ARG1);
442 FreeTemp(cu, rMIPS_ARG2);
443 FreeTemp(cu, rMIPS_ARG3);
buzbeeefc63692012-11-14 16:31:52 -0800444}
445
buzbee02031b12012-11-23 09:41:35 -0800446void MipsCodegen::GenMemBarrier(CompilationUnit *cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800447{
448#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800449 NewLIR1(cu, kMipsSync, 0 /* Only stype currently supported */);
buzbeeefc63692012-11-14 16:31:52 -0800450#endif
451}
452
453/*
454 * Alloc a pair of core registers, or a double. Low reg in low byte,
455 * high reg in next byte.
456 */
buzbee02031b12012-11-23 09:41:35 -0800457int MipsCodegen::AllocTypedTempPair(CompilationUnit *cu, bool fp_hint,
buzbeefa57c472012-11-21 12:06:18 -0800458 int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800459{
buzbeefa57c472012-11-21 12:06:18 -0800460 int high_reg;
461 int low_reg;
buzbeeefc63692012-11-14 16:31:52 -0800462 int res = 0;
463
buzbeefa57c472012-11-21 12:06:18 -0800464 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
465 low_reg = AllocTempDouble(cu);
466 high_reg = low_reg + 1;
467 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800468 return res;
469 }
buzbeeefc63692012-11-14 16:31:52 -0800470
buzbeefa57c472012-11-21 12:06:18 -0800471 low_reg = AllocTemp(cu);
472 high_reg = AllocTemp(cu);
473 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800474 return res;
475}
476
buzbee02031b12012-11-23 09:41:35 -0800477int MipsCodegen::AllocTypedTemp(CompilationUnit *cu, bool fp_hint, int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800478{
buzbeefa57c472012-11-21 12:06:18 -0800479 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
buzbeeefc63692012-11-14 16:31:52 -0800480{
buzbeefa57c472012-11-21 12:06:18 -0800481 return AllocTempFloat(cu);
buzbeeefc63692012-11-14 16:31:52 -0800482}
buzbeefa57c472012-11-21 12:06:18 -0800483 return AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800484}
485
buzbee02031b12012-11-23 09:41:35 -0800486void MipsCodegen::CompilerInitializeRegAlloc(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800487{
buzbeefa57c472012-11-21 12:06:18 -0800488 int num_regs = sizeof(core_regs)/sizeof(*core_regs);
489 int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
490 int num_temps = sizeof(core_temps)/sizeof(*core_temps);
buzbeefa57c472012-11-21 12:06:18 -0800491 int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
492 int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
buzbeecbd6d442012-11-17 14:11:25 -0800493 RegisterPool *pool =
buzbeefa57c472012-11-21 12:06:18 -0800494 static_cast<RegisterPool*>(NewMem(cu, sizeof(*pool), true, kAllocRegAlloc));
495 cu->reg_pool = pool;
496 pool->num_core_regs = num_regs;
497 pool->core_regs = static_cast<RegisterInfo*>
498 (NewMem(cu, num_regs * sizeof(*cu->reg_pool->core_regs), true, kAllocRegAlloc));
499 pool->num_fp_regs = num_fp_regs;
buzbeecbd6d442012-11-17 14:11:25 -0800500 pool->FPRegs = static_cast<RegisterInfo*>
buzbeefa57c472012-11-21 12:06:18 -0800501 (NewMem(cu, num_fp_regs * sizeof(*cu->reg_pool->FPRegs), true, kAllocRegAlloc));
502 CompilerInitPool(pool->core_regs, core_regs, pool->num_core_regs);
503 CompilerInitPool(pool->FPRegs, FpRegs, pool->num_fp_regs);
buzbeeefc63692012-11-14 16:31:52 -0800504 // Keep special registers from being allocated
buzbeefa57c472012-11-21 12:06:18 -0800505 for (int i = 0; i < num_reserved; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800506 if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
buzbeeefc63692012-11-14 16:31:52 -0800507 //To measure cost of suspend check
508 continue;
509 }
buzbeefa57c472012-11-21 12:06:18 -0800510 MarkInUse(cu, ReservedRegs[i]);
buzbeeefc63692012-11-14 16:31:52 -0800511 }
512 // Mark temp regs - all others not in use can be used for promotion
buzbeefa57c472012-11-21 12:06:18 -0800513 for (int i = 0; i < num_temps; i++) {
514 MarkTemp(cu, core_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800515 }
buzbeefa57c472012-11-21 12:06:18 -0800516 for (int i = 0; i < num_fp_temps; i++) {
517 MarkTemp(cu, fp_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800518 }
519 // Construct the alias map.
buzbeefa57c472012-11-21 12:06:18 -0800520 cu->phi_alias_map = static_cast<int*>
521 (NewMem(cu, cu->num_ssa_regs * sizeof(cu->phi_alias_map[0]), false, kAllocDFInfo));
522 for (int i = 0; i < cu->num_ssa_regs; i++) {
523 cu->phi_alias_map[i] = i;
buzbeeefc63692012-11-14 16:31:52 -0800524 }
buzbeefa57c472012-11-21 12:06:18 -0800525 for (MIR* phi = cu->phi_list; phi; phi = phi->meta.phi_next) {
526 int def_reg = phi->ssa_rep->defs[0];
527 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
528 for (int j = 0; j < cu->num_ssa_regs; j++) {
529 if (cu->phi_alias_map[j] == phi->ssa_rep->uses[i]) {
530 cu->phi_alias_map[j] = def_reg;
buzbeeefc63692012-11-14 16:31:52 -0800531 }
532 }
533 }
534 }
535}
536
buzbee02031b12012-11-23 09:41:35 -0800537void MipsCodegen::FreeRegLocTemps(CompilationUnit* cu, RegLocation rl_keep, RegLocation rl_free)
buzbeeefc63692012-11-14 16:31:52 -0800538{
buzbeefa57c472012-11-21 12:06:18 -0800539 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
540 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
buzbeeefc63692012-11-14 16:31:52 -0800541 // No overlap, free both
buzbeefa57c472012-11-21 12:06:18 -0800542 FreeTemp(cu, rl_free.low_reg);
543 FreeTemp(cu, rl_free.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800544 }
545}
546/*
547 * In the Arm code a it is typical to use the link register
548 * to hold the target address. However, for Mips we must
549 * ensure that all branch instructions can be restarted if
550 * there is a trap in the shadow. Allocate a temp register.
551 */
buzbee02031b12012-11-23 09:41:35 -0800552int MipsCodegen::LoadHelper(CompilationUnit* cu, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800553{
buzbeefa57c472012-11-21 12:06:18 -0800554 LoadWordDisp(cu, rMIPS_SELF, offset, r_T9);
buzbeeefc63692012-11-14 16:31:52 -0800555 return r_T9;
556}
557
buzbee02031b12012-11-23 09:41:35 -0800558void MipsCodegen::SpillCoreRegs(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800559{
buzbeefa57c472012-11-21 12:06:18 -0800560 if (cu->num_core_spills == 0) {
buzbeeefc63692012-11-14 16:31:52 -0800561 return;
562 }
buzbeefa57c472012-11-21 12:06:18 -0800563 uint32_t mask = cu->core_spill_mask;
564 int offset = cu->num_core_spills * 4;
565 OpRegImm(cu, kOpSub, rMIPS_SP, offset);
buzbeeefc63692012-11-14 16:31:52 -0800566 for (int reg = 0; mask; mask >>= 1, reg++) {
567 if (mask & 0x1) {
568 offset -= 4;
buzbeefa57c472012-11-21 12:06:18 -0800569 StoreWordDisp(cu, rMIPS_SP, offset, reg);
buzbeeefc63692012-11-14 16:31:52 -0800570 }
571 }
572}
573
buzbee02031b12012-11-23 09:41:35 -0800574void MipsCodegen::UnSpillCoreRegs(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800575{
buzbeefa57c472012-11-21 12:06:18 -0800576 if (cu->num_core_spills == 0) {
buzbeeefc63692012-11-14 16:31:52 -0800577 return;
578 }
buzbeefa57c472012-11-21 12:06:18 -0800579 uint32_t mask = cu->core_spill_mask;
580 int offset = cu->frame_size;
buzbeeefc63692012-11-14 16:31:52 -0800581 for (int reg = 0; mask; mask >>= 1, reg++) {
582 if (mask & 0x1) {
583 offset -= 4;
buzbeefa57c472012-11-21 12:06:18 -0800584 LoadWordDisp(cu, rMIPS_SP, offset, reg);
buzbeeefc63692012-11-14 16:31:52 -0800585 }
586 }
buzbeefa57c472012-11-21 12:06:18 -0800587 OpRegImm(cu, kOpAdd, rMIPS_SP, cu->frame_size);
buzbeeefc63692012-11-14 16:31:52 -0800588}
589
buzbee02031b12012-11-23 09:41:35 -0800590bool MipsCodegen::IsUnconditionalBranch(LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800591{
buzbeecbd6d442012-11-17 14:11:25 -0800592 return (lir->opcode == kMipsB);
buzbeeefc63692012-11-14 16:31:52 -0800593}
594
buzbeeefc63692012-11-14 16:31:52 -0800595/* Common initialization routine for an architecture family */
buzbee02031b12012-11-23 09:41:35 -0800596bool InitMipsCodegen(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800597{
buzbee02031b12012-11-23 09:41:35 -0800598 cu->cg.reset(new MipsCodegen());
599 for (int i = 0; i < kMipsLast; i++) {
600 if (MipsCodegen::EncodingMap[i].opcode != i) {
601 LOG(FATAL) << "Encoding order for " << MipsCodegen::EncodingMap[i].name
602 << " is wrong: expecting " << i << ", seeing "
603 << static_cast<int>(MipsCodegen::EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800604 }
605 }
buzbee02031b12012-11-23 09:41:35 -0800606 return true;
buzbeeefc63692012-11-14 16:31:52 -0800607}
608
buzbee02031b12012-11-23 09:41:35 -0800609uint64_t MipsCodegen::GetTargetInstFlags(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800610{
buzbee02031b12012-11-23 09:41:35 -0800611 return MipsCodegen::EncodingMap[opcode].flags;
buzbee1bc37c62012-11-20 13:35:41 -0800612}
613
buzbee02031b12012-11-23 09:41:35 -0800614const char* MipsCodegen::GetTargetInstName(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800615{
buzbee02031b12012-11-23 09:41:35 -0800616 return MipsCodegen::EncodingMap[opcode].name;
buzbee1bc37c62012-11-20 13:35:41 -0800617}
618
buzbee02031b12012-11-23 09:41:35 -0800619const char* MipsCodegen::GetTargetInstFmt(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800620{
buzbee02031b12012-11-23 09:41:35 -0800621 return MipsCodegen::EncodingMap[opcode].fmt;
buzbee1bc37c62012-11-20 13:35:41 -0800622}
623
buzbeeefc63692012-11-14 16:31:52 -0800624} // namespace art