diff options
Diffstat (limited to 'src/compiler/codegen')
| -rw-r--r-- | src/compiler/codegen/arm/ArchFactory.cc | 227 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/ArmRallocUtil.cc | 186 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/Thumb2/Ralloc.cc | 119 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/arm_lir.h (renamed from src/compiler/codegen/arm/ArmLIR.h) | 4 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/armv7-a/ArchVariant.cc | 55 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/armv7-a/Codegen.cc | 57 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/assemble_arm.cc (renamed from src/compiler/codegen/arm/Assemble.cc) | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/backend_arm.cc | 43 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/call_arm.cc (renamed from src/compiler/codegen/arm/Thumb2/Gen.cc) | 565 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/codegen.h (renamed from src/compiler/codegen/arm/Codegen.h) | 2 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/fp_arm.cc (renamed from src/compiler/codegen/arm/FP/Thumb2VFP.cc) | 44 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/int_arm.cc | 549 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/target_arm.cc (renamed from src/compiler/codegen/arm/ArchUtility.cc) | 361 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/utility_arm.cc (renamed from src/compiler/codegen/arm/Thumb2/Factory.cc) | 11 | ||||
| -rw-r--r-- | src/compiler/codegen/codegen_factory.cc (renamed from src/compiler/codegen/CodegenFactory.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/codegen_util.cc (renamed from src/compiler/codegen/CodegenUtil.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/compiler_codegen.h (renamed from src/compiler/codegen/CompilerCodegen.h) | 13 | ||||
| -rw-r--r-- | src/compiler/codegen/gen_common.cc (renamed from src/compiler/codegen/GenCommon.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/gen_invoke.cc (renamed from src/compiler/codegen/GenInvoke.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/local_optimizations.cc (renamed from src/compiler/codegen/LocalOptimizations.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/method_bitcode.cc (renamed from src/compiler/codegen/MethodBitcode.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/method_codegen_driver.cc (renamed from src/compiler/codegen/MethodCodegenDriver.cc) | 0 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/ArchFactory.cc | 281 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/ArchUtility.cc | 308 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/Mips32/Ralloc.cc | 129 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/MipsRallocUtil.cc | 183 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/assemble_mips.cc (renamed from src/compiler/codegen/mips/Assemble.cc) | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/backend_mips.cc | 43 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/call_mips.cc (renamed from src/compiler/codegen/mips/Mips32/Gen.cc) | 398 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/codegen.h (renamed from src/compiler/codegen/mips/Codegen.h) | 2 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/fp_mips.cc (renamed from src/compiler/codegen/mips/FP/MipsFP.cc) | 25 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/int_mips.cc | 443 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/mips/ArchVariant.cc | 59 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/mips/Codegen.cc | 57 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/mips_lir.h (renamed from src/compiler/codegen/mips/MipsLIR.h) | 4 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/target_mips.cc | 719 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/utility_mips.cc (renamed from src/compiler/codegen/mips/Mips32/Factory.cc) | 15 | ||||
| -rw-r--r-- | src/compiler/codegen/optimizer.h (renamed from src/compiler/codegen/Optimizer.h) | 2 | ||||
| -rw-r--r-- | src/compiler/codegen/ralloc.h (renamed from src/compiler/codegen/Ralloc.h) | 6 | ||||
| -rw-r--r-- | src/compiler/codegen/ralloc_util.cc (renamed from src/compiler/codegen/RallocUtil.cc) | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/ArchFactory.cc | 282 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/ArchUtility.cc | 304 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/X86/Ralloc.cc | 113 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/X86RallocUtil.cc | 151 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/assemble_x86.cc (renamed from src/compiler/codegen/x86/Assemble.cc) | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/backend_x86.cc | 43 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/call_x86.cc | 276 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/codegen.h (renamed from src/compiler/codegen/x86/Codegen.h) | 2 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/fp_x86.cc (renamed from src/compiler/codegen/x86/FP/X86FP.cc) | 26 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/int_x86.cc (renamed from src/compiler/codegen/x86/X86/Gen.cc) | 329 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/target_x86.cc | 664 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/utility_x86.cc (renamed from src/compiler/codegen/x86/X86/Factory.cc) | 22 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/x86/ArchVariant.cc | 60 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/x86/Codegen.cc | 56 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/x86_lir.h (renamed from src/compiler/codegen/x86/X86LIR.h) | 4 |
55 files changed, 3505 insertions, 3769 deletions
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc deleted file mode 100644 index f75d8e3580..0000000000 --- a/src/compiler/codegen/arm/ArchFactory.cc +++ /dev/null @@ -1,227 +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 arm-specific codegen factory support. */ - -#include "oat/runtime/oat_support_entrypoints.h" - -namespace art { - -bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - int zReg = oatAllocTemp(cUnit); - loadConstantNoClobber(cUnit, zReg, 0); - // Check for destructive overlap - if (rlResult.lowReg == rlSrc.highReg) { - int tReg = oatAllocTemp(cUnit); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg); - opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, tReg); - oatFreeTemp(cUnit, tReg); - } else { - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg); - opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, rlSrc.highReg); - } - oatFreeTemp(cUnit, zReg); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -int loadHelper(CompilationUnit* cUnit, int offset) -{ - loadWordDisp(cUnit, rARM_SELF, offset, rARM_LR); - return rARM_LR; -} - -void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, - RegLocation rlMethod) -{ - int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; - /* - * On entry, r0, r1, r2 & r3 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 a single temp: r12. This should be enough. - */ - oatLockTemp(cUnit, r0); - oatLockTemp(cUnit, r1); - oatLockTemp(cUnit, r2); - oatLockTemp(cUnit, r3); - - /* - * 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); - if (!skipOverflowCheck) { - /* Load stack limit */ - loadWordDisp(cUnit, rARM_SELF, Thread::StackEndOffset().Int32Value(), r12); - } - /* Spill core callee saves */ - newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask); - /* Need to spill any FP regs? */ - if (cUnit->numFPSpills) { - /* - * NOTE: fp spills are a little different from core spills in that - * they are pushed as a contiguous block. When promoting from - * the fp set, we must allocate all singles from s16..highest-promoted - */ - newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills); - } - if (!skipOverflowCheck) { - opRegRegImm(cUnit, kOpSub, rARM_LR, rARM_SP, cUnit->frameSize - (spillCount * 4)); - genRegRegCheck(cUnit, kCondCc, rARM_LR, r12, kThrowStackOverflow); - opRegCopy(cUnit, rARM_SP, rARM_LR); // Establish stack - } else { - opRegImm(cUnit, kOpSub, rARM_SP, cUnit->frameSize - (spillCount * 4)); - } - - flushIns(cUnit, argLocs, rlMethod); - - oatFreeTemp(cUnit, r0); - oatFreeTemp(cUnit, r1); - oatFreeTemp(cUnit, r2); - oatFreeTemp(cUnit, r3); -} - -void genExitSequence(CompilationUnit* cUnit) -{ - int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; - /* - * In the exit path, r0/r1 are live - make sure they aren't - * allocated by the register utilities as temps. - */ - oatLockTemp(cUnit, r0); - oatLockTemp(cUnit, r1); - - newLIR0(cUnit, kPseudoMethodExit); - opRegImm(cUnit, kOpAdd, rARM_SP, cUnit->frameSize - (spillCount * 4)); - /* Need to restore any FP callee saves? */ - if (cUnit->numFPSpills) { - newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills); - } - if (cUnit->coreSpillMask & (1 << rARM_LR)) { - /* Unspill rARM_LR to rARM_PC */ - cUnit->coreSpillMask &= ~(1 << rARM_LR); - cUnit->coreSpillMask |= (1 << rARM_PC); - } - newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask); - if (!(cUnit->coreSpillMask & (1 << rARM_PC))) { - /* We didn't pop to rARM_PC, so must do a bv rARM_LR */ - newLIR1(cUnit, kThumbBx, rARM_LR); - } -} - -/* - * 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 == kThumbBUncond) || - (thisLIR->opcode == kThumb2BUncond)) { - 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 < kArmLast; 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(); -} - -bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genAddLong for Arm"; - return false; -} - -bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genSubLong for Arm"; - return false; -} - -bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genAndLong for Arm"; - return false; -} - -bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genOrLong for Arm"; - return false; -} - -bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genXoLong for Arm"; - return false; -} - -} // namespace art diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc deleted file mode 100644 index 05fe7faa5e..0000000000 --- a/src/compiler/codegen/arm/ArmRallocUtil.cc +++ /dev/null @@ -1,186 +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 Arm-specific register allocation support. - */ - -#include "../../CompilerUtility.h" -#include "../../CompilerIR.h" -#include "../..//Dataflow.h" -#include "ArmLIR.h" -#include "Codegen.h" -#include "../Ralloc.h" - -namespace art { - -/* - * TUNING: is leaf? Can't just use "hasInvoke" to determine as some - * instructions might call out to C/assembly helper functions. Until - * machinery is in place, always spill lr. - */ - -void oatAdjustSpillMask(CompilationUnit* cUnit) -{ - cUnit->coreSpillMask |= (1 << rARM_LR); - 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) -{ - DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE); - reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE; - // Ensure fpVmapTable is large enough - int tableSize = cUnit->fpVmapTable.size(); - for (int i = tableSize; i < (reg + 1); i++) { - cUnit->fpVmapTable.push_back(INVALID_VREG); - } - // Add the current mapping - cUnit->fpVmapTable[reg] = vReg; - // Size of fpVmapTable is high-water mark, use to set mask - cUnit->numFPSpills = cUnit->fpVmapTable.size(); - cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << ARM_FP_CALLEE_SAVE_BASE; -} - -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, rARM_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, rARM_SP, oatVRegOffset(cUnit, vReg), reg, kWord); - } -} - -/* Give access to the target-dependent FP register encoding to common code */ -bool oatIsFpReg(int reg) { - return ARM_FPREG(reg); -} - -uint32_t oatFpRegMask() { - return ARM_FP_REG_MASK; -} - -/* Clobber all regs that might be used by an external C call */ -void oatClobberCalleeSave(CompilationUnit *cUnit) -{ - oatClobber(cUnit, r0); - oatClobber(cUnit, r1); - oatClobber(cUnit, r2); - oatClobber(cUnit, r3); - oatClobber(cUnit, r12); - oatClobber(cUnit, r14lr); - oatClobber(cUnit, fr0); - oatClobber(cUnit, fr1); - oatClobber(cUnit, fr2); - oatClobber(cUnit, fr3); - oatClobber(cUnit, fr4); - oatClobber(cUnit, fr5); - oatClobber(cUnit, fr6); - oatClobber(cUnit, fr7); - oatClobber(cUnit, fr8); - oatClobber(cUnit, fr9); - oatClobber(cUnit, fr10); - oatClobber(cUnit, fr11); - oatClobber(cUnit, fr12); - oatClobber(cUnit, fr13); - oatClobber(cUnit, fr14); - oatClobber(cUnit, fr15); -} - -extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) -{ - RegLocation res = locCReturnWide(); - res.lowReg = r2; - res.highReg = r3; - oatClobber(cUnit, r2); - oatClobber(cUnit, r3); - oatMarkInUse(cUnit, r2); - oatMarkInUse(cUnit, r3); - oatMarkPair(cUnit, res.lowReg, res.highReg); - return res; -} - -extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) -{ - RegLocation res = locCReturn(); - res.lowReg = r1; - oatClobber(cUnit, r1); - oatMarkInUse(cUnit, r1); - return res; -} - -extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) -{ - return ARM_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & ARM_FP_REG_MASK] - : &cUnit->regPool->coreRegs[reg]; -} - -/* To be used when explicitly managing register use */ -extern void oatLockCallTemps(CompilationUnit* cUnit) -{ - oatLockTemp(cUnit, r0); - oatLockTemp(cUnit, r1); - oatLockTemp(cUnit, r2); - oatLockTemp(cUnit, r3); -} - -/* To be used when explicitly managing register use */ -extern void oatFreeCallTemps(CompilationUnit* cUnit) -{ - oatFreeTemp(cUnit, r0); - oatFreeTemp(cUnit, r1); - oatFreeTemp(cUnit, r2); - oatFreeTemp(cUnit, r3); -} - -/* Convert an instruction to a NOP */ -void oatNopLIR( LIR* lir) -{ - ((LIR*)lir)->flags.isNop = true; -} - -} // namespace art diff --git a/src/compiler/codegen/arm/Thumb2/Ralloc.cc b/src/compiler/codegen/arm/Thumb2/Ralloc.cc deleted file mode 100644 index ab5cf337bb..0000000000 --- a/src/compiler/codegen/arm/Thumb2/Ralloc.cc +++ /dev/null @@ -1,119 +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. - */ - -namespace art { - -/* This file contains codegen for the Thumb 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; - } else { - 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++) { - if (NO_SUSPEND && (reservedRegs[i] == rARM_SUSPEND)) { - //To measure cost of suspend check - continue; - } - 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]); - } - - // Start allocation at r2 in an attempt to avoid clobbering return values - pool->nextCoreReg = r2; - - // 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/arm/ArmLIR.h b/src/compiler/codegen/arm/arm_lir.h index 7eebc835ec..a068502972 100644 --- a/src/compiler/codegen/arm/ArmLIR.h +++ b/src/compiler/codegen/arm/arm_lir.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_ #define ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" namespace art { diff --git a/src/compiler/codegen/arm/armv7-a/ArchVariant.cc b/src/compiler/codegen/arm/armv7-a/ArchVariant.cc deleted file mode 100644 index 3977d502ca..0000000000 --- a/src/compiler/codegen/arm/armv7-a/ArchVariant.cc +++ /dev/null @@ -1,55 +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. - */ - -namespace art { - -/* - * Determine the initial instruction set to be used for this trace. - * Later components may decide to change this. - */ -InstructionSet oatInstructionSet() -{ - return kThumb2; -} - -/* Architecture-specific initializations and checks go here */ -bool oatArchVariantInit(void) -{ - return true; -} - -int oatTargetOptHint(int key) -{ - int res = 0; - switch (key) { - case kMaxHoistDistance: - res = 7; - break; - default: - LOG(FATAL) << "Unknown target optimization hint key: " << key; - } - return res; -} - -void oatGenMemBarrier(CompilationUnit* cUnit, int barrierKind) -{ -#if ANDROID_SMP != 0 - LIR* dmb = newLIR1(cUnit, kThumb2Dmb, barrierKind); - dmb->defMask = ENCODE_ALL; -#endif -} - -} // namespace art diff --git a/src/compiler/codegen/arm/armv7-a/Codegen.cc b/src/compiler/codegen/arm/armv7-a/Codegen.cc deleted file mode 100644 index c398b8ebfc..0000000000 --- a/src/compiler/codegen/arm/armv7-a/Codegen.cc +++ /dev/null @@ -1,57 +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. - */ -#define _CODEGEN_C -#define _ARMV7_A - -#include "../../../Dalvik.h" -#include "../../../CompilerInternals.h" -#include "../ArmLIR.h" -#include "../../Ralloc.h" -#include "../Codegen.h" - -/* Common codegen utility code */ -#include "../../CodegenUtil.cc" - -/* Thumb2-specific factory utilities */ -#include "../Thumb2/Factory.cc" -/* Target independent factory utilities */ -#include "../../CodegenFactory.cc" -/* Target independent gen routines */ -#include "../../GenCommon.cc" -/* Shared invoke gen routines */ -#include "../../GenInvoke.cc" -/* Arm-specific factory utilities */ -#include "../ArchFactory.cc" - -/* Thumb2-specific codegen routines */ -#include "../Thumb2/Gen.cc" -/* Thumb2+VFP codegen routines */ -#include "../FP/Thumb2VFP.cc" - -/* Thumb2-specific register allocation */ -#include "../Thumb2/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/arm/Assemble.cc b/src/compiler/codegen/arm/assemble_arm.cc index 765a8ffc66..e1b867254a 100644 --- a/src/compiler/codegen/arm/Assemble.cc +++ b/src/compiler/codegen/arm/assemble_arm.cc @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" -#include "ArmLIR.h" -#include "Codegen.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" +#include "arm_lir.h" +#include "codegen.h" namespace art { diff --git a/src/compiler/codegen/arm/backend_arm.cc b/src/compiler/codegen/arm/backend_arm.cc new file mode 100644 index 0000000000..d8f29968d0 --- /dev/null +++ b/src/compiler/codegen/arm/backend_arm.cc @@ -0,0 +1,43 @@ +/* + * 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. + */ +#define _CODEGEN_C +#define _ARMV7_A + +#include "../../dalvik.h" +#include "../../compiler_internals.h" +#include "arm_lir.h" +#include "../ralloc.h" +#include "codegen.h" + +/* Common codegen utility code */ +#include "../codegen_util.cc" + +#include "utility_arm.cc" +#include "../codegen_factory.cc" +#include "../gen_common.cc" +#include "../gen_invoke.cc" +#include "call_arm.cc" +#include "fp_arm.cc" +#include "int_arm.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/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/call_arm.cc index 0a8e579477..3fd5b15b8d 100644 --- a/src/compiler/codegen/arm/Thumb2/Gen.cc +++ b/src/compiler/codegen/arm/call_arm.cc @@ -302,51 +302,6 @@ void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, } } -LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, - int src2, LIR* target) -{ - opRegReg(cUnit, kOpCmp, src1, src2); - return opCondBranch(cUnit, cond, target); -} - -/* - * Generate a Thumb2 IT instruction, which can nullify up to - * four subsequent instructions based on a condition and its - * inverse. The condition applies to the first instruction, which - * is executed if the condition is met. The string "guide" consists - * of 0 to 3 chars, and applies to the 2nd through 4th instruction. - * A "T" means the instruction is executed if the condition is - * met, and an "E" means the instruction is executed if the condition - * is not met. - */ -LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide) -{ - int mask; - int condBit = code & 1; - int altBit = condBit ^ 1; - int mask3 = 0; - int mask2 = 0; - int mask1 = 0; - - //Note: case fallthroughs intentional - switch (strlen(guide)) { - case 3: - mask1 = (guide[2] == 'T') ? condBit : altBit; - case 2: - mask2 = (guide[1] == 'T') ? condBit : altBit; - case 1: - mask3 = (guide[0] == 'T') ? condBit : altBit; - break; - case 0: - break; - default: - LOG(FATAL) << "OAT: bad case in opIT"; - } - mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) | - (1 << (3 - strlen(guide))); - return newLIR2(cUnit, kThumb2It, code, mask); -} - /* * The sparse table in the literal pool is an array of <key,displacement> * pairs. For each set, we'll load them as a pair using ldmia. @@ -497,25 +452,6 @@ void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, RegLocation markSafepointPC(cUnit, callInst); } -void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc) -{ - RegLocation rlResult; - rlSrc = loadValue(cUnit, rlSrc, kFPReg); - rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); - newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg); - storeValue(cUnit, rlDest, rlResult); -} - -void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc) -{ - RegLocation rlResult; - rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); - rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); - newLIR2(cUnit, kThumb2Vnegd, s2d(rlResult.lowReg, rlResult.highReg), - s2d(rlSrc.lowReg, rlSrc.highReg)); - storeValueWide(cUnit, rlDest, rlResult); -} - /* * Handle simple case (thin lock) inline. If it's complicated, bail * out to the heavyweight lock/unlock routines. We'll use dedicated @@ -604,267 +540,6 @@ void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) } /* - * 64-bit 3way compare function. - * mov rX, #-1 - * cmp op1hi, op2hi - * blt done - * bgt flip - * sub rX, op1lo, op2lo (treat as unsigned) - * beq done - * ite hi - * mov(hi) rX, #-1 - * mov(!hi) rX, #1 - * flip: - * neg rX - * done: - */ -void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LIR* target1; - LIR* target2; - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - int tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, -1); - opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); - LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL); - LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL); - opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg); - LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL); - - opIT(cUnit, kArmCondHi, "E"); - newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1)); - loadConstant(cUnit, tReg, 1); - genBarrier(cUnit); - - target2 = newLIR0(cUnit, kPseudoTargetLabel); - opRegReg(cUnit, kOpNeg, tReg, tReg); - - target1 = newLIR0(cUnit, kPseudoTargetLabel); - - RegLocation rlTemp = locCReturn(); // Just using as template, will change - rlTemp.lowReg = tReg; - storeValue(cUnit, rlDest, rlTemp); - oatFreeTemp(cUnit, tReg); - - branch1->target = (LIR*)target1; - branch2->target = (LIR*)target2; - branch3->target = branch1->target; -} - -void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) -{ - LIR* labelList = cUnit->blockLabelList; - LIR* taken = &labelList[bb->taken->id]; - LIR* notTaken = &labelList[bb->fallThrough->id]; - RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0); - RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2); - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]); - opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); - switch(ccode) { - case kCondEq: - opCondBranch(cUnit, kCondNe, notTaken); - break; - case kCondNe: - opCondBranch(cUnit, kCondNe, taken); - break; - case kCondLt: - opCondBranch(cUnit, kCondLt, taken); - opCondBranch(cUnit, kCondGt, notTaken); - ccode = kCondCc; - break; - case kCondLe: - opCondBranch(cUnit, kCondLt, taken); - opCondBranch(cUnit, kCondGt, notTaken); - ccode = kCondLs; - break; - case kCondGt: - opCondBranch(cUnit, kCondGt, taken); - opCondBranch(cUnit, kCondLt, notTaken); - ccode = kCondHi; - break; - case kCondGe: - opCondBranch(cUnit, kCondGt, taken); - opCondBranch(cUnit, kCondLt, notTaken); - ccode = kCondCs; - break; - default: - LOG(FATAL) << "Unexpected ccode: " << (int)ccode; - } - opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); - opCondBranch(cUnit, ccode, taken); -} - -/* - * Generate a register comparison to an immediate and branch. Caller - * is responsible for setting branch target field. - */ -LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, - int checkValue, LIR* target) -{ - LIR* branch; - int modImm; - ArmConditionCode armCond = oatArmConditionEncoding(cond); - if ((ARM_LOWREG(reg)) && (checkValue == 0) && - ((armCond == kArmCondEq) || (armCond == kArmCondNe))) { - branch = newLIR2(cUnit, (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, - reg, 0); - } else { - modImm = modifiedImmediate(checkValue); - if (ARM_LOWREG(reg) && ((checkValue & 0xff) == checkValue)) { - newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); - } else if (modImm >= 0) { - newLIR2(cUnit, kThumb2CmpRI8, reg, modImm); - } else { - int tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, checkValue); - opRegReg(cUnit, kOpCmp, reg, tReg); - } - branch = newLIR2(cUnit, kThumbBCond, 0, armCond); - } - branch->target = target; - return branch; -} -LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc) -{ - LIR* res; - int opcode; - if (ARM_FPREG(rDest) || ARM_FPREG(rSrc)) - return fpRegCopy(cUnit, rDest, rSrc); - if (ARM_LOWREG(rDest) && ARM_LOWREG(rSrc)) - opcode = kThumbMovRR; - else if (!ARM_LOWREG(rDest) && !ARM_LOWREG(rSrc)) - opcode = kThumbMovRR_H2H; - else if (ARM_LOWREG(rDest)) - opcode = kThumbMovRR_H2L; - else - opcode = kThumbMovRR_L2H; - res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc); - if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) { - res->flags.isNop = true; - } - return res; -} - -LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc) -{ - LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc); - oatAppendLIR(cUnit, (LIR*)res); - return res; -} - -void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi, - int srcLo, int srcHi) -{ - bool destFP = ARM_FPREG(destLo) && ARM_FPREG(destHi); - bool srcFP = ARM_FPREG(srcLo) && ARM_FPREG(srcHi); - DCHECK_EQ(ARM_FPREG(srcLo), ARM_FPREG(srcHi)); - DCHECK_EQ(ARM_FPREG(destLo), ARM_FPREG(destHi)); - if (destFP) { - if (srcFP) { - opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi)); - } else { - newLIR3(cUnit, kThumb2Fmdrr, s2d(destLo, destHi), srcLo, srcHi); - } - } else { - if (srcFP) { - newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, s2d(srcLo, srcHi)); - } else { - // Handle overlap - if (srcHi == destLo) { - opRegCopy(cUnit, destHi, srcHi); - opRegCopy(cUnit, destLo, srcLo); - } else { - opRegCopy(cUnit, destLo, srcLo); - opRegCopy(cUnit, destHi, srcHi); - } - } - } -} - -// Table of magic divisors -enum DividePattern { - DivideNone, - Divide3, - Divide5, - Divide7, -}; - -struct MagicTable { - uint32_t magic; - uint32_t shift; - DividePattern pattern; -}; - -static const MagicTable magicTable[] = { - {0, 0, DivideNone}, // 0 - {0, 0, DivideNone}, // 1 - {0, 0, DivideNone}, // 2 - {0x55555556, 0, Divide3}, // 3 - {0, 0, DivideNone}, // 4 - {0x66666667, 1, Divide5}, // 5 - {0x2AAAAAAB, 0, Divide3}, // 6 - {0x92492493, 2, Divide7}, // 7 - {0, 0, DivideNone}, // 8 - {0x38E38E39, 1, Divide5}, // 9 - {0x66666667, 2, Divide5}, // 10 - {0x2E8BA2E9, 1, Divide5}, // 11 - {0x2AAAAAAB, 1, Divide5}, // 12 - {0x4EC4EC4F, 2, Divide5}, // 13 - {0x92492493, 3, Divide7}, // 14 - {0x88888889, 3, Divide7}, // 15 -}; - -// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4) -bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, - RegLocation rlSrc, RegLocation rlDest, int lit) -{ - if ((lit < 0) || (lit >= (int)(sizeof(magicTable)/sizeof(magicTable[0])))) { - return false; - } - DividePattern pattern = magicTable[lit].pattern; - if (pattern == DivideNone) { - return false; - } - // Tuning: add rem patterns - if (dalvikOpcode != Instruction::DIV_INT_LIT8) { - return false; - } - - int rMagic = oatAllocTemp(cUnit); - loadConstant(cUnit, rMagic, magicTable[lit].magic); - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - int rHi = oatAllocTemp(cUnit); - int rLo = oatAllocTemp(cUnit); - newLIR4(cUnit, kThumb2Smull, rLo, rHi, rMagic, rlSrc.lowReg); - switch(pattern) { - case Divide3: - opRegRegRegShift(cUnit, kOpSub, rlResult.lowReg, rHi, - rlSrc.lowReg, encodeShift(kArmAsr, 31)); - break; - case Divide5: - opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31); - opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi, - encodeShift(kArmAsr, magicTable[lit].shift)); - break; - case Divide7: - opRegReg(cUnit, kOpAdd, rHi, rlSrc.lowReg); - opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31); - opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi, - encodeShift(kArmAsr, magicTable[lit].shift)); - break; - default: - LOG(FATAL) << "Unexpected pattern: " << (int)pattern; - } - storeValue(cUnit, rlDest, rlResult); - return true; -} - -/* * Mark garbage collection card. Skip if the value we're storing is null. */ void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) @@ -882,182 +557,86 @@ void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) oatFreeTemp(cUnit, regCardNo); } -LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg1, int base, int offset, ThrowKind kind) -{ - LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm"; - return NULL; -} - -RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv) -{ - LOG(FATAL) << "Unexpected use of genDivRemLit for Arm"; - return rlDest; -} - -RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv) -{ - LOG(FATAL) << "Unexpected use of genDivRem for Arm"; - return rlDest; -} - -bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin) -{ - DCHECK_EQ(cUnit->instructionSet, kThumb2); - RegLocation rlSrc1 = info->args[0]; - RegLocation rlSrc2 = info->args[1]; - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - RegLocation rlDest = inlineTarget(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); - opIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E"); - opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg); - opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg); - genBarrier(cUnit); - storeValue(cUnit, rlDest, rlResult); - return true; -} - -void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset) -{ - LOG(FATAL) << "Unexpected use of opLea for Arm"; -} - -void opTlsCmp(CompilationUnit* cUnit, int offset, int val) -{ - LOG(FATAL) << "Unexpected use of opTlsCmp for Arm"; -} - -bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) { - DCHECK_EQ(cUnit->instructionSet, kThumb2); - // Unused - RegLocation rlSrcUnsafe = info->args[0]; - RegLocation rlSrcObj= info->args[1]; // Object - known non-null - RegLocation rlSrcOffset= info->args[2]; // long low - rlSrcOffset.wide = 0; // ignore high half in info->args[3] - RegLocation rlSrcExpected= info->args[4]; // int or Object - RegLocation rlSrcNewValue= info->args[5]; // int or Object - RegLocation rlDest = inlineTarget(cUnit, info); // boolean place for result - - - // Release store semantics, get the barrier out of the way. - oatGenMemBarrier(cUnit, kSY); - - RegLocation rlObject = loadValue(cUnit, rlSrcObj, kCoreReg); - RegLocation rlNewValue = loadValue(cUnit, rlSrcNewValue, kCoreReg); - - if (need_write_barrier) { - // Mark card for object assuming new value is stored. - markGCCard(cUnit, rlNewValue.lowReg, rlObject.lowReg); +void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, + RegLocation rlMethod) +{ + int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; + /* + * On entry, r0, r1, r2 & r3 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 a single temp: r12. This should be enough. + */ + oatLockTemp(cUnit, r0); + oatLockTemp(cUnit, r1); + oatLockTemp(cUnit, r2); + oatLockTemp(cUnit, r3); + + /* + * 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); + if (!skipOverflowCheck) { + /* Load stack limit */ + loadWordDisp(cUnit, rARM_SELF, Thread::StackEndOffset().Int32Value(), r12); + } + /* Spill core callee saves */ + newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask); + /* Need to spill any FP regs? */ + if (cUnit->numFPSpills) { + /* + * NOTE: fp spills are a little different from core spills in that + * they are pushed as a contiguous block. When promoting from + * the fp set, we must allocate all singles from s16..highest-promoted + */ + newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills); + } + if (!skipOverflowCheck) { + opRegRegImm(cUnit, kOpSub, rARM_LR, rARM_SP, cUnit->frameSize - (spillCount * 4)); + genRegRegCheck(cUnit, kCondCc, rARM_LR, r12, kThrowStackOverflow); + opRegCopy(cUnit, rARM_SP, rARM_LR); // Establish stack + } else { + opRegImm(cUnit, kOpSub, rARM_SP, cUnit->frameSize - (spillCount * 4)); } - RegLocation rlOffset = loadValue(cUnit, rlSrcOffset, kCoreReg); - - int rPtr = oatAllocTemp(cUnit); - opRegRegReg(cUnit, kOpAdd, rPtr, rlObject.lowReg, rlOffset.lowReg); - - // Free now unneeded rlObject and rlOffset to give more temps. - oatClobberSReg(cUnit, rlObject.sRegLow); - oatFreeTemp(cUnit, rlObject.lowReg); - oatClobberSReg(cUnit, rlOffset.sRegLow); - oatFreeTemp(cUnit, rlOffset.lowReg); - - int rOldValue = oatAllocTemp(cUnit); - newLIR3(cUnit, kThumb2Ldrex, rOldValue, rPtr, 0); // rOldValue := [rPtr] - - RegLocation rlExpected = loadValue(cUnit, rlSrcExpected, kCoreReg); - - // if (rOldValue == rExpected) { - // [rPtr] <- rNewValue && rResult := success ? 0 : 1 - // rResult ^= 1 - // } else { - // rResult := 0 - // } - opRegReg(cUnit, kOpCmp, rOldValue, rlExpected.lowReg); - oatFreeTemp(cUnit, rOldValue); // Now unneeded. - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opIT(cUnit, kArmCondEq, "TE"); - newLIR4(cUnit, kThumb2Strex, rlResult.lowReg, rlNewValue.lowReg, rPtr, 0); - oatFreeTemp(cUnit, rPtr); // Now unneeded. - opRegImm(cUnit, kOpXor, rlResult.lowReg, 1); - opRegReg(cUnit, kOpXor, rlResult.lowReg, rlResult.lowReg); - - storeValue(cUnit, rlDest, rlResult); - - return true; -} - -bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) { - DCHECK_EQ(cUnit->instructionSet, kThumb2); - LIR *branch; - RegLocation rlSrc = info->args[0]; - RegLocation rlDest = inlineTargetWide(cUnit, info); // double place for result - rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); - newLIR2(cUnit, kThumb2Vsqrtd, s2d(rlResult.lowReg, rlResult.highReg), - s2d(rlSrc.lowReg, rlSrc.highReg)); - newLIR2(cUnit, kThumb2Vcmpd, s2d(rlResult.lowReg, rlResult.highReg), - s2d(rlResult.lowReg, rlResult.highReg)); - newLIR0(cUnit, kThumb2Fmstat); - branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq); - oatClobberCalleeSave(cUnit); - oatLockCallTemps(cUnit); // Using fixed registers - int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pSqrt)); - newLIR3(cUnit, kThumb2Fmrrd, r0, r1, s2d(rlSrc.lowReg, rlSrc.highReg)); - newLIR1(cUnit, kThumbBlxR, rTgt); - newLIR3(cUnit, kThumb2Fmdrr, s2d(rlResult.lowReg, rlResult.highReg), r0, r1); - branch->target = newLIR0(cUnit, kPseudoTargetLabel); - storeValueWide(cUnit, rlDest, rlResult); - return true; -} - -LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) -{ - return rawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target); -} + flushIns(cUnit, argLocs, rlMethod); -LIR* opVldm(CompilationUnit* cUnit, int rBase, int count) -{ - return newLIR3(cUnit, kThumb2Vldms, rBase, fr0, count); + oatFreeTemp(cUnit, r0); + oatFreeTemp(cUnit, r1); + oatFreeTemp(cUnit, r2); + oatFreeTemp(cUnit, r3); } -LIR* opVstm(CompilationUnit* cUnit, int rBase, int count) +void genExitSequence(CompilationUnit* cUnit) { - return newLIR3(cUnit, kThumb2Vstms, rBase, fr0, count); -} + int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; + /* + * In the exit path, r0/r1 are live - make sure they aren't + * allocated by the register utilities as temps. + */ + oatLockTemp(cUnit, r0); + oatLockTemp(cUnit, r1); -void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, - RegLocation rlResult, int lit, - int firstBit, int secondBit) -{ - opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg, - encodeShift(kArmLsl, secondBit - firstBit)); - if (firstBit != 0) { - opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); + newLIR0(cUnit, kPseudoMethodExit); + opRegImm(cUnit, kOpAdd, rARM_SP, cUnit->frameSize - (spillCount * 4)); + /* Need to restore any FP callee saves? */ + if (cUnit->numFPSpills) { + newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills); + } + if (cUnit->coreSpillMask & (1 << rARM_LR)) { + /* Unspill rARM_LR to rARM_PC */ + cUnit->coreSpillMask &= ~(1 << rARM_LR); + cUnit->coreSpillMask |= (1 << rARM_PC); + } + newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask); + if (!(cUnit->coreSpillMask & (1 << rARM_PC))) { + /* We didn't pop to rARM_PC, so must do a bv rARM_LR */ + newLIR1(cUnit, kThumbBx, rARM_LR); } -} - -void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi) -{ - int tReg = oatAllocTemp(cUnit); - newLIR4(cUnit, kThumb2OrrRRRs, tReg, regLo, regHi, 0); - oatFreeTemp(cUnit, tReg); - genCheck(cUnit, kCondEq, kThrowDivZero); -} - -// Test suspend flag, return target of taken suspend branch -LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target) -{ - newLIR2(cUnit, kThumbSubRI8, rARM_SUSPEND, 1); - return opCondBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, target); -} - -// Decrement register and branch on condition -LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target) -{ - // Combine sub & test using sub setflags encoding here - newLIR3(cUnit, kThumb2SubsRRI12, reg, reg, 1); - return opCondBranch(cUnit, cCode, target); } } // namespace art diff --git a/src/compiler/codegen/arm/Codegen.h b/src/compiler/codegen/arm/codegen.h index 0890c15bab..47f45c6c20 100644 --- a/src/compiler/codegen/arm/Codegen.h +++ b/src/compiler/codegen/arm/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/arm/FP/Thumb2VFP.cc b/src/compiler/codegen/arm/fp_arm.cc index 1774a5b23a..8c220500b2 100644 --- a/src/compiler/codegen/arm/FP/Thumb2VFP.cc +++ b/src/compiler/codegen/arm/fp_arm.cc @@ -272,4 +272,48 @@ bool genCmpFP(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDe return false; } +void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc) +{ + RegLocation rlResult; + rlSrc = loadValue(cUnit, rlSrc, kFPReg); + rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg); + storeValue(cUnit, rlDest, rlResult); +} + +void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc) +{ + RegLocation rlResult; + rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); + rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR2(cUnit, kThumb2Vnegd, s2d(rlResult.lowReg, rlResult.highReg), + s2d(rlSrc.lowReg, rlSrc.highReg)); + storeValueWide(cUnit, rlDest, rlResult); +} + +bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) { + DCHECK_EQ(cUnit->instructionSet, kThumb2); + LIR *branch; + RegLocation rlSrc = info->args[0]; + RegLocation rlDest = inlineTargetWide(cUnit, info); // double place for result + rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR2(cUnit, kThumb2Vsqrtd, s2d(rlResult.lowReg, rlResult.highReg), + s2d(rlSrc.lowReg, rlSrc.highReg)); + newLIR2(cUnit, kThumb2Vcmpd, s2d(rlResult.lowReg, rlResult.highReg), + s2d(rlResult.lowReg, rlResult.highReg)); + newLIR0(cUnit, kThumb2Fmstat); + branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq); + oatClobberCalleeSave(cUnit); + oatLockCallTemps(cUnit); // Using fixed registers + int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pSqrt)); + newLIR3(cUnit, kThumb2Fmrrd, r0, r1, s2d(rlSrc.lowReg, rlSrc.highReg)); + newLIR1(cUnit, kThumbBlxR, rTgt); + newLIR3(cUnit, kThumb2Fmdrr, s2d(rlResult.lowReg, rlResult.highReg), r0, r1); + branch->target = newLIR0(cUnit, kPseudoTargetLabel); + storeValueWide(cUnit, rlDest, rlResult); + return true; +} + + } // namespace art diff --git a/src/compiler/codegen/arm/int_arm.cc b/src/compiler/codegen/arm/int_arm.cc new file mode 100644 index 0000000000..d7bd5235fc --- /dev/null +++ b/src/compiler/codegen/arm/int_arm.cc @@ -0,0 +1,549 @@ +/* + * 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 codegen for the Thumb2 ISA. */ + +#include "oat_compilation_unit.h" +#include "oat/runtime/oat_support_entrypoints.h" + +namespace art { + +LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, + int src2, LIR* target) +{ + opRegReg(cUnit, kOpCmp, src1, src2); + return opCondBranch(cUnit, cond, target); +} + +/* + * Generate a Thumb2 IT instruction, which can nullify up to + * four subsequent instructions based on a condition and its + * inverse. The condition applies to the first instruction, which + * is executed if the condition is met. The string "guide" consists + * of 0 to 3 chars, and applies to the 2nd through 4th instruction. + * A "T" means the instruction is executed if the condition is + * met, and an "E" means the instruction is executed if the condition + * is not met. + */ +LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide) +{ + int mask; + int condBit = code & 1; + int altBit = condBit ^ 1; + int mask3 = 0; + int mask2 = 0; + int mask1 = 0; + + //Note: case fallthroughs intentional + switch (strlen(guide)) { + case 3: + mask1 = (guide[2] == 'T') ? condBit : altBit; + case 2: + mask2 = (guide[1] == 'T') ? condBit : altBit; + case 1: + mask3 = (guide[0] == 'T') ? condBit : altBit; + break; + case 0: + break; + default: + LOG(FATAL) << "OAT: bad case in opIT"; + } + mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) | + (1 << (3 - strlen(guide))); + return newLIR2(cUnit, kThumb2It, code, mask); +} + +/* + * 64-bit 3way compare function. + * mov rX, #-1 + * cmp op1hi, op2hi + * blt done + * bgt flip + * sub rX, op1lo, op2lo (treat as unsigned) + * beq done + * ite hi + * mov(hi) rX, #-1 + * mov(!hi) rX, #1 + * flip: + * neg rX + * done: + */ +void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LIR* target1; + LIR* target2; + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, -1); + opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); + LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL); + LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL); + opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg); + LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL); + + opIT(cUnit, kArmCondHi, "E"); + newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1)); + loadConstant(cUnit, tReg, 1); + genBarrier(cUnit); + + target2 = newLIR0(cUnit, kPseudoTargetLabel); + opRegReg(cUnit, kOpNeg, tReg, tReg); + + target1 = newLIR0(cUnit, kPseudoTargetLabel); + + RegLocation rlTemp = locCReturn(); // Just using as template, will change + rlTemp.lowReg = tReg; + storeValue(cUnit, rlDest, rlTemp); + oatFreeTemp(cUnit, tReg); + + branch1->target = (LIR*)target1; + branch2->target = (LIR*)target2; + branch3->target = branch1->target; +} + +void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) +{ + LIR* labelList = cUnit->blockLabelList; + LIR* taken = &labelList[bb->taken->id]; + LIR* notTaken = &labelList[bb->fallThrough->id]; + RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0); + RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2); + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]); + opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); + switch(ccode) { + case kCondEq: + opCondBranch(cUnit, kCondNe, notTaken); + break; + case kCondNe: + opCondBranch(cUnit, kCondNe, taken); + break; + case kCondLt: + opCondBranch(cUnit, kCondLt, taken); + opCondBranch(cUnit, kCondGt, notTaken); + ccode = kCondCc; + break; + case kCondLe: + opCondBranch(cUnit, kCondLt, taken); + opCondBranch(cUnit, kCondGt, notTaken); + ccode = kCondLs; + break; + case kCondGt: + opCondBranch(cUnit, kCondGt, taken); + opCondBranch(cUnit, kCondLt, notTaken); + ccode = kCondHi; + break; + case kCondGe: + opCondBranch(cUnit, kCondGt, taken); + opCondBranch(cUnit, kCondLt, notTaken); + ccode = kCondCs; + break; + default: + LOG(FATAL) << "Unexpected ccode: " << (int)ccode; + } + opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); + opCondBranch(cUnit, ccode, taken); +} + +/* + * Generate a register comparison to an immediate and branch. Caller + * is responsible for setting branch target field. + */ +LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, + int checkValue, LIR* target) +{ + LIR* branch; + int modImm; + ArmConditionCode armCond = oatArmConditionEncoding(cond); + if ((ARM_LOWREG(reg)) && (checkValue == 0) && + ((armCond == kArmCondEq) || (armCond == kArmCondNe))) { + branch = newLIR2(cUnit, (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, + reg, 0); + } else { + modImm = modifiedImmediate(checkValue); + if (ARM_LOWREG(reg) && ((checkValue & 0xff) == checkValue)) { + newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); + } else if (modImm >= 0) { + newLIR2(cUnit, kThumb2CmpRI8, reg, modImm); + } else { + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + opRegReg(cUnit, kOpCmp, reg, tReg); + } + branch = newLIR2(cUnit, kThumbBCond, 0, armCond); + } + branch->target = target; + return branch; +} +LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc) +{ + LIR* res; + int opcode; + if (ARM_FPREG(rDest) || ARM_FPREG(rSrc)) + return fpRegCopy(cUnit, rDest, rSrc); + if (ARM_LOWREG(rDest) && ARM_LOWREG(rSrc)) + opcode = kThumbMovRR; + else if (!ARM_LOWREG(rDest) && !ARM_LOWREG(rSrc)) + opcode = kThumbMovRR_H2H; + else if (ARM_LOWREG(rDest)) + opcode = kThumbMovRR_H2L; + else + opcode = kThumbMovRR_L2H; + res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc); + if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) { + res->flags.isNop = true; + } + return res; +} + +LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc) +{ + LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc); + oatAppendLIR(cUnit, (LIR*)res); + return res; +} + +void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi, + int srcLo, int srcHi) +{ + bool destFP = ARM_FPREG(destLo) && ARM_FPREG(destHi); + bool srcFP = ARM_FPREG(srcLo) && ARM_FPREG(srcHi); + DCHECK_EQ(ARM_FPREG(srcLo), ARM_FPREG(srcHi)); + DCHECK_EQ(ARM_FPREG(destLo), ARM_FPREG(destHi)); + if (destFP) { + if (srcFP) { + opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi)); + } else { + newLIR3(cUnit, kThumb2Fmdrr, s2d(destLo, destHi), srcLo, srcHi); + } + } else { + if (srcFP) { + newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, s2d(srcLo, srcHi)); + } else { + // Handle overlap + if (srcHi == destLo) { + opRegCopy(cUnit, destHi, srcHi); + opRegCopy(cUnit, destLo, srcLo); + } else { + opRegCopy(cUnit, destLo, srcLo); + opRegCopy(cUnit, destHi, srcHi); + } + } + } +} + +// Table of magic divisors +enum DividePattern { + DivideNone, + Divide3, + Divide5, + Divide7, +}; + +struct MagicTable { + uint32_t magic; + uint32_t shift; + DividePattern pattern; +}; + +static const MagicTable magicTable[] = { + {0, 0, DivideNone}, // 0 + {0, 0, DivideNone}, // 1 + {0, 0, DivideNone}, // 2 + {0x55555556, 0, Divide3}, // 3 + {0, 0, DivideNone}, // 4 + {0x66666667, 1, Divide5}, // 5 + {0x2AAAAAAB, 0, Divide3}, // 6 + {0x92492493, 2, Divide7}, // 7 + {0, 0, DivideNone}, // 8 + {0x38E38E39, 1, Divide5}, // 9 + {0x66666667, 2, Divide5}, // 10 + {0x2E8BA2E9, 1, Divide5}, // 11 + {0x2AAAAAAB, 1, Divide5}, // 12 + {0x4EC4EC4F, 2, Divide5}, // 13 + {0x92492493, 3, Divide7}, // 14 + {0x88888889, 3, Divide7}, // 15 +}; + +// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4) +bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, + RegLocation rlSrc, RegLocation rlDest, int lit) +{ + if ((lit < 0) || (lit >= (int)(sizeof(magicTable)/sizeof(magicTable[0])))) { + return false; + } + DividePattern pattern = magicTable[lit].pattern; + if (pattern == DivideNone) { + return false; + } + // Tuning: add rem patterns + if (dalvikOpcode != Instruction::DIV_INT_LIT8) { + return false; + } + + int rMagic = oatAllocTemp(cUnit); + loadConstant(cUnit, rMagic, magicTable[lit].magic); + rlSrc = loadValue(cUnit, rlSrc, kCoreReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + int rHi = oatAllocTemp(cUnit); + int rLo = oatAllocTemp(cUnit); + newLIR4(cUnit, kThumb2Smull, rLo, rHi, rMagic, rlSrc.lowReg); + switch(pattern) { + case Divide3: + opRegRegRegShift(cUnit, kOpSub, rlResult.lowReg, rHi, + rlSrc.lowReg, encodeShift(kArmAsr, 31)); + break; + case Divide5: + opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31); + opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi, + encodeShift(kArmAsr, magicTable[lit].shift)); + break; + case Divide7: + opRegReg(cUnit, kOpAdd, rHi, rlSrc.lowReg); + opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31); + opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi, + encodeShift(kArmAsr, magicTable[lit].shift)); + break; + default: + LOG(FATAL) << "Unexpected pattern: " << (int)pattern; + } + storeValue(cUnit, rlDest, rlResult); + return true; +} + +LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, + int reg1, int base, int offset, ThrowKind kind) +{ + LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm"; + return NULL; +} + +RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv) +{ + LOG(FATAL) << "Unexpected use of genDivRemLit for Arm"; + return rlDest; +} + +RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv) +{ + LOG(FATAL) << "Unexpected use of genDivRem for Arm"; + return rlDest; +} + +bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin) +{ + DCHECK_EQ(cUnit->instructionSet, kThumb2); + RegLocation rlSrc1 = info->args[0]; + RegLocation rlSrc2 = info->args[1]; + rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); + RegLocation rlDest = inlineTarget(cUnit, info); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); + opIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E"); + opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg); + opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg); + genBarrier(cUnit); + storeValue(cUnit, rlDest, rlResult); + return true; +} + +void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset) +{ + LOG(FATAL) << "Unexpected use of opLea for Arm"; +} + +void opTlsCmp(CompilationUnit* cUnit, int offset, int val) +{ + LOG(FATAL) << "Unexpected use of opTlsCmp for Arm"; +} + +bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) { + DCHECK_EQ(cUnit->instructionSet, kThumb2); + // Unused - RegLocation rlSrcUnsafe = info->args[0]; + RegLocation rlSrcObj= info->args[1]; // Object - known non-null + RegLocation rlSrcOffset= info->args[2]; // long low + rlSrcOffset.wide = 0; // ignore high half in info->args[3] + RegLocation rlSrcExpected= info->args[4]; // int or Object + RegLocation rlSrcNewValue= info->args[5]; // int or Object + RegLocation rlDest = inlineTarget(cUnit, info); // boolean place for result + + + // Release store semantics, get the barrier out of the way. + oatGenMemBarrier(cUnit, kSY); + + RegLocation rlObject = loadValue(cUnit, rlSrcObj, kCoreReg); + RegLocation rlNewValue = loadValue(cUnit, rlSrcNewValue, kCoreReg); + + if (need_write_barrier) { + // Mark card for object assuming new value is stored. + markGCCard(cUnit, rlNewValue.lowReg, rlObject.lowReg); + } + + RegLocation rlOffset = loadValue(cUnit, rlSrcOffset, kCoreReg); + + int rPtr = oatAllocTemp(cUnit); + opRegRegReg(cUnit, kOpAdd, rPtr, rlObject.lowReg, rlOffset.lowReg); + + // Free now unneeded rlObject and rlOffset to give more temps. + oatClobberSReg(cUnit, rlObject.sRegLow); + oatFreeTemp(cUnit, rlObject.lowReg); + oatClobberSReg(cUnit, rlOffset.sRegLow); + oatFreeTemp(cUnit, rlOffset.lowReg); + + int rOldValue = oatAllocTemp(cUnit); + newLIR3(cUnit, kThumb2Ldrex, rOldValue, rPtr, 0); // rOldValue := [rPtr] + + RegLocation rlExpected = loadValue(cUnit, rlSrcExpected, kCoreReg); + + // if (rOldValue == rExpected) { + // [rPtr] <- rNewValue && rResult := success ? 0 : 1 + // rResult ^= 1 + // } else { + // rResult := 0 + // } + opRegReg(cUnit, kOpCmp, rOldValue, rlExpected.lowReg); + oatFreeTemp(cUnit, rOldValue); // Now unneeded. + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + opIT(cUnit, kArmCondEq, "TE"); + newLIR4(cUnit, kThumb2Strex, rlResult.lowReg, rlNewValue.lowReg, rPtr, 0); + oatFreeTemp(cUnit, rPtr); // Now unneeded. + opRegImm(cUnit, kOpXor, rlResult.lowReg, 1); + opRegReg(cUnit, kOpXor, rlResult.lowReg, rlResult.lowReg); + + storeValue(cUnit, rlDest, rlResult); + + return true; +} + +LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) +{ + return rawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target); +} + +LIR* opVldm(CompilationUnit* cUnit, int rBase, int count) +{ + return newLIR3(cUnit, kThumb2Vldms, rBase, fr0, count); +} + +LIR* opVstm(CompilationUnit* cUnit, int rBase, int count) +{ + return newLIR3(cUnit, kThumb2Vstms, rBase, fr0, count); +} + +void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, + RegLocation rlResult, int lit, + int firstBit, int secondBit) +{ + opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg, + encodeShift(kArmLsl, secondBit - firstBit)); + if (firstBit != 0) { + opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); + } +} + +void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi) +{ + int tReg = oatAllocTemp(cUnit); + newLIR4(cUnit, kThumb2OrrRRRs, tReg, regLo, regHi, 0); + oatFreeTemp(cUnit, tReg); + genCheck(cUnit, kCondEq, kThrowDivZero); +} + +// Test suspend flag, return target of taken suspend branch +LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target) +{ + newLIR2(cUnit, kThumbSubRI8, rARM_SUSPEND, 1); + return opCondBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, target); +} + +// Decrement register and branch on condition +LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target) +{ + // Combine sub & test using sub setflags encoding here + newLIR3(cUnit, kThumb2SubsRRI12, reg, reg, 1); + return opCondBranch(cUnit, cCode, target); +} + +void oatGenMemBarrier(CompilationUnit* cUnit, int barrierKind) +{ +#if ANDROID_SMP != 0 + LIR* dmb = newLIR1(cUnit, kThumb2Dmb, barrierKind); + dmb->defMask = ENCODE_ALL; +#endif +} + +bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + int zReg = oatAllocTemp(cUnit); + loadConstantNoClobber(cUnit, zReg, 0); + // Check for destructive overlap + if (rlResult.lowReg == rlSrc.highReg) { + int tReg = oatAllocTemp(cUnit); + opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg); + opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, tReg); + oatFreeTemp(cUnit, tReg); + } else { + opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg); + opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, rlSrc.highReg); + } + oatFreeTemp(cUnit, zReg); + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genAddLong for Arm"; + return false; +} + +bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genSubLong for Arm"; + return false; +} + +bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genAndLong for Arm"; + return false; +} + +bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genOrLong for Arm"; + return false; +} + +bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genXoLong for Arm"; + return false; +} + +} // namespace art diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/target_arm.cc index 2d4b314d51..fc643ea8cc 100644 --- a/src/compiler/codegen/arm/ArchUtility.cc +++ b/src/compiler/codegen/arm/target_arm.cc @@ -14,14 +14,25 @@ * limitations under the License. */ -#include "../../CompilerInternals.h" -#include "ArmLIR.h" -#include "../Ralloc.h" +#include "../../compiler_internals.h" +#include "arm_lir.h" +#include "../ralloc.h" #include <string> namespace art { +static int coreRegs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10, + r11, r12, rARM_SP, rARM_LR, rARM_PC}; +static int reservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC}; +static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, + fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15, + fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23, + fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31}; +static int coreTemps[] = {r0, r1, r2, r3, r12}; +static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, + fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15}; + RegLocation locCReturn() { RegLocation res = ARM_LOC_C_RETURN; @@ -508,5 +519,349 @@ void oatDumpResourceMask(LIR* lir, u8 mask, const char* prefix) } } +/* + * 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 == kThumbBUncond) || + (thisLIR->opcode == kThumb2BUncond)) { + 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 < kArmLast; 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(); +} +/* + * Determine the initial instruction set to be used for this trace. + * Later components may decide to change this. + */ +InstructionSet oatInstructionSet() +{ + return kThumb2; +} + +/* Architecture-specific initializations and checks go here */ +bool oatArchVariantInit(void) +{ + return true; +} + +int oatTargetOptHint(int key) +{ + int res = 0; + switch (key) { + case kMaxHoistDistance: + res = 7; + break; + default: + LOG(FATAL) << "Unknown target optimization hint key: " << key; + } + return res; +} + +/* This file contains codegen for the Thumb 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; + } else { + 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++) { + if (NO_SUSPEND && (reservedRegs[i] == rARM_SUSPEND)) { + //To measure cost of suspend check + continue; + } + 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]); + } + + // Start allocation at r2 in an attempt to avoid clobbering return values + pool->nextCoreReg = r2; + + // 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); + } +} +/* + * TUNING: is leaf? Can't just use "hasInvoke" to determine as some + * instructions might call out to C/assembly helper functions. Until + * machinery is in place, always spill lr. + */ + +void oatAdjustSpillMask(CompilationUnit* cUnit) +{ + cUnit->coreSpillMask |= (1 << rARM_LR); + 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) +{ + DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE); + reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE; + // Ensure fpVmapTable is large enough + int tableSize = cUnit->fpVmapTable.size(); + for (int i = tableSize; i < (reg + 1); i++) { + cUnit->fpVmapTable.push_back(INVALID_VREG); + } + // Add the current mapping + cUnit->fpVmapTable[reg] = vReg; + // Size of fpVmapTable is high-water mark, use to set mask + cUnit->numFPSpills = cUnit->fpVmapTable.size(); + cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << ARM_FP_CALLEE_SAVE_BASE; +} + +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, rARM_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, rARM_SP, oatVRegOffset(cUnit, vReg), reg, kWord); + } +} + +/* Give access to the target-dependent FP register encoding to common code */ +bool oatIsFpReg(int reg) { + return ARM_FPREG(reg); +} + +uint32_t oatFpRegMask() { + return ARM_FP_REG_MASK; +} + +/* Clobber all regs that might be used by an external C call */ +void oatClobberCalleeSave(CompilationUnit *cUnit) +{ + oatClobber(cUnit, r0); + oatClobber(cUnit, r1); + oatClobber(cUnit, r2); + oatClobber(cUnit, r3); + oatClobber(cUnit, r12); + oatClobber(cUnit, r14lr); + oatClobber(cUnit, fr0); + oatClobber(cUnit, fr1); + oatClobber(cUnit, fr2); + oatClobber(cUnit, fr3); + oatClobber(cUnit, fr4); + oatClobber(cUnit, fr5); + oatClobber(cUnit, fr6); + oatClobber(cUnit, fr7); + oatClobber(cUnit, fr8); + oatClobber(cUnit, fr9); + oatClobber(cUnit, fr10); + oatClobber(cUnit, fr11); + oatClobber(cUnit, fr12); + oatClobber(cUnit, fr13); + oatClobber(cUnit, fr14); + oatClobber(cUnit, fr15); +} + +extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) +{ + RegLocation res = locCReturnWide(); + res.lowReg = r2; + res.highReg = r3; + oatClobber(cUnit, r2); + oatClobber(cUnit, r3); + oatMarkInUse(cUnit, r2); + oatMarkInUse(cUnit, r3); + oatMarkPair(cUnit, res.lowReg, res.highReg); + return res; +} + +extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) +{ + RegLocation res = locCReturn(); + res.lowReg = r1; + oatClobber(cUnit, r1); + oatMarkInUse(cUnit, r1); + return res; +} + +extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) +{ + return ARM_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & ARM_FP_REG_MASK] + : &cUnit->regPool->coreRegs[reg]; +} + +/* To be used when explicitly managing register use */ +extern void oatLockCallTemps(CompilationUnit* cUnit) +{ + oatLockTemp(cUnit, r0); + oatLockTemp(cUnit, r1); + oatLockTemp(cUnit, r2); + oatLockTemp(cUnit, r3); +} + +/* To be used when explicitly managing register use */ +extern void oatFreeCallTemps(CompilationUnit* cUnit) +{ + oatFreeTemp(cUnit, r0); + oatFreeTemp(cUnit, r1); + oatFreeTemp(cUnit, r2); + oatFreeTemp(cUnit, r3); +} + +/* Convert an instruction to a NOP */ +void oatNopLIR( LIR* lir) +{ + ((LIR*)lir)->flags.isNop = true; +} + +int loadHelper(CompilationUnit* cUnit, int offset) +{ + loadWordDisp(cUnit, rARM_SELF, offset, rARM_LR); + return rARM_LR; +} } // namespace art diff --git a/src/compiler/codegen/arm/Thumb2/Factory.cc b/src/compiler/codegen/arm/utility_arm.cc index fc3aaa0e95..e83093b198 100644 --- a/src/compiler/codegen/arm/Thumb2/Factory.cc +++ b/src/compiler/codegen/arm/utility_arm.cc @@ -18,17 +18,6 @@ namespace art { /* This file contains codegen for the Thumb ISA. */ -static int coreRegs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10, - r11, r12, rARM_SP, rARM_LR, rARM_PC}; -static int reservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC}; -static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, - fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15, - fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23, - fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31}; -static int coreTemps[] = {r0, r1, r2, r3, r12}; -static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, - fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15}; - int encodeImmSingle(int value) { int res; diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/codegen_factory.cc index 600b324841..600b324841 100644 --- a/src/compiler/codegen/CodegenFactory.cc +++ b/src/compiler/codegen/codegen_factory.cc diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/codegen_util.cc index b0a1e4437c..b0a1e4437c 100644 --- a/src/compiler/codegen/CodegenUtil.cc +++ b/src/compiler/codegen/codegen_util.cc diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/compiler_codegen.h index 868e666b08..45838c1465 100644 --- a/src/compiler/codegen/CompilerCodegen.h +++ b/src/compiler/codegen/compiler_codegen.h @@ -17,7 +17,7 @@ #ifndef ART_SRC_COMPILER_COMPILERCODEGEN_H_ #define ART_SRC_COMPILER_COMPILERCODEGEN_H_ -#include "../CompilerIR.h" +#include "../compiler_ir.h" namespace art { @@ -222,6 +222,7 @@ LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* t LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide); uint64_t getPCUseDefEncoding(); uint64_t getRegMaskCommon(CompilationUnit* cUnit, int reg); +// TODO: clean up include files int s2d(int lowReg, int highReg); bool fpReg(int reg); bool singleReg(int reg); @@ -233,6 +234,16 @@ RegLocation locCReturn(); RegLocation locCReturnWide(); RegLocation locCReturnFloat(); RegLocation locCReturnDouble(); +LIR* loadWordDisp(CompilationUnit* cUnit, int rBase, int displacement, int rDest); +LIR *storeWordDisp(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc); +void removeRedundantBranches(CompilationUnit* cUnit); +LIR* newLIR0(CompilationUnit* cUnit, int opcode); +LIR* newLIR1(CompilationUnit* cUnit, int opcode, int dest); +LIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, int value); +void spillCoreRegs(CompilationUnit* cUnit); +void unSpillCoreRegs(CompilationUnit* cUnit); +void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset); } // namespace art diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/gen_common.cc index bc61c54f1f..bc61c54f1f 100644 --- a/src/compiler/codegen/GenCommon.cc +++ b/src/compiler/codegen/gen_common.cc diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/gen_invoke.cc index efd4f5ae6a..efd4f5ae6a 100644 --- a/src/compiler/codegen/GenInvoke.cc +++ b/src/compiler/codegen/gen_invoke.cc diff --git a/src/compiler/codegen/LocalOptimizations.cc b/src/compiler/codegen/local_optimizations.cc index 2688d65877..2688d65877 100644 --- a/src/compiler/codegen/LocalOptimizations.cc +++ b/src/compiler/codegen/local_optimizations.cc diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/method_bitcode.cc index 1e81458dca..1e81458dca 100644 --- a/src/compiler/codegen/MethodBitcode.cc +++ b/src/compiler/codegen/method_bitcode.cc diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/method_codegen_driver.cc index 3170abc7f0..3170abc7f0 100644 --- a/src/compiler/codegen/MethodCodegenDriver.cc +++ b/src/compiler/codegen/method_codegen_driver.cc diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc deleted file mode 100644 index 90c0ede67b..0000000000 --- a/src/compiler/codegen/mips/ArchFactory.cc +++ /dev/null @@ -1,281 +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 mips-specific codegen factory support. */ - -#include "oat/runtime/oat_support_entrypoints.h" - -namespace art { - -bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - /* - * [v1 v0] = [a1 a0] + [a3 a2]; - * addu v0,a2,a0 - * addu t1,a3,a1 - * sltu v1,v0,a2 - * addu v1,v1,t1 - */ - - opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg); - int tReg = oatAllocTemp(cUnit); - opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg); - newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg); - oatFreeTemp(cUnit, tReg); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - /* - * [v1 v0] = [a1 a0] - [a3 a2]; - * sltu t1,a0,a2 - * subu v0,a0,a2 - * subu v1,a1,a3 - * subu v1,v1,t1 - */ - - int tReg = oatAllocTemp(cUnit); - newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg); - opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg); - oatFreeTemp(cUnit, tReg); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - /* - * [v1 v0] = -[a1 a0] - * negu v0,a0 - * negu v1,a1 - * sltu t1,r_zero - * subu v1,v1,t1 - */ - - opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg); - opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg); - int tReg = oatAllocTemp(cUnit); - newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg); - opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg); - oatFreeTemp(cUnit, tReg); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -/* - * In the Arm code a it is typical to use the link register - * to hold the target address. However, for Mips we must - * ensure that all branch instructions can be restarted if - * there is a trap in the shadow. Allocate a temp register. - */ -int loadHelper(CompilationUnit* cUnit, int offset) -{ - loadWordDisp(cUnit, rMIPS_SELF, offset, r_T9); - return r_T9; -} - -void spillCoreRegs(CompilationUnit* cUnit) -{ - if (cUnit->numCoreSpills == 0) { - return; - } - uint32_t mask = cUnit->coreSpillMask; - int offset = cUnit->numCoreSpills * 4; - opRegImm(cUnit, kOpSub, rMIPS_SP, offset); - for (int reg = 0; mask; mask >>= 1, reg++) { - if (mask & 0x1) { - offset -= 4; - storeWordDisp(cUnit, rMIPS_SP, offset, reg); - } - } -} - -void unSpillCoreRegs(CompilationUnit* cUnit) -{ - if (cUnit->numCoreSpills == 0) { - return; - } - uint32_t mask = cUnit->coreSpillMask; - int offset = cUnit->frameSize; - for (int reg = 0; mask; mask >>= 1, reg++) { - if (mask & 0x1) { - offset -= 4; - loadWordDisp(cUnit, rMIPS_SP, offset, reg); - } - } - opRegImm(cUnit, kOpAdd, rMIPS_SP, cUnit->frameSize); -} - -void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, - RegLocation rlMethod) -{ - int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; - /* - * On entry, rMIPS_ARG0, rMIPS_ARG1, rMIPS_ARG2 & rMIPS_ARG3 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 a single temp: r12. This should be enough. - */ - oatLockTemp(cUnit, rMIPS_ARG0); - oatLockTemp(cUnit, rMIPS_ARG1); - oatLockTemp(cUnit, rMIPS_ARG2); - oatLockTemp(cUnit, rMIPS_ARG3); - - /* - * 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); - int checkReg = oatAllocTemp(cUnit); - int newSP = oatAllocTemp(cUnit); - if (!skipOverflowCheck) { - /* Load stack limit */ - loadWordDisp(cUnit, rMIPS_SELF, Thread::StackEndOffset().Int32Value(), checkReg); - } - /* Spill core callee saves */ - spillCoreRegs(cUnit); - /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ - DCHECK_EQ(cUnit->numFPSpills, 0); - if (!skipOverflowCheck) { - opRegRegImm(cUnit, kOpSub, newSP, rMIPS_SP, cUnit->frameSize - (spillCount * 4)); - genRegRegCheck(cUnit, kCondCc, newSP, checkReg, kThrowStackOverflow); - opRegCopy(cUnit, rMIPS_SP, newSP); // Establish stack - } else { - opRegImm(cUnit, kOpSub, rMIPS_SP, cUnit->frameSize - (spillCount * 4)); - } - - flushIns(cUnit, argLocs, rlMethod); - - oatFreeTemp(cUnit, rMIPS_ARG0); - oatFreeTemp(cUnit, rMIPS_ARG1); - oatFreeTemp(cUnit, rMIPS_ARG2); - oatFreeTemp(cUnit, rMIPS_ARG3); -} - -void genExitSequence(CompilationUnit* cUnit) -{ - /* - * In the exit path, rMIPS_RET0/rMIPS_RET1 are live - make sure they aren't - * allocated by the register utilities as temps. - */ - oatLockTemp(cUnit, rMIPS_RET0); - oatLockTemp(cUnit, rMIPS_RET1); - - newLIR0(cUnit, kPseudoMethodExit); - unSpillCoreRegs(cUnit); - opReg(cUnit, kOpBx, r_RA); -} - -/* - * 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 == kMipsB) { - 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 < kMipsLast; 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(); -} - -bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genAndLong for Mips"; - return false; -} - -bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genOrLong for Mips"; - return false; -} - -bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - LOG(FATAL) << "Unexpected use of genXorLong for Mips"; - return false; -} - - - -} // namespace art diff --git a/src/compiler/codegen/mips/ArchUtility.cc b/src/compiler/codegen/mips/ArchUtility.cc deleted file mode 100644 index 3063e69518..0000000000 --- a/src/compiler/codegen/mips/ArchUtility.cc +++ /dev/null @@ -1,308 +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 "MipsLIR.h" -#include "../Ralloc.h" - -#include <string> - -namespace art { - -RegLocation locCReturn() -{ - RegLocation res = MIPS_LOC_C_RETURN; - return res; -} - -RegLocation locCReturnWide() -{ - RegLocation res = MIPS_LOC_C_RETURN_WIDE; - return res; -} - -RegLocation locCReturnFloat() -{ - RegLocation res = MIPS_LOC_C_RETURN_FLOAT; - return res; -} - -RegLocation locCReturnDouble() -{ - RegLocation res = MIPS_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 = rMIPS_SELF; break; - case kSuspend: res = rMIPS_SUSPEND; break; - case kLr: res = rMIPS_LR; break; - case kPc: res = rMIPS_PC; break; - case kSp: res = rMIPS_SP; break; - case kArg0: res = rMIPS_ARG0; break; - case kArg1: res = rMIPS_ARG1; break; - case kArg2: res = rMIPS_ARG2; break; - case kArg3: res = rMIPS_ARG3; break; - case kFArg0: res = rMIPS_FARG0; break; - case kFArg1: res = rMIPS_FARG1; break; - case kFArg2: res = rMIPS_FARG2; break; - case kFArg3: res = rMIPS_FARG3; break; - case kRet0: res = rMIPS_RET0; break; - case kRet1: res = rMIPS_RET1; break; - case kInvokeTgt: res = rMIPS_INVOKE_TGT; break; - case kCount: res = rMIPS_COUNT; break; - } - return res; -} - -// Create a double from a pair of singles. -int s2d(int lowReg, int highReg) -{ - return MIPS_S2D(lowReg, highReg); -} - -// Is reg a single or double? -bool fpReg(int reg) -{ - return MIPS_FPREG(reg); -} - -// Is reg a single? -bool singleReg(int reg) -{ - return MIPS_SINGLEREG(reg); -} - -// Is reg a double? -bool doubleReg(int reg) -{ - return MIPS_DOUBLEREG(reg); -} - -// Return mask to strip off fp reg flags and bias. -uint32_t fpRegMask() -{ - return MIPS_FP_REG_MASK; -} - -// True if both regs single, both core or both double. -bool sameRegType(int reg1, int reg2) -{ - return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2)); -} - -/* - * Decode the register id. - */ -u8 getRegMaskCommon(CompilationUnit* cUnit, int reg) -{ - u8 seed; - int shift; - int regId; - - - regId = reg & 0x1f; - /* Each double register is equal to a pair of single-precision FP registers */ - seed = MIPS_DOUBLEREG(reg) ? 3 : 1; - /* FP register starts at bit position 16 */ - shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0; - /* Expand the double register id into single offset */ - shift += regId; - return (seed << shift); -} - -uint64_t getPCUseDefEncoding() -{ - return ENCODE_MIPS_REG_PC; -} - - -void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) -{ - DCHECK_EQ(cUnit->instructionSet, kMips); - - // Mips-specific resource map setup here. - uint64_t flags = EncodingMap[lir->opcode].flags; - - if (flags & REG_DEF_SP) { - lir->defMask |= ENCODE_MIPS_REG_SP; - } - - if (flags & REG_USE_SP) { - lir->useMask |= ENCODE_MIPS_REG_SP; - } - - if (flags & REG_DEF_LR) { - lir->defMask |= ENCODE_MIPS_REG_LR; - } -} - -/* For dumping instructions */ -#define MIPS_REG_COUNT 32 -static const char *mipsRegName[MIPS_REG_COUNT] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" -}; - -/* - * Interpret a format string and build a string no longer than size - * See format key in Assemble.c. - */ -std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) -{ - std::string buf; - int i; - const char *fmtEnd = &fmt[strlen(fmt)]; - char tbuf[256]; - char nc; - while (fmt < fmtEnd) { - int operand; - if (*fmt == '!') { - fmt++; - DCHECK_LT(fmt, fmtEnd); - nc = *fmt++; - if (nc=='!') { - strcpy(tbuf, "!"); - } else { - DCHECK_LT(fmt, fmtEnd); - DCHECK_LT((unsigned)(nc-'0'), 4u); - operand = lir->operands[nc-'0']; - switch (*fmt++) { - case 'b': - strcpy(tbuf,"0000"); - for (i=3; i>= 0; i--) { - tbuf[i] += operand & 1; - operand >>= 1; - } - break; - case 's': - sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK); - break; - case 'S': - DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0); - sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK); - break; - case 'h': - sprintf(tbuf,"%04x", operand); - break; - case 'M': - case 'd': - sprintf(tbuf,"%d", operand); - break; - case 'D': - sprintf(tbuf,"%d", operand+1); - break; - case 'E': - sprintf(tbuf,"%d", operand*4); - break; - case 'F': - sprintf(tbuf,"%d", operand*2); - break; - case 't': - sprintf(tbuf,"0x%08x (L%p)", (int) baseAddr + lir->offset + 4 + - (operand << 2), lir->target); - break; - case 'T': - sprintf(tbuf,"0x%08x", (int) (operand << 2)); - break; - case 'u': { - int offset_1 = lir->operands[0]; - int offset_2 = NEXT_LIR(lir)->operands[0]; - intptr_t target = - ((((intptr_t) baseAddr + lir->offset + 4) & ~3) + - (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc; - sprintf(tbuf, "%p", (void *) target); - break; - } - - /* Nothing to print for BLX_2 */ - case 'v': - strcpy(tbuf, "see above"); - break; - case 'r': - DCHECK(operand >= 0 && operand < MIPS_REG_COUNT); - strcpy(tbuf, mipsRegName[operand]); - break; - case 'N': - // Placeholder for delay slot handling - strcpy(tbuf, "; nop"); - break; - default: - strcpy(tbuf,"DecodeError"); - break; - } - buf += tbuf; - } - } else { - buf += *fmt++; - } - } - return buf; -} - -// FIXME: need to redo resource maps for MIPS - fix this at that time -void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) -{ - char buf[256]; - buf[0] = 0; - LIR *mipsLIR = (LIR *) lir; - - if (mask == ENCODE_ALL) { - strcpy(buf, "all"); - } else { - char num[8]; - int i; - - for (i = 0; i < kMipsRegEnd; i++) { - if (mask & (1ULL << i)) { - sprintf(num, "%d ", i); - strcat(buf, num); - } - } - - if (mask & ENCODE_CCODE) { - strcat(buf, "cc "); - } - if (mask & ENCODE_FP_STATUS) { - strcat(buf, "fpcc "); - } - /* Memory bits */ - if (mipsLIR && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff, - (mipsLIR->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/mips/Mips32/Ralloc.cc b/src/compiler/codegen/mips/Mips32/Ralloc.cc deleted file mode 100644 index b913bfb0f3..0000000000 --- a/src/compiler/codegen/mips/Mips32/Ralloc.cc +++ /dev/null @@ -1,129 +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 Mips 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; - -#ifdef __mips_hard_float - if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { - lowReg = oatAllocTempDouble(cUnit); - highReg = lowReg + 1; - res = (lowReg & 0xff) | ((highReg & 0xff) << 8); - return res; - } -#endif - - lowReg = oatAllocTemp(cUnit); - highReg = oatAllocTemp(cUnit); - res = (lowReg & 0xff) | ((highReg & 0xff) << 8); - return res; -} - -int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) -{ -#ifdef __mips_hard_float - if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) -{ - return oatAllocTempFloat(cUnit); -} -#endif - 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); -#ifdef __mips_hard_float - int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); - int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); -#else - int numFPRegs = 0; - int numFPTemps = 0; -#endif - 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++) { - if (NO_SUSPEND && (reservedRegs[i] == rMIPS_SUSPEND)) { - //To measure cost of suspend check - continue; - } - 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/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc deleted file mode 100644 index 4979ae023c..0000000000 --- a/src/compiler/codegen/mips/MipsRallocUtil.cc +++ /dev/null @@ -1,183 +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 Mips-specific register allocation support. - */ - -#include "../../CompilerUtility.h" -#include "../../CompilerIR.h" -#include "../..//Dataflow.h" -#include "MipsLIR.h" -#include "Codegen.h" -#include "../Ralloc.h" - -namespace art { - -/* - * TUNING: is leaf? Can't just use "hasInvoke" to determine as some - * instructions might call out to C/assembly helper functions. Until - * machinery is in place, always spill lr. - */ - -void oatAdjustSpillMask(CompilationUnit* cUnit) -{ - cUnit->coreSpillMask |= (1 << r_RA); - 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 sReg, int reg) -{ - LOG(FATAL) << "No support yet for promoted FP regs"; -} - -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, rMIPS_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, rMIPS_SP, oatVRegOffset(cUnit, vReg), reg, kWord); - } -} - -/* Give access to the target-dependent FP register encoding to common code */ -bool oatIsFpReg(int reg) { - return MIPS_FPREG(reg); -} - -uint32_t oatFpRegMask() { - return MIPS_FP_REG_MASK; -} - -/* Clobber all regs that might be used by an external C call */ -extern void oatClobberCalleeSave(CompilationUnit *cUnit) -{ - oatClobber(cUnit, r_ZERO); - oatClobber(cUnit, r_AT); - oatClobber(cUnit, r_V0); - oatClobber(cUnit, r_V1); - oatClobber(cUnit, r_A0); - oatClobber(cUnit, r_A1); - oatClobber(cUnit, r_A2); - oatClobber(cUnit, r_A3); - oatClobber(cUnit, r_T0); - oatClobber(cUnit, r_T1); - oatClobber(cUnit, r_T2); - oatClobber(cUnit, r_T3); - oatClobber(cUnit, r_T4); - oatClobber(cUnit, r_T5); - oatClobber(cUnit, r_T6); - oatClobber(cUnit, r_T7); - oatClobber(cUnit, r_T8); - oatClobber(cUnit, r_T9); - oatClobber(cUnit, r_K0); - oatClobber(cUnit, r_K1); - oatClobber(cUnit, r_GP); - oatClobber(cUnit, r_FP); - oatClobber(cUnit, r_RA); - oatClobber(cUnit, r_F0); - oatClobber(cUnit, r_F1); - oatClobber(cUnit, r_F2); - oatClobber(cUnit, r_F3); - oatClobber(cUnit, r_F4); - oatClobber(cUnit, r_F5); - oatClobber(cUnit, r_F6); - oatClobber(cUnit, r_F7); - oatClobber(cUnit, r_F8); - oatClobber(cUnit, r_F9); - oatClobber(cUnit, r_F10); - oatClobber(cUnit, r_F11); - oatClobber(cUnit, r_F12); - oatClobber(cUnit, r_F13); - oatClobber(cUnit, r_F14); - oatClobber(cUnit, r_F15); -} - -extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) -{ - UNIMPLEMENTED(FATAL) << "No oatGetReturnWideAlt for MIPS"; - RegLocation res = locCReturnWide(); - return res; -} - -extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) -{ - UNIMPLEMENTED(FATAL) << "No oatGetReturnAlt for MIPS"; - RegLocation res = locCReturn(); - return res; -} - -extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) -{ - return MIPS_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & MIPS_FP_REG_MASK] - : &cUnit->regPool->coreRegs[reg]; -} - -/* To be used when explicitly managing register use */ -extern void oatLockCallTemps(CompilationUnit* cUnit) -{ - oatLockTemp(cUnit, rMIPS_ARG0); - oatLockTemp(cUnit, rMIPS_ARG1); - oatLockTemp(cUnit, rMIPS_ARG2); - oatLockTemp(cUnit, rMIPS_ARG3); -} - -/* To be used when explicitly managing register use */ -extern void oatFreeCallTemps(CompilationUnit* cUnit) -{ - oatFreeTemp(cUnit, rMIPS_ARG0); - oatFreeTemp(cUnit, rMIPS_ARG1); - oatFreeTemp(cUnit, rMIPS_ARG2); - oatFreeTemp(cUnit, rMIPS_ARG3); -} - -/* Convert an instruction to a NOP */ -void oatNopLIR( LIR* lir) -{ - ((LIR*)lir)->flags.isNop = true; -} - -} // namespace art diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/assemble_mips.cc index e9dd2197e3..ab7a6775eb 100644 --- a/src/compiler/codegen/mips/Assemble.cc +++ b/src/compiler/codegen/mips/assemble_mips.cc @@ -14,10 +14,10 @@ * limitations under the License. */ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" -#include "MipsLIR.h" -#include "Codegen.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" +#include "mips_lir.h" +#include "codegen.h" namespace art { diff --git a/src/compiler/codegen/mips/backend_mips.cc b/src/compiler/codegen/mips/backend_mips.cc new file mode 100644 index 0000000000..023d6135e0 --- /dev/null +++ b/src/compiler/codegen/mips/backend_mips.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 "mips_lir.h" +#include "../ralloc.h" +#include "codegen.h" + +/* Common codegen building blocks */ +#include "../codegen_util.cc" + +#include "utility_mips.cc" +#include "../codegen_factory.cc" +#include "../gen_common.cc" +#include "../gen_invoke.cc" +#include "call_mips.cc" +#include "fp_mips.cc" +#include "int_mips.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/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/call_mips.cc index a772c09643..50cb5948e6 100644 --- a/src/compiler/codegen/mips/Mips32/Gen.cc +++ b/src/compiler/codegen/mips/call_mips.cc @@ -259,25 +259,6 @@ void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, markSafepointPC(cUnit, callInst); } -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); -} - /* * TODO: implement fast path to short-circuit thin-lock case */ @@ -311,249 +292,6 @@ void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc) } /* - * Compare two 64-bit values - * x = y return 0 - * x < y return -1 - * x > y return 1 - * - * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0 - * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0 - * subu res, t0, t1 # res = -1:1:0 for [ < > = ] - * bnez res, finish - * sltu t0, x.lo, y.lo - * sgtu r1, x.lo, y.lo - * subu res, t0, t1 - * finish: - * - */ -void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - int t0 = oatAllocTemp(cUnit); - int t1 = oatAllocTemp(cUnit); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg); - newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg); - newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); - LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL); - newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg); - newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg); - newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); - oatFreeTemp(cUnit, t0); - oatFreeTemp(cUnit, t1); - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branch->target = (LIR*)target; - storeValue(cUnit, rlDest, rlResult); -} - -LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, - int src2, LIR* target) -{ - LIR* branch; - MipsOpCode sltOp; - MipsOpCode brOp; - bool cmpZero = false; - bool swapped = false; - switch (cond) { - case kCondEq: - brOp = kMipsBeq; - cmpZero = true; - break; - case kCondNe: - brOp = kMipsBne; - cmpZero = true; - break; - case kCondCc: - sltOp = kMipsSltu; - brOp = kMipsBnez; - break; - case kCondCs: - sltOp = kMipsSltu; - brOp = kMipsBeqz; - break; - case kCondGe: - sltOp = kMipsSlt; - brOp = kMipsBeqz; - break; - case kCondGt: - sltOp = kMipsSlt; - brOp = kMipsBnez; - swapped = true; - break; - case kCondLe: - sltOp = kMipsSlt; - brOp = kMipsBeqz; - swapped = true; - break; - case kCondLt: - sltOp = kMipsSlt; - brOp = kMipsBnez; - break; - case kCondHi: // Gtu - sltOp = kMipsSltu; - brOp = kMipsBnez; - swapped = true; - break; - default: - LOG(FATAL) << "No support for ConditionCode: " << (int) cond; - return NULL; - } - if (cmpZero) { - branch = newLIR2(cUnit, brOp, src1, src2); - } else { - int tReg = oatAllocTemp(cUnit); - if (swapped) { - newLIR3(cUnit, sltOp, tReg, src2, src1); - } else { - newLIR3(cUnit, sltOp, tReg, src1, src2); - } - branch = newLIR1(cUnit, brOp, tReg); - oatFreeTemp(cUnit, tReg); - } - branch->target = target; - return branch; -} - -LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, - int checkValue, LIR* target) -{ - LIR* branch; - if (checkValue != 0) { - // TUNING: handle s16 & kCondLt/Mi case using slti - int tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, checkValue); - branch = opCmpBranch(cUnit, cond, reg, tReg, target); - oatFreeTemp(cUnit, tReg); - return branch; - } - MipsOpCode opc; - switch (cond) { - case kCondEq: opc = kMipsBeqz; break; - case kCondGe: opc = kMipsBgez; break; - case kCondGt: opc = kMipsBgtz; break; - case kCondLe: opc = kMipsBlez; break; - //case KCondMi: - case kCondLt: opc = kMipsBltz; break; - case kCondNe: opc = kMipsBnez; break; - default: - // Tuning: use slti when applicable - int tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, checkValue); - branch = opCmpBranch(cUnit, cond, reg, tReg, target); - oatFreeTemp(cUnit, tReg); - return branch; - } - branch = newLIR1(cUnit, opc, reg); - branch->target = target; - return branch; -} - -LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) -{ -#ifdef __mips_hard_float - if (MIPS_FPREG(rDest) || MIPS_FPREG(rSrc)) - return fpRegCopy(cUnit, rDest, rSrc); -#endif - LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove, - rDest, rSrc); - if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) { - res->flags.isNop = true; - } - return res; -} - -LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) -{ - LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc); - oatAppendLIR(cUnit, (LIR*)res); - return res; -} - -void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, - int srcLo, int srcHi) -{ -#ifdef __mips_hard_float - bool destFP = MIPS_FPREG(destLo) && MIPS_FPREG(destHi); - bool srcFP = MIPS_FPREG(srcLo) && MIPS_FPREG(srcHi); - assert(MIPS_FPREG(srcLo) == MIPS_FPREG(srcHi)); - assert(MIPS_FPREG(destLo) == MIPS_FPREG(destHi)); - if (destFP) { - if (srcFP) { - opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi)); - } else { - /* note the operands are swapped for the mtc1 instr */ - newLIR2(cUnit, kMipsMtc1, srcLo, destLo); - newLIR2(cUnit, kMipsMtc1, srcHi, destHi); - } - } else { - if (srcFP) { - newLIR2(cUnit, kMipsMfc1, destLo, srcLo); - newLIR2(cUnit, kMipsMfc1, destHi, srcHi); - } else { - // Handle overlap - if (srcHi == destLo) { - opRegCopy(cUnit, destHi, srcHi); - opRegCopy(cUnit, destLo, srcLo); - } else { - opRegCopy(cUnit, destLo, srcLo); - opRegCopy(cUnit, destHi, srcHi); - } - } - } -#else - // Handle overlap - if (srcHi == destLo) { - opRegCopy(cUnit, destHi, srcHi); - opRegCopy(cUnit, destLo, srcLo); - } else { - opRegCopy(cUnit, destLo, srcLo); - opRegCopy(cUnit, destHi, srcHi); - } -#endif -} - -void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) -{ - UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; -} - -LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg1, int base, int offset, ThrowKind kind) -{ - LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm"; - return NULL; -} - -RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv) -{ - newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, reg2); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (isDiv) { - newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO); - } else { - newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI); - } - return rlResult; -} - -RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv) -{ - int tReg = oatAllocTemp(cUnit); - newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit); - newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, tReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (isDiv) { - newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO); - } else { - newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI); - } - oatFreeTemp(cUnit, tReg); - return rlResult; -} - -/* * Mark garbage collection card. Skip if the value we're storing is null. */ void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) @@ -570,96 +308,66 @@ void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) oatFreeTemp(cUnit, regCardBase); oatFreeTemp(cUnit, regCardNo); } - -bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin) -{ - // TODO: need Mips implementation - return false; -} - -void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset) -{ - LOG(FATAL) << "Unexpected use of opLea for Arm"; -} - -void opTlsCmp(CompilationUnit* cUnit, int offset, int val) -{ - LOG(FATAL) << "Unexpected use of opTlsCmp for Arm"; -} - -bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) { - DCHECK_NE(cUnit->instructionSet, kThumb2); - 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 Mips"; - return NULL; -} - -LIR* opVldm(CompilationUnit* cUnit, int rBase, int count) -{ - LOG(FATAL) << "Unexpected use of opVldm for Mips"; - return NULL; -} - -LIR* opVstm(CompilationUnit* cUnit, int rBase, int count) -{ - LOG(FATAL) << "Unexpected use of opVstm for Mips"; - return NULL; -} - -void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, - RegLocation rlResult, int lit, - int firstBit, int secondBit) +void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs, + RegLocation rlMethod) { - int tReg = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit); - opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg); - oatFreeTemp(cUnit, tReg); - if (firstBit != 0) { - opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); + int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; + /* + * On entry, rMIPS_ARG0, rMIPS_ARG1, rMIPS_ARG2 & rMIPS_ARG3 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 a single temp: r12. This should be enough. + */ + oatLockTemp(cUnit, rMIPS_ARG0); + oatLockTemp(cUnit, rMIPS_ARG1); + oatLockTemp(cUnit, rMIPS_ARG2); + oatLockTemp(cUnit, rMIPS_ARG3); + + /* + * 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); + int checkReg = oatAllocTemp(cUnit); + int newSP = oatAllocTemp(cUnit); + if (!skipOverflowCheck) { + /* Load stack limit */ + loadWordDisp(cUnit, rMIPS_SELF, Thread::StackEndOffset().Int32Value(), checkReg); + } + /* Spill core callee saves */ + spillCoreRegs(cUnit); + /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ + DCHECK_EQ(cUnit->numFPSpills, 0); + if (!skipOverflowCheck) { + opRegRegImm(cUnit, kOpSub, newSP, rMIPS_SP, cUnit->frameSize - (spillCount * 4)); + genRegRegCheck(cUnit, kCondCc, newSP, checkReg, kThrowStackOverflow); + opRegCopy(cUnit, rMIPS_SP, newSP); // Establish stack + } else { + opRegImm(cUnit, kOpSub, rMIPS_SP, cUnit->frameSize - (spillCount * 4)); } -} - -void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi) -{ - int tReg = oatAllocTemp(cUnit); - opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi); - genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero); - oatFreeTemp(cUnit, tReg); -} - -// Test suspend flag, return target of taken suspend branch -LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target) -{ - opRegImm(cUnit, kOpSub, rMIPS_SUSPEND, 1); - return opCmpImmBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target); -} -// Decrement register and branch on condition -LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target) -{ - opRegImm(cUnit, kOpSub, reg, 1); - return opCmpImmBranch(cUnit, cCode, reg, 0, target); -} + flushIns(cUnit, argLocs, rlMethod); -bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, - RegLocation rlSrc, RegLocation rlDest, int lit) -{ - LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; - return false; + oatFreeTemp(cUnit, rMIPS_ARG0); + oatFreeTemp(cUnit, rMIPS_ARG1); + oatFreeTemp(cUnit, rMIPS_ARG2); + oatFreeTemp(cUnit, rMIPS_ARG3); } -LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide) +void genExitSequence(CompilationUnit* cUnit) { - LOG(FATAL) << "Unexpected use of opIT in Mips"; - return NULL; + /* + * In the exit path, rMIPS_RET0/rMIPS_RET1 are live - make sure they aren't + * allocated by the register utilities as temps. + */ + oatLockTemp(cUnit, rMIPS_RET0); + oatLockTemp(cUnit, rMIPS_RET1); + + newLIR0(cUnit, kPseudoMethodExit); + unSpillCoreRegs(cUnit); + opReg(cUnit, kOpBx, r_RA); } } // namespace art diff --git a/src/compiler/codegen/mips/Codegen.h b/src/compiler/codegen/mips/codegen.h index 03efe03c6a..0b3a01e4a0 100644 --- a/src/compiler/codegen/mips/Codegen.h +++ b/src/compiler/codegen/mips/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/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/fp_mips.cc index fb6c8df9e6..04056ad96d 100644 --- a/src/compiler/codegen/mips/FP/MipsFP.cc +++ b/src/compiler/codegen/mips/fp_mips.cc @@ -217,4 +217,29 @@ void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch"; } +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 genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin) +{ + // TODO: need Mips implementation + return false; +} + } // namespace art diff --git a/src/compiler/codegen/mips/int_mips.cc b/src/compiler/codegen/mips/int_mips.cc new file mode 100644 index 0000000000..0e1ae626e9 --- /dev/null +++ b/src/compiler/codegen/mips/int_mips.cc @@ -0,0 +1,443 @@ +/* + * 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 Mips ISA */ + +#include "oat/runtime/oat_support_entrypoints.h" + +namespace art { + +/* + * Compare two 64-bit values + * x = y return 0 + * x < y return -1 + * x > y return 1 + * + * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0 + * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0 + * subu res, t0, t1 # res = -1:1:0 for [ < > = ] + * bnez res, finish + * sltu t0, x.lo, y.lo + * sgtu r1, x.lo, y.lo + * subu res, t0, t1 + * finish: + * + */ +void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + int t0 = oatAllocTemp(cUnit); + int t1 = oatAllocTemp(cUnit); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg); + newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg); + newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); + LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL); + newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg); + newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg); + newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); + oatFreeTemp(cUnit, t0); + oatFreeTemp(cUnit, t1); + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); + branch->target = (LIR*)target; + storeValue(cUnit, rlDest, rlResult); +} + +LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, + int src2, LIR* target) +{ + LIR* branch; + MipsOpCode sltOp; + MipsOpCode brOp; + bool cmpZero = false; + bool swapped = false; + switch (cond) { + case kCondEq: + brOp = kMipsBeq; + cmpZero = true; + break; + case kCondNe: + brOp = kMipsBne; + cmpZero = true; + break; + case kCondCc: + sltOp = kMipsSltu; + brOp = kMipsBnez; + break; + case kCondCs: + sltOp = kMipsSltu; + brOp = kMipsBeqz; + break; + case kCondGe: + sltOp = kMipsSlt; + brOp = kMipsBeqz; + break; + case kCondGt: + sltOp = kMipsSlt; + brOp = kMipsBnez; + swapped = true; + break; + case kCondLe: + sltOp = kMipsSlt; + brOp = kMipsBeqz; + swapped = true; + break; + case kCondLt: + sltOp = kMipsSlt; + brOp = kMipsBnez; + break; + case kCondHi: // Gtu + sltOp = kMipsSltu; + brOp = kMipsBnez; + swapped = true; + break; + default: + LOG(FATAL) << "No support for ConditionCode: " << (int) cond; + return NULL; + } + if (cmpZero) { + branch = newLIR2(cUnit, brOp, src1, src2); + } else { + int tReg = oatAllocTemp(cUnit); + if (swapped) { + newLIR3(cUnit, sltOp, tReg, src2, src1); + } else { + newLIR3(cUnit, sltOp, tReg, src1, src2); + } + branch = newLIR1(cUnit, brOp, tReg); + oatFreeTemp(cUnit, tReg); + } + branch->target = target; + return branch; +} + +LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, + int checkValue, LIR* target) +{ + LIR* branch; + if (checkValue != 0) { + // TUNING: handle s16 & kCondLt/Mi case using slti + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + branch = opCmpBranch(cUnit, cond, reg, tReg, target); + oatFreeTemp(cUnit, tReg); + return branch; + } + MipsOpCode opc; + switch (cond) { + case kCondEq: opc = kMipsBeqz; break; + case kCondGe: opc = kMipsBgez; break; + case kCondGt: opc = kMipsBgtz; break; + case kCondLe: opc = kMipsBlez; break; + //case KCondMi: + case kCondLt: opc = kMipsBltz; break; + case kCondNe: opc = kMipsBnez; break; + default: + // Tuning: use slti when applicable + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + branch = opCmpBranch(cUnit, cond, reg, tReg, target); + oatFreeTemp(cUnit, tReg); + return branch; + } + branch = newLIR1(cUnit, opc, reg); + branch->target = target; + return branch; +} + +LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) +{ +#ifdef __mips_hard_float + if (MIPS_FPREG(rDest) || MIPS_FPREG(rSrc)) + return fpRegCopy(cUnit, rDest, rSrc); +#endif + LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove, + rDest, rSrc); + if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) { + res->flags.isNop = true; + } + return res; +} + +LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) +{ + LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc); + oatAppendLIR(cUnit, (LIR*)res); + return res; +} + +void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, + int srcLo, int srcHi) +{ +#ifdef __mips_hard_float + bool destFP = MIPS_FPREG(destLo) && MIPS_FPREG(destHi); + bool srcFP = MIPS_FPREG(srcLo) && MIPS_FPREG(srcHi); + assert(MIPS_FPREG(srcLo) == MIPS_FPREG(srcHi)); + assert(MIPS_FPREG(destLo) == MIPS_FPREG(destHi)); + if (destFP) { + if (srcFP) { + opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi)); + } else { + /* note the operands are swapped for the mtc1 instr */ + newLIR2(cUnit, kMipsMtc1, srcLo, destLo); + newLIR2(cUnit, kMipsMtc1, srcHi, destHi); + } + } else { + if (srcFP) { + newLIR2(cUnit, kMipsMfc1, destLo, srcLo); + newLIR2(cUnit, kMipsMfc1, destHi, srcHi); + } else { + // Handle overlap + if (srcHi == destLo) { + opRegCopy(cUnit, destHi, srcHi); + opRegCopy(cUnit, destLo, srcLo); + } else { + opRegCopy(cUnit, destLo, srcLo); + opRegCopy(cUnit, destHi, srcHi); + } + } + } +#else + // Handle overlap + if (srcHi == destLo) { + opRegCopy(cUnit, destHi, srcHi); + opRegCopy(cUnit, destLo, srcLo); + } else { + opRegCopy(cUnit, destLo, srcLo); + opRegCopy(cUnit, destHi, srcHi); + } +#endif +} + +void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) +{ + UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch"; +} + +LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, + int reg1, int base, int offset, ThrowKind kind) +{ + LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm"; + return NULL; +} + +RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv) +{ + newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, reg2); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + if (isDiv) { + newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO); + } else { + newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI); + } + return rlResult; +} + +RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv) +{ + int tReg = oatAllocTemp(cUnit); + newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit); + newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, tReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + if (isDiv) { + newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO); + } else { + newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI); + } + oatFreeTemp(cUnit, tReg); + return rlResult; +} + +void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset) +{ + LOG(FATAL) << "Unexpected use of opLea for Arm"; +} + +void opTlsCmp(CompilationUnit* cUnit, int offset, int val) +{ + LOG(FATAL) << "Unexpected use of opTlsCmp for Arm"; +} + +bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) { + DCHECK_NE(cUnit->instructionSet, kThumb2); + 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 Mips"; + return NULL; +} + +LIR* opVldm(CompilationUnit* cUnit, int rBase, int count) +{ + LOG(FATAL) << "Unexpected use of opVldm for Mips"; + return NULL; +} + +LIR* opVstm(CompilationUnit* cUnit, int rBase, int count) +{ + LOG(FATAL) << "Unexpected use of opVstm for Mips"; + return NULL; +} + +void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, + RegLocation rlResult, int lit, + int firstBit, int secondBit) +{ + int tReg = oatAllocTemp(cUnit); + opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit); + opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg); + oatFreeTemp(cUnit, tReg); + if (firstBit != 0) { + opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); + } +} + +void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi) +{ + int tReg = oatAllocTemp(cUnit); + opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi); + genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero); + oatFreeTemp(cUnit, tReg); +} + +// Test suspend flag, return target of taken suspend branch +LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target) +{ + opRegImm(cUnit, kOpSub, rMIPS_SUSPEND, 1); + return opCmpImmBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target); +} + +// Decrement register and branch on condition +LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target) +{ + opRegImm(cUnit, kOpSub, reg, 1); + return opCmpImmBranch(cUnit, cCode, reg, 0, target); +} + +bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, + RegLocation rlSrc, RegLocation rlDest, int lit) +{ + LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips"; + return false; +} + +LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide) +{ + LOG(FATAL) << "Unexpected use of opIT in Mips"; + return NULL; +} + +bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + /* + * [v1 v0] = [a1 a0] + [a3 a2]; + * addu v0,a2,a0 + * addu t1,a3,a1 + * sltu v1,v0,a2 + * addu v1,v1,t1 + */ + + opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg); + int tReg = oatAllocTemp(cUnit); + opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg); + newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg); + opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg); + oatFreeTemp(cUnit, tReg); + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + /* + * [v1 v0] = [a1 a0] - [a3 a2]; + * sltu t1,a0,a2 + * subu v0,a0,a2 + * subu v1,a1,a3 + * subu v1,v1,t1 + */ + + int tReg = oatAllocTemp(cUnit); + newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlSrc2.lowReg); + opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); + opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg); + opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg); + oatFreeTemp(cUnit, tReg); + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + /* + * [v1 v0] = -[a1 a0] + * negu v0,a0 + * negu v1,a1 + * sltu t1,r_zero + * subu v1,v1,t1 + */ + + opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg); + opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg); + int tReg = oatAllocTemp(cUnit); + newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg); + opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg); + oatFreeTemp(cUnit, tReg); + storeValueWide(cUnit, rlDest, rlResult); + return false; +} + +bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genAndLong for Mips"; + return false; +} + +bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genOrLong for Mips"; + return false; +} + +bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + LOG(FATAL) << "Unexpected use of genXorLong for Mips"; + return false; +} + +} // namespace art diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc deleted file mode 100644 index 3018ffe6f8..0000000000 --- a/src/compiler/codegen/mips/mips/ArchVariant.cc +++ /dev/null @@ -1,59 +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-mips.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 kMips; -} - -/* 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 - newLIR1(cUnit, kMipsSync, barrierKind); -#endif -} - -} // namespace art diff --git a/src/compiler/codegen/mips/mips/Codegen.cc b/src/compiler/codegen/mips/mips/Codegen.cc deleted file mode 100644 index 0c726d349a..0000000000 --- a/src/compiler/codegen/mips/mips/Codegen.cc +++ /dev/null @@ -1,57 +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 "../MipsLIR.h" -#include "../../Ralloc.h" -#include "../Codegen.h" - -/* Mips codegen building blocks */ -#include "../../CodegenUtil.cc" - -/* Mips-specific factory utilities */ -#include "../Mips32/Factory.cc" -/* Target independent factory utilities */ -#include "../../CodegenFactory.cc" -/* Target independent gen routines */ -#include "../../GenCommon.cc" -/* Shared invoke gen routines */ -#include "../../GenInvoke.cc" -/* Mips-specific factory utilities */ -#include "../ArchFactory.cc" - -/* Mips32-specific codegen routines */ -#include "../Mips32/Gen.cc" -/* FP codegen routines */ -#include "../FP/MipsFP.cc" - -/* Mips32-specific register allocation */ -#include "../Mips32/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/mips/MipsLIR.h b/src/compiler/codegen/mips/mips_lir.h index c0fde466c1..03dd71401c 100644 --- a/src/compiler/codegen/mips/MipsLIR.h +++ b/src/compiler/codegen/mips/mips_lir.h @@ -17,8 +17,8 @@ #ifndef ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_ #define ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_ -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" +#include "../../dalvik.h" +#include "../../compiler_internals.h" namespace art { diff --git a/src/compiler/codegen/mips/target_mips.cc b/src/compiler/codegen/mips/target_mips.cc new file mode 100644 index 0000000000..f32f6c2b40 --- /dev/null +++ b/src/compiler/codegen/mips/target_mips.cc @@ -0,0 +1,719 @@ +/* + * 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 "mips_lir.h" +#include "../ralloc.h" + +#include <string> + +namespace art { + +static int coreRegs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, + r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7, + r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8, + r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA}; +static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP, + r_RA}; +static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2, + r_T3, r_T4, r_T5, r_T6, r_T7, r_T8}; +#ifdef __mips_hard_float +static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, + r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; +static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, + r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; +#endif + +RegLocation locCReturn() +{ + RegLocation res = MIPS_LOC_C_RETURN; + return res; +} + +RegLocation locCReturnWide() +{ + RegLocation res = MIPS_LOC_C_RETURN_WIDE; + return res; +} + +RegLocation locCReturnFloat() +{ + RegLocation res = MIPS_LOC_C_RETURN_FLOAT; + return res; +} + +RegLocation locCReturnDouble() +{ + RegLocation res = MIPS_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 = rMIPS_SELF; break; + case kSuspend: res = rMIPS_SUSPEND; break; + case kLr: res = rMIPS_LR; break; + case kPc: res = rMIPS_PC; break; + case kSp: res = rMIPS_SP; break; + case kArg0: res = rMIPS_ARG0; break; + case kArg1: res = rMIPS_ARG1; break; + case kArg2: res = rMIPS_ARG2; break; + case kArg3: res = rMIPS_ARG3; break; + case kFArg0: res = rMIPS_FARG0; break; + case kFArg1: res = rMIPS_FARG1; break; + case kFArg2: res = rMIPS_FARG2; break; + case kFArg3: res = rMIPS_FARG3; break; + case kRet0: res = rMIPS_RET0; break; + case kRet1: res = rMIPS_RET1; break; + case kInvokeTgt: res = rMIPS_INVOKE_TGT; break; + case kCount: res = rMIPS_COUNT; break; + } + return res; +} + +// Create a double from a pair of singles. +int s2d(int lowReg, int highReg) +{ + return MIPS_S2D(lowReg, highReg); +} + +// Is reg a single or double? +bool fpReg(int reg) +{ + return MIPS_FPREG(reg); +} + +// Is reg a single? +bool singleReg(int reg) +{ + return MIPS_SINGLEREG(reg); +} + +// Is reg a double? +bool doubleReg(int reg) +{ + return MIPS_DOUBLEREG(reg); +} + +// Return mask to strip off fp reg flags and bias. +uint32_t fpRegMask() +{ + return MIPS_FP_REG_MASK; +} + +// True if both regs single, both core or both double. +bool sameRegType(int reg1, int reg2) +{ + return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2)); +} + +/* + * Decode the register id. + */ +u8 getRegMaskCommon(CompilationUnit* cUnit, int reg) +{ + u8 seed; + int shift; + int regId; + + + regId = reg & 0x1f; + /* Each double register is equal to a pair of single-precision FP registers */ + seed = MIPS_DOUBLEREG(reg) ? 3 : 1; + /* FP register starts at bit position 16 */ + shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0; + /* Expand the double register id into single offset */ + shift += regId; + return (seed << shift); +} + +uint64_t getPCUseDefEncoding() +{ + return ENCODE_MIPS_REG_PC; +} + + +void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) +{ + DCHECK_EQ(cUnit->instructionSet, kMips); + + // Mips-specific resource map setup here. + uint64_t flags = EncodingMap[lir->opcode].flags; + + if (flags & REG_DEF_SP) { + lir->defMask |= ENCODE_MIPS_REG_SP; + } + + if (flags & REG_USE_SP) { + lir->useMask |= ENCODE_MIPS_REG_SP; + } + + if (flags & REG_DEF_LR) { + lir->defMask |= ENCODE_MIPS_REG_LR; + } +} + +/* For dumping instructions */ +#define MIPS_REG_COUNT 32 +static const char *mipsRegName[MIPS_REG_COUNT] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; + +/* + * Interpret a format string and build a string no longer than size + * See format key in Assemble.c. + */ +std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) +{ + std::string buf; + int i; + const char *fmtEnd = &fmt[strlen(fmt)]; + char tbuf[256]; + char nc; + while (fmt < fmtEnd) { + int operand; + if (*fmt == '!') { + fmt++; + DCHECK_LT(fmt, fmtEnd); + nc = *fmt++; + if (nc=='!') { + strcpy(tbuf, "!"); + } else { + DCHECK_LT(fmt, fmtEnd); + DCHECK_LT((unsigned)(nc-'0'), 4u); + operand = lir->operands[nc-'0']; + switch (*fmt++) { + case 'b': + strcpy(tbuf,"0000"); + for (i=3; i>= 0; i--) { + tbuf[i] += operand & 1; + operand >>= 1; + } + break; + case 's': + sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK); + break; + case 'S': + DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0); + sprintf(tbuf,"$f%d",operand & MIPS_FP_REG_MASK); + break; + case 'h': + sprintf(tbuf,"%04x", operand); + break; + case 'M': + case 'd': + sprintf(tbuf,"%d", operand); + break; + case 'D': + sprintf(tbuf,"%d", operand+1); + break; + case 'E': + sprintf(tbuf,"%d", operand*4); + break; + case 'F': + sprintf(tbuf,"%d", operand*2); + break; + case 't': + sprintf(tbuf,"0x%08x (L%p)", (int) baseAddr + lir->offset + 4 + + (operand << 2), lir->target); + break; + case 'T': + sprintf(tbuf,"0x%08x", (int) (operand << 2)); + break; + case 'u': { + int offset_1 = lir->operands[0]; + int offset_2 = NEXT_LIR(lir)->operands[0]; + intptr_t target = + ((((intptr_t) baseAddr + lir->offset + 4) & ~3) + + (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc; + sprintf(tbuf, "%p", (void *) target); + break; + } + + /* Nothing to print for BLX_2 */ + case 'v': + strcpy(tbuf, "see above"); + break; + case 'r': + DCHECK(operand >= 0 && operand < MIPS_REG_COUNT); + strcpy(tbuf, mipsRegName[operand]); + break; + case 'N': + // Placeholder for delay slot handling + strcpy(tbuf, "; nop"); + break; + default: + strcpy(tbuf,"DecodeError"); + break; + } + buf += tbuf; + } + } else { + buf += *fmt++; + } + } + return buf; +} + +// FIXME: need to redo resource maps for MIPS - fix this at that time +void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) +{ + char buf[256]; + buf[0] = 0; + LIR *mipsLIR = (LIR *) lir; + + if (mask == ENCODE_ALL) { + strcpy(buf, "all"); + } else { + char num[8]; + int i; + + for (i = 0; i < kMipsRegEnd; i++) { + if (mask & (1ULL << i)) { + sprintf(num, "%d ", i); + strcat(buf, num); + } + } + + if (mask & ENCODE_CCODE) { + strcat(buf, "cc "); + } + if (mask & ENCODE_FP_STATUS) { + strcat(buf, "fpcc "); + } + /* Memory bits */ + if (mipsLIR && (mask & ENCODE_DALVIK_REG)) { + sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff, + (mipsLIR->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; + } +} + +/* + * TUNING: is leaf? Can't just use "hasInvoke" to determine as some + * instructions might call out to C/assembly helper functions. Until + * machinery is in place, always spill lr. + */ + +void oatAdjustSpillMask(CompilationUnit* cUnit) +{ + cUnit->coreSpillMask |= (1 << r_RA); + 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 sReg, int reg) +{ + LOG(FATAL) << "No support yet for promoted FP regs"; +} + +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, rMIPS_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, rMIPS_SP, oatVRegOffset(cUnit, vReg), reg, kWord); + } +} + +/* Give access to the target-dependent FP register encoding to common code */ +bool oatIsFpReg(int reg) { + return MIPS_FPREG(reg); +} + +uint32_t oatFpRegMask() { + return MIPS_FP_REG_MASK; +} + +/* Clobber all regs that might be used by an external C call */ +extern void oatClobberCalleeSave(CompilationUnit *cUnit) +{ + oatClobber(cUnit, r_ZERO); + oatClobber(cUnit, r_AT); + oatClobber(cUnit, r_V0); + oatClobber(cUnit, r_V1); + oatClobber(cUnit, r_A0); + oatClobber(cUnit, r_A1); + oatClobber(cUnit, r_A2); + oatClobber(cUnit, r_A3); + oatClobber(cUnit, r_T0); + oatClobber(cUnit, r_T1); + oatClobber(cUnit, r_T2); + oatClobber(cUnit, r_T3); + oatClobber(cUnit, r_T4); + oatClobber(cUnit, r_T5); + oatClobber(cUnit, r_T6); + oatClobber(cUnit, r_T7); + oatClobber(cUnit, r_T8); + oatClobber(cUnit, r_T9); + oatClobber(cUnit, r_K0); + oatClobber(cUnit, r_K1); + oatClobber(cUnit, r_GP); + oatClobber(cUnit, r_FP); + oatClobber(cUnit, r_RA); + oatClobber(cUnit, r_F0); + oatClobber(cUnit, r_F1); + oatClobber(cUnit, r_F2); + oatClobber(cUnit, r_F3); + oatClobber(cUnit, r_F4); + oatClobber(cUnit, r_F5); + oatClobber(cUnit, r_F6); + oatClobber(cUnit, r_F7); + oatClobber(cUnit, r_F8); + oatClobber(cUnit, r_F9); + oatClobber(cUnit, r_F10); + oatClobber(cUnit, r_F11); + oatClobber(cUnit, r_F12); + oatClobber(cUnit, r_F13); + oatClobber(cUnit, r_F14); + oatClobber(cUnit, r_F15); +} + +extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) +{ + UNIMPLEMENTED(FATAL) << "No oatGetReturnWideAlt for MIPS"; + RegLocation res = locCReturnWide(); + return res; +} + +extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) +{ + UNIMPLEMENTED(FATAL) << "No oatGetReturnAlt for MIPS"; + RegLocation res = locCReturn(); + return res; +} + +extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) +{ + return MIPS_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & MIPS_FP_REG_MASK] + : &cUnit->regPool->coreRegs[reg]; +} + +/* To be used when explicitly managing register use */ +extern void oatLockCallTemps(CompilationUnit* cUnit) +{ + oatLockTemp(cUnit, rMIPS_ARG0); + oatLockTemp(cUnit, rMIPS_ARG1); + oatLockTemp(cUnit, rMIPS_ARG2); + oatLockTemp(cUnit, rMIPS_ARG3); +} + +/* To be used when explicitly managing register use */ +extern void oatFreeCallTemps(CompilationUnit* cUnit) +{ + oatFreeTemp(cUnit, rMIPS_ARG0); + oatFreeTemp(cUnit, rMIPS_ARG1); + oatFreeTemp(cUnit, rMIPS_ARG2); + oatFreeTemp(cUnit, rMIPS_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 kMips; +} + +/* 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 + newLIR1(cUnit, kMipsSync, barrierKind); +#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; + +#ifdef __mips_hard_float + if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { + lowReg = oatAllocTempDouble(cUnit); + highReg = lowReg + 1; + res = (lowReg & 0xff) | ((highReg & 0xff) << 8); + return res; + } +#endif + + lowReg = oatAllocTemp(cUnit); + highReg = oatAllocTemp(cUnit); + res = (lowReg & 0xff) | ((highReg & 0xff) << 8); + return res; +} + +int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) +{ +#ifdef __mips_hard_float + if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) +{ + return oatAllocTempFloat(cUnit); +} +#endif + 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); +#ifdef __mips_hard_float + int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); + int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); +#else + int numFPRegs = 0; + int numFPTemps = 0; +#endif + 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++) { + if (NO_SUSPEND && (reservedRegs[i] == rMIPS_SUSPEND)) { + //To measure cost of suspend check + continue; + } + 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); + } +} +/* + * In the Arm code a it is typical to use the link register + * to hold the target address. However, for Mips we must + * ensure that all branch instructions can be restarted if + * there is a trap in the shadow. Allocate a temp register. + */ +int loadHelper(CompilationUnit* cUnit, int offset) +{ + loadWordDisp(cUnit, rMIPS_SELF, offset, r_T9); + return r_T9; +} + +void spillCoreRegs(CompilationUnit* cUnit) +{ + if (cUnit->numCoreSpills == 0) { + return; + } + uint32_t mask = cUnit->coreSpillMask; + int offset = cUnit->numCoreSpills * 4; + opRegImm(cUnit, kOpSub, rMIPS_SP, offset); + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + offset -= 4; + storeWordDisp(cUnit, rMIPS_SP, offset, reg); + } + } +} + +void unSpillCoreRegs(CompilationUnit* cUnit) +{ + if (cUnit->numCoreSpills == 0) { + return; + } + uint32_t mask = cUnit->coreSpillMask; + int offset = cUnit->frameSize; + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + offset -= 4; + loadWordDisp(cUnit, rMIPS_SP, offset, reg); + } + } + opRegImm(cUnit, kOpAdd, rMIPS_SP, cUnit->frameSize); +} + +/* + * 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 == kMipsB) { + 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 < kMipsLast; 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(); +} + +} // namespace art diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/utility_mips.cc index 0a0d906538..a7faa1d394 100644 --- a/src/compiler/codegen/mips/Mips32/Factory.cc +++ b/src/compiler/codegen/mips/utility_mips.cc @@ -18,21 +18,6 @@ namespace art { /* This file contains codegen for the MIPS32 ISA. */ -static int coreRegs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, - r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7, - r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8, - r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA}; -static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP, - r_RA}; -static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2, - r_T3, r_T4, r_T5, r_T6, r_T7, r_T8}; -#ifdef __mips_hard_float -static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, - r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; -static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, - r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; -#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/Optimizer.h b/src/compiler/codegen/optimizer.h index 94b1907ef1..f5c81a673d 100644 --- a/src/compiler/codegen/Optimizer.h +++ b/src/compiler/codegen/optimizer.h @@ -17,7 +17,7 @@ #ifndef ART_SRC_COMPILER_COMPILER_OPTIMIZATION_H_ #define ART_SRC_COMPILER_COMPILER_OPTIMIZATION_H_ -#include "../Dalvik.h" +#include "../dalvik.h" namespace art { diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/ralloc.h index 55e62b1a73..8c327e4d21 100644 --- a/src/compiler/codegen/Ralloc.h +++ b/src/compiler/codegen/ralloc.h @@ -21,9 +21,9 @@ * This file contains target independent register alloction support. */ -#include "../CompilerUtility.h" -#include "../CompilerIR.h" -#include "../Dataflow.h" +#include "../compiler_utility.h" +#include "../compiler_ir.h" +#include "../dataflow.h" namespace art { diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/ralloc_util.cc index 4848a59fc6..059d1c3c24 100644 --- a/src/compiler/codegen/RallocUtil.cc +++ b/src/compiler/codegen/ralloc_util.cc @@ -16,10 +16,10 @@ /* This file contains register alloction support. */ -#include "../CompilerUtility.h" -#include "../CompilerIR.h" -#include "../Dataflow.h" -#include "Ralloc.h" +#include "../compiler_utility.h" +#include "../compiler_ir.h" +#include "../dataflow.h" +#include "ralloc.h" namespace art { 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 { |