summaryrefslogtreecommitdiff
path: root/src/compiler/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/codegen')
-rw-r--r--src/compiler/codegen/arm/ArchFactory.cc227
-rw-r--r--src/compiler/codegen/arm/ArmRallocUtil.cc186
-rw-r--r--src/compiler/codegen/arm/Thumb2/Ralloc.cc119
-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.cc55
-rw-r--r--src/compiler/codegen/arm/armv7-a/Codegen.cc57
-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.cc43
-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.cc549
-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.cc281
-rw-r--r--src/compiler/codegen/mips/ArchUtility.cc308
-rw-r--r--src/compiler/codegen/mips/Mips32/Ralloc.cc129
-rw-r--r--src/compiler/codegen/mips/MipsRallocUtil.cc183
-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.cc43
-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.cc443
-rw-r--r--src/compiler/codegen/mips/mips/ArchVariant.cc59
-rw-r--r--src/compiler/codegen/mips/mips/Codegen.cc57
-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.cc719
-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.cc282
-rw-r--r--src/compiler/codegen/x86/ArchUtility.cc304
-rw-r--r--src/compiler/codegen/x86/X86/Ralloc.cc113
-rw-r--r--src/compiler/codegen/x86/X86RallocUtil.cc151
-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.cc43
-rw-r--r--src/compiler/codegen/x86/call_x86.cc276
-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.cc664
-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.cc60
-rw-r--r--src/compiler/codegen/x86/x86/Codegen.cc56
-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 {