blob: a254876e6044523e4b1a4b247e7f6ca89c7cc2a6 [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
buzbeeeaf09bc2012-11-15 14:51:41 -0800284void oatDumpResourceMask(LIR *lir, uint64_t mask, const char *prefix)
buzbeeefc63692012-11-14 16:31:52 -0800285{
286 char buf[256];
287 buf[0] = 0;
288 LIR *x86LIR = (LIR *) lir;
289
290 if (mask == ENCODE_ALL) {
291 strcpy(buf, "all");
292 } else {
293 char num[8];
294 int i;
295
296 for (i = 0; i < kX86RegEnd; i++) {
297 if (mask & (1ULL << i)) {
298 sprintf(num, "%d ", i);
299 strcat(buf, num);
300 }
301 }
302
303 if (mask & ENCODE_CCODE) {
304 strcat(buf, "cc ");
305 }
306 /* Memory bits */
307 if (x86LIR && (mask & ENCODE_DALVIK_REG)) {
308 sprintf(buf + strlen(buf), "dr%d%s", x86LIR->aliasInfo & 0xffff,
309 (x86LIR->aliasInfo & 0x80000000) ? "(+1)" : "");
310 }
311 if (mask & ENCODE_LITERAL) {
312 strcat(buf, "lit ");
313 }
314
315 if (mask & ENCODE_HEAP_REF) {
316 strcat(buf, "heap ");
317 }
318 if (mask & ENCODE_MUST_NOT_ALIAS) {
319 strcat(buf, "noalias ");
320 }
321 }
322 if (buf[0]) {
323 LOG(INFO) << prefix << ": " << buf;
324 }
325}
326void oatAdjustSpillMask(CompilationUnit* cUnit) {
327 // Adjustment for LR spilling, x86 has no LR so nothing to do here
328 cUnit->coreSpillMask |= (1 << rRET);
329 cUnit->numCoreSpills++;
330}
331
332/*
333 * Mark a callee-save fp register as promoted. Note that
334 * vpush/vpop uses contiguous register lists so we must
335 * include any holes in the mask. Associate holes with
336 * Dalvik register INVALID_VREG (0xFFFFU).
337 */
338void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg)
339{
340 UNIMPLEMENTED(WARNING) << "oatMarkPreservedSingle";
341#if 0
342 LOG(FATAL) << "No support yet for promoted FP regs";
343#endif
344}
345
346void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
347{
348 RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
349 RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
350 DCHECK(info1 && info2 && info1->pair && info2->pair &&
351 (info1->partner == info2->reg) &&
352 (info2->partner == info1->reg));
353 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
354 if (!(info1->isTemp && info2->isTemp)) {
355 /* Should not happen. If it does, there's a problem in evalLoc */
356 LOG(FATAL) << "Long half-temp, half-promoted";
357 }
358
359 info1->dirty = false;
360 info2->dirty = false;
361 if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg))
362 info1 = info2;
363 int vReg = SRegToVReg(cUnit, info1->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800364 storeBaseDispWide(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800365 }
366}
367
368void oatFlushReg(CompilationUnit* cUnit, int reg)
369{
370 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
371 if (info->live && info->dirty) {
372 info->dirty = false;
373 int vReg = SRegToVReg(cUnit, info->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800374 storeBaseDisp(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800375 }
376}
377
378/* Give access to the target-dependent FP register encoding to common code */
379bool oatIsFpReg(int reg) {
380 return X86_FPREG(reg);
381}
382
383uint32_t oatFpRegMask() {
384 return X86_FP_REG_MASK;
385}
386
387/* Clobber all regs that might be used by an external C call */
388extern void oatClobberCalleeSave(CompilationUnit *cUnit)
389{
390 oatClobber(cUnit, rAX);
391 oatClobber(cUnit, rCX);
392 oatClobber(cUnit, rDX);
393}
394
395extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) {
396 RegLocation res = locCReturnWide();
397 CHECK(res.lowReg == rAX);
398 CHECK(res.highReg == rDX);
399 oatClobber(cUnit, rAX);
400 oatClobber(cUnit, rDX);
401 oatMarkInUse(cUnit, rAX);
402 oatMarkInUse(cUnit, rDX);
403 oatMarkPair(cUnit, res.lowReg, res.highReg);
404 return res;
405}
406
407extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
408{
409 RegLocation res = locCReturn();
410 res.lowReg = rDX;
411 oatClobber(cUnit, rDX);
412 oatMarkInUse(cUnit, rDX);
413 return res;
414}
415
416extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
417{
418 return X86_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & X86_FP_REG_MASK]
419 : &cUnit->regPool->coreRegs[reg];
420}
421
422/* To be used when explicitly managing register use */
423extern void oatLockCallTemps(CompilationUnit* cUnit)
424{
425 oatLockTemp(cUnit, rX86_ARG0);
426 oatLockTemp(cUnit, rX86_ARG1);
427 oatLockTemp(cUnit, rX86_ARG2);
428 oatLockTemp(cUnit, rX86_ARG3);
429}
430
431/* To be used when explicitly managing register use */
432extern void oatFreeCallTemps(CompilationUnit* cUnit)
433{
434 oatFreeTemp(cUnit, rX86_ARG0);
435 oatFreeTemp(cUnit, rX86_ARG1);
436 oatFreeTemp(cUnit, rX86_ARG2);
437 oatFreeTemp(cUnit, rX86_ARG3);
438}
439
440/* Convert an instruction to a NOP */
441void oatNopLIR( LIR* lir)
442{
443 ((LIR*)lir)->flags.isNop = true;
444}
445
446/*
447 * Determine the initial instruction set to be used for this trace.
448 * Later components may decide to change this.
449 */
450InstructionSet oatInstructionSet()
451{
452 return kX86;
453}
454
455/* Architecture-specific initializations and checks go here */
456bool oatArchVariantInit(void)
457{
458 return true;
459}
460
buzbeeefc63692012-11-14 16:31:52 -0800461void oatGenMemBarrier(CompilationUnit *cUnit, int /* barrierKind */)
462{
463#if ANDROID_SMP != 0
464 // TODO: optimize fences
465 newLIR0(cUnit, kX86Mfence);
466#endif
467}
468/*
469 * Alloc a pair of core registers, or a double. Low reg in low byte,
470 * high reg in next byte.
471 */
472int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
473 int regClass)
474{
475 int highReg;
476 int lowReg;
477 int res = 0;
478
479 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
480 lowReg = oatAllocTempDouble(cUnit);
481 highReg = lowReg + 1;
482 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
483 return res;
484 }
485
486 lowReg = oatAllocTemp(cUnit);
487 highReg = oatAllocTemp(cUnit);
488 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
489 return res;
490}
491
492int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) {
493 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
494 return oatAllocTempFloat(cUnit);
495 }
496 return oatAllocTemp(cUnit);
497}
498
499void oatInitializeRegAlloc(CompilationUnit* cUnit) {
500 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
501 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
502 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
503 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
504 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
505 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
506 kAllocRegAlloc);
507 cUnit->regPool = pool;
508 pool->numCoreRegs = numRegs;
509 pool->coreRegs = (RegisterInfo *)
510 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), true,
511 kAllocRegAlloc);
512 pool->numFPRegs = numFPRegs;
513 pool->FPRegs = (RegisterInfo *)
514 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
515 kAllocRegAlloc);
516 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
517 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
518 // Keep special registers from being allocated
519 for (int i = 0; i < numReserved; i++) {
520 oatMarkInUse(cUnit, reservedRegs[i]);
521 }
522 // Mark temp regs - all others not in use can be used for promotion
523 for (int i = 0; i < numTemps; i++) {
524 oatMarkTemp(cUnit, coreTemps[i]);
525 }
526 for (int i = 0; i < numFPTemps; i++) {
527 oatMarkTemp(cUnit, fpTemps[i]);
528 }
529 // Construct the alias map.
530 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
531 sizeof(cUnit->phiAliasMap[0]), false,
532 kAllocDFInfo);
533 for (int i = 0; i < cUnit->numSSARegs; i++) {
534 cUnit->phiAliasMap[i] = i;
535 }
536 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
537 int defReg = phi->ssaRep->defs[0];
538 for (int i = 0; i < phi->ssaRep->numUses; i++) {
539 for (int j = 0; j < cUnit->numSSARegs; j++) {
540 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
541 cUnit->phiAliasMap[j] = defReg;
542 }
543 }
544 }
545 }
546}
547
548void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
549 RegLocation rlFree)
550{
551 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
552 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
553 // No overlap, free both
554 oatFreeTemp(cUnit, rlFree.lowReg);
555 oatFreeTemp(cUnit, rlFree.highReg);
556 }
557}
558
559void spillCoreRegs(CompilationUnit* cUnit) {
560 if (cUnit->numCoreSpills == 0) {
561 return;
562 }
563 // Spill mask not including fake return address register
564 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
565 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
566 for (int reg = 0; mask; mask >>= 1, reg++) {
567 if (mask & 0x1) {
568 storeWordDisp(cUnit, rX86_SP, offset, reg);
569 offset += 4;
570 }
571 }
572}
573
574void unSpillCoreRegs(CompilationUnit* cUnit) {
575 if (cUnit->numCoreSpills == 0) {
576 return;
577 }
578 // Spill mask not including fake return address register
579 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
580 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
581 for (int reg = 0; mask; mask >>= 1, reg++) {
582 if (mask & 0x1) {
583 loadWordDisp(cUnit, rX86_SP, offset, reg);
584 offset += 4;
585 }
586 }
587}
588
589/*
590 * Nop any unconditional branches that go to the next instruction.
591 * Note: new redundant branches may be inserted later, and we'll
592 * use a check in final instruction assembly to nop those out.
593 */
594void removeRedundantBranches(CompilationUnit* cUnit) {
595 LIR* thisLIR;
596
597 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
598 thisLIR != (LIR*) cUnit->lastLIRInsn;
599 thisLIR = NEXT_LIR(thisLIR)) {
600
601 /* Branch to the next instruction */
602 if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) {
603 LIR* nextLIR = thisLIR;
604
605 while (true) {
606 nextLIR = NEXT_LIR(nextLIR);
607
608 /*
609 * Is the branch target the next instruction?
610 */
611 if (nextLIR == (LIR*) thisLIR->target) {
612 thisLIR->flags.isNop = true;
613 break;
614 }
615
616 /*
617 * Found real useful stuff between the branch and the target.
618 * Need to explicitly check the lastLIRInsn here because it
619 * might be the last real instruction.
620 */
621 if (!isPseudoOpcode(nextLIR->opcode) ||
622 (nextLIR = (LIR*) cUnit->lastLIRInsn))
623 break;
624 }
625 }
626 }
627}
628
629/* Common initialization routine for an architecture family */
630bool oatArchInit() {
631 int i;
632
633 for (i = 0; i < kX86Last; i++) {
634 if (EncodingMap[i].opcode != i) {
635 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
636 << " is wrong: expecting " << i << ", seeing "
637 << (int)EncodingMap[i].opcode;
638 }
639 }
640
641 return oatArchVariantInit();
642}
643
644// Not used in x86
645int loadHelper(CompilationUnit* cUnit, int offset)
646{
647 LOG(FATAL) << "Unexpected use of loadHelper in x86";
648 return INVALID_REG;
649}
650
651} // namespace art