blob: b6440a759d06eaf9cfebe9acd31edcc712468c92 [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"
buzbeeeaf09bc2012-11-15 14:51:41 -080019#include "../ralloc_util.h"
20#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080021
22#include <string>
23
24namespace art {
25
26//FIXME: restore "static" when usage uncovered
27/*static*/ int coreRegs[] = {
28 rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI
29#ifdef TARGET_REX_SUPPORT
30 r8, r9, r10, r11, r12, r13, r14, 15
31#endif
32};
33/*static*/ int reservedRegs[] = {rX86_SP};
34/*static*/ int coreTemps[] = {rAX, rCX, rDX, rBX};
35/*static*/ int fpRegs[] = {
36 fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
37#ifdef TARGET_REX_SUPPORT
38 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
39#endif
40};
41/*static*/ int fpTemps[] = {
42 fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
43#ifdef TARGET_REX_SUPPORT
44 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
45#endif
46};
47
48RegLocation locCReturn()
49{
50 RegLocation res = X86_LOC_C_RETURN;
51 return res;
52}
53
54RegLocation locCReturnWide()
55{
56 RegLocation res = X86_LOC_C_RETURN_WIDE;
57 return res;
58}
59
60RegLocation locCReturnFloat()
61{
62 RegLocation res = X86_LOC_C_RETURN_FLOAT;
63 return res;
64}
65
66RegLocation locCReturnDouble()
67{
68 RegLocation res = X86_LOC_C_RETURN_DOUBLE;
69 return res;
70}
71
72// Return a target-dependent special register.
73int targetReg(SpecialTargetRegister reg) {
74 int res = INVALID_REG;
75 switch (reg) {
76 case kSelf: res = rX86_SELF; break;
77 case kSuspend: res = rX86_SUSPEND; break;
78 case kLr: res = rX86_LR; break;
79 case kPc: res = rX86_PC; break;
80 case kSp: res = rX86_SP; break;
81 case kArg0: res = rX86_ARG0; break;
82 case kArg1: res = rX86_ARG1; break;
83 case kArg2: res = rX86_ARG2; break;
84 case kArg3: res = rX86_ARG3; break;
85 case kFArg0: res = rX86_FARG0; break;
86 case kFArg1: res = rX86_FARG1; break;
87 case kFArg2: res = rX86_FARG2; break;
88 case kFArg3: res = rX86_FARG3; break;
89 case kRet0: res = rX86_RET0; break;
90 case kRet1: res = rX86_RET1; break;
91 case kInvokeTgt: res = rX86_INVOKE_TGT; break;
92 case kCount: res = rX86_COUNT; break;
93 }
94 return res;
95}
96
97// Create a double from a pair of singles.
98int s2d(int lowReg, int highReg)
99{
100 return X86_S2D(lowReg, highReg);
101}
102
103// Is reg a single or double?
104bool fpReg(int reg)
105{
106 return X86_FPREG(reg);
107}
108
109// Is reg a single?
110bool singleReg(int reg)
111{
112 return X86_SINGLEREG(reg);
113}
114
115// Is reg a double?
116bool doubleReg(int reg)
117{
118 return X86_DOUBLEREG(reg);
119}
120
121// Return mask to strip off fp reg flags and bias.
122uint32_t fpRegMask()
123{
124 return X86_FP_REG_MASK;
125}
126
127// True if both regs single, both core or both double.
128bool sameRegType(int reg1, int reg2)
129{
130 return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2));
131}
132
133/*
134 * Decode the register id.
135 */
buzbeeeaf09bc2012-11-15 14:51:41 -0800136uint64_t getRegMaskCommon(CompilationUnit* cUnit, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800137{
buzbeeeaf09bc2012-11-15 14:51:41 -0800138 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800139 int shift;
140 int regId;
141
142 regId = reg & 0xf;
143 /* Double registers in x86 are just a single FP register */
144 seed = 1;
145 /* FP register starts at bit position 16 */
146 shift = X86_FPREG(reg) ? kX86FPReg0 : 0;
147 /* Expand the double register id into single offset */
148 shift += regId;
149 return (seed << shift);
150}
151
152uint64_t getPCUseDefEncoding()
153{
154 /*
155 * FIXME: might make sense to use a virtual resource encoding bit for pc. Might be
156 * able to clean up some of the x86/Arm_Mips differences
157 */
158 LOG(FATAL) << "Unexpected call to getPCUseDefEncoding for x86";
159 return 0ULL;
160}
161
162void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir)
163{
164 DCHECK_EQ(cUnit->instructionSet, kX86);
165
166 // X86-specific resource map setup here.
167 uint64_t flags = EncodingMap[lir->opcode].flags;
168
169 if (flags & REG_USE_SP) {
170 lir->useMask |= ENCODE_X86_REG_SP;
171 }
172
173 if (flags & REG_DEF_SP) {
174 lir->defMask |= ENCODE_X86_REG_SP;
175 }
176
177 if (flags & REG_DEFA) {
178 oatSetupRegMask(cUnit, &lir->defMask, rAX);
179 }
180
181 if (flags & REG_DEFD) {
182 oatSetupRegMask(cUnit, &lir->defMask, rDX);
183 }
184 if (flags & REG_USEA) {
185 oatSetupRegMask(cUnit, &lir->useMask, rAX);
186 }
187
188 if (flags & REG_USEC) {
189 oatSetupRegMask(cUnit, &lir->useMask, rCX);
190 }
191
192 if (flags & REG_USED) {
193 oatSetupRegMask(cUnit, &lir->useMask, rDX);
194 }
195}
196
197/* For dumping instructions */
198static const char* x86RegName[] = {
199 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
200 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
201};
202
203static const char* x86CondName[] = {
204 "O",
205 "NO",
206 "B/NAE/C",
207 "NB/AE/NC",
208 "Z/EQ",
209 "NZ/NE",
210 "BE/NA",
211 "NBE/A",
212 "S",
213 "NS",
214 "P/PE",
215 "NP/PO",
216 "L/NGE",
217 "NL/GE",
218 "LE/NG",
219 "NLE/G"
220};
221
222/*
223 * Interpret a format string and build a string no longer than size
224 * See format key in Assemble.cc.
225 */
226std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) {
227 std::string buf;
228 size_t i = 0;
229 size_t fmt_len = strlen(fmt);
230 while (i < fmt_len) {
231 if (fmt[i] != '!') {
232 buf += fmt[i];
233 i++;
234 } else {
235 i++;
236 DCHECK_LT(i, fmt_len);
237 char operand_number_ch = fmt[i];
238 i++;
239 if (operand_number_ch == '!') {
240 buf += "!";
241 } else {
242 int operand_number = operand_number_ch - '0';
243 DCHECK_LT(operand_number, 6); // Expect upto 6 LIR operands.
244 DCHECK_LT(i, fmt_len);
245 int operand = lir->operands[operand_number];
246 switch (fmt[i]) {
247 case 'c':
248 DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName));
249 buf += x86CondName[operand];
250 break;
251 case 'd':
252 buf += StringPrintf("%d", operand);
253 break;
254 case 'p': {
255 SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(operand);
256 buf += StringPrintf("0x%08x", tabRec->offset);
257 break;
258 }
259 case 'r':
260 if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) {
261 int fp_reg = operand & X86_FP_REG_MASK;
262 buf += StringPrintf("xmm%d", fp_reg);
263 } else {
264 DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName));
265 buf += x86RegName[operand];
266 }
267 break;
268 case 't':
269 buf += StringPrintf("0x%08x (L%p)",
270 reinterpret_cast<uint32_t>(baseAddr)
271 + lir->offset + operand, lir->target);
272 break;
273 default:
274 buf += StringPrintf("DecodeError '%c'", fmt[i]);
275 break;
276 }
277 i++;
278 }
279 }
280 }
281 return buf;
282}
283
buzbeecbd6d442012-11-17 14:11:25 -0800284void oatDumpResourceMask(LIR *x86LIR, uint64_t mask, const char *prefix)
buzbeeefc63692012-11-14 16:31:52 -0800285{
286 char buf[256];
287 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800288
289 if (mask == ENCODE_ALL) {
290 strcpy(buf, "all");
291 } else {
292 char num[8];
293 int i;
294
295 for (i = 0; i < kX86RegEnd; i++) {
296 if (mask & (1ULL << i)) {
297 sprintf(num, "%d ", i);
298 strcat(buf, num);
299 }
300 }
301
302 if (mask & ENCODE_CCODE) {
303 strcat(buf, "cc ");
304 }
305 /* Memory bits */
306 if (x86LIR && (mask & ENCODE_DALVIK_REG)) {
307 sprintf(buf + strlen(buf), "dr%d%s", x86LIR->aliasInfo & 0xffff,
308 (x86LIR->aliasInfo & 0x80000000) ? "(+1)" : "");
309 }
310 if (mask & ENCODE_LITERAL) {
311 strcat(buf, "lit ");
312 }
313
314 if (mask & ENCODE_HEAP_REF) {
315 strcat(buf, "heap ");
316 }
317 if (mask & ENCODE_MUST_NOT_ALIAS) {
318 strcat(buf, "noalias ");
319 }
320 }
321 if (buf[0]) {
322 LOG(INFO) << prefix << ": " << buf;
323 }
324}
325void oatAdjustSpillMask(CompilationUnit* cUnit) {
326 // Adjustment for LR spilling, x86 has no LR so nothing to do here
327 cUnit->coreSpillMask |= (1 << rRET);
328 cUnit->numCoreSpills++;
329}
330
331/*
332 * Mark a callee-save fp register as promoted. Note that
333 * vpush/vpop uses contiguous register lists so we must
334 * include any holes in the mask. Associate holes with
335 * Dalvik register INVALID_VREG (0xFFFFU).
336 */
337void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg)
338{
339 UNIMPLEMENTED(WARNING) << "oatMarkPreservedSingle";
340#if 0
341 LOG(FATAL) << "No support yet for promoted FP regs";
342#endif
343}
344
345void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
346{
347 RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
348 RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
349 DCHECK(info1 && info2 && info1->pair && info2->pair &&
350 (info1->partner == info2->reg) &&
351 (info2->partner == info1->reg));
352 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
353 if (!(info1->isTemp && info2->isTemp)) {
354 /* Should not happen. If it does, there's a problem in evalLoc */
355 LOG(FATAL) << "Long half-temp, half-promoted";
356 }
357
358 info1->dirty = false;
359 info2->dirty = false;
360 if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg))
361 info1 = info2;
362 int vReg = SRegToVReg(cUnit, info1->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800363 storeBaseDispWide(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800364 }
365}
366
367void oatFlushReg(CompilationUnit* cUnit, int reg)
368{
369 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
370 if (info->live && info->dirty) {
371 info->dirty = false;
372 int vReg = SRegToVReg(cUnit, info->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800373 storeBaseDisp(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800374 }
375}
376
377/* Give access to the target-dependent FP register encoding to common code */
378bool oatIsFpReg(int reg) {
379 return X86_FPREG(reg);
380}
381
382uint32_t oatFpRegMask() {
383 return X86_FP_REG_MASK;
384}
385
386/* Clobber all regs that might be used by an external C call */
387extern void oatClobberCalleeSave(CompilationUnit *cUnit)
388{
389 oatClobber(cUnit, rAX);
390 oatClobber(cUnit, rCX);
391 oatClobber(cUnit, rDX);
392}
393
394extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) {
395 RegLocation res = locCReturnWide();
396 CHECK(res.lowReg == rAX);
397 CHECK(res.highReg == rDX);
398 oatClobber(cUnit, rAX);
399 oatClobber(cUnit, rDX);
400 oatMarkInUse(cUnit, rAX);
401 oatMarkInUse(cUnit, rDX);
402 oatMarkPair(cUnit, res.lowReg, res.highReg);
403 return res;
404}
405
406extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
407{
408 RegLocation res = locCReturn();
409 res.lowReg = rDX;
410 oatClobber(cUnit, rDX);
411 oatMarkInUse(cUnit, rDX);
412 return res;
413}
414
415extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
416{
417 return X86_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & X86_FP_REG_MASK]
418 : &cUnit->regPool->coreRegs[reg];
419}
420
421/* To be used when explicitly managing register use */
422extern void oatLockCallTemps(CompilationUnit* cUnit)
423{
424 oatLockTemp(cUnit, rX86_ARG0);
425 oatLockTemp(cUnit, rX86_ARG1);
426 oatLockTemp(cUnit, rX86_ARG2);
427 oatLockTemp(cUnit, rX86_ARG3);
428}
429
430/* To be used when explicitly managing register use */
431extern void oatFreeCallTemps(CompilationUnit* cUnit)
432{
433 oatFreeTemp(cUnit, rX86_ARG0);
434 oatFreeTemp(cUnit, rX86_ARG1);
435 oatFreeTemp(cUnit, rX86_ARG2);
436 oatFreeTemp(cUnit, rX86_ARG3);
437}
438
buzbeeefc63692012-11-14 16:31:52 -0800439/*
440 * Determine the initial instruction set to be used for this trace.
441 * Later components may decide to change this.
442 */
443InstructionSet oatInstructionSet()
444{
445 return kX86;
446}
447
448/* Architecture-specific initializations and checks go here */
449bool oatArchVariantInit(void)
450{
451 return true;
452}
453
buzbeeefc63692012-11-14 16:31:52 -0800454void oatGenMemBarrier(CompilationUnit *cUnit, int /* barrierKind */)
455{
456#if ANDROID_SMP != 0
457 // TODO: optimize fences
458 newLIR0(cUnit, kX86Mfence);
459#endif
460}
461/*
462 * Alloc a pair of core registers, or a double. Low reg in low byte,
463 * high reg in next byte.
464 */
465int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
466 int regClass)
467{
468 int highReg;
469 int lowReg;
470 int res = 0;
471
472 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
473 lowReg = oatAllocTempDouble(cUnit);
474 highReg = lowReg + 1;
475 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
476 return res;
477 }
478
479 lowReg = oatAllocTemp(cUnit);
480 highReg = oatAllocTemp(cUnit);
481 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
482 return res;
483}
484
485int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) {
486 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
487 return oatAllocTempFloat(cUnit);
488 }
489 return oatAllocTemp(cUnit);
490}
491
492void oatInitializeRegAlloc(CompilationUnit* cUnit) {
493 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
494 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
495 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
496 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
497 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
buzbeecbd6d442012-11-17 14:11:25 -0800498 RegisterPool *pool =
499 static_cast<RegisterPool*>(oatNew(cUnit, sizeof(*pool), true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800500 cUnit->regPool = pool;
501 pool->numCoreRegs = numRegs;
buzbeecbd6d442012-11-17 14:11:25 -0800502 pool->coreRegs =
503 static_cast<RegisterInfo*>(oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
504 true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800505 pool->numFPRegs = numFPRegs;
buzbeecbd6d442012-11-17 14:11:25 -0800506 pool->FPRegs =
507 static_cast<RegisterInfo *>(oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs),
508 true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800509 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
510 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
511 // Keep special registers from being allocated
512 for (int i = 0; i < numReserved; i++) {
513 oatMarkInUse(cUnit, reservedRegs[i]);
514 }
515 // Mark temp regs - all others not in use can be used for promotion
516 for (int i = 0; i < numTemps; i++) {
517 oatMarkTemp(cUnit, coreTemps[i]);
518 }
519 for (int i = 0; i < numFPTemps; i++) {
520 oatMarkTemp(cUnit, fpTemps[i]);
521 }
522 // Construct the alias map.
buzbeecbd6d442012-11-17 14:11:25 -0800523 cUnit->phiAliasMap = static_cast<int*>
524 (oatNew(cUnit, cUnit->numSSARegs * sizeof(cUnit->phiAliasMap[0]), false, kAllocDFInfo));
buzbeeefc63692012-11-14 16:31:52 -0800525 for (int i = 0; i < cUnit->numSSARegs; i++) {
526 cUnit->phiAliasMap[i] = i;
527 }
528 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
529 int defReg = phi->ssaRep->defs[0];
530 for (int i = 0; i < phi->ssaRep->numUses; i++) {
531 for (int j = 0; j < cUnit->numSSARegs; j++) {
532 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
533 cUnit->phiAliasMap[j] = defReg;
534 }
535 }
536 }
537 }
538}
539
540void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
541 RegLocation rlFree)
542{
543 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
544 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
545 // No overlap, free both
546 oatFreeTemp(cUnit, rlFree.lowReg);
547 oatFreeTemp(cUnit, rlFree.highReg);
548 }
549}
550
551void spillCoreRegs(CompilationUnit* cUnit) {
552 if (cUnit->numCoreSpills == 0) {
553 return;
554 }
555 // Spill mask not including fake return address register
556 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
557 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
558 for (int reg = 0; mask; mask >>= 1, reg++) {
559 if (mask & 0x1) {
560 storeWordDisp(cUnit, rX86_SP, offset, reg);
561 offset += 4;
562 }
563 }
564}
565
566void unSpillCoreRegs(CompilationUnit* cUnit) {
567 if (cUnit->numCoreSpills == 0) {
568 return;
569 }
570 // Spill mask not including fake return address register
571 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
572 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
573 for (int reg = 0; mask; mask >>= 1, reg++) {
574 if (mask & 0x1) {
575 loadWordDisp(cUnit, rX86_SP, offset, reg);
576 offset += 4;
577 }
578 }
579}
580
buzbeecbd6d442012-11-17 14:11:25 -0800581bool branchUnconditional(LIR* lir)
582{
583 return (lir->opcode == kX86Jmp8 || lir->opcode == kX86Jmp32);
buzbeeefc63692012-11-14 16:31:52 -0800584}
585
586/* Common initialization routine for an architecture family */
587bool oatArchInit() {
588 int i;
589
590 for (i = 0; i < kX86Last; i++) {
591 if (EncodingMap[i].opcode != i) {
592 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
593 << " is wrong: expecting " << i << ", seeing "
buzbeecbd6d442012-11-17 14:11:25 -0800594 << static_cast<int>(EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800595 }
596 }
597
598 return oatArchVariantInit();
599}
600
601// Not used in x86
602int loadHelper(CompilationUnit* cUnit, int offset)
603{
604 LOG(FATAL) << "Unexpected use of loadHelper in x86";
605 return INVALID_REG;
606}
607
608} // namespace art