diff options
Diffstat (limited to 'src/compiler/codegen/x86')
15 files changed, 1122 insertions, 1218 deletions
diff --git a/src/compiler/codegen/x86/ArchFactory.cc b/src/compiler/codegen/x86/ArchFactory.cc deleted file mode 100644 index 0ed68484f4..0000000000 --- a/src/compiler/codegen/x86/ArchFactory.cc +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This file contains x86-specific codegen factory support. */ - -namespace art { - -bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - // Compute (r1:r0) = (r1:r0) + (r2:r3) - opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2 - opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - // Compute (r1:r0) = (r1:r0) + (r2:r3) - opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2 - opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - // Compute (r1:r0) = (r1:r0) + (r2:r3) - opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2 - opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - // Compute (r1:r0) = (r1:r0) + (r2:r3) - opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2 - opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - // Compute (r1:r0) = (r1:r0) + (r2:r3) - opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2 - opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Prepare for explicit register usage - loadValueDirectWideFixed(cUnit, rlSrc, r0, r1); - // Compute (r1:r0) = -(r1:r0) - opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0 - opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF - opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1 - RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, - INVALID_SREG, INVALID_SREG}; - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -void spillCoreRegs(CompilationUnit* cUnit) { - if (cUnit->numCoreSpills == 0) { - return; - } - // Spill mask not including fake return address register - uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET); - int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills); - for (int reg = 0; mask; mask >>= 1, reg++) { - if (mask & 0x1) { - storeWordDisp(cUnit, rX86_SP, offset, reg); - offset += 4; - } - } -} - -void unSpillCoreRegs(CompilationUnit* cUnit) { - if (cUnit->numCoreSpills == 0) { - return; - } - // Spill mask not including fake return address register - uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET); - int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills); - for (int reg = 0; mask; mask >>= 1, reg++) { - if (mask & 0x1) { - loadWordDisp(cUnit, rX86_SP, offset, reg); - offset += 4; - } - } -} - -void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) { - X86OpCode opcode = kX86Bkpt; - switch (op) { - case kOpCmp: opcode = kX86Cmp32RT; break; - default: - LOG(FATAL) << "Bad opcode: " << op; - break; - } - newLIR2(cUnit, opcode, rDest, threadOffset); -} - -void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, - RegLocation rlMethod) -{ - /* - * On entry, rX86_ARG0, rX86_ARG1, rX86_ARG2 are live. Let the register - * allocation mechanism know so it doesn't try to use any of them when - * expanding the frame or flushing. This leaves the utility - * code with no spare temps. - */ - oatLockTemp(cUnit, rX86_ARG0); - oatLockTemp(cUnit, rX86_ARG1); - oatLockTemp(cUnit, rX86_ARG2); - - /* Build frame, return address already on stack */ - opRegImm(cUnit, kOpSub, rX86_SP, cUnit->frameSize - 4); - - /* - * We can safely skip the stack overflow check if we're - * a leaf *and* our frame size < fudge factor. - */ - bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) && - ((size_t)cUnit->frameSize < - Thread::kStackOverflowReservedBytes)); - newLIR0(cUnit, kPseudoMethodEntry); - /* Spill core callee saves */ - spillCoreRegs(cUnit); - /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ - DCHECK_EQ(cUnit->numFPSpills, 0); - if (!skipOverflowCheck) { - // cmp rX86_SP, fs:[stack_end_]; jcc throw_launchpad - LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0); - opRegThreadMem(cUnit, kOpCmp, rX86_SP, Thread::StackEndOffset().Int32Value()); - opCondBranch(cUnit, kCondUlt, tgt); - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - } - - flushIns(cUnit, argLocs, rlMethod); - - oatFreeTemp(cUnit, rX86_ARG0); - oatFreeTemp(cUnit, rX86_ARG1); - oatFreeTemp(cUnit, rX86_ARG2); -} - -void genExitSequence(CompilationUnit* cUnit) { - /* - * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't - * allocated by the register utilities as temps. - */ - oatLockTemp(cUnit, rX86_RET0); - oatLockTemp(cUnit, rX86_RET1); - - newLIR0(cUnit, kPseudoMethodExit); - unSpillCoreRegs(cUnit); - /* Remove frame except for return address */ - opRegImm(cUnit, kOpAdd, rX86_SP, cUnit->frameSize - 4); - newLIR0(cUnit, kX86Ret); -} - -/* - * Nop any unconditional branches that go to the next instruction. - * Note: new redundant branches may be inserted later, and we'll - * use a check in final instruction assembly to nop those out. - */ -void removeRedundantBranches(CompilationUnit* cUnit) { - LIR* thisLIR; - - for (thisLIR = (LIR*) cUnit->firstLIRInsn; - thisLIR != (LIR*) cUnit->lastLIRInsn; - thisLIR = NEXT_LIR(thisLIR)) { - - /* Branch to the next instruction */ - if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) { - LIR* nextLIR = thisLIR; - - while (true) { - nextLIR = NEXT_LIR(nextLIR); - - /* - * Is the branch target the next instruction? - */ - if (nextLIR == (LIR*) thisLIR->target) { - thisLIR->flags.isNop = true; - break; - } - - /* - * Found real useful stuff between the branch and the target. - * Need to explicitly check the lastLIRInsn here because it - * might be the last real instruction. - */ - if (!isPseudoOpcode(nextLIR->opcode) || - (nextLIR = (LIR*) cUnit->lastLIRInsn)) - break; - } - } - } -} - - -/* Common initialization routine for an architecture family */ -bool oatArchInit() { - int i; - - for (i = 0; i < kX86Last; i++) { - if (EncodingMap[i].opcode != i) { - LOG(FATAL) << "Encoding order for " << EncodingMap[i].name - << " is wrong: expecting " << i << ", seeing " - << (int)EncodingMap[i].opcode; - } - } - - return oatArchVariantInit(); -} - -// Not used in x86 -int loadHelper(CompilationUnit* cUnit, int offset) -{ - LOG(FATAL) << "Unexpected use of loadHelper in x86"; - return INVALID_REG; -} - - - -} // namespace art diff --git a/src/compiler/codegen/x86/ArchUtility.cc b/src/compiler/codegen/x86/ArchUtility.cc deleted file mode 100644 index 32dd811045..0000000000 --- a/src/compiler/codegen/x86/ArchUtility.cc +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../../CompilerInternals.h" -#include "X86LIR.h" -#include "../Ralloc.h" - -#include <string> - -namespace art { - -RegLocation locCReturn() -{ - RegLocation res = X86_LOC_C_RETURN; - return res; -} - -RegLocation locCReturnWide() -{ - RegLocation res = X86_LOC_C_RETURN_WIDE; - return res; -} - -RegLocation locCReturnFloat() -{ - RegLocation res = X86_LOC_C_RETURN_FLOAT; - return res; -} - -RegLocation locCReturnDouble() -{ - RegLocation res = X86_LOC_C_RETURN_DOUBLE; - return res; -} - -// Return a target-dependent special register. -int targetReg(SpecialTargetRegister reg) { - int res = INVALID_REG; - switch (reg) { - case kSelf: res = rX86_SELF; break; - case kSuspend: res = rX86_SUSPEND; break; - case kLr: res = rX86_LR; break; - case kPc: res = rX86_PC; break; - case kSp: res = rX86_SP; break; - case kArg0: res = rX86_ARG0; break; - case kArg1: res = rX86_ARG1; break; - case kArg2: res = rX86_ARG2; break; - case kArg3: res = rX86_ARG3; break; - case kFArg0: res = rX86_FARG0; break; - case kFArg1: res = rX86_FARG1; break; - case kFArg2: res = rX86_FARG2; break; - case kFArg3: res = rX86_FARG3; break; - case kRet0: res = rX86_RET0; break; - case kRet1: res = rX86_RET1; break; - case kInvokeTgt: res = rX86_INVOKE_TGT; break; - case kCount: res = rX86_COUNT; break; - } - return res; -} - -// Create a double from a pair of singles. -int s2d(int lowReg, int highReg) -{ - return X86_S2D(lowReg, highReg); -} - -// Is reg a single or double? -bool fpReg(int reg) -{ - return X86_FPREG(reg); -} - -// Is reg a single? -bool singleReg(int reg) -{ - return X86_SINGLEREG(reg); -} - -// Is reg a double? -bool doubleReg(int reg) -{ - return X86_DOUBLEREG(reg); -} - -// Return mask to strip off fp reg flags and bias. -uint32_t fpRegMask() -{ - return X86_FP_REG_MASK; -} - -// True if both regs single, both core or both double. -bool sameRegType(int reg1, int reg2) -{ - return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2)); -} - -/* - * Decode the register id. - */ -u8 getRegMaskCommon(CompilationUnit* cUnit, int reg) -{ - u8 seed; - int shift; - int regId; - - regId = reg & 0xf; - /* Double registers in x86 are just a single FP register */ - seed = 1; - /* FP register starts at bit position 16 */ - shift = X86_FPREG(reg) ? kX86FPReg0 : 0; - /* Expand the double register id into single offset */ - shift += regId; - return (seed << shift); -} - -uint64_t getPCUseDefEncoding() -{ - /* - * FIXME: might make sense to use a virtual resource encoding bit for pc. Might be - * able to clean up some of the x86/Arm_Mips differences - */ - LOG(FATAL) << "Unexpected call to getPCUseDefEncoding for x86"; - return 0ULL; -} - -void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) -{ - DCHECK_EQ(cUnit->instructionSet, kX86); - - // X86-specific resource map setup here. - uint64_t flags = EncodingMap[lir->opcode].flags; - - if (flags & REG_USE_SP) { - lir->useMask |= ENCODE_X86_REG_SP; - } - - if (flags & REG_DEF_SP) { - lir->defMask |= ENCODE_X86_REG_SP; - } - - if (flags & REG_DEFA) { - oatSetupRegMask(cUnit, &lir->defMask, rAX); - } - - if (flags & REG_DEFD) { - oatSetupRegMask(cUnit, &lir->defMask, rDX); - } - if (flags & REG_USEA) { - oatSetupRegMask(cUnit, &lir->useMask, rAX); - } - - if (flags & REG_USEC) { - oatSetupRegMask(cUnit, &lir->useMask, rCX); - } - - if (flags & REG_USED) { - oatSetupRegMask(cUnit, &lir->useMask, rDX); - } -} - -/* For dumping instructions */ -static const char* x86RegName[] = { - "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" -}; - -static const char* x86CondName[] = { - "O", - "NO", - "B/NAE/C", - "NB/AE/NC", - "Z/EQ", - "NZ/NE", - "BE/NA", - "NBE/A", - "S", - "NS", - "P/PE", - "NP/PO", - "L/NGE", - "NL/GE", - "LE/NG", - "NLE/G" -}; - -/* - * Interpret a format string and build a string no longer than size - * See format key in Assemble.cc. - */ -std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) { - std::string buf; - size_t i = 0; - size_t fmt_len = strlen(fmt); - while (i < fmt_len) { - if (fmt[i] != '!') { - buf += fmt[i]; - i++; - } else { - i++; - DCHECK_LT(i, fmt_len); - char operand_number_ch = fmt[i]; - i++; - if (operand_number_ch == '!') { - buf += "!"; - } else { - int operand_number = operand_number_ch - '0'; - DCHECK_LT(operand_number, 6); // Expect upto 6 LIR operands. - DCHECK_LT(i, fmt_len); - int operand = lir->operands[operand_number]; - switch (fmt[i]) { - case 'c': - DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName)); - buf += x86CondName[operand]; - break; - case 'd': - buf += StringPrintf("%d", operand); - break; - case 'p': { - SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(operand); - buf += StringPrintf("0x%08x", tabRec->offset); - break; - } - case 'r': - if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) { - int fp_reg = operand & X86_FP_REG_MASK; - buf += StringPrintf("xmm%d", fp_reg); - } else { - DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName)); - buf += x86RegName[operand]; - } - break; - case 't': - buf += StringPrintf("0x%08x (L%p)", - reinterpret_cast<uint32_t>(baseAddr) - + lir->offset + operand, lir->target); - break; - default: - buf += StringPrintf("DecodeError '%c'", fmt[i]); - break; - } - i++; - } - } - } - return buf; -} - -void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) -{ - char buf[256]; - buf[0] = 0; - LIR *x86LIR = (LIR *) lir; - - if (mask == ENCODE_ALL) { - strcpy(buf, "all"); - } else { - char num[8]; - int i; - - for (i = 0; i < kX86RegEnd; i++) { - if (mask & (1ULL << i)) { - sprintf(num, "%d ", i); - strcat(buf, num); - } - } - - if (mask & ENCODE_CCODE) { - strcat(buf, "cc "); - } - /* Memory bits */ - if (x86LIR && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", x86LIR->aliasInfo & 0xffff, - (x86LIR->aliasInfo & 0x80000000) ? "(+1)" : ""); - } - if (mask & ENCODE_LITERAL) { - strcat(buf, "lit "); - } - - if (mask & ENCODE_HEAP_REF) { - strcat(buf, "heap "); - } - if (mask & ENCODE_MUST_NOT_ALIAS) { - strcat(buf, "noalias "); - } - } - if (buf[0]) { - LOG(INFO) << prefix << ": " << buf; - } -} - -} // namespace art diff --git a/src/compiler/codegen/x86/X86/Ralloc.cc b/src/compiler/codegen/x86/X86/Ralloc.cc deleted file mode 100644 index ef72e52515..0000000000 --- a/src/compiler/codegen/x86/X86/Ralloc.cc +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace art { - -/* This file contains codegen for the X86 ISA */ - -/* - * Alloc a pair of core registers, or a double. Low reg in low byte, - * high reg in next byte. - */ -int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint, - int regClass) -{ - int highReg; - int lowReg; - int res = 0; - - if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { - lowReg = oatAllocTempDouble(cUnit); - highReg = lowReg + 1; - res = (lowReg & 0xff) | ((highReg & 0xff) << 8); - return res; - } - - lowReg = oatAllocTemp(cUnit); - highReg = oatAllocTemp(cUnit); - res = (lowReg & 0xff) | ((highReg & 0xff) << 8); - return res; -} - -int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) { - if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { - return oatAllocTempFloat(cUnit); - } - return oatAllocTemp(cUnit); -} - -void oatInitializeRegAlloc(CompilationUnit* cUnit) { - int numRegs = sizeof(coreRegs)/sizeof(*coreRegs); - int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs); - int numTemps = sizeof(coreTemps)/sizeof(*coreTemps); - int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); - int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); - RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true, - kAllocRegAlloc); - cUnit->regPool = pool; - pool->numCoreRegs = numRegs; - pool->coreRegs = (RegisterInfo *) - oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), true, - kAllocRegAlloc); - pool->numFPRegs = numFPRegs; - pool->FPRegs = (RegisterInfo *) - oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true, - kAllocRegAlloc); - oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs); - oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs); - // Keep special registers from being allocated - for (int i = 0; i < numReserved; i++) { - oatMarkInUse(cUnit, reservedRegs[i]); - } - // Mark temp regs - all others not in use can be used for promotion - for (int i = 0; i < numTemps; i++) { - oatMarkTemp(cUnit, coreTemps[i]); - } - for (int i = 0; i < numFPTemps; i++) { - oatMarkTemp(cUnit, fpTemps[i]); - } - // Construct the alias map. - cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs * - sizeof(cUnit->phiAliasMap[0]), false, - kAllocDFInfo); - for (int i = 0; i < cUnit->numSSARegs; i++) { - cUnit->phiAliasMap[i] = i; - } - for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) { - int defReg = phi->ssaRep->defs[0]; - for (int i = 0; i < phi->ssaRep->numUses; i++) { - for (int j = 0; j < cUnit->numSSARegs; j++) { - if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) { - cUnit->phiAliasMap[j] = defReg; - } - } - } - } -} - -void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep, - RegLocation rlFree) -{ - if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) && - (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) { - // No overlap, free both - oatFreeTemp(cUnit, rlFree.lowReg); - oatFreeTemp(cUnit, rlFree.highReg); - } -} - - -} // namespace art diff --git a/src/compiler/codegen/x86/X86RallocUtil.cc b/src/compiler/codegen/x86/X86RallocUtil.cc deleted file mode 100644 index caf4e08977..0000000000 --- a/src/compiler/codegen/x86/X86RallocUtil.cc +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This file contains X86-specific register allocation support. - */ - -#include "../../CompilerUtility.h" -#include "../../CompilerIR.h" -#include "../..//Dataflow.h" -#include "X86LIR.h" -#include "Codegen.h" -#include "../Ralloc.h" - -namespace art { - -void oatAdjustSpillMask(CompilationUnit* cUnit) { - // Adjustment for LR spilling, x86 has no LR so nothing to do here - cUnit->coreSpillMask |= (1 << rRET); - cUnit->numCoreSpills++; -} - -/* - * Mark a callee-save fp register as promoted. Note that - * vpush/vpop uses contiguous register lists so we must - * include any holes in the mask. Associate holes with - * Dalvik register INVALID_VREG (0xFFFFU). - */ -void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg) -{ - UNIMPLEMENTED(WARNING) << "oatMarkPreservedSingle"; -#if 0 - LOG(FATAL) << "No support yet for promoted FP regs"; -#endif -} - -void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2) -{ - RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1); - RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2); - DCHECK(info1 && info2 && info1->pair && info2->pair && - (info1->partner == info2->reg) && - (info2->partner == info1->reg)); - if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) { - if (!(info1->isTemp && info2->isTemp)) { - /* Should not happen. If it does, there's a problem in evalLoc */ - LOG(FATAL) << "Long half-temp, half-promoted"; - } - - info1->dirty = false; - info2->dirty = false; - if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg)) - info1 = info2; - int vReg = SRegToVReg(cUnit, info1->sReg); - oatFlushRegWideImpl(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), - info1->reg, info1->partner); - } -} - -void oatFlushReg(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, reg); - if (info->live && info->dirty) { - info->dirty = false; - int vReg = SRegToVReg(cUnit, info->sReg); - oatFlushRegImpl(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), reg, kWord); - } -} - -/* Give access to the target-dependent FP register encoding to common code */ -bool oatIsFpReg(int reg) { - return X86_FPREG(reg); -} - -uint32_t oatFpRegMask() { - return X86_FP_REG_MASK; -} - -/* Clobber all regs that might be used by an external C call */ -extern void oatClobberCalleeSave(CompilationUnit *cUnit) -{ - oatClobber(cUnit, rAX); - oatClobber(cUnit, rCX); - oatClobber(cUnit, rDX); -} - -extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) { - RegLocation res = locCReturnWide(); - CHECK(res.lowReg == rAX); - CHECK(res.highReg == rDX); - oatClobber(cUnit, rAX); - oatClobber(cUnit, rDX); - oatMarkInUse(cUnit, rAX); - oatMarkInUse(cUnit, rDX); - oatMarkPair(cUnit, res.lowReg, res.highReg); - return res; -} - -extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) -{ - RegLocation res = locCReturn(); - res.lowReg = rDX; - oatClobber(cUnit, rDX); - oatMarkInUse(cUnit, rDX); - return res; -} - -extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) -{ - return X86_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & X86_FP_REG_MASK] - : &cUnit->regPool->coreRegs[reg]; -} - -/* To be used when explicitly managing register use */ -extern void oatLockCallTemps(CompilationUnit* cUnit) -{ - oatLockTemp(cUnit, rX86_ARG0); - oatLockTemp(cUnit, rX86_ARG1); - oatLockTemp(cUnit, rX86_ARG2); - oatLockTemp(cUnit, rX86_ARG3); -} - -/* To be used when explicitly managing register use */ -extern void oatFreeCallTemps(CompilationUnit* cUnit) -{ - oatFreeTemp(cUnit, rX86_ARG0); - oatFreeTemp(cUnit, rX86_ARG1); - oatFreeTemp(cUnit, rX86_ARG2); - oatFreeTemp(cUnit, rX86_ARG3); -} - -/* Convert an instruction to a NOP */ -void oatNopLIR( LIR* lir) -{ - ((LIR*)lir)->flags.isNop = true; -} - -} // namespace art diff --git a/src/compiler/codegen/x86/Assemble.cc b/src/compiler/codegen/x86/assemble_x86.cc index a5388e8428..79ed075828 100644 --- a/src/compiler/codegen/x86/Assemble.cc +++ b/src/compiler/codegen/x86/assemble_x86.cc @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" -#include "X86LIR.h" -#include "Codegen.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" +#include "x86_lir.h" +#include "codegen.h" namespace art { diff --git a/src/compiler/codegen/x86/backend_x86.cc b/src/compiler/codegen/x86/backend_x86.cc new file mode 100644 index 0000000000..6abfb23b09 --- /dev/null +++ b/src/compiler/codegen/x86/backend_x86.cc @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _CODEGEN_C + +#include "../../dalvik.h" +#include "../../compiler_internals.h" +#include "x86_lir.h" +#include "../ralloc.h" +#include "codegen.h" + +/* Common codegen utility code */ +#include "../codegen_util.cc" + +#include "utility_x86.cc" +#include "../codegen_factory.cc" +#include "../gen_common.cc" +#include "../gen_invoke.cc" +#include "call_x86.cc" +#include "fp_x86.cc" +#include "int_x86.cc" + +/* Bitcode conversion */ +#include "../method_bitcode.cc" + +/* MIR2LIR dispatcher and architectural independent codegen routines */ +#include "../method_codegen_driver.cc" + +/* Target-independent local optimizations */ +#include "../local_optimizations.cc" diff --git a/src/compiler/codegen/x86/call_x86.cc b/src/compiler/codegen/x86/call_x86.cc new file mode 100644 index 0000000000..0cd9b2da2d --- /dev/null +++ b/src/compiler/codegen/x86/call_x86.cc @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file contains codegen for the X86 ISA */ + +namespace art { + +void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, + SpecialCaseHandler specialCase) +{ + // TODO +} + +/* + * The sparse table in the literal pool is an array of <key,displacement> + * pairs. + */ +BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset, + bool split, bool create, BasicBlock** immedPredBlockP); +void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset, + RegLocation rlSrc) +{ + const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; + if (cUnit->printMe) { + dumpSparseSwitchTable(table); + } + int entries = table[1]; + int* keys = (int*)&table[2]; + int* targets = &keys[entries]; + rlSrc = loadValue(cUnit, rlSrc, kCoreReg); + for (int i = 0; i < entries; i++) { + int key = keys[i]; + BasicBlock* case_block = findBlock(cUnit, + cUnit->currentDalvikOffset + targets[i], + false, false, NULL); + LIR* labelList = cUnit->blockLabelList; + opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key, + &labelList[case_block->id]); + } +} + +/* + * Code pattern will look something like: + * + * mov rVal, .. + * call 0 + * pop rStartOfMethod + * sub rStartOfMethod, .. + * mov rKeyReg, rVal + * sub rKeyReg, lowKey + * cmp rKeyReg, size-1 ; bound check + * ja done + * mov rDisp, [rStartOfMethod + rKeyReg * 4 + tableOffset] + * add rStartOfMethod, rDisp + * jmp rStartOfMethod + * done: + */ +void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset, + RegLocation rlSrc) +{ + const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; + if (cUnit->printMe) { + dumpPackedSwitchTable(table); + } + // Add the table to the list - we'll process it later + SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable), + true, kAllocData); + tabRec->table = table; + tabRec->vaddr = cUnit->currentDalvikOffset; + int size = table[1]; + tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, + kAllocLIR); + oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec); + + // Get the switch value + rlSrc = loadValue(cUnit, rlSrc, kCoreReg); + int startOfMethodReg = oatAllocTemp(cUnit); + // Materialize a pointer to the switch table + //newLIR0(cUnit, kX86Bkpt); + newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg); + int lowKey = s4FromSwitchData(&table[2]); + int keyReg; + // Remove the bias, if necessary + if (lowKey == 0) { + keyReg = rlSrc.lowReg; + } else { + keyReg = oatAllocTemp(cUnit); + opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey); + } + // Bounds check - if < 0 or >= size continue following switch + opRegImm(cUnit, kOpCmp, keyReg, size-1); + LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL); + + // Load the displacement from the switch table + int dispReg = oatAllocTemp(cUnit); + newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2, + (intptr_t)tabRec); + // Add displacement to start of method + opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg); + // ..and go! + LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg); + tabRec->anchor = switchBranch; + + /* branchOver target here */ + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); + branchOver->target = (LIR*)target; +} + +void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, + int arg0, int arg1, bool safepointPC); +/* + * Array data table format: + * ushort ident = 0x0300 magic value + * ushort width width of each element in the table + * uint size number of elements in the table + * ubyte data[size*width] table of data values (may contain a single-byte + * padding at the end) + * + * Total size is 4+(width * size + 1)/2 16-bit code units. + */ +void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, + RegLocation rlSrc) +{ + const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; + // Add the table to the list - we'll process it later + FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData), + true, kAllocData); + tabRec->table = table; + tabRec->vaddr = cUnit->currentDalvikOffset; + u2 width = tabRec->table[1]; + u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16); + tabRec->size = (size * width) + 8; + + oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec); + + // Making a call - use explicit registers + oatFlushAllRegs(cUnit); /* Everything to home location */ + loadValueDirectFixed(cUnit, rlSrc, rX86_ARG0); + // Materialize a pointer to the fill data image + newLIR1(cUnit, kX86StartOfMethod, rX86_ARG2); + newLIR2(cUnit, kX86PcRelAdr, rX86_ARG1, (intptr_t)tabRec); + newLIR2(cUnit, kX86Add32RR, rX86_ARG1, rX86_ARG2); + callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rX86_ARG0, rX86_ARG1, + true); +} + +void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) +{ + oatFlushAllRegs(cUnit); + loadValueDirectFixed(cUnit, rlSrc, rCX); // Get obj + oatLockCallTemps(cUnit); // Prepare for explicit register usage + genNullCheck(cUnit, rlSrc.sRegLow, rCX, optFlags); + // If lock is unheld, try to grab it quickly with compare and exchange + // TODO: copy and clear hash state? + newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); + newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); + newLIR2(cUnit, kX86Xor32RR, rAX, rAX); + newLIR3(cUnit, kX86LockCmpxchgMR, rCX, Object::MonitorOffset().Int32Value(), rDX); + LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondEq); + // If lock is held, go the expensive route - artLockObjectFromCode(self, obj); + callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true); + branch->target = newLIR0(cUnit, kPseudoTargetLabel); +} + +void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) +{ + oatFlushAllRegs(cUnit); + loadValueDirectFixed(cUnit, rlSrc, rAX); // Get obj + oatLockCallTemps(cUnit); // Prepare for explicit register usage + genNullCheck(cUnit, rlSrc.sRegLow, rAX, optFlags); + // If lock is held by the current thread, clear it to quickly release it + // TODO: clear hash state? + newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); + newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); + newLIR3(cUnit, kX86Mov32RM, rCX, rAX, Object::MonitorOffset().Int32Value()); + opRegReg(cUnit, kOpSub, rCX, rDX); + LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondNe); + newLIR3(cUnit, kX86Mov32MR, rAX, Object::MonitorOffset().Int32Value(), rCX); + LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0); + branch->target = newLIR0(cUnit, kPseudoTargetLabel); + // Otherwise, go the expensive route - UnlockObjectFromCode(obj); + callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true); + branch2->target = newLIR0(cUnit, kPseudoTargetLabel); +} + +/* + * Mark garbage collection card. Skip if the value we're storing is null. + */ +void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) +{ + int regCardBase = oatAllocTemp(cUnit); + int regCardNo = oatAllocTemp(cUnit); + LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL); + newLIR2(cUnit, kX86Mov32RT, regCardBase, Thread::CardTableOffset().Int32Value()); + opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift); + storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0, + kUnsignedByte); + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); + branchOver->target = (LIR*)target; + oatFreeTemp(cUnit, regCardBase); + oatFreeTemp(cUnit, regCardNo); +} + +void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, + RegLocation rlMethod) +{ + /* + * On entry, rX86_ARG0, rX86_ARG1, rX86_ARG2 are live. Let the register + * allocation mechanism know so it doesn't try to use any of them when + * expanding the frame or flushing. This leaves the utility + * code with no spare temps. + */ + oatLockTemp(cUnit, rX86_ARG0); + oatLockTemp(cUnit, rX86_ARG1); + oatLockTemp(cUnit, rX86_ARG2); + + /* Build frame, return address already on stack */ + opRegImm(cUnit, kOpSub, rX86_SP, cUnit->frameSize - 4); + + /* + * We can safely skip the stack overflow check if we're + * a leaf *and* our frame size < fudge factor. + */ + bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) && + ((size_t)cUnit->frameSize < + Thread::kStackOverflowReservedBytes)); + newLIR0(cUnit, kPseudoMethodEntry); + /* Spill core callee saves */ + spillCoreRegs(cUnit); + /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ + DCHECK_EQ(cUnit->numFPSpills, 0); + if (!skipOverflowCheck) { + // cmp rX86_SP, fs:[stack_end_]; jcc throw_launchpad + LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0); + opRegThreadMem(cUnit, kOpCmp, rX86_SP, Thread::StackEndOffset().Int32Value()); + opCondBranch(cUnit, kCondUlt, tgt); + // Remember branch target - will process later + oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); + } + + flushIns(cUnit, argLocs, rlMethod); + + oatFreeTemp(cUnit, rX86_ARG0); + oatFreeTemp(cUnit, rX86_ARG1); + oatFreeTemp(cUnit, rX86_ARG2); +} + +void genExitSequence(CompilationUnit* cUnit) { + /* + * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't + * allocated by the register utilities as temps. + */ + oatLockTemp(cUnit, rX86_RET0); + oatLockTemp(cUnit, rX86_RET1); + + newLIR0(cUnit, kPseudoMethodExit); + unSpillCoreRegs(cUnit); + /* Remove frame except for return address */ + opRegImm(cUnit, kOpAdd, rX86_SP, cUnit->frameSize - 4); + newLIR0(cUnit, kX86Ret); +} + +} // namespace art diff --git a/src/compiler/codegen/x86/Codegen.h b/src/compiler/codegen/x86/codegen.h index 3755e500aa..c95fa672ac 100644 --- a/src/compiler/codegen/x86/Codegen.h +++ b/src/compiler/codegen/x86/codegen.h @@ -16,7 +16,7 @@ /* This file contains register alloction support */ -#include "../../CompilerIR.h" +#include "../../compiler_ir.h" namespace art { diff --git a/src/compiler/codegen/x86/FP/X86FP.cc b/src/compiler/codegen/x86/fp_x86.cc index 5e97a50d50..0a08ab0b4c 100644 --- a/src/compiler/codegen/x86/FP/X86FP.cc +++ b/src/compiler/codegen/x86/fp_x86.cc @@ -331,4 +331,30 @@ void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, opCondBranch(cUnit, ccode, taken); } +void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) +{ + RegLocation rlResult; + rlSrc = loadValue(cUnit, rlSrc, kCoreReg); + rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000); + storeValue(cUnit, rlDest, rlResult); +} + +void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) +{ + RegLocation rlResult; + rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); + rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000); + opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); + storeValueWide(cUnit, rlDest, rlResult); +} + +bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) { + DCHECK_NE(cUnit->instructionSet, kThumb2); + return false; +} + + + } // namespace art diff --git a/src/compiler/codegen/x86/X86/Gen.cc b/src/compiler/codegen/x86/int_x86.cc index 37cd725025..1673b55fdf 100644 --- a/src/compiler/codegen/x86/X86/Gen.cc +++ b/src/compiler/codegen/x86/int_x86.cc @@ -18,12 +18,6 @@ namespace art { -void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - SpecialCaseHandler specialCase) -{ - // TODO -} - /* * Perform register memory operation. */ @@ -40,200 +34,6 @@ LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, } /* - * The sparse table in the literal pool is an array of <key,displacement> - * pairs. - */ -BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset, - bool split, bool create, BasicBlock** immedPredBlockP); -void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset, - RegLocation rlSrc) -{ - const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; - if (cUnit->printMe) { - dumpSparseSwitchTable(table); - } - int entries = table[1]; - int* keys = (int*)&table[2]; - int* targets = &keys[entries]; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - for (int i = 0; i < entries; i++) { - int key = keys[i]; - BasicBlock* case_block = findBlock(cUnit, - cUnit->currentDalvikOffset + targets[i], - false, false, NULL); - LIR* labelList = cUnit->blockLabelList; - opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key, - &labelList[case_block->id]); - } -} - -/* - * Code pattern will look something like: - * - * mov rVal, .. - * call 0 - * pop rStartOfMethod - * sub rStartOfMethod, .. - * mov rKeyReg, rVal - * sub rKeyReg, lowKey - * cmp rKeyReg, size-1 ; bound check - * ja done - * mov rDisp, [rStartOfMethod + rKeyReg * 4 + tableOffset] - * add rStartOfMethod, rDisp - * jmp rStartOfMethod - * done: - */ -void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset, - RegLocation rlSrc) -{ - const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; - if (cUnit->printMe) { - dumpPackedSwitchTable(table); - } - // Add the table to the list - we'll process it later - SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable), - true, kAllocData); - tabRec->table = table; - tabRec->vaddr = cUnit->currentDalvikOffset; - int size = table[1]; - tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, - kAllocLIR); - oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec); - - // Get the switch value - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - int startOfMethodReg = oatAllocTemp(cUnit); - // Materialize a pointer to the switch table - //newLIR0(cUnit, kX86Bkpt); - newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg); - int lowKey = s4FromSwitchData(&table[2]); - int keyReg; - // Remove the bias, if necessary - if (lowKey == 0) { - keyReg = rlSrc.lowReg; - } else { - keyReg = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey); - } - // Bounds check - if < 0 or >= size continue following switch - opRegImm(cUnit, kOpCmp, keyReg, size-1); - LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL); - - // Load the displacement from the switch table - int dispReg = oatAllocTemp(cUnit); - newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2, - (intptr_t)tabRec); - // Add displacement to start of method - opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg); - // ..and go! - LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg); - tabRec->anchor = switchBranch; - - /* branchOver target here */ - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branchOver->target = (LIR*)target; -} - -void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, - int arg0, int arg1, bool safepointPC); -/* - * Array data table format: - * ushort ident = 0x0300 magic value - * ushort width width of each element in the table - * uint size number of elements in the table - * ubyte data[size*width] table of data values (may contain a single-byte - * padding at the end) - * - * Total size is 4+(width * size + 1)/2 16-bit code units. - */ -void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, - RegLocation rlSrc) -{ - const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; - // Add the table to the list - we'll process it later - FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData), - true, kAllocData); - tabRec->table = table; - tabRec->vaddr = cUnit->currentDalvikOffset; - u2 width = tabRec->table[1]; - u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16); - tabRec->size = (size * width) + 8; - - oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec); - - // Making a call - use explicit registers - oatFlushAllRegs(cUnit); /* Everything to home location */ - loadValueDirectFixed(cUnit, rlSrc, rX86_ARG0); - // Materialize a pointer to the fill data image - newLIR1(cUnit, kX86StartOfMethod, rX86_ARG2); - newLIR2(cUnit, kX86PcRelAdr, rX86_ARG1, (intptr_t)tabRec); - newLIR2(cUnit, kX86Add32RR, rX86_ARG1, rX86_ARG2); - callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rX86_ARG0, rX86_ARG1, - true); -} - -void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) -{ - RegLocation rlResult; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000); - storeValue(cUnit, rlDest, rlResult); -} - -void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) -{ - RegLocation rlResult; - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000); - opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - storeValueWide(cUnit, rlDest, rlResult); -} - -LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags); -void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC); - -void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - loadValueDirectFixed(cUnit, rlSrc, rCX); // Get obj - oatLockCallTemps(cUnit); // Prepare for explicit register usage - genNullCheck(cUnit, rlSrc.sRegLow, rCX, optFlags); - // If lock is unheld, try to grab it quickly with compare and exchange - // TODO: copy and clear hash state? - newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); - newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); - newLIR2(cUnit, kX86Xor32RR, rAX, rAX); - newLIR3(cUnit, kX86LockCmpxchgMR, rCX, Object::MonitorOffset().Int32Value(), rDX); - LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondEq); - // If lock is held, go the expensive route - artLockObjectFromCode(self, obj); - callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true); - branch->target = newLIR0(cUnit, kPseudoTargetLabel); -} - -void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - loadValueDirectFixed(cUnit, rlSrc, rAX); // Get obj - oatLockCallTemps(cUnit); // Prepare for explicit register usage - genNullCheck(cUnit, rlSrc.sRegLow, rAX, optFlags); - // If lock is held by the current thread, clear it to quickly release it - // TODO: clear hash state? - newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); - newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); - newLIR3(cUnit, kX86Mov32RM, rCX, rAX, Object::MonitorOffset().Int32Value()); - opRegReg(cUnit, kOpSub, rCX, rDX); - LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondNe); - newLIR3(cUnit, kX86Mov32MR, rAX, Object::MonitorOffset().Int32Value(), rCX); - LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0); - branch->target = newLIR0(cUnit, kPseudoTargetLabel); - // Otherwise, go the expensive route - UnlockObjectFromCode(obj); - callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true); - branch2->target = newLIR0(cUnit, kPseudoTargetLabel); -} - -/* * Compare two 64-bit values * x = y return 0 * x < y return -1 @@ -424,24 +224,6 @@ RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int return rlDest; } -/* - * Mark garbage collection card. Skip if the value we're storing is null. - */ -void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) -{ - int regCardBase = oatAllocTemp(cUnit); - int regCardNo = oatAllocTemp(cUnit); - LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL); - newLIR2(cUnit, kX86Mov32RT, regCardBase, Thread::CardTableOffset().Int32Value()); - opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift); - storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0, - kUnsignedByte); - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branchOver->target = (LIR*)target; - oatFreeTemp(cUnit, regCardBase); - oatFreeTemp(cUnit, regCardNo); -} - bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin) { DCHECK_EQ(cUnit->instructionSet, kX86); @@ -478,11 +260,6 @@ bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_bar return false; } -bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) { - DCHECK_NE(cUnit->instructionSet, kThumb2); - return false; -} - LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) { LOG(FATAL) << "Unexpected use of opPcRelLoad for x86"; return NULL; @@ -547,5 +324,111 @@ LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide) LOG(FATAL) << "Unexpected use of opIT in x86"; return NULL; } +bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + // Compute (r1:r0) = (r1:r0) + (r2:r3) + opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2 + opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + // Compute (r1:r0) = (r1:r0) + (r2:r3) + opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2 + opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + // Compute (r1:r0) = (r1:r0) + (r2:r3) + opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2 + opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + // Compute (r1:r0) = (r1:r0) + (r2:r3) + opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2 + opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + // Compute (r1:r0) = (r1:r0) + (r2:r3) + opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2 + opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + oatFlushAllRegs(cUnit); + oatLockCallTemps(cUnit); // Prepare for explicit register usage + loadValueDirectWideFixed(cUnit, rlSrc, r0, r1); + // Compute (r1:r0) = -(r1:r0) + opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0 + opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF + opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1 + RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, + INVALID_SREG, INVALID_SREG}; + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) { + X86OpCode opcode = kX86Bkpt; + switch (op) { + case kOpCmp: opcode = kX86Cmp32RT; break; + default: + LOG(FATAL) << "Bad opcode: " << op; + break; + } + newLIR2(cUnit, opcode, rDest, threadOffset); +} } // namespace art diff --git a/src/compiler/codegen/x86/target_x86.cc b/src/compiler/codegen/x86/target_x86.cc new file mode 100644 index 0000000000..a211c2fe0e --- /dev/null +++ b/src/compiler/codegen/x86/target_x86.cc @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../compiler_internals.h" +#include "x86_lir.h" +#include "../ralloc.h" + +#include <string> + +namespace art { + +//FIXME: restore "static" when usage uncovered +/*static*/ int coreRegs[] = { + rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI +#ifdef TARGET_REX_SUPPORT + r8, r9, r10, r11, r12, r13, r14, 15 +#endif +}; +/*static*/ int reservedRegs[] = {rX86_SP}; +/*static*/ int coreTemps[] = {rAX, rCX, rDX, rBX}; +/*static*/ int fpRegs[] = { + fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, +#ifdef TARGET_REX_SUPPORT + fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 +#endif +}; +/*static*/ int fpTemps[] = { + fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, +#ifdef TARGET_REX_SUPPORT + fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 +#endif +}; + +RegLocation locCReturn() +{ + RegLocation res = X86_LOC_C_RETURN; + return res; +} + +RegLocation locCReturnWide() +{ + RegLocation res = X86_LOC_C_RETURN_WIDE; + return res; +} + +RegLocation locCReturnFloat() +{ + RegLocation res = X86_LOC_C_RETURN_FLOAT; + return res; +} + +RegLocation locCReturnDouble() +{ + RegLocation res = X86_LOC_C_RETURN_DOUBLE; + return res; +} + +// Return a target-dependent special register. +int targetReg(SpecialTargetRegister reg) { + int res = INVALID_REG; + switch (reg) { + case kSelf: res = rX86_SELF; break; + case kSuspend: res = rX86_SUSPEND; break; + case kLr: res = rX86_LR; break; + case kPc: res = rX86_PC; break; + case kSp: res = rX86_SP; break; + case kArg0: res = rX86_ARG0; break; + case kArg1: res = rX86_ARG1; break; + case kArg2: res = rX86_ARG2; break; + case kArg3: res = rX86_ARG3; break; + case kFArg0: res = rX86_FARG0; break; + case kFArg1: res = rX86_FARG1; break; + case kFArg2: res = rX86_FARG2; break; + case kFArg3: res = rX86_FARG3; break; + case kRet0: res = rX86_RET0; break; + case kRet1: res = rX86_RET1; break; + case kInvokeTgt: res = rX86_INVOKE_TGT; break; + case kCount: res = rX86_COUNT; break; + } + return res; +} + +// Create a double from a pair of singles. +int s2d(int lowReg, int highReg) +{ + return X86_S2D(lowReg, highReg); +} + +// Is reg a single or double? +bool fpReg(int reg) +{ + return X86_FPREG(reg); +} + +// Is reg a single? +bool singleReg(int reg) +{ + return X86_SINGLEREG(reg); +} + +// Is reg a double? +bool doubleReg(int reg) +{ + return X86_DOUBLEREG(reg); +} + +// Return mask to strip off fp reg flags and bias. +uint32_t fpRegMask() +{ + return X86_FP_REG_MASK; +} + +// True if both regs single, both core or both double. +bool sameRegType(int reg1, int reg2) +{ + return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2)); +} + +/* + * Decode the register id. + */ +u8 getRegMaskCommon(CompilationUnit* cUnit, int reg) +{ + u8 seed; + int shift; + int regId; + + regId = reg & 0xf; + /* Double registers in x86 are just a single FP register */ + seed = 1; + /* FP register starts at bit position 16 */ + shift = X86_FPREG(reg) ? kX86FPReg0 : 0; + /* Expand the double register id into single offset */ + shift += regId; + return (seed << shift); +} + +uint64_t getPCUseDefEncoding() +{ + /* + * FIXME: might make sense to use a virtual resource encoding bit for pc. Might be + * able to clean up some of the x86/Arm_Mips differences + */ + LOG(FATAL) << "Unexpected call to getPCUseDefEncoding for x86"; + return 0ULL; +} + +void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) +{ + DCHECK_EQ(cUnit->instructionSet, kX86); + + // X86-specific resource map setup here. + uint64_t flags = EncodingMap[lir->opcode].flags; + + if (flags & REG_USE_SP) { + lir->useMask |= ENCODE_X86_REG_SP; + } + + if (flags & REG_DEF_SP) { + lir->defMask |= ENCODE_X86_REG_SP; + } + + if (flags & REG_DEFA) { + oatSetupRegMask(cUnit, &lir->defMask, rAX); + } + + if (flags & REG_DEFD) { + oatSetupRegMask(cUnit, &lir->defMask, rDX); + } + if (flags & REG_USEA) { + oatSetupRegMask(cUnit, &lir->useMask, rAX); + } + + if (flags & REG_USEC) { + oatSetupRegMask(cUnit, &lir->useMask, rCX); + } + + if (flags & REG_USED) { + oatSetupRegMask(cUnit, &lir->useMask, rDX); + } +} + +/* For dumping instructions */ +static const char* x86RegName[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +static const char* x86CondName[] = { + "O", + "NO", + "B/NAE/C", + "NB/AE/NC", + "Z/EQ", + "NZ/NE", + "BE/NA", + "NBE/A", + "S", + "NS", + "P/PE", + "NP/PO", + "L/NGE", + "NL/GE", + "LE/NG", + "NLE/G" +}; + +/* + * Interpret a format string and build a string no longer than size + * See format key in Assemble.cc. + */ +std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) { + std::string buf; + size_t i = 0; + size_t fmt_len = strlen(fmt); + while (i < fmt_len) { + if (fmt[i] != '!') { + buf += fmt[i]; + i++; + } else { + i++; + DCHECK_LT(i, fmt_len); + char operand_number_ch = fmt[i]; + i++; + if (operand_number_ch == '!') { + buf += "!"; + } else { + int operand_number = operand_number_ch - '0'; + DCHECK_LT(operand_number, 6); // Expect upto 6 LIR operands. + DCHECK_LT(i, fmt_len); + int operand = lir->operands[operand_number]; + switch (fmt[i]) { + case 'c': + DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName)); + buf += x86CondName[operand]; + break; + case 'd': + buf += StringPrintf("%d", operand); + break; + case 'p': { + SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(operand); + buf += StringPrintf("0x%08x", tabRec->offset); + break; + } + case 'r': + if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) { + int fp_reg = operand & X86_FP_REG_MASK; + buf += StringPrintf("xmm%d", fp_reg); + } else { + DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName)); + buf += x86RegName[operand]; + } + break; + case 't': + buf += StringPrintf("0x%08x (L%p)", + reinterpret_cast<uint32_t>(baseAddr) + + lir->offset + operand, lir->target); + break; + default: + buf += StringPrintf("DecodeError '%c'", fmt[i]); + break; + } + i++; + } + } + } + return buf; +} + +void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) +{ + char buf[256]; + buf[0] = 0; + LIR *x86LIR = (LIR *) lir; + + if (mask == ENCODE_ALL) { + strcpy(buf, "all"); + } else { + char num[8]; + int i; + + for (i = 0; i < kX86RegEnd; i++) { + if (mask & (1ULL << i)) { + sprintf(num, "%d ", i); + strcat(buf, num); + } + } + + if (mask & ENCODE_CCODE) { + strcat(buf, "cc "); + } + /* Memory bits */ + if (x86LIR && (mask & ENCODE_DALVIK_REG)) { + sprintf(buf + strlen(buf), "dr%d%s", x86LIR->aliasInfo & 0xffff, + (x86LIR->aliasInfo & 0x80000000) ? "(+1)" : ""); + } + if (mask & ENCODE_LITERAL) { + strcat(buf, "lit "); + } + + if (mask & ENCODE_HEAP_REF) { + strcat(buf, "heap "); + } + if (mask & ENCODE_MUST_NOT_ALIAS) { + strcat(buf, "noalias "); + } + } + if (buf[0]) { + LOG(INFO) << prefix << ": " << buf; + } +} +void oatAdjustSpillMask(CompilationUnit* cUnit) { + // Adjustment for LR spilling, x86 has no LR so nothing to do here + cUnit->coreSpillMask |= (1 << rRET); + cUnit->numCoreSpills++; +} + +/* + * Mark a callee-save fp register as promoted. Note that + * vpush/vpop uses contiguous register lists so we must + * include any holes in the mask. Associate holes with + * Dalvik register INVALID_VREG (0xFFFFU). + */ +void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg) +{ + UNIMPLEMENTED(WARNING) << "oatMarkPreservedSingle"; +#if 0 + LOG(FATAL) << "No support yet for promoted FP regs"; +#endif +} + +void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2) +{ + RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1); + RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2); + DCHECK(info1 && info2 && info1->pair && info2->pair && + (info1->partner == info2->reg) && + (info2->partner == info1->reg)); + if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) { + if (!(info1->isTemp && info2->isTemp)) { + /* Should not happen. If it does, there's a problem in evalLoc */ + LOG(FATAL) << "Long half-temp, half-promoted"; + } + + info1->dirty = false; + info2->dirty = false; + if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg)) + info1 = info2; + int vReg = SRegToVReg(cUnit, info1->sReg); + oatFlushRegWideImpl(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), + info1->reg, info1->partner); + } +} + +void oatFlushReg(CompilationUnit* cUnit, int reg) +{ + RegisterInfo* info = oatGetRegInfo(cUnit, reg); + if (info->live && info->dirty) { + info->dirty = false; + int vReg = SRegToVReg(cUnit, info->sReg); + oatFlushRegImpl(cUnit, rX86_SP, oatVRegOffset(cUnit, vReg), reg, kWord); + } +} + +/* Give access to the target-dependent FP register encoding to common code */ +bool oatIsFpReg(int reg) { + return X86_FPREG(reg); +} + +uint32_t oatFpRegMask() { + return X86_FP_REG_MASK; +} + +/* Clobber all regs that might be used by an external C call */ +extern void oatClobberCalleeSave(CompilationUnit *cUnit) +{ + oatClobber(cUnit, rAX); + oatClobber(cUnit, rCX); + oatClobber(cUnit, rDX); +} + +extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) { + RegLocation res = locCReturnWide(); + CHECK(res.lowReg == rAX); + CHECK(res.highReg == rDX); + oatClobber(cUnit, rAX); + oatClobber(cUnit, rDX); + oatMarkInUse(cUnit, rAX); + oatMarkInUse(cUnit, rDX); + oatMarkPair(cUnit, res.lowReg, res.highReg); + return res; +} + +extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) +{ + RegLocation res = locCReturn(); + res.lowReg = rDX; + oatClobber(cUnit, rDX); + oatMarkInUse(cUnit, rDX); + return res; +} + +extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) +{ + return X86_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & X86_FP_REG_MASK] + : &cUnit->regPool->coreRegs[reg]; +} + +/* To be used when explicitly managing register use */ +extern void oatLockCallTemps(CompilationUnit* cUnit) +{ + oatLockTemp(cUnit, rX86_ARG0); + oatLockTemp(cUnit, rX86_ARG1); + oatLockTemp(cUnit, rX86_ARG2); + oatLockTemp(cUnit, rX86_ARG3); +} + +/* To be used when explicitly managing register use */ +extern void oatFreeCallTemps(CompilationUnit* cUnit) +{ + oatFreeTemp(cUnit, rX86_ARG0); + oatFreeTemp(cUnit, rX86_ARG1); + oatFreeTemp(cUnit, rX86_ARG2); + oatFreeTemp(cUnit, rX86_ARG3); +} + +/* Convert an instruction to a NOP */ +void oatNopLIR( LIR* lir) +{ + ((LIR*)lir)->flags.isNop = true; +} + +/* + * Determine the initial instruction set to be used for this trace. + * Later components may decide to change this. + */ +InstructionSet oatInstructionSet() +{ + return kX86; +} + +/* Architecture-specific initializations and checks go here */ +bool oatArchVariantInit(void) +{ + return true; +} + +int dvmCompilerTargetOptHint(int key) +{ + int res; + switch (key) { + case kMaxHoistDistance: + res = 2; + break; + default: + LOG(FATAL) << "Unknown target optimization hint key: " << key; + } + return res; +} + +void oatGenMemBarrier(CompilationUnit *cUnit, int /* barrierKind */) +{ +#if ANDROID_SMP != 0 + // TODO: optimize fences + newLIR0(cUnit, kX86Mfence); +#endif +} +/* + * Alloc a pair of core registers, or a double. Low reg in low byte, + * high reg in next byte. + */ +int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint, + int regClass) +{ + int highReg; + int lowReg; + int res = 0; + + if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { + lowReg = oatAllocTempDouble(cUnit); + highReg = lowReg + 1; + res = (lowReg & 0xff) | ((highReg & 0xff) << 8); + return res; + } + + lowReg = oatAllocTemp(cUnit); + highReg = oatAllocTemp(cUnit); + res = (lowReg & 0xff) | ((highReg & 0xff) << 8); + return res; +} + +int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) { + if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { + return oatAllocTempFloat(cUnit); + } + return oatAllocTemp(cUnit); +} + +void oatInitializeRegAlloc(CompilationUnit* cUnit) { + int numRegs = sizeof(coreRegs)/sizeof(*coreRegs); + int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs); + int numTemps = sizeof(coreTemps)/sizeof(*coreTemps); + int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); + int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); + RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true, + kAllocRegAlloc); + cUnit->regPool = pool; + pool->numCoreRegs = numRegs; + pool->coreRegs = (RegisterInfo *) + oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), true, + kAllocRegAlloc); + pool->numFPRegs = numFPRegs; + pool->FPRegs = (RegisterInfo *) + oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true, + kAllocRegAlloc); + oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs); + oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs); + // Keep special registers from being allocated + for (int i = 0; i < numReserved; i++) { + oatMarkInUse(cUnit, reservedRegs[i]); + } + // Mark temp regs - all others not in use can be used for promotion + for (int i = 0; i < numTemps; i++) { + oatMarkTemp(cUnit, coreTemps[i]); + } + for (int i = 0; i < numFPTemps; i++) { + oatMarkTemp(cUnit, fpTemps[i]); + } + // Construct the alias map. + cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs * + sizeof(cUnit->phiAliasMap[0]), false, + kAllocDFInfo); + for (int i = 0; i < cUnit->numSSARegs; i++) { + cUnit->phiAliasMap[i] = i; + } + for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) { + int defReg = phi->ssaRep->defs[0]; + for (int i = 0; i < phi->ssaRep->numUses; i++) { + for (int j = 0; j < cUnit->numSSARegs; j++) { + if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) { + cUnit->phiAliasMap[j] = defReg; + } + } + } + } +} + +void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep, + RegLocation rlFree) +{ + if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) && + (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) { + // No overlap, free both + oatFreeTemp(cUnit, rlFree.lowReg); + oatFreeTemp(cUnit, rlFree.highReg); + } +} + +void spillCoreRegs(CompilationUnit* cUnit) { + if (cUnit->numCoreSpills == 0) { + return; + } + // Spill mask not including fake return address register + uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET); + int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills); + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + storeWordDisp(cUnit, rX86_SP, offset, reg); + offset += 4; + } + } +} + +void unSpillCoreRegs(CompilationUnit* cUnit) { + if (cUnit->numCoreSpills == 0) { + return; + } + // Spill mask not including fake return address register + uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET); + int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills); + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + loadWordDisp(cUnit, rX86_SP, offset, reg); + offset += 4; + } + } +} + +/* + * Nop any unconditional branches that go to the next instruction. + * Note: new redundant branches may be inserted later, and we'll + * use a check in final instruction assembly to nop those out. + */ +void removeRedundantBranches(CompilationUnit* cUnit) { + LIR* thisLIR; + + for (thisLIR = (LIR*) cUnit->firstLIRInsn; + thisLIR != (LIR*) cUnit->lastLIRInsn; + thisLIR = NEXT_LIR(thisLIR)) { + + /* Branch to the next instruction */ + if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) { + LIR* nextLIR = thisLIR; + + while (true) { + nextLIR = NEXT_LIR(nextLIR); + + /* + * Is the branch target the next instruction? + */ + if (nextLIR == (LIR*) thisLIR->target) { + thisLIR->flags.isNop = true; + break; + } + + /* + * Found real useful stuff between the branch and the target. + * Need to explicitly check the lastLIRInsn here because it + * might be the last real instruction. + */ + if (!isPseudoOpcode(nextLIR->opcode) || + (nextLIR = (LIR*) cUnit->lastLIRInsn)) + break; + } + } + } +} + +/* Common initialization routine for an architecture family */ +bool oatArchInit() { + int i; + + for (i = 0; i < kX86Last; i++) { + if (EncodingMap[i].opcode != i) { + LOG(FATAL) << "Encoding order for " << EncodingMap[i].name + << " is wrong: expecting " << i << ", seeing " + << (int)EncodingMap[i].opcode; + } + } + + return oatArchVariantInit(); +} + +// Not used in x86 +int loadHelper(CompilationUnit* cUnit, int offset) +{ + LOG(FATAL) << "Unexpected use of loadHelper in x86"; + return INVALID_REG; +} + +} // namespace art diff --git a/src/compiler/codegen/x86/X86/Factory.cc b/src/compiler/codegen/x86/utility_x86.cc index 454b98d687..418a6fe0c1 100644 --- a/src/compiler/codegen/x86/X86/Factory.cc +++ b/src/compiler/codegen/x86/utility_x86.cc @@ -18,28 +18,6 @@ namespace art { /* This file contains codegen for the X86 ISA */ -//FIXME: restore "static" when usage uncovered -/*static*/ int coreRegs[] = { - rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI -#ifdef TARGET_REX_SUPPORT - r8, r9, r10, r11, r12, r13, r14, 15 -#endif -}; -/*static*/ int reservedRegs[] = {rX86_SP}; -/*static*/ int coreTemps[] = {rAX, rCX, rDX, rBX}; -/*static*/ int fpRegs[] = { - fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, -#ifdef TARGET_REX_SUPPORT - fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 -#endif -}; -/*static*/ int fpTemps[] = { - fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, -#ifdef TARGET_REX_SUPPORT - fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 -#endif -}; - void genBarrier(CompilationUnit *cUnit); void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg); LIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, diff --git a/src/compiler/codegen/x86/x86/ArchVariant.cc b/src/compiler/codegen/x86/x86/ArchVariant.cc deleted file mode 100644 index 4b70202205..0000000000 --- a/src/compiler/codegen/x86/x86/ArchVariant.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace art { - -/* - * This file is included by Codegen-x86.c, and implements architecture - * variant-specific code. - */ - -/* - * Determine the initial instruction set to be used for this trace. - * Later components may decide to change this. - */ -InstructionSet oatInstructionSet() -{ - return kX86; -} - -/* Architecture-specific initializations and checks go here */ -bool oatArchVariantInit(void) -{ - return true; -} - -int dvmCompilerTargetOptHint(int key) -{ - int res; - switch (key) { - case kMaxHoistDistance: - res = 2; - break; - default: - LOG(FATAL) << "Unknown target optimization hint key: " << key; - } - return res; -} - -void oatGenMemBarrier(CompilationUnit *cUnit, int /* barrierKind */) -{ -#if ANDROID_SMP != 0 - // TODO: optimize fences - newLIR0(cUnit, kX86Mfence); -#endif -} - -} // namespace art diff --git a/src/compiler/codegen/x86/x86/Codegen.cc b/src/compiler/codegen/x86/x86/Codegen.cc deleted file mode 100644 index 744a7d2246..0000000000 --- a/src/compiler/codegen/x86/x86/Codegen.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _CODEGEN_C - -#include "../../../Dalvik.h" -#include "../../../CompilerInternals.h" -#include "../X86LIR.h" -#include "../../Ralloc.h" -#include "../Codegen.h" - -/* X86 codegen building blocks */ -#include "../../CodegenUtil.cc" - -/* X86-specific factory utilities */ -#include "../X86/Factory.cc" -/* Target independent factory utilities */ -#include "../../CodegenFactory.cc" -/* X86-specific codegen routines */ -#include "../X86/Gen.cc" -/* FP codegen routines */ -#include "../FP/X86FP.cc" -/* Target independent gen routines */ -#include "../../GenCommon.cc" -/* Shared invoke gen routines */ -#include "../../GenInvoke.cc" -/* X86-specific factory utilities */ -#include "../ArchFactory.cc" - -/* X86-specific register allocation */ -#include "../X86/Ralloc.cc" - -/* Bitcode conversion */ -#include "../../MethodBitcode.cc" - -/* MIR2LIR dispatcher and architectural independent codegen routines */ -#include "../../MethodCodegenDriver.cc" - -/* Target-independent local optimizations */ -#include "../../LocalOptimizations.cc" - -/* Architecture manifest */ -#include "ArchVariant.cc" diff --git a/src/compiler/codegen/x86/X86LIR.h b/src/compiler/codegen/x86/x86_lir.h index bccd365604..fe6d8cb338 100644 --- a/src/compiler/codegen/x86/X86LIR.h +++ b/src/compiler/codegen/x86/x86_lir.h @@ -17,8 +17,8 @@ #ifndef ART_COMPILER_COMPILER_CODEGEN_X86_X86LIR_H_ #define ART_COMPILER_COMPILER_CODEGEN_X86_X86LIR_H_ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" namespace art { |