blob: c3c79f17b3a4f9e2e5ff186d90ed1f6a6f577937 [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 "x86_lir.h"
buzbee02031b12012-11-23 09:41:35 -080019#include "codegen_x86.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
27//FIXME: restore "static" when usage uncovered
buzbeefa57c472012-11-21 12:06:18 -080028/*static*/ int core_regs[] = {
buzbeeefc63692012-11-14 16:31:52 -080029 rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI
30#ifdef TARGET_REX_SUPPORT
31 r8, r9, r10, r11, r12, r13, r14, 15
32#endif
33};
buzbee52a77fc2012-11-20 19:50:46 -080034/*static*/ int ReservedRegs[] = {rX86_SP};
buzbeefa57c472012-11-21 12:06:18 -080035/*static*/ int core_temps[] = {rAX, rCX, rDX, rBX};
buzbee52a77fc2012-11-20 19:50:46 -080036/*static*/ int FpRegs[] = {
buzbeeefc63692012-11-14 16:31:52 -080037 fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
38#ifdef TARGET_REX_SUPPORT
39 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
40#endif
41};
buzbeefa57c472012-11-21 12:06:18 -080042/*static*/ int fp_temps[] = {
buzbeeefc63692012-11-14 16:31:52 -080043 fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
44#ifdef TARGET_REX_SUPPORT
45 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
46#endif
47};
48
buzbee02031b12012-11-23 09:41:35 -080049RegLocation X86Codegen::LocCReturn()
buzbeeefc63692012-11-14 16:31:52 -080050{
51 RegLocation res = X86_LOC_C_RETURN;
52 return res;
53}
54
buzbee02031b12012-11-23 09:41:35 -080055RegLocation X86Codegen::LocCReturnWide()
buzbeeefc63692012-11-14 16:31:52 -080056{
57 RegLocation res = X86_LOC_C_RETURN_WIDE;
58 return res;
59}
60
buzbee02031b12012-11-23 09:41:35 -080061RegLocation X86Codegen::LocCReturnFloat()
buzbeeefc63692012-11-14 16:31:52 -080062{
63 RegLocation res = X86_LOC_C_RETURN_FLOAT;
64 return res;
65}
66
buzbee02031b12012-11-23 09:41:35 -080067RegLocation X86Codegen::LocCReturnDouble()
buzbeeefc63692012-11-14 16:31:52 -080068{
69 RegLocation res = X86_LOC_C_RETURN_DOUBLE;
70 return res;
71}
72
73// Return a target-dependent special register.
buzbee02031b12012-11-23 09:41:35 -080074int X86Codegen::TargetReg(SpecialTargetRegister reg) {
buzbeeefc63692012-11-14 16:31:52 -080075 int res = INVALID_REG;
76 switch (reg) {
77 case kSelf: res = rX86_SELF; break;
78 case kSuspend: res = rX86_SUSPEND; break;
79 case kLr: res = rX86_LR; break;
80 case kPc: res = rX86_PC; break;
81 case kSp: res = rX86_SP; break;
82 case kArg0: res = rX86_ARG0; break;
83 case kArg1: res = rX86_ARG1; break;
84 case kArg2: res = rX86_ARG2; break;
85 case kArg3: res = rX86_ARG3; break;
86 case kFArg0: res = rX86_FARG0; break;
87 case kFArg1: res = rX86_FARG1; break;
88 case kFArg2: res = rX86_FARG2; break;
89 case kFArg3: res = rX86_FARG3; break;
90 case kRet0: res = rX86_RET0; break;
91 case kRet1: res = rX86_RET1; break;
92 case kInvokeTgt: res = rX86_INVOKE_TGT; break;
93 case kCount: res = rX86_COUNT; break;
94 }
95 return res;
96}
97
98// Create a double from a pair of singles.
buzbee02031b12012-11-23 09:41:35 -080099int X86Codegen::S2d(int low_reg, int high_reg)
buzbeeefc63692012-11-14 16:31:52 -0800100{
buzbeefa57c472012-11-21 12:06:18 -0800101 return X86_S2D(low_reg, high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800102}
103
buzbeeefc63692012-11-14 16:31:52 -0800104// Return mask to strip off fp reg flags and bias.
buzbee02031b12012-11-23 09:41:35 -0800105uint32_t X86Codegen::FpRegMask()
buzbeeefc63692012-11-14 16:31:52 -0800106{
107 return X86_FP_REG_MASK;
108}
109
110// True if both regs single, both core or both double.
buzbee02031b12012-11-23 09:41:35 -0800111bool X86Codegen::SameRegType(int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800112{
113 return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2));
114}
115
116/*
117 * Decode the register id.
118 */
buzbee02031b12012-11-23 09:41:35 -0800119uint64_t X86Codegen::GetRegMaskCommon(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800120{
buzbeeeaf09bc2012-11-15 14:51:41 -0800121 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800122 int shift;
buzbeefa57c472012-11-21 12:06:18 -0800123 int reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800124
buzbeefa57c472012-11-21 12:06:18 -0800125 reg_id = reg & 0xf;
buzbeeefc63692012-11-14 16:31:52 -0800126 /* Double registers in x86 are just a single FP register */
127 seed = 1;
128 /* FP register starts at bit position 16 */
129 shift = X86_FPREG(reg) ? kX86FPReg0 : 0;
130 /* Expand the double register id into single offset */
buzbeefa57c472012-11-21 12:06:18 -0800131 shift += reg_id;
buzbeeefc63692012-11-14 16:31:52 -0800132 return (seed << shift);
133}
134
buzbee02031b12012-11-23 09:41:35 -0800135uint64_t X86Codegen::GetPCUseDefEncoding()
buzbeeefc63692012-11-14 16:31:52 -0800136{
137 /*
138 * FIXME: might make sense to use a virtual resource encoding bit for pc. Might be
139 * able to clean up some of the x86/Arm_Mips differences
140 */
buzbee52a77fc2012-11-20 19:50:46 -0800141 LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for x86";
buzbeeefc63692012-11-14 16:31:52 -0800142 return 0ULL;
143}
144
buzbee02031b12012-11-23 09:41:35 -0800145void X86Codegen::SetupTargetResourceMasks(CompilationUnit* cu, LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800146{
buzbeefa57c472012-11-21 12:06:18 -0800147 DCHECK_EQ(cu->instruction_set, kX86);
buzbeeefc63692012-11-14 16:31:52 -0800148
149 // X86-specific resource map setup here.
buzbee02031b12012-11-23 09:41:35 -0800150 uint64_t flags = X86Codegen::EncodingMap[lir->opcode].flags;
buzbeeefc63692012-11-14 16:31:52 -0800151
152 if (flags & REG_USE_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800153 lir->use_mask |= ENCODE_X86_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800154 }
155
156 if (flags & REG_DEF_SP) {
buzbeefa57c472012-11-21 12:06:18 -0800157 lir->def_mask |= ENCODE_X86_REG_SP;
buzbeeefc63692012-11-14 16:31:52 -0800158 }
159
160 if (flags & REG_DEFA) {
buzbeefa57c472012-11-21 12:06:18 -0800161 SetupRegMask(cu, &lir->def_mask, rAX);
buzbeeefc63692012-11-14 16:31:52 -0800162 }
163
164 if (flags & REG_DEFD) {
buzbeefa57c472012-11-21 12:06:18 -0800165 SetupRegMask(cu, &lir->def_mask, rDX);
buzbeeefc63692012-11-14 16:31:52 -0800166 }
167 if (flags & REG_USEA) {
buzbeefa57c472012-11-21 12:06:18 -0800168 SetupRegMask(cu, &lir->use_mask, rAX);
buzbeeefc63692012-11-14 16:31:52 -0800169 }
170
171 if (flags & REG_USEC) {
buzbeefa57c472012-11-21 12:06:18 -0800172 SetupRegMask(cu, &lir->use_mask, rCX);
buzbeeefc63692012-11-14 16:31:52 -0800173 }
174
175 if (flags & REG_USED) {
buzbeefa57c472012-11-21 12:06:18 -0800176 SetupRegMask(cu, &lir->use_mask, rDX);
buzbeeefc63692012-11-14 16:31:52 -0800177 }
178}
179
180/* For dumping instructions */
181static const char* x86RegName[] = {
182 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
183 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
184};
185
186static const char* x86CondName[] = {
187 "O",
188 "NO",
189 "B/NAE/C",
190 "NB/AE/NC",
191 "Z/EQ",
192 "NZ/NE",
193 "BE/NA",
194 "NBE/A",
195 "S",
196 "NS",
197 "P/PE",
198 "NP/PO",
199 "L/NGE",
200 "NL/GE",
201 "LE/NG",
202 "NLE/G"
203};
204
205/*
206 * Interpret a format string and build a string no longer than size
207 * See format key in Assemble.cc.
208 */
buzbee02031b12012-11-23 09:41:35 -0800209std::string X86Codegen::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
buzbeeefc63692012-11-14 16:31:52 -0800210 std::string buf;
211 size_t i = 0;
212 size_t fmt_len = strlen(fmt);
213 while (i < fmt_len) {
214 if (fmt[i] != '!') {
215 buf += fmt[i];
216 i++;
217 } else {
218 i++;
219 DCHECK_LT(i, fmt_len);
220 char operand_number_ch = fmt[i];
221 i++;
222 if (operand_number_ch == '!') {
223 buf += "!";
224 } else {
225 int operand_number = operand_number_ch - '0';
226 DCHECK_LT(operand_number, 6); // Expect upto 6 LIR operands.
227 DCHECK_LT(i, fmt_len);
228 int operand = lir->operands[operand_number];
229 switch (fmt[i]) {
230 case 'c':
231 DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName));
232 buf += x86CondName[operand];
233 break;
234 case 'd':
235 buf += StringPrintf("%d", operand);
236 break;
237 case 'p': {
buzbeefa57c472012-11-21 12:06:18 -0800238 SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(operand);
239 buf += StringPrintf("0x%08x", tab_rec->offset);
buzbeeefc63692012-11-14 16:31:52 -0800240 break;
241 }
242 case 'r':
243 if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) {
244 int fp_reg = operand & X86_FP_REG_MASK;
245 buf += StringPrintf("xmm%d", fp_reg);
246 } else {
247 DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName));
248 buf += x86RegName[operand];
249 }
250 break;
251 case 't':
252 buf += StringPrintf("0x%08x (L%p)",
buzbeefa57c472012-11-21 12:06:18 -0800253 reinterpret_cast<uint32_t>(base_addr)
buzbeeefc63692012-11-14 16:31:52 -0800254 + lir->offset + operand, lir->target);
255 break;
256 default:
257 buf += StringPrintf("DecodeError '%c'", fmt[i]);
258 break;
259 }
260 i++;
261 }
262 }
263 }
264 return buf;
265}
266
buzbee02031b12012-11-23 09:41:35 -0800267void X86Codegen::DumpResourceMask(LIR *x86LIR, uint64_t mask, const char *prefix)
buzbeeefc63692012-11-14 16:31:52 -0800268{
269 char buf[256];
270 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800271
272 if (mask == ENCODE_ALL) {
273 strcpy(buf, "all");
274 } else {
275 char num[8];
276 int i;
277
278 for (i = 0; i < kX86RegEnd; i++) {
279 if (mask & (1ULL << i)) {
280 sprintf(num, "%d ", i);
281 strcat(buf, num);
282 }
283 }
284
285 if (mask & ENCODE_CCODE) {
286 strcat(buf, "cc ");
287 }
288 /* Memory bits */
289 if (x86LIR && (mask & ENCODE_DALVIK_REG)) {
buzbeefa57c472012-11-21 12:06:18 -0800290 sprintf(buf + strlen(buf), "dr%d%s", x86LIR->alias_info & 0xffff,
291 (x86LIR->alias_info & 0x80000000) ? "(+1)" : "");
buzbeeefc63692012-11-14 16:31:52 -0800292 }
293 if (mask & ENCODE_LITERAL) {
294 strcat(buf, "lit ");
295 }
296
297 if (mask & ENCODE_HEAP_REF) {
298 strcat(buf, "heap ");
299 }
300 if (mask & ENCODE_MUST_NOT_ALIAS) {
301 strcat(buf, "noalias ");
302 }
303 }
304 if (buf[0]) {
305 LOG(INFO) << prefix << ": " << buf;
306 }
307}
buzbee02031b12012-11-23 09:41:35 -0800308
309void X86Codegen::AdjustSpillMask(CompilationUnit* cu) {
buzbeeefc63692012-11-14 16:31:52 -0800310 // Adjustment for LR spilling, x86 has no LR so nothing to do here
buzbeefa57c472012-11-21 12:06:18 -0800311 cu->core_spill_mask |= (1 << rRET);
312 cu->num_core_spills++;
buzbeeefc63692012-11-14 16:31:52 -0800313}
314
315/*
316 * Mark a callee-save fp register as promoted. Note that
317 * vpush/vpop uses contiguous register lists so we must
318 * include any holes in the mask. Associate holes with
319 * Dalvik register INVALID_VREG (0xFFFFU).
320 */
buzbee02031b12012-11-23 09:41:35 -0800321void X86Codegen::MarkPreservedSingle(CompilationUnit* cu, int v_reg, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800322{
buzbee52a77fc2012-11-20 19:50:46 -0800323 UNIMPLEMENTED(WARNING) << "MarkPreservedSingle";
buzbeeefc63692012-11-14 16:31:52 -0800324#if 0
325 LOG(FATAL) << "No support yet for promoted FP regs";
326#endif
327}
328
buzbee02031b12012-11-23 09:41:35 -0800329void X86Codegen::FlushRegWide(CompilationUnit* cu, int reg1, int reg2)
buzbeeefc63692012-11-14 16:31:52 -0800330{
buzbeefa57c472012-11-21 12:06:18 -0800331 RegisterInfo* info1 = GetRegInfo(cu, reg1);
332 RegisterInfo* info2 = GetRegInfo(cu, reg2);
buzbeeefc63692012-11-14 16:31:52 -0800333 DCHECK(info1 && info2 && info1->pair && info2->pair &&
334 (info1->partner == info2->reg) &&
335 (info2->partner == info1->reg));
336 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
buzbeefa57c472012-11-21 12:06:18 -0800337 if (!(info1->is_temp && info2->is_temp)) {
338 /* Should not happen. If it does, there's a problem in eval_loc */
buzbeeefc63692012-11-14 16:31:52 -0800339 LOG(FATAL) << "Long half-temp, half-promoted";
340 }
341
342 info1->dirty = false;
343 info2->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800344 if (SRegToVReg(cu, info2->s_reg) < SRegToVReg(cu, info1->s_reg))
buzbeeefc63692012-11-14 16:31:52 -0800345 info1 = info2;
buzbeefa57c472012-11-21 12:06:18 -0800346 int v_reg = SRegToVReg(cu, info1->s_reg);
347 StoreBaseDispWide(cu, rX86_SP, VRegOffset(cu, v_reg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800348 }
349}
350
buzbee02031b12012-11-23 09:41:35 -0800351void X86Codegen::FlushReg(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800352{
buzbeefa57c472012-11-21 12:06:18 -0800353 RegisterInfo* info = GetRegInfo(cu, reg);
buzbeeefc63692012-11-14 16:31:52 -0800354 if (info->live && info->dirty) {
355 info->dirty = false;
buzbeefa57c472012-11-21 12:06:18 -0800356 int v_reg = SRegToVReg(cu, info->s_reg);
357 StoreBaseDisp(cu, rX86_SP, VRegOffset(cu, v_reg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800358 }
359}
360
361/* Give access to the target-dependent FP register encoding to common code */
buzbee02031b12012-11-23 09:41:35 -0800362bool X86Codegen::IsFpReg(int reg) {
buzbeeefc63692012-11-14 16:31:52 -0800363 return X86_FPREG(reg);
364}
365
buzbeeefc63692012-11-14 16:31:52 -0800366/* Clobber all regs that might be used by an external C call */
buzbee02031b12012-11-23 09:41:35 -0800367void X86Codegen::ClobberCalleeSave(CompilationUnit *cu)
buzbeeefc63692012-11-14 16:31:52 -0800368{
buzbeefa57c472012-11-21 12:06:18 -0800369 Clobber(cu, rAX);
370 Clobber(cu, rCX);
371 Clobber(cu, rDX);
buzbeeefc63692012-11-14 16:31:52 -0800372}
373
buzbee02031b12012-11-23 09:41:35 -0800374RegLocation X86Codegen::GetReturnWideAlt(CompilationUnit* cu) {
buzbee52a77fc2012-11-20 19:50:46 -0800375 RegLocation res = LocCReturnWide();
buzbeefa57c472012-11-21 12:06:18 -0800376 CHECK(res.low_reg == rAX);
377 CHECK(res.high_reg == rDX);
378 Clobber(cu, rAX);
379 Clobber(cu, rDX);
380 MarkInUse(cu, rAX);
381 MarkInUse(cu, rDX);
382 MarkPair(cu, res.low_reg, res.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800383 return res;
384}
385
buzbee02031b12012-11-23 09:41:35 -0800386RegLocation X86Codegen::GetReturnAlt(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800387{
buzbee52a77fc2012-11-20 19:50:46 -0800388 RegLocation res = LocCReturn();
buzbeefa57c472012-11-21 12:06:18 -0800389 res.low_reg = rDX;
390 Clobber(cu, rDX);
391 MarkInUse(cu, rDX);
buzbeeefc63692012-11-14 16:31:52 -0800392 return res;
393}
394
buzbee02031b12012-11-23 09:41:35 -0800395RegisterInfo* X86Codegen::GetRegInfo(CompilationUnit* cu, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800396{
buzbeefa57c472012-11-21 12:06:18 -0800397 return X86_FPREG(reg) ? &cu->reg_pool->FPRegs[reg & X86_FP_REG_MASK]
398 : &cu->reg_pool->core_regs[reg];
buzbeeefc63692012-11-14 16:31:52 -0800399}
400
401/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800402void X86Codegen::LockCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800403{
buzbeefa57c472012-11-21 12:06:18 -0800404 LockTemp(cu, rX86_ARG0);
405 LockTemp(cu, rX86_ARG1);
406 LockTemp(cu, rX86_ARG2);
407 LockTemp(cu, rX86_ARG3);
buzbeeefc63692012-11-14 16:31:52 -0800408}
409
410/* To be used when explicitly managing register use */
buzbee02031b12012-11-23 09:41:35 -0800411void X86Codegen::FreeCallTemps(CompilationUnit* cu)
buzbeeefc63692012-11-14 16:31:52 -0800412{
buzbeefa57c472012-11-21 12:06:18 -0800413 FreeTemp(cu, rX86_ARG0);
414 FreeTemp(cu, rX86_ARG1);
415 FreeTemp(cu, rX86_ARG2);
416 FreeTemp(cu, rX86_ARG3);
buzbeeefc63692012-11-14 16:31:52 -0800417}
418
buzbee02031b12012-11-23 09:41:35 -0800419void X86Codegen::GenMemBarrier(CompilationUnit *cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800420{
421#if ANDROID_SMP != 0
422 // TODO: optimize fences
buzbeefa57c472012-11-21 12:06:18 -0800423 NewLIR0(cu, kX86Mfence);
buzbeeefc63692012-11-14 16:31:52 -0800424#endif
425}
426/*
427 * Alloc a pair of core registers, or a double. Low reg in low byte,
428 * high reg in next byte.
429 */
buzbee02031b12012-11-23 09:41:35 -0800430int X86Codegen::AllocTypedTempPair(CompilationUnit *cu, bool fp_hint,
buzbeefa57c472012-11-21 12:06:18 -0800431 int reg_class)
buzbeeefc63692012-11-14 16:31:52 -0800432{
buzbeefa57c472012-11-21 12:06:18 -0800433 int high_reg;
434 int low_reg;
buzbeeefc63692012-11-14 16:31:52 -0800435 int res = 0;
436
buzbeefa57c472012-11-21 12:06:18 -0800437 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
438 low_reg = AllocTempDouble(cu);
439 high_reg = low_reg + 1;
440 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800441 return res;
442 }
443
buzbeefa57c472012-11-21 12:06:18 -0800444 low_reg = AllocTemp(cu);
445 high_reg = AllocTemp(cu);
446 res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
buzbeeefc63692012-11-14 16:31:52 -0800447 return res;
448}
449
buzbee02031b12012-11-23 09:41:35 -0800450int X86Codegen::AllocTypedTemp(CompilationUnit *cu, bool fp_hint, int reg_class) {
buzbeefa57c472012-11-21 12:06:18 -0800451 if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
452 return AllocTempFloat(cu);
buzbeeefc63692012-11-14 16:31:52 -0800453 }
buzbeefa57c472012-11-21 12:06:18 -0800454 return AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800455}
456
buzbee02031b12012-11-23 09:41:35 -0800457void X86Codegen::CompilerInitializeRegAlloc(CompilationUnit* cu) {
buzbeefa57c472012-11-21 12:06:18 -0800458 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);
buzbeecbd6d442012-11-17 14:11:25 -0800463 RegisterPool *pool =
buzbeefa57c472012-11-21 12:06:18 -0800464 static_cast<RegisterPool*>(NewMem(cu, sizeof(*pool), true, kAllocRegAlloc));
465 cu->reg_pool = pool;
466 pool->num_core_regs = num_regs;
467 pool->core_regs =
468 static_cast<RegisterInfo*>(NewMem(cu, num_regs * sizeof(*cu->reg_pool->core_regs),
buzbeecbd6d442012-11-17 14:11:25 -0800469 true, kAllocRegAlloc));
buzbeefa57c472012-11-21 12:06:18 -0800470 pool->num_fp_regs = num_fp_regs;
buzbeecbd6d442012-11-17 14:11:25 -0800471 pool->FPRegs =
buzbeefa57c472012-11-21 12:06:18 -0800472 static_cast<RegisterInfo *>(NewMem(cu, num_fp_regs * sizeof(*cu->reg_pool->FPRegs),
buzbeecbd6d442012-11-17 14:11:25 -0800473 true, kAllocRegAlloc));
buzbeefa57c472012-11-21 12:06:18 -0800474 CompilerInitPool(pool->core_regs, core_regs, pool->num_core_regs);
475 CompilerInitPool(pool->FPRegs, FpRegs, pool->num_fp_regs);
buzbeeefc63692012-11-14 16:31:52 -0800476 // Keep special registers from being allocated
buzbeefa57c472012-11-21 12:06:18 -0800477 for (int i = 0; i < num_reserved; i++) {
478 MarkInUse(cu, ReservedRegs[i]);
buzbeeefc63692012-11-14 16:31:52 -0800479 }
480 // Mark temp regs - all others not in use can be used for promotion
buzbeefa57c472012-11-21 12:06:18 -0800481 for (int i = 0; i < num_temps; i++) {
482 MarkTemp(cu, core_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800483 }
buzbeefa57c472012-11-21 12:06:18 -0800484 for (int i = 0; i < num_fp_temps; i++) {
485 MarkTemp(cu, fp_temps[i]);
buzbeeefc63692012-11-14 16:31:52 -0800486 }
487 // Construct the alias map.
buzbeefa57c472012-11-21 12:06:18 -0800488 cu->phi_alias_map = static_cast<int*>
489 (NewMem(cu, cu->num_ssa_regs * sizeof(cu->phi_alias_map[0]), false, kAllocDFInfo));
490 for (int i = 0; i < cu->num_ssa_regs; i++) {
491 cu->phi_alias_map[i] = i;
buzbeeefc63692012-11-14 16:31:52 -0800492 }
buzbee28c9a832012-11-21 15:39:13 -0800493 for (MIR* phi = cu->phi_list; phi != NULL; phi = phi->meta.phi_next) {
buzbeefa57c472012-11-21 12:06:18 -0800494 int def_reg = phi->ssa_rep->defs[0];
495 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
496 for (int j = 0; j < cu->num_ssa_regs; j++) {
497 if (cu->phi_alias_map[j] == phi->ssa_rep->uses[i]) {
498 cu->phi_alias_map[j] = def_reg;
buzbeeefc63692012-11-14 16:31:52 -0800499 }
500 }
501 }
502 }
503}
504
buzbee02031b12012-11-23 09:41:35 -0800505void X86Codegen::FreeRegLocTemps(CompilationUnit* cu, RegLocation rl_keep,
buzbeefa57c472012-11-21 12:06:18 -0800506 RegLocation rl_free)
buzbeeefc63692012-11-14 16:31:52 -0800507{
buzbeefa57c472012-11-21 12:06:18 -0800508 if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
509 (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
buzbeeefc63692012-11-14 16:31:52 -0800510 // No overlap, free both
buzbeefa57c472012-11-21 12:06:18 -0800511 FreeTemp(cu, rl_free.low_reg);
512 FreeTemp(cu, rl_free.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800513 }
514}
515
buzbee02031b12012-11-23 09:41:35 -0800516void X86Codegen::SpillCoreRegs(CompilationUnit* cu) {
buzbeefa57c472012-11-21 12:06:18 -0800517 if (cu->num_core_spills == 0) {
buzbeeefc63692012-11-14 16:31:52 -0800518 return;
519 }
520 // Spill mask not including fake return address register
buzbeefa57c472012-11-21 12:06:18 -0800521 uint32_t mask = cu->core_spill_mask & ~(1 << rRET);
522 int offset = cu->frame_size - (4 * cu->num_core_spills);
buzbeeefc63692012-11-14 16:31:52 -0800523 for (int reg = 0; mask; mask >>= 1, reg++) {
524 if (mask & 0x1) {
buzbeefa57c472012-11-21 12:06:18 -0800525 StoreWordDisp(cu, rX86_SP, offset, reg);
buzbeeefc63692012-11-14 16:31:52 -0800526 offset += 4;
527 }
528 }
529}
530
buzbee02031b12012-11-23 09:41:35 -0800531void X86Codegen::UnSpillCoreRegs(CompilationUnit* cu) {
buzbeefa57c472012-11-21 12:06:18 -0800532 if (cu->num_core_spills == 0) {
buzbeeefc63692012-11-14 16:31:52 -0800533 return;
534 }
535 // Spill mask not including fake return address register
buzbeefa57c472012-11-21 12:06:18 -0800536 uint32_t mask = cu->core_spill_mask & ~(1 << rRET);
537 int offset = cu->frame_size - (4 * cu->num_core_spills);
buzbeeefc63692012-11-14 16:31:52 -0800538 for (int reg = 0; mask; mask >>= 1, reg++) {
539 if (mask & 0x1) {
buzbeefa57c472012-11-21 12:06:18 -0800540 LoadWordDisp(cu, rX86_SP, offset, reg);
buzbeeefc63692012-11-14 16:31:52 -0800541 offset += 4;
542 }
543 }
544}
545
buzbee02031b12012-11-23 09:41:35 -0800546bool X86Codegen::IsUnconditionalBranch(LIR* lir)
buzbeecbd6d442012-11-17 14:11:25 -0800547{
548 return (lir->opcode == kX86Jmp8 || lir->opcode == kX86Jmp32);
buzbeeefc63692012-11-14 16:31:52 -0800549}
550
551/* Common initialization routine for an architecture family */
buzbee02031b12012-11-23 09:41:35 -0800552bool InitX86Codegen(CompilationUnit* cu) {
553 cu->cg.reset(new X86Codegen());
554 for (int i = 0; i < kX86Last; i++) {
555 if (X86Codegen::EncodingMap[i].opcode != i) {
556 LOG(FATAL) << "Encoding order for " << X86Codegen::EncodingMap[i].name
buzbeeefc63692012-11-14 16:31:52 -0800557 << " is wrong: expecting " << i << ", seeing "
buzbee02031b12012-11-23 09:41:35 -0800558 << static_cast<int>(X86Codegen::EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800559 }
560 }
buzbee02031b12012-11-23 09:41:35 -0800561 return true;
buzbeeefc63692012-11-14 16:31:52 -0800562}
563
564// Not used in x86
buzbee02031b12012-11-23 09:41:35 -0800565int X86Codegen::LoadHelper(CompilationUnit* cu, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800566{
buzbee52a77fc2012-11-20 19:50:46 -0800567 LOG(FATAL) << "Unexpected use of LoadHelper in x86";
buzbeeefc63692012-11-14 16:31:52 -0800568 return INVALID_REG;
569}
570
buzbee02031b12012-11-23 09:41:35 -0800571uint64_t X86Codegen::GetTargetInstFlags(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800572{
buzbee02031b12012-11-23 09:41:35 -0800573 return X86Codegen::EncodingMap[opcode].flags;
buzbee1bc37c62012-11-20 13:35:41 -0800574}
575
buzbee02031b12012-11-23 09:41:35 -0800576const char* X86Codegen::GetTargetInstName(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800577{
buzbee02031b12012-11-23 09:41:35 -0800578 return X86Codegen::EncodingMap[opcode].name;
buzbee1bc37c62012-11-20 13:35:41 -0800579}
580
buzbee02031b12012-11-23 09:41:35 -0800581const char* X86Codegen::GetTargetInstFmt(int opcode)
buzbee1bc37c62012-11-20 13:35:41 -0800582{
buzbee02031b12012-11-23 09:41:35 -0800583 return X86Codegen::EncodingMap[opcode].fmt;
buzbee1bc37c62012-11-20 13:35:41 -0800584}
585
buzbeeefc63692012-11-14 16:31:52 -0800586} // namespace art