diff options
| author | 2012-11-14 16:31:52 -0800 | |
|---|---|---|
| committer | 2012-11-15 09:47:38 -0800 | |
| commit | efc6369224b036a1fb77849f7ae65b3492c832c0 (patch) | |
| tree | e61d88a5b3b787d782b2fa02b90947ba9a115458 /src/compiler/codegen | |
| parent | a3c6849b160cd5d2b2ca6e6fa9d9df834def85ee (diff) | |
Quick compiler source reorganizatio - part 1
A step towards cleanup of the quick compiler source. In this
CL we rename all files to Art standards, combine some of the
old target-specific files that may have made sense in the
JIT, but no longer do. Also removed some codegen/<target>/
subdirectories, combined and deleted some existing files.
Still quite a bit of work to do in cleaning up header files,
getting some better consistency in what codegen functions
go where. That will happen in later CLs.
No logic changes in this CL - just renaming and moving stuff around
Change-Id: Ic172cd3b76d4c670f8e4d5fdd4a3e967db3f4c1e
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 { |