From 5d90c20bd7903d7bba966b224e576bf137bf8b4b Mon Sep 17 00:00:00 2001 From: Ben Cheng Date: Sun, 22 Nov 2009 23:31:11 -0800 Subject: Restructure the codegen to make architectural depedency explicit. The original Codegen.c is broken into three components: - CodegenCommon.c (arch-independend) - CodegenFactory.c (Thumb1/2 dependent) - CodegenDriver.c (Dalvik dependent) For the Thumb/Thumb2 directories, each contain the followin three files: - Factory.c (low-level routines for instruction selections) - Gen.c (invoke the ISA-specific instruction selection routines) - Ralloc.c (arch-dependent register pools) The FP directory contains FP-specific codegen routines depending on Thumb/Thumb2/VFP/PortableFP: - Thumb2VFP.c - ThumbVFP.c - ThumbPortableFP.c Then the hierarchy is formed by stacking these files in the following top-down order: 1 CodegenCommon.c 2 Thumb[2]/Factory.c 3 CodegenFactory.c 4 Thumb[2]/Gen.c 5 FP stuff 6 Thumb[2]/Ralloc.c 7 CodegenDriver.c --- vm/compiler/codegen/arm/CodegenFactory.c | 335 +++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 vm/compiler/codegen/arm/CodegenFactory.c (limited to 'vm/compiler/codegen/arm/CodegenFactory.c') diff --git a/vm/compiler/codegen/arm/CodegenFactory.c b/vm/compiler/codegen/arm/CodegenFactory.c new file mode 100644 index 000000000..e5a56cc45 --- /dev/null +++ b/vm/compiler/codegen/arm/CodegenFactory.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2009 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 and support common to all supported + * ARM variants. It is included by: + * + * Codegen-$(TARGET_ARCH_VARIANT).c + * + * which combines this common code with specific support found in the + * applicable directory below this one. + */ + + +/* Load a word at base + displacement. Displacement must be word multiple */ +static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, + int rDest) +{ + return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, + INVALID_SREG); +} + +static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc) +{ + return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord); +} + +/* + * Load a Dalvik register into a physical register. Take care when + * using this routine, as it doesn't perform any bookkeeping regarding + * register liveness. That is the responsibility of the caller. + */ +static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc, + int reg1) +{ + rlSrc = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */ + if (rlSrc.location == kLocPhysReg) { + genRegCopy(cUnit, reg1, rlSrc.lowReg); + } else if (rlSrc.location == kLocRetval) { + loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1); + } else { + assert(rlSrc.location == kLocDalvikFrame); + loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2, + reg1); + } +} + +/* + * Similar to loadValueDirect, but clobbers and allocates the target + * register. Should be used when loading to a fixed register (for example, + * loading arguments to an out of line call. + */ +static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc, + int reg1) +{ + clobberReg(cUnit, reg1); + markRegInUse(cUnit, reg1); + loadValueDirect(cUnit, rlSrc, reg1); +} + +/* + * Load a Dalvik register pair into a physical register[s]. Take care when + * using this routine, as it doesn't perform any bookkeeping regarding + * register liveness. That is the responsibility of the caller. + */ +static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc, + int regLo, int regHi) +{ + rlSrc = updateLocWide(cUnit, rlSrc); + if (rlSrc.location == kLocPhysReg) { + genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg); + } else if (rlSrc.location == kLocRetval) { + loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval), + regLo, regHi, INVALID_SREG); + } else { + assert(rlSrc.location == kLocDalvikFrame); + loadBaseDispWide(cUnit, NULL, rFP, + sReg2vReg(cUnit, rlSrc.sRegLow) << 2, + regLo, regHi, INVALID_SREG); + } +} + +/* + * Similar to loadValueDirect, but clobbers and allocates the target + * registers. Should be used when loading to a fixed registers (for example, + * loading arguments to an out of line call. + */ +static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc, + int regLo, int regHi) +{ + clobberReg(cUnit, regLo); + clobberReg(cUnit, regHi); + markRegInUse(cUnit, regLo); + markRegInUse(cUnit, regHi); + loadValueDirectWide(cUnit, rlSrc, regLo, regHi); +} + +static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc, + RegisterClass opKind) +{ + RegisterInfo *pReg; + rlSrc = evalLoc(cUnit, rlSrc, opKind, false); + if (rlSrc.location == kLocDalvikFrame) { + loadValueDirect(cUnit, rlSrc, rlSrc.lowReg); + rlSrc.location = kLocPhysReg; + markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); + } else if (rlSrc.location == kLocRetval) { + loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg); + rlSrc.location = kLocPhysReg; + clobberReg(cUnit, rlSrc.lowReg); + } + return rlSrc; +} + +static void storeValue(CompilationUnit *cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + RegisterInfo *pRegLo; + LIR *defStart; + LIR *defEnd; + assert(!rlDest.wide); + assert(!rlSrc.wide); + killNullCheckedLocation(cUnit, rlDest); + rlSrc = updateLoc(cUnit, rlSrc); + rlDest = updateLoc(cUnit, rlDest); + if (rlSrc.location == kLocPhysReg) { + if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) { + // Src is live or Dest has assigned reg. + rlDest = evalLoc(cUnit, rlDest, kAnyReg, false); + genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg); + } else { + // Just re-assign the registers. Dest gets Src's regs + rlDest.lowReg = rlSrc.lowReg; + clobberReg(cUnit, rlSrc.lowReg); + } + } else { + // Load Src either into promoted Dest or temps allocated for Dest + rlDest = evalLoc(cUnit, rlDest, kAnyReg, false); + loadValueDirect(cUnit, rlSrc, rlDest.lowReg); + } + + // Dest is now live and dirty (until/if we flush it to home location) + markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow); + markRegDirty(cUnit, rlDest.lowReg); + + + if (rlDest.location == kLocRetval) { + storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval), + rlDest.lowReg, kWord); + clobberReg(cUnit, rlDest.lowReg); + } else { + resetDefLoc(cUnit, rlDest); + if (liveOut(cUnit, rlDest.sRegLow)) { + defStart = (LIR *)cUnit->lastLIRInsn; + int vReg = sReg2vReg(cUnit, rlDest.sRegLow); + storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord); + markRegClean(cUnit, rlDest.lowReg); + defEnd = (LIR *)cUnit->lastLIRInsn; + markDef(cUnit, rlDest, defStart, defEnd); + } + } +} + +static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc, + RegisterClass opKind) +{ + RegisterInfo *pRegLo; + RegisterInfo *pRegHi; + assert(rlSrc.wide); + rlSrc = evalLoc(cUnit, rlSrc, opKind, false); + if (rlSrc.location == kLocDalvikFrame) { + loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg); + rlSrc.location = kLocPhysReg; + markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); + markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow)); + } else if (rlSrc.location == kLocRetval) { + loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval), + rlSrc.lowReg, rlSrc.highReg, INVALID_SREG); + rlSrc.location = kLocPhysReg; + clobberReg(cUnit, rlSrc.lowReg); + clobberReg(cUnit, rlSrc.highReg); + } + return rlSrc; +} + +static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + RegisterInfo *pRegLo; + RegisterInfo *pRegHi; + LIR *defStart; + LIR *defEnd; + bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg); + assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg)); + assert(rlDest.wide); + assert(rlSrc.wide); + killNullCheckedLocation(cUnit, rlDest); + if (rlSrc.location == kLocPhysReg) { + if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) || + (rlDest.location == kLocPhysReg)) { + // Src is live or Dest has assigned reg. + rlDest = evalLoc(cUnit, rlDest, kAnyReg, false); + genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg, + rlSrc.lowReg, rlSrc.highReg); + } else { + // Just re-assign the registers. Dest gets Src's regs + rlDest.lowReg = rlSrc.lowReg; + rlDest.highReg = rlSrc.highReg; + clobberReg(cUnit, rlSrc.lowReg); + clobberReg(cUnit, rlSrc.highReg); + } + } else { + // Load Src either into promoted Dest or temps allocated for Dest + rlDest = evalLoc(cUnit, rlDest, kAnyReg, false); + loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg, + rlDest.highReg); + } + + // Dest is now live and dirty (until/if we flush it to home location) + markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow); + markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow)); + markRegDirty(cUnit, rlDest.lowReg); + markRegDirty(cUnit, rlDest.highReg); + markRegPair(cUnit, rlDest.lowReg, rlDest.highReg); + + + if (rlDest.location == kLocRetval) { + storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval), + rlDest.lowReg, rlDest.highReg); + clobberReg(cUnit, rlDest.lowReg); + clobberReg(cUnit, rlDest.highReg); + } else { + resetDefLocWide(cUnit, rlDest); + if (liveOut(cUnit, rlDest.sRegLow) || + liveOut(cUnit, hiSReg(rlDest.sRegLow))) { + defStart = (LIR *)cUnit->lastLIRInsn; + int vReg = sReg2vReg(cUnit, rlDest.sRegLow); + assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow))); + storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg, + rlDest.highReg); + markRegClean(cUnit, rlDest.lowReg); + markRegClean(cUnit, rlDest.highReg); + defEnd = (LIR *)cUnit->lastLIRInsn; + markDefWide(cUnit, rlDest, defStart, defEnd); + } + } +} +/* + * Perform null-check on a register. sReg is the ssa register being checked, + * and mReg is the machine register holding the actual value. If internal state + * indicates that sReg has been checked before the check request is ignored. + */ +static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg, + int dOffset, ArmLIR *pcrLabel) +{ + /* This particular Dalvik register has been null-checked */ + if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) { + return pcrLabel; + } + dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg); + return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel); +} + + + +/* + * Perform a "reg cmp reg" operation and jump to the PCR region if condition + * satisfies. + */ +static ArmLIR *genRegRegCheck(CompilationUnit *cUnit, + ArmConditionCode cond, + int reg1, int reg2, int dOffset, + ArmLIR *pcrLabel) +{ + ArmLIR *res; + res = opRegReg(cUnit, kOpCmp, reg1, reg2); + ArmLIR *branch = opCondBranch(cUnit, cond); + genCheckCommon(cUnit, dOffset, branch, pcrLabel); + return res; +} + +/* + * Perform zero-check on a register. Similar to genNullCheck but the value being + * checked does not have a corresponding Dalvik register. + */ +static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg, + int dOffset, ArmLIR *pcrLabel) +{ + return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel); +} + +/* Perform bound check on two registers */ +static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex, + int rBound, int dOffset, ArmLIR *pcrLabel) +{ + return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset, + pcrLabel); +} + +/* + * Jump to the out-of-line handler in ARM mode to finish executing the + * remaining of more complex instructions. + */ +static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode) +{ + /* + * NOTE - In practice BLX only needs one operand, but since the assembler + * may abort itself and retry due to other out-of-range conditions we + * cannot really use operand[0] to store the absolute target address since + * it may get clobbered by the final relative offset. Therefore, + * we fake BLX_1 is a two operand instruction and the absolute target + * address is stored in operand[1]. + */ + clobberHandlerRegs(cUnit); + newLIR2(cUnit, kThumbBlx1, + (int) gDvmJit.codeCache + templateEntryOffsets[opCode], + (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); + newLIR2(cUnit, kThumbBlx2, + (int) gDvmJit.codeCache + templateEntryOffsets[opCode], + (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); +} -- cgit v1.2.3