From efc6369224b036a1fb77849f7ae65b3492c832c0 Mon Sep 17 00:00:00 2001 From: buzbee Date: Wed, 14 Nov 2012 16:31:52 -0800 Subject: Quick compiler source reorganizatio - part 1 A step towards cleanup of the quick compiler source. In this CL we rename all files to Art standards, combine some of the old target-specific files that may have made sense in the JIT, but no longer do. Also removed some codegen// subdirectories, combined and deleted some existing files. Still quite a bit of work to do in cleaning up header files, getting some better consistency in what codegen functions go where. That will happen in later CLs. No logic changes in this CL - just renaming and moving stuff around Change-Id: Ic172cd3b76d4c670f8e4d5fdd4a3e967db3f4c1e --- src/compiler/codegen/CodegenFactory.cc | 276 -- src/compiler/codegen/CodegenUtil.cc | 1051 ------- src/compiler/codegen/CompilerCodegen.h | 239 -- src/compiler/codegen/GenCommon.cc | 2321 --------------- src/compiler/codegen/GenInvoke.cc | 1010 ------- src/compiler/codegen/LocalOptimizations.cc | 458 --- src/compiler/codegen/MethodBitcode.cc | 3541 ----------------------- src/compiler/codegen/MethodCodegenDriver.cc | 1066 ------- src/compiler/codegen/Optimizer.h | 32 - src/compiler/codegen/Ralloc.h | 234 -- src/compiler/codegen/RallocUtil.cc | 1264 -------- src/compiler/codegen/arm/ArchFactory.cc | 227 -- src/compiler/codegen/arm/ArchUtility.cc | 512 ---- src/compiler/codegen/arm/ArmLIR.h | 617 ---- src/compiler/codegen/arm/ArmRallocUtil.cc | 186 -- src/compiler/codegen/arm/Assemble.cc | 1401 --------- src/compiler/codegen/arm/Codegen.h | 103 - src/compiler/codegen/arm/FP/Thumb2VFP.cc | 275 -- src/compiler/codegen/arm/Thumb2/Factory.cc | 1069 ------- src/compiler/codegen/arm/Thumb2/Gen.cc | 1063 ------- src/compiler/codegen/arm/Thumb2/Ralloc.cc | 119 - src/compiler/codegen/arm/arm_lir.h | 617 ++++ src/compiler/codegen/arm/armv7-a/ArchVariant.cc | 55 - src/compiler/codegen/arm/armv7-a/Codegen.cc | 57 - src/compiler/codegen/arm/assemble_arm.cc | 1401 +++++++++ src/compiler/codegen/arm/backend_arm.cc | 43 + src/compiler/codegen/arm/call_arm.cc | 642 ++++ src/compiler/codegen/arm/codegen.h | 103 + src/compiler/codegen/arm/fp_arm.cc | 319 ++ src/compiler/codegen/arm/int_arm.cc | 549 ++++ src/compiler/codegen/arm/target_arm.cc | 867 ++++++ src/compiler/codegen/arm/utility_arm.cc | 1058 +++++++ src/compiler/codegen/codegen_factory.cc | 276 ++ src/compiler/codegen/codegen_util.cc | 1051 +++++++ src/compiler/codegen/compiler_codegen.h | 250 ++ src/compiler/codegen/gen_common.cc | 2321 +++++++++++++++ src/compiler/codegen/gen_invoke.cc | 1010 +++++++ src/compiler/codegen/local_optimizations.cc | 458 +++ src/compiler/codegen/method_bitcode.cc | 3541 +++++++++++++++++++++++ src/compiler/codegen/method_codegen_driver.cc | 1066 +++++++ src/compiler/codegen/mips/ArchFactory.cc | 281 -- src/compiler/codegen/mips/ArchUtility.cc | 308 -- src/compiler/codegen/mips/Assemble.cc | 751 ----- src/compiler/codegen/mips/Codegen.h | 106 - src/compiler/codegen/mips/FP/MipsFP.cc | 220 -- src/compiler/codegen/mips/Mips32/Factory.cc | 785 ----- src/compiler/codegen/mips/Mips32/Gen.cc | 665 ----- src/compiler/codegen/mips/Mips32/Ralloc.cc | 129 - src/compiler/codegen/mips/MipsLIR.h | 449 --- src/compiler/codegen/mips/MipsRallocUtil.cc | 183 -- src/compiler/codegen/mips/assemble_mips.cc | 751 +++++ src/compiler/codegen/mips/backend_mips.cc | 43 + src/compiler/codegen/mips/call_mips.cc | 373 +++ src/compiler/codegen/mips/codegen.h | 106 + src/compiler/codegen/mips/fp_mips.cc | 245 ++ src/compiler/codegen/mips/int_mips.cc | 443 +++ src/compiler/codegen/mips/mips/ArchVariant.cc | 59 - src/compiler/codegen/mips/mips/Codegen.cc | 57 - src/compiler/codegen/mips/mips_lir.h | 449 +++ src/compiler/codegen/mips/target_mips.cc | 719 +++++ src/compiler/codegen/mips/utility_mips.cc | 770 +++++ src/compiler/codegen/optimizer.h | 32 + src/compiler/codegen/ralloc.h | 234 ++ src/compiler/codegen/ralloc_util.cc | 1264 ++++++++ src/compiler/codegen/x86/ArchFactory.cc | 282 -- src/compiler/codegen/x86/ArchUtility.cc | 304 -- src/compiler/codegen/x86/Assemble.cc | 1450 ---------- src/compiler/codegen/x86/Codegen.h | 102 - src/compiler/codegen/x86/FP/X86FP.cc | 334 --- src/compiler/codegen/x86/X86/Factory.cc | 614 ---- src/compiler/codegen/x86/X86/Gen.cc | 551 ---- src/compiler/codegen/x86/X86/Ralloc.cc | 113 - src/compiler/codegen/x86/X86LIR.h | 456 --- src/compiler/codegen/x86/X86RallocUtil.cc | 151 - src/compiler/codegen/x86/assemble_x86.cc | 1450 ++++++++++ src/compiler/codegen/x86/backend_x86.cc | 43 + src/compiler/codegen/x86/call_x86.cc | 276 ++ src/compiler/codegen/x86/codegen.h | 102 + src/compiler/codegen/x86/fp_x86.cc | 360 +++ src/compiler/codegen/x86/int_x86.cc | 434 +++ src/compiler/codegen/x86/target_x86.cc | 664 +++++ src/compiler/codegen/x86/utility_x86.cc | 592 ++++ src/compiler/codegen/x86/x86/ArchVariant.cc | 60 - src/compiler/codegen/x86/x86/Codegen.cc | 56 - src/compiler/codegen/x86/x86_lir.h | 456 +++ 85 files changed, 25378 insertions(+), 25642 deletions(-) delete mode 100644 src/compiler/codegen/CodegenFactory.cc delete mode 100644 src/compiler/codegen/CodegenUtil.cc delete mode 100644 src/compiler/codegen/CompilerCodegen.h delete mode 100644 src/compiler/codegen/GenCommon.cc delete mode 100644 src/compiler/codegen/GenInvoke.cc delete mode 100644 src/compiler/codegen/LocalOptimizations.cc delete mode 100644 src/compiler/codegen/MethodBitcode.cc delete mode 100644 src/compiler/codegen/MethodCodegenDriver.cc delete mode 100644 src/compiler/codegen/Optimizer.h delete mode 100644 src/compiler/codegen/Ralloc.h delete mode 100644 src/compiler/codegen/RallocUtil.cc delete mode 100644 src/compiler/codegen/arm/ArchFactory.cc delete mode 100644 src/compiler/codegen/arm/ArchUtility.cc delete mode 100644 src/compiler/codegen/arm/ArmLIR.h delete mode 100644 src/compiler/codegen/arm/ArmRallocUtil.cc delete mode 100644 src/compiler/codegen/arm/Assemble.cc delete mode 100644 src/compiler/codegen/arm/Codegen.h delete mode 100644 src/compiler/codegen/arm/FP/Thumb2VFP.cc delete mode 100644 src/compiler/codegen/arm/Thumb2/Factory.cc delete mode 100644 src/compiler/codegen/arm/Thumb2/Gen.cc delete mode 100644 src/compiler/codegen/arm/Thumb2/Ralloc.cc create mode 100644 src/compiler/codegen/arm/arm_lir.h delete mode 100644 src/compiler/codegen/arm/armv7-a/ArchVariant.cc delete mode 100644 src/compiler/codegen/arm/armv7-a/Codegen.cc create mode 100644 src/compiler/codegen/arm/assemble_arm.cc create mode 100644 src/compiler/codegen/arm/backend_arm.cc create mode 100644 src/compiler/codegen/arm/call_arm.cc create mode 100644 src/compiler/codegen/arm/codegen.h create mode 100644 src/compiler/codegen/arm/fp_arm.cc create mode 100644 src/compiler/codegen/arm/int_arm.cc create mode 100644 src/compiler/codegen/arm/target_arm.cc create mode 100644 src/compiler/codegen/arm/utility_arm.cc create mode 100644 src/compiler/codegen/codegen_factory.cc create mode 100644 src/compiler/codegen/codegen_util.cc create mode 100644 src/compiler/codegen/compiler_codegen.h create mode 100644 src/compiler/codegen/gen_common.cc create mode 100644 src/compiler/codegen/gen_invoke.cc create mode 100644 src/compiler/codegen/local_optimizations.cc create mode 100644 src/compiler/codegen/method_bitcode.cc create mode 100644 src/compiler/codegen/method_codegen_driver.cc delete mode 100644 src/compiler/codegen/mips/ArchFactory.cc delete mode 100644 src/compiler/codegen/mips/ArchUtility.cc delete mode 100644 src/compiler/codegen/mips/Assemble.cc delete mode 100644 src/compiler/codegen/mips/Codegen.h delete mode 100644 src/compiler/codegen/mips/FP/MipsFP.cc delete mode 100644 src/compiler/codegen/mips/Mips32/Factory.cc delete mode 100644 src/compiler/codegen/mips/Mips32/Gen.cc delete mode 100644 src/compiler/codegen/mips/Mips32/Ralloc.cc delete mode 100644 src/compiler/codegen/mips/MipsLIR.h delete mode 100644 src/compiler/codegen/mips/MipsRallocUtil.cc create mode 100644 src/compiler/codegen/mips/assemble_mips.cc create mode 100644 src/compiler/codegen/mips/backend_mips.cc create mode 100644 src/compiler/codegen/mips/call_mips.cc create mode 100644 src/compiler/codegen/mips/codegen.h create mode 100644 src/compiler/codegen/mips/fp_mips.cc create mode 100644 src/compiler/codegen/mips/int_mips.cc delete mode 100644 src/compiler/codegen/mips/mips/ArchVariant.cc delete mode 100644 src/compiler/codegen/mips/mips/Codegen.cc create mode 100644 src/compiler/codegen/mips/mips_lir.h create mode 100644 src/compiler/codegen/mips/target_mips.cc create mode 100644 src/compiler/codegen/mips/utility_mips.cc create mode 100644 src/compiler/codegen/optimizer.h create mode 100644 src/compiler/codegen/ralloc.h create mode 100644 src/compiler/codegen/ralloc_util.cc delete mode 100644 src/compiler/codegen/x86/ArchFactory.cc delete mode 100644 src/compiler/codegen/x86/ArchUtility.cc delete mode 100644 src/compiler/codegen/x86/Assemble.cc delete mode 100644 src/compiler/codegen/x86/Codegen.h delete mode 100644 src/compiler/codegen/x86/FP/X86FP.cc delete mode 100644 src/compiler/codegen/x86/X86/Factory.cc delete mode 100644 src/compiler/codegen/x86/X86/Gen.cc delete mode 100644 src/compiler/codegen/x86/X86/Ralloc.cc delete mode 100644 src/compiler/codegen/x86/X86LIR.h delete mode 100644 src/compiler/codegen/x86/X86RallocUtil.cc create mode 100644 src/compiler/codegen/x86/assemble_x86.cc create mode 100644 src/compiler/codegen/x86/backend_x86.cc create mode 100644 src/compiler/codegen/x86/call_x86.cc create mode 100644 src/compiler/codegen/x86/codegen.h create mode 100644 src/compiler/codegen/x86/fp_x86.cc create mode 100644 src/compiler/codegen/x86/int_x86.cc create mode 100644 src/compiler/codegen/x86/target_x86.cc create mode 100644 src/compiler/codegen/x86/utility_x86.cc delete mode 100644 src/compiler/codegen/x86/x86/ArchVariant.cc delete mode 100644 src/compiler/codegen/x86/x86/Codegen.cc create mode 100644 src/compiler/codegen/x86/x86_lir.h (limited to 'src/compiler/codegen') diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc deleted file mode 100644 index 600b324841..0000000000 --- a/src/compiler/codegen/CodegenFactory.cc +++ /dev/null @@ -1,276 +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 target-independent codegen and support. */ - -/* - * Load an immediate value into a fixed or temp register. Target - * register is clobbered, and marked inUse. - */ -LIR* loadConstant(CompilationUnit* cUnit, int rDest, int value) -{ - if (oatIsTemp(cUnit, rDest)) { - oatClobber(cUnit, rDest); - oatMarkInUse(cUnit, rDest); - } - return loadConstantNoClobber(cUnit, rDest, value); -} - -/* Load a word at base + displacement. Displacement must be word multiple */ -LIR* loadWordDisp(CompilationUnit* cUnit, int rBase, int displacement, - int rDest) -{ - return loadBaseDisp(cUnit, rBase, displacement, rDest, kWord, - INVALID_SREG); -} - -LIR* 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. - */ -void loadValueDirect(CompilationUnit* cUnit, RegLocation rlSrc, int rDest) -{ - rlSrc = oatUpdateLoc(cUnit, rlSrc); - if (rlSrc.location == kLocPhysReg) { - opRegCopy(cUnit, rDest, rlSrc.lowReg); - } else { - DCHECK((rlSrc.location == kLocDalvikFrame) || - (rlSrc.location == kLocCompilerTemp)); - loadWordDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, rlSrc.sRegLow), rDest); - } -} - -/* - * 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. - */ -void loadValueDirectFixed(CompilationUnit* cUnit, RegLocation rlSrc, int rDest) -{ - oatClobber(cUnit, rDest); - oatMarkInUse(cUnit, rDest); - loadValueDirect(cUnit, rlSrc, rDest); -} - -/* - * 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. - */ -void loadValueDirectWide(CompilationUnit* cUnit, RegLocation rlSrc, int regLo, - int regHi) -{ - rlSrc = oatUpdateLocWide(cUnit, rlSrc); - if (rlSrc.location == kLocPhysReg) { - opRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg); - } else { - DCHECK((rlSrc.location == kLocDalvikFrame) || - (rlSrc.location == kLocCompilerTemp)); - loadBaseDispWide(cUnit, targetReg(kSp), oatSRegOffset(cUnit, rlSrc.sRegLow), - 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. - */ -void loadValueDirectWideFixed(CompilationUnit* cUnit, RegLocation rlSrc, - int regLo, int regHi) -{ - oatClobber(cUnit, regLo); - oatClobber(cUnit, regHi); - oatMarkInUse(cUnit, regLo); - oatMarkInUse(cUnit, regHi); - loadValueDirectWide(cUnit, rlSrc, regLo, regHi); -} - -RegLocation loadValue(CompilationUnit* cUnit, RegLocation rlSrc, - RegisterClass opKind) -{ - rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false); - if (rlSrc.location != kLocPhysReg) { - DCHECK((rlSrc.location == kLocDalvikFrame) || - (rlSrc.location == kLocCompilerTemp)); - loadValueDirect(cUnit, rlSrc, rlSrc.lowReg); - rlSrc.location = kLocPhysReg; - oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); - } - return rlSrc; -} - -void storeValue(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc) -{ -#ifndef NDEBUG - /* - * Sanity checking - should never try to store to the same - * ssa name during the compilation of a single instruction - * without an intervening oatClobberSReg(). - */ - DCHECK((cUnit->liveSReg == INVALID_SREG) || - (rlDest.sRegLow != cUnit->liveSReg)); - cUnit->liveSReg = rlDest.sRegLow; -#endif - LIR* defStart; - LIR* defEnd; - DCHECK(!rlDest.wide); - DCHECK(!rlSrc.wide); - rlSrc = oatUpdateLoc(cUnit, rlSrc); - rlDest = oatUpdateLoc(cUnit, rlDest); - if (rlSrc.location == kLocPhysReg) { - if (oatIsLive(cUnit, rlSrc.lowReg) || - oatIsPromoted(cUnit, rlSrc.lowReg) || - (rlDest.location == kLocPhysReg)) { - // Src is live/promoted or Dest has assigned reg. - rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false); - opRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg); - } else { - // Just re-assign the registers. Dest gets Src's regs - rlDest.lowReg = rlSrc.lowReg; - oatClobber(cUnit, rlSrc.lowReg); - } - } else { - // Load Src either into promoted Dest or temps allocated for Dest - rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false); - loadValueDirect(cUnit, rlSrc, rlDest.lowReg); - } - - // Dest is now live and dirty (until/if we flush it to home location) - oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); - oatMarkDirty(cUnit, rlDest); - - - oatResetDefLoc(cUnit, rlDest); - if (oatIsDirty(cUnit, rlDest.lowReg) && - oatLiveOut(cUnit, rlDest.sRegLow)) { - defStart = (LIR* )cUnit->lastLIRInsn; - storeBaseDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, rlDest.sRegLow), - rlDest.lowReg, kWord); - oatMarkClean(cUnit, rlDest); - defEnd = (LIR* )cUnit->lastLIRInsn; - oatMarkDef(cUnit, rlDest, defStart, defEnd); - } -} - -RegLocation loadValueWide(CompilationUnit* cUnit, RegLocation rlSrc, - RegisterClass opKind) -{ - DCHECK(rlSrc.wide); - rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false); - if (rlSrc.location != kLocPhysReg) { - DCHECK((rlSrc.location == kLocDalvikFrame) || - (rlSrc.location == kLocCompilerTemp)); - loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg); - rlSrc.location = kLocPhysReg; - oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); - oatMarkLive(cUnit, rlSrc.highReg, - oatSRegHi(rlSrc.sRegLow)); - } - return rlSrc; -} - -void storeValueWide(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ -#ifndef NDEBUG - /* - * Sanity checking - should never try to store to the same - * ssa name during the compilation of a single instruction - * without an intervening oatClobberSReg(). - */ - DCHECK((cUnit->liveSReg == INVALID_SREG) || - (rlDest.sRegLow != cUnit->liveSReg)); - cUnit->liveSReg = rlDest.sRegLow; -#endif - LIR* defStart; - LIR* defEnd; - DCHECK_EQ(fpReg(rlSrc.lowReg), fpReg(rlSrc.highReg)); - DCHECK(rlDest.wide); - DCHECK(rlSrc.wide); - if (rlSrc.location == kLocPhysReg) { - if (oatIsLive(cUnit, rlSrc.lowReg) || - oatIsLive(cUnit, rlSrc.highReg) || - oatIsPromoted(cUnit, rlSrc.lowReg) || - oatIsPromoted(cUnit, rlSrc.highReg) || - (rlDest.location == kLocPhysReg)) { - // Src is live or promoted or Dest has assigned reg. - rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false); - opRegCopyWide(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; - oatClobber(cUnit, rlSrc.lowReg); - oatClobber(cUnit, rlSrc.highReg); - } - } else { - // Load Src either into promoted Dest or temps allocated for Dest - rlDest = oatEvalLoc(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) - oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); - oatMarkLive(cUnit, rlDest.highReg, oatSRegHi(rlDest.sRegLow)); - oatMarkDirty(cUnit, rlDest); - oatMarkPair(cUnit, rlDest.lowReg, rlDest.highReg); - - - oatResetDefLocWide(cUnit, rlDest); - if ((oatIsDirty(cUnit, rlDest.lowReg) || - oatIsDirty(cUnit, rlDest.highReg)) && - (oatLiveOut(cUnit, rlDest.sRegLow) || - oatLiveOut(cUnit, oatSRegHi(rlDest.sRegLow)))) { - defStart = (LIR*)cUnit->lastLIRInsn; - DCHECK_EQ((SRegToVReg(cUnit, rlDest.sRegLow)+1), - SRegToVReg(cUnit, oatSRegHi(rlDest.sRegLow))); - storeBaseDispWide(cUnit, targetReg(kSp), oatSRegOffset(cUnit, rlDest.sRegLow), - rlDest.lowReg, rlDest.highReg); - oatMarkClean(cUnit, rlDest); - defEnd = (LIR*)cUnit->lastLIRInsn; - oatMarkDefWide(cUnit, rlDest, defStart, defEnd); - } -} - -/* Utilities to load the current Method* */ -void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt) -{ - loadValueDirectFixed(cUnit, cUnit->methodLoc, rTgt); -} - -RegLocation loadCurrMethod(CompilationUnit *cUnit) -{ - return loadValue(cUnit, cUnit->methodLoc, kCoreReg); -} - -bool methodStarInReg(CompilationUnit* cUnit) -{ - return (cUnit->methodLoc.location == kLocPhysReg); -} - - -} // namespace art diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc deleted file mode 100644 index b0a1e4437c..0000000000 --- a/src/compiler/codegen/CodegenUtil.cc +++ /dev/null @@ -1,1051 +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. - */ - -#include "gc_map.h" -#include "verifier/dex_gc_map.h" -#include "verifier/method_verifier.h" - -namespace art { - -void setMemRefType(LIR* lir, bool isLoad, int memType) -{ - u8 *maskPtr; - u8 mask = ENCODE_MEM;; - DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE)); - if (isLoad) { - maskPtr = &lir->useMask; - } else { - maskPtr = &lir->defMask; - } - /* Clear out the memref flags */ - *maskPtr &= ~mask; - /* ..and then add back the one we need */ - switch (memType) { - case kLiteral: - DCHECK(isLoad); - *maskPtr |= ENCODE_LITERAL; - break; - case kDalvikReg: - *maskPtr |= ENCODE_DALVIK_REG; - break; - case kHeapRef: - *maskPtr |= ENCODE_HEAP_REF; - break; - case kMustNotAlias: - /* Currently only loads can be marked as kMustNotAlias */ - DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE)); - *maskPtr |= ENCODE_MUST_NOT_ALIAS; - break; - default: - LOG(FATAL) << "Oat: invalid memref kind - " << memType; - } -} - -/* - * Mark load/store instructions that access Dalvik registers through the stack. - */ -void annotateDalvikRegAccess(LIR* lir, int regId, bool isLoad, bool is64bit) -{ - setMemRefType(lir, isLoad, kDalvikReg); - - /* - * Store the Dalvik register id in aliasInfo. Mark the MSB if it is a 64-bit - * access. - */ - lir->aliasInfo = ENCODE_ALIAS_INFO(regId, is64bit); -} - -u8 oatGetRegMaskCommon(CompilationUnit* cUnit, int reg) -{ - return getRegMaskCommon(cUnit, reg); -} - -/* - * Mark the corresponding bit(s). - */ -inline void setupRegMask(CompilationUnit* cUnit, u8* mask, int reg) -{ - *mask |= getRegMaskCommon(cUnit, reg); -} - -/* Exported version of setupRegMask */ -void oatSetupRegMask(CompilationUnit* cUnit, u8* mask, int reg) -{ - setupRegMask(cUnit, mask, reg); -} - -/* - * Set up the proper fields in the resource mask - */ -void setupResourceMasks(CompilationUnit* cUnit, LIR* lir) -{ - int opcode = lir->opcode; - - if (opcode <= 0) { - lir->useMask = lir->defMask = 0; - return; - } - - uint64_t flags = EncodingMap[opcode].flags; - - if (flags & NEEDS_FIXUP) { - lir->flags.pcRelFixup = true; - } - - /* Get the starting size of the instruction's template */ - lir->flags.size = oatGetInsnSize(lir); - - /* Set up the mask for resources that are updated */ - if (flags & (IS_LOAD | IS_STORE)) { - /* Default to heap - will catch specialized classes later */ - setMemRefType(lir, flags & IS_LOAD, kHeapRef); - } - - /* - * Conservatively assume the branch here will call out a function that in - * turn will trash everything. - */ - if (flags & IS_BRANCH) { - lir->defMask = lir->useMask = ENCODE_ALL; - return; - } - - if (flags & REG_DEF0) { - setupRegMask(cUnit, &lir->defMask, lir->operands[0]); - } - - if (flags & REG_DEF1) { - setupRegMask(cUnit, &lir->defMask, lir->operands[1]); - } - - - if (flags & SETS_CCODES) { - lir->defMask |= ENCODE_CCODE; - } - - if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) { - int i; - - for (i = 0; i < 4; i++) { - if (flags & (1 << (kRegUse0 + i))) { - setupRegMask(cUnit, &lir->useMask, lir->operands[i]); - } - } - } - - if (flags & USES_CCODES) { - lir->useMask |= ENCODE_CCODE; - } - - // Handle target-specific actions - setupTargetResourceMasks(cUnit, lir); -} - -/* - * Debugging macros - */ -#define DUMP_RESOURCE_MASK(X) -#define DUMP_SSA_REP(X) - -/* Pretty-print a LIR instruction */ -void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr) -{ - LIR* lir = (LIR*) arg; - int offset = lir->offset; - int dest = lir->operands[0]; - const bool dumpNop = (cUnit->enableDebug & (1 << kDebugShowNops)); - - /* Handle pseudo-ops individually, and all regular insns as a group */ - switch (lir->opcode) { - case kPseudoMethodEntry: - LOG(INFO) << "-------- method entry " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - break; - case kPseudoMethodExit: - LOG(INFO) << "-------- Method_Exit"; - break; - case kPseudoBarrier: - LOG(INFO) << "-------- BARRIER"; - break; - case kPseudoExtended: - LOG(INFO) << "-------- " << (char* ) dest; - break; - case kPseudoSSARep: - DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest); - break; - case kPseudoEntryBlock: - LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest; - break; - case kPseudoDalvikByteCodeBoundary: - LOG(INFO) << "-------- dalvik offset: 0x" << std::hex - << lir->dalvikOffset << " @ " << (char* )lir->operands[0]; - break; - case kPseudoExitBlock: - LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; - break; - case kPseudoPseudoAlign4: - LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex - << offset << "): .align4"; - break; - case kPseudoEHBlockLabel: - LOG(INFO) << "Exception_Handling:"; - break; - case kPseudoTargetLabel: - case kPseudoNormalBlockLabel: - LOG(INFO) << "L" << (void*)lir << ":"; - break; - case kPseudoThrowTarget: - LOG(INFO) << "LT" << (void*)lir << ":"; - break; - case kPseudoIntrinsicRetry: - LOG(INFO) << "IR" << (void*)lir << ":"; - break; - case kPseudoSuspendTarget: - LOG(INFO) << "LS" << (void*)lir << ":"; - break; - case kPseudoSafepointPC: - LOG(INFO) << "LsafepointPC_0x" << std::hex << lir->offset << "_" << lir->dalvikOffset << ":"; - break; - case kPseudoExportedPC: - LOG(INFO) << "LexportedPC_0x" << std::hex << lir->offset << "_" << lir->dalvikOffset << ":"; - break; - case kPseudoCaseLabel: - LOG(INFO) << "LC" << (void*)lir << ": Case target 0x" - << std::hex << lir->operands[0] << "|" << std::dec << - lir->operands[0]; - break; - default: - if (lir->flags.isNop && !dumpNop) { - break; - } else { - std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, - lir, baseAddr)); - std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt - , lir, baseAddr)); - LOG(INFO) << StringPrintf("%05x: %-9s%s%s", - (unsigned int)(baseAddr + offset), - op_name.c_str(), op_operands.c_str(), - lir->flags.isNop ? "(nop)" : ""); - } - break; - } - - if (lir->useMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, lir->useMask, "use")); - } - if (lir->defMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, lir->defMask, "def")); - } -} - -void oatDumpPromotionMap(CompilationUnit *cUnit) -{ - int numRegs = cUnit->numDalvikRegisters + cUnit->numCompilerTemps + 1; - for (int i = 0; i < numRegs; i++) { - PromotionMap vRegMap = cUnit->promotionMap[i]; - std::string buf; - if (vRegMap.fpLocation == kLocPhysReg) { - StringAppendF(&buf, " : s%d", vRegMap.fpReg & fpRegMask()); - } - - std::string buf3; - if (i < cUnit->numDalvikRegisters) { - StringAppendF(&buf3, "%02d", i); - } else if (i == cUnit->methodSReg) { - buf3 = "Method*"; - } else { - StringAppendF(&buf3, "ct%d", i - cUnit->numDalvikRegisters); - } - - LOG(INFO) << StringPrintf("V[%s] -> %s%d%s", buf3.c_str(), - vRegMap.coreLocation == kLocPhysReg ? - "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ? - vRegMap.coreReg : oatSRegOffset(cUnit, i), - buf.c_str()); - } -} - -/* Dump a mapping table */ -void dumpMappingTable(const char* table_name, const std::string& descriptor, - const std::string& name, const std::string& signature, - const std::vector& v) { - if (v.size() > 0) { - std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, - descriptor.c_str(), name.c_str(), signature.c_str(), v.size())); - std::replace(line.begin(), line.end(), ';', '_'); - LOG(INFO) << line; - for (uint32_t i = 0; i < v.size(); i+=2) { - line = StringPrintf(" {0x%05x, 0x%04x},", v[i], v[i+1]); - LOG(INFO) << line; - } - LOG(INFO) <<" };\n\n"; - } -} - -/* Dump instructions and constant pool contents */ -void oatCodegenDump(CompilationUnit* cUnit) -{ - LOG(INFO) << "Dumping LIR insns for " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - LIR* lirInsn; - LIR* thisLIR; - int insnsSize = cUnit->insnsSize; - - LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs; - LOG(INFO) << "Ins : " << cUnit->numIns; - LOG(INFO) << "Outs : " << cUnit->numOuts; - LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills; - LOG(INFO) << "FPSpills : " << cUnit->numFPSpills; - LOG(INFO) << "CompilerTemps : " << cUnit->numCompilerTemps; - LOG(INFO) << "Frame size : " << cUnit->frameSize; - LOG(INFO) << "code size is " << cUnit->totalSize << - " bytes, Dalvik size is " << insnsSize * 2; - LOG(INFO) << "expansion factor: " - << (float)cUnit->totalSize / (float)(insnsSize * 2); - oatDumpPromotionMap(cUnit); - for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) { - oatDumpLIRInsn(cUnit, lirInsn, 0); - } - for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) { - thisLIR = (LIR*) lirInsn; - LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", - thisLIR->offset, thisLIR->offset, - thisLIR->operands[0]); - } - - const DexFile::MethodId& method_id = - cUnit->dex_file->GetMethodId(cUnit->method_idx); - std::string signature(cUnit->dex_file->GetMethodSignature(method_id)); - std::string name(cUnit->dex_file->GetMethodName(method_id)); - std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id)); - - // Dump mapping tables - dumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, cUnit->pc2dexMappingTable); - dumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, cUnit->dex2pcMappingTable); -} - - -LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0, - int op1, int op2, int op3, int op4, LIR* target) -{ - LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); - insn->dalvikOffset = dalvikOffset; - insn->opcode = opcode; - insn->operands[0] = op0; - insn->operands[1] = op1; - insn->operands[2] = op2; - insn->operands[3] = op3; - insn->operands[4] = op4; - insn->target = target; - oatSetupResourceMasks(cUnit, insn); - if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) || - (opcode == kPseudoExportedPC)) { - // Always make labels scheduling barriers - insn->useMask = insn->defMask = ENCODE_ALL; - } - return insn; -} - -/* - * The following are building blocks to construct low-level IRs with 0 - 4 - * operands. - */ -LIR* newLIR0(CompilationUnit* cUnit, int opcode) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -LIR* newLIR1(CompilationUnit* cUnit, int opcode, - int dest) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -LIR* newLIR2(CompilationUnit* cUnit, int opcode, - int dest, int src1) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_BINARY_OP)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -LIR* newLIR3(CompilationUnit* cUnit, int opcode, - int dest, int src1, int src2) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_TERTIARY_OP)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1, - src2); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -LIR* newLIR4(CompilationUnit* cUnit, int opcode, - int dest, int src1, int src2, int info) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_QUAD_OP)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1, - src2, info); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -LIR* newLIR5(CompilationUnit* cUnit, int opcode, - int dest, int src1, int src2, int info1, int info2) -{ - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_QUIN_OP)) - << EncodingMap[opcode].name << " " << (int)opcode << " " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " " - << cUnit->currentDalvikOffset; - LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1, - src2, info1, info2); - oatAppendLIR(cUnit, (LIR*) insn); - return insn; -} - -/* - * Search the existing constants in the literal pool for an exact or close match - * within specified delta (greater or equal to 0). - */ -LIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta) -{ - while (dataTarget) { - if (((unsigned) (value - ((LIR* ) dataTarget)->operands[0])) <= delta) - return (LIR* ) dataTarget; - dataTarget = dataTarget->next; - } - return NULL; -} - -/* Search the existing constants in the literal pool for an exact wide match */ -LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi) -{ - bool loMatch = false; - LIR* loTarget = NULL; - while (dataTarget) { - if (loMatch && (((LIR*)dataTarget)->operands[0] == valHi)) { - return (LIR*)loTarget; - } - loMatch = false; - if (((LIR*)dataTarget)->operands[0] == valLo) { - loMatch = true; - loTarget = dataTarget; - } - dataTarget = dataTarget->next; - } - return NULL; -} - -/* - * The following are building blocks to insert constants into the pool or - * instruction streams. - */ - -/* Add a 32-bit constant either in the constant pool */ -LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP, int value) -{ - /* Add the constant to the literal pool */ - if (constantListP) { - LIR* newValue = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocData); - newValue->operands[0] = value; - newValue->next = *constantListP; - *constantListP = (LIR*) newValue; - return newValue; - } - return NULL; -} - -/* Add a 64-bit constant to the constant pool or mixed with code */ -LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP, - int valLo, int valHi) -{ - //FIXME: hard-coded little endian, need BE variant - // Insert high word into list first - addWordData(cUnit, constantListP, valHi); - return addWordData(cUnit, constantListP, valLo); -} - -void pushWord(std::vector&buf, int data) { - buf.push_back( data & 0xff); - buf.push_back( (data >> 8) & 0xff); - buf.push_back( (data >> 16) & 0xff); - buf.push_back( (data >> 24) & 0xff); -} - -void alignBuffer(std::vector&buf, size_t offset) { - while (buf.size() < offset) { - buf.push_back(0); - } -} - -bool IsDirect(int invokeType) { - InvokeType type = static_cast(invokeType); - return type == kStatic || type == kDirect; -} - -/* Write the literal pool to the output stream */ -void installLiteralPools(CompilationUnit* cUnit) -{ - alignBuffer(cUnit->codeBuffer, cUnit->dataOffset); - LIR* dataLIR = cUnit->literalList; - while (dataLIR != NULL) { - pushWord(cUnit->codeBuffer, dataLIR->operands[0]); - dataLIR = NEXT_LIR(dataLIR); - } - // Push code and method literals, record offsets for the compiler to patch. - dataLIR = cUnit->codeLiteralList; - while (dataLIR != NULL) { - uint32_t target = dataLIR->operands[0]; - cUnit->compiler->AddCodePatch(cUnit->dex_file, - cUnit->method_idx, - cUnit->invoke_type, - target, - static_cast(dataLIR->operands[1]), - cUnit->codeBuffer.size()); - const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target); - // unique based on target to ensure code deduplication works - uint32_t unique_patch_value = reinterpret_cast(&id); - pushWord(cUnit->codeBuffer, unique_patch_value); - dataLIR = NEXT_LIR(dataLIR); - } - dataLIR = cUnit->methodLiteralList; - while (dataLIR != NULL) { - uint32_t target = dataLIR->operands[0]; - cUnit->compiler->AddMethodPatch(cUnit->dex_file, - cUnit->method_idx, - cUnit->invoke_type, - target, - static_cast(dataLIR->operands[1]), - cUnit->codeBuffer.size()); - const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target); - // unique based on target to ensure code deduplication works - uint32_t unique_patch_value = reinterpret_cast(&id); - pushWord(cUnit->codeBuffer, unique_patch_value); - dataLIR = NEXT_LIR(dataLIR); - } -} - -/* Write the switch tables to the output stream */ -void installSwitchTables(CompilationUnit* cUnit) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); - while (true) { - SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext( - &iterator); - if (tabRec == NULL) break; - alignBuffer(cUnit->codeBuffer, tabRec->offset); - /* - * For Arm, our reference point is the address of the bx - * instruction that does the launch, so we have to subtract - * the auto pc-advance. For other targets the reference point - * is a label, so we can use the offset as-is. - */ - int bxOffset = INVALID_OFFSET; - switch (cUnit->instructionSet) { - case kThumb2: - bxOffset = tabRec->anchor->offset + 4; - break; - case kX86: - bxOffset = 0; - break; - case kMips: - bxOffset = tabRec->anchor->offset; - break; - default: LOG(FATAL) << "Unexpected instruction set: " << cUnit->instructionSet; - } - if (cUnit->printMe) { - LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset; - } - if (tabRec->table[0] == Instruction::kSparseSwitchSignature) { - int* keys = (int*)&(tabRec->table[2]); - for (int elems = 0; elems < tabRec->table[1]; elems++) { - int disp = tabRec->targets[elems]->offset - bxOffset; - if (cUnit->printMe) { - LOG(INFO) << " Case[" << elems << "] key: 0x" - << std::hex << keys[elems] << ", disp: 0x" - << std::hex << disp; - } - pushWord(cUnit->codeBuffer, keys[elems]); - pushWord(cUnit->codeBuffer, - tabRec->targets[elems]->offset - bxOffset); - } - } else { - DCHECK_EQ(static_cast(tabRec->table[0]), - static_cast(Instruction::kPackedSwitchSignature)); - for (int elems = 0; elems < tabRec->table[1]; elems++) { - int disp = tabRec->targets[elems]->offset - bxOffset; - if (cUnit->printMe) { - LOG(INFO) << " Case[" << elems << "] disp: 0x" - << std::hex << disp; - } - pushWord(cUnit->codeBuffer, tabRec->targets[elems]->offset - bxOffset); - } - } - } -} - -/* Write the fill array dta to the output stream */ -void installFillArrayData(CompilationUnit* cUnit) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); - while (true) { - FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( - &iterator); - if (tabRec == NULL) break; - alignBuffer(cUnit->codeBuffer, tabRec->offset); - for (int i = 0; i < (tabRec->size + 1) / 2; i++) { - cUnit->codeBuffer.push_back( tabRec->table[i] & 0xFF); - cUnit->codeBuffer.push_back( (tabRec->table[i] >> 8) & 0xFF); - } - } -} - -int assignLiteralOffsetCommon(LIR* lir, int offset) -{ - for (;lir != NULL; lir = lir->next) { - lir->offset = offset; - offset += 4; - } - return offset; -} - -// Make sure we have a code address for every declared catch entry -bool verifyCatchEntries(CompilationUnit* cUnit) -{ - bool success = true; - for (std::set::const_iterator it = cUnit->catches.begin(); it != cUnit->catches.end(); ++it) { - uint32_t dexPc = *it; - bool found = false; - for (size_t i = 0; i < cUnit->dex2pcMappingTable.size(); i += 2) { - if (dexPc == cUnit->dex2pcMappingTable[i+1]) { - found = true; - break; - } - } - if (!found) { - LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dexPc; - success = false; - } - } - // Now, try in the other direction - for (size_t i = 0; i < cUnit->dex2pcMappingTable.size(); i += 2) { - uint32_t dexPc = cUnit->dex2pcMappingTable[i+1]; - if (cUnit->catches.find(dexPc) == cUnit->catches.end()) { - LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << dexPc; - success = false; - } - } - if (!success) { - LOG(INFO) << "Bad dex2pcMapping table in " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - LOG(INFO) << "Entries @ decode: " << cUnit->catches.size() << ", Entries in table: " - << cUnit->dex2pcMappingTable.size()/2; - } - return success; -} - -void createMappingTables(CompilationUnit* cUnit) -{ - for (LIR* tgtLIR = (LIR *) cUnit->firstLIRInsn; tgtLIR != NULL; tgtLIR = NEXT_LIR(tgtLIR)) { - if (!tgtLIR->flags.isNop && (tgtLIR->opcode == kPseudoSafepointPC)) { - cUnit->pc2dexMappingTable.push_back(tgtLIR->offset); - cUnit->pc2dexMappingTable.push_back(tgtLIR->dalvikOffset); - } - if (!tgtLIR->flags.isNop && (tgtLIR->opcode == kPseudoExportedPC)) { - cUnit->dex2pcMappingTable.push_back(tgtLIR->offset); - cUnit->dex2pcMappingTable.push_back(tgtLIR->dalvikOffset); - } - } - DCHECK(verifyCatchEntries(cUnit)); - cUnit->combinedMappingTable.push_back(cUnit->pc2dexMappingTable.size() + - cUnit->dex2pcMappingTable.size()); - cUnit->combinedMappingTable.push_back(cUnit->pc2dexMappingTable.size()); - cUnit->combinedMappingTable.insert(cUnit->combinedMappingTable.end(), - cUnit->pc2dexMappingTable.begin(), - cUnit->pc2dexMappingTable.end()); - cUnit->combinedMappingTable.insert(cUnit->combinedMappingTable.end(), - cUnit->dex2pcMappingTable.begin(), - cUnit->dex2pcMappingTable.end()); -} - -class NativePcToReferenceMapBuilder { - public: - NativePcToReferenceMapBuilder(std::vector* table, - size_t entries, uint32_t max_native_offset, - size_t references_width) : entries_(entries), - references_width_(references_width), in_use_(entries), - table_(table) { - // Compute width in bytes needed to hold max_native_offset. - native_offset_width_ = 0; - while (max_native_offset != 0) { - native_offset_width_++; - max_native_offset >>= 8; - } - // Resize table and set up header. - table->resize((EntryWidth() * entries) + sizeof(uint32_t)); - CHECK_LT(native_offset_width_, 1U << 3); - (*table)[0] = native_offset_width_ & 7; - CHECK_LT(references_width_, 1U << 13); - (*table)[0] |= (references_width_ << 3) & 0xFF; - (*table)[1] = (references_width_ >> 5) & 0xFF; - CHECK_LT(entries, 1U << 16); - (*table)[2] = entries & 0xFF; - (*table)[3] = (entries >> 8) & 0xFF; - } - - void AddEntry(uint32_t native_offset, const uint8_t* references) { - size_t table_index = TableIndex(native_offset); - while (in_use_[table_index]) { - table_index = (table_index + 1) % entries_; - } - in_use_[table_index] = true; - SetNativeOffset(table_index, native_offset); - DCHECK_EQ(native_offset, GetNativeOffset(table_index)); - SetReferences(table_index, references); - } - - private: - size_t TableIndex(uint32_t native_offset) { - return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_; - } - - uint32_t GetNativeOffset(size_t table_index) { - uint32_t native_offset = 0; - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - for (size_t i = 0; i < native_offset_width_; i++) { - native_offset |= (*table_)[table_offset + i] << (i * 8); - } - return native_offset; - } - - void SetNativeOffset(size_t table_index, uint32_t native_offset) { - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - for (size_t i = 0; i < native_offset_width_; i++) { - (*table_)[table_offset + i] = (native_offset >> (i * 8)) & 0xFF; - } - } - - void SetReferences(size_t table_index, const uint8_t* references) { - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - memcpy(&(*table_)[table_offset + native_offset_width_], references, references_width_); - } - - size_t EntryWidth() const { - return native_offset_width_ + references_width_; - } - - // Number of entries in the table. - const size_t entries_; - // Number of bytes used to encode the reference bitmap. - const size_t references_width_; - // Number of bytes used to encode a native offset. - size_t native_offset_width_; - // Entries that are in use. - std::vector in_use_; - // The table we're building. - std::vector* const table_; -}; - -static void createNativeGcMap(CompilationUnit* cUnit) { - const std::vector& mapping_table = cUnit->pc2dexMappingTable; - uint32_t max_native_offset = 0; - for (size_t i = 0; i < mapping_table.size(); i += 2) { - uint32_t native_offset = mapping_table[i + 0]; - if (native_offset > max_native_offset) { - max_native_offset = native_offset; - } - } - Compiler::MethodReference method_ref(cUnit->dex_file, cUnit->method_idx); - const std::vector* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref); - verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4); - // Compute native offset to references size. - NativePcToReferenceMapBuilder native_gc_map_builder(&cUnit->nativeGcMap, - mapping_table.size() / 2, max_native_offset, - dex_gc_map.RegWidth()); - - for (size_t i = 0; i < mapping_table.size(); i += 2) { - uint32_t native_offset = mapping_table[i + 0]; - uint32_t dex_pc = mapping_table[i + 1]; - const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); - CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc; - native_gc_map_builder.AddEntry(native_offset, references); - } -} - -/* Determine the offset of each literal field */ -int assignLiteralOffset(CompilationUnit* cUnit, int offset) -{ - offset = assignLiteralOffsetCommon(cUnit->literalList, offset); - offset = assignLiteralOffsetCommon(cUnit->codeLiteralList, offset); - offset = assignLiteralOffsetCommon(cUnit->methodLiteralList, offset); - return offset; -} - -int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); - while (true) { - SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext( - &iterator); - if (tabRec == NULL) break; - tabRec->offset = offset; - if (tabRec->table[0] == Instruction::kSparseSwitchSignature) { - offset += tabRec->table[1] * (sizeof(int) * 2); - } else { - DCHECK_EQ(static_cast(tabRec->table[0]), - static_cast(Instruction::kPackedSwitchSignature)); - offset += tabRec->table[1] * sizeof(int); - } - } - return offset; -} - -int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); - while (true) { - FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( - &iterator); - if (tabRec == NULL) break; - tabRec->offset = offset; - offset += tabRec->size; - // word align - offset = (offset + 3) & ~3; - } - return offset; -} - -/* - * Walk the compilation unit and assign offsets to instructions - * and literals and compute the total size of the compiled unit. - */ -void oatAssignOffsets(CompilationUnit* cUnit) -{ - int offset = oatAssignInsnOffsets(cUnit); - - /* Const values have to be word aligned */ - offset = (offset + 3) & ~3; - - /* Set up offsets for literals */ - cUnit->dataOffset = offset; - - offset = assignLiteralOffset(cUnit, offset); - - offset = assignSwitchTablesOffset(cUnit, offset); - - offset = assignFillArrayDataOffset(cUnit, offset); - - cUnit->totalSize = offset; -} - -/* - * Go over each instruction in the list and calculate the offset from the top - * before sending them off to the assembler. If out-of-range branch distance is - * seen rearrange the instructions a bit to correct it. - */ -void oatAssembleLIR(CompilationUnit* cUnit) -{ - oatAssignOffsets(cUnit); - /* - * Assemble here. Note that we generate code with optimistic assumptions - * and if found now to work, we'll have to redo the sequence and retry. - */ - - while (true) { - AssemblerStatus res = oatAssembleInstructions(cUnit, 0); - if (res == kSuccess) { - break; - } else { - cUnit->assemblerRetries++; - if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) { - oatCodegenDump(cUnit); - LOG(FATAL) << "Assembler error - too many retries"; - } - // Redo offsets and try again - oatAssignOffsets(cUnit); - cUnit->codeBuffer.clear(); - } - } - - // Install literals - installLiteralPools(cUnit); - - // Install switch tables - installSwitchTables(cUnit); - - // Install fill array data - installFillArrayData(cUnit); - - // Create the mapping table and native offset to reference map. - createMappingTables(cUnit); - - createNativeGcMap(cUnit); -} - -/* - * Insert a kPseudoCaseLabel at the beginning of the Dalvik - * offset vaddr. This label will be used to fix up the case - * branch table during the assembly phase. Be sure to set - * all resource flags on this to prevent code motion across - * target boundaries. KeyVal is just there for debugging. - */ -LIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal) -{ - SafeMap::iterator it; - it = cUnit->boundaryMap.find(vaddr); - if (it == cUnit->boundaryMap.end()) { - LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr; - } - LIR* newLabel = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR); - newLabel->dalvikOffset = vaddr; - newLabel->opcode = kPseudoCaseLabel; - newLabel->operands[0] = keyVal; - oatInsertLIRAfter(it->second, (LIR*)newLabel); - return newLabel; -} - -void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec) -{ - const u2* table = tabRec->table; - int baseVaddr = tabRec->vaddr; - int *targets = (int*)&table[4]; - int entries = table[1]; - int lowKey = s4FromSwitchData(&table[2]); - for (int i = 0; i < entries; i++) { - tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i], - i + lowKey); - } -} - -void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec) -{ - const u2* table = tabRec->table; - int baseVaddr = tabRec->vaddr; - int entries = table[1]; - int* keys = (int*)&table[2]; - int* targets = &keys[entries]; - for (int i = 0; i < entries; i++) { - tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i], - keys[i]); - } -} - -void oatProcessSwitchTables(CompilationUnit* cUnit) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); - while (true) { - SwitchTable *tabRec = - (SwitchTable *) oatGrowableListIteratorNext(&iterator); - if (tabRec == NULL) break; - if (tabRec->table[0] == Instruction::kPackedSwitchSignature) { - markPackedCaseLabels(cUnit, tabRec); - } else if (tabRec->table[0] == Instruction::kSparseSwitchSignature) { - markSparseCaseLabels(cUnit, tabRec); - } else { - LOG(FATAL) << "Invalid switch table"; - } - } -} - -//FIXME: Do we have endian issues here? - -void dumpSparseSwitchTable(const u2* table) - /* - * Sparse switch data format: - * ushort ident = 0x0200 magic value - * ushort size number of entries in the table; > 0 - * int keys[size] keys, sorted low-to-high; 32-bit aligned - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (2+size*4) 16-bit code units. - */ -{ - u2 ident = table[0]; - int entries = table[1]; - int* keys = (int*)&table[2]; - int* targets = &keys[entries]; - LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident - << ", entries: " << std::dec << entries; - for (int i = 0; i < entries; i++) { - LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex << targets[i]; - } -} - -void dumpPackedSwitchTable(const u2* table) - /* - * Packed switch data format: - * ushort ident = 0x0100 magic value - * ushort size number of entries in the table - * int first_key first (and lowest) switch case value - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (4+size*2) 16-bit code units. - */ -{ - u2 ident = table[0]; - int* targets = (int*)&table[4]; - int entries = table[1]; - int lowKey = s4FromSwitchData(&table[2]); - LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident - << ", entries: " << std::dec << entries << ", lowKey: " << lowKey; - for (int i = 0; i < entries; i++) { - LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex - << targets[i]; - } -} - -/* - * Set up special LIR to mark a Dalvik byte-code instruction start and - * record it in the boundaryMap. NOTE: in cases such as kMirOpCheck in - * which we split a single Dalvik instruction, only the first MIR op - * associated with a Dalvik PC should be entered into the map. - */ -LIR* markBoundary(CompilationUnit* cUnit, int offset, const char* instStr) -{ - LIR* res = newLIR1(cUnit, kPseudoDalvikByteCodeBoundary, (intptr_t) instStr); - if (cUnit->boundaryMap.find(offset) == cUnit->boundaryMap.end()) { - cUnit->boundaryMap.Put(offset, res); - } - return res; -} - -} - // namespace art diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h deleted file mode 100644 index 868e666b08..0000000000 --- a/src/compiler/codegen/CompilerCodegen.h +++ /dev/null @@ -1,239 +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. - */ - -#ifndef ART_SRC_COMPILER_COMPILERCODEGEN_H_ -#define ART_SRC_COMPILER_COMPILERCODEGEN_H_ - -#include "../CompilerIR.h" - -namespace art { - - -// Set to 1 to measure cost of suspend check -#define NO_SUSPEND 0 - -/* Bit flags describing the behavior of native opcodes (Arm/Mips/x86 combined) */ -enum OpFeatureFlags { - kIsBranch = 0, - kNoOperand, - kIsUnaryOp, - kIsBinaryOp, - kIsTertiaryOp, - kIsQuadOp, - kIsQuinOp, - kIsSextupleOp, - kIsIT, - kMemLoad, - kMemStore, - kPCRelFixup, // x86 FIXME: add NEEDS_FIXUP to instruction attributes - kRegDef0, - kRegDef1, - kRegDefA, - kRegDefD, - kRegDefFPCSList0, - kRegDefFPCSList2, - kRegDefList0, - kRegDefList1, - kRegDefList2, - kRegDefLR, - kRegDefSP, - kRegUse0, - kRegUse1, - kRegUse2, - kRegUse3, - kRegUse4, - kRegUseA, - kRegUseC, - kRegUseD, - kRegUseFPCSList0, - kRegUseFPCSList2, - kRegUseList0, - kRegUseList1, - kRegUseLR, - kRegUsePC, - kRegUseSP, - kSetsCCodes, - kUsesCCodes -}; - -#define IS_BINARY_OP (1ULL << kIsBinaryOp) -#define IS_BRANCH (1ULL << kIsBranch) -#define IS_IT (1ULL << kIsIT) -#define IS_LOAD (1ULL << kMemLoad) -#define IS_QUAD_OP (1ULL << kIsQuadOp) -#define IS_QUIN_OP (1ULL << kIsQuinOp) -#define IS_SEXTUPLE_OP (1ULL << kIsSextupleOp) -#define IS_STORE (1ULL << kMemStore) -#define IS_TERTIARY_OP (1ULL << kIsTertiaryOp) -#define IS_UNARY_OP (1ULL << kIsUnaryOp) -#define NEEDS_FIXUP (1ULL << kPCRelFixup) -#define NO_OPERAND (1ULL << kNoOperand) -#define REG_DEF0 (1ULL << kRegDef0) -#define REG_DEF1 (1ULL << kRegDef1) -#define REG_DEFA (1ULL << kRegDefA) -#define REG_DEFD (1ULL << kRegDefD) -#define REG_DEF_FPCS_LIST0 (1ULL << kRegDefFPCSList0) -#define REG_DEF_FPCS_LIST2 (1ULL << kRegDefFPCSList2) -#define REG_DEF_LIST0 (1ULL << kRegDefList0) -#define REG_DEF_LIST1 (1ULL << kRegDefList1) -#define REG_DEF_LR (1ULL << kRegDefLR) -#define REG_DEF_SP (1ULL << kRegDefSP) -#define REG_USE0 (1ULL << kRegUse0) -#define REG_USE1 (1ULL << kRegUse1) -#define REG_USE2 (1ULL << kRegUse2) -#define REG_USE3 (1ULL << kRegUse3) -#define REG_USE4 (1ULL << kRegUse4) -#define REG_USEA (1ULL << kRegUseA) -#define REG_USEC (1ULL << kRegUseC) -#define REG_USED (1ULL << kRegUseD) -#define REG_USE_FPCS_LIST0 (1ULL << kRegUseFPCSList0) -#define REG_USE_FPCS_LIST2 (1ULL << kRegUseFPCSList2) -#define REG_USE_LIST0 (1ULL << kRegUseList0) -#define REG_USE_LIST1 (1ULL << kRegUseList1) -#define REG_USE_LR (1ULL << kRegUseLR) -#define REG_USE_PC (1ULL << kRegUsePC) -#define REG_USE_SP (1ULL << kRegUseSP) -#define SETS_CCODES (1ULL << kSetsCCodes) -#define USES_CCODES (1ULL << kUsesCCodes) - -/* Common combo register usage patterns */ -#define REG_DEF01 (REG_DEF0 | REG_DEF1) -#define REG_DEF01_USE2 (REG_DEF0 | REG_DEF1 | REG_USE2) -#define REG_DEF0_USE01 (REG_DEF0 | REG_USE01) -#define REG_DEF0_USE0 (REG_DEF0 | REG_USE0) -#define REG_DEF0_USE12 (REG_DEF0 | REG_USE12) -#define REG_DEF0_USE1 (REG_DEF0 | REG_USE1) -#define REG_DEF0_USE2 (REG_DEF0 | REG_USE2) -#define REG_DEFAD_USEAD (REG_DEFAD_USEA | REG_USED) -#define REG_DEFAD_USEA (REG_DEFA_USEA | REG_DEFD) -#define REG_DEFA_USEA (REG_DEFA | REG_USEA) -#define REG_USE012 (REG_USE01 | REG_USE2) -#define REG_USE014 (REG_USE01 | REG_USE4) -#define REG_USE01 (REG_USE0 | REG_USE1) -#define REG_USE02 (REG_USE0 | REG_USE2) -#define REG_USE12 (REG_USE1 | REG_USE2) -#define REG_USE23 (REG_USE2 | REG_USE3) - -LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0 = 0, - int op1 = 0, int op2 = 0, int op3 = 0, int op4 = 0, - LIR* target = NULL); - -int oatGetInsnSize(LIR* lir); - -void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir); -void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - bool gtBias, bool isDouble); - -CallInfo* oatNewCallInfo(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - InvokeType type, bool isRange); - -/* Lower middle-level IR to low-level IR for the whole method */ -void oatMethodMIR2LIR(CompilationUnit* cUnit); - -/* Bitcode conversions */ -void oatMethodMIR2Bitcode(CompilationUnit* cUnit); -void oatMethodBitcode2LIR(CompilationUnit* cUnit); - -/* Lower middle-level IR to low-level IR for the simple methods */ -void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase ); - -/* Assemble LIR into machine code */ -void oatAssembleLIR(CompilationUnit* cUnit); -AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit, - intptr_t startAddr); -void oatAssignOffsets(CompilationUnit* cUnit); -int oatAssignInsnOffsets(CompilationUnit* cUnit); - -/* Implemented in the codegen//ArchUtility.c */ -void oatCodegenDump(CompilationUnit* cUnit); -void oatDumpPromotionMap(CompilationUnit* cUnit); -std::string buildInsnString(const char* fmt, LIR* lir, - unsigned char* baseAddr); - - -/* Implemented in codegen//Ralloc.c */ -void oatSimpleRegAlloc(CompilationUnit* cUnit); - -/* Implemented in codegen//ThumbUtil.c */ -void oatInitializeRegAlloc(CompilationUnit* cUnit); - -/* Implemented in codegen///ArchVariant.c */ -InstructionSet oatInstructionSet(); - -/* - * Implemented in codegen///ArchVariant.c - * Architecture-specific initializations and checks - */ -bool oatArchVariantInit(void); - -/* Implemented in codegen///ArchVariant.c */ -int oatTargetOptHint(int key); - -/* Implemented in codegen///ArchVariant.c */ -void oatGenMemBarrier(CompilationUnit* cUnit, int barrierKind); - -LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg1, int base, int offset, ThrowKind kind); -LIR* opThreadMem(CompilationUnit* cUnit, OpKind op, int threadOffset); -LIR* opMem(CompilationUnit* cUnit, OpKind op, int rBase, int disp); -LIR* storeBaseIndexedDisp(CompilationUnit *cUnit, - int rBase, int rIndex, int scale, int displacement, - int rSrc, int rSrcHi, OpSize size, int sReg); -LIR* opRegMem(CompilationUnit *cUnit, OpKind op, int rDest, int rBase, int offset); -LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, - int src2, LIR* target); -void oatSetupRegMask(CompilationUnit* cUnit, u8* mask, int reg); -u8 oatGetRegMaskCommon(CompilationUnit* cUnit, int reg); -void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir); -RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int regHi, bool isDiv); -RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int lit, bool isDiv); -void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg); -bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin); -void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset); -void opTlsCmp(CompilationUnit* cUnit, int offset, int val); -bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info); -bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier); -LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target); -LIR* opVldm(CompilationUnit* cUnit, int rBase, int count); -LIR* opVstm(CompilationUnit* cUnit, int rBase, int count); -void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, - RegLocation rlResult, int lit, - int firstBit, int secondBit); -RegLocation inlineTarget(CompilationUnit* cUnit, CallInfo* info); -RegLocation inlineTargetWide(CompilationUnit* cUnit, CallInfo* info); -void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi); -LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg, int immVal, ThrowKind kind); -LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target); -LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target); -LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide); -uint64_t getPCUseDefEncoding(); -uint64_t getRegMaskCommon(CompilationUnit* cUnit, int reg); -int s2d(int lowReg, int highReg); -bool fpReg(int reg); -bool singleReg(int reg); -bool doubleReg(int reg); -uint32_t fpRegMask(); -bool sameRegType(int reg1, int reg2); -int targetReg(SpecialTargetRegister reg); -RegLocation locCReturn(); -RegLocation locCReturnWide(); -RegLocation locCReturnFloat(); -RegLocation locCReturnDouble(); - -} // namespace art - -#endif // ART_SRC_COMPILER_COMPILERCODEGEN_H_ diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc deleted file mode 100644 index bc61c54f1f..0000000000 --- a/src/compiler/codegen/GenCommon.cc +++ /dev/null @@ -1,2321 +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 "oat/runtime/oat_support_entrypoints.h" - -namespace art { - -/* - * This source files contains "gen" codegen routines that should - * be applicable to most targets. Only mid-level support utilities - * and "op" calls may be used here. - */ -void genInvoke(CompilationUnit* cUnit, CallInfo* info); -bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, - RegLocation rlSrc, RegLocation rlDest, int lit); - -void markSafepointPC(CompilationUnit* cUnit, LIR* inst) -{ - inst->defMask = ENCODE_ALL; - LIR* safepointPC = newLIR0(cUnit, kPseudoSafepointPC); - DCHECK_EQ(safepointPC->defMask, ENCODE_ALL); -} - -/* - * To save scheduling time, helper calls are broken into two parts: generation of - * the helper target address, and the actuall call to the helper. Because x86 - * has a memory call operation, part 1 is a NOP for x86. For other targets, - * load arguments between the two parts. - */ -int callHelperSetup(CompilationUnit* cUnit, int helperOffset) -{ - return (cUnit->instructionSet == kX86) ? 0 : loadHelper(cUnit, helperOffset); -} - -/* NOTE: if rTgt is a temp, it will be freed following use */ -LIR* callHelper(CompilationUnit* cUnit, int rTgt, int helperOffset, bool safepointPC) -{ - LIR* callInst; - if (cUnit->instructionSet == kX86) { - callInst = opThreadMem(cUnit, kOpBlx, helperOffset); - } else { - callInst = opReg(cUnit, kOpBlx, rTgt); - oatFreeTemp(cUnit, rTgt); - } - if (safepointPC) { - markSafepointPC(cUnit, callInst); - } - return callInst; -} - -void callRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - opRegCopy(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset, RegLocation arg0, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - if (arg0.wide == 0) { - loadValueDirectFixed(cUnit, arg0, targetReg(kArg0)); - } else { - loadValueDirectWideFixed(cUnit, arg0, targetReg(kArg0), targetReg(kArg1)); - } - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadConstant(cUnit, targetReg(kArg0), arg0); - loadConstant(cUnit, targetReg(kArg1), arg1); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0, - RegLocation arg1, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - if (arg1.wide == 0) { - loadValueDirectFixed(cUnit, arg1, targetReg(kArg1)); - } else { - loadValueDirectWideFixed(cUnit, arg1, targetReg(kArg1), targetReg(kArg2)); - } - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset, RegLocation arg0, - int arg1, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadValueDirectFixed(cUnit, arg0, targetReg(kArg0)); - loadConstant(cUnit, targetReg(kArg1), arg1); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - opRegCopy(cUnit, targetReg(kArg1), arg1); - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - opRegCopy(cUnit, targetReg(kArg0), arg0); - loadConstant(cUnit, targetReg(kArg1), arg1); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadCurrMethodDirect(cUnit, targetReg(kArg1)); - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset, - RegLocation arg0, RegLocation arg1, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - if (arg0.wide == 0) { - loadValueDirectFixed(cUnit, arg0, arg0.fp ? targetReg(kFArg0) : targetReg(kArg0)); - if (arg1.wide == 0) { - if (cUnit->instructionSet == kMips) { - loadValueDirectFixed(cUnit, arg1, arg1.fp ? targetReg(kFArg2) : targetReg(kArg1)); - } else { - loadValueDirectFixed(cUnit, arg1, targetReg(kArg1)); - } - } else { - if (cUnit->instructionSet == kMips) { - loadValueDirectWideFixed(cUnit, arg1, arg1.fp ? targetReg(kFArg2) : targetReg(kArg1), arg1.fp ? targetReg(kFArg3) : targetReg(kArg2)); - } else { - loadValueDirectWideFixed(cUnit, arg1, targetReg(kArg1), targetReg(kArg2)); - } - } - } else { - loadValueDirectWideFixed(cUnit, arg0, arg0.fp ? targetReg(kFArg0) : targetReg(kArg0), arg0.fp ? targetReg(kFArg1) : targetReg(kArg1)); - if (arg1.wide == 0) { - loadValueDirectFixed(cUnit, arg1, arg1.fp ? targetReg(kFArg2) : targetReg(kArg2)); - } else { - loadValueDirectWideFixed(cUnit, arg1, arg1.fp ? targetReg(kFArg2) : targetReg(kArg2), arg1.fp ? targetReg(kFArg3) : targetReg(kArg3)); - } - } - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - DCHECK_NE((int)targetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1 - opRegCopy(cUnit, targetReg(kArg0), arg0); - opRegCopy(cUnit, targetReg(kArg1), arg1); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1, - int arg2, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - DCHECK_NE((int)targetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1 - opRegCopy(cUnit, targetReg(kArg0), arg0); - opRegCopy(cUnit, targetReg(kArg1), arg1); - loadConstant(cUnit, targetReg(kArg2), arg2); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0, - RegLocation arg2, bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadValueDirectFixed(cUnit, arg2, targetReg(kArg2)); - loadCurrMethodDirect(cUnit, targetReg(kArg1)); - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg2, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadCurrMethodDirect(cUnit, targetReg(kArg1)); - loadConstant(cUnit, targetReg(kArg2), arg2); - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -void callRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset, - int arg0, RegLocation arg1, RegLocation arg2, - bool safepointPC) { - int rTgt = callHelperSetup(cUnit, helperOffset); - loadValueDirectFixed(cUnit, arg1, targetReg(kArg1)); - if (arg2.wide == 0) { - loadValueDirectFixed(cUnit, arg2, targetReg(kArg2)); - } else { - loadValueDirectWideFixed(cUnit, arg2, targetReg(kArg2), targetReg(kArg3)); - } - loadConstant(cUnit, targetReg(kArg0), arg0); - oatClobberCalleeSave(cUnit); - callHelper(cUnit, rTgt, helperOffset, safepointPC); -} - -/* - * Generate an kPseudoBarrier marker to indicate the boundary of special - * blocks. - */ -void genBarrier(CompilationUnit* cUnit) -{ - LIR* barrier = newLIR0(cUnit, kPseudoBarrier); - /* Mark all resources as being clobbered */ - barrier->defMask = -1; -} - - -/* Generate unconditional branch instructions */ -LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target) -{ - LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr); - branch->target = (LIR*) target; - return branch; -} - -// FIXME: need to do some work to split out targets with -// condition codes and those without -LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, - ThrowKind kind) -{ - DCHECK_NE(cUnit->instructionSet, kMips); - LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, - cUnit->currentDalvikOffset); - LIR* branch = opCondBranch(cUnit, cCode, tgt); - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - return branch; -} - -LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg, int immVal, ThrowKind kind) -{ - LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, - cUnit->currentDalvikOffset); - LIR* branch; - if (cCode == kCondAl) { - branch = opUnconditionalBranch(cUnit, tgt); - } else { - branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt); - } - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - return branch; -} - -/* Perform null-check on a register. */ -LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags) -{ - if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) && - optFlags & MIR_IGNORE_NULL_CHECK) { - return NULL; - } - return genImmedCheck(cUnit, kCondEq, mReg, 0, kThrowNullPointer); -} - -/* Perform check on two registers */ -LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode, - int reg1, int reg2, ThrowKind kind) -{ - LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, - cUnit->currentDalvikOffset, reg1, reg2); - LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt); - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - return branch; -} - -void genCompareAndBranch(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlSrc1, RegLocation rlSrc2, LIR* taken, - LIR* fallThrough) -{ - ConditionCode cond; - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - switch (opcode) { - case Instruction::IF_EQ: - cond = kCondEq; - break; - case Instruction::IF_NE: - cond = kCondNe; - break; - case Instruction::IF_LT: - cond = kCondLt; - break; - case Instruction::IF_GE: - cond = kCondGe; - break; - case Instruction::IF_GT: - cond = kCondGt; - break; - case Instruction::IF_LE: - cond = kCondLe; - break; - default: - cond = (ConditionCode)0; - LOG(FATAL) << "Unexpected opcode " << (int)opcode; - } - opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg, taken); - opUnconditionalBranch(cUnit, fallThrough); -} - -void genCompareZeroAndBranch(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlSrc, LIR* taken, LIR* fallThrough) -{ - ConditionCode cond; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - switch (opcode) { - case Instruction::IF_EQZ: - cond = kCondEq; - break; - case Instruction::IF_NEZ: - cond = kCondNe; - break; - case Instruction::IF_LTZ: - cond = kCondLt; - break; - case Instruction::IF_GEZ: - cond = kCondGe; - break; - case Instruction::IF_GTZ: - cond = kCondGt; - break; - case Instruction::IF_LEZ: - cond = kCondLe; - break; - default: - cond = (ConditionCode)0; - LOG(FATAL) << "Unexpected opcode " << (int)opcode; - } - if (cUnit->instructionSet == kThumb2) { - opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); - opCondBranch(cUnit, cond, taken); - } else { - opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, taken); - } - opUnconditionalBranch(cUnit, fallThrough); -} - -void genIntToLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (rlSrc.location == kLocPhysReg) { - opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - } else { - loadValueDirect(cUnit, rlSrc, rlResult.lowReg); - } - opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31); - storeValueWide(cUnit, rlDest, rlResult); -} - -void genIntNarrowing(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlDest, RegLocation rlSrc) -{ - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - OpKind op = kOpInvalid; - switch (opcode) { - case Instruction::INT_TO_BYTE: - op = kOp2Byte; - break; - case Instruction::INT_TO_SHORT: - op = kOp2Short; - break; - case Instruction::INT_TO_CHAR: - op = kOp2Char; - break; - default: - LOG(ERROR) << "Bad int conversion type"; - } - opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg); - storeValue(cUnit, rlDest, rlResult); -} - -/* - * Let helper function take care of everything. Will call - * Array::AllocFromCode(type_idx, method, count); - * Note: AllocFromCode will handle checks for errNegativeArraySize. - */ -void genNewArray(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest, - RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); /* Everything to home location */ - int funcOffset; - if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - *cUnit->dex_file, - type_idx)) { - funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode); - } else { - funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck); - } - callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc, true); - RegLocation rlResult = oatGetReturn(cUnit, false); - storeValue(cUnit, rlDest, rlResult); -} - -/* - * Similar to genNewArray, but with post-allocation initialization. - * Verifier guarantees we're dealing with an array class. Current - * code throws runtime exception "bad Filled array req" for 'D' and 'J'. - * Current code also throws internal unimp if not 'L', '[' or 'I'. - */ -void genFilledNewArray(CompilationUnit* cUnit, CallInfo* info) -{ - int elems = info->numArgWords; - int typeIdx = info->index; - oatFlushAllRegs(cUnit); /* Everything to home location */ - int funcOffset; - if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - *cUnit->dex_file, - typeIdx)) { - funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode); - } else { - funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck); - } - callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems, true); - oatFreeTemp(cUnit, targetReg(kArg2)); - oatFreeTemp(cUnit, targetReg(kArg1)); - /* - * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the - * return region. Because AllocFromCode placed the new array - * in kRet0, we'll just lock it into place. When debugger support is - * added, it may be necessary to additionally copy all return - * values to a home location in thread-local storage - */ - oatLockTemp(cUnit, targetReg(kRet0)); - - // TODO: use the correct component size, currently all supported types - // share array alignment with ints (see comment at head of function) - size_t component_size = sizeof(int32_t); - - // Having a range of 0 is legal - if (info->isRange && (elems > 0)) { - /* - * Bit of ugliness here. We're going generate a mem copy loop - * on the register range, but it is possible that some regs - * in the range have been promoted. This is unlikely, but - * before generating the copy, we'll just force a flush - * of any regs in the source range that have been promoted to - * home location. - */ - for (int i = 0; i < elems; i++) { - RegLocation loc = oatUpdateLoc(cUnit, info->args[i]); - if (loc.location == kLocPhysReg) { - storeBaseDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, kWord); - } - } - /* - * TUNING note: generated code here could be much improved, but - * this is an uncommon operation and isn't especially performance - * critical. - */ - int rSrc = oatAllocTemp(cUnit); - int rDst = oatAllocTemp(cUnit); - int rIdx = oatAllocTemp(cUnit); - int rVal = INVALID_REG; - switch(cUnit->instructionSet) { - case kThumb2: - rVal = targetReg(kLr); - break; - case kX86: - oatFreeTemp(cUnit, targetReg(kRet0)); - rVal = oatAllocTemp(cUnit); - break; - case kMips: - rVal = oatAllocTemp(cUnit); - break; - default: LOG(FATAL) << "Unexpected instruction set: " << cUnit->instructionSet; - } - // Set up source pointer - RegLocation rlFirst = info->args[0]; - opRegRegImm(cUnit, kOpAdd, rSrc, targetReg(kSp), - oatSRegOffset(cUnit, rlFirst.sRegLow)); - // Set up the target pointer - opRegRegImm(cUnit, kOpAdd, rDst, targetReg(kRet0), - Array::DataOffset(component_size).Int32Value()); - // Set up the loop counter (known to be > 0) - loadConstant(cUnit, rIdx, elems - 1); - // Generate the copy loop. Going backwards for convenience - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - // Copy next element - loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord); - storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord); - oatFreeTemp(cUnit, rVal); - opDecAndBranch(cUnit, kCondGe, rIdx, target); - if (cUnit->instructionSet == kX86) { - // Restore the target pointer - opRegRegImm(cUnit, kOpAdd, targetReg(kRet0), rDst, -Array::DataOffset(component_size).Int32Value()); - } - } else if (!info->isRange) { - // TUNING: interleave - for (int i = 0; i < elems; i++) { - RegLocation rlArg = loadValue(cUnit, info->args[i], kCoreReg); - storeBaseDisp(cUnit, targetReg(kRet0), - Array::DataOffset(component_size).Int32Value() + - i * 4, rlArg.lowReg, kWord); - // If the loadValue caused a temp to be allocated, free it - if (oatIsTemp(cUnit, rlArg.lowReg)) { - oatFreeTemp(cUnit, rlArg.lowReg); - } - } - } - if (info->result.location != kLocInvalid) { - storeValue(cUnit, info->result, oatGetReturn(cUnit, false /* not fp */)); - } -} - -void genSput(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlSrc, - bool isLongOrDouble, bool isObject) -{ - int fieldOffset; - int ssbIndex; - bool isVolatile; - bool isReferrersClass; - - OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, *cUnit->dex_file, - cUnit->code_item, cUnit->method_idx, cUnit->access_flags); - - bool fastPath = - cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit, - fieldOffset, ssbIndex, - isReferrersClass, isVolatile, - true); - if (fastPath && !SLOW_FIELD_PATH) { - DCHECK_GE(fieldOffset, 0); - int rBase; - if (isReferrersClass) { - // Fast path, static storage base is this method's class - RegLocation rlMethod = loadCurrMethod(cUnit); - rBase = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rlMethod.lowReg, - AbstractMethod::DeclaringClassOffset().Int32Value(), rBase); - if (oatIsTemp(cUnit, rlMethod.lowReg)) { - oatFreeTemp(cUnit, rlMethod.lowReg); - } - } else { - // Medium path, static storage base in a different class which - // requires checks that the other class is initialized. - DCHECK_GE(ssbIndex, 0); - // May do runtime call so everything to home locations. - oatFlushAllRegs(cUnit); - // Using fixed register to sync with possible call to runtime - // support. - int rMethod = targetReg(kArg1); - oatLockTemp(cUnit, rMethod); - loadCurrMethodDirect(cUnit, rMethod); - rBase = targetReg(kArg0); - oatLockTemp(cUnit, rBase); - loadWordDisp(cUnit, rMethod, - AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), - rBase); - loadWordDisp(cUnit, rBase, - Array::DataOffset(sizeof(Object*)).Int32Value() + - sizeof(int32_t*) * ssbIndex, rBase); - // rBase now points at appropriate static storage base (Class*) - // or NULL if not initialized. Check for NULL and call helper if NULL. - // TUNING: fast path should fall through - LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL); - loadConstant(cUnit, targetReg(kArg0), ssbIndex); - callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true); - if (cUnit->instructionSet == kMips) { - // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy - opRegCopy(cUnit, rBase, targetReg(kRet0)); - } - LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel); - branchOver->target = (LIR*)skipTarget; - oatFreeTemp(cUnit, rMethod); - } - // rBase now holds static storage base - if (isLongOrDouble) { - rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); - } else { - rlSrc = loadValue(cUnit, rlSrc, kAnyReg); - } -//FIXME: need to generalize the barrier call - if (isVolatile) { - oatGenMemBarrier(cUnit, kST); - } - if (isLongOrDouble) { - storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg, - rlSrc.highReg); - } else { - storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg); - } - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - if (isObject) { - markGCCard(cUnit, rlSrc.lowReg, rBase); - } - oatFreeTemp(cUnit, rBase); - } else { - oatFlushAllRegs(cUnit); // Everything to home locations - int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) : - (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic) - : ENTRYPOINT_OFFSET(pSet32Static)); - callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc, true); - } -} - -void genSget(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlDest, - bool isLongOrDouble, bool isObject) -{ - int fieldOffset; - int ssbIndex; - bool isVolatile; - bool isReferrersClass; - - OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, - *cUnit->dex_file, - cUnit->code_item, cUnit->method_idx, - cUnit->access_flags); - - bool fastPath = - cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit, - fieldOffset, ssbIndex, - isReferrersClass, isVolatile, - false); - if (fastPath && !SLOW_FIELD_PATH) { - DCHECK_GE(fieldOffset, 0); - int rBase; - if (isReferrersClass) { - // Fast path, static storage base is this method's class - RegLocation rlMethod = loadCurrMethod(cUnit); - rBase = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rlMethod.lowReg, - AbstractMethod::DeclaringClassOffset().Int32Value(), rBase); - } else { - // Medium path, static storage base in a different class which - // requires checks that the other class is initialized - DCHECK_GE(ssbIndex, 0); - // May do runtime call so everything to home locations. - oatFlushAllRegs(cUnit); - // Using fixed register to sync with possible call to runtime - // support - int rMethod = targetReg(kArg1); - oatLockTemp(cUnit, rMethod); - loadCurrMethodDirect(cUnit, rMethod); - rBase = targetReg(kArg0); - oatLockTemp(cUnit, rBase); - loadWordDisp(cUnit, rMethod, - AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), - rBase); - loadWordDisp(cUnit, rBase, - Array::DataOffset(sizeof(Object*)).Int32Value() + - sizeof(int32_t*) * ssbIndex, rBase); - // rBase now points at appropriate static storage base (Class*) - // or NULL if not initialized. Check for NULL and call helper if NULL. - // TUNING: fast path should fall through - LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL); - callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true); - if (cUnit->instructionSet == kMips) { - // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy - opRegCopy(cUnit, rBase, targetReg(kRet0)); - } - LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel); - branchOver->target = (LIR*)skipTarget; - oatFreeTemp(cUnit, rMethod); - } - // rBase now holds static storage base - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - if (isLongOrDouble) { - loadBaseDispWide(cUnit, rBase, fieldOffset, rlResult.lowReg, - rlResult.highReg, INVALID_SREG); - } else { - loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg); - } - oatFreeTemp(cUnit, rBase); - if (isLongOrDouble) { - storeValueWide(cUnit, rlDest, rlResult); - } else { - storeValue(cUnit, rlDest, rlResult); - } - } else { - oatFlushAllRegs(cUnit); // Everything to home locations - int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) : - (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic) - : ENTRYPOINT_OFFSET(pGet32Static)); - callRuntimeHelperImm(cUnit, getterOffset, fieldIdx, true); - if (isLongOrDouble) { - RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp); - storeValueWide(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp); - storeValue(cUnit, rlDest, rlResult); - } - } -} - - -// Debugging routine - if null target, branch to DebugMe -void genShowTarget(CompilationUnit* cUnit) -{ - DCHECK_NE(cUnit->instructionSet, kX86) << "unimplemented genShowTarget"; - LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, targetReg(kInvokeTgt), 0, NULL); - loadWordDisp(cUnit, targetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), targetReg(kInvokeTgt)); - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branchOver->target = (LIR*)target; -} - -void handleSuspendLaunchpads(CompilationUnit *cUnit) -{ - LIR** suspendLabel = (LIR **)cUnit->suspendLaunchpads.elemList; - int numElems = cUnit->suspendLaunchpads.numUsed; - int helperOffset = ENTRYPOINT_OFFSET(pTestSuspendFromCode); - for (int i = 0; i < numElems; i++) { - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - LIR* lab = suspendLabel[i]; - LIR* resumeLab = (LIR*)lab->operands[0]; - cUnit->currentDalvikOffset = lab->operands[1]; - oatAppendLIR(cUnit, lab); - int rTgt = callHelperSetup(cUnit, helperOffset); - callHelper(cUnit, rTgt, helperOffset, true /* markSafepointPC */); - opUnconditionalBranch(cUnit, resumeLab); - } -} - -void handleIntrinsicLaunchpads(CompilationUnit *cUnit) -{ - LIR** intrinsicLabel = (LIR **)cUnit->intrinsicLaunchpads.elemList; - int numElems = cUnit->intrinsicLaunchpads.numUsed; - for (int i = 0; i < numElems; i++) { - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - LIR* lab = intrinsicLabel[i]; - CallInfo* info = (CallInfo*)lab->operands[0]; - cUnit->currentDalvikOffset = info->offset; - oatAppendLIR(cUnit, lab); - // NOTE: genInvoke handles markSafepointPC - genInvoke(cUnit, info); - LIR* resumeLab = (LIR*)lab->operands[2]; - if (resumeLab != NULL) { - opUnconditionalBranch(cUnit, resumeLab); - } - } -} - -void handleThrowLaunchpads(CompilationUnit *cUnit) -{ - LIR** throwLabel = (LIR **)cUnit->throwLaunchpads.elemList; - int numElems = cUnit->throwLaunchpads.numUsed; - for (int i = 0; i < numElems; i++) { - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - LIR* lab = throwLabel[i]; - cUnit->currentDalvikOffset = lab->operands[1]; - oatAppendLIR(cUnit, lab); - int funcOffset = 0; - int v1 = lab->operands[2]; - int v2 = lab->operands[3]; - bool targetX86 = (cUnit->instructionSet == kX86); - switch (lab->operands[0]) { - case kThrowNullPointer: - funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode); - break; - case kThrowArrayBounds: - // Move v1 (array index) to kArg0 and v2 (array length) to kArg1 - if (v2 != targetReg(kArg0)) { - opRegCopy(cUnit, targetReg(kArg0), v1); - if (targetX86) { - // x86 leaves the array pointer in v2, so load the array length that the handler expects - opRegMem(cUnit, kOpMov, targetReg(kArg1), v2, Array::LengthOffset().Int32Value()); - } else { - opRegCopy(cUnit, targetReg(kArg1), v2); - } - } else { - if (v1 == targetReg(kArg1)) { - // Swap v1 and v2, using kArg2 as a temp - opRegCopy(cUnit, targetReg(kArg2), v1); - if (targetX86) { - // x86 leaves the array pointer in v2; load the array length that the handler expects - opRegMem(cUnit, kOpMov, targetReg(kArg1), v2, Array::LengthOffset().Int32Value()); - } else { - opRegCopy(cUnit, targetReg(kArg1), v2); - } - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); - } else { - if (targetX86) { - // x86 leaves the array pointer in v2; load the array length that the handler expects - opRegMem(cUnit, kOpMov, targetReg(kArg1), v2, Array::LengthOffset().Int32Value()); - } else { - opRegCopy(cUnit, targetReg(kArg1), v2); - } - opRegCopy(cUnit, targetReg(kArg0), v1); - } - } - funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode); - break; - case kThrowDivZero: - funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode); - break; - case kThrowNoSuchMethod: - opRegCopy(cUnit, targetReg(kArg0), v1); - funcOffset = - ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode); - break; - case kThrowStackOverflow: - funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode); - // Restore stack alignment - if (targetX86) { - opRegImm(cUnit, kOpAdd, targetReg(kSp), cUnit->frameSize); - } else { - opRegImm(cUnit, kOpAdd, targetReg(kSp), (cUnit->numCoreSpills + cUnit->numFPSpills) * 4); - } - break; - default: - LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0]; - } - oatClobberCalleeSave(cUnit); - int rTgt = callHelperSetup(cUnit, funcOffset); - callHelper(cUnit, rTgt, funcOffset, true /* markSafepointPC */); - } -} - -/* Needed by the Assembler */ -void oatSetupResourceMasks(CompilationUnit* cUnit, LIR* lir) -{ - setupResourceMasks(cUnit, lir); -} - -bool fastInstance(CompilationUnit* cUnit, uint32_t fieldIdx, - int& fieldOffset, bool& isVolatile, bool isPut) -{ - OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, - *cUnit->dex_file, - cUnit->code_item, cUnit->method_idx, - cUnit->access_flags); - return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit, - fieldOffset, isVolatile, isPut); -} - -void genIGet(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size, - RegLocation rlDest, RegLocation rlObj, - bool isLongOrDouble, bool isObject) -{ - int fieldOffset; - bool isVolatile; - - bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false); - - if (fastPath && !SLOW_FIELD_PATH) { - RegLocation rlResult; - RegisterClass regClass = oatRegClassBySize(size); - DCHECK_GE(fieldOffset, 0); - rlObj = loadValue(cUnit, rlObj, kCoreReg); - if (isLongOrDouble) { - DCHECK(rlDest.wide); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags); - if (cUnit->instructionSet == kX86) { - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags); - loadBaseDispWide(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg, - rlResult.highReg, rlObj.sRegLow); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - } else { - int regPtr = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset); - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - oatFreeTemp(cUnit, regPtr); - } - storeValueWide(cUnit, rlDest, rlResult); - } else { - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags); - loadBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg, - kWord, rlObj.sRegLow); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - storeValue(cUnit, rlDest, rlResult); - } - } else { - int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) : - (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance) - : ENTRYPOINT_OFFSET(pGet32Instance)); - callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj, true); - if (isLongOrDouble) { - RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp); - storeValueWide(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp); - storeValue(cUnit, rlDest, rlResult); - } - } -} - -void genIPut(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size, - RegLocation rlSrc, RegLocation rlObj, bool isLongOrDouble, bool isObject) -{ - int fieldOffset; - bool isVolatile; - - bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, - true); - if (fastPath && !SLOW_FIELD_PATH) { - RegisterClass regClass = oatRegClassBySize(size); - DCHECK_GE(fieldOffset, 0); - rlObj = loadValue(cUnit, rlObj, kCoreReg); - if (isLongOrDouble) { - int regPtr; - rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags); - regPtr = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset); - if (isVolatile) { - oatGenMemBarrier(cUnit, kST); - } - storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - oatFreeTemp(cUnit, regPtr); - } else { - rlSrc = loadValue(cUnit, rlSrc, regClass); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags); - if (isVolatile) { - oatGenMemBarrier(cUnit, kST); - } - storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - if (isObject) { - markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg); - } - } - } else { - int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) : - (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance) - : ENTRYPOINT_OFFSET(pSet32Instance)); - callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset, fieldIdx, rlObj, rlSrc, true); - } -} - -void genConstClass(CompilationUnit* cUnit, uint32_t type_idx, - RegLocation rlDest) -{ - RegLocation rlMethod = loadCurrMethod(cUnit); - int resReg = oatAllocTemp(cUnit); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - *cUnit->dex_file, - type_idx)) { - // Call out to helper which resolves type and verifies access. - // Resolved type returned in kRet0. - callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), - type_idx, rlMethod.lowReg, true); - RegLocation rlResult = oatGetReturn(cUnit, false); - storeValue(cUnit, rlDest, rlResult); - } else { - // We're don't need access checks, load type from dex cache - int32_t dex_cache_offset = - AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(); - loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg); - int32_t offset_of_type = - Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*) - * type_idx); - loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg); - if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(*cUnit->dex_file, - type_idx) || SLOW_TYPE_PATH) { - // Slow path, at runtime test if type is null and if so initialize - oatFlushAllRegs(cUnit); - LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL); - // Resolved, store and hop over following code - storeValue(cUnit, rlDest, rlResult); - /* - * Because we have stores of the target value on two paths, - * clobber temp tracking for the destination using the ssa name - */ - oatClobberSReg(cUnit, rlDest.sRegLow); - LIR* branch2 = opUnconditionalBranch(cUnit,0); - // TUNING: move slow path to end & remove unconditional branch - LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel); - // Call out to helper, which will return resolved type in kArg0 - callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, - rlMethod.lowReg, true); - RegLocation rlResult = oatGetReturn(cUnit, false); - storeValue(cUnit, rlDest, rlResult); - /* - * Because we have stores of the target value on two paths, - * clobber temp tracking for the destination using the ssa name - */ - oatClobberSReg(cUnit, rlDest.sRegLow); - // Rejoin code paths - LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel); - branch1->target = (LIR*)target1; - branch2->target = (LIR*)target2; - } else { - // Fast path, we're done - just store result - storeValue(cUnit, rlDest, rlResult); - } - } -} - -void genConstString(CompilationUnit* cUnit, uint32_t string_idx, - RegLocation rlDest) -{ - /* NOTE: Most strings should be available at compile time */ - int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() + - (sizeof(String*) * string_idx); - if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache( - *cUnit->dex_file, string_idx) || SLOW_STRING_PATH) { - // slow path, resolve string if not in dex cache - oatFlushAllRegs(cUnit); - oatLockCallTemps(cUnit); // Using explicit registers - loadCurrMethodDirect(cUnit, targetReg(kArg2)); - loadWordDisp(cUnit, targetReg(kArg2), - AbstractMethod::DexCacheStringsOffset().Int32Value(), targetReg(kArg0)); - // Might call out to helper, which will return resolved string in kRet0 - int rTgt = callHelperSetup(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode)); - loadWordDisp(cUnit, targetReg(kArg0), offset_of_string, targetReg(kRet0)); - loadConstant(cUnit, targetReg(kArg1), string_idx); - if (cUnit->instructionSet == kThumb2) { - opRegImm(cUnit, kOpCmp, targetReg(kRet0), 0); // Is resolved? - genBarrier(cUnit); - // For testing, always force through helper - if (!EXERCISE_SLOWEST_STRING_PATH) { - opIT(cUnit, kArmCondEq, "T"); - } - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); // .eq - LIR* callInst = opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx) - markSafepointPC(cUnit, callInst); - oatFreeTemp(cUnit, rTgt); - } else if (cUnit->instructionSet == kMips) { - LIR* branch = opCmpImmBranch(cUnit, kCondNe, targetReg(kRet0), 0, NULL); - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); // .eq - LIR* callInst = opReg(cUnit, kOpBlx, rTgt); - markSafepointPC(cUnit, callInst); - oatFreeTemp(cUnit, rTgt); - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branch->target = target; - } else { - DCHECK_EQ(cUnit->instructionSet, kX86); - callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode), targetReg(kArg2), targetReg(kArg1), true); - } - genBarrier(cUnit); - storeValue(cUnit, rlDest, oatGetReturn(cUnit, false)); - } else { - RegLocation rlMethod = loadCurrMethod(cUnit); - int resReg = oatAllocTemp(cUnit); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - loadWordDisp(cUnit, rlMethod.lowReg, - AbstractMethod::DexCacheStringsOffset().Int32Value(), resReg); - loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg); - storeValue(cUnit, rlDest, rlResult); - } -} - -/* - * Let helper function take care of everything. Will - * call Class::NewInstanceFromCode(type_idx, method); - */ -void genNewInstance(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest) -{ - oatFlushAllRegs(cUnit); /* Everything to home location */ - // alloc will always check for resolution, do we also need to verify - // access because the verifier was unable to? - int funcOffset; - if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks( - cUnit->method_idx, *cUnit->dex_file, type_idx)) { - funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode); - } else { - funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck); - } - callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx, true); - RegLocation rlResult = oatGetReturn(cUnit, false); - storeValue(cUnit, rlDest, rlResult); -} - -void genMoveException(CompilationUnit* cUnit, RegLocation rlDest) -{ - oatFlushAllRegs(cUnit); /* Everything to home location */ - int funcOffset = ENTRYPOINT_OFFSET(pGetAndClearException); - if (cUnit->instructionSet == kX86) { - // Runtime helper will load argument for x86. - callRuntimeHelperReg(cUnit, funcOffset, targetReg(kArg0), false); - } else { - callRuntimeHelperReg(cUnit, funcOffset, targetReg(kSelf), false); - } - RegLocation rlResult = oatGetReturn(cUnit, false); - storeValue(cUnit, rlDest, rlResult); -} - -void genThrow(CompilationUnit* cUnit, RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException), rlSrc, true); -} - -void genInstanceof(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest, - RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - // May generate a call - use explicit registers - oatLockCallTemps(cUnit); - loadCurrMethodDirect(cUnit, targetReg(kArg1)); // kArg1 <= current Method* - int classReg = targetReg(kArg2); // kArg2 will hold the Class* - if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - *cUnit->dex_file, - type_idx)) { - // Check we have access to type_idx and if not throw IllegalAccessError, - // returns Class* in kArg0 - callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), - type_idx, true); - opRegCopy(cUnit, classReg, targetReg(kRet0)); // Align usage with fast path - loadValueDirectFixed(cUnit, rlSrc, targetReg(kArg0)); // kArg0 <= ref - } else { - // Load dex cache entry into classReg (kArg2) - loadValueDirectFixed(cUnit, rlSrc, targetReg(kArg0)); // kArg0 <= ref - loadWordDisp(cUnit, targetReg(kArg1), - AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg); - int32_t offset_of_type = - Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*) - * type_idx); - loadWordDisp(cUnit, classReg, offset_of_type, classReg); - if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache( - *cUnit->dex_file, type_idx)) { - // Need to test presence of type in dex cache at runtime - LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL); - // Not resolved - // Call out to helper, which will return resolved type in kRet0 - callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true); - opRegCopy(cUnit, targetReg(kArg2), targetReg(kRet0)); // Align usage with fast path - loadValueDirectFixed(cUnit, rlSrc, targetReg(kArg0)); /* reload Ref */ - // Rejoin code paths - LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel); - hopBranch->target = (LIR*)hopTarget; - } - } - /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */ - RegLocation rlResult = oatGetReturn(cUnit, false); - if (cUnit->instructionSet == kMips) { - loadConstant(cUnit, rlResult.lowReg, 0); // store false result for if branch is taken - } - LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, targetReg(kArg0), 0, NULL); - /* load object->klass_ */ - DCHECK_EQ(Object::ClassOffset().Int32Value(), 0); - loadWordDisp(cUnit, targetReg(kArg0), Object::ClassOffset().Int32Value(), targetReg(kArg1)); - /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */ - LIR* callInst; - LIR* branchover = NULL; - if (cUnit->instructionSet == kThumb2) { - /* Uses conditional nullification */ - int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); - opRegReg(cUnit, kOpCmp, targetReg(kArg1), targetReg(kArg2)); // Same? - opIT(cUnit, kArmCondEq, "EE"); // if-convert the test - loadConstant(cUnit, targetReg(kArg0), 1); // .eq case - load true - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); // .ne case - arg0 <= class - callInst = opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class) - oatFreeTemp(cUnit, rTgt); - } else { - /* Uses branchovers */ - loadConstant(cUnit, rlResult.lowReg, 1); // assume true - branchover = opCmpBranch(cUnit, kCondEq, targetReg(kArg1), targetReg(kArg2), NULL); - if (cUnit->instructionSet != kX86) { - int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); // .ne case - arg0 <= class - callInst = opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class) - oatFreeTemp(cUnit, rTgt); - } else { - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg2)); - callInst = opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); - } - } - markSafepointPC(cUnit, callInst); - oatClobberCalleeSave(cUnit); - /* branch targets here */ - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - storeValue(cUnit, rlDest, rlResult); - branch1->target = target; - if (cUnit->instructionSet != kThumb2) { - branchover->target = target; - } -} - -void genCheckCast(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); - // May generate a call - use explicit registers - oatLockCallTemps(cUnit); - loadCurrMethodDirect(cUnit, targetReg(kArg1)); // kArg1 <= current Method* - int classReg = targetReg(kArg2); // kArg2 will hold the Class* - if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - *cUnit->dex_file, - type_idx)) { - // Check we have access to type_idx and if not throw IllegalAccessError, - // returns Class* in kRet0 - // InitializeTypeAndVerifyAccess(idx, method) - callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), - type_idx, targetReg(kArg1), true); - opRegCopy(cUnit, classReg, targetReg(kRet0)); // Align usage with fast path - } else { - // Load dex cache entry into classReg (kArg2) - loadWordDisp(cUnit, targetReg(kArg1), - AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg); - int32_t offset_of_type = - Array::DataOffset(sizeof(Class*)).Int32Value() + - (sizeof(Class*) * type_idx); - loadWordDisp(cUnit, classReg, offset_of_type, classReg); - if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache( - *cUnit->dex_file, type_idx)) { - // Need to test presence of type in dex cache at runtime - LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL); - // Not resolved - // Call out to helper, which will return resolved type in kArg0 - // InitializeTypeFromCode(idx, method) - callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, targetReg(kArg1), - true); - opRegCopy(cUnit, classReg, targetReg(kRet0)); // Align usage with fast path - // Rejoin code paths - LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel); - hopBranch->target = (LIR*)hopTarget; - } - } - // At this point, classReg (kArg2) has class - loadValueDirectFixed(cUnit, rlSrc, targetReg(kArg0)); // kArg0 <= ref - /* Null is OK - continue */ - LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, targetReg(kArg0), 0, NULL); - /* load object->klass_ */ - DCHECK_EQ(Object::ClassOffset().Int32Value(), 0); - loadWordDisp(cUnit, targetReg(kArg0), Object::ClassOffset().Int32Value(), targetReg(kArg1)); - /* kArg1 now contains object->klass_ */ - LIR* branch2; - if (cUnit->instructionSet == kThumb2) { - int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode)); - opRegReg(cUnit, kOpCmp, targetReg(kArg1), classReg); - branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */ - opRegCopy(cUnit, targetReg(kArg0), targetReg(kArg1)); - opRegCopy(cUnit, targetReg(kArg1), targetReg(kArg2)); - oatClobberCalleeSave(cUnit); - LIR* callInst = opReg(cUnit, kOpBlx, rTgt); - markSafepointPC(cUnit, callInst); - oatFreeTemp(cUnit, rTgt); - } else { - branch2 = opCmpBranch(cUnit, kCondEq, targetReg(kArg1), classReg, NULL); - callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode), targetReg(kArg1), targetReg(kArg2), true); - } - /* branch target here */ - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - branch1->target = target; - branch2->target = target; -} - -/* - * Generate array store - * - */ -void genArrayObjPut(CompilationUnit* cUnit, int optFlags, RegLocation rlArray, - RegLocation rlIndex, RegLocation rlSrc, int scale) -{ - int lenOffset = Array::LengthOffset().Int32Value(); - int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value(); - - oatFlushAllRegs(cUnit); // Use explicit registers - oatLockCallTemps(cUnit); - - int rValue = targetReg(kArg0); // Register holding value - int rArrayClass = targetReg(kArg1); // Register holding array's Class - int rArray = targetReg(kArg2); // Register holding array - int rIndex = targetReg(kArg3); // Register holding index into array - - loadValueDirectFixed(cUnit, rlArray, rArray); // Grab array - loadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value - loadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index - - genNullCheck(cUnit, rlArray.sRegLow, rArray, optFlags); // NPE? - - // Store of null? - LIR* null_value_check = opCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL); - - // Get the array's class. - loadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass); - callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), rValue, - rArrayClass, true); - // Redo loadValues in case they didn't survive the call. - loadValueDirectFixed(cUnit, rlArray, rArray); // Reload array - loadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index - loadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value - rArrayClass = INVALID_REG; - - // Branch here if value to be stored == null - LIR* target = newLIR0(cUnit, kPseudoTargetLabel); - null_value_check->target = target; - - if (cUnit->instructionSet == kX86) { - // make an extra temp available for card mark below - oatFreeTemp(cUnit, targetReg(kArg1)); - if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */ - genRegMemCheck(cUnit, kCondUge, rIndex, rArray, lenOffset, kThrowArrayBounds); - } - storeBaseIndexedDisp(cUnit, rArray, rIndex, scale, - dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG); - } else { - bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK)); - int regLen = INVALID_REG; - if (needsRangeCheck) { - regLen = targetReg(kArg1); - loadWordDisp(cUnit, rArray, lenOffset, regLen); // Get len - } - /* rPtr -> array data */ - int rPtr = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset); - if (needsRangeCheck) { - genRegRegCheck(cUnit, kCondCs, rIndex, regLen, kThrowArrayBounds); - } - storeBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord); - oatFreeTemp(cUnit, rPtr); - } - oatFreeTemp(cUnit, rIndex); - markGCCard(cUnit, rValue, rArray); -} - -/* - * Generate array load - */ -void genArrayGet(CompilationUnit* cUnit, int optFlags, OpSize size, - RegLocation rlArray, RegLocation rlIndex, - RegLocation rlDest, int scale) -{ - RegisterClass regClass = oatRegClassBySize(size); - int lenOffset = Array::LengthOffset().Int32Value(); - int dataOffset; - RegLocation rlResult; - rlArray = loadValue(cUnit, rlArray, kCoreReg); - rlIndex = loadValue(cUnit, rlIndex, kCoreReg); - - if (size == kLong || size == kDouble) { - dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value(); - } else { - dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value(); - } - - /* null object? */ - genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags); - - if (cUnit->instructionSet == kX86) { - if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */ - genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg, - lenOffset, kThrowArrayBounds); - } - if ((size == kLong) || (size == kDouble)) { - int regAddr = oatAllocTemp(cUnit); - opLea(cUnit, regAddr, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset); - oatFreeTemp(cUnit, rlArray.lowReg); - oatFreeTemp(cUnit, rlIndex.lowReg); - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - loadBaseIndexedDisp(cUnit, regAddr, INVALID_REG, 0, 0, rlResult.lowReg, - rlResult.highReg, size, INVALID_SREG); - storeValueWide(cUnit, rlDest, rlResult); - } else { - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - - loadBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale, - dataOffset, rlResult.lowReg, INVALID_REG, size, - INVALID_SREG); - - storeValue(cUnit, rlDest, rlResult); - } - } else { - int regPtr = oatAllocTemp(cUnit); - bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK)); - int regLen = INVALID_REG; - if (needsRangeCheck) { - regLen = oatAllocTemp(cUnit); - /* Get len */ - loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); - } - /* regPtr -> array data */ - opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); - oatFreeTemp(cUnit, rlArray.lowReg); - if ((size == kLong) || (size == kDouble)) { - if (scale) { - int rNewIndex = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); - opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); - oatFreeTemp(cUnit, rNewIndex); - } else { - opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); - } - oatFreeTemp(cUnit, rlIndex.lowReg); - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - - if (needsRangeCheck) { - // TODO: change kCondCS to a more meaningful name, is the sense of - // carry-set/clear flipped? - genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds); - oatFreeTemp(cUnit, regLen); - } - loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); - - oatFreeTemp(cUnit, regPtr); - storeValueWide(cUnit, rlDest, rlResult); - } else { - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - - if (needsRangeCheck) { - // TODO: change kCondCS to a more meaningful name, is the sense of - // carry-set/clear flipped? - genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds); - oatFreeTemp(cUnit, regLen); - } - loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg, scale, size); - - oatFreeTemp(cUnit, regPtr); - storeValue(cUnit, rlDest, rlResult); - } - } -} - -/* - * Generate array store - * - */ -void genArrayPut(CompilationUnit* cUnit, int optFlags, OpSize size, - RegLocation rlArray, RegLocation rlIndex, - RegLocation rlSrc, int scale) -{ - RegisterClass regClass = oatRegClassBySize(size); - int lenOffset = Array::LengthOffset().Int32Value(); - int dataOffset; - - if (size == kLong || size == kDouble) { - dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value(); - } else { - dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value(); - } - - rlArray = loadValue(cUnit, rlArray, kCoreReg); - rlIndex = loadValue(cUnit, rlIndex, kCoreReg); - int regPtr = INVALID_REG; - if (cUnit->instructionSet != kX86) { - if (oatIsTemp(cUnit, rlArray.lowReg)) { - oatClobber(cUnit, rlArray.lowReg); - regPtr = rlArray.lowReg; - } else { - regPtr = oatAllocTemp(cUnit); - opRegCopy(cUnit, regPtr, rlArray.lowReg); - } - } - - /* null object? */ - genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags); - - if (cUnit->instructionSet == kX86) { - if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */ - genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg, lenOffset, kThrowArrayBounds); - } - if ((size == kLong) || (size == kDouble)) { - rlSrc = loadValueWide(cUnit, rlSrc, regClass); - } else { - rlSrc = loadValue(cUnit, rlSrc, regClass); - } - // If the src reg can't be byte accessed, move it to a temp first. - if ((size == kSignedByte || size == kUnsignedByte) && rlSrc.lowReg >= 4) { - int temp = oatAllocTemp(cUnit); - opRegCopy(cUnit, temp, rlSrc.lowReg); - storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset, temp, - INVALID_REG, size, INVALID_SREG); - } else { - storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset, rlSrc.lowReg, - rlSrc.highReg, size, INVALID_SREG); - } - } else { - bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK)); - int regLen = INVALID_REG; - if (needsRangeCheck) { - regLen = oatAllocTemp(cUnit); - //NOTE: max live temps(4) here. - /* Get len */ - loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); - } - /* regPtr -> array data */ - opRegImm(cUnit, kOpAdd, regPtr, dataOffset); - /* at this point, regPtr points to array, 2 live temps */ - if ((size == kLong) || (size == kDouble)) { - //TUNING: specific wide routine that can handle fp regs - if (scale) { - int rNewIndex = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); - opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); - oatFreeTemp(cUnit, rNewIndex); - } else { - opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); - } - rlSrc = loadValueWide(cUnit, rlSrc, regClass); - - if (needsRangeCheck) { - genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds); - oatFreeTemp(cUnit, regLen); - } - - storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg); - - oatFreeTemp(cUnit, regPtr); - } else { - rlSrc = loadValue(cUnit, rlSrc, regClass); - if (needsRangeCheck) { - genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds); - oatFreeTemp(cUnit, regLen); - } - storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg, - scale, size); - } - } -} - -void genLong3Addr(CompilationUnit* cUnit, OpKind firstOp, - OpKind secondOp, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - RegLocation rlResult; - if (cUnit->instructionSet == kThumb2) { - /* - * NOTE: This is the one place in the code in which we might have - * as many as six live temporary registers. There are 5 in the normal - * set for Arm. Until we have spill capabilities, temporarily add - * lr to the temp set. It is safe to do this locally, but note that - * lr is used explicitly elsewhere in the code generator and cannot - * normally be used as a general temp register. - */ - oatMarkTemp(cUnit, targetReg(kLr)); // Add lr to the temp pool - oatFreeTemp(cUnit, targetReg(kLr)); // and make it available - } - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - // The longs may overlap - use intermediate temp if so - if ((rlResult.lowReg == rlSrc1.highReg) || (rlResult.lowReg == rlSrc2.highReg)){ - int tReg = oatAllocTemp(cUnit); - opRegRegReg(cUnit, firstOp, tReg, rlSrc1.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg); - opRegCopy(cUnit, rlResult.lowReg, tReg); - oatFreeTemp(cUnit, tReg); - } else { - opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, - rlSrc2.highReg); - } - /* - * NOTE: If rlDest refers to a frame variable in a large frame, the - * following storeValueWide might need to allocate a temp register. - * To further work around the lack of a spill capability, explicitly - * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult. - * Remove when spill is functional. - */ - freeRegLocTemps(cUnit, rlResult, rlSrc1); - freeRegLocTemps(cUnit, rlResult, rlSrc2); - storeValueWide(cUnit, rlDest, rlResult); - if (cUnit->instructionSet == kThumb2) { - oatClobber(cUnit, targetReg(kLr)); - oatUnmarkTemp(cUnit, targetReg(kLr)); // Remove lr from the temp pool - } -} - - -bool genShiftOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlShift) -{ - int funcOffset; - - switch (opcode) { - case Instruction::SHL_LONG: - case Instruction::SHL_LONG_2ADDR: - funcOffset = ENTRYPOINT_OFFSET(pShlLong); - break; - case Instruction::SHR_LONG: - case Instruction::SHR_LONG_2ADDR: - funcOffset = ENTRYPOINT_OFFSET(pShrLong); - break; - case Instruction::USHR_LONG: - case Instruction::USHR_LONG_2ADDR: - funcOffset = ENTRYPOINT_OFFSET(pUshrLong); - break; - default: - LOG(FATAL) << "Unexpected case"; - return true; - } - oatFlushAllRegs(cUnit); /* Send everything to home location */ - callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift, false); - RegLocation rlResult = oatGetReturnWide(cUnit, false); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - - -bool genArithOpInt(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - OpKind op = kOpBkpt; - bool isDivRem = false; - bool checkZero = false; - bool unary = false; - RegLocation rlResult; - bool shiftOp = false; - switch (opcode) { - case Instruction::NEG_INT: - op = kOpNeg; - unary = true; - break; - case Instruction::NOT_INT: - op = kOpMvn; - unary = true; - break; - case Instruction::ADD_INT: - case Instruction::ADD_INT_2ADDR: - op = kOpAdd; - break; - case Instruction::SUB_INT: - case Instruction::SUB_INT_2ADDR: - op = kOpSub; - break; - case Instruction::MUL_INT: - case Instruction::MUL_INT_2ADDR: - op = kOpMul; - break; - case Instruction::DIV_INT: - case Instruction::DIV_INT_2ADDR: - checkZero = true; - op = kOpDiv; - isDivRem = true; - break; - /* NOTE: returns in kArg1 */ - case Instruction::REM_INT: - case Instruction::REM_INT_2ADDR: - checkZero = true; - op = kOpRem; - isDivRem = true; - break; - case Instruction::AND_INT: - case Instruction::AND_INT_2ADDR: - op = kOpAnd; - break; - case Instruction::OR_INT: - case Instruction::OR_INT_2ADDR: - op = kOpOr; - break; - case Instruction::XOR_INT: - case Instruction::XOR_INT_2ADDR: - op = kOpXor; - break; - case Instruction::SHL_INT: - case Instruction::SHL_INT_2ADDR: - shiftOp = true; - op = kOpLsl; - break; - case Instruction::SHR_INT: - case Instruction::SHR_INT_2ADDR: - shiftOp = true; - op = kOpAsr; - break; - case Instruction::USHR_INT: - case Instruction::USHR_INT_2ADDR: - shiftOp = true; - op = kOpLsr; - break; - default: - LOG(FATAL) << "Invalid word arith op: " << - (int)opcode; - } - if (!isDivRem) { - if (unary) { - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg); - } else { - if (shiftOp) { - int tReg = INVALID_REG; - if (cUnit->instructionSet == kX86) { - // X86 doesn't require masking and must use ECX - tReg = targetReg(kCount); // rCX - loadValueDirectFixed(cUnit, rlSrc2, tReg); - } else { - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - tReg = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31); - } - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg); - oatFreeTemp(cUnit, tReg); - } else { - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); - } - } - storeValue(cUnit, rlDest, rlResult); - } else { - if (cUnit->instructionSet == kMips) { - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - if (checkZero) { - genImmedCheck(cUnit, kCondEq, rlSrc2.lowReg, 0, kThrowDivZero); - } - rlResult = genDivRem(cUnit, rlDest, rlSrc1.lowReg, rlSrc2.lowReg, op == kOpDiv); - } else { - int funcOffset = ENTRYPOINT_OFFSET(pIdivmod); - oatFlushAllRegs(cUnit); /* Send everything to home location */ - loadValueDirectFixed(cUnit, rlSrc2, targetReg(kArg1)); - int rTgt = callHelperSetup(cUnit, funcOffset); - loadValueDirectFixed(cUnit, rlSrc1, targetReg(kArg0)); - if (checkZero) { - genImmedCheck(cUnit, kCondEq, targetReg(kArg1), 0, kThrowDivZero); - } - // NOTE: callout here is not a safepoint - callHelper(cUnit, rTgt, funcOffset, false /* not a safepoint */ ); - if (op == kOpDiv) - rlResult = oatGetReturn(cUnit, false); - else - rlResult = oatGetReturnAlt(cUnit); - } - storeValue(cUnit, rlDest, rlResult); - } - return false; -} - -/* - * The following are the first-level codegen routines that analyze the format - * of each bytecode then either dispatch special purpose codegen routines - * or produce corresponding Thumb instructions directly. - */ - -bool isPowerOfTwo(int x) -{ - return (x & (x - 1)) == 0; -} - -// Returns true if no more than two bits are set in 'x'. -bool isPopCountLE2(unsigned int x) -{ - x &= x - 1; - return (x & (x - 1)) == 0; -} - -// Returns the index of the lowest set bit in 'x'. -int lowestSetBit(unsigned int x) { - int bit_posn = 0; - while ((x & 0xf) == 0) { - bit_posn += 4; - x >>= 4; - } - while ((x & 1) == 0) { - bit_posn++; - x >>= 1; - } - return bit_posn; -} - -// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit' -// and store the result in 'rlDest'. -bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode, - RegLocation rlSrc, RegLocation rlDest, int lit) -{ - if ((lit < 2) || ((cUnit->instructionSet != kThumb2) && !isPowerOfTwo(lit))) { - return false; - } - // No divide instruction for Arm, so check for more special cases - if ((cUnit->instructionSet == kThumb2) && !isPowerOfTwo(lit)) { - return smallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit); - } - int k = lowestSetBit(lit); - if (k >= 30) { - // Avoid special cases. - return false; - } - bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 || - dalvikOpcode == Instruction::DIV_INT_LIT16); - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (div) { - int tReg = oatAllocTemp(cUnit); - if (lit == 2) { - // Division by 2 is by far the most common division by constant. - opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k); - opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); - opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); - } else { - opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31); - opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k); - opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); - opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); - } - } else { - int tReg1 = oatAllocTemp(cUnit); - int tReg2 = oatAllocTemp(cUnit); - if (lit == 2) { - opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k); - opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); - opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); - } else { - opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31); - opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k); - opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); - opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); - } - } - storeValue(cUnit, rlDest, rlResult); - return true; -} - -// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit' -// and store the result in 'rlDest'. -bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc, - RegLocation rlDest, int lit) -{ - // Can we simplify this multiplication? - bool powerOfTwo = false; - bool popCountLE2 = false; - bool powerOfTwoMinusOne = false; - if (lit < 2) { - // Avoid special cases. - return false; - } else if (isPowerOfTwo(lit)) { - powerOfTwo = true; - } else if (isPopCountLE2(lit)) { - popCountLE2 = true; - } else if (isPowerOfTwo(lit + 1)) { - powerOfTwoMinusOne = true; - } else { - return false; - } - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (powerOfTwo) { - // Shift. - opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg, - lowestSetBit(lit)); - } else if (popCountLE2) { - // Shift and add and shift. - int firstBit = lowestSetBit(lit); - int secondBit = lowestSetBit(lit ^ (1 << firstBit)); - genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit, - firstBit, secondBit); - } else { - // Reverse subtract: (src << (shift + 1)) - src. - DCHECK(powerOfTwoMinusOne); - // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1) - int tReg = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1)); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); - } - storeValue(cUnit, rlDest, rlResult); - return true; -} - -bool genArithOpIntLit(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlDest, RegLocation rlSrc, int lit) -{ - RegLocation rlResult; - OpKind op = (OpKind)0; /* Make gcc happy */ - int shiftOp = false; - bool isDiv = false; - - switch (opcode) { - case Instruction::RSUB_INT_LIT8: - case Instruction::RSUB_INT: { - int tReg; - //TUNING: add support for use of Arm rsub op - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, lit); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); - storeValue(cUnit, rlDest, rlResult); - return false; - break; - } - - case Instruction::ADD_INT_LIT8: - case Instruction::ADD_INT_LIT16: - op = kOpAdd; - break; - case Instruction::MUL_INT_LIT8: - case Instruction::MUL_INT_LIT16: { - if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) { - return false; - } - op = kOpMul; - break; - } - case Instruction::AND_INT_LIT8: - case Instruction::AND_INT_LIT16: - op = kOpAnd; - break; - case Instruction::OR_INT_LIT8: - case Instruction::OR_INT_LIT16: - op = kOpOr; - break; - case Instruction::XOR_INT_LIT8: - case Instruction::XOR_INT_LIT16: - op = kOpXor; - break; - case Instruction::SHL_INT_LIT8: - case Instruction::SHL_INT: - lit &= 31; - shiftOp = true; - op = kOpLsl; - break; - case Instruction::SHR_INT_LIT8: - case Instruction::SHR_INT: - lit &= 31; - shiftOp = true; - op = kOpAsr; - break; - case Instruction::USHR_INT_LIT8: - case Instruction::USHR_INT: - lit &= 31; - shiftOp = true; - op = kOpLsr; - break; - - case Instruction::DIV_INT_LIT8: - case Instruction::DIV_INT_LIT16: - case Instruction::REM_INT_LIT8: - case Instruction::REM_INT_LIT16: { - if (lit == 0) { - genImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero); - return false; - } - if (handleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) { - return false; - } - if ((opcode == Instruction::DIV_INT_LIT8) || - (opcode == Instruction::DIV_INT_LIT16)) { - isDiv = true; - } else { - isDiv = false; - } - if (cUnit->instructionSet == kMips) { - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - rlResult = genDivRemLit(cUnit, rlDest, rlSrc.lowReg, lit, isDiv); - } else { - oatFlushAllRegs(cUnit); /* Everything to home location */ - loadValueDirectFixed(cUnit, rlSrc, targetReg(kArg0)); - oatClobber(cUnit, targetReg(kArg0)); - int funcOffset = ENTRYPOINT_OFFSET(pIdivmod); - callRuntimeHelperRegImm(cUnit, funcOffset, targetReg(kArg0), lit, false); - if (isDiv) - rlResult = oatGetReturn(cUnit, false); - else - rlResult = oatGetReturnAlt(cUnit); - } - storeValue(cUnit, rlDest, rlResult); - return false; - break; - } - default: - return true; - } - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - // Avoid shifts by literal 0 - no support in Thumb. Change to copy - if (shiftOp && (lit == 0)) { - opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - } else { - opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit); - } - storeValue(cUnit, rlDest, rlResult); - return false; -} - -bool genArithOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - RegLocation rlResult; - OpKind firstOp = kOpBkpt; - OpKind secondOp = kOpBkpt; - bool callOut = false; - bool checkZero = false; - int funcOffset; - int retReg = targetReg(kRet0); - - switch (opcode) { - case Instruction::NOT_LONG: - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - // Check for destructive overlap - if (rlResult.lowReg == rlSrc2.highReg) { - int tReg = oatAllocTemp(cUnit); - opRegCopy(cUnit, tReg, rlSrc2.highReg); - opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg); - opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg); - oatFreeTemp(cUnit, tReg); - } else { - opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg); - opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg); - } - storeValueWide(cUnit, rlDest, rlResult); - return false; - break; - case Instruction::ADD_LONG: - case Instruction::ADD_LONG_2ADDR: - if (cUnit->instructionSet != kThumb2) { - return genAddLong(cUnit, rlDest, rlSrc1, rlSrc2); - } - firstOp = kOpAdd; - secondOp = kOpAdc; - break; - case Instruction::SUB_LONG: - case Instruction::SUB_LONG_2ADDR: - if (cUnit->instructionSet != kThumb2) { - return genSubLong(cUnit, rlDest, rlSrc1, rlSrc2); - } - firstOp = kOpSub; - secondOp = kOpSbc; - break; - case Instruction::MUL_LONG: - case Instruction::MUL_LONG_2ADDR: - callOut = true; - retReg = targetReg(kRet0); - funcOffset = ENTRYPOINT_OFFSET(pLmul); - break; - case Instruction::DIV_LONG: - case Instruction::DIV_LONG_2ADDR: - callOut = true; - checkZero = true; - retReg = targetReg(kRet0); - funcOffset = ENTRYPOINT_OFFSET(pLdiv); - break; - case Instruction::REM_LONG: - case Instruction::REM_LONG_2ADDR: - callOut = true; - checkZero = true; - funcOffset = ENTRYPOINT_OFFSET(pLdivmod); - /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */ - retReg = (cUnit->instructionSet == kThumb2) ? targetReg(kArg2) : targetReg(kRet0); - break; - case Instruction::AND_LONG_2ADDR: - case Instruction::AND_LONG: - if (cUnit->instructionSet == kX86) { - return genAndLong(cUnit, rlDest, rlSrc1, rlSrc2); - } - firstOp = kOpAnd; - secondOp = kOpAnd; - break; - case Instruction::OR_LONG: - case Instruction::OR_LONG_2ADDR: - if (cUnit->instructionSet == kX86) { - return genOrLong(cUnit, rlDest, rlSrc1, rlSrc2); - } - firstOp = kOpOr; - secondOp = kOpOr; - break; - case Instruction::XOR_LONG: - case Instruction::XOR_LONG_2ADDR: - if (cUnit->instructionSet == kX86) { - return genXorLong(cUnit, rlDest, rlSrc1, rlSrc2); - } - firstOp = kOpXor; - secondOp = kOpXor; - break; - case Instruction::NEG_LONG: { - return genNegLong(cUnit, rlDest, rlSrc2); - } - default: - LOG(FATAL) << "Invalid long arith op"; - } - if (!callOut) { - genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2); - } else { - oatFlushAllRegs(cUnit); /* Send everything to home location */ - if (checkZero) { - loadValueDirectWideFixed(cUnit, rlSrc2, targetReg(kArg2), targetReg(kArg3)); - int rTgt = callHelperSetup(cUnit, funcOffset); - genDivZeroCheck(cUnit, targetReg(kArg2), targetReg(kArg3)); - loadValueDirectWideFixed(cUnit, rlSrc1, targetReg(kArg0), targetReg(kArg1)); - // NOTE: callout here is not a safepoint - callHelper(cUnit, rTgt, funcOffset, false /* not safepoint */); - } else { - callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, - rlSrc1, rlSrc2, false); - } - // Adjust return regs in to handle case of rem returning kArg2/kArg3 - if (retReg == targetReg(kRet0)) - rlResult = oatGetReturnWide(cUnit, false); - else - rlResult = oatGetReturnWideAlt(cUnit); - storeValueWide(cUnit, rlDest, rlResult); - } - return false; -} - -bool genConversionCall(CompilationUnit* cUnit, int funcOffset, - RegLocation rlDest, RegLocation rlSrc) -{ - /* - * Don't optimize the register usage since it calls out to support - * functions - */ - oatFlushAllRegs(cUnit); /* Send everything to home location */ - if (rlSrc.wide) { - loadValueDirectWideFixed(cUnit, rlSrc, rlSrc.fp ? targetReg(kFArg0) : targetReg(kArg0), - rlSrc.fp ? targetReg(kFArg1) : targetReg(kArg1)); - } else { - loadValueDirectFixed(cUnit, rlSrc, rlSrc.fp ? targetReg(kFArg0) : targetReg(kArg0)); - } - callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc, false); - if (rlDest.wide) { - RegLocation rlResult; - rlResult = oatGetReturnWide(cUnit, rlDest.fp); - storeValueWide(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult; - rlResult = oatGetReturn(cUnit, rlDest.fp); - storeValue(cUnit, rlDest, rlResult); - } - return false; -} - -void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc); -bool genArithOpFloatPortable(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - RegLocation rlResult; - int funcOffset; - - switch (opcode) { - case Instruction::ADD_FLOAT_2ADDR: - case Instruction::ADD_FLOAT: - funcOffset = ENTRYPOINT_OFFSET(pFadd); - break; - case Instruction::SUB_FLOAT_2ADDR: - case Instruction::SUB_FLOAT: - funcOffset = ENTRYPOINT_OFFSET(pFsub); - break; - case Instruction::DIV_FLOAT_2ADDR: - case Instruction::DIV_FLOAT: - funcOffset = ENTRYPOINT_OFFSET(pFdiv); - break; - case Instruction::MUL_FLOAT_2ADDR: - case Instruction::MUL_FLOAT: - funcOffset = ENTRYPOINT_OFFSET(pFmul); - break; - case Instruction::REM_FLOAT_2ADDR: - case Instruction::REM_FLOAT: - funcOffset = ENTRYPOINT_OFFSET(pFmodf); - break; - case Instruction::NEG_FLOAT: { - genNegFloat(cUnit, rlDest, rlSrc1); - return false; - } - default: - return true; - } - oatFlushAllRegs(cUnit); /* Send everything to home location */ - callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false); - rlResult = oatGetReturn(cUnit, true); - storeValue(cUnit, rlDest, rlResult); - return false; -} - -void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc); -bool genArithOpDoublePortable(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - RegLocation rlResult; - int funcOffset; - - switch (opcode) { - case Instruction::ADD_DOUBLE_2ADDR: - case Instruction::ADD_DOUBLE: - funcOffset = ENTRYPOINT_OFFSET(pDadd); - break; - case Instruction::SUB_DOUBLE_2ADDR: - case Instruction::SUB_DOUBLE: - funcOffset = ENTRYPOINT_OFFSET(pDsub); - break; - case Instruction::DIV_DOUBLE_2ADDR: - case Instruction::DIV_DOUBLE: - funcOffset = ENTRYPOINT_OFFSET(pDdiv); - break; - case Instruction::MUL_DOUBLE_2ADDR: - case Instruction::MUL_DOUBLE: - funcOffset = ENTRYPOINT_OFFSET(pDmul); - break; - case Instruction::REM_DOUBLE_2ADDR: - case Instruction::REM_DOUBLE: - funcOffset = ENTRYPOINT_OFFSET(pFmod); - break; - case Instruction::NEG_DOUBLE: { - genNegDouble(cUnit, rlDest, rlSrc1); - return false; - } - default: - return true; - } - oatFlushAllRegs(cUnit); /* Send everything to home location */ - callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false); - rlResult = oatGetReturnWide(cUnit, true); - storeValueWide(cUnit, rlDest, rlResult); - return false; -} - -bool genConversionPortable(CompilationUnit* cUnit, Instruction::Code opcode, - RegLocation rlDest, RegLocation rlSrc) -{ - - switch (opcode) { - case Instruction::INT_TO_FLOAT: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2f), - rlDest, rlSrc); - case Instruction::FLOAT_TO_INT: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2iz), - rlDest, rlSrc); - case Instruction::DOUBLE_TO_FLOAT: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2f), - rlDest, rlSrc); - case Instruction::FLOAT_TO_DOUBLE: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2d), - rlDest, rlSrc); - case Instruction::INT_TO_DOUBLE: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2d), - rlDest, rlSrc); - case Instruction::DOUBLE_TO_INT: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2iz), - rlDest, rlSrc); - case Instruction::FLOAT_TO_LONG: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2l), - rlDest, rlSrc); - case Instruction::LONG_TO_FLOAT: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2f), - rlDest, rlSrc); - case Instruction::DOUBLE_TO_LONG: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2l), - rlDest, rlSrc); - case Instruction::LONG_TO_DOUBLE: - return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2d), - rlDest, rlSrc); - default: - return true; - } - return false; -} - -/* Check if we need to check for pending suspend request */ -void genSuspendTest(CompilationUnit* cUnit, int optFlags) -{ - if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) { - return; - } - oatFlushAllRegs(cUnit); - LIR* branch = opTestSuspend(cUnit, NULL); - LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel); - LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset, kPseudoSuspendTarget, - (intptr_t)retLab, cUnit->currentDalvikOffset); - branch->target = (LIR*)target; - oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target); -} - -/* Check if we need to check for pending suspend request */ -void genSuspendTestAndBranch(CompilationUnit* cUnit, int optFlags, LIR* target) -{ - if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) { - opUnconditionalBranch(cUnit, target); - return; - } - opTestSuspend(cUnit, target); - LIR* launchPad = rawLIR(cUnit, cUnit->currentDalvikOffset, kPseudoSuspendTarget, (intptr_t)target, - cUnit->currentDalvikOffset); - oatFlushAllRegs(cUnit); - opUnconditionalBranch(cUnit, launchPad); - oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)launchPad); -} - -} // namespace art diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc deleted file mode 100644 index efd4f5ae6a..0000000000 --- a/src/compiler/codegen/GenInvoke.cc +++ /dev/null @@ -1,1010 +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 "oat/runtime/oat_support_entrypoints.h" - -namespace art { - -/* - * This source files contains "gen" codegen routines that should - * be applicable to most targets. Only mid-level support utilities - * and "op" calls may be used here. - */ - -typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dexIdx, - uint32_t methodIdx, uintptr_t directCode, - uintptr_t directMethod, InvokeType type); -LIR* opCondBranch(CompilationUnit* cUnit, ConditionCode cc, LIR* target); - -/* - * If there are any ins passed in registers that have not been promoted - * to a callee-save register, flush them to the frame. Perform intial - * assignment of promoted arguments. - * - * argLocs is an array of location records describing the incoming arguments - * with one location record per word of argument. - */ -void flushIns(CompilationUnit* cUnit, RegLocation* argLocs, RegLocation rlMethod) -{ - /* - * Dummy up a RegLocation for the incoming Method* - * It will attempt to keep kArg0 live (or copy it to home location - * if promoted). - */ - RegLocation rlSrc = rlMethod; - rlSrc.location = kLocPhysReg; - rlSrc.lowReg = targetReg(kArg0); - rlSrc.home = false; - oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); - storeValue(cUnit, rlMethod, rlSrc); - // If Method* has been promoted, explicitly flush - if (rlMethod.location == kLocPhysReg) { - storeWordDisp(cUnit, targetReg(kSp), 0, targetReg(kArg0)); - } - - if (cUnit->numIns == 0) - return; - const int numArgRegs = 3; - static SpecialTargetRegister argRegs[] = {kArg1, kArg2, kArg3}; - int startVReg = cUnit->numDalvikRegisters - cUnit->numIns; - /* - * Copy incoming arguments to their proper home locations. - * NOTE: an older version of dx had an issue in which - * it would reuse static method argument registers. - * This could result in the same Dalvik virtual register - * being promoted to both core and fp regs. To account for this, - * we only copy to the corresponding promoted physical register - * if it matches the type of the SSA name for the incoming - * argument. It is also possible that long and double arguments - * end up half-promoted. In those cases, we must flush the promoted - * half to memory as well. - */ - for (int i = 0; i < cUnit->numIns; i++) { - PromotionMap* vMap = &cUnit->promotionMap[startVReg + i]; - if (i < numArgRegs) { - // If arriving in register - bool needFlush = true; - RegLocation* tLoc = &argLocs[i]; - if ((vMap->coreLocation == kLocPhysReg) && !tLoc->fp) { - opRegCopy(cUnit, vMap->coreReg, targetReg(argRegs[i])); - needFlush = false; - } else if ((vMap->fpLocation == kLocPhysReg) && tLoc->fp) { - opRegCopy(cUnit, vMap->fpReg, targetReg(argRegs[i])); - needFlush = false; - } else { - needFlush = true; - } - - // For wide args, force flush if only half is promoted - if (tLoc->wide) { - PromotionMap* pMap = vMap + (tLoc->highWord ? -1 : +1); - needFlush |= (pMap->coreLocation != vMap->coreLocation) || - (pMap->fpLocation != vMap->fpLocation); - } - if (needFlush) { - storeBaseDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, startVReg + i), - targetReg(argRegs[i]), kWord); - } - } else { - // If arriving in frame & promoted - if (vMap->coreLocation == kLocPhysReg) { - loadWordDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, startVReg + i), - vMap->coreReg); - } - if (vMap->fpLocation == kLocPhysReg) { - loadWordDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, startVReg + i), - vMap->fpReg); - } - } - } -} - -void scanMethodLiteralPool(CompilationUnit* cUnit, LIR** methodTarget, LIR** codeTarget, const DexFile* dexFile, uint32_t dexMethodIdx) -{ - LIR* curTarget = cUnit->methodLiteralList; - LIR* nextTarget = curTarget != NULL ? curTarget->next : NULL; - while (curTarget != NULL && nextTarget != NULL) { - if (curTarget->operands[0] == (int)dexFile && - nextTarget->operands[0] == (int)dexMethodIdx) { - *codeTarget = curTarget; - *methodTarget = nextTarget; - DCHECK((*codeTarget)->next == *methodTarget); - DCHECK_EQ((*codeTarget)->operands[0], (int)dexFile); - DCHECK_EQ((*methodTarget)->operands[0], (int)dexMethodIdx); - break; - } - curTarget = nextTarget->next; - nextTarget = curTarget != NULL ? curTarget->next : NULL; - } -} - -/* - * Bit of a hack here - in the absence of a real scheduling pass, - * emit the next instruction in static & direct invoke sequences. - */ -int nextSDCallInsn(CompilationUnit* cUnit, CallInfo* info, - int state, uint32_t dexIdx, uint32_t unused, - uintptr_t directCode, uintptr_t directMethod, - InvokeType type) -{ - if (cUnit->instructionSet != kThumb2) { - // Disable sharpening - directCode = 0; - directMethod = 0; - } - if (directCode != 0 && directMethod != 0) { - switch (state) { - case 0: // Get the current Method* [sets kArg0] - if (directCode != (uintptr_t)-1) { - loadConstant(cUnit, targetReg(kInvokeTgt), directCode); - } else { - LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0); - if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx); - dataTarget->operands[1] = type; - } - LIR* loadPcRel = opPcRelLoad(cUnit, targetReg(kInvokeTgt), dataTarget); - oatAppendLIR(cUnit, loadPcRel); - DCHECK_EQ(cUnit->instructionSet, kThumb2) << (void*)dataTarget; - } - if (directMethod != (uintptr_t)-1) { - loadConstant(cUnit, targetReg(kArg0), directMethod); - } else { - LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0); - if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx); - dataTarget->operands[1] = type; - } - LIR* loadPcRel = opPcRelLoad(cUnit, targetReg(kArg0), dataTarget); - oatAppendLIR(cUnit, loadPcRel); - DCHECK_EQ(cUnit->instructionSet, kThumb2) << (void*)dataTarget; - } - break; - default: - return -1; - } - } else { - switch (state) { - case 0: // Get the current Method* [sets kArg0] - // TUNING: we can save a reg copy if Method* has been promoted. - loadCurrMethodDirect(cUnit, targetReg(kArg0)); - break; - case 1: // Get method->dex_cache_resolved_methods_ - loadWordDisp(cUnit, targetReg(kArg0), - AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), targetReg(kArg0)); - // Set up direct code if known. - if (directCode != 0) { - if (directCode != (uintptr_t)-1) { - loadConstant(cUnit, targetReg(kInvokeTgt), directCode); - } else { - LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0); - if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx); - dataTarget->operands[1] = type; - } - LIR* loadPcRel = opPcRelLoad(cUnit, targetReg(kInvokeTgt), dataTarget); - oatAppendLIR(cUnit, loadPcRel); - DCHECK_EQ(cUnit->instructionSet, kThumb2) << (void*)dataTarget; - } - } - break; - case 2: // Grab target method* - loadWordDisp(cUnit, targetReg(kArg0), - Array::DataOffset(sizeof(Object*)).Int32Value() + dexIdx * 4, targetReg(kArg0)); - break; - case 3: // Grab the code from the method* - if (cUnit->instructionSet != kX86) { - if (directCode == 0) { - loadWordDisp(cUnit, targetReg(kArg0), AbstractMethod::GetCodeOffset().Int32Value(), - targetReg(kInvokeTgt)); - } - break; - } - // Intentional fallthrough for x86 - default: - return -1; - } - } - return state + 1; -} - -/* - * Bit of a hack here - in the absence of a real scheduling pass, - * emit the next instruction in a virtual invoke sequence. - * We can use kLr as a temp prior to target address loading - * Note also that we'll load the first argument ("this") into - * kArg1 here rather than the standard loadArgRegs. - */ -int nextVCallInsn(CompilationUnit* cUnit, CallInfo* info, - int state, uint32_t dexIdx, uint32_t methodIdx, - uintptr_t unused, uintptr_t unused2, InvokeType unused3) -{ - /* - * This is the fast path in which the target virtual method is - * fully resolved at compile time. - */ - switch (state) { - case 0: { // Get "this" [set kArg1] - RegLocation rlArg = info->args[0]; - loadValueDirectFixed(cUnit, rlArg, targetReg(kArg1)); - break; - } - case 1: // Is "this" null? [use kArg1] - genNullCheck(cUnit, info->args[0].sRegLow, targetReg(kArg1), info->optFlags); - // get this->klass_ [use kArg1, set kInvokeTgt] - loadWordDisp(cUnit, targetReg(kArg1), Object::ClassOffset().Int32Value(), - targetReg(kInvokeTgt)); - break; - case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt] - loadWordDisp(cUnit, targetReg(kInvokeTgt), Class::VTableOffset().Int32Value(), - targetReg(kInvokeTgt)); - break; - case 3: // Get target method [use kInvokeTgt, set kArg0] - loadWordDisp(cUnit, targetReg(kInvokeTgt), (methodIdx * 4) + - Array::DataOffset(sizeof(Object*)).Int32Value(), targetReg(kArg0)); - break; - case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt] - if (cUnit->instructionSet != kX86) { - loadWordDisp(cUnit, targetReg(kArg0), AbstractMethod::GetCodeOffset().Int32Value(), - targetReg(kInvokeTgt)); - break; - } - // Intentional fallthrough for X86 - default: - return -1; - } - return state + 1; -} - -/* - * All invoke-interface calls bounce off of art_invoke_interface_trampoline, - * which will locate the target and continue on via a tail call. - */ -int nextInterfaceCallInsn(CompilationUnit* cUnit, CallInfo* info, int state, - uint32_t dexIdx, uint32_t unused, uintptr_t unused2, - uintptr_t directMethod, InvokeType unused4) -{ - if (cUnit->instructionSet != kThumb2) { - // Disable sharpening - directMethod = 0; - } - int trampoline = (cUnit->instructionSet == kX86) ? 0 - : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); - - if (directMethod != 0) { - switch (state) { - case 0: // Load the trampoline target [sets kInvokeTgt]. - if (cUnit->instructionSet != kX86) { - loadWordDisp(cUnit, targetReg(kSelf), trampoline, targetReg(kInvokeTgt)); - } - // Get the interface Method* [sets kArg0] - if (directMethod != (uintptr_t)-1) { - loadConstant(cUnit, targetReg(kArg0), directMethod); - } else { - LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0); - if (dataTarget == NULL) { - dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx); - dataTarget->operands[1] = kInterface; - } - LIR* loadPcRel = opPcRelLoad(cUnit, targetReg(kArg0), dataTarget); - oatAppendLIR(cUnit, loadPcRel); - DCHECK_EQ(cUnit->instructionSet, kThumb2) << (void*)dataTarget; - } - break; - default: - return -1; - } - } else { - switch (state) { - case 0: - // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted. - loadCurrMethodDirect(cUnit, targetReg(kArg0)); - // Load the trampoline target [sets kInvokeTgt]. - if (cUnit->instructionSet != kX86) { - loadWordDisp(cUnit, targetReg(kSelf), trampoline, targetReg(kInvokeTgt)); - } - break; - case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0] - loadWordDisp(cUnit, targetReg(kArg0), - AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), - targetReg(kArg0)); - break; - case 2: // Grab target method* [set/use kArg0] - loadWordDisp(cUnit, targetReg(kArg0), - Array::DataOffset(sizeof(Object*)).Int32Value() + dexIdx * 4, - targetReg(kArg0)); - break; - default: - return -1; - } - } - return state + 1; -} - -int nextInvokeInsnSP(CompilationUnit* cUnit, CallInfo* info, int trampoline, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - /* - * This handles the case in which the base method is not fully - * resolved at compile time, we bail to a runtime helper. - */ - if (state == 0) { - if (cUnit->instructionSet != kX86) { - // Load trampoline target - loadWordDisp(cUnit, targetReg(kSelf), trampoline, targetReg(kInvokeTgt)); - } - // Load kArg0 with method index - loadConstant(cUnit, targetReg(kArg0), dexIdx); - return 1; - } - return -1; -} - -int nextStaticCallInsnSP(CompilationUnit* cUnit, CallInfo* info, - int state, uint32_t dexIdx, uint32_t methodIdx, - uintptr_t unused, uintptr_t unused2, - InvokeType unused3) -{ - int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0); -} - -int nextDirectCallInsnSP(CompilationUnit* cUnit, CallInfo* info, int state, - uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused, - uintptr_t unused2, InvokeType unused3) -{ - int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0); -} - -int nextSuperCallInsnSP(CompilationUnit* cUnit, CallInfo* info, int state, - uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused, - uintptr_t unused2, InvokeType unused3) -{ - int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0); -} - -int nextVCallInsnSP(CompilationUnit* cUnit, CallInfo* info, int state, - uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused, - uintptr_t unused2, InvokeType unused3) -{ - int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0); -} - -int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit, - CallInfo* info, int state, - uint32_t dexIdx, uint32_t unused, - uintptr_t unused2, uintptr_t unused3, - InvokeType unused4) -{ - int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0); -} - -int loadArgRegs(CompilationUnit* cUnit, CallInfo* info, int callState, - NextCallInsn nextCallInsn, uint32_t dexIdx, - uint32_t methodIdx, uintptr_t directCode, - uintptr_t directMethod, InvokeType type, bool skipThis) -{ - int lastArgReg = targetReg(kArg3); - int nextReg = targetReg(kArg1); - int nextArg = 0; - if (skipThis) { - nextReg++; - nextArg++; - } - for (; (nextReg <= lastArgReg) && (nextArg < info->numArgWords); nextReg++) { - RegLocation rlArg = info->args[nextArg++]; - rlArg = oatUpdateRawLoc(cUnit, rlArg); - if (rlArg.wide && (nextReg <= targetReg(kArg2))) { - loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1); - nextReg++; - nextArg++; - } else { - rlArg.wide = false; - loadValueDirectFixed(cUnit, rlArg, nextReg); - } - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - } - return callState; -} - -/* - * Load up to 5 arguments, the first three of which will be in - * kArg1 .. kArg3. On entry kArg0 contains the current method pointer, - * and as part of the load sequence, it must be replaced with - * the target method pointer. Note, this may also be called - * for "range" variants if the number of arguments is 5 or fewer. - */ -int genDalvikArgsNoRange(CompilationUnit* cUnit, CallInfo* info, - int callState, - LIR** pcrLabel, NextCallInsn nextCallInsn, - uint32_t dexIdx, uint32_t methodIdx, - uintptr_t directCode, uintptr_t directMethod, - InvokeType type, bool skipThis) -{ - RegLocation rlArg; - - /* If no arguments, just return */ - if (info->numArgWords == 0) - return callState; - - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - - DCHECK_LE(info->numArgWords, 5); - if (info->numArgWords > 3) { - int32_t nextUse = 3; - //Detect special case of wide arg spanning arg3/arg4 - RegLocation rlUse0 = info->args[0]; - RegLocation rlUse1 = info->args[1]; - RegLocation rlUse2 = info->args[2]; - if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) && - rlUse2.wide) { - int reg = -1; - // Wide spans, we need the 2nd half of uses[2]. - rlArg = oatUpdateLocWide(cUnit, rlUse2); - if (rlArg.location == kLocPhysReg) { - reg = rlArg.highReg; - } else { - // kArg2 & rArg3 can safely be used here - reg = targetReg(kArg3); - loadWordDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg); - callState = nextCallInsn(cUnit, info, callState, dexIdx, - methodIdx, directCode, directMethod, type); - } - storeBaseDisp(cUnit, targetReg(kSp), (nextUse + 1) * 4, reg, kWord); - storeBaseDisp(cUnit, targetReg(kSp), 16 /* (3+1)*4 */, reg, kWord); - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - nextUse++; - } - // Loop through the rest - while (nextUse < info->numArgWords) { - int lowReg; - int highReg = -1; - rlArg = info->args[nextUse]; - rlArg = oatUpdateRawLoc(cUnit, rlArg); - if (rlArg.location == kLocPhysReg) { - lowReg = rlArg.lowReg; - highReg = rlArg.highReg; - } else { - lowReg = targetReg(kArg2); - if (rlArg.wide) { - highReg = targetReg(kArg3); - loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg); - } else { - loadValueDirectFixed(cUnit, rlArg, lowReg); - } - callState = nextCallInsn(cUnit, info, callState, dexIdx, - methodIdx, directCode, directMethod, type); - } - int outsOffset = (nextUse + 1) * 4; - if (rlArg.wide) { - storeBaseDispWide(cUnit, targetReg(kSp), outsOffset, lowReg, highReg); - nextUse += 2; - } else { - storeWordDisp(cUnit, targetReg(kSp), outsOffset, lowReg); - nextUse++; - } - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - } - } - - callState = loadArgRegs(cUnit, info, callState, nextCallInsn, - dexIdx, methodIdx, directCode, directMethod, - type, skipThis); - - if (pcrLabel) { - *pcrLabel = genNullCheck(cUnit, info->args[0].sRegLow, targetReg(kArg1), - info->optFlags); - } - return callState; -} - -/* - * May have 0+ arguments (also used for jumbo). Note that - * source virtual registers may be in physical registers, so may - * need to be flushed to home location before copying. This - * applies to arg3 and above (see below). - * - * Two general strategies: - * If < 20 arguments - * Pass args 3-18 using vldm/vstm block copy - * Pass arg0, arg1 & arg2 in kArg1-kArg3 - * If 20+ arguments - * Pass args arg19+ using memcpy block copy - * Pass arg0, arg1 & arg2 in kArg1-kArg3 - * - */ -int genDalvikArgsRange(CompilationUnit* cUnit, CallInfo* info, int callState, - LIR** pcrLabel, NextCallInsn nextCallInsn, - uint32_t dexIdx, uint32_t methodIdx, - uintptr_t directCode, uintptr_t directMethod, - InvokeType type, bool skipThis) -{ - - // If we can treat it as non-range (Jumbo ops will use range form) - if (info->numArgWords <= 5) - return genDalvikArgsNoRange(cUnit, info, callState, pcrLabel, - nextCallInsn, dexIdx, methodIdx, - directCode, directMethod, type, skipThis); - /* - * First load the non-register arguments. Both forms expect all - * of the source arguments to be in their home frame location, so - * scan the sReg names and flush any that have been promoted to - * frame backing storage. - */ - // Scan the rest of the args - if in physReg flush to memory - for (int nextArg = 0; nextArg < info->numArgWords;) { - RegLocation loc = info->args[nextArg]; - if (loc.wide) { - loc = oatUpdateLocWide(cUnit, loc); - if ((nextArg >= 2) && (loc.location == kLocPhysReg)) { - storeBaseDispWide(cUnit, targetReg(kSp), oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, loc.highReg); - } - nextArg += 2; - } else { - loc = oatUpdateLoc(cUnit, loc); - if ((nextArg >= 3) && (loc.location == kLocPhysReg)) { - storeBaseDisp(cUnit, targetReg(kSp), oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, kWord); - } - nextArg++; - } - } - - int startOffset = oatSRegOffset(cUnit, info->args[3].sRegLow); - int outsOffset = 4 /* Method* */ + (3 * 4); - if (cUnit->instructionSet != kThumb2) { - // Generate memcpy - opRegRegImm(cUnit, kOpAdd, targetReg(kArg0), targetReg(kSp), outsOffset); - opRegRegImm(cUnit, kOpAdd, targetReg(kArg1), targetReg(kSp), startOffset); - callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy), targetReg(kArg0), - targetReg(kArg1), (info->numArgWords - 3) * 4, false); - } else { - if (info->numArgWords >= 20) { - // Generate memcpy - opRegRegImm(cUnit, kOpAdd, targetReg(kArg0), targetReg(kSp), outsOffset); - opRegRegImm(cUnit, kOpAdd, targetReg(kArg1), targetReg(kSp), startOffset); - callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy), targetReg(kArg0), - targetReg(kArg1), (info->numArgWords - 3) * 4, false); - } else { - // Use vldm/vstm pair using kArg3 as a temp - int regsLeft = std::min(info->numArgWords - 3, 16); - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - opRegRegImm(cUnit, kOpAdd, targetReg(kArg3), targetReg(kSp), startOffset); - LIR* ld = opVldm(cUnit, targetReg(kArg3), regsLeft); - //TUNING: loosen barrier - ld->defMask = ENCODE_ALL; - setMemRefType(ld, true /* isLoad */, kDalvikReg); - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - opRegRegImm(cUnit, kOpAdd, targetReg(kArg3), targetReg(kSp), 4 /* Method* */ + (3 * 4)); - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - LIR* st = opVstm(cUnit, targetReg(kArg3), regsLeft); - setMemRefType(st, false /* isLoad */, kDalvikReg); - st->defMask = ENCODE_ALL; - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - } - } - - callState = loadArgRegs(cUnit, info, callState, nextCallInsn, - dexIdx, methodIdx, directCode, directMethod, - type, skipThis); - - callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx, - directCode, directMethod, type); - if (pcrLabel) { - *pcrLabel = genNullCheck(cUnit, info->args[0].sRegLow, targetReg(kArg1), - info->optFlags); - } - return callState; -} - -RegLocation inlineTarget(CompilationUnit* cUnit, CallInfo* info) -{ - RegLocation res; - if (info->result.location == kLocInvalid) { - res = oatGetReturn(cUnit, false); - } else { - res = info->result; - } - return res; -} - -RegLocation inlineTargetWide(CompilationUnit* cUnit, CallInfo* info) -{ - RegLocation res; - if (info->result.location == kLocInvalid) { - res = oatGetReturnWide(cUnit, false); - } else { - res = info->result; - } - return res; -} - -bool genInlinedCharAt(CompilationUnit* cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - // Location of reference to data array - int valueOffset = String::ValueOffset().Int32Value(); - // Location of count - int countOffset = String::CountOffset().Int32Value(); - // Starting offset within data array - int offsetOffset = String::OffsetOffset().Int32Value(); - // Start of char data with array_ - int dataOffset = Array::DataOffset(sizeof(uint16_t)).Int32Value(); - - RegLocation rlObj = info->args[0]; - RegLocation rlIdx = info->args[1]; - rlObj = loadValue(cUnit, rlObj, kCoreReg); - rlIdx = loadValue(cUnit, rlIdx, kCoreReg); - int regMax; - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, info->optFlags); - bool rangeCheck = (!(info->optFlags & MIR_IGNORE_RANGE_CHECK)); - LIR* launchPad = NULL; - int regOff = INVALID_REG; - int regPtr = INVALID_REG; - if (cUnit->instructionSet != kX86) { - regOff = oatAllocTemp(cUnit); - regPtr = oatAllocTemp(cUnit); - if (rangeCheck) { - regMax = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rlObj.lowReg, countOffset, regMax); - } - loadWordDisp(cUnit, rlObj.lowReg, offsetOffset, regOff); - loadWordDisp(cUnit, rlObj.lowReg, valueOffset, regPtr); - if (rangeCheck) { - // Set up a launch pad to allow retry in case of bounds violation */ - launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info); - oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads, - (intptr_t)launchPad); - opRegReg(cUnit, kOpCmp, rlIdx.lowReg, regMax); - oatFreeTemp(cUnit, regMax); - opCondBranch(cUnit, kCondCs, launchPad); - } - } else { - if (rangeCheck) { - regMax = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rlObj.lowReg, countOffset, regMax); - // Set up a launch pad to allow retry in case of bounds violation */ - launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info); - oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads, - (intptr_t)launchPad); - opRegReg(cUnit, kOpCmp, rlIdx.lowReg, regMax); - oatFreeTemp(cUnit, regMax); - opCondBranch(cUnit, kCondCc, launchPad); - } - regOff = oatAllocTemp(cUnit); - regPtr = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rlObj.lowReg, offsetOffset, regOff); - loadWordDisp(cUnit, rlObj.lowReg, valueOffset, regPtr); - } - opRegImm(cUnit, kOpAdd, regPtr, dataOffset); - opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg); - oatFreeTemp(cUnit, rlObj.lowReg); - oatFreeTemp(cUnit, rlIdx.lowReg); - RegLocation rlDest = inlineTarget(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf); - oatFreeTemp(cUnit, regOff); - oatFreeTemp(cUnit, regPtr); - storeValue(cUnit, rlDest, rlResult); - if (rangeCheck) { - launchPad->operands[2] = 0; // no resumption - } - // Record that we've already inlined & null checked - info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK); - return true; -} - -// Generates an inlined String.isEmpty or String.length. -bool genInlinedStringIsEmptyOrLength(CompilationUnit* cUnit, CallInfo* info, - bool isEmpty) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - // dst = src.length(); - RegLocation rlObj = info->args[0]; - rlObj = loadValue(cUnit, rlObj, kCoreReg); - RegLocation rlDest = inlineTarget(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, info->optFlags); - loadWordDisp(cUnit, rlObj.lowReg, String::CountOffset().Int32Value(), - rlResult.lowReg); - if (isEmpty) { - // dst = (dst == 0); - if (cUnit->instructionSet == kThumb2) { - int tReg = oatAllocTemp(cUnit); - opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg); - opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg); - } else { - DCHECK_EQ(cUnit->instructionSet, kX86); - opRegImm(cUnit, kOpSub, rlResult.lowReg, 1); - opRegImm(cUnit, kOpLsr, rlResult.lowReg, 31); - } - } - storeValue(cUnit, rlDest, rlResult); - return true; -} - -bool genInlinedAbsInt(CompilationUnit *cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - RegLocation rlSrc = info->args[0]; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlDest = inlineTarget(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - int signReg = oatAllocTemp(cUnit); - // abs(x) = y<=x>>31, (x+y)^y. - opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31); - opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); - opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); - storeValue(cUnit, rlDest, rlResult); - return true; -} - -bool genInlinedAbsLong(CompilationUnit *cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - if (cUnit->instructionSet == kThumb2) { - RegLocation rlSrc = info->args[0]; - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - RegLocation rlDest = inlineTargetWide(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - int signReg = oatAllocTemp(cUnit); - // abs(x) = y<=x>>31, (x+y)^y. - opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31); - opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); - opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg); - opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); - opRegReg(cUnit, kOpXor, rlResult.highReg, signReg); - storeValueWide(cUnit, rlDest, rlResult); - return true; - } else { - DCHECK_EQ(cUnit->instructionSet, kX86); - // Reuse source registers to avoid running out of temps - RegLocation rlSrc = info->args[0]; - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - RegLocation rlDest = inlineTargetWide(cUnit, info); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegCopyWide(cUnit, rlResult.lowReg, rlResult.highReg, rlSrc.lowReg, rlSrc.highReg); - oatFreeTemp(cUnit, rlSrc.lowReg); - oatFreeTemp(cUnit, rlSrc.highReg); - int signReg = oatAllocTemp(cUnit); - // abs(x) = y<=x>>31, (x+y)^y. - opRegRegImm(cUnit, kOpAsr, signReg, rlResult.highReg, 31); - opRegReg(cUnit, kOpAdd, rlResult.lowReg, signReg); - opRegReg(cUnit, kOpAdc, rlResult.highReg, signReg); - opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); - opRegReg(cUnit, kOpXor, rlResult.highReg, signReg); - storeValueWide(cUnit, rlDest, rlResult); - return true; - } -} - -bool genInlinedFloatCvt(CompilationUnit *cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - RegLocation rlSrc = info->args[0]; - RegLocation rlDest = inlineTarget(cUnit, info); - storeValue(cUnit, rlDest, rlSrc); - return true; -} - -bool genInlinedDoubleCvt(CompilationUnit *cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - RegLocation rlSrc = info->args[0]; - RegLocation rlDest = inlineTargetWide(cUnit, info); - storeValueWide(cUnit, rlDest, rlSrc); - return true; -} - -/* - * Fast string.indexOf(I) & (II). Tests for simple case of char <= 0xffff, - * otherwise bails to standard library code. - */ -bool genInlinedIndexOf(CompilationUnit* cUnit, CallInfo* info, - bool zeroBased) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - oatClobberCalleeSave(cUnit); - oatLockCallTemps(cUnit); // Using fixed registers - int regPtr = targetReg(kArg0); - int regChar = targetReg(kArg1); - int regStart = targetReg(kArg2); - - RegLocation rlObj = info->args[0]; - RegLocation rlChar = info->args[1]; - RegLocation rlStart = info->args[2]; - loadValueDirectFixed(cUnit, rlObj, regPtr); - loadValueDirectFixed(cUnit, rlChar, regChar); - if (zeroBased) { - loadConstant(cUnit, regStart, 0); - } else { - loadValueDirectFixed(cUnit, rlStart, regStart); - } - int rTgt = (cUnit->instructionSet != kX86) ? loadHelper(cUnit, ENTRYPOINT_OFFSET(pIndexOf)) : 0; - genNullCheck(cUnit, rlObj.sRegLow, regPtr, info->optFlags); - LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info); - oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads, - (intptr_t)launchPad); - opCmpImmBranch(cUnit, kCondGt, regChar, 0xFFFF, launchPad); - // NOTE: not a safepoint - if (cUnit->instructionSet != kX86) { - opReg(cUnit, kOpBlx, rTgt); - } else { - opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pIndexOf)); - } - LIR* resumeTgt = newLIR0(cUnit, kPseudoTargetLabel); - launchPad->operands[2] = (uintptr_t)resumeTgt; - // Record that we've already inlined & null checked - info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK); - RegLocation rlReturn = oatGetReturn(cUnit, false); - RegLocation rlDest = inlineTarget(cUnit, info); - storeValue(cUnit, rlDest, rlReturn); - return true; -} - -/* Fast string.compareTo(Ljava/lang/string;)I. */ -bool genInlinedStringCompareTo(CompilationUnit* cUnit, CallInfo* info) -{ - if (cUnit->instructionSet == kMips) { - // TODO - add Mips implementation - return false; - } - oatClobberCalleeSave(cUnit); - oatLockCallTemps(cUnit); // Using fixed registers - int regThis = targetReg(kArg0); - int regCmp = targetReg(kArg1); - - RegLocation rlThis = info->args[0]; - RegLocation rlCmp = info->args[1]; - loadValueDirectFixed(cUnit, rlThis, regThis); - loadValueDirectFixed(cUnit, rlCmp, regCmp); - int rTgt = (cUnit->instructionSet != kX86) ? - loadHelper(cUnit, ENTRYPOINT_OFFSET(pStringCompareTo)) : 0; - genNullCheck(cUnit, rlThis.sRegLow, regThis, info->optFlags); - //TUNING: check if rlCmp.sRegLow is already null checked - LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info); - oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads, - (intptr_t)launchPad); - opCmpImmBranch(cUnit, kCondEq, regCmp, 0, launchPad); - // NOTE: not a safepoint - if (cUnit->instructionSet != kX86) { - opReg(cUnit, kOpBlx, rTgt); - } else { - opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo)); - } - launchPad->operands[2] = 0; // No return possible - // Record that we've already inlined & null checked - info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK); - RegLocation rlReturn = oatGetReturn(cUnit, false); - RegLocation rlDest = inlineTarget(cUnit, info); - storeValue(cUnit, rlDest, rlReturn); - return true; -} - -bool genIntrinsic(CompilationUnit* cUnit, CallInfo* info) -{ - if (info->optFlags & MIR_INLINED) { - return false; - } - /* - * TODO: move these to a target-specific structured constant array - * and use a generic match function. The list of intrinsics may be - * slightly different depending on target. - * TODO: Fold this into a matching function that runs during - * basic block building. This should be part of the action for - * small method inlining and recognition of the special object init - * method. By doing this during basic block construction, we can also - * take advantage of/generate new useful dataflow info. - */ - std::string tgtMethod(PrettyMethod(info->index, *cUnit->dex_file)); - if (tgtMethod.find(" java.lang") != std::string::npos) { - if (tgtMethod == "long java.lang.Double.doubleToRawLongBits(double)") { - return genInlinedDoubleCvt(cUnit, info); - } - if (tgtMethod == "double java.lang.Double.longBitsToDouble(long)") { - return genInlinedDoubleCvt(cUnit, info); - } - if (tgtMethod == "int java.lang.Float.floatToRawIntBits(float)") { - return genInlinedFloatCvt(cUnit, info); - } - if (tgtMethod == "float java.lang.Float.intBitsToFloat(int)") { - return genInlinedFloatCvt(cUnit, info); - } - if (tgtMethod == "int java.lang.Math.abs(int)" || - tgtMethod == "int java.lang.StrictMath.abs(int)") { - return genInlinedAbsInt(cUnit, info); - } - if (tgtMethod == "long java.lang.Math.abs(long)" || - tgtMethod == "long java.lang.StrictMath.abs(long)") { - return genInlinedAbsLong(cUnit, info); - } - if (tgtMethod == "int java.lang.Math.max(int, int)" || - tgtMethod == "int java.lang.StrictMath.max(int, int)") { - return genInlinedMinMaxInt(cUnit, info, false /* isMin */); - } - if (tgtMethod == "int java.lang.Math.min(int, int)" || - tgtMethod == "int java.lang.StrictMath.min(int, int)") { - return genInlinedMinMaxInt(cUnit, info, true /* isMin */); - } - if (tgtMethod == "double java.lang.Math.sqrt(double)" || - tgtMethod == "double java.lang.StrictMath.sqrt(double)") { - return genInlinedSqrt(cUnit, info); - } - if (tgtMethod == "char java.lang.String.charAt(int)") { - return genInlinedCharAt(cUnit, info); - } - if (tgtMethod == "int java.lang.String.compareTo(java.lang.String)") { - return genInlinedStringCompareTo(cUnit, info); - } - if (tgtMethod == "boolean java.lang.String.isEmpty()") { - return genInlinedStringIsEmptyOrLength(cUnit, info, true /* isEmpty */); - } - if (tgtMethod == "int java.lang.String.indexOf(int, int)") { - return genInlinedIndexOf(cUnit, info, false /* base 0 */); - } - if (tgtMethod == "int java.lang.String.indexOf(int)") { - return genInlinedIndexOf(cUnit, info, true /* base 0 */); - } - if (tgtMethod == "int java.lang.String.length()") { - return genInlinedStringIsEmptyOrLength(cUnit, info, false /* isEmpty */); - } - } else if (tgtMethod.find("boolean sun.misc.Unsafe.compareAndSwap") != std::string::npos) { - if (tgtMethod == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") { - return genInlinedCas32(cUnit, info, false); - } - if (tgtMethod == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") { - return genInlinedCas32(cUnit, info, true); - } - } - return false; -} - - -} // namespace art diff --git a/src/compiler/codegen/LocalOptimizations.cc b/src/compiler/codegen/LocalOptimizations.cc deleted file mode 100644 index 2688d65877..0000000000 --- a/src/compiler/codegen/LocalOptimizations.cc +++ /dev/null @@ -1,458 +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 { - -#define DEBUG_OPT(X) - -/* Check RAW, WAR, and WAR dependency on the register operands */ -#define CHECK_REG_DEP(use, def, check) ((def & check->useMask) || \ - ((use | def) & check->defMask)) - -/* Scheduler heuristics */ -#define MAX_HOIST_DISTANCE 20 -#define LDLD_DISTANCE 4 -#define LD_LATENCY 2 - -inline bool isDalvikRegisterClobbered(LIR* lir1, LIR* lir2) -{ - int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo); - int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo); - int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo); - int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo); - - return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo); -} - -/* Convert a more expensive instruction (ie load) into a move */ -void convertMemOpIntoMove(CompilationUnit* cUnit, LIR* origLIR, int dest, - int src) -{ - /* Insert a move to replace the load */ - LIR* moveLIR; - moveLIR = oatRegCopyNoInsert( cUnit, dest, src); - /* - * Insert the converted instruction after the original since the - * optimization is scannng in the top-down order and the new instruction - * will need to be re-checked (eg the new dest clobbers the src used in - * thisLIR). - */ - oatInsertLIRAfter((LIR*) origLIR, (LIR*) moveLIR); -} - -/* - * Perform a pass of top-down walk, from the second-last instruction in the - * superblock, to eliminate redundant loads and stores. - * - * An earlier load can eliminate a later load iff - * 1) They are must-aliases - * 2) The native register is not clobbered in between - * 3) The memory location is not written to in between - * - * An earlier store can eliminate a later load iff - * 1) They are must-aliases - * 2) The native register is not clobbered in between - * 3) The memory location is not written to in between - * - * A later store can be eliminated by an earlier store iff - * 1) They are must-aliases - * 2) The memory location is not written to in between - */ -void applyLoadStoreElimination(CompilationUnit* cUnit, LIR* headLIR, - LIR* tailLIR) -{ - LIR* thisLIR; - - if (headLIR == tailLIR) return; - - for (thisLIR = PREV_LIR(tailLIR); - thisLIR != headLIR; - thisLIR = PREV_LIR(thisLIR)) { - int sinkDistance = 0; - - /* Skip non-interesting instructions */ - if ((thisLIR->flags.isNop == true) || - isPseudoOpcode(thisLIR->opcode) || - (EncodingMap[thisLIR->opcode].flags & IS_BRANCH) || - !(EncodingMap[thisLIR->opcode].flags & (IS_LOAD | IS_STORE))) { - continue; - } - - int nativeRegId; - if (cUnit->instructionSet == kX86) { - // If x86, location differs depending on whether memory/reg operation. - nativeRegId = (EncodingMap[thisLIR->opcode].flags & IS_STORE) ? thisLIR->operands[2] - : thisLIR->operands[0]; - } else { - nativeRegId = thisLIR->operands[0]; - } - bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD; - LIR* checkLIR; - /* Use the mem mask to determine the rough memory location */ - u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM; - - /* - * Currently only eliminate redundant ld/st for constant and Dalvik - * register accesses. - */ - if (!(thisMemMask & (ENCODE_LITERAL | ENCODE_DALVIK_REG))) continue; - - u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM; - u8 stopUseRegMask; - if (cUnit->instructionSet == kX86) { - stopUseRegMask = (IS_BRANCH | thisLIR->useMask) & ~ENCODE_MEM; - } else { - /* - * Add pc to the resource mask to prevent this instruction - * from sinking past branch instructions. Also take out the memory - * region bits since stopMask is used to check data/control - * dependencies. - */ - stopUseRegMask = (getPCUseDefEncoding() | thisLIR->useMask) & ~ENCODE_MEM; - } - - for (checkLIR = NEXT_LIR(thisLIR); - checkLIR != tailLIR; - checkLIR = NEXT_LIR(checkLIR)) { - - /* - * Skip already dead instructions (whose dataflow information is - * outdated and misleading). - */ - if (checkLIR->flags.isNop) continue; - - u8 checkMemMask = (checkLIR->useMask | checkLIR->defMask) & ENCODE_MEM; - u8 aliasCondition = thisMemMask & checkMemMask; - bool stopHere = false; - - /* - * Potential aliases seen - check the alias relations - */ - if (checkMemMask != ENCODE_MEM && aliasCondition != 0) { - bool isCheckLIRLoad = EncodingMap[checkLIR->opcode].flags & IS_LOAD; - if (aliasCondition == ENCODE_LITERAL) { - /* - * Should only see literal loads in the instruction - * stream. - */ - DCHECK(!(EncodingMap[checkLIR->opcode].flags & IS_STORE)); - /* Same value && same register type */ - if (checkLIR->aliasInfo == thisLIR->aliasInfo && - sameRegType(checkLIR->operands[0], nativeRegId)) { - /* - * Different destination register - insert - * a move - */ - if (checkLIR->operands[0] != nativeRegId) { - convertMemOpIntoMove(cUnit, checkLIR, checkLIR->operands[0], - nativeRegId); - } - checkLIR->flags.isNop = true; - } - } else if (aliasCondition == ENCODE_DALVIK_REG) { - /* Must alias */ - if (checkLIR->aliasInfo == thisLIR->aliasInfo) { - /* Only optimize compatible registers */ - bool regCompatible = sameRegType(checkLIR->operands[0], nativeRegId); - if ((isThisLIRLoad && isCheckLIRLoad) || - (!isThisLIRLoad && isCheckLIRLoad)) { - /* RAR or RAW */ - if (regCompatible) { - /* - * Different destination register - - * insert a move - */ - if (checkLIR->operands[0] != - nativeRegId) { - convertMemOpIntoMove(cUnit, checkLIR, checkLIR->operands[0], - nativeRegId); - } - checkLIR->flags.isNop = true; - } else { - /* - * Destinaions are of different types - - * something complicated going on so - * stop looking now. - */ - stopHere = true; - } - } else if (isThisLIRLoad && !isCheckLIRLoad) { - /* WAR - register value is killed */ - stopHere = true; - } else if (!isThisLIRLoad && !isCheckLIRLoad) { - /* WAW - nuke the earlier store */ - thisLIR->flags.isNop = true; - stopHere = true; - } - /* Partial overlap */ - } else if (isDalvikRegisterClobbered(thisLIR, checkLIR)) { - /* - * It is actually ok to continue if checkLIR - * is a read. But it is hard to make a test - * case for this so we just stop here to be - * conservative. - */ - stopHere = true; - } - } - /* Memory content may be updated. Stop looking now. */ - if (stopHere) { - break; - /* The checkLIR has been transformed - check the next one */ - } else if (checkLIR->flags.isNop) { - continue; - } - } - - - /* - * this and check LIRs have no memory dependency. Now check if - * their register operands have any RAW, WAR, and WAW - * dependencies. If so, stop looking. - */ - if (stopHere == false) { - stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask, checkLIR); - } - - if (stopHere == true) { - if (cUnit->instructionSet == kX86) { - // Prevent stores from being sunk between ops that generate ccodes and - // ops that use them. - uint64_t flags = EncodingMap[checkLIR->opcode].flags; - if (sinkDistance > 0 && (flags & IS_BRANCH) && (flags & USES_CCODES)) { - checkLIR = PREV_LIR(checkLIR); - sinkDistance--; - } - } - DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR, "REG CLOBBERED")); - /* Only sink store instructions */ - if (sinkDistance && !isThisLIRLoad) { - LIR* newStoreLIR = - (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); - *newStoreLIR = *thisLIR; - /* - * Stop point found - insert *before* the checkLIR - * since the instruction list is scanned in the - * top-down order. - */ - oatInsertLIRBefore((LIR*) checkLIR, (LIR*) newStoreLIR); - thisLIR->flags.isNop = true; - } - break; - } else if (!checkLIR->flags.isNop) { - sinkDistance++; - } - } - } -} - -/* - * Perform a pass of bottom-up walk, from the second instruction in the - * superblock, to try to hoist loads to earlier slots. - */ -void applyLoadHoisting(CompilationUnit* cUnit, LIR* headLIR, LIR* tailLIR) -{ - LIR* thisLIR, *checkLIR; - /* - * Store the list of independent instructions that can be hoisted past. - * Will decide the best place to insert later. - */ - LIR* prevInstList[MAX_HOIST_DISTANCE]; - - /* Empty block */ - if (headLIR == tailLIR) return; - - /* Start from the second instruction */ - for (thisLIR = NEXT_LIR(headLIR); - thisLIR != tailLIR; - thisLIR = NEXT_LIR(thisLIR)) { - - /* Skip non-interesting instructions */ - if ((thisLIR->flags.isNop == true) || - isPseudoOpcode(thisLIR->opcode) || - !(EncodingMap[thisLIR->opcode].flags & IS_LOAD)) { - continue; - } - - u8 stopUseAllMask = thisLIR->useMask; - - if (cUnit->instructionSet != kX86) { - /* - * Branches for null/range checks are marked with the true resource - * bits, and loads to Dalvik registers, constant pools, and non-alias - * locations are safe to be hoisted. So only mark the heap references - * conservatively here. - */ - if (stopUseAllMask & ENCODE_HEAP_REF) { - stopUseAllMask |= getPCUseDefEncoding(); - } - } - - /* Similar as above, but just check for pure register dependency */ - u8 stopUseRegMask = stopUseAllMask & ~ENCODE_MEM; - u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM; - - int nextSlot = 0; - bool stopHere = false; - - /* Try to hoist the load to a good spot */ - for (checkLIR = PREV_LIR(thisLIR); - checkLIR != headLIR; - checkLIR = PREV_LIR(checkLIR)) { - - /* - * Skip already dead instructions (whose dataflow information is - * outdated and misleading). - */ - if (checkLIR->flags.isNop) continue; - - u8 checkMemMask = checkLIR->defMask & ENCODE_MEM; - u8 aliasCondition = stopUseAllMask & checkMemMask; - stopHere = false; - - /* Potential WAR alias seen - check the exact relation */ - if (checkMemMask != ENCODE_MEM && aliasCondition != 0) { - /* We can fully disambiguate Dalvik references */ - if (aliasCondition == ENCODE_DALVIK_REG) { - /* Must alias or partually overlap */ - if ((checkLIR->aliasInfo == thisLIR->aliasInfo) || - isDalvikRegisterClobbered(thisLIR, checkLIR)) { - stopHere = true; - } - /* Conservatively treat all heap refs as may-alias */ - } else { - DCHECK_EQ(aliasCondition, ENCODE_HEAP_REF); - stopHere = true; - } - /* Memory content may be updated. Stop looking now. */ - if (stopHere) { - prevInstList[nextSlot++] = checkLIR; - break; - } - } - - if (stopHere == false) { - stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask, - checkLIR); - } - - /* - * Store the dependent or non-pseudo/indepedent instruction to the - * list. - */ - if (stopHere || !isPseudoOpcode(checkLIR->opcode)) { - prevInstList[nextSlot++] = checkLIR; - if (nextSlot == MAX_HOIST_DISTANCE) break; - } - - /* Found a new place to put the load - move it here */ - if (stopHere == true) { - DEBUG_OPT(dumpDependentInsnPair(checkLIR, thisLIR "HOIST STOP")); - break; - } - } - - /* - * Reached the top - use headLIR as the dependent marker as all labels - * are barriers. - */ - if (stopHere == false && nextSlot < MAX_HOIST_DISTANCE) { - prevInstList[nextSlot++] = headLIR; - } - - /* - * At least one independent instruction is found. Scan in the reversed - * direction to find a beneficial slot. - */ - if (nextSlot >= 2) { - int firstSlot = nextSlot - 2; - int slot; - LIR* depLIR = prevInstList[nextSlot-1]; - /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */ - if (!isPseudoOpcode(depLIR->opcode) && - (EncodingMap[depLIR->opcode].flags & IS_LOAD)) { - firstSlot -= LDLD_DISTANCE; - } - /* - * Make sure we check slot >= 0 since firstSlot may be negative - * when the loop is first entered. - */ - for (slot = firstSlot; slot >= 0; slot--) { - LIR* curLIR = prevInstList[slot]; - LIR* prevLIR = prevInstList[slot+1]; - - /* Check the highest instruction */ - if (prevLIR->defMask == ENCODE_ALL) { - /* - * If the first instruction is a load, don't hoist anything - * above it since it is unlikely to be beneficial. - */ - if (EncodingMap[curLIR->opcode].flags & IS_LOAD) continue; - /* - * If the remaining number of slots is less than LD_LATENCY, - * insert the hoisted load here. - */ - if (slot < LD_LATENCY) break; - } - - // Don't look across a barrier label - if ((prevLIR->opcode == kPseudoTargetLabel) || - (prevLIR->opcode == kPseudoSafepointPC) || - (prevLIR->opcode == kPseudoBarrier)) { - break; - } - - /* - * Try to find two instructions with load/use dependency until - * the remaining instructions are less than LD_LATENCY. - */ - bool prevIsLoad = isPseudoOpcode(prevLIR->opcode) ? false : - (EncodingMap[prevLIR->opcode].flags & IS_LOAD); - if (((curLIR->useMask & prevLIR->defMask) && prevIsLoad) || (slot < LD_LATENCY)) { - break; - } - } - - /* Found a slot to hoist to */ - if (slot >= 0) { - LIR* curLIR = prevInstList[slot]; - LIR* newLoadLIR = (LIR* ) oatNew(cUnit, sizeof(LIR), - true, kAllocLIR); - *newLoadLIR = *thisLIR; - /* - * Insertion is guaranteed to succeed since checkLIR - * is never the first LIR on the list - */ - oatInsertLIRBefore((LIR*) curLIR, (LIR*) newLoadLIR); - thisLIR->flags.isNop = true; - } - } - } -} - -void oatApplyLocalOptimizations(CompilationUnit* cUnit, LIR* headLIR, - LIR* tailLIR) -{ - if (!(cUnit->disableOpt & (1 << kLoadStoreElimination))) { - applyLoadStoreElimination(cUnit, (LIR* ) headLIR, - (LIR* ) tailLIR); - } - if (!(cUnit->disableOpt & (1 << kLoadHoisting))) { - applyLoadHoisting(cUnit, (LIR* ) headLIR, (LIR* ) tailLIR); - } -} - -} // namespace art diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc deleted file mode 100644 index 1e81458dca..0000000000 --- a/src/compiler/codegen/MethodBitcode.cc +++ /dev/null @@ -1,3541 +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. - */ - -#include "object_utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const char* kLabelFormat = "%c0x%x_%d"; -static const char kInvalidBlock = 0xff; -static const char kNormalBlock = 'L'; -static const char kCatchBlock = 'C'; - -namespace art { -extern const RegLocation badLoc; -RegLocation getLoc(CompilationUnit* cUnit, llvm::Value* val); - -llvm::BasicBlock* getLLVMBlock(CompilationUnit* cUnit, int id) -{ - return cUnit->idToBlockMap.Get(id); -} - -llvm::Value* getLLVMValue(CompilationUnit* cUnit, int sReg) -{ - return (llvm::Value*)oatGrowableListGetElement(&cUnit->llvmValues, sReg); -} - -// Replace the placeholder value with the real definition -void defineValue(CompilationUnit* cUnit, llvm::Value* val, int sReg) -{ - llvm::Value* placeholder = getLLVMValue(cUnit, sReg); - if (placeholder == NULL) { - // This can happen on instruction rewrite on verification failure - LOG(WARNING) << "Null placeholder"; - return; - } - placeholder->replaceAllUsesWith(val); - val->takeName(placeholder); - cUnit->llvmValues.elemList[sReg] = (intptr_t)val; - llvm::Instruction* inst = llvm::dyn_cast(placeholder); - DCHECK(inst != NULL); - inst->eraseFromParent(); - - // Set vreg for debugging - if (!cUnit->compiler->IsDebuggingSupported()) { - greenland::IntrinsicHelper::IntrinsicId id = - greenland::IntrinsicHelper::SetVReg; - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - int vReg = SRegToVReg(cUnit, sReg); - llvm::Value* tableSlot = cUnit->irb->getInt32(vReg); - llvm::Value* args[] = { tableSlot, val }; - cUnit->irb->CreateCall(func, args); - } -} - -llvm::Type* llvmTypeFromLocRec(CompilationUnit* cUnit, RegLocation loc) -{ - llvm::Type* res = NULL; - if (loc.wide) { - if (loc.fp) - res = cUnit->irb->getDoubleTy(); - else - res = cUnit->irb->getInt64Ty(); - } else { - if (loc.fp) { - res = cUnit->irb->getFloatTy(); - } else { - if (loc.ref) - res = cUnit->irb->GetJObjectTy(); - else - res = cUnit->irb->getInt32Ty(); - } - } - return res; -} - -/* Create an in-memory RegLocation from an llvm Value. */ -void createLocFromValue(CompilationUnit* cUnit, llvm::Value* val) -{ - // NOTE: llvm takes shortcuts with c_str() - get to std::string firstt - std::string s(val->getName().str()); - const char* valName = s.c_str(); - SafeMap::iterator it = cUnit->locMap.find(val); - DCHECK(it == cUnit->locMap.end()) << " - already defined: " << valName; - int baseSReg = INVALID_SREG; - int subscript = -1; - sscanf(valName, "v%d_%d", &baseSReg, &subscript); - if ((baseSReg == INVALID_SREG) && (!strcmp(valName, "method"))) { - baseSReg = SSA_METHOD_BASEREG; - subscript = 0; - } - DCHECK_NE(baseSReg, INVALID_SREG); - DCHECK_NE(subscript, -1); - // TODO: redo during C++'ification - RegLocation loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, INVALID_REG, - INVALID_REG, INVALID_SREG, INVALID_SREG}; - llvm::Type* ty = val->getType(); - loc.wide = ((ty == cUnit->irb->getInt64Ty()) || - (ty == cUnit->irb->getDoubleTy())); - loc.defined = true; - loc.home = false; // May change during promotion - loc.sRegLow = baseSReg; - loc.origSReg = cUnit->locMap.size(); - PromotionMap pMap = cUnit->promotionMap[baseSReg]; - if (ty == cUnit->irb->getFloatTy()) { - loc.fp = true; - if (pMap.fpLocation == kLocPhysReg) { - loc.lowReg = pMap.fpReg; - loc.location = kLocPhysReg; - loc.home = true; - } - } else if (ty == cUnit->irb->getDoubleTy()) { - loc.fp = true; - PromotionMap pMapHigh = cUnit->promotionMap[baseSReg + 1]; - if ((pMap.fpLocation == kLocPhysReg) && - (pMapHigh.fpLocation == kLocPhysReg) && - ((pMap.fpReg & 0x1) == 0) && - (pMap.fpReg + 1 == pMapHigh.fpReg)) { - loc.lowReg = pMap.fpReg; - loc.highReg = pMapHigh.fpReg; - loc.location = kLocPhysReg; - loc.home = true; - } - } else if (ty == cUnit->irb->GetJObjectTy()) { - loc.ref = true; - if (pMap.coreLocation == kLocPhysReg) { - loc.lowReg = pMap.coreReg; - loc.location = kLocPhysReg; - loc.home = true; - } - } else if (ty == cUnit->irb->getInt64Ty()) { - loc.core = true; - PromotionMap pMapHigh = cUnit->promotionMap[baseSReg + 1]; - if ((pMap.coreLocation == kLocPhysReg) && - (pMapHigh.coreLocation == kLocPhysReg)) { - loc.lowReg = pMap.coreReg; - loc.highReg = pMapHigh.coreReg; - loc.location = kLocPhysReg; - loc.home = true; - } - } else { - loc.core = true; - if (pMap.coreLocation == kLocPhysReg) { - loc.lowReg = pMap.coreReg; - loc.location = kLocPhysReg; - loc.home = true; - } - } - - if (cUnit->printMe && loc.home) { - if (loc.wide) { - LOG(INFO) << "Promoted wide " << s << " to regs " << static_cast(loc.lowReg) - << "/" << loc.highReg; - } else { - LOG(INFO) << "Promoted " << s << " to reg " << static_cast(loc.lowReg); - } - } - cUnit->locMap.Put(val, loc); -} -void initIR(CompilationUnit* cUnit) -{ - LLVMInfo* llvmInfo = cUnit->llvm_info; - if (llvmInfo == NULL) { - CompilerTls* tls = cUnit->compiler->GetTls(); - CHECK(tls != NULL); - llvmInfo = static_cast(tls->GetLLVMInfo()); - if (llvmInfo == NULL) { - llvmInfo = new LLVMInfo(); - tls->SetLLVMInfo(llvmInfo); - } - } - cUnit->context = llvmInfo->GetLLVMContext(); - cUnit->module = llvmInfo->GetLLVMModule(); - cUnit->intrinsic_helper = llvmInfo->GetIntrinsicHelper(); - cUnit->irb = llvmInfo->GetIRBuilder(); -} - -const char* llvmSSAName(CompilationUnit* cUnit, int ssaReg) { - return GET_ELEM_N(cUnit->ssaStrings, char*, ssaReg); -} - -llvm::BasicBlock* findCaseTarget(CompilationUnit* cUnit, uint32_t vaddr) -{ - BasicBlock* bb = oatFindBlock(cUnit, vaddr); - DCHECK(bb != NULL); - return getLLVMBlock(cUnit, bb->id); -} - -void convertPackedSwitch(CompilationUnit* cUnit, BasicBlock* bb, - int32_t tableOffset, RegLocation rlSrc) -{ - const Instruction::PackedSwitchPayload* payload = - reinterpret_cast( - cUnit->insns + cUnit->currentDalvikOffset + tableOffset); - - llvm::Value* value = getLLVMValue(cUnit, rlSrc.origSReg); - - llvm::SwitchInst* sw = - cUnit->irb->CreateSwitch(value, getLLVMBlock(cUnit, bb->fallThrough->id), - payload->case_count); - - for (uint16_t i = 0; i < payload->case_count; ++i) { - llvm::BasicBlock* llvmBB = - findCaseTarget(cUnit, cUnit->currentDalvikOffset + payload->targets[i]); - sw->addCase(cUnit->irb->getInt32(payload->first_key + i), llvmBB); - } - llvm::MDNode* switchNode = - llvm::MDNode::get(*cUnit->context, cUnit->irb->getInt32(tableOffset)); - sw->setMetadata("SwitchTable", switchNode); - bb->taken = NULL; - bb->fallThrough = NULL; -} - -void convertSparseSwitch(CompilationUnit* cUnit, BasicBlock* bb, - int32_t tableOffset, RegLocation rlSrc) -{ - const Instruction::SparseSwitchPayload* payload = - reinterpret_cast( - cUnit->insns + cUnit->currentDalvikOffset + tableOffset); - - const int32_t* keys = payload->GetKeys(); - const int32_t* targets = payload->GetTargets(); - - llvm::Value* value = getLLVMValue(cUnit, rlSrc.origSReg); - - llvm::SwitchInst* sw = - cUnit->irb->CreateSwitch(value, getLLVMBlock(cUnit, bb->fallThrough->id), - payload->case_count); - - for (size_t i = 0; i < payload->case_count; ++i) { - llvm::BasicBlock* llvmBB = - findCaseTarget(cUnit, cUnit->currentDalvikOffset + targets[i]); - sw->addCase(cUnit->irb->getInt32(keys[i]), llvmBB); - } - llvm::MDNode* switchNode = - llvm::MDNode::get(*cUnit->context, cUnit->irb->getInt32(tableOffset)); - sw->setMetadata("SwitchTable", switchNode); - bb->taken = NULL; - bb->fallThrough = NULL; -} - -void convertSget(CompilationUnit* cUnit, int32_t fieldIndex, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest) -{ - llvm::Constant* fieldIdx = cUnit->irb->getInt32(fieldIndex); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = cUnit->irb->CreateCall(intr, fieldIdx); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertSput(CompilationUnit* cUnit, int32_t fieldIndex, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlSrc) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(fieldIndex)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(intr, args); -} - -void convertFillArrayData(CompilationUnit* cUnit, int32_t offset, - RegLocation rlArray) -{ - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::HLFillArrayData; - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(offset)); - args.push_back(getLLVMValue(cUnit, rlArray.origSReg)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(intr, args); -} - -llvm::Value* emitConst(CompilationUnit* cUnit, llvm::ArrayRef src, - RegLocation loc) -{ - greenland::IntrinsicHelper::IntrinsicId id; - if (loc.wide) { - if (loc.fp) { - id = greenland::IntrinsicHelper::ConstDouble; - } else { - id = greenland::IntrinsicHelper::ConstLong; - } - } else { - if (loc.fp) { - id = greenland::IntrinsicHelper::ConstFloat; - } else if (loc.ref) { - id = greenland::IntrinsicHelper::ConstObj; - } else { - id = greenland::IntrinsicHelper::ConstInt; - } - } - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - return cUnit->irb->CreateCall(intr, src); -} - -void emitPopShadowFrame(CompilationUnit* cUnit) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction( - greenland::IntrinsicHelper::PopShadowFrame); - cUnit->irb->CreateCall(intr); -} - -llvm::Value* emitCopy(CompilationUnit* cUnit, llvm::ArrayRef src, - RegLocation loc) -{ - greenland::IntrinsicHelper::IntrinsicId id; - if (loc.wide) { - if (loc.fp) { - id = greenland::IntrinsicHelper::CopyDouble; - } else { - id = greenland::IntrinsicHelper::CopyLong; - } - } else { - if (loc.fp) { - id = greenland::IntrinsicHelper::CopyFloat; - } else if (loc.ref) { - id = greenland::IntrinsicHelper::CopyObj; - } else { - id = greenland::IntrinsicHelper::CopyInt; - } - } - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - return cUnit->irb->CreateCall(intr, src); -} - -void convertMoveException(CompilationUnit* cUnit, RegLocation rlDest) -{ - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction( - greenland::IntrinsicHelper::GetException); - llvm::Value* res = cUnit->irb->CreateCall(func); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertThrow(CompilationUnit* cUnit, RegLocation rlSrc) -{ - llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg); - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction( - greenland::IntrinsicHelper::HLThrowException); - cUnit->irb->CreateCall(func, src); -} - -void convertMonitorEnterExit(CompilationUnit* cUnit, int optFlags, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlSrc) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(func, args); -} - -void convertArrayLength(CompilationUnit* cUnit, int optFlags, - RegLocation rlDest, RegLocation rlSrc) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction( - greenland::IntrinsicHelper::OptArrayLength); - llvm::Value* res = cUnit->irb->CreateCall(func, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void emitSuspendCheck(CompilationUnit* cUnit) -{ - greenland::IntrinsicHelper::IntrinsicId id = - greenland::IntrinsicHelper::CheckSuspend; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(intr); -} - -llvm::Value* convertCompare(CompilationUnit* cUnit, ConditionCode cc, - llvm::Value* src1, llvm::Value* src2) -{ - llvm::Value* res = NULL; - DCHECK_EQ(src1->getType(), src2->getType()); - switch(cc) { - case kCondEq: res = cUnit->irb->CreateICmpEQ(src1, src2); break; - case kCondNe: res = cUnit->irb->CreateICmpNE(src1, src2); break; - case kCondLt: res = cUnit->irb->CreateICmpSLT(src1, src2); break; - case kCondGe: res = cUnit->irb->CreateICmpSGE(src1, src2); break; - case kCondGt: res = cUnit->irb->CreateICmpSGT(src1, src2); break; - case kCondLe: res = cUnit->irb->CreateICmpSLE(src1, src2); break; - default: LOG(FATAL) << "Unexpected cc value " << cc; - } - return res; -} - -void convertCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - ConditionCode cc, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - if (bb->taken->startOffset <= mir->offset) { - emitSuspendCheck(cUnit); - } - llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg); - llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg); - llvm::Value* condValue = convertCompare(cUnit, cc, src1, src2); - condValue->setName(StringPrintf("t%d", cUnit->tempName++)); - cUnit->irb->CreateCondBr(condValue, getLLVMBlock(cUnit, bb->taken->id), - getLLVMBlock(cUnit, bb->fallThrough->id)); - // Don't redo the fallthrough branch in the BB driver - bb->fallThrough = NULL; -} - -void convertCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, - MIR* mir, ConditionCode cc, RegLocation rlSrc1) -{ - if (bb->taken->startOffset <= mir->offset) { - emitSuspendCheck(cUnit); - } - llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg); - llvm::Value* src2; - if (rlSrc1.ref) { - src2 = cUnit->irb->GetJNull(); - } else { - src2 = cUnit->irb->getInt32(0); - } - llvm::Value* condValue = convertCompare(cUnit, cc, src1, src2); - cUnit->irb->CreateCondBr(condValue, getLLVMBlock(cUnit, bb->taken->id), - getLLVMBlock(cUnit, bb->fallThrough->id)); - // Don't redo the fallthrough branch in the BB driver - bb->fallThrough = NULL; -} - -llvm::Value* genDivModOp(CompilationUnit* cUnit, bool isDiv, bool isLong, - llvm::Value* src1, llvm::Value* src2) -{ - greenland::IntrinsicHelper::IntrinsicId id; - if (isLong) { - if (isDiv) { - id = greenland::IntrinsicHelper::DivLong; - } else { - id = greenland::IntrinsicHelper::RemLong; - } - } else { - if (isDiv) { - id = greenland::IntrinsicHelper::DivInt; - } else { - id = greenland::IntrinsicHelper::RemInt; - } - } - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVectorargs; - args.push_back(src1); - args.push_back(src2); - return cUnit->irb->CreateCall(intr, args); -} - -llvm::Value* genArithOp(CompilationUnit* cUnit, OpKind op, bool isLong, - llvm::Value* src1, llvm::Value* src2) -{ - llvm::Value* res = NULL; - switch(op) { - case kOpAdd: res = cUnit->irb->CreateAdd(src1, src2); break; - case kOpSub: res = cUnit->irb->CreateSub(src1, src2); break; - case kOpRsub: res = cUnit->irb->CreateSub(src2, src1); break; - case kOpMul: res = cUnit->irb->CreateMul(src1, src2); break; - case kOpOr: res = cUnit->irb->CreateOr(src1, src2); break; - case kOpAnd: res = cUnit->irb->CreateAnd(src1, src2); break; - case kOpXor: res = cUnit->irb->CreateXor(src1, src2); break; - case kOpDiv: res = genDivModOp(cUnit, true, isLong, src1, src2); break; - case kOpRem: res = genDivModOp(cUnit, false, isLong, src1, src2); break; - case kOpLsl: res = cUnit->irb->CreateShl(src1, src2); break; - case kOpLsr: res = cUnit->irb->CreateLShr(src1, src2); break; - case kOpAsr: res = cUnit->irb->CreateAShr(src1, src2); break; - default: - LOG(FATAL) << "Invalid op " << op; - } - return res; -} - -void convertFPArithOp(CompilationUnit* cUnit, OpKind op, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg); - llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg); - llvm::Value* res = NULL; - switch(op) { - case kOpAdd: res = cUnit->irb->CreateFAdd(src1, src2); break; - case kOpSub: res = cUnit->irb->CreateFSub(src1, src2); break; - case kOpMul: res = cUnit->irb->CreateFMul(src1, src2); break; - case kOpDiv: res = cUnit->irb->CreateFDiv(src1, src2); break; - case kOpRem: res = cUnit->irb->CreateFRem(src1, src2); break; - default: - LOG(FATAL) << "Invalid op " << op; - } - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertShift(CompilationUnit* cUnit, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVectorargs; - args.push_back(getLLVMValue(cUnit, rlSrc1.origSReg)); - args.push_back(getLLVMValue(cUnit, rlSrc2.origSReg)); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertShiftLit(CompilationUnit* cUnit, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, RegLocation rlSrc, int shiftAmount) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVectorargs; - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - args.push_back(cUnit->irb->getInt32(shiftAmount)); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertArithOp(CompilationUnit* cUnit, OpKind op, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg); - llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg); - DCHECK_EQ(src1->getType(), src2->getType()); - llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2); - defineValue(cUnit, res, rlDest.origSReg); -} - -void setShadowFrameEntry(CompilationUnit* cUnit, llvm::Value* newVal) -{ - int index = -1; - DCHECK(newVal != NULL); - int vReg = SRegToVReg(cUnit, getLoc(cUnit, newVal).origSReg); - for (int i = 0; i < cUnit->numShadowFrameEntries; i++) { - if (cUnit->shadowMap[i] == vReg) { - index = i; - break; - } - } - if (index == -1) { - return; - } - llvm::Type* ty = newVal->getType(); - greenland::IntrinsicHelper::IntrinsicId id = - greenland::IntrinsicHelper::SetShadowFrameEntry; - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* tableSlot = cUnit->irb->getInt32(index); - // If newVal is a Null pointer, we'll see it here as a const int. Replace - if (!ty->isPointerTy()) { - // TODO: assert newVal created w/ dex_lang_const_int(0) or dex_lang_const_float(0) - newVal = cUnit->irb->GetJNull(); - } - llvm::Value* args[] = { newVal, tableSlot }; - cUnit->irb->CreateCall(func, args); -} - -void convertArithOpLit(CompilationUnit* cUnit, OpKind op, RegLocation rlDest, - RegLocation rlSrc1, int32_t imm) -{ - llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg); - llvm::Value* src2 = cUnit->irb->getInt32(imm); - llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2); - defineValue(cUnit, res, rlDest.origSReg); -} - -/* - * Process arguments for invoke. Note: this code is also used to - * collect and process arguments for NEW_FILLED_ARRAY and NEW_FILLED_ARRAY_RANGE. - * The requirements are similar. - */ -void convertInvoke(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - InvokeType invokeType, bool isRange, bool isFilledNewArray) -{ - CallInfo* info = oatNewCallInfo(cUnit, bb, mir, invokeType, isRange); - llvm::SmallVector args; - // Insert the invokeType - args.push_back(cUnit->irb->getInt32(static_cast(invokeType))); - // Insert the method_idx - args.push_back(cUnit->irb->getInt32(info->index)); - // Insert the optimization flags - args.push_back(cUnit->irb->getInt32(info->optFlags)); - // Now, insert the actual arguments - for (int i = 0; i < info->numArgWords;) { - llvm::Value* val = getLLVMValue(cUnit, info->args[i].origSReg); - args.push_back(val); - i += info->args[i].wide ? 2 : 1; - } - /* - * Choose the invoke return type based on actual usage. Note: may - * be different than shorty. For example, if a function return value - * is not used, we'll treat this as a void invoke. - */ - greenland::IntrinsicHelper::IntrinsicId id; - if (isFilledNewArray) { - id = greenland::IntrinsicHelper::HLFilledNewArray; - } else if (info->result.location == kLocInvalid) { - id = greenland::IntrinsicHelper::HLInvokeVoid; - } else { - if (info->result.wide) { - if (info->result.fp) { - id = greenland::IntrinsicHelper::HLInvokeDouble; - } else { - id = greenland::IntrinsicHelper::HLInvokeLong; - } - } else if (info->result.ref) { - id = greenland::IntrinsicHelper::HLInvokeObj; - } else if (info->result.fp) { - id = greenland::IntrinsicHelper::HLInvokeFloat; - } else { - id = greenland::IntrinsicHelper::HLInvokeInt; - } - } - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - if (info->result.location != kLocInvalid) { - defineValue(cUnit, res, info->result.origSReg); - if (info->result.ref) { - setShadowFrameEntry(cUnit, (llvm::Value*) - cUnit->llvmValues.elemList[info->result.origSReg]); - } - } -} - -void convertConstObject(CompilationUnit* cUnit, uint32_t idx, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* index = cUnit->irb->getInt32(idx); - llvm::Value* res = cUnit->irb->CreateCall(intr, index); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertCheckCast(CompilationUnit* cUnit, uint32_t type_idx, - RegLocation rlSrc) -{ - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::HLCheckCast; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(type_idx)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - cUnit->irb->CreateCall(intr, args); -} - -void convertNewInstance(CompilationUnit* cUnit, uint32_t type_idx, - RegLocation rlDest) -{ - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::NewInstance; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* index = cUnit->irb->getInt32(type_idx); - llvm::Value* res = cUnit->irb->CreateCall(intr, index); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertNewArray(CompilationUnit* cUnit, uint32_t type_idx, - RegLocation rlDest, RegLocation rlSrc) -{ - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::NewArray; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(type_idx)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertAget(CompilationUnit* cUnit, int optFlags, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, RegLocation rlArray, RegLocation rlIndex) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlArray.origSReg)); - args.push_back(getLLVMValue(cUnit, rlIndex.origSReg)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertAput(CompilationUnit* cUnit, int optFlags, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlSrc, RegLocation rlArray, RegLocation rlIndex) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - args.push_back(getLLVMValue(cUnit, rlArray.origSReg)); - args.push_back(getLLVMValue(cUnit, rlIndex.origSReg)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(intr, args); -} - -void convertIget(CompilationUnit* cUnit, int optFlags, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, RegLocation rlObj, int fieldIndex) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlObj.origSReg)); - args.push_back(cUnit->irb->getInt32(fieldIndex)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertIput(CompilationUnit* cUnit, int optFlags, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlSrc, RegLocation rlObj, int fieldIndex) -{ - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(optFlags)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - args.push_back(getLLVMValue(cUnit, rlObj.origSReg)); - args.push_back(cUnit->irb->getInt32(fieldIndex)); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - cUnit->irb->CreateCall(intr, args); -} - -void convertInstanceOf(CompilationUnit* cUnit, uint32_t type_idx, - RegLocation rlDest, RegLocation rlSrc) -{ - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::InstanceOf; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVector args; - args.push_back(cUnit->irb->getInt32(type_idx)); - args.push_back(getLLVMValue(cUnit, rlSrc.origSReg)); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertIntToLong(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* res = cUnit->irb->CreateSExt(getLLVMValue(cUnit, rlSrc.origSReg), - cUnit->irb->getInt64Ty()); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertLongToInt(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg); - llvm::Value* res = cUnit->irb->CreateTrunc(src, cUnit->irb->getInt32Ty()); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertFloatToDouble(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg); - llvm::Value* res = cUnit->irb->CreateFPExt(src, cUnit->irb->getDoubleTy()); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertDoubleToFloat(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg); - llvm::Value* res = cUnit->irb->CreateFPTrunc(src, cUnit->irb->getFloatTy()); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertWideComparison(CompilationUnit* cUnit, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - DCHECK_EQ(rlSrc1.fp, rlSrc2.fp); - DCHECK_EQ(rlSrc1.wide, rlSrc2.wide); - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::SmallVector args; - args.push_back(getLLVMValue(cUnit, rlSrc1.origSReg)); - args.push_back(getLLVMValue(cUnit, rlSrc2.origSReg)); - llvm::Value* res = cUnit->irb->CreateCall(intr, args); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertIntNarrowing(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc, - greenland::IntrinsicHelper::IntrinsicId id) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = - cUnit->irb->CreateCall(intr, getLLVMValue(cUnit, rlSrc.origSReg)); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertNeg(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* res = cUnit->irb->CreateNeg(getLLVMValue(cUnit, rlSrc.origSReg)); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertIntToFP(CompilationUnit* cUnit, llvm::Type* ty, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* res = - cUnit->irb->CreateSIToFP(getLLVMValue(cUnit, rlSrc.origSReg), ty); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertFPToInt(CompilationUnit* cUnit, - greenland::IntrinsicHelper::IntrinsicId id, - RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* res = cUnit->irb->CreateCall(intr, getLLVMValue(cUnit, rlSrc.origSReg)); - defineValue(cUnit, res, rlDest.origSReg); -} - - -void convertNegFP(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* res = - cUnit->irb->CreateFNeg(getLLVMValue(cUnit, rlSrc.origSReg)); - defineValue(cUnit, res, rlDest.origSReg); -} - -void convertNot(CompilationUnit* cUnit, RegLocation rlDest, - RegLocation rlSrc) -{ - llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg); - llvm::Value* res = cUnit->irb->CreateXor(src, static_cast(-1)); - defineValue(cUnit, res, rlDest.origSReg); -} - -/* - * Target-independent code generation. Use only high-level - * load/store utilities here, or target-dependent genXX() handlers - * when necessary. - */ -bool convertMIRNode(CompilationUnit* cUnit, MIR* mir, BasicBlock* bb, - llvm::BasicBlock* llvmBB, LIR* labelList) -{ - bool res = false; // Assume success - RegLocation rlSrc[3]; - RegLocation rlDest = badLoc; - Instruction::Code opcode = mir->dalvikInsn.opcode; - uint32_t vB = mir->dalvikInsn.vB; - uint32_t vC = mir->dalvikInsn.vC; - int optFlags = mir->optimizationFlags; - - bool objectDefinition = false; - - if (cUnit->printMe) { - if ((int)opcode < kMirOpFirst) { - LOG(INFO) << ".. " << Instruction::Name(opcode) << " 0x" - << std::hex << (int)opcode; - } else { - LOG(INFO) << ".. opcode 0x" << std::hex << (int)opcode; - } - } - - /* Prep Src and Dest locations */ - int nextSreg = 0; - int nextLoc = 0; - int attrs = oatDataFlowAttributes[opcode]; - rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc; - if (attrs & DF_UA) { - if (attrs & DF_A_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - nextSreg+= 2; - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - nextSreg++; - } - } - if (attrs & DF_UB) { - if (attrs & DF_B_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - nextSreg+= 2; - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - nextSreg++; - } - } - if (attrs & DF_UC) { - if (attrs & DF_C_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - } - } - if (attrs & DF_DA) { - if (attrs & DF_A_WIDE) { - rlDest = oatGetDestWide(cUnit, mir); - } else { - rlDest = oatGetDest(cUnit, mir); - if (rlDest.ref) { - objectDefinition = true; - } - } - } - - switch (opcode) { - case Instruction::NOP: - break; - - case Instruction::MOVE: - case Instruction::MOVE_OBJECT: - case Instruction::MOVE_16: - case Instruction::MOVE_OBJECT_16: - case Instruction::MOVE_OBJECT_FROM16: - case Instruction::MOVE_FROM16: - case Instruction::MOVE_WIDE: - case Instruction::MOVE_WIDE_16: - case Instruction::MOVE_WIDE_FROM16: { - /* - * Moves/copies are meaningless in pure SSA register form, - * but we need to preserve them for the conversion back into - * MIR (at least until we stop using the Dalvik register maps). - * Insert a dummy intrinsic copy call, which will be recognized - * by the quick path and removed by the portable path. - */ - llvm::Value* src = getLLVMValue(cUnit, rlSrc[0].origSReg); - llvm::Value* res = emitCopy(cUnit, src, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - - case Instruction::CONST: - case Instruction::CONST_4: - case Instruction::CONST_16: { - if (vB == 0) { - objectDefinition = true; - } - llvm::Constant* immValue = cUnit->irb->GetJInt(vB); - llvm::Value* res = emitConst(cUnit, immValue, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - - case Instruction::CONST_WIDE_16: - case Instruction::CONST_WIDE_32: { - // Sign extend to 64 bits - int64_t imm = static_cast(vB); - llvm::Constant* immValue = cUnit->irb->GetJLong(imm); - llvm::Value* res = emitConst(cUnit, immValue, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - - case Instruction::CONST_HIGH16: { - llvm::Constant* immValue = cUnit->irb->GetJInt(vB << 16); - llvm::Value* res = emitConst(cUnit, immValue, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - - case Instruction::CONST_WIDE: { - llvm::Constant* immValue = - cUnit->irb->GetJLong(mir->dalvikInsn.vB_wide); - llvm::Value* res = emitConst(cUnit, immValue, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - case Instruction::CONST_WIDE_HIGH16: { - int64_t imm = static_cast(vB) << 48; - llvm::Constant* immValue = cUnit->irb->GetJLong(imm); - llvm::Value* res = emitConst(cUnit, immValue, rlDest); - defineValue(cUnit, res, rlDest.origSReg); - } - break; - - case Instruction::SPUT_OBJECT: - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputObject, - rlSrc[0]); - break; - case Instruction::SPUT: - if (rlSrc[0].fp) { - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputFloat, - rlSrc[0]); - } else { - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSput, rlSrc[0]); - } - break; - case Instruction::SPUT_BOOLEAN: - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputBoolean, - rlSrc[0]); - break; - case Instruction::SPUT_BYTE: - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputByte, rlSrc[0]); - break; - case Instruction::SPUT_CHAR: - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputChar, rlSrc[0]); - break; - case Instruction::SPUT_SHORT: - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputShort, rlSrc[0]); - break; - case Instruction::SPUT_WIDE: - if (rlSrc[0].fp) { - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputDouble, - rlSrc[0]); - } else { - convertSput(cUnit, vB, greenland::IntrinsicHelper::HLSputWide, - rlSrc[0]); - } - break; - - case Instruction::SGET_OBJECT: - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetObject, rlDest); - break; - case Instruction::SGET: - if (rlDest.fp) { - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetFloat, rlDest); - } else { - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSget, rlDest); - } - break; - case Instruction::SGET_BOOLEAN: - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetBoolean, rlDest); - break; - case Instruction::SGET_BYTE: - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetByte, rlDest); - break; - case Instruction::SGET_CHAR: - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetChar, rlDest); - break; - case Instruction::SGET_SHORT: - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetShort, rlDest); - break; - case Instruction::SGET_WIDE: - if (rlDest.fp) { - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetDouble, - rlDest); - } else { - convertSget(cUnit, vB, greenland::IntrinsicHelper::HLSgetWide, rlDest); - } - break; - - case Instruction::RETURN_WIDE: - case Instruction::RETURN: - case Instruction::RETURN_OBJECT: { - if (!(cUnit->attrs & METHOD_IS_LEAF)) { - emitSuspendCheck(cUnit); - } - emitPopShadowFrame(cUnit); - cUnit->irb->CreateRet(getLLVMValue(cUnit, rlSrc[0].origSReg)); - bb->hasReturn = true; - } - break; - - case Instruction::RETURN_VOID: { - if (!(cUnit->attrs & METHOD_IS_LEAF)) { - emitSuspendCheck(cUnit); - } - emitPopShadowFrame(cUnit); - cUnit->irb->CreateRetVoid(); - bb->hasReturn = true; - } - break; - - case Instruction::IF_EQ: - convertCompareAndBranch(cUnit, bb, mir, kCondEq, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_NE: - convertCompareAndBranch(cUnit, bb, mir, kCondNe, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_LT: - convertCompareAndBranch(cUnit, bb, mir, kCondLt, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_GE: - convertCompareAndBranch(cUnit, bb, mir, kCondGe, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_GT: - convertCompareAndBranch(cUnit, bb, mir, kCondGt, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_LE: - convertCompareAndBranch(cUnit, bb, mir, kCondLe, rlSrc[0], rlSrc[1]); - break; - case Instruction::IF_EQZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondEq, rlSrc[0]); - break; - case Instruction::IF_NEZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondNe, rlSrc[0]); - break; - case Instruction::IF_LTZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondLt, rlSrc[0]); - break; - case Instruction::IF_GEZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondGe, rlSrc[0]); - break; - case Instruction::IF_GTZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondGt, rlSrc[0]); - break; - case Instruction::IF_LEZ: - convertCompareZeroAndBranch(cUnit, bb, mir, kCondLe, rlSrc[0]); - break; - - case Instruction::GOTO: - case Instruction::GOTO_16: - case Instruction::GOTO_32: { - if (bb->taken->startOffset <= bb->startOffset) { - emitSuspendCheck(cUnit); - } - cUnit->irb->CreateBr(getLLVMBlock(cUnit, bb->taken->id)); - } - break; - - case Instruction::ADD_LONG: - case Instruction::ADD_LONG_2ADDR: - case Instruction::ADD_INT: - case Instruction::ADD_INT_2ADDR: - convertArithOp(cUnit, kOpAdd, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::SUB_LONG: - case Instruction::SUB_LONG_2ADDR: - case Instruction::SUB_INT: - case Instruction::SUB_INT_2ADDR: - convertArithOp(cUnit, kOpSub, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::MUL_LONG: - case Instruction::MUL_LONG_2ADDR: - case Instruction::MUL_INT: - case Instruction::MUL_INT_2ADDR: - convertArithOp(cUnit, kOpMul, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::DIV_LONG: - case Instruction::DIV_LONG_2ADDR: - case Instruction::DIV_INT: - case Instruction::DIV_INT_2ADDR: - convertArithOp(cUnit, kOpDiv, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::REM_LONG: - case Instruction::REM_LONG_2ADDR: - case Instruction::REM_INT: - case Instruction::REM_INT_2ADDR: - convertArithOp(cUnit, kOpRem, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AND_LONG: - case Instruction::AND_LONG_2ADDR: - case Instruction::AND_INT: - case Instruction::AND_INT_2ADDR: - convertArithOp(cUnit, kOpAnd, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::OR_LONG: - case Instruction::OR_LONG_2ADDR: - case Instruction::OR_INT: - case Instruction::OR_INT_2ADDR: - convertArithOp(cUnit, kOpOr, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::XOR_LONG: - case Instruction::XOR_LONG_2ADDR: - case Instruction::XOR_INT: - case Instruction::XOR_INT_2ADDR: - convertArithOp(cUnit, kOpXor, rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::SHL_LONG: - case Instruction::SHL_LONG_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::SHLLong, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::SHL_INT: - case Instruction::SHL_INT_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::SHLInt, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::SHR_LONG: - case Instruction::SHR_LONG_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::SHRLong, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::SHR_INT: - case Instruction::SHR_INT_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::SHRInt, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::USHR_LONG: - case Instruction::USHR_LONG_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::USHRLong, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::USHR_INT: - case Instruction::USHR_INT_2ADDR: - convertShift(cUnit, greenland::IntrinsicHelper::USHRInt, - rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::ADD_INT_LIT16: - case Instruction::ADD_INT_LIT8: - convertArithOpLit(cUnit, kOpAdd, rlDest, rlSrc[0], vC); - break; - case Instruction::RSUB_INT: - case Instruction::RSUB_INT_LIT8: - convertArithOpLit(cUnit, kOpRsub, rlDest, rlSrc[0], vC); - break; - case Instruction::MUL_INT_LIT16: - case Instruction::MUL_INT_LIT8: - convertArithOpLit(cUnit, kOpMul, rlDest, rlSrc[0], vC); - break; - case Instruction::DIV_INT_LIT16: - case Instruction::DIV_INT_LIT8: - convertArithOpLit(cUnit, kOpDiv, rlDest, rlSrc[0], vC); - break; - case Instruction::REM_INT_LIT16: - case Instruction::REM_INT_LIT8: - convertArithOpLit(cUnit, kOpRem, rlDest, rlSrc[0], vC); - break; - case Instruction::AND_INT_LIT16: - case Instruction::AND_INT_LIT8: - convertArithOpLit(cUnit, kOpAnd, rlDest, rlSrc[0], vC); - break; - case Instruction::OR_INT_LIT16: - case Instruction::OR_INT_LIT8: - convertArithOpLit(cUnit, kOpOr, rlDest, rlSrc[0], vC); - break; - case Instruction::XOR_INT_LIT16: - case Instruction::XOR_INT_LIT8: - convertArithOpLit(cUnit, kOpXor, rlDest, rlSrc[0], vC); - break; - case Instruction::SHL_INT_LIT8: - convertShiftLit(cUnit, greenland::IntrinsicHelper::SHLInt, - rlDest, rlSrc[0], vC & 0x1f); - break; - case Instruction::SHR_INT_LIT8: - convertShiftLit(cUnit, greenland::IntrinsicHelper::SHRInt, - rlDest, rlSrc[0], vC & 0x1f); - break; - case Instruction::USHR_INT_LIT8: - convertShiftLit(cUnit, greenland::IntrinsicHelper::USHRInt, - rlDest, rlSrc[0], vC & 0x1f); - break; - - case Instruction::ADD_FLOAT: - case Instruction::ADD_FLOAT_2ADDR: - case Instruction::ADD_DOUBLE: - case Instruction::ADD_DOUBLE_2ADDR: - convertFPArithOp(cUnit, kOpAdd, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::SUB_FLOAT: - case Instruction::SUB_FLOAT_2ADDR: - case Instruction::SUB_DOUBLE: - case Instruction::SUB_DOUBLE_2ADDR: - convertFPArithOp(cUnit, kOpSub, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::MUL_FLOAT: - case Instruction::MUL_FLOAT_2ADDR: - case Instruction::MUL_DOUBLE: - case Instruction::MUL_DOUBLE_2ADDR: - convertFPArithOp(cUnit, kOpMul, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::DIV_FLOAT: - case Instruction::DIV_FLOAT_2ADDR: - case Instruction::DIV_DOUBLE: - case Instruction::DIV_DOUBLE_2ADDR: - convertFPArithOp(cUnit, kOpDiv, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::REM_FLOAT: - case Instruction::REM_FLOAT_2ADDR: - case Instruction::REM_DOUBLE: - case Instruction::REM_DOUBLE_2ADDR: - convertFPArithOp(cUnit, kOpRem, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::INVOKE_STATIC: - convertInvoke(cUnit, bb, mir, kStatic, false /*range*/, - false /* NewFilledArray */); - break; - case Instruction::INVOKE_STATIC_RANGE: - convertInvoke(cUnit, bb, mir, kStatic, true /*range*/, - false /* NewFilledArray */); - break; - - case Instruction::INVOKE_DIRECT: - convertInvoke(cUnit, bb, mir, kDirect, false /*range*/, - false /* NewFilledArray */); - break; - case Instruction::INVOKE_DIRECT_RANGE: - convertInvoke(cUnit, bb, mir, kDirect, true /*range*/, - false /* NewFilledArray */); - break; - - case Instruction::INVOKE_VIRTUAL: - convertInvoke(cUnit, bb, mir, kVirtual, false /*range*/, - false /* NewFilledArray */); - break; - case Instruction::INVOKE_VIRTUAL_RANGE: - convertInvoke(cUnit, bb, mir, kVirtual, true /*range*/, - false /* NewFilledArray */); - break; - - case Instruction::INVOKE_SUPER: - convertInvoke(cUnit, bb, mir, kSuper, false /*range*/, - false /* NewFilledArray */); - break; - case Instruction::INVOKE_SUPER_RANGE: - convertInvoke(cUnit, bb, mir, kSuper, true /*range*/, - false /* NewFilledArray */); - break; - - case Instruction::INVOKE_INTERFACE: - convertInvoke(cUnit, bb, mir, kInterface, false /*range*/, - false /* NewFilledArray */); - break; - case Instruction::INVOKE_INTERFACE_RANGE: - convertInvoke(cUnit, bb, mir, kInterface, true /*range*/, - false /* NewFilledArray */); - break; - case Instruction::FILLED_NEW_ARRAY: - convertInvoke(cUnit, bb, mir, kInterface, false /*range*/, - true /* NewFilledArray */); - break; - case Instruction::FILLED_NEW_ARRAY_RANGE: - convertInvoke(cUnit, bb, mir, kInterface, true /*range*/, - true /* NewFilledArray */); - break; - - case Instruction::CONST_STRING: - case Instruction::CONST_STRING_JUMBO: - convertConstObject(cUnit, vB, greenland::IntrinsicHelper::ConstString, - rlDest); - break; - - case Instruction::CONST_CLASS: - convertConstObject(cUnit, vB, greenland::IntrinsicHelper::ConstClass, - rlDest); - break; - - case Instruction::CHECK_CAST: - convertCheckCast(cUnit, vB, rlSrc[0]); - break; - - case Instruction::NEW_INSTANCE: - convertNewInstance(cUnit, vB, rlDest); - break; - - case Instruction::MOVE_EXCEPTION: - convertMoveException(cUnit, rlDest); - break; - - case Instruction::THROW: - convertThrow(cUnit, rlSrc[0]); - /* - * If this throw is standalone, terminate. - * If it might rethrow, force termination - * of the following block. - */ - if (bb->fallThrough == NULL) { - cUnit->irb->CreateUnreachable(); - } else { - bb->fallThrough->fallThrough = NULL; - bb->fallThrough->taken = NULL; - } - break; - - case Instruction::MOVE_RESULT_WIDE: - case Instruction::MOVE_RESULT: - case Instruction::MOVE_RESULT_OBJECT: - /* - * All move_results should have been folded into the preceeding invoke. - */ - LOG(FATAL) << "Unexpected move_result"; - break; - - case Instruction::MONITOR_ENTER: - convertMonitorEnterExit(cUnit, optFlags, - greenland::IntrinsicHelper::MonitorEnter, - rlSrc[0]); - break; - - case Instruction::MONITOR_EXIT: - convertMonitorEnterExit(cUnit, optFlags, - greenland::IntrinsicHelper::MonitorExit, - rlSrc[0]); - break; - - case Instruction::ARRAY_LENGTH: - convertArrayLength(cUnit, optFlags, rlDest, rlSrc[0]); - break; - - case Instruction::NEW_ARRAY: - convertNewArray(cUnit, vC, rlDest, rlSrc[0]); - break; - - case Instruction::INSTANCE_OF: - convertInstanceOf(cUnit, vC, rlDest, rlSrc[0]); - break; - - case Instruction::AGET: - if (rlDest.fp) { - convertAget(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayGetFloat, - rlDest, rlSrc[0], rlSrc[1]); - } else { - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGet, - rlDest, rlSrc[0], rlSrc[1]); - } - break; - case Instruction::AGET_OBJECT: - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGetObject, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AGET_BOOLEAN: - convertAget(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayGetBoolean, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AGET_BYTE: - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGetByte, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AGET_CHAR: - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGetChar, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AGET_SHORT: - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGetShort, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::AGET_WIDE: - if (rlDest.fp) { - convertAget(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayGetDouble, - rlDest, rlSrc[0], rlSrc[1]); - } else { - convertAget(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayGetWide, - rlDest, rlSrc[0], rlSrc[1]); - } - break; - - case Instruction::APUT: - if (rlSrc[0].fp) { - convertAput(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayPutFloat, - rlSrc[0], rlSrc[1], rlSrc[2]); - } else { - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPut, - rlSrc[0], rlSrc[1], rlSrc[2]); - } - break; - case Instruction::APUT_OBJECT: - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPutObject, - rlSrc[0], rlSrc[1], rlSrc[2]); - break; - case Instruction::APUT_BOOLEAN: - convertAput(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayPutBoolean, - rlSrc[0], rlSrc[1], rlSrc[2]); - break; - case Instruction::APUT_BYTE: - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPutByte, - rlSrc[0], rlSrc[1], rlSrc[2]); - break; - case Instruction::APUT_CHAR: - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPutChar, - rlSrc[0], rlSrc[1], rlSrc[2]); - break; - case Instruction::APUT_SHORT: - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPutShort, - rlSrc[0], rlSrc[1], rlSrc[2]); - break; - case Instruction::APUT_WIDE: - if (rlSrc[0].fp) { - convertAput(cUnit, optFlags, - greenland::IntrinsicHelper::HLArrayPutDouble, - rlSrc[0], rlSrc[1], rlSrc[2]); - } else { - convertAput(cUnit, optFlags, greenland::IntrinsicHelper::HLArrayPutWide, - rlSrc[0], rlSrc[1], rlSrc[2]); - } - break; - - case Instruction::IGET: - if (rlDest.fp) { - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetFloat, - rlDest, rlSrc[0], vC); - } else { - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGet, - rlDest, rlSrc[0], vC); - } - break; - case Instruction::IGET_OBJECT: - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetObject, - rlDest, rlSrc[0], vC); - break; - case Instruction::IGET_BOOLEAN: - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetBoolean, - rlDest, rlSrc[0], vC); - break; - case Instruction::IGET_BYTE: - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetByte, - rlDest, rlSrc[0], vC); - break; - case Instruction::IGET_CHAR: - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetChar, - rlDest, rlSrc[0], vC); - break; - case Instruction::IGET_SHORT: - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetShort, - rlDest, rlSrc[0], vC); - break; - case Instruction::IGET_WIDE: - if (rlDest.fp) { - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetDouble, - rlDest, rlSrc[0], vC); - } else { - convertIget(cUnit, optFlags, greenland::IntrinsicHelper::HLIGetWide, - rlDest, rlSrc[0], vC); - } - break; - case Instruction::IPUT: - if (rlSrc[0].fp) { - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutFloat, - rlSrc[0], rlSrc[1], vC); - } else { - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPut, - rlSrc[0], rlSrc[1], vC); - } - break; - case Instruction::IPUT_OBJECT: - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutObject, - rlSrc[0], rlSrc[1], vC); - break; - case Instruction::IPUT_BOOLEAN: - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutBoolean, - rlSrc[0], rlSrc[1], vC); - break; - case Instruction::IPUT_BYTE: - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutByte, - rlSrc[0], rlSrc[1], vC); - break; - case Instruction::IPUT_CHAR: - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutChar, - rlSrc[0], rlSrc[1], vC); - break; - case Instruction::IPUT_SHORT: - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutShort, - rlSrc[0], rlSrc[1], vC); - break; - case Instruction::IPUT_WIDE: - if (rlSrc[0].fp) { - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutDouble, - rlSrc[0], rlSrc[1], vC); - } else { - convertIput(cUnit, optFlags, greenland::IntrinsicHelper::HLIPutWide, - rlSrc[0], rlSrc[1], vC); - } - break; - - case Instruction::FILL_ARRAY_DATA: - convertFillArrayData(cUnit, vB, rlSrc[0]); - break; - - case Instruction::LONG_TO_INT: - convertLongToInt(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::INT_TO_LONG: - convertIntToLong(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::INT_TO_CHAR: - convertIntNarrowing(cUnit, rlDest, rlSrc[0], - greenland::IntrinsicHelper::IntToChar); - break; - case Instruction::INT_TO_BYTE: - convertIntNarrowing(cUnit, rlDest, rlSrc[0], - greenland::IntrinsicHelper::IntToByte); - break; - case Instruction::INT_TO_SHORT: - convertIntNarrowing(cUnit, rlDest, rlSrc[0], - greenland::IntrinsicHelper::IntToShort); - break; - - case Instruction::INT_TO_FLOAT: - case Instruction::LONG_TO_FLOAT: - convertIntToFP(cUnit, cUnit->irb->getFloatTy(), rlDest, rlSrc[0]); - break; - - case Instruction::INT_TO_DOUBLE: - case Instruction::LONG_TO_DOUBLE: - convertIntToFP(cUnit, cUnit->irb->getDoubleTy(), rlDest, rlSrc[0]); - break; - - case Instruction::FLOAT_TO_DOUBLE: - convertFloatToDouble(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::DOUBLE_TO_FLOAT: - convertDoubleToFloat(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::NEG_LONG: - case Instruction::NEG_INT: - convertNeg(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::NEG_FLOAT: - case Instruction::NEG_DOUBLE: - convertNegFP(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::NOT_LONG: - case Instruction::NOT_INT: - convertNot(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::FLOAT_TO_INT: - convertFPToInt(cUnit, greenland::IntrinsicHelper::F2I, rlDest, rlSrc[0]); - break; - - case Instruction::DOUBLE_TO_INT: - convertFPToInt(cUnit, greenland::IntrinsicHelper::D2I, rlDest, rlSrc[0]); - break; - - case Instruction::FLOAT_TO_LONG: - convertFPToInt(cUnit, greenland::IntrinsicHelper::F2L, rlDest, rlSrc[0]); - break; - - case Instruction::DOUBLE_TO_LONG: - convertFPToInt(cUnit, greenland::IntrinsicHelper::D2L, rlDest, rlSrc[0]); - break; - - case Instruction::CMPL_FLOAT: - convertWideComparison(cUnit, greenland::IntrinsicHelper::CmplFloat, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::CMPG_FLOAT: - convertWideComparison(cUnit, greenland::IntrinsicHelper::CmpgFloat, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::CMPL_DOUBLE: - convertWideComparison(cUnit, greenland::IntrinsicHelper::CmplDouble, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::CMPG_DOUBLE: - convertWideComparison(cUnit, greenland::IntrinsicHelper::CmpgDouble, - rlDest, rlSrc[0], rlSrc[1]); - break; - case Instruction::CMP_LONG: - convertWideComparison(cUnit, greenland::IntrinsicHelper::CmpLong, - rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::PACKED_SWITCH: - convertPackedSwitch(cUnit, bb, vB, rlSrc[0]); - break; - - case Instruction::SPARSE_SWITCH: - convertSparseSwitch(cUnit, bb, vB, rlSrc[0]); - break; - - default: - UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode; - res = true; - } - if (objectDefinition) { - setShadowFrameEntry(cUnit, (llvm::Value*) - cUnit->llvmValues.elemList[rlDest.origSReg]); - } - return res; -} - -/* Extended MIR instructions like PHI */ -void convertExtendedMIR(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - llvm::BasicBlock* llvmBB) -{ - - switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) { - case kMirOpPhi: { - RegLocation rlDest = cUnit->regLocation[mir->ssaRep->defs[0]]; - /* - * The Art compiler's Phi nodes only handle 32-bit operands, - * representing wide values using a matched set of Phi nodes - * for the lower and upper halves. In the llvm world, we only - * want a single Phi for wides. Here we will simply discard - * the Phi node representing the high word. - */ - if (rlDest.highWord) { - return; // No Phi node - handled via low word - } - int* incoming = (int*)mir->dalvikInsn.vB; - llvm::Type* phiType = - llvmTypeFromLocRec(cUnit, rlDest); - llvm::PHINode* phi = cUnit->irb->CreatePHI(phiType, mir->ssaRep->numUses); - for (int i = 0; i < mir->ssaRep->numUses; i++) { - RegLocation loc; - // Don't check width here. - loc = oatGetRawSrc(cUnit, mir, i); - DCHECK_EQ(rlDest.wide, loc.wide); - DCHECK_EQ(rlDest.wide & rlDest.highWord, loc.wide & loc.highWord); - DCHECK_EQ(rlDest.fp, loc.fp); - DCHECK_EQ(rlDest.core, loc.core); - DCHECK_EQ(rlDest.ref, loc.ref); - SafeMap::iterator it; - it = cUnit->blockIdMap.find(incoming[i]); - DCHECK(it != cUnit->blockIdMap.end()); - phi->addIncoming(getLLVMValue(cUnit, loc.origSReg), - getLLVMBlock(cUnit, it->second)); - } - defineValue(cUnit, phi, rlDest.origSReg); - break; - } - case kMirOpCopy: { - UNIMPLEMENTED(WARNING) << "unimp kMirOpPhi"; - break; - } - case kMirOpNop: - if ((mir == bb->lastMIRInsn) && (bb->taken == NULL) && - (bb->fallThrough == NULL)) { - cUnit->irb->CreateUnreachable(); - } - break; - - // TODO: need GBC intrinsic to take advantage of fused operations - case kMirOpFusedCmplFloat: - UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpFloat unsupported"; - break; - case kMirOpFusedCmpgFloat: - UNIMPLEMENTED(FATAL) << "kMirOpFusedCmgFloat unsupported"; - break; - case kMirOpFusedCmplDouble: - UNIMPLEMENTED(FATAL) << "kMirOpFusedCmplDouble unsupported"; - break; - case kMirOpFusedCmpgDouble: - UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpgDouble unsupported"; - break; - case kMirOpFusedCmpLong: - UNIMPLEMENTED(FATAL) << "kMirOpLongCmpBranch unsupported"; - break; - default: - break; - } -} - -void setDexOffset(CompilationUnit* cUnit, int32_t offset) -{ - cUnit->currentDalvikOffset = offset; - llvm::SmallVector arrayRef; - arrayRef.push_back(cUnit->irb->getInt32(offset)); - llvm::MDNode* node = llvm::MDNode::get(*cUnit->context, arrayRef); - cUnit->irb->SetDexOffset(node); -} - -// Attach method info as metadata to special intrinsic -void setMethodInfo(CompilationUnit* cUnit) -{ - // We don't want dex offset on this - cUnit->irb->SetDexOffset(NULL); - greenland::IntrinsicHelper::IntrinsicId id; - id = greenland::IntrinsicHelper::MethodInfo; - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Instruction* inst = cUnit->irb->CreateCall(intr); - llvm::SmallVector regInfo; - regInfo.push_back(cUnit->irb->getInt32(cUnit->numIns)); - regInfo.push_back(cUnit->irb->getInt32(cUnit->numRegs)); - regInfo.push_back(cUnit->irb->getInt32(cUnit->numOuts)); - regInfo.push_back(cUnit->irb->getInt32(cUnit->numCompilerTemps)); - regInfo.push_back(cUnit->irb->getInt32(cUnit->numSSARegs)); - llvm::MDNode* regInfoNode = llvm::MDNode::get(*cUnit->context, regInfo); - inst->setMetadata("RegInfo", regInfoNode); - int promoSize = cUnit->numDalvikRegisters + cUnit->numCompilerTemps + 1; - llvm::SmallVector pmap; - for (int i = 0; i < promoSize; i++) { - PromotionMap* p = &cUnit->promotionMap[i]; - int32_t mapData = ((p->firstInPair & 0xff) << 24) | - ((p->fpReg & 0xff) << 16) | - ((p->coreReg & 0xff) << 8) | - ((p->fpLocation & 0xf) << 4) | - (p->coreLocation & 0xf); - pmap.push_back(cUnit->irb->getInt32(mapData)); - } - llvm::MDNode* mapNode = llvm::MDNode::get(*cUnit->context, pmap); - inst->setMetadata("PromotionMap", mapNode); - setDexOffset(cUnit, cUnit->currentDalvikOffset); -} - -/* Handle the content in each basic block */ -bool methodBlockBitcodeConversion(CompilationUnit* cUnit, BasicBlock* bb) -{ - if (bb->blockType == kDead) return false; - llvm::BasicBlock* llvmBB = getLLVMBlock(cUnit, bb->id); - if (llvmBB == NULL) { - CHECK(bb->blockType == kExitBlock); - } else { - cUnit->irb->SetInsertPoint(llvmBB); - setDexOffset(cUnit, bb->startOffset); - } - - if (cUnit->printMe) { - LOG(INFO) << "................................"; - LOG(INFO) << "Block id " << bb->id; - if (llvmBB != NULL) { - LOG(INFO) << "label " << llvmBB->getName().str().c_str(); - } else { - LOG(INFO) << "llvmBB is NULL"; - } - } - - if (bb->blockType == kEntryBlock) { - setMethodInfo(cUnit); - bool *canBeRef = (bool*) oatNew(cUnit, sizeof(bool) * - cUnit->numDalvikRegisters, true, - kAllocMisc); - for (int i = 0; i < cUnit->numSSARegs; i++) { - int vReg = SRegToVReg(cUnit, i); - if (vReg > SSA_METHOD_BASEREG) { - canBeRef[SRegToVReg(cUnit, i)] |= cUnit->regLocation[i].ref; - } - } - for (int i = 0; i < cUnit->numDalvikRegisters; i++) { - if (canBeRef[i]) { - cUnit->numShadowFrameEntries++; - } - } - if (cUnit->numShadowFrameEntries > 0) { - cUnit->shadowMap = (int*) oatNew(cUnit, sizeof(int) * - cUnit->numShadowFrameEntries, true, - kAllocMisc); - for (int i = 0, j = 0; i < cUnit->numDalvikRegisters; i++) { - if (canBeRef[i]) { - cUnit->shadowMap[j++] = i; - } - } - } - greenland::IntrinsicHelper::IntrinsicId id = - greenland::IntrinsicHelper::AllocaShadowFrame; - llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(id); - llvm::Value* entries = cUnit->irb->getInt32(cUnit->numShadowFrameEntries); - llvm::Value* dalvikRegs = cUnit->irb->getInt32(cUnit->numDalvikRegisters); - llvm::Value* args[] = { entries, dalvikRegs }; - cUnit->irb->CreateCall(func, args); - } else if (bb->blockType == kExitBlock) { - /* - * Because of the differences between how MIR/LIR and llvm handle exit - * blocks, we won't explicitly covert them. On the llvm-to-lir - * path, it will need to be regenereated. - */ - return false; - } else if (bb->blockType == kExceptionHandling) { - /* - * Because we're deferring null checking, delete the associated empty - * exception block. - */ - llvmBB->eraseFromParent(); - return false; - } - - for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) { - - setDexOffset(cUnit, mir->offset); - - int opcode = mir->dalvikInsn.opcode; - Instruction::Format dalvikFormat = - Instruction::FormatOf(mir->dalvikInsn.opcode); - - if (opcode == kMirOpCheck) { - // Combine check and work halves of throwing instruction. - MIR* workHalf = mir->meta.throwInsn; - mir->dalvikInsn.opcode = workHalf->dalvikInsn.opcode; - opcode = mir->dalvikInsn.opcode; - SSARepresentation* ssaRep = workHalf->ssaRep; - workHalf->ssaRep = mir->ssaRep; - mir->ssaRep = ssaRep; - workHalf->dalvikInsn.opcode = static_cast(kMirOpNop); - if (bb->successorBlockList.blockListType == kCatch) { - llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction( - greenland::IntrinsicHelper::CatchTargets); - llvm::Value* switchKey = - cUnit->irb->CreateCall(intr, cUnit->irb->getInt32(mir->offset)); - GrowableListIterator iter; - oatGrowableListIteratorInit(&bb->successorBlockList.blocks, &iter); - // New basic block to use for work half - llvm::BasicBlock* workBB = - llvm::BasicBlock::Create(*cUnit->context, "", cUnit->func); - llvm::SwitchInst* sw = - cUnit->irb->CreateSwitch(switchKey, workBB, - bb->successorBlockList.blocks.numUsed); - while (true) { - SuccessorBlockInfo *successorBlockInfo = - (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iter); - if (successorBlockInfo == NULL) break; - llvm::BasicBlock *target = - getLLVMBlock(cUnit, successorBlockInfo->block->id); - int typeIndex = successorBlockInfo->key; - sw->addCase(cUnit->irb->getInt32(typeIndex), target); - } - llvmBB = workBB; - cUnit->irb->SetInsertPoint(llvmBB); - } - } - - if (opcode >= kMirOpFirst) { - convertExtendedMIR(cUnit, bb, mir, llvmBB); - continue; - } - - bool notHandled = convertMIRNode(cUnit, mir, bb, llvmBB, - NULL /* labelList */); - if (notHandled) { - Instruction::Code dalvikOpcode = static_cast(opcode); - LOG(WARNING) << StringPrintf("%#06x: Op %#x (%s) / Fmt %d not handled", - mir->offset, opcode, - Instruction::Name(dalvikOpcode), - dalvikFormat); - } - } - - if (bb->blockType == kEntryBlock) { - cUnit->entryTargetBB = getLLVMBlock(cUnit, bb->fallThrough->id); - } else if ((bb->fallThrough != NULL) && !bb->hasReturn) { - cUnit->irb->CreateBr(getLLVMBlock(cUnit, bb->fallThrough->id)); - } - - return false; -} - -char remapShorty(char shortyType) { - /* - * TODO: might want to revisit this. Dalvik registers are 32-bits wide, - * and longs/doubles are represented as a pair of registers. When sub-word - * arguments (and method results) are passed, they are extended to Dalvik - * virtual register containers. Because llvm is picky about type consistency, - * we must either cast the "real" type to 32-bit container multiple Dalvik - * register types, or always use the expanded values. - * Here, we're doing the latter. We map the shorty signature to container - * types (which is valid so long as we always do a real expansion of passed - * arguments and field loads). - */ - switch(shortyType) { - case 'Z' : shortyType = 'I'; break; - case 'B' : shortyType = 'I'; break; - case 'S' : shortyType = 'I'; break; - case 'C' : shortyType = 'I'; break; - default: break; - } - return shortyType; -} - -llvm::FunctionType* getFunctionType(CompilationUnit* cUnit) { - - // Get return type - llvm::Type* ret_type = cUnit->irb->GetJType(remapShorty(cUnit->shorty[0]), - greenland::kAccurate); - - // Get argument type - std::vector args_type; - - // method object - args_type.push_back(cUnit->irb->GetJMethodTy()); - - // Do we have a "this"? - if ((cUnit->access_flags & kAccStatic) == 0) { - args_type.push_back(cUnit->irb->GetJObjectTy()); - } - - for (uint32_t i = 1; i < strlen(cUnit->shorty); ++i) { - args_type.push_back(cUnit->irb->GetJType(remapShorty(cUnit->shorty[i]), - greenland::kAccurate)); - } - - return llvm::FunctionType::get(ret_type, args_type, false); -} - -bool createFunction(CompilationUnit* cUnit) { - std::string func_name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file, - /* with_signature */ false)); - llvm::FunctionType* func_type = getFunctionType(cUnit); - - if (func_type == NULL) { - return false; - } - - cUnit->func = llvm::Function::Create(func_type, - llvm::Function::ExternalLinkage, - func_name, cUnit->module); - - llvm::Function::arg_iterator arg_iter(cUnit->func->arg_begin()); - llvm::Function::arg_iterator arg_end(cUnit->func->arg_end()); - - arg_iter->setName("method"); - ++arg_iter; - - int startSReg = cUnit->numRegs; - - for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) { - arg_iter->setName(StringPrintf("v%i_0", startSReg)); - startSReg += cUnit->regLocation[startSReg].wide ? 2 : 1; - } - - return true; -} - -bool createLLVMBasicBlock(CompilationUnit* cUnit, BasicBlock* bb) -{ - // Skip the exit block - if ((bb->blockType == kDead) ||(bb->blockType == kExitBlock)) { - cUnit->idToBlockMap.Put(bb->id, NULL); - } else { - int offset = bb->startOffset; - bool entryBlock = (bb->blockType == kEntryBlock); - llvm::BasicBlock* llvmBB = - llvm::BasicBlock::Create(*cUnit->context, entryBlock ? "entry" : - StringPrintf(kLabelFormat, bb->catchEntry ? kCatchBlock : - kNormalBlock, offset, bb->id), cUnit->func); - if (entryBlock) { - cUnit->entryBB = llvmBB; - cUnit->placeholderBB = - llvm::BasicBlock::Create(*cUnit->context, "placeholder", - cUnit->func); - } - cUnit->idToBlockMap.Put(bb->id, llvmBB); - } - return false; -} - - -/* - * Convert MIR to LLVM_IR - * o For each ssa name, create LLVM named value. Type these - * appropriately, and ignore high half of wide and double operands. - * o For each MIR basic block, create an LLVM basic block. - * o Iterate through the MIR a basic block at a time, setting arguments - * to recovered ssa name. - */ -void oatMethodMIR2Bitcode(CompilationUnit* cUnit) -{ - initIR(cUnit); - oatInitGrowableList(cUnit, &cUnit->llvmValues, cUnit->numSSARegs); - - // Create the function - createFunction(cUnit); - - // Create an LLVM basic block for each MIR block in dfs preorder - oatDataFlowAnalysisDispatcher(cUnit, createLLVMBasicBlock, - kPreOrderDFSTraversal, false /* isIterative */); - /* - * Create an llvm named value for each MIR SSA name. Note: we'll use - * placeholders for all non-argument values (because we haven't seen - * the definition yet). - */ - cUnit->irb->SetInsertPoint(cUnit->placeholderBB); - llvm::Function::arg_iterator arg_iter(cUnit->func->arg_begin()); - arg_iter++; /* Skip path method */ - for (int i = 0; i < cUnit->numSSARegs; i++) { - llvm::Value* val; - RegLocation rlTemp = cUnit->regLocation[i]; - if ((SRegToVReg(cUnit, i) < 0) || rlTemp.highWord) { - oatInsertGrowableList(cUnit, &cUnit->llvmValues, 0); - } else if ((i < cUnit->numRegs) || - (i >= (cUnit->numRegs + cUnit->numIns))) { - llvm::Constant* immValue = cUnit->regLocation[i].wide ? - cUnit->irb->GetJLong(0) : cUnit->irb->GetJInt(0); - val = emitConst(cUnit, immValue, cUnit->regLocation[i]); - val->setName(llvmSSAName(cUnit, i)); - oatInsertGrowableList(cUnit, &cUnit->llvmValues, (intptr_t)val); - } else { - // Recover previously-created argument values - llvm::Value* argVal = arg_iter++; - oatInsertGrowableList(cUnit, &cUnit->llvmValues, (intptr_t)argVal); - } - } - - oatDataFlowAnalysisDispatcher(cUnit, methodBlockBitcodeConversion, - kPreOrderDFSTraversal, false /* Iterative */); - - /* - * In a few rare cases of verification failure, the verifier will - * replace one or more Dalvik opcodes with the special - * throw-verification-failure opcode. This can leave the SSA graph - * in an invalid state, as definitions may be lost, while uses retained. - * To work around this problem, we insert placeholder definitions for - * all Dalvik SSA regs in the "placeholder" block. Here, after - * bitcode conversion is complete, we examine those placeholder definitions - * and delete any with no references (which normally is all of them). - * - * If any definitions remain, we link the placeholder block into the - * CFG. Otherwise, it is deleted. - */ - for (llvm::BasicBlock::iterator it = cUnit->placeholderBB->begin(), - itEnd = cUnit->placeholderBB->end(); it != itEnd;) { - llvm::Instruction* inst = llvm::dyn_cast(it++); - DCHECK(inst != NULL); - llvm::Value* val = llvm::dyn_cast(inst); - DCHECK(val != NULL); - if (val->getNumUses() == 0) { - inst->eraseFromParent(); - } - } - setDexOffset(cUnit, 0); - if (cUnit->placeholderBB->empty()) { - cUnit->placeholderBB->eraseFromParent(); - } else { - cUnit->irb->SetInsertPoint(cUnit->placeholderBB); - cUnit->irb->CreateBr(cUnit->entryTargetBB); - cUnit->entryTargetBB = cUnit->placeholderBB; - } - cUnit->irb->SetInsertPoint(cUnit->entryBB); - cUnit->irb->CreateBr(cUnit->entryTargetBB); - - if (cUnit->enableDebug & (1 << kDebugVerifyBitcode)) { - if (llvm::verifyFunction(*cUnit->func, llvm::PrintMessageAction)) { - LOG(INFO) << "Bitcode verification FAILED for " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) - << " of size " << cUnit->insnsSize; - cUnit->enableDebug |= (1 << kDebugDumpBitcodeFile); - } - } - - if (cUnit->enableDebug & (1 << kDebugDumpBitcodeFile)) { - // Write bitcode to file - std::string errmsg; - std::string fname(PrettyMethod(cUnit->method_idx, *cUnit->dex_file)); - oatReplaceSpecialChars(fname); - // TODO: make configurable change naming mechanism to avoid fname length issues. - fname = StringPrintf("/sdcard/Bitcode/%s.bc", fname.c_str()); - - if (fname.size() > 240) { - LOG(INFO) << "Warning: bitcode filename too long. Truncated."; - fname.resize(240); - } - - llvm::OwningPtr out_file( - new llvm::tool_output_file(fname.c_str(), errmsg, - llvm::raw_fd_ostream::F_Binary)); - - if (!errmsg.empty()) { - LOG(ERROR) << "Failed to create bitcode output file: " << errmsg; - } - - llvm::WriteBitcodeToFile(cUnit->module, out_file->os()); - out_file->keep(); - } -} - -RegLocation getLoc(CompilationUnit* cUnit, llvm::Value* val) { - RegLocation res; - DCHECK(val != NULL); - SafeMap::iterator it = cUnit->locMap.find(val); - if (it == cUnit->locMap.end()) { - std::string valName = val->getName().str(); - if (valName.empty()) { - // FIXME: need to be more robust, handle FP and be in a position to - // manage unnamed temps whose lifetimes span basic block boundaries - UNIMPLEMENTED(WARNING) << "Need to handle unnamed llvm temps"; - memset(&res, 0, sizeof(res)); - res.location = kLocPhysReg; - res.lowReg = oatAllocTemp(cUnit); - res.home = true; - res.sRegLow = INVALID_SREG; - res.origSReg = INVALID_SREG; - llvm::Type* ty = val->getType(); - res.wide = ((ty == cUnit->irb->getInt64Ty()) || - (ty == cUnit->irb->getDoubleTy())); - if (res.wide) { - res.highReg = oatAllocTemp(cUnit); - } - cUnit->locMap.Put(val, res); - } else { - DCHECK_EQ(valName[0], 'v'); - int baseSReg = INVALID_SREG; - sscanf(valName.c_str(), "v%d_", &baseSReg); - res = cUnit->regLocation[baseSReg]; - cUnit->locMap.Put(val, res); - } - } else { - res = it->second; - } - return res; -} - -Instruction::Code getDalvikOpcode(OpKind op, bool isConst, bool isWide) -{ - Instruction::Code res = Instruction::NOP; - if (isWide) { - switch(op) { - case kOpAdd: res = Instruction::ADD_LONG; break; - case kOpSub: res = Instruction::SUB_LONG; break; - case kOpMul: res = Instruction::MUL_LONG; break; - case kOpDiv: res = Instruction::DIV_LONG; break; - case kOpRem: res = Instruction::REM_LONG; break; - case kOpAnd: res = Instruction::AND_LONG; break; - case kOpOr: res = Instruction::OR_LONG; break; - case kOpXor: res = Instruction::XOR_LONG; break; - case kOpLsl: res = Instruction::SHL_LONG; break; - case kOpLsr: res = Instruction::USHR_LONG; break; - case kOpAsr: res = Instruction::SHR_LONG; break; - default: LOG(FATAL) << "Unexpected OpKind " << op; - } - } else if (isConst){ - switch(op) { - case kOpAdd: res = Instruction::ADD_INT_LIT16; break; - case kOpSub: res = Instruction::RSUB_INT_LIT8; break; - case kOpMul: res = Instruction::MUL_INT_LIT16; break; - case kOpDiv: res = Instruction::DIV_INT_LIT16; break; - case kOpRem: res = Instruction::REM_INT_LIT16; break; - case kOpAnd: res = Instruction::AND_INT_LIT16; break; - case kOpOr: res = Instruction::OR_INT_LIT16; break; - case kOpXor: res = Instruction::XOR_INT_LIT16; break; - case kOpLsl: res = Instruction::SHL_INT_LIT8; break; - case kOpLsr: res = Instruction::USHR_INT_LIT8; break; - case kOpAsr: res = Instruction::SHR_INT_LIT8; break; - default: LOG(FATAL) << "Unexpected OpKind " << op; - } - } else { - switch(op) { - case kOpAdd: res = Instruction::ADD_INT; break; - case kOpSub: res = Instruction::SUB_INT; break; - case kOpMul: res = Instruction::MUL_INT; break; - case kOpDiv: res = Instruction::DIV_INT; break; - case kOpRem: res = Instruction::REM_INT; break; - case kOpAnd: res = Instruction::AND_INT; break; - case kOpOr: res = Instruction::OR_INT; break; - case kOpXor: res = Instruction::XOR_INT; break; - case kOpLsl: res = Instruction::SHL_INT; break; - case kOpLsr: res = Instruction::USHR_INT; break; - case kOpAsr: res = Instruction::SHR_INT; break; - default: LOG(FATAL) << "Unexpected OpKind " << op; - } - } - return res; -} - -Instruction::Code getDalvikFPOpcode(OpKind op, bool isConst, bool isWide) -{ - Instruction::Code res = Instruction::NOP; - if (isWide) { - switch(op) { - case kOpAdd: res = Instruction::ADD_DOUBLE; break; - case kOpSub: res = Instruction::SUB_DOUBLE; break; - case kOpMul: res = Instruction::MUL_DOUBLE; break; - case kOpDiv: res = Instruction::DIV_DOUBLE; break; - case kOpRem: res = Instruction::REM_DOUBLE; break; - default: LOG(FATAL) << "Unexpected OpKind " << op; - } - } else { - switch(op) { - case kOpAdd: res = Instruction::ADD_FLOAT; break; - case kOpSub: res = Instruction::SUB_FLOAT; break; - case kOpMul: res = Instruction::MUL_FLOAT; break; - case kOpDiv: res = Instruction::DIV_FLOAT; break; - case kOpRem: res = Instruction::REM_FLOAT; break; - default: LOG(FATAL) << "Unexpected OpKind " << op; - } - } - return res; -} - -void cvtBinFPOp(CompilationUnit* cUnit, OpKind op, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - /* - * Normally, we won't ever generate an FP operation with an immediate - * operand (not supported in Dex instruction set). However, the IR builder - * may insert them - in particular for createNegFP. Recognize this case - * and deal with it. - */ - llvm::ConstantFP* op1C = llvm::dyn_cast(inst->getOperand(0)); - llvm::ConstantFP* op2C = llvm::dyn_cast(inst->getOperand(1)); - DCHECK(op2C == NULL); - if ((op1C != NULL) && (op == kOpSub)) { - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(1)); - if (rlDest.wide) { - genArithOpDouble(cUnit, Instruction::NEG_DOUBLE, rlDest, rlSrc, rlSrc); - } else { - genArithOpFloat(cUnit, Instruction::NEG_FLOAT, rlDest, rlSrc, rlSrc); - } - } else { - DCHECK(op1C == NULL); - RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(0)); - RegLocation rlSrc2 = getLoc(cUnit, inst->getOperand(1)); - Instruction::Code dalvikOp = getDalvikFPOpcode(op, false, rlDest.wide); - if (rlDest.wide) { - genArithOpDouble(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2); - } else { - genArithOpFloat(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2); - } - } -} - -void cvtIntNarrowing(CompilationUnit* cUnit, llvm::Instruction* inst, - Instruction::Code opcode) -{ - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - genIntNarrowing(cUnit, opcode, rlDest, rlSrc); -} - -void cvtIntToFP(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - Instruction::Code opcode; - if (rlDest.wide) { - if (rlSrc.wide) { - opcode = Instruction::LONG_TO_DOUBLE; - } else { - opcode = Instruction::INT_TO_DOUBLE; - } - } else { - if (rlSrc.wide) { - opcode = Instruction::LONG_TO_FLOAT; - } else { - opcode = Instruction::INT_TO_FLOAT; - } - } - genConversion(cUnit, opcode, rlDest, rlSrc); -} - -void cvtFPToInt(CompilationUnit* cUnit, llvm::CallInst* call_inst) -{ - RegLocation rlDest = getLoc(cUnit, call_inst); - RegLocation rlSrc = getLoc(cUnit, call_inst->getOperand(0)); - Instruction::Code opcode; - if (rlDest.wide) { - if (rlSrc.wide) { - opcode = Instruction::DOUBLE_TO_LONG; - } else { - opcode = Instruction::FLOAT_TO_LONG; - } - } else { - if (rlSrc.wide) { - opcode = Instruction::DOUBLE_TO_INT; - } else { - opcode = Instruction::FLOAT_TO_INT; - } - } - genConversion(cUnit, opcode, rlDest, rlSrc); -} - -void cvtFloatToDouble(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - genConversion(cUnit, Instruction::FLOAT_TO_DOUBLE, rlDest, rlSrc); -} - -void cvtTrunc(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - rlSrc = oatUpdateLocWide(cUnit, rlSrc); - rlSrc = oatWideToNarrow(cUnit, rlSrc); - storeValue(cUnit, rlDest, rlSrc); -} - -void cvtDoubleToFloat(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - genConversion(cUnit, Instruction::DOUBLE_TO_FLOAT, rlDest, rlSrc); -} - - -void cvtIntExt(CompilationUnit* cUnit, llvm::Instruction* inst, bool isSigned) -{ - // TODO: evaluate src/tgt types and add general support for more than int to long - RegLocation rlDest = getLoc(cUnit, inst); - RegLocation rlSrc = getLoc(cUnit, inst->getOperand(0)); - DCHECK(rlDest.wide); - DCHECK(!rlSrc.wide); - DCHECK(!rlDest.fp); - DCHECK(!rlSrc.fp); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (rlSrc.location == kLocPhysReg) { - opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - } else { - loadValueDirect(cUnit, rlSrc, rlResult.lowReg); - } - if (isSigned) { - opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31); - } else { - loadConstant(cUnit, rlResult.highReg, 0); - } - storeValueWide(cUnit, rlDest, rlResult); -} - -void cvtBinOp(CompilationUnit* cUnit, OpKind op, llvm::Instruction* inst) -{ - RegLocation rlDest = getLoc(cUnit, inst); - llvm::Value* lhs = inst->getOperand(0); - // Special-case RSUB/NEG - llvm::ConstantInt* lhsImm = llvm::dyn_cast(lhs); - if ((op == kOpSub) && (lhsImm != NULL)) { - RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(1)); - if (rlSrc1.wide) { - DCHECK_EQ(lhsImm->getSExtValue(), 0); - genArithOpLong(cUnit, Instruction::NEG_LONG, rlDest, rlSrc1, rlSrc1); - } else { - genArithOpIntLit(cUnit, Instruction::RSUB_INT, rlDest, rlSrc1, - lhsImm->getSExtValue()); - } - return; - } - DCHECK(lhsImm == NULL); - RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(0)); - llvm::Value* rhs = inst->getOperand(1); - llvm::ConstantInt* constRhs = llvm::dyn_cast(rhs); - if (!rlDest.wide && (constRhs != NULL)) { - Instruction::Code dalvikOp = getDalvikOpcode(op, true, false); - genArithOpIntLit(cUnit, dalvikOp, rlDest, rlSrc1, constRhs->getSExtValue()); - } else { - Instruction::Code dalvikOp = getDalvikOpcode(op, false, rlDest.wide); - RegLocation rlSrc2; - if (constRhs != NULL) { - // ir_builder converts NOT_LONG to xor src, -1. Restore - DCHECK_EQ(dalvikOp, Instruction::XOR_LONG); - DCHECK_EQ(-1L, constRhs->getSExtValue()); - dalvikOp = Instruction::NOT_LONG; - rlSrc2 = rlSrc1; - } else { - rlSrc2 = getLoc(cUnit, rhs); - } - if (rlDest.wide) { - genArithOpLong(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2); - } else { - genArithOpInt(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2); - } - } -} - -void cvtShiftOp(CompilationUnit* cUnit, Instruction::Code opcode, - llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - RegLocation rlDest = getLoc(cUnit, callInst); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(0)); - llvm::Value* rhs = callInst->getArgOperand(1); - if (llvm::ConstantInt* src2 = llvm::dyn_cast(rhs)) { - DCHECK(!rlDest.wide); - genArithOpIntLit(cUnit, opcode, rlDest, rlSrc, src2->getSExtValue()); - } else { - RegLocation rlShift = getLoc(cUnit, rhs); - if (callInst->getType() == cUnit->irb->getInt64Ty()) { - genShiftOpLong(cUnit, opcode, rlDest, rlSrc, rlShift); - } else { - genArithOpInt(cUnit, opcode, rlDest, rlSrc, rlShift); - } - } -} - -void cvtBr(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - llvm::BranchInst* brInst = llvm::dyn_cast(inst); - DCHECK(brInst != NULL); - DCHECK(brInst->isUnconditional()); // May change - but this is all we use now - llvm::BasicBlock* targetBB = brInst->getSuccessor(0); - opUnconditionalBranch(cUnit, cUnit->blockToLabelMap.Get(targetBB)); -} - -void cvtPhi(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - // Nop - these have already been processed -} - -void cvtRet(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - llvm::ReturnInst* retInst = llvm::dyn_cast(inst); - llvm::Value* retVal = retInst->getReturnValue(); - if (retVal != NULL) { - RegLocation rlSrc = getLoc(cUnit, retVal); - if (rlSrc.wide) { - storeValueWide(cUnit, oatGetReturnWide(cUnit, rlSrc.fp), rlSrc); - } else { - storeValue(cUnit, oatGetReturn(cUnit, rlSrc.fp), rlSrc); - } - } - genExitSequence(cUnit); -} - -ConditionCode getCond(llvm::ICmpInst::Predicate llvmCond) -{ - ConditionCode res = kCondAl; - switch(llvmCond) { - case llvm::ICmpInst::ICMP_EQ: res = kCondEq; break; - case llvm::ICmpInst::ICMP_NE: res = kCondNe; break; - case llvm::ICmpInst::ICMP_SLT: res = kCondLt; break; - case llvm::ICmpInst::ICMP_SGE: res = kCondGe; break; - case llvm::ICmpInst::ICMP_SGT: res = kCondGt; break; - case llvm::ICmpInst::ICMP_SLE: res = kCondLe; break; - default: LOG(FATAL) << "Unexpected llvm condition"; - } - return res; -} - -void cvtICmp(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - // genCmpLong(cUnit, rlDest, rlSrc1, rlSrc2) - UNIMPLEMENTED(FATAL); -} - -void cvtICmpBr(CompilationUnit* cUnit, llvm::Instruction* inst, - llvm::BranchInst* brInst) -{ - // Get targets - llvm::BasicBlock* takenBB = brInst->getSuccessor(0); - LIR* taken = cUnit->blockToLabelMap.Get(takenBB); - llvm::BasicBlock* fallThroughBB = brInst->getSuccessor(1); - LIR* fallThrough = cUnit->blockToLabelMap.Get(fallThroughBB); - // Get comparison operands - llvm::ICmpInst* iCmpInst = llvm::dyn_cast(inst); - ConditionCode cond = getCond(iCmpInst->getPredicate()); - llvm::Value* lhs = iCmpInst->getOperand(0); - // Not expecting a constant as 1st operand - DCHECK(llvm::dyn_cast(lhs) == NULL); - RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(0)); - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - llvm::Value* rhs = inst->getOperand(1); - if (cUnit->instructionSet == kMips) { - // Compare and branch in one shot - UNIMPLEMENTED(FATAL); - } - //Compare, then branch - // TODO: handle fused CMP_LONG/IF_xxZ case - if (llvm::ConstantInt* src2 = llvm::dyn_cast(rhs)) { - opRegImm(cUnit, kOpCmp, rlSrc1.lowReg, src2->getSExtValue()); - } else if (llvm::dyn_cast(rhs) != NULL) { - opRegImm(cUnit, kOpCmp, rlSrc1.lowReg, 0); - } else { - RegLocation rlSrc2 = getLoc(cUnit, rhs); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); - } - opCondBranch(cUnit, cond, taken); - // Fallthrough - opUnconditionalBranch(cUnit, fallThrough); -} - -void cvtCall(CompilationUnit* cUnit, llvm::CallInst* callInst, - llvm::Function* callee) -{ - UNIMPLEMENTED(FATAL); -} - -void cvtCopy(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(0)); - RegLocation rlDest = getLoc(cUnit, callInst); - DCHECK_EQ(rlSrc.wide, rlDest.wide); - DCHECK_EQ(rlSrc.fp, rlDest.fp); - if (rlSrc.wide) { - storeValueWide(cUnit, rlDest, rlSrc); - } else { - storeValue(cUnit, rlDest, rlSrc); - } -} - -// Note: Immediate arg is a ConstantInt regardless of result type -void cvtConst(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - llvm::ConstantInt* src = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint64_t immval = src->getZExtValue(); - RegLocation rlDest = getLoc(cUnit, callInst); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - if (rlDest.wide) { - loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, - (immval) & 0xffffffff, (immval >> 32) & 0xffffffff); - storeValueWide(cUnit, rlDest, rlResult); - } else { - loadConstantNoClobber(cUnit, rlResult.lowReg, immval & 0xffffffff); - storeValue(cUnit, rlDest, rlResult); - } -} - -void cvtConstObject(CompilationUnit* cUnit, llvm::CallInst* callInst, - bool isString) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - llvm::ConstantInt* idxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t index = idxVal->getZExtValue(); - RegLocation rlDest = getLoc(cUnit, callInst); - if (isString) { - genConstString(cUnit, index, rlDest); - } else { - genConstClass(cUnit, index, rlDest); - } -} - -void cvtFillArrayData(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* offsetVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1)); - genFillArrayData(cUnit, offsetVal->getSExtValue(), rlSrc); -} - -void cvtNewInstance(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - llvm::ConstantInt* typeIdxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t typeIdx = typeIdxVal->getZExtValue(); - RegLocation rlDest = getLoc(cUnit, callInst); - genNewInstance(cUnit, typeIdx, rlDest); -} - -void cvtNewArray(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* typeIdxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t typeIdx = typeIdxVal->getZExtValue(); - llvm::Value* len = callInst->getArgOperand(1); - RegLocation rlLen = getLoc(cUnit, len); - RegLocation rlDest = getLoc(cUnit, callInst); - genNewArray(cUnit, typeIdx, rlDest, rlLen); -} - -void cvtInstanceOf(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* typeIdxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t typeIdx = typeIdxVal->getZExtValue(); - llvm::Value* src = callInst->getArgOperand(1); - RegLocation rlSrc = getLoc(cUnit, src); - RegLocation rlDest = getLoc(cUnit, callInst); - genInstanceof(cUnit, typeIdx, rlDest, rlSrc); -} - -void cvtThrow(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - llvm::Value* src = callInst->getArgOperand(0); - RegLocation rlSrc = getLoc(cUnit, src); - genThrow(cUnit, rlSrc); -} - -void cvtMonitorEnterExit(CompilationUnit* cUnit, bool isEnter, - llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - llvm::Value* src = callInst->getArgOperand(1); - RegLocation rlSrc = getLoc(cUnit, src); - if (isEnter) { - genMonitorEnter(cUnit, optFlags->getZExtValue(), rlSrc); - } else { - genMonitorExit(cUnit, optFlags->getZExtValue(), rlSrc); - } -} - -void cvtArrayLength(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - llvm::Value* src = callInst->getArgOperand(1); - RegLocation rlSrc = getLoc(cUnit, src); - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg, optFlags->getZExtValue()); - RegLocation rlDest = getLoc(cUnit, callInst); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - int lenOffset = Array::LengthOffset().Int32Value(); - loadWordDisp(cUnit, rlSrc.lowReg, lenOffset, rlResult.lowReg); - storeValue(cUnit, rlDest, rlResult); -} - -void cvtMoveException(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - RegLocation rlDest = getLoc(cUnit, callInst); - genMoveException(cUnit, rlDest); -} - -void cvtSget(CompilationUnit* cUnit, llvm::CallInst* callInst, bool isWide, - bool isObject) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 1U); - llvm::ConstantInt* typeIdxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t typeIdx = typeIdxVal->getZExtValue(); - RegLocation rlDest = getLoc(cUnit, callInst); - genSget(cUnit, typeIdx, rlDest, isWide, isObject); -} - -void cvtSput(CompilationUnit* cUnit, llvm::CallInst* callInst, bool isWide, - bool isObject) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* typeIdxVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - uint32_t typeIdx = typeIdxVal->getZExtValue(); - llvm::Value* src = callInst->getArgOperand(1); - RegLocation rlSrc = getLoc(cUnit, src); - genSput(cUnit, typeIdx, rlSrc, isWide, isObject); -} - -void cvtAget(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size, - int scale) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 3U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlArray = getLoc(cUnit, callInst->getArgOperand(1)); - RegLocation rlIndex = getLoc(cUnit, callInst->getArgOperand(2)); - RegLocation rlDest = getLoc(cUnit, callInst); - genArrayGet(cUnit, optFlags->getZExtValue(), size, rlArray, rlIndex, - rlDest, scale); -} - -void cvtAput(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size, - int scale, bool isObject) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 4U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1)); - RegLocation rlArray = getLoc(cUnit, callInst->getArgOperand(2)); - RegLocation rlIndex = getLoc(cUnit, callInst->getArgOperand(3)); - if (isObject) { - genArrayObjPut(cUnit, optFlags->getZExtValue(), rlArray, rlIndex, - rlSrc, scale); - } else { - genArrayPut(cUnit, optFlags->getZExtValue(), size, rlArray, rlIndex, - rlSrc, scale); - } -} - -void cvtAputObj(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - cvtAput(cUnit, callInst, kWord, 2, true /* isObject */); -} - -void cvtAputPrimitive(CompilationUnit* cUnit, llvm::CallInst* callInst, - OpSize size, int scale) -{ - cvtAput(cUnit, callInst, size, scale, false /* isObject */); -} - -void cvtIget(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size, - bool isWide, bool isObj) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 3U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlObj = getLoc(cUnit, callInst->getArgOperand(1)); - llvm::ConstantInt* fieldIdx = - llvm::dyn_cast(callInst->getArgOperand(2)); - RegLocation rlDest = getLoc(cUnit, callInst); - genIGet(cUnit, fieldIdx->getZExtValue(), optFlags->getZExtValue(), - size, rlDest, rlObj, isWide, isObj); -} - -void cvtIput(CompilationUnit* cUnit, llvm::CallInst* callInst, OpSize size, - bool isWide, bool isObj) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 4U); - llvm::ConstantInt* optFlags = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1)); - RegLocation rlObj = getLoc(cUnit, callInst->getArgOperand(2)); - llvm::ConstantInt* fieldIdx = - llvm::dyn_cast(callInst->getArgOperand(3)); - genIPut(cUnit, fieldIdx->getZExtValue(), optFlags->getZExtValue(), - size, rlSrc, rlObj, isWide, isObj); -} - -void cvtCheckCast(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - DCHECK_EQ(callInst->getNumArgOperands(), 2U); - llvm::ConstantInt* typeIdx = - llvm::dyn_cast(callInst->getArgOperand(0)); - RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(1)); - genCheckCast(cUnit, typeIdx->getZExtValue(), rlSrc); -} - -void cvtFPCompare(CompilationUnit* cUnit, llvm::CallInst* callInst, - Instruction::Code opcode) -{ - RegLocation rlSrc1 = getLoc(cUnit, callInst->getArgOperand(0)); - RegLocation rlSrc2 = getLoc(cUnit, callInst->getArgOperand(1)); - RegLocation rlDest = getLoc(cUnit, callInst); - genCmpFP(cUnit, opcode, rlDest, rlSrc1, rlSrc2); -} - -void cvtLongCompare(CompilationUnit* cUnit, llvm::CallInst* callInst) -{ - RegLocation rlSrc1 = getLoc(cUnit, callInst->getArgOperand(0)); - RegLocation rlSrc2 = getLoc(cUnit, callInst->getArgOperand(1)); - RegLocation rlDest = getLoc(cUnit, callInst); - genCmpLong(cUnit, rlDest, rlSrc1, rlSrc2); -} - -void cvtSwitch(CompilationUnit* cUnit, llvm::Instruction* inst) -{ - llvm::SwitchInst* swInst = llvm::dyn_cast(inst); - DCHECK(swInst != NULL); - llvm::Value* testVal = swInst->getCondition(); - llvm::MDNode* tableOffsetNode = swInst->getMetadata("SwitchTable"); - DCHECK(tableOffsetNode != NULL); - llvm::ConstantInt* tableOffsetValue = - static_cast(tableOffsetNode->getOperand(0)); - int32_t tableOffset = tableOffsetValue->getSExtValue(); - RegLocation rlSrc = getLoc(cUnit, testVal); - const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset; - u2 tableMagic = *table; - if (tableMagic == 0x100) { - genPackedSwitch(cUnit, tableOffset, rlSrc); - } else { - DCHECK_EQ(tableMagic, 0x200); - genSparseSwitch(cUnit, tableOffset, rlSrc); - } -} - -void cvtInvoke(CompilationUnit* cUnit, llvm::CallInst* callInst, - bool isVoid, bool isFilledNewArray) -{ - CallInfo* info = (CallInfo*)oatNew(cUnit, sizeof(CallInfo), true, - kAllocMisc); - if (isVoid) { - info->result.location = kLocInvalid; - } else { - info->result = getLoc(cUnit, callInst); - } - llvm::ConstantInt* invokeTypeVal = - llvm::dyn_cast(callInst->getArgOperand(0)); - llvm::ConstantInt* methodIndexVal = - llvm::dyn_cast(callInst->getArgOperand(1)); - llvm::ConstantInt* optFlagsVal = - llvm::dyn_cast(callInst->getArgOperand(2)); - info->type = static_cast(invokeTypeVal->getZExtValue()); - info->index = methodIndexVal->getZExtValue(); - info->optFlags = optFlagsVal->getZExtValue(); - info->offset = cUnit->currentDalvikOffset; - - // Count the argument words, and then build argument array. - info->numArgWords = 0; - for (unsigned int i = 3; i < callInst->getNumArgOperands(); i++) { - RegLocation tLoc = getLoc(cUnit, callInst->getArgOperand(i)); - info->numArgWords += tLoc.wide ? 2 : 1; - } - info->args = (info->numArgWords == 0) ? NULL : (RegLocation*) - oatNew(cUnit, sizeof(RegLocation) * info->numArgWords, false, kAllocMisc); - // Now, fill in the location records, synthesizing high loc of wide vals - for (int i = 3, next = 0; next < info->numArgWords;) { - info->args[next] = getLoc(cUnit, callInst->getArgOperand(i++)); - if (info->args[next].wide) { - next++; - // TODO: Might make sense to mark this as an invalid loc - info->args[next].origSReg = info->args[next-1].origSReg+1; - info->args[next].sRegLow = info->args[next-1].sRegLow+1; - } - next++; - } - // TODO - rework such that we no longer need isRange - info->isRange = (info->numArgWords > 5); - - if (isFilledNewArray) { - genFilledNewArray(cUnit, info); - } else { - genInvoke(cUnit, info); - } -} - -/* Look up the RegLocation associated with a Value. Must already be defined */ -RegLocation valToLoc(CompilationUnit* cUnit, llvm::Value* val) -{ - SafeMap::iterator it = cUnit->locMap.find(val); - DCHECK(it != cUnit->locMap.end()) << "Missing definition"; - return it->second; -} - -bool methodBitcodeBlockCodeGen(CompilationUnit* cUnit, llvm::BasicBlock* bb) -{ - while (cUnit->llvmBlocks.find(bb) == cUnit->llvmBlocks.end()) { - llvm::BasicBlock* nextBB = NULL; - cUnit->llvmBlocks.insert(bb); - bool isEntry = (bb == &cUnit->func->getEntryBlock()); - // Define the starting label - LIR* blockLabel = cUnit->blockToLabelMap.Get(bb); - // Extract the type and starting offset from the block's name - char blockType = kInvalidBlock; - if (isEntry) { - blockType = kNormalBlock; - blockLabel->operands[0] = 0; - } else if (!bb->hasName()) { - blockType = kNormalBlock; - blockLabel->operands[0] = DexFile::kDexNoIndex; - } else { - std::string blockName = bb->getName().str(); - int dummy; - sscanf(blockName.c_str(), kLabelFormat, &blockType, &blockLabel->operands[0], &dummy); - cUnit->currentDalvikOffset = blockLabel->operands[0]; - } - DCHECK((blockType == kNormalBlock) || (blockType == kCatchBlock)); - cUnit->currentDalvikOffset = blockLabel->operands[0]; - // Set the label kind - blockLabel->opcode = kPseudoNormalBlockLabel; - // Insert the label - oatAppendLIR(cUnit, blockLabel); - - LIR* headLIR = NULL; - - if (blockType == kCatchBlock) { - headLIR = newLIR0(cUnit, kPseudoExportedPC); - } - - // Free temp registers and reset redundant store tracking */ - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - - //TODO: restore oat incoming liveness optimization - oatClobberAllRegs(cUnit); - - if (isEntry) { - RegLocation* argLocs = (RegLocation*) - oatNew(cUnit, sizeof(RegLocation) * cUnit->numIns, true, kAllocMisc); - llvm::Function::arg_iterator it(cUnit->func->arg_begin()); - llvm::Function::arg_iterator it_end(cUnit->func->arg_end()); - // Skip past Method* - it++; - for (unsigned i = 0; it != it_end; ++it) { - llvm::Value* val = it; - argLocs[i++] = valToLoc(cUnit, val); - llvm::Type* ty = val->getType(); - if ((ty == cUnit->irb->getInt64Ty()) || (ty == cUnit->irb->getDoubleTy())) { - argLocs[i] = argLocs[i-1]; - argLocs[i].lowReg = argLocs[i].highReg; - argLocs[i].origSReg++; - argLocs[i].sRegLow = INVALID_SREG; - argLocs[i].highWord = true; - i++; - } - } - genEntrySequence(cUnit, argLocs, cUnit->methodLoc); - } - - // Visit all of the instructions in the block - for (llvm::BasicBlock::iterator it = bb->begin(), e = bb->end(); it != e;) { - llvm::Instruction* inst = it; - llvm::BasicBlock::iterator nextIt = ++it; - // Extract the Dalvik offset from the instruction - uint32_t opcode = inst->getOpcode(); - llvm::MDNode* dexOffsetNode = inst->getMetadata("DexOff"); - if (dexOffsetNode != NULL) { - llvm::ConstantInt* dexOffsetValue = - static_cast(dexOffsetNode->getOperand(0)); - cUnit->currentDalvikOffset = dexOffsetValue->getZExtValue(); - } - - oatResetRegPool(cUnit); - if (cUnit->disableOpt & (1 << kTrackLiveTemps)) { - oatClobberAllRegs(cUnit); - } - - if (cUnit->disableOpt & (1 << kSuppressLoads)) { - oatResetDefTracking(cUnit); - } - - #ifndef NDEBUG - /* Reset temp tracking sanity check */ - cUnit->liveSReg = INVALID_SREG; - #endif - - // TODO: use llvm opcode name here instead of "boundary" if verbose - LIR* boundaryLIR = markBoundary(cUnit, cUnit->currentDalvikOffset, "boundary"); - - /* Remember the first LIR for thisl block*/ - if (headLIR == NULL) { - headLIR = boundaryLIR; - headLIR->defMask = ENCODE_ALL; - } - - switch(opcode) { - - case llvm::Instruction::ICmp: { - llvm::Instruction* nextInst = nextIt; - llvm::BranchInst* brInst = llvm::dyn_cast(nextInst); - if (brInst != NULL /* and... */) { - cvtICmpBr(cUnit, inst, brInst); - ++it; - } else { - cvtICmp(cUnit, inst); - } - } - break; - - case llvm::Instruction::Call: { - llvm::CallInst* callInst = llvm::dyn_cast(inst); - llvm::Function* callee = callInst->getCalledFunction(); - greenland::IntrinsicHelper::IntrinsicId id = - cUnit->intrinsic_helper->GetIntrinsicId(callee); - switch (id) { - case greenland::IntrinsicHelper::AllocaShadowFrame: - case greenland::IntrinsicHelper::SetShadowFrameEntry: - case greenland::IntrinsicHelper::PopShadowFrame: - case greenland::IntrinsicHelper::SetVReg: - // Ignore shadow frame stuff for quick compiler - break; - case greenland::IntrinsicHelper::CopyInt: - case greenland::IntrinsicHelper::CopyObj: - case greenland::IntrinsicHelper::CopyFloat: - case greenland::IntrinsicHelper::CopyLong: - case greenland::IntrinsicHelper::CopyDouble: - cvtCopy(cUnit, callInst); - break; - case greenland::IntrinsicHelper::ConstInt: - case greenland::IntrinsicHelper::ConstObj: - case greenland::IntrinsicHelper::ConstLong: - case greenland::IntrinsicHelper::ConstFloat: - case greenland::IntrinsicHelper::ConstDouble: - cvtConst(cUnit, callInst); - break; - case greenland::IntrinsicHelper::DivInt: - case greenland::IntrinsicHelper::DivLong: - cvtBinOp(cUnit, kOpDiv, inst); - break; - case greenland::IntrinsicHelper::RemInt: - case greenland::IntrinsicHelper::RemLong: - cvtBinOp(cUnit, kOpRem, inst); - break; - case greenland::IntrinsicHelper::MethodInfo: - // Already dealt with - just ignore it here. - break; - case greenland::IntrinsicHelper::CheckSuspend: - genSuspendTest(cUnit, 0 /* optFlags already applied */); - break; - case greenland::IntrinsicHelper::HLInvokeObj: - case greenland::IntrinsicHelper::HLInvokeFloat: - case greenland::IntrinsicHelper::HLInvokeDouble: - case greenland::IntrinsicHelper::HLInvokeLong: - case greenland::IntrinsicHelper::HLInvokeInt: - cvtInvoke(cUnit, callInst, false /* isVoid */, false /* newArray */); - break; - case greenland::IntrinsicHelper::HLInvokeVoid: - cvtInvoke(cUnit, callInst, true /* isVoid */, false /* newArray */); - break; - case greenland::IntrinsicHelper::HLFilledNewArray: - cvtInvoke(cUnit, callInst, false /* isVoid */, true /* newArray */); - break; - case greenland::IntrinsicHelper::HLFillArrayData: - cvtFillArrayData(cUnit, callInst); - break; - case greenland::IntrinsicHelper::ConstString: - cvtConstObject(cUnit, callInst, true /* isString */); - break; - case greenland::IntrinsicHelper::ConstClass: - cvtConstObject(cUnit, callInst, false /* isString */); - break; - case greenland::IntrinsicHelper::HLCheckCast: - cvtCheckCast(cUnit, callInst); - break; - case greenland::IntrinsicHelper::NewInstance: - cvtNewInstance(cUnit, callInst); - break; - case greenland::IntrinsicHelper::HLSgetObject: - cvtSget(cUnit, callInst, false /* wide */, true /* Object */); - break; - case greenland::IntrinsicHelper::HLSget: - case greenland::IntrinsicHelper::HLSgetFloat: - case greenland::IntrinsicHelper::HLSgetBoolean: - case greenland::IntrinsicHelper::HLSgetByte: - case greenland::IntrinsicHelper::HLSgetChar: - case greenland::IntrinsicHelper::HLSgetShort: - cvtSget(cUnit, callInst, false /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSgetWide: - case greenland::IntrinsicHelper::HLSgetDouble: - cvtSget(cUnit, callInst, true /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSput: - case greenland::IntrinsicHelper::HLSputFloat: - case greenland::IntrinsicHelper::HLSputBoolean: - case greenland::IntrinsicHelper::HLSputByte: - case greenland::IntrinsicHelper::HLSputChar: - case greenland::IntrinsicHelper::HLSputShort: - cvtSput(cUnit, callInst, false /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSputWide: - case greenland::IntrinsicHelper::HLSputDouble: - cvtSput(cUnit, callInst, true /* wide */, false /* Object */); - break; - case greenland::IntrinsicHelper::HLSputObject: - cvtSput(cUnit, callInst, false /* wide */, true /* Object */); - break; - case greenland::IntrinsicHelper::GetException: - cvtMoveException(cUnit, callInst); - break; - case greenland::IntrinsicHelper::HLThrowException: - cvtThrow(cUnit, callInst); - break; - case greenland::IntrinsicHelper::MonitorEnter: - cvtMonitorEnterExit(cUnit, true /* isEnter */, callInst); - break; - case greenland::IntrinsicHelper::MonitorExit: - cvtMonitorEnterExit(cUnit, false /* isEnter */, callInst); - break; - case greenland::IntrinsicHelper::OptArrayLength: - cvtArrayLength(cUnit, callInst); - break; - case greenland::IntrinsicHelper::NewArray: - cvtNewArray(cUnit, callInst); - break; - case greenland::IntrinsicHelper::InstanceOf: - cvtInstanceOf(cUnit, callInst); - break; - - case greenland::IntrinsicHelper::HLArrayGet: - case greenland::IntrinsicHelper::HLArrayGetObject: - case greenland::IntrinsicHelper::HLArrayGetFloat: - cvtAget(cUnit, callInst, kWord, 2); - break; - case greenland::IntrinsicHelper::HLArrayGetWide: - case greenland::IntrinsicHelper::HLArrayGetDouble: - cvtAget(cUnit, callInst, kLong, 3); - break; - case greenland::IntrinsicHelper::HLArrayGetBoolean: - cvtAget(cUnit, callInst, kUnsignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayGetByte: - cvtAget(cUnit, callInst, kSignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayGetChar: - cvtAget(cUnit, callInst, kUnsignedHalf, 1); - break; - case greenland::IntrinsicHelper::HLArrayGetShort: - cvtAget(cUnit, callInst, kSignedHalf, 1); - break; - - case greenland::IntrinsicHelper::HLArrayPut: - case greenland::IntrinsicHelper::HLArrayPutFloat: - cvtAputPrimitive(cUnit, callInst, kWord, 2); - break; - case greenland::IntrinsicHelper::HLArrayPutObject: - cvtAputObj(cUnit, callInst); - break; - case greenland::IntrinsicHelper::HLArrayPutWide: - case greenland::IntrinsicHelper::HLArrayPutDouble: - cvtAputPrimitive(cUnit, callInst, kLong, 3); - break; - case greenland::IntrinsicHelper::HLArrayPutBoolean: - cvtAputPrimitive(cUnit, callInst, kUnsignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayPutByte: - cvtAputPrimitive(cUnit, callInst, kSignedByte, 0); - break; - case greenland::IntrinsicHelper::HLArrayPutChar: - cvtAputPrimitive(cUnit, callInst, kUnsignedHalf, 1); - break; - case greenland::IntrinsicHelper::HLArrayPutShort: - cvtAputPrimitive(cUnit, callInst, kSignedHalf, 1); - break; - - case greenland::IntrinsicHelper::HLIGet: - case greenland::IntrinsicHelper::HLIGetFloat: - cvtIget(cUnit, callInst, kWord, false /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetObject: - cvtIget(cUnit, callInst, kWord, false /* isWide */, true /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetWide: - case greenland::IntrinsicHelper::HLIGetDouble: - cvtIget(cUnit, callInst, kLong, true /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetBoolean: - cvtIget(cUnit, callInst, kUnsignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetByte: - cvtIget(cUnit, callInst, kSignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetChar: - cvtIget(cUnit, callInst, kUnsignedHalf, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIGetShort: - cvtIget(cUnit, callInst, kSignedHalf, false /* isWide */, - false /* obj */); - break; - - case greenland::IntrinsicHelper::HLIPut: - case greenland::IntrinsicHelper::HLIPutFloat: - cvtIput(cUnit, callInst, kWord, false /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutObject: - cvtIput(cUnit, callInst, kWord, false /* isWide */, true /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutWide: - case greenland::IntrinsicHelper::HLIPutDouble: - cvtIput(cUnit, callInst, kLong, true /* isWide */, false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutBoolean: - cvtIput(cUnit, callInst, kUnsignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutByte: - cvtIput(cUnit, callInst, kSignedByte, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutChar: - cvtIput(cUnit, callInst, kUnsignedHalf, false /* isWide */, - false /* obj */); - break; - case greenland::IntrinsicHelper::HLIPutShort: - cvtIput(cUnit, callInst, kSignedHalf, false /* isWide */, - false /* obj */); - break; - - case greenland::IntrinsicHelper::IntToChar: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_CHAR); - break; - case greenland::IntrinsicHelper::IntToShort: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_SHORT); - break; - case greenland::IntrinsicHelper::IntToByte: - cvtIntNarrowing(cUnit, callInst, Instruction::INT_TO_BYTE); - break; - - case greenland::IntrinsicHelper::F2I: - case greenland::IntrinsicHelper::D2I: - case greenland::IntrinsicHelper::F2L: - case greenland::IntrinsicHelper::D2L: - cvtFPToInt(cUnit, callInst); - break; - - case greenland::IntrinsicHelper::CmplFloat: - cvtFPCompare(cUnit, callInst, Instruction::CMPL_FLOAT); - break; - case greenland::IntrinsicHelper::CmpgFloat: - cvtFPCompare(cUnit, callInst, Instruction::CMPG_FLOAT); - break; - case greenland::IntrinsicHelper::CmplDouble: - cvtFPCompare(cUnit, callInst, Instruction::CMPL_DOUBLE); - break; - case greenland::IntrinsicHelper::CmpgDouble: - cvtFPCompare(cUnit, callInst, Instruction::CMPG_DOUBLE); - break; - - case greenland::IntrinsicHelper::CmpLong: - cvtLongCompare(cUnit, callInst); - break; - - case greenland::IntrinsicHelper::SHLLong: - cvtShiftOp(cUnit, Instruction::SHL_LONG, callInst); - break; - case greenland::IntrinsicHelper::SHRLong: - cvtShiftOp(cUnit, Instruction::SHR_LONG, callInst); - break; - case greenland::IntrinsicHelper::USHRLong: - cvtShiftOp(cUnit, Instruction::USHR_LONG, callInst); - break; - case greenland::IntrinsicHelper::SHLInt: - cvtShiftOp(cUnit, Instruction::SHL_INT, callInst); - break; - case greenland::IntrinsicHelper::SHRInt: - cvtShiftOp(cUnit, Instruction::SHR_INT, callInst); - break; - case greenland::IntrinsicHelper::USHRInt: - cvtShiftOp(cUnit, Instruction::USHR_INT, callInst); - break; - - case greenland::IntrinsicHelper::CatchTargets: { - llvm::SwitchInst* swInst = - llvm::dyn_cast(nextIt); - DCHECK(swInst != NULL); - /* - * Discard the edges and the following conditional branch. - * Do a direct branch to the default target (which is the - * "work" portion of the pair. - * TODO: awful code layout - rework - */ - llvm::BasicBlock* targetBB = swInst->getDefaultDest(); - DCHECK(targetBB != NULL); - opUnconditionalBranch(cUnit, - cUnit->blockToLabelMap.Get(targetBB)); - ++it; - // Set next bb to default target - improves code layout - nextBB = targetBB; - } - break; - - default: - LOG(FATAL) << "Unexpected intrinsic " << (int)id << ", " - << cUnit->intrinsic_helper->GetName(id); - } - } - break; - - case llvm::Instruction::Br: cvtBr(cUnit, inst); break; - case llvm::Instruction::Add: cvtBinOp(cUnit, kOpAdd, inst); break; - case llvm::Instruction::Sub: cvtBinOp(cUnit, kOpSub, inst); break; - case llvm::Instruction::Mul: cvtBinOp(cUnit, kOpMul, inst); break; - case llvm::Instruction::SDiv: cvtBinOp(cUnit, kOpDiv, inst); break; - case llvm::Instruction::SRem: cvtBinOp(cUnit, kOpRem, inst); break; - case llvm::Instruction::And: cvtBinOp(cUnit, kOpAnd, inst); break; - case llvm::Instruction::Or: cvtBinOp(cUnit, kOpOr, inst); break; - case llvm::Instruction::Xor: cvtBinOp(cUnit, kOpXor, inst); break; - case llvm::Instruction::PHI: cvtPhi(cUnit, inst); break; - case llvm::Instruction::Ret: cvtRet(cUnit, inst); break; - case llvm::Instruction::FAdd: cvtBinFPOp(cUnit, kOpAdd, inst); break; - case llvm::Instruction::FSub: cvtBinFPOp(cUnit, kOpSub, inst); break; - case llvm::Instruction::FMul: cvtBinFPOp(cUnit, kOpMul, inst); break; - case llvm::Instruction::FDiv: cvtBinFPOp(cUnit, kOpDiv, inst); break; - case llvm::Instruction::FRem: cvtBinFPOp(cUnit, kOpRem, inst); break; - case llvm::Instruction::SIToFP: cvtIntToFP(cUnit, inst); break; - case llvm::Instruction::FPTrunc: cvtDoubleToFloat(cUnit, inst); break; - case llvm::Instruction::FPExt: cvtFloatToDouble(cUnit, inst); break; - case llvm::Instruction::Trunc: cvtTrunc(cUnit, inst); break; - - case llvm::Instruction::ZExt: cvtIntExt(cUnit, inst, false /* signed */); - break; - case llvm::Instruction::SExt: cvtIntExt(cUnit, inst, true /* signed */); - break; - - case llvm::Instruction::Switch: cvtSwitch(cUnit, inst); break; - - case llvm::Instruction::Unreachable: - break; // FIXME: can we really ignore these? - - case llvm::Instruction::Shl: - case llvm::Instruction::LShr: - case llvm::Instruction::AShr: - case llvm::Instruction::Invoke: - case llvm::Instruction::FPToUI: - case llvm::Instruction::FPToSI: - case llvm::Instruction::UIToFP: - case llvm::Instruction::PtrToInt: - case llvm::Instruction::IntToPtr: - case llvm::Instruction::FCmp: - case llvm::Instruction::URem: - case llvm::Instruction::UDiv: - case llvm::Instruction::Resume: - case llvm::Instruction::Alloca: - case llvm::Instruction::GetElementPtr: - case llvm::Instruction::Fence: - case llvm::Instruction::AtomicCmpXchg: - case llvm::Instruction::AtomicRMW: - case llvm::Instruction::BitCast: - case llvm::Instruction::VAArg: - case llvm::Instruction::Select: - case llvm::Instruction::UserOp1: - case llvm::Instruction::UserOp2: - case llvm::Instruction::ExtractElement: - case llvm::Instruction::InsertElement: - case llvm::Instruction::ShuffleVector: - case llvm::Instruction::ExtractValue: - case llvm::Instruction::InsertValue: - case llvm::Instruction::LandingPad: - case llvm::Instruction::IndirectBr: - case llvm::Instruction::Load: - case llvm::Instruction::Store: - LOG(FATAL) << "Unexpected llvm opcode: " << opcode; break; - - default: - LOG(FATAL) << "Unknown llvm opcode: " << inst->getOpcodeName(); - break; - } - } - - if (headLIR != NULL) { - oatApplyLocalOptimizations(cUnit, headLIR, cUnit->lastLIRInsn); - } - if (nextBB != NULL) { - bb = nextBB; - nextBB = NULL; - } - } - return false; -} - -/* - * Convert LLVM_IR to MIR: - * o Iterate through the LLVM_IR and construct a graph using - * standard MIR building blocks. - * o Perform a basic-block optimization pass to remove unnecessary - * store/load sequences. - * o Convert the LLVM Value operands into RegLocations where applicable. - * o Create ssaRep def/use operand arrays for each converted LLVM opcode - * o Perform register promotion - * o Iterate through the graph a basic block at a time, generating - * LIR. - * o Assemble LIR as usual. - * o Profit. - */ -void oatMethodBitcode2LIR(CompilationUnit* cUnit) -{ - llvm::Function* func = cUnit->func; - int numBasicBlocks = func->getBasicBlockList().size(); - // Allocate a list for LIR basic block labels - cUnit->blockLabelList = - (LIR*)oatNew(cUnit, sizeof(LIR) * numBasicBlocks, true, kAllocLIR); - LIR* labelList = cUnit->blockLabelList; - int nextLabel = 0; - for (llvm::Function::iterator i = func->begin(), - e = func->end(); i != e; ++i) { - cUnit->blockToLabelMap.Put(static_cast(i), - &labelList[nextLabel++]); - } - - /* - * Keep honest - clear regLocations, Value => RegLocation, - * promotion map and VmapTables. - */ - cUnit->locMap.clear(); // Start fresh - cUnit->regLocation = NULL; - for (int i = 0; i < cUnit->numDalvikRegisters + cUnit->numCompilerTemps + 1; - i++) { - cUnit->promotionMap[i].coreLocation = kLocDalvikFrame; - cUnit->promotionMap[i].fpLocation = kLocDalvikFrame; - } - cUnit->coreSpillMask = 0; - cUnit->numCoreSpills = 0; - cUnit->fpSpillMask = 0; - cUnit->numFPSpills = 0; - cUnit->coreVmapTable.clear(); - cUnit->fpVmapTable.clear(); - - /* - * At this point, we've lost all knowledge of register promotion. - * Rebuild that info from the MethodInfo intrinsic (if it - * exists - not required for correctness). Normally, this will - * be the first instruction we encounter, so we won't have to iterate - * through everything. - */ - for (llvm::inst_iterator i = llvm::inst_begin(func), - e = llvm::inst_end(func); i != e; ++i) { - llvm::CallInst* callInst = llvm::dyn_cast(&*i); - if (callInst != NULL) { - llvm::Function* callee = callInst->getCalledFunction(); - greenland::IntrinsicHelper::IntrinsicId id = - cUnit->intrinsic_helper->GetIntrinsicId(callee); - if (id == greenland::IntrinsicHelper::MethodInfo) { - if (cUnit->printMe) { - LOG(INFO) << "Found MethodInfo"; - } - llvm::MDNode* regInfoNode = callInst->getMetadata("RegInfo"); - if (regInfoNode != NULL) { - llvm::ConstantInt* numInsValue = - static_cast(regInfoNode->getOperand(0)); - llvm::ConstantInt* numRegsValue = - static_cast(regInfoNode->getOperand(1)); - llvm::ConstantInt* numOutsValue = - static_cast(regInfoNode->getOperand(2)); - llvm::ConstantInt* numCompilerTempsValue = - static_cast(regInfoNode->getOperand(3)); - llvm::ConstantInt* numSSARegsValue = - static_cast(regInfoNode->getOperand(4)); - if (cUnit->printMe) { - LOG(INFO) << "RegInfo - Ins:" << numInsValue->getZExtValue() - << ", Regs:" << numRegsValue->getZExtValue() - << ", Outs:" << numOutsValue->getZExtValue() - << ", CTemps:" << numCompilerTempsValue->getZExtValue() - << ", SSARegs:" << numSSARegsValue->getZExtValue(); - } - } - llvm::MDNode* pmapInfoNode = callInst->getMetadata("PromotionMap"); - if (pmapInfoNode != NULL) { - int elems = pmapInfoNode->getNumOperands(); - if (cUnit->printMe) { - LOG(INFO) << "PMap size: " << elems; - } - for (int i = 0; i < elems; i++) { - llvm::ConstantInt* rawMapData = - static_cast(pmapInfoNode->getOperand(i)); - uint32_t mapData = rawMapData->getZExtValue(); - PromotionMap* p = &cUnit->promotionMap[i]; - p->firstInPair = (mapData >> 24) & 0xff; - p->fpReg = (mapData >> 16) & 0xff; - p->coreReg = (mapData >> 8) & 0xff; - p->fpLocation = static_cast((mapData >> 4) & 0xf); - if (p->fpLocation == kLocPhysReg) { - oatRecordFpPromotion(cUnit, p->fpReg, i); - } - p->coreLocation = static_cast(mapData & 0xf); - if (p->coreLocation == kLocPhysReg) { - oatRecordCorePromotion(cUnit, p->coreReg, i); - } - } - if (cUnit->printMe) { - oatDumpPromotionMap(cUnit); - } - } - break; - } - } - } - oatAdjustSpillMask(cUnit); - cUnit->frameSize = oatComputeFrameSize(cUnit); - - // Create RegLocations for arguments - llvm::Function::arg_iterator it(cUnit->func->arg_begin()); - llvm::Function::arg_iterator it_end(cUnit->func->arg_end()); - for (; it != it_end; ++it) { - llvm::Value* val = it; - createLocFromValue(cUnit, val); - } - // Create RegLocations for all non-argument defintions - for (llvm::inst_iterator i = llvm::inst_begin(func), - e = llvm::inst_end(func); i != e; ++i) { - llvm::Value* val = &*i; - if (val->hasName() && (val->getName().str().c_str()[0] == 'v')) { - createLocFromValue(cUnit, val); - } - } - - // Walk the blocks, generating code. - for (llvm::Function::iterator i = cUnit->func->begin(), - e = cUnit->func->end(); i != e; ++i) { - methodBitcodeBlockCodeGen(cUnit, static_cast(i)); - } - - handleSuspendLaunchpads(cUnit); - - handleThrowLaunchpads(cUnit); - - handleIntrinsicLaunchpads(cUnit); - - cUnit->func->eraseFromParent(); - cUnit->func = NULL; -} - - -} // namespace art diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc deleted file mode 100644 index 3170abc7f0..0000000000 --- a/src/compiler/codegen/MethodCodegenDriver.cc +++ /dev/null @@ -1,1066 +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. - */ - -#include "object_utils.h" - -namespace art { - -const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, - INVALID_REG, INVALID_REG, INVALID_SREG, - INVALID_SREG}; - -/* Mark register usage state and return long retloc */ -RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble) -{ - RegLocation gpr_res = locCReturnWide(); - RegLocation fpr_res = locCReturnDouble(); - RegLocation res = isDouble ? fpr_res : gpr_res; - oatClobber(cUnit, res.lowReg); - oatClobber(cUnit, res.highReg); - oatLockTemp(cUnit, res.lowReg); - oatLockTemp(cUnit, res.highReg); - oatMarkPair(cUnit, res.lowReg, res.highReg); - return res; -} - -RegLocation oatGetReturn(CompilationUnit* cUnit, bool isFloat) -{ - RegLocation gpr_res = locCReturn(); - RegLocation fpr_res = locCReturnFloat(); - RegLocation res = isFloat ? fpr_res : gpr_res; - oatClobber(cUnit, res.lowReg); - if (cUnit->instructionSet == kMips) { - oatMarkInUse(cUnit, res.lowReg); - } else { - oatLockTemp(cUnit, res.lowReg); - } - return res; -} - -void genInvoke(CompilationUnit* cUnit, CallInfo* info) -{ - if (genIntrinsic(cUnit, info)) { - return; - } - InvokeType originalType = info->type; // avoiding mutation by ComputeInvokeInfo - int callState = 0; - LIR* nullCk; - LIR** pNullCk = NULL; - NextCallInsn nextCallInsn; - oatFlushAllRegs(cUnit); /* Everything to home location */ - // Explicit register usage - oatLockCallTemps(cUnit); - - OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, - *cUnit->dex_file, - cUnit->code_item, cUnit->method_idx, - cUnit->access_flags); - - uint32_t dexMethodIdx = info->index; - int vtableIdx; - uintptr_t directCode; - uintptr_t directMethod; - bool skipThis; - bool fastPath = - cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, info->type, - vtableIdx, directCode, - directMethod) - && !SLOW_INVOKE_PATH; - if (info->type == kInterface) { - if (fastPath) { - pNullCk = &nullCk; - } - nextCallInsn = fastPath ? nextInterfaceCallInsn - : nextInterfaceCallInsnWithAccessCheck; - skipThis = false; - } else if (info->type == kDirect) { - if (fastPath) { - pNullCk = &nullCk; - } - nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP; - skipThis = false; - } else if (info->type == kStatic) { - nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP; - skipThis = false; - } else if (info->type == kSuper) { - DCHECK(!fastPath); // Fast path is a direct call. - nextCallInsn = nextSuperCallInsnSP; - skipThis = false; - } else { - DCHECK_EQ(info->type, kVirtual); - nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP; - skipThis = fastPath; - } - if (!info->isRange) { - callState = genDalvikArgsNoRange(cUnit, info, callState, pNullCk, - nextCallInsn, dexMethodIdx, - vtableIdx, directCode, directMethod, - originalType, skipThis); - } else { - callState = genDalvikArgsRange(cUnit, info, callState, pNullCk, - nextCallInsn, dexMethodIdx, vtableIdx, - directCode, directMethod, originalType, - skipThis); - } - // Finish up any of the call sequence not interleaved in arg loading - while (callState >= 0) { - callState = nextCallInsn(cUnit, info, callState, dexMethodIdx, - vtableIdx, directCode, directMethod, - originalType); - } - if (cUnit->enableDebug & (1 << kDebugDisplayMissingTargets)) { - genShowTarget(cUnit); - } - LIR* callInst; - if (cUnit->instructionSet != kX86) { - callInst = opReg(cUnit, kOpBlx, targetReg(kInvokeTgt)); - } else { - if (fastPath && info->type != kInterface) { - callInst = opMem(cUnit, kOpBlx, targetReg(kArg0), - AbstractMethod::GetCodeOffset().Int32Value()); - } else { - int trampoline = 0; - switch (info->type) { - case kInterface: - trampoline = fastPath ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline) - : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); - break; - case kDirect: - trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); - break; - case kStatic: - trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); - break; - case kSuper: - trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); - break; - case kVirtual: - trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); - break; - default: - LOG(FATAL) << "Unexpected invoke type"; - } - callInst = opThreadMem(cUnit, kOpBlx, trampoline); - } - } - markSafepointPC(cUnit, callInst); - - oatClobberCalleeSave(cUnit); - if (info->result.location != kLocInvalid) { - // We have a following MOVE_RESULT - do it now. - if (info->result.wide) { - RegLocation retLoc = oatGetReturnWide(cUnit, info->result.fp); - storeValueWide(cUnit, info->result, retLoc); - } else { - RegLocation retLoc = oatGetReturn(cUnit, info->result.fp); - storeValue(cUnit, info->result, retLoc); - } - } -} - -/* - * Build an array of location records for the incoming arguments. - * Note: one location record per word of arguments, with dummy - * high-word loc for wide arguments. Also pull up any following - * MOVE_RESULT and incorporate it into the invoke. - */ -CallInfo* oatNewCallInfo(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, - InvokeType type, bool isRange) -{ - CallInfo* info = (CallInfo*)oatNew(cUnit, sizeof(CallInfo), true, - kAllocMisc); - MIR* moveResultMIR = oatFindMoveResult(cUnit, bb, mir); - if (moveResultMIR == NULL) { - info->result.location = kLocInvalid; - } else { - info->result = oatGetRawDest(cUnit, moveResultMIR); - moveResultMIR->dalvikInsn.opcode = Instruction::NOP; - } - info->numArgWords = mir->ssaRep->numUses; - info->args = (info->numArgWords == 0) ? NULL : (RegLocation*) - oatNew(cUnit, sizeof(RegLocation) * info->numArgWords, false, kAllocMisc); - for (int i = 0; i < info->numArgWords; i++) { - info->args[i] = oatGetRawSrc(cUnit, mir, i); - } - info->optFlags = mir->optimizationFlags; - info->type = type; - info->isRange = isRange; - info->index = mir->dalvikInsn.vB; - info->offset = mir->offset; - return info; -} - -/* - * Target-independent code generation. Use only high-level - * load/store utilities here, or target-dependent genXX() handlers - * when necessary. - */ -bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir, - BasicBlock* bb, LIR* labelList) -{ - bool res = false; // Assume success - RegLocation rlSrc[3]; - RegLocation rlDest = badLoc; - RegLocation rlResult = badLoc; - Instruction::Code opcode = mir->dalvikInsn.opcode; - int optFlags = mir->optimizationFlags; - uint32_t vB = mir->dalvikInsn.vB; - uint32_t vC = mir->dalvikInsn.vC; - - /* Prep Src and Dest locations */ - int nextSreg = 0; - int nextLoc = 0; - int attrs = oatDataFlowAttributes[opcode]; - rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc; - if (attrs & DF_UA) { - if (attrs & DF_A_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - nextSreg+= 2; - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - nextSreg++; - } - } - if (attrs & DF_UB) { - if (attrs & DF_B_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - nextSreg+= 2; - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - nextSreg++; - } - } - if (attrs & DF_UC) { - if (attrs & DF_C_WIDE) { - rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg); - } else { - rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg); - } - } - if (attrs & DF_DA) { - if (attrs & DF_A_WIDE) { - rlDest = oatGetDestWide(cUnit, mir); - } else { - rlDest = oatGetDest(cUnit, mir); - } - } - switch (opcode) { - case Instruction::NOP: - break; - - case Instruction::MOVE_EXCEPTION: - genMoveException(cUnit, rlDest); - break; - case Instruction::RETURN_VOID: - if (!(cUnit->attrs & METHOD_IS_LEAF)) { - genSuspendTest(cUnit, optFlags); - } - break; - - case Instruction::RETURN: - case Instruction::RETURN_OBJECT: - if (!(cUnit->attrs & METHOD_IS_LEAF)) { - genSuspendTest(cUnit, optFlags); - } - storeValue(cUnit, oatGetReturn(cUnit, cUnit->shorty[0] == 'F'), rlSrc[0]); - break; - - case Instruction::RETURN_WIDE: - if (!(cUnit->attrs & METHOD_IS_LEAF)) { - genSuspendTest(cUnit, optFlags); - } - storeValueWide(cUnit, oatGetReturnWide(cUnit, - cUnit->shorty[0] == 'D'), rlSrc[0]); - break; - - case Instruction::MOVE_RESULT_WIDE: - if (optFlags & MIR_INLINED) - break; // Nop - combined w/ previous invoke - storeValueWide(cUnit, rlDest, oatGetReturnWide(cUnit, rlDest.fp)); - break; - - case Instruction::MOVE_RESULT: - case Instruction::MOVE_RESULT_OBJECT: - if (optFlags & MIR_INLINED) - break; // Nop - combined w/ previous invoke - storeValue(cUnit, rlDest, oatGetReturn(cUnit, rlDest.fp)); - break; - - case Instruction::MOVE: - case Instruction::MOVE_OBJECT: - case Instruction::MOVE_16: - case Instruction::MOVE_OBJECT_16: - case Instruction::MOVE_FROM16: - case Instruction::MOVE_OBJECT_FROM16: - storeValue(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::MOVE_WIDE: - case Instruction::MOVE_WIDE_16: - case Instruction::MOVE_WIDE_FROM16: - storeValueWide(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::CONST: - case Instruction::CONST_4: - case Instruction::CONST_16: - rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - loadConstantNoClobber(cUnit, rlResult.lowReg, vB); - storeValue(cUnit, rlDest, rlResult); - break; - - case Instruction::CONST_HIGH16: - rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - loadConstantNoClobber(cUnit, rlResult.lowReg, vB << 16); - storeValue(cUnit, rlDest, rlResult); - break; - - case Instruction::CONST_WIDE_16: - case Instruction::CONST_WIDE_32: - rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, vB, - (vB & 0x80000000) ? -1 : 0); - storeValueWide(cUnit, rlDest, rlResult); - break; - - case Instruction::CONST_WIDE: - rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, - mir->dalvikInsn.vB_wide & 0xffffffff, - (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff); - storeValueWide(cUnit, rlDest, rlResult); - break; - - case Instruction::CONST_WIDE_HIGH16: - rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, - 0, vB << 16); - storeValueWide(cUnit, rlDest, rlResult); - break; - - case Instruction::MONITOR_ENTER: - genMonitorEnter(cUnit, optFlags, rlSrc[0]); - break; - - case Instruction::MONITOR_EXIT: - genMonitorExit(cUnit, optFlags, rlSrc[0]); - break; - - case Instruction::CHECK_CAST: - genCheckCast(cUnit, vB, rlSrc[0]); - break; - - case Instruction::INSTANCE_OF: - genInstanceof(cUnit, vC, rlDest, rlSrc[0]); - break; - - case Instruction::NEW_INSTANCE: - genNewInstance(cUnit, vB, rlDest); - break; - - case Instruction::THROW: - genThrow(cUnit, rlSrc[0]); - break; - - case Instruction::ARRAY_LENGTH: - int lenOffset; - lenOffset = Array::LengthOffset().Int32Value(); - rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg); - genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, optFlags); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset, rlResult.lowReg); - storeValue(cUnit, rlDest, rlResult); - break; - - case Instruction::CONST_STRING: - case Instruction::CONST_STRING_JUMBO: - genConstString(cUnit, vB, rlDest); - break; - - case Instruction::CONST_CLASS: - genConstClass(cUnit, vB, rlDest); - break; - - case Instruction::FILL_ARRAY_DATA: - genFillArrayData(cUnit, vB, rlSrc[0]); - break; - - case Instruction::FILLED_NEW_ARRAY: - genFilledNewArray(cUnit, oatNewCallInfo(cUnit, bb, mir, kStatic, - false /* not range */)); - break; - - case Instruction::FILLED_NEW_ARRAY_RANGE: - genFilledNewArray(cUnit, oatNewCallInfo(cUnit, bb, mir, kStatic, - true /* range */)); - break; - - case Instruction::NEW_ARRAY: - genNewArray(cUnit, vC, rlDest, rlSrc[0]); - break; - - case Instruction::GOTO: - case Instruction::GOTO_16: - case Instruction::GOTO_32: - if (bb->taken->startOffset <= mir->offset) { - genSuspendTestAndBranch(cUnit, optFlags, &labelList[bb->taken->id]); - } else { - opUnconditionalBranch(cUnit, &labelList[bb->taken->id]); - } - break; - - case Instruction::PACKED_SWITCH: - genPackedSwitch(cUnit, vB, rlSrc[0]); - break; - - case Instruction::SPARSE_SWITCH: - genSparseSwitch(cUnit, vB, rlSrc[0]); - break; - - case Instruction::CMPL_FLOAT: - case Instruction::CMPG_FLOAT: - case Instruction::CMPL_DOUBLE: - case Instruction::CMPG_DOUBLE: - res = genCmpFP(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::CMP_LONG: - genCmpLong(cUnit, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::IF_EQ: - case Instruction::IF_NE: - case Instruction::IF_LT: - case Instruction::IF_GE: - case Instruction::IF_GT: - case Instruction::IF_LE: { - LIR* taken = &labelList[bb->taken->id]; - LIR* fallThrough = &labelList[bb->fallThrough->id]; - bool backwardBranch; - backwardBranch = (bb->taken->startOffset <= mir->offset); - if (backwardBranch) { - genSuspendTest(cUnit, optFlags); - } - genCompareAndBranch(cUnit, opcode, rlSrc[0], rlSrc[1], taken, - fallThrough); - break; - } - - case Instruction::IF_EQZ: - case Instruction::IF_NEZ: - case Instruction::IF_LTZ: - case Instruction::IF_GEZ: - case Instruction::IF_GTZ: - case Instruction::IF_LEZ: { - LIR* taken = &labelList[bb->taken->id]; - LIR* fallThrough = &labelList[bb->fallThrough->id]; - bool backwardBranch; - backwardBranch = (bb->taken->startOffset <= mir->offset); - if (backwardBranch) { - genSuspendTest(cUnit, optFlags); - } - genCompareZeroAndBranch(cUnit, opcode, rlSrc[0], taken, fallThrough); - break; - } - - case Instruction::AGET_WIDE: - genArrayGet(cUnit, optFlags, kLong, rlSrc[0], rlSrc[1], rlDest, 3); - break; - case Instruction::AGET: - case Instruction::AGET_OBJECT: - genArrayGet(cUnit, optFlags, kWord, rlSrc[0], rlSrc[1], rlDest, 2); - break; - case Instruction::AGET_BOOLEAN: - genArrayGet(cUnit, optFlags, kUnsignedByte, rlSrc[0], rlSrc[1], rlDest, 0); - break; - case Instruction::AGET_BYTE: - genArrayGet(cUnit, optFlags, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0); - break; - case Instruction::AGET_CHAR: - genArrayGet(cUnit, optFlags, kUnsignedHalf, rlSrc[0], rlSrc[1], rlDest, 1); - break; - case Instruction::AGET_SHORT: - genArrayGet(cUnit, optFlags, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1); - break; - case Instruction::APUT_WIDE: - genArrayPut(cUnit, optFlags, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3); - break; - case Instruction::APUT: - genArrayPut(cUnit, optFlags, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2); - break; - case Instruction::APUT_OBJECT: - genArrayObjPut(cUnit, optFlags, rlSrc[1], rlSrc[2], rlSrc[0], 2); - break; - case Instruction::APUT_SHORT: - case Instruction::APUT_CHAR: - genArrayPut(cUnit, optFlags, kUnsignedHalf, rlSrc[1], rlSrc[2], rlSrc[0], 1); - break; - case Instruction::APUT_BYTE: - case Instruction::APUT_BOOLEAN: - genArrayPut(cUnit, optFlags, kUnsignedByte, rlSrc[1], rlSrc[2], - rlSrc[0], 0); - break; - - case Instruction::IGET_OBJECT: - //case Instruction::IGET_OBJECT_VOLATILE: - genIGet(cUnit, vC, optFlags, kWord, rlDest, rlSrc[0], false, true); - break; - - case Instruction::IGET_WIDE: - //case Instruction::IGET_WIDE_VOLATILE: - genIGet(cUnit, vC, optFlags, kLong, rlDest, rlSrc[0], true, false); - break; - - case Instruction::IGET: - //case Instruction::IGET_VOLATILE: - genIGet(cUnit, vC, optFlags, kWord, rlDest, rlSrc[0], false, false); - break; - - case Instruction::IGET_CHAR: - genIGet(cUnit, vC, optFlags, kUnsignedHalf, rlDest, rlSrc[0], false, false); - break; - - case Instruction::IGET_SHORT: - genIGet(cUnit, vC, optFlags, kSignedHalf, rlDest, rlSrc[0], false, false); - break; - - case Instruction::IGET_BOOLEAN: - case Instruction::IGET_BYTE: - genIGet(cUnit, vC, optFlags, kUnsignedByte, rlDest, rlSrc[0], false, false); - break; - - case Instruction::IPUT_WIDE: - //case Instruction::IPUT_WIDE_VOLATILE: - genIPut(cUnit, vC, optFlags, kLong, rlSrc[0], rlSrc[1], true, false); - break; - - case Instruction::IPUT_OBJECT: - //case Instruction::IPUT_OBJECT_VOLATILE: - genIPut(cUnit, vC, optFlags, kWord, rlSrc[0], rlSrc[1], false, true); - break; - - case Instruction::IPUT: - //case Instruction::IPUT_VOLATILE: - genIPut(cUnit, vC, optFlags, kWord, rlSrc[0], rlSrc[1], false, false); - break; - - case Instruction::IPUT_BOOLEAN: - case Instruction::IPUT_BYTE: - genIPut(cUnit, vC, optFlags, kUnsignedByte, rlSrc[0], rlSrc[1], false, false); - break; - - case Instruction::IPUT_CHAR: - genIPut(cUnit, vC, optFlags, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false); - break; - - case Instruction::IPUT_SHORT: - genIPut(cUnit, vC, optFlags, kSignedHalf, rlSrc[0], rlSrc[1], false, false); - break; - - case Instruction::SGET_OBJECT: - genSget(cUnit, vB, rlDest, false, true); - break; - case Instruction::SGET: - case Instruction::SGET_BOOLEAN: - case Instruction::SGET_BYTE: - case Instruction::SGET_CHAR: - case Instruction::SGET_SHORT: - genSget(cUnit, vB, rlDest, false, false); - break; - - case Instruction::SGET_WIDE: - genSget(cUnit, vB, rlDest, true, false); - break; - - case Instruction::SPUT_OBJECT: - genSput(cUnit, vB, rlSrc[0], false, true); - break; - - case Instruction::SPUT: - case Instruction::SPUT_BOOLEAN: - case Instruction::SPUT_BYTE: - case Instruction::SPUT_CHAR: - case Instruction::SPUT_SHORT: - genSput(cUnit, vB, rlSrc[0], false, false); - break; - - case Instruction::SPUT_WIDE: - genSput(cUnit, vB, rlSrc[0], true, false); - break; - - case Instruction::INVOKE_STATIC_RANGE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kStatic, true)); - break; - case Instruction::INVOKE_STATIC: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kStatic, false)); - break; - - case Instruction::INVOKE_DIRECT: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kDirect, false)); - break; - case Instruction::INVOKE_DIRECT_RANGE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kDirect, true)); - break; - - case Instruction::INVOKE_VIRTUAL: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kVirtual, false)); - break; - case Instruction::INVOKE_VIRTUAL_RANGE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kVirtual, true)); - break; - - case Instruction::INVOKE_SUPER: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kSuper, false)); - break; - case Instruction::INVOKE_SUPER_RANGE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kSuper, true)); - break; - - case Instruction::INVOKE_INTERFACE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kInterface, false)); - break; - case Instruction::INVOKE_INTERFACE_RANGE: - genInvoke(cUnit, oatNewCallInfo(cUnit, bb, mir, kInterface, true)); - break; - - case Instruction::NEG_INT: - case Instruction::NOT_INT: - res = genArithOpInt(cUnit, opcode, rlDest, rlSrc[0], rlSrc[0]); - break; - - case Instruction::NEG_LONG: - case Instruction::NOT_LONG: - res = genArithOpLong(cUnit, opcode, rlDest, rlSrc[0], rlSrc[0]); - break; - - case Instruction::NEG_FLOAT: - res = genArithOpFloat(cUnit, opcode, rlDest, rlSrc[0], rlSrc[0]); - break; - - case Instruction::NEG_DOUBLE: - res = genArithOpDouble(cUnit, opcode, rlDest, rlSrc[0], rlSrc[0]); - break; - - case Instruction::INT_TO_LONG: - genIntToLong(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::LONG_TO_INT: - rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]); - rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]); - storeValue(cUnit, rlDest, rlSrc[0]); - break; - - case Instruction::INT_TO_BYTE: - case Instruction::INT_TO_SHORT: - case Instruction::INT_TO_CHAR: - genIntNarrowing(cUnit, opcode, rlDest, rlSrc[0]); - break; - - case Instruction::INT_TO_FLOAT: - case Instruction::INT_TO_DOUBLE: - case Instruction::LONG_TO_FLOAT: - case Instruction::LONG_TO_DOUBLE: - case Instruction::FLOAT_TO_INT: - case Instruction::FLOAT_TO_LONG: - case Instruction::FLOAT_TO_DOUBLE: - case Instruction::DOUBLE_TO_INT: - case Instruction::DOUBLE_TO_LONG: - case Instruction::DOUBLE_TO_FLOAT: - genConversion(cUnit, opcode, rlDest, rlSrc[0]); - break; - - case Instruction::ADD_INT: - case Instruction::SUB_INT: - case Instruction::MUL_INT: - case Instruction::DIV_INT: - case Instruction::REM_INT: - case Instruction::AND_INT: - case Instruction::OR_INT: - case Instruction::XOR_INT: - case Instruction::SHL_INT: - case Instruction::SHR_INT: - case Instruction::USHR_INT: - case Instruction::ADD_INT_2ADDR: - case Instruction::SUB_INT_2ADDR: - case Instruction::MUL_INT_2ADDR: - case Instruction::DIV_INT_2ADDR: - case Instruction::REM_INT_2ADDR: - case Instruction::AND_INT_2ADDR: - case Instruction::OR_INT_2ADDR: - case Instruction::XOR_INT_2ADDR: - case Instruction::SHL_INT_2ADDR: - case Instruction::SHR_INT_2ADDR: - case Instruction::USHR_INT_2ADDR: - genArithOpInt(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::ADD_LONG: - case Instruction::SUB_LONG: - case Instruction::MUL_LONG: - case Instruction::DIV_LONG: - case Instruction::REM_LONG: - case Instruction::AND_LONG: - case Instruction::OR_LONG: - case Instruction::XOR_LONG: - case Instruction::ADD_LONG_2ADDR: - case Instruction::SUB_LONG_2ADDR: - case Instruction::MUL_LONG_2ADDR: - case Instruction::DIV_LONG_2ADDR: - case Instruction::REM_LONG_2ADDR: - case Instruction::AND_LONG_2ADDR: - case Instruction::OR_LONG_2ADDR: - case Instruction::XOR_LONG_2ADDR: - genArithOpLong(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::SHL_LONG: - case Instruction::SHR_LONG: - case Instruction::USHR_LONG: - case Instruction::SHL_LONG_2ADDR: - case Instruction::SHR_LONG_2ADDR: - case Instruction::USHR_LONG_2ADDR: - genShiftOpLong(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::ADD_FLOAT: - case Instruction::SUB_FLOAT: - case Instruction::MUL_FLOAT: - case Instruction::DIV_FLOAT: - case Instruction::REM_FLOAT: - case Instruction::ADD_FLOAT_2ADDR: - case Instruction::SUB_FLOAT_2ADDR: - case Instruction::MUL_FLOAT_2ADDR: - case Instruction::DIV_FLOAT_2ADDR: - case Instruction::REM_FLOAT_2ADDR: - genArithOpFloat(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::ADD_DOUBLE: - case Instruction::SUB_DOUBLE: - case Instruction::MUL_DOUBLE: - case Instruction::DIV_DOUBLE: - case Instruction::REM_DOUBLE: - case Instruction::ADD_DOUBLE_2ADDR: - case Instruction::SUB_DOUBLE_2ADDR: - case Instruction::MUL_DOUBLE_2ADDR: - case Instruction::DIV_DOUBLE_2ADDR: - case Instruction::REM_DOUBLE_2ADDR: - genArithOpDouble(cUnit, opcode, rlDest, rlSrc[0], rlSrc[1]); - break; - - case Instruction::RSUB_INT: - case Instruction::ADD_INT_LIT16: - case Instruction::MUL_INT_LIT16: - case Instruction::DIV_INT_LIT16: - case Instruction::REM_INT_LIT16: - case Instruction::AND_INT_LIT16: - case Instruction::OR_INT_LIT16: - case Instruction::XOR_INT_LIT16: - case Instruction::ADD_INT_LIT8: - case Instruction::RSUB_INT_LIT8: - case Instruction::MUL_INT_LIT8: - case Instruction::DIV_INT_LIT8: - case Instruction::REM_INT_LIT8: - case Instruction::AND_INT_LIT8: - case Instruction::OR_INT_LIT8: - case Instruction::XOR_INT_LIT8: - case Instruction::SHL_INT_LIT8: - case Instruction::SHR_INT_LIT8: - case Instruction::USHR_INT_LIT8: - genArithOpIntLit(cUnit, opcode, rlDest, rlSrc[0], vC); - break; - - default: - res = true; - } - return res; -} - -const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = { - "kMirOpPhi", - "kMirOpCopy", - "kMirFusedCmplFloat", - "kMirFusedCmpgFloat", - "kMirFusedCmplDouble", - "kMirFusedCmpgDouble", - "kMirFusedCmpLong", - "kMirNop", - "kMirOpNullCheck", - "kMirOpRangeCheck", - "kMirOpDivZeroCheck", - "kMirOpCheck", -}; - -/* Extended MIR instructions like PHI */ -void handleExtendedMethodMIR(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) -{ - int opOffset = mir->dalvikInsn.opcode - kMirOpFirst; - char* msg = NULL; - if (cUnit->printMe) { - msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1, - false, kAllocDebugInfo); - strcpy(msg, extendedMIROpNames[opOffset]); - } - LIR* op = newLIR1(cUnit, kPseudoExtended, (int) msg); - - switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) { - case kMirOpPhi: { - char* ssaString = NULL; - if (cUnit->printMe) { - ssaString = oatGetSSAString(cUnit, mir->ssaRep); - } - op->flags.isNop = true; - newLIR1(cUnit, kPseudoSSARep, (int) ssaString); - break; - } - case kMirOpCopy: { - RegLocation rlSrc = oatGetSrc(cUnit, mir, 0); - RegLocation rlDest = oatGetDest(cUnit, mir); - storeValue(cUnit, rlDest, rlSrc); - break; - } - case kMirOpFusedCmplFloat: - genFusedFPCmpBranch(cUnit, bb, mir, false /*gt bias*/, false /*double*/); - break; - case kMirOpFusedCmpgFloat: - genFusedFPCmpBranch(cUnit, bb, mir, true /*gt bias*/, false /*double*/); - break; - case kMirOpFusedCmplDouble: - genFusedFPCmpBranch(cUnit, bb, mir, false /*gt bias*/, true /*double*/); - break; - case kMirOpFusedCmpgDouble: - genFusedFPCmpBranch(cUnit, bb, mir, true /*gt bias*/, true /*double*/); - break; - case kMirOpFusedCmpLong: - genFusedLongCmpBranch(cUnit, bb, mir); - break; - default: - break; - } -} - -/* Handle the content in each basic block */ -bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb) -{ - if (bb->blockType == kDead) return false; - cUnit->currentDalvikOffset = bb->startOffset; - MIR* mir; - LIR* labelList = cUnit->blockLabelList; - int blockId = bb->id; - - cUnit->curBlock = bb; - labelList[blockId].operands[0] = bb->startOffset; - - /* Insert the block label */ - labelList[blockId].opcode = kPseudoNormalBlockLabel; - oatAppendLIR(cUnit, (LIR*) &labelList[blockId]); - - LIR* headLIR = NULL; - - /* If this is a catch block, export the start address */ - if (bb->catchEntry) { - headLIR = newLIR0(cUnit, kPseudoExportedPC); - } - - /* Free temp registers and reset redundant store tracking */ - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - - oatClobberAllRegs(cUnit); - - - if (bb->blockType == kEntryBlock) { - int startVReg = cUnit->numDalvikRegisters - cUnit->numIns; - genEntrySequence(cUnit, &cUnit->regLocation[startVReg], - cUnit->regLocation[cUnit->methodSReg]); - } else if (bb->blockType == kExitBlock) { - genExitSequence(cUnit); - } - - for (mir = bb->firstMIRInsn; mir; mir = mir->next) { - oatResetRegPool(cUnit); - if (cUnit->disableOpt & (1 << kTrackLiveTemps)) { - oatClobberAllRegs(cUnit); - } - - if (cUnit->disableOpt & (1 << kSuppressLoads)) { - oatResetDefTracking(cUnit); - } - -#ifndef NDEBUG - /* Reset temp tracking sanity check */ - cUnit->liveSReg = INVALID_SREG; -#endif - - cUnit->currentDalvikOffset = mir->offset; - int opcode = mir->dalvikInsn.opcode; - LIR* boundaryLIR; - - /* Mark the beginning of a Dalvik instruction for line tracking */ - char* instStr = cUnit->printMe ? - oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL; - boundaryLIR = markBoundary(cUnit, mir->offset, instStr); - /* Remember the first LIR for this block */ - if (headLIR == NULL) { - headLIR = boundaryLIR; - /* Set the first boundaryLIR as a scheduling barrier */ - headLIR->defMask = ENCODE_ALL; - } - - /* Don't generate the SSA annotation unless verbose mode is on */ - if (cUnit->printMe && mir->ssaRep) { - char* ssaString = oatGetSSAString(cUnit, mir->ssaRep); - newLIR1(cUnit, kPseudoSSARep, (int) ssaString); - } - - if (opcode == kMirOpCheck) { - // Combine check and work halves of throwing instruction. - MIR* workHalf = mir->meta.throwInsn; - mir->dalvikInsn.opcode = workHalf->dalvikInsn.opcode; - opcode = workHalf->dalvikInsn.opcode; - SSARepresentation* ssaRep = workHalf->ssaRep; - workHalf->ssaRep = mir->ssaRep; - mir->ssaRep = ssaRep; - workHalf->dalvikInsn.opcode = static_cast(kMirOpNop); - } - - if (opcode >= kMirOpFirst) { - handleExtendedMethodMIR(cUnit, bb, mir); - continue; - } - - bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList); - if (notHandled) { - LOG(FATAL) << StringPrintf("%#06x: Opcode %#x (%s)", - mir->offset, opcode, - Instruction::Name(mir->dalvikInsn.opcode)); - } - } - - if (headLIR) { - /* - * Eliminate redundant loads/stores and delay stores into later - * slots - */ - oatApplyLocalOptimizations(cUnit, (LIR*) headLIR, cUnit->lastLIRInsn); - - /* - * Generate an unconditional branch to the fallthrough block. - */ - if (bb->fallThrough) { - opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); - } - } - return false; -} - -/* Set basic block labels */ -bool labelBlocks(CompilationUnit* cUnit, BasicBlock* bb) -{ - LIR* labelList = cUnit->blockLabelList; - int blockId = bb->id; - - cUnit->curBlock = bb; - labelList[blockId].operands[0] = bb->startOffset; - - /* Insert the block label */ - labelList[blockId].opcode = kPseudoNormalBlockLabel; - return false; -} - -void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase) -{ - /* Find the first DalvikByteCode block */ - int numReachableBlocks = cUnit->numReachableBlocks; - const GrowableList *blockList = &cUnit->blockList; - BasicBlock*bb = NULL; - for (int idx = 0; idx < numReachableBlocks; idx++) { - int dfsIndex = cUnit->dfsOrder.elemList[idx]; - bb = (BasicBlock*)oatGrowableListGetElement(blockList, dfsIndex); - if (bb->blockType == kDalvikByteCode) { - break; - } - } - if (bb == NULL) { - return; - } - DCHECK_EQ(bb->startOffset, 0); - DCHECK(bb->firstMIRInsn != NULL); - - /* Get the first instruction */ - MIR* mir = bb->firstMIRInsn; - - /* Free temp registers and reset redundant store tracking */ - oatResetRegPool(cUnit); - oatResetDefTracking(cUnit); - oatClobberAllRegs(cUnit); - - genSpecialCase(cUnit, bb, mir, specialCase); -} - -void oatMethodMIR2LIR(CompilationUnit* cUnit) -{ - /* Used to hold the labels of each block */ - cUnit->blockLabelList = - (LIR*) oatNew(cUnit, sizeof(LIR) * cUnit->numBlocks, true, kAllocLIR); - - oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen, - kPreOrderDFSTraversal, false /* Iterative */); - - handleSuspendLaunchpads(cUnit); - - handleThrowLaunchpads(cUnit); - - handleIntrinsicLaunchpads(cUnit); - - if (!(cUnit->disableOpt & (1 << kSafeOptimizations))) { - removeRedundantBranches(cUnit); - } -} - -/* Needed by the ld/st optmizatons */ -LIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc) -{ - return opRegCopyNoInsert(cUnit, rDest, rSrc); -} - -/* Needed by the register allocator */ -void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc) -{ - opRegCopy(cUnit, rDest, rSrc); -} - -/* Needed by the register allocator */ -void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi, - int srcLo, int srcHi) -{ - opRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi); -} - -void oatFlushRegImpl(CompilationUnit* cUnit, int rBase, - int displacement, int rSrc, OpSize size) -{ - storeBaseDisp(cUnit, rBase, displacement, rSrc, size); -} - -void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase, - int displacement, int rSrcLo, int rSrcHi) -{ - storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi); -} - -} // namespace art diff --git a/src/compiler/codegen/Optimizer.h b/src/compiler/codegen/Optimizer.h deleted file mode 100644 index 94b1907ef1..0000000000 --- a/src/compiler/codegen/Optimizer.h +++ /dev/null @@ -1,32 +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. - */ - -#ifndef ART_SRC_COMPILER_COMPILER_OPTIMIZATION_H_ -#define ART_SRC_COMPILER_COMPILER_OPTIMIZATION_H_ - -#include "../Dalvik.h" - -namespace art { - -/* Forward declarations */ -struct CompilationUnit; -struct LIR; - -void oatApplyLocalOptimizations(CompilationUnit* cUnit, LIR* head, LIR* tail); - -} // namespace art - -#endif // ART_SRC_COMPILER_COMPILER_OPTIMIZATION_H_ diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h deleted file mode 100644 index 55e62b1a73..0000000000 --- a/src/compiler/codegen/Ralloc.h +++ /dev/null @@ -1,234 +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. - */ - -#ifndef ART_SRC_COMPILER_RALLOC_H_ -#define ART_SRC_COMPILER_RALLOC_H_ - -/* - * This file contains target independent register alloction support. - */ - -#include "../CompilerUtility.h" -#include "../CompilerIR.h" -#include "../Dataflow.h" - -namespace art { - -/* Static register use counts */ -struct RefCounts { - int count; - int sReg; - bool doubleStart; // Starting vReg for a double -}; - - -/* - * Get the "real" sreg number associated with an sReg slot. In general, - * sReg values passed through codegen are the SSA names created by - * dataflow analysis and refer to slot numbers in the cUnit->regLocation - * array. However, renaming is accomplished by simply replacing RegLocation - * entries in the cUnit->reglocation[] array. Therefore, when location - * records for operands are first created, we need to ask the locRecord - * identified by the dataflow pass what it's new name is. - */ - -inline int oatSRegHi(int lowSreg) { - return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1; -} - - -inline bool oatLiveOut(CompilationUnit* cUnit, int sReg) { - //For now. - return true; -} - -inline int oatSSASrc(MIR* mir, int num) { - DCHECK_GT(mir->ssaRep->numUses, num); - return mir->ssaRep->uses[num]; -} - -extern RegLocation oatEvalLoc(CompilationUnit* cUnit, RegLocation loc, - int regClass, bool update); -/* Mark a temp register as dead. Does not affect allocation state. */ -extern void oatClobber(CompilationUnit* cUnit, int reg); -extern RegLocation oatUpdateLoc(CompilationUnit* cUnit, RegLocation loc); - -/* see comments for updateLoc */ -extern RegLocation oatUpdateLocWide(CompilationUnit* cUnit, RegLocation loc); - -extern RegLocation oatUpdateRawLoc(CompilationUnit* cUnit, RegLocation loc); - -extern void oatMarkLive(CompilationUnit* cUnit, int reg, int sReg); - -extern void oatMarkTemp(CompilationUnit* cUnit, int reg); - -extern void oatUnmarkTemp(CompilationUnit* cUnit, int reg); - -extern void oatMarkDirty(CompilationUnit* cUnit, RegLocation loc); - -extern void oatMarkPair(CompilationUnit* cUnit, int lowReg, int highReg); - -extern void oatMarkClean(CompilationUnit* cUnit, RegLocation loc); - -extern void oatResetDef(CompilationUnit* cUnit, int reg); - -extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl); - -/* Set up temp & preserved register pools specialized by target */ -extern void oatInitPool(RegisterInfo* regs, int* regNums, int num); - -/* - * Mark the beginning and end LIR of a def sequence. Note that - * on entry start points to the LIR prior to the beginning of the - * sequence. - */ -extern void oatMarkDef(CompilationUnit* cUnit, RegLocation rl, LIR* start, - LIR* finish); -/* - * Mark the beginning and end LIR of a def sequence. Note that - * on entry start points to the LIR prior to the beginning of the - * sequence. - */ -extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl, - LIR* start, LIR* finish); - - -// Get the LocRecord associated with an SSA name use. -extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num); -extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir, int low); -// Non-width checking version -extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num); - -// Get the LocRecord associated with an SSA name def. -extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir); -extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir); -// Non-width checking version -extern RegLocation oatGetRawDest(CompilationUnit* cUnit, MIR* mir); - -extern RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble); - -/* Clobber all regs that might be used by an external C call */ -extern void oatClobberCalleeSave(CompilationUnit* cUnit); - -extern RegisterInfo *oatIsTemp(CompilationUnit* cUnit, int reg); - -extern RegisterInfo *oatIsPromoted(CompilationUnit* cUnit, int reg); - -extern bool oatIsDirty(CompilationUnit* cUnit, int reg); - -extern void oatMarkInUse(CompilationUnit* cUnit, int reg); - -extern int oatAllocTemp(CompilationUnit* cUnit); - -extern int oatAllocTempFloat(CompilationUnit* cUnit); - -//REDO: too many assumptions. -extern int oatAllocTempDouble(CompilationUnit* cUnit); - -extern void oatFreeTemp(CompilationUnit* cUnit, int reg); - -extern void oatResetDefLocWide(CompilationUnit* cUnit, RegLocation rl); - -extern void oatResetDefTracking(CompilationUnit* cUnit); - -extern RegisterInfo *oatIsLive(CompilationUnit* cUnit, int reg); - -/* To be used when explicitly managing register use */ -extern void oatLockCallTemps(CompilationUnit* cUnit); - -extern void oatFreeCallTemps(CompilationUnit* cUnit); - -extern void oatFlushAllRegs(CompilationUnit* cUnit); - -extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit); - -extern RegLocation oatGetReturn(CompilationUnit* cUnit, bool isFloat); - -extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit); - -/* Clobber any temp associated with an sReg. Could be in either class */ -extern void oatClobberSReg(CompilationUnit* cUnit, int sReg); - -/* Return a temp if one is available, -1 otherwise */ -extern int oatAllocFreeTemp(CompilationUnit* cUnit); - -/* Attempt to allocate a callee-save register */ -extern int oatAllocPreservedCoreReg(CompilationUnit* cUnit, int sreg); -extern int oatAllocPreservedFPReg(CompilationUnit* cUnit, int sReg, - bool doubleStart); - -/* - * Similar to oatAllocTemp(), but forces the allocation of a specific - * register. No check is made to see if the register was previously - * allocated. Use with caution. - */ -extern void oatLockTemp(CompilationUnit* cUnit, int reg); - -extern RegLocation oatWideToNarrow(CompilationUnit* cUnit, RegLocation rl); - -/* - * Free all allocated temps in the temp pools. Note that this does - * not affect the "liveness" of a temp register, which will stay - * live until it is either explicitly killed or reallocated. - */ -extern void oatResetRegPool(CompilationUnit* cUnit); - -extern void oatClobberAllRegs(CompilationUnit* cUnit); - -extern void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2); - -extern void oatFlushReg(CompilationUnit* cUnit, int reg); - -extern void oatDoPromotion(CompilationUnit* cUnit); -extern int oatVRegOffset(CompilationUnit* cUnit, int reg); -extern int oatSRegOffset(CompilationUnit* cUnit, int reg); -extern void oatCountRefs(CompilationUnit*, BasicBlock*, RefCounts*, RefCounts*); -extern int oatSortCounts(const void *val1, const void *val2); -extern void oatDumpCounts(const RefCounts* arr, int size, const char* msg); -extern void oatRecordCorePromotion(CompilationUnit* cUnit, int reg, int sReg); -extern void oatRecordFpPromotion(CompilationUnit* cUnit, int reg, int sReg); - - -/* Architecture-dependent register allocation routines. */ -extern int oatAllocTypedTempPair(CompilationUnit* cUnit, - bool fpHint, int regClass); - -extern int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint, int regClass); - -extern void oatRegCopyWide(CompilationUnit* cUnit, int destLo, - int destHi, int srcLo, int srcHi); - -extern void oatFlushRegImpl(CompilationUnit* cUnit, int rBase, - int displacement, int rSrc, OpSize size); - -extern void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase, - int displacement, int rSrcLo, int rSrcHi); - -extern void oatDumpCoreRegPool(CompilationUnit* cUint); -extern void oatDumpFPRegPool(CompilationUnit* cUint); -extern bool oatCheckCorePoolSanity(CompilationUnit* cUnit); -extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg); -extern void oatNopLIR(LIR* lir); -extern bool oatIsFPReg(int reg); -extern uint32_t oatFPRegMask(void); -extern void oatAdjustSpillMask(CompilationUnit* cUnit); -void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg); -void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc); -int oatComputeFrameSize(CompilationUnit* cUnit); - -} // namespace art - -#endif // ART_SRC_COMPILER_RALLOC_H_ diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc deleted file mode 100644 index 4848a59fc6..0000000000 --- a/src/compiler/codegen/RallocUtil.cc +++ /dev/null @@ -1,1264 +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 register alloction support. */ - -#include "../CompilerUtility.h" -#include "../CompilerIR.h" -#include "../Dataflow.h" -#include "Ralloc.h" - -namespace art { - -/* - * Free all allocated temps in the temp pools. Note that this does - * not affect the "liveness" of a temp register, which will stay - * live until it is either explicitly killed or reallocated. - */ -extern void oatResetRegPool(CompilationUnit* cUnit) -{ - int i; - for (i=0; i < cUnit->regPool->numCoreRegs; i++) { - if (cUnit->regPool->coreRegs[i].isTemp) - cUnit->regPool->coreRegs[i].inUse = false; - } - for (i=0; i < cUnit->regPool->numFPRegs; i++) { - if (cUnit->regPool->FPRegs[i].isTemp) - cUnit->regPool->FPRegs[i].inUse = false; - } -} - - /* - * Set up temp & preserved register pools specialized by target. - * Note: numRegs may be zero. - */ -extern void oatInitPool(RegisterInfo* regs, int* regNums, int num) -{ - int i; - for (i=0; i < num; i++) { - regs[i].reg = regNums[i]; - regs[i].inUse = false; - regs[i].isTemp = false; - regs[i].pair = false; - regs[i].live = false; - regs[i].dirty = false; - regs[i].sReg = INVALID_SREG; - } -} - -void dumpRegPool(RegisterInfo* p, int numRegs) -{ - LOG(INFO) << "================================================"; - for (int i = 0; i < numRegs; i++) { - LOG(INFO) << StringPrintf( - "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x", - p[i].reg, p[i].isTemp, p[i].inUse, p[i].pair, p[i].partner, - p[i].live, p[i].dirty, p[i].sReg,(int)p[i].defStart, - (int)p[i].defEnd); - } - LOG(INFO) << "================================================"; -} - -void oatDumpCoreRegPool(CompilationUnit* cUnit) -{ - dumpRegPool(cUnit->regPool->coreRegs, cUnit->regPool->numCoreRegs); -} - -void oatDumpFpRegPool(CompilationUnit* cUnit) -{ - dumpRegPool(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs); -} - -/* Mark a temp register as dead. Does not affect allocation state. */ -static inline void clobberBody(CompilationUnit *cUnit, RegisterInfo* p) -{ - if (p->isTemp) { - DCHECK(!(p->live && p->dirty)) << "Live & dirty temp in clobber"; - p->live = false; - p->sReg = INVALID_SREG; - p->defStart = NULL; - p->defEnd = NULL; - if (p->pair) { - p->pair = false; - oatClobber(cUnit, p->partner); - } - } -} - -/* Mark a temp register as dead. Does not affect allocation state. */ -void oatClobber(CompilationUnit* cUnit, int reg) -{ - clobberBody(cUnit, oatGetRegInfo(cUnit, reg)); -} - -void clobberSRegBody(RegisterInfo* p, int numRegs, int sReg) -{ - int i; - for (i=0; i< numRegs; i++) { - if (p[i].sReg == sReg) { - if (p[i].isTemp) { - p[i].live = false; - } - p[i].defStart = NULL; - p[i].defEnd = NULL; - } - } -} - -/* Clobber any temp associated with an sReg. Could be in either class */ -extern void oatClobberSReg(CompilationUnit* cUnit, int sReg) -{ -#ifndef NDEBUG - /* Reset live temp tracking sanity checker */ - if (sReg == cUnit->liveSReg) { - cUnit->liveSReg = INVALID_SREG; - } -#endif - clobberSRegBody(cUnit->regPool->coreRegs, cUnit->regPool->numCoreRegs, sReg); - clobberSRegBody(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs, sReg); -} - -/* - * SSA names associated with the initial definitions of Dalvik - * registers are the same as the Dalvik register number (and - * thus take the same position in the promotionMap. However, - * the special Method* and compiler temp resisters use negative - * vReg numbers to distinguish them and can have an arbitrary - * ssa name (above the last original Dalvik register). This function - * maps SSA names to positions in the promotionMap array. - */ -int SRegToPMap(CompilationUnit* cUnit, int sReg) -{ - DCHECK_LT(sReg, cUnit->numSSARegs); - DCHECK_GE(sReg, 0); - int vReg = SRegToVReg(cUnit, sReg); - if (vReg >= 0) { - DCHECK_LT(vReg, cUnit->numDalvikRegisters); - return vReg; - } else { - int pos = std::abs(vReg) - std::abs(SSA_METHOD_BASEREG); - DCHECK_LE(pos, cUnit->numCompilerTemps); - return cUnit->numDalvikRegisters + pos; - } -} - -void oatRecordCorePromotion(CompilationUnit* cUnit, int reg, int sReg) -{ - int pMapIdx = SRegToPMap(cUnit, sReg); - int vReg = SRegToVReg(cUnit, sReg); - oatGetRegInfo(cUnit, reg)->inUse = true; - cUnit->coreSpillMask |= (1 << reg); - // Include reg for later sort - cUnit->coreVmapTable.push_back(reg << VREG_NUM_WIDTH | - (vReg & ((1 << VREG_NUM_WIDTH) - 1))); - cUnit->numCoreSpills++; - cUnit->promotionMap[pMapIdx].coreLocation = kLocPhysReg; - cUnit->promotionMap[pMapIdx].coreReg = reg; -} - -/* Reserve a callee-save register. Return -1 if none available */ -extern int oatAllocPreservedCoreReg(CompilationUnit* cUnit, int sReg) -{ - int res = -1; - RegisterInfo* coreRegs = cUnit->regPool->coreRegs; - for (int i = 0; i < cUnit->regPool->numCoreRegs; i++) { - if (!coreRegs[i].isTemp && !coreRegs[i].inUse) { - res = coreRegs[i].reg; - oatRecordCorePromotion(cUnit, res, sReg); - break; - } - } - return res; -} - -void oatRecordFpPromotion(CompilationUnit* cUnit, int reg, int sReg) -{ - int pMapIdx = SRegToPMap(cUnit, sReg); - int vReg = SRegToVReg(cUnit, sReg); - oatGetRegInfo(cUnit, reg)->inUse = true; - oatMarkPreservedSingle(cUnit, vReg, reg); - cUnit->promotionMap[pMapIdx].fpLocation = kLocPhysReg; - cUnit->promotionMap[pMapIdx].fpReg = reg; -} - -/* - * Reserve a callee-save fp single register. Try to fullfill request for - * even/odd allocation, but go ahead and allocate anything if not - * available. If nothing's available, return -1. - */ -int allocPreservedSingle(CompilationUnit* cUnit, int sReg, bool even) -{ - int res = -1; - RegisterInfo* FPRegs = cUnit->regPool->FPRegs; - for (int i = 0; i < cUnit->regPool->numFPRegs; i++) { - if (!FPRegs[i].isTemp && !FPRegs[i].inUse && - ((FPRegs[i].reg & 0x1) == 0) == even) { - res = FPRegs[i].reg; - oatRecordFpPromotion(cUnit, res, sReg); - break; - } - } - return res; -} - -/* - * Somewhat messy code here. We want to allocate a pair of contiguous - * physical single-precision floating point registers starting with - * an even numbered reg. It is possible that the paired sReg (sReg+1) - * has already been allocated - try to fit if possible. Fail to - * allocate if we can't meet the requirements for the pair of - * sReg<=sX[even] & (sReg+1)<= sX+1. - */ -int allocPreservedDouble(CompilationUnit* cUnit, int sReg) -{ - int res = -1; // Assume failure - int vReg = SRegToVReg(cUnit, sReg); - int pMapIdx = SRegToPMap(cUnit, sReg); - if (cUnit->promotionMap[pMapIdx+1].fpLocation == kLocPhysReg) { - // Upper reg is already allocated. Can we fit? - int highReg = cUnit->promotionMap[pMapIdx+1].fpReg; - if ((highReg & 1) == 0) { - // High reg is even - fail. - return res; - } - // Is the low reg of the pair free? - RegisterInfo* p = oatGetRegInfo(cUnit, highReg-1); - if (p->inUse || p->isTemp) { - // Already allocated or not preserved - fail. - return res; - } - // OK - good to go. - res = p->reg; - p->inUse = true; - DCHECK_EQ((res & 1), 0); - oatMarkPreservedSingle(cUnit, vReg, res); - } else { - RegisterInfo* FPRegs = cUnit->regPool->FPRegs; - for (int i = 0; i < cUnit->regPool->numFPRegs; i++) { - if (!FPRegs[i].isTemp && !FPRegs[i].inUse && - ((FPRegs[i].reg & 0x1) == 0x0) && - !FPRegs[i+1].isTemp && !FPRegs[i+1].inUse && - ((FPRegs[i+1].reg & 0x1) == 0x1) && - (FPRegs[i].reg + 1) == FPRegs[i+1].reg) { - res = FPRegs[i].reg; - FPRegs[i].inUse = true; - oatMarkPreservedSingle(cUnit, vReg, res); - FPRegs[i+1].inUse = true; - DCHECK_EQ(res + 1, FPRegs[i+1].reg); - oatMarkPreservedSingle(cUnit, vReg+1, res+1); - break; - } - } - } - if (res != -1) { - cUnit->promotionMap[pMapIdx].fpLocation = kLocPhysReg; - cUnit->promotionMap[pMapIdx].fpReg = res; - cUnit->promotionMap[pMapIdx+1].fpLocation = kLocPhysReg; - cUnit->promotionMap[pMapIdx+1].fpReg = res + 1; - } - return res; -} - - -/* - * Reserve a callee-save fp register. If this register can be used - * as the first of a double, attempt to allocate an even pair of fp - * single regs (but if can't still attempt to allocate a single, preferring - * first to allocate an odd register. - */ -extern int oatAllocPreservedFPReg(CompilationUnit* cUnit, int sReg, - bool doubleStart) -{ - int res = -1; - if (doubleStart) { - res = allocPreservedDouble(cUnit, sReg); - } - if (res == -1) { - res = allocPreservedSingle(cUnit, sReg, false /* try odd # */); - } - if (res == -1) - res = allocPreservedSingle(cUnit, sReg, true /* try even # */); - return res; -} - -int allocTempBody(CompilationUnit* cUnit, RegisterInfo* p, int numRegs, - int* nextTemp, bool required) -{ - int i; - int next = *nextTemp; - for (i=0; i< numRegs; i++) { - if (next >= numRegs) - next = 0; - if (p[next].isTemp && !p[next].inUse && !p[next].live) { - oatClobber(cUnit, p[next].reg); - p[next].inUse = true; - p[next].pair = false; - *nextTemp = next + 1; - return p[next].reg; - } - next++; - } - next = *nextTemp; - for (i=0; i< numRegs; i++) { - if (next >= numRegs) - next = 0; - if (p[next].isTemp && !p[next].inUse) { - oatClobber(cUnit, p[next].reg); - p[next].inUse = true; - p[next].pair = false; - *nextTemp = next + 1; - return p[next].reg; - } - next++; - } - if (required) { - oatCodegenDump(cUnit); - dumpRegPool(cUnit->regPool->coreRegs, - cUnit->regPool->numCoreRegs); - LOG(FATAL) << "No free temp registers"; - } - return -1; // No register available -} - -//REDO: too many assumptions. -extern int oatAllocTempDouble(CompilationUnit* cUnit) -{ - RegisterInfo* p = cUnit->regPool->FPRegs; - int numRegs = cUnit->regPool->numFPRegs; - /* Start looking at an even reg */ - int next = cUnit->regPool->nextFPReg & ~0x1; - - // First try to avoid allocating live registers - for (int i=0; i < numRegs; i+=2) { - if (next >= numRegs) - next = 0; - if ((p[next].isTemp && !p[next].inUse && !p[next].live) && - (p[next+1].isTemp && !p[next+1].inUse && !p[next+1].live)) { - oatClobber(cUnit, p[next].reg); - oatClobber(cUnit, p[next+1].reg); - p[next].inUse = true; - p[next+1].inUse = true; - DCHECK_EQ((p[next].reg+1), p[next+1].reg); - DCHECK_EQ((p[next].reg & 0x1), 0); - cUnit->regPool->nextFPReg = next + 2; - if (cUnit->regPool->nextFPReg >= numRegs) { - cUnit->regPool->nextFPReg = 0; - } - return p[next].reg; - } - next += 2; - } - next = cUnit->regPool->nextFPReg & ~0x1; - - // No choice - find a pair and kill it. - for (int i=0; i < numRegs; i+=2) { - if (next >= numRegs) - next = 0; - if (p[next].isTemp && !p[next].inUse && p[next+1].isTemp && - !p[next+1].inUse) { - oatClobber(cUnit, p[next].reg); - oatClobber(cUnit, p[next+1].reg); - p[next].inUse = true; - p[next+1].inUse = true; - DCHECK_EQ((p[next].reg+1), p[next+1].reg); - DCHECK_EQ((p[next].reg & 0x1), 0); - cUnit->regPool->nextFPReg = next + 2; - if (cUnit->regPool->nextFPReg >= numRegs) { - cUnit->regPool->nextFPReg = 0; - } - return p[next].reg; - } - next += 2; - } - LOG(FATAL) << "No free temp registers (pair)"; - return -1; -} - -/* Return a temp if one is available, -1 otherwise */ -extern int oatAllocFreeTemp(CompilationUnit* cUnit) -{ - return allocTempBody(cUnit, cUnit->regPool->coreRegs, - cUnit->regPool->numCoreRegs, - &cUnit->regPool->nextCoreReg, true); -} - -extern int oatAllocTemp(CompilationUnit* cUnit) -{ - return allocTempBody(cUnit, cUnit->regPool->coreRegs, - cUnit->regPool->numCoreRegs, - &cUnit->regPool->nextCoreReg, true); -} - -extern int oatAllocTempFloat(CompilationUnit* cUnit) -{ - return allocTempBody(cUnit, cUnit->regPool->FPRegs, - cUnit->regPool->numFPRegs, - &cUnit->regPool->nextFPReg, true); -} - -RegisterInfo* allocLiveBody(RegisterInfo* p, int numRegs, int sReg) -{ - int i; - if (sReg == -1) - return NULL; - for (i=0; i < numRegs; i++) { - if (p[i].live && (p[i].sReg == sReg)) { - if (p[i].isTemp) - p[i].inUse = true; - return &p[i]; - } - } - return NULL; -} - -RegisterInfo* allocLive(CompilationUnit* cUnit, int sReg, int regClass) -{ - RegisterInfo* res = NULL; - switch (regClass) { - case kAnyReg: - res = allocLiveBody(cUnit->regPool->FPRegs, - cUnit->regPool->numFPRegs, sReg); - if (res) - break; - /* Intentional fallthrough */ - case kCoreReg: - res = allocLiveBody(cUnit->regPool->coreRegs, - cUnit->regPool->numCoreRegs, sReg); - break; - case kFPReg: - res = allocLiveBody(cUnit->regPool->FPRegs, - cUnit->regPool->numFPRegs, sReg); - break; - default: - LOG(FATAL) << "Invalid register type"; - } - return res; -} - -extern void oatFreeTemp(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = cUnit->regPool->coreRegs; - int numRegs = cUnit->regPool->numCoreRegs; - int i; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - if (p[i].isTemp) { - p[i].inUse = false; - } - p[i].pair = false; - return; - } - } - p = cUnit->regPool->FPRegs; - numRegs = cUnit->regPool->numFPRegs; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - if (p[i].isTemp) { - p[i].inUse = false; - } - p[i].pair = false; - return; - } - } - LOG(FATAL) << "Tried to free a non-existant temp: r" << reg; -} - -extern RegisterInfo* oatIsLive(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = cUnit->regPool->coreRegs; - int numRegs = cUnit->regPool->numCoreRegs; - int i; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - return p[i].live ? &p[i] : NULL; - } - } - p = cUnit->regPool->FPRegs; - numRegs = cUnit->regPool->numFPRegs; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - return p[i].live ? &p[i] : NULL; - } - } - return NULL; -} - -extern RegisterInfo* oatIsTemp(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = oatGetRegInfo(cUnit, reg); - return (p->isTemp) ? p : NULL; -} - -extern RegisterInfo* oatIsPromoted(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = oatGetRegInfo(cUnit, reg); - return (p->isTemp) ? NULL : p; -} - -extern bool oatIsDirty(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = oatGetRegInfo(cUnit, reg); - return p->dirty; -} - -/* - * Similar to oatAllocTemp(), but forces the allocation of a specific - * register. No check is made to see if the register was previously - * allocated. Use with caution. - */ -extern void oatLockTemp(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* p = cUnit->regPool->coreRegs; - int numRegs = cUnit->regPool->numCoreRegs; - int i; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - DCHECK(p[i].isTemp); - p[i].inUse = true; - p[i].live = false; - return; - } - } - p = cUnit->regPool->FPRegs; - numRegs = cUnit->regPool->numFPRegs; - for (i=0; i< numRegs; i++) { - if (p[i].reg == reg) { - DCHECK(p[i].isTemp); - p[i].inUse = true; - p[i].live = false; - return; - } - } - LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg; -} - -static inline void resetDefBody(RegisterInfo* p) -{ - p->defStart = NULL; - p->defEnd = NULL; -} - -extern void oatResetDef(CompilationUnit* cUnit, int reg) -{ - resetDefBody(oatGetRegInfo(cUnit, reg)); -} - -void nullifyRange(CompilationUnit* cUnit, LIR *start, LIR *finish, - int sReg1, int sReg2) -{ - if (start && finish) { - LIR *p; - DCHECK_EQ(sReg1, sReg2); - for (p = start; ;p = p->next) { - oatNopLIR(p); - if (p == finish) - break; - } - } -} - -/* - * Mark the beginning and end LIR of a def sequence. Note that - * on entry start points to the LIR prior to the beginning of the - * sequence. - */ -extern void oatMarkDef(CompilationUnit* cUnit, RegLocation rl, - LIR *start, LIR *finish) -{ - DCHECK(!rl.wide); - DCHECK(start && start->next); - DCHECK(finish); - RegisterInfo* p = oatGetRegInfo(cUnit, rl.lowReg); - p->defStart = start->next; - p->defEnd = finish; -} - -/* - * Mark the beginning and end LIR of a def sequence. Note that - * on entry start points to the LIR prior to the beginning of the - * sequence. - */ -extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl, - LIR *start, LIR *finish) -{ - DCHECK(rl.wide); - DCHECK(start && start->next); - DCHECK(finish); - RegisterInfo* p = oatGetRegInfo(cUnit, rl.lowReg); - oatResetDef(cUnit, rl.highReg); // Only track low of pair - p->defStart = start->next; - p->defEnd = finish; -} - -extern RegLocation oatWideToNarrow(CompilationUnit* cUnit, RegLocation rl) -{ - DCHECK(rl.wide); - if (rl.location == kLocPhysReg) { - RegisterInfo* infoLo = oatGetRegInfo(cUnit, rl.lowReg); - RegisterInfo* infoHi = oatGetRegInfo(cUnit, rl.highReg); - if (infoLo->isTemp) { - infoLo->pair = false; - infoLo->defStart = NULL; - infoLo->defEnd = NULL; - } - if (infoHi->isTemp) { - infoHi->pair = false; - infoHi->defStart = NULL; - infoHi->defEnd = NULL; - } - } - rl.wide = false; - return rl; -} - -extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl) -{ - DCHECK(!rl.wide); - RegisterInfo* p = oatIsTemp(cUnit, rl.lowReg); - if (p && !(cUnit->disableOpt & (1 << kSuppressLoads))) { - DCHECK(!p->pair); - nullifyRange(cUnit, p->defStart, p->defEnd, p->sReg, rl.sRegLow); - } - oatResetDef(cUnit, rl.lowReg); -} - -extern void oatResetDefLocWide(CompilationUnit* cUnit, RegLocation rl) -{ - DCHECK(rl.wide); - RegisterInfo* pLow = oatIsTemp(cUnit, rl.lowReg); - RegisterInfo* pHigh = oatIsTemp(cUnit, rl.highReg); - if (pLow && !(cUnit->disableOpt & (1 << kSuppressLoads))) { - DCHECK(pLow->pair); - nullifyRange(cUnit, pLow->defStart, pLow->defEnd, pLow->sReg, rl.sRegLow); - } - if (pHigh && !(cUnit->disableOpt & (1 << kSuppressLoads))) { - DCHECK(pHigh->pair); - } - oatResetDef(cUnit, rl.lowReg); - oatResetDef(cUnit, rl.highReg); -} - -extern void oatResetDefTracking(CompilationUnit* cUnit) -{ - int i; - for (i=0; i< cUnit->regPool->numCoreRegs; i++) { - resetDefBody(&cUnit->regPool->coreRegs[i]); - } - for (i=0; i< cUnit->regPool->numFPRegs; i++) { - resetDefBody(&cUnit->regPool->FPRegs[i]); - } -} - -extern void oatClobberAllRegs(CompilationUnit* cUnit) -{ - int i; - for (i=0; i< cUnit->regPool->numCoreRegs; i++) { - clobberBody(cUnit, &cUnit->regPool->coreRegs[i]); - } - for (i=0; i< cUnit->regPool->numFPRegs; i++) { - clobberBody(cUnit, &cUnit->regPool->FPRegs[i]); - } -} - -// Make sure nothing is live and dirty -void flushAllRegsBody(CompilationUnit* cUnit, RegisterInfo* info, - int numRegs) -{ - int i; - for (i=0; i < numRegs; i++) { - if (info[i].live && info[i].dirty) { - if (info[i].pair) { - oatFlushRegWide(cUnit, info[i].reg, info[i].partner); - } else { - oatFlushReg(cUnit, info[i].reg); - } - } - } -} - -extern void oatFlushAllRegs(CompilationUnit* cUnit) -{ - flushAllRegsBody(cUnit, cUnit->regPool->coreRegs, - cUnit->regPool->numCoreRegs); - flushAllRegsBody(cUnit, cUnit->regPool->FPRegs, - cUnit->regPool->numFPRegs); - oatClobberAllRegs(cUnit); -} - - -//TUNING: rewrite all of this reg stuff. Probably use an attribute table -bool regClassMatches(int regClass, int reg) -{ - if (regClass == kAnyReg) { - return true; - } else if (regClass == kCoreReg) { - return !oatIsFpReg(reg); - } else { - return oatIsFpReg(reg); - } -} - -extern void oatMarkLive(CompilationUnit* cUnit, int reg, int sReg) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, reg); - if ((info->reg == reg) && (info->sReg == sReg) && info->live) { - return; /* already live */ - } else if (sReg != INVALID_SREG) { - oatClobberSReg(cUnit, sReg); - if (info->isTemp) { - info->live = true; - } - } else { - /* Can't be live if no associated sReg */ - DCHECK(info->isTemp); - info->live = false; - } - info->sReg = sReg; -} - -extern void oatMarkTemp(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, reg); - info->isTemp = true; -} - -extern void oatUnmarkTemp(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, reg); - info->isTemp = false; -} - -extern void oatMarkPair(CompilationUnit* cUnit, int lowReg, int highReg) -{ - RegisterInfo* infoLo = oatGetRegInfo(cUnit, lowReg); - RegisterInfo* infoHi = oatGetRegInfo(cUnit, highReg); - infoLo->pair = infoHi->pair = true; - infoLo->partner = highReg; - infoHi->partner = lowReg; -} - -extern void oatMarkClean(CompilationUnit* cUnit, RegLocation loc) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, loc.lowReg); - info->dirty = false; - if (loc.wide) { - info = oatGetRegInfo(cUnit, loc.highReg); - info->dirty = false; - } -} - -extern void oatMarkDirty(CompilationUnit* cUnit, RegLocation loc) -{ - if (loc.home) { - // If already home, can't be dirty - return; - } - RegisterInfo* info = oatGetRegInfo(cUnit, loc.lowReg); - info->dirty = true; - if (loc.wide) { - info = oatGetRegInfo(cUnit, loc.highReg); - info->dirty = true; - } -} - -extern void oatMarkInUse(CompilationUnit* cUnit, int reg) -{ - RegisterInfo* info = oatGetRegInfo(cUnit, reg); - info->inUse = true; -} - -void copyRegInfo(CompilationUnit* cUnit, int newReg, int oldReg) -{ - RegisterInfo* newInfo = oatGetRegInfo(cUnit, newReg); - RegisterInfo* oldInfo = oatGetRegInfo(cUnit, oldReg); - // Target temp status must not change - bool isTemp = newInfo->isTemp; - *newInfo = *oldInfo; - // Restore target's temp status - newInfo->isTemp = isTemp; - newInfo->reg = newReg; -} - -/* - * Return an updated location record with current in-register status. - * If the value lives in live temps, reflect that fact. No code - * is generated. If the live value is part of an older pair, - * clobber both low and high. - * TUNING: clobbering both is a bit heavy-handed, but the alternative - * is a bit complex when dealing with FP regs. Examine code to see - * if it's worthwhile trying to be more clever here. - */ - -extern RegLocation oatUpdateLoc(CompilationUnit* cUnit, RegLocation loc) -{ - DCHECK(!loc.wide); - DCHECK(oatCheckCorePoolSanity(cUnit)); - if (loc.location != kLocPhysReg) { - DCHECK((loc.location == kLocDalvikFrame) || - (loc.location == kLocCompilerTemp)); - RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); - if (infoLo) { - if (infoLo->pair) { - oatClobber(cUnit, infoLo->reg); - oatClobber(cUnit, infoLo->partner); - oatFreeTemp(cUnit, infoLo->reg); - } else { - loc.lowReg = infoLo->reg; - loc.location = kLocPhysReg; - } - } - } - - return loc; -} - -bool oatCheckCorePoolSanity(CompilationUnit* cUnit) -{ - for (static int i = 0; i < cUnit->regPool->numCoreRegs; i++) { - if (cUnit->regPool->coreRegs[i].pair) { - static int myReg = cUnit->regPool->coreRegs[i].reg; - static int mySreg = cUnit->regPool->coreRegs[i].sReg; - static int partnerReg = cUnit->regPool->coreRegs[i].partner; - static RegisterInfo* partner = oatGetRegInfo(cUnit, partnerReg); - DCHECK(partner != NULL); - DCHECK(partner->pair); - DCHECK_EQ(myReg, partner->partner); - static int partnerSreg = partner->sReg; - if (mySreg == INVALID_SREG) { - DCHECK_EQ(partnerSreg, INVALID_SREG); - } else { - int diff = mySreg - partnerSreg; - DCHECK((diff == -1) || (diff == 1)); - } - } - if (!cUnit->regPool->coreRegs[i].live) { - DCHECK(cUnit->regPool->coreRegs[i].defStart == NULL); - DCHECK(cUnit->regPool->coreRegs[i].defEnd == NULL); - } - } - return true; -} - -/* see comments for updateLoc */ -extern RegLocation oatUpdateLocWide(CompilationUnit* cUnit, RegLocation loc) -{ - DCHECK(loc.wide); - DCHECK(oatCheckCorePoolSanity(cUnit)); - if (loc.location != kLocPhysReg) { - DCHECK((loc.location == kLocDalvikFrame) || - (loc.location == kLocCompilerTemp)); - // Are the dalvik regs already live in physical registers? - RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg); - RegisterInfo* infoHi = allocLive(cUnit, - oatSRegHi(loc.sRegLow), kAnyReg); - bool match = true; - match = match && (infoLo != NULL); - match = match && (infoHi != NULL); - // Are they both core or both FP? - match = match && (oatIsFpReg(infoLo->reg) == oatIsFpReg(infoHi->reg)); - // If a pair of floating point singles, are they properly aligned? - if (match && oatIsFpReg(infoLo->reg)) { - match &= ((infoLo->reg & 0x1) == 0); - match &= ((infoHi->reg - infoLo->reg) == 1); - } - // If previously used as a pair, it is the same pair? - if (match && (infoLo->pair || infoHi->pair)) { - match = (infoLo->pair == infoHi->pair); - match &= ((infoLo->reg == infoHi->partner) && - (infoHi->reg == infoLo->partner)); - } - if (match) { - // Can reuse - update the register usage info - loc.lowReg = infoLo->reg; - loc.highReg = infoHi->reg; - loc.location = kLocPhysReg; - oatMarkPair(cUnit, loc.lowReg, loc.highReg); - DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); - return loc; - } - // Can't easily reuse - clobber and free any overlaps - if (infoLo) { - oatClobber(cUnit, infoLo->reg); - oatFreeTemp(cUnit, infoLo->reg); - if (infoLo->pair) - oatClobber(cUnit, infoLo->partner); - } - if (infoHi) { - oatClobber(cUnit, infoHi->reg); - oatFreeTemp(cUnit, infoHi->reg); - if (infoHi->pair) - oatClobber(cUnit, infoHi->partner); - } - } - return loc; -} - - -/* For use in cases we don't know (or care) width */ -extern RegLocation oatUpdateRawLoc(CompilationUnit* cUnit, RegLocation loc) -{ - if (loc.wide) - return oatUpdateLocWide(cUnit, loc); - else - return oatUpdateLoc(cUnit, loc); -} - -RegLocation evalLocWide(CompilationUnit* cUnit, RegLocation loc, - int regClass, bool update) -{ - DCHECK(loc.wide); - int newRegs; - int lowReg; - int highReg; - - loc = oatUpdateLocWide(cUnit, loc); - - /* If already in registers, we can assume proper form. Right reg class? */ - if (loc.location == kLocPhysReg) { - DCHECK_EQ(oatIsFpReg(loc.lowReg), oatIsFpReg(loc.highReg)); - DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); - if (!regClassMatches(regClass, loc.lowReg)) { - /* Wrong register class. Reallocate and copy */ - newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass); - lowReg = newRegs & 0xff; - highReg = (newRegs >> 8) & 0xff; - oatRegCopyWide(cUnit, lowReg, highReg, loc.lowReg, - loc.highReg); - copyRegInfo(cUnit, lowReg, loc.lowReg); - copyRegInfo(cUnit, highReg, loc.highReg); - oatClobber(cUnit, loc.lowReg); - oatClobber(cUnit, loc.highReg); - loc.lowReg = lowReg; - loc.highReg = highReg; - oatMarkPair(cUnit, loc.lowReg, loc.highReg); - DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); - } - return loc; - } - - DCHECK_NE(loc.sRegLow, INVALID_SREG); - DCHECK_NE(oatSRegHi(loc.sRegLow), INVALID_SREG); - - newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass); - loc.lowReg = newRegs & 0xff; - loc.highReg = (newRegs >> 8) & 0xff; - - oatMarkPair(cUnit, loc.lowReg, loc.highReg); - if (update) { - loc.location = kLocPhysReg; - oatMarkLive(cUnit, loc.lowReg, loc.sRegLow); - oatMarkLive(cUnit, loc.highReg, oatSRegHi(loc.sRegLow)); - } - DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0)); - return loc; -} - -extern RegLocation oatEvalLoc(CompilationUnit* cUnit, RegLocation loc, - int regClass, bool update) -{ - int newReg; - - if (loc.wide) - return evalLocWide(cUnit, loc, regClass, update); - - loc = oatUpdateLoc(cUnit, loc); - - if (loc.location == kLocPhysReg) { - if (!regClassMatches(regClass, loc.lowReg)) { - /* Wrong register class. Realloc, copy and transfer ownership */ - newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass); - oatRegCopy(cUnit, newReg, loc.lowReg); - copyRegInfo(cUnit, newReg, loc.lowReg); - oatClobber(cUnit, loc.lowReg); - loc.lowReg = newReg; - } - return loc; - } - - DCHECK_NE(loc.sRegLow, INVALID_SREG); - - newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass); - loc.lowReg = newReg; - - if (update) { - loc.location = kLocPhysReg; - oatMarkLive(cUnit, loc.lowReg, loc.sRegLow); - } - return loc; -} - -extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num) -{ - DCHECK(num < mir->ssaRep->numUses); - RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]]; - return res; -} -extern RegLocation oatGetRawDest(CompilationUnit* cUnit, MIR* mir) -{ - DCHECK_GT(mir->ssaRep->numDefs, 0); - RegLocation res = cUnit->regLocation[mir->ssaRep->defs[0]]; - return res; -} -extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir) -{ - RegLocation res = oatGetRawDest(cUnit, mir); - DCHECK(!res.wide); - return res; -} -extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num) -{ - RegLocation res = oatGetRawSrc(cUnit, mir, num); - DCHECK(!res.wide); - return res; -} -extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir) -{ - RegLocation res = oatGetRawDest(cUnit, mir); - DCHECK(res.wide); - return res; -} - -extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir, - int low) -{ - RegLocation res = oatGetRawSrc(cUnit, mir, low); - DCHECK(res.wide); - return res; -} - -/* USE SSA names to count references of base Dalvik vRegs. */ -void oatCountRefs(CompilationUnit *cUnit, BasicBlock* bb, - RefCounts* coreCounts, RefCounts* fpCounts) -{ - if ((cUnit->disableOpt & (1 << kPromoteRegs)) || - !((bb->blockType == kEntryBlock) || (bb->blockType == kExitBlock) || - (bb->blockType == kDalvikByteCode))) { - return; - } - for (int i = 0; i < cUnit->numSSARegs;) { - RegLocation loc = cUnit->regLocation[i]; - RefCounts* counts = loc.fp ? fpCounts : coreCounts; - int pMapIdx = SRegToPMap(cUnit, loc.sRegLow); - if (loc.defined) { - counts[pMapIdx].count += cUnit->useCounts.elemList[i]; - } - if (loc.wide) { - if (loc.defined) { - if (loc.fp) { - counts[pMapIdx].doubleStart = true; - counts[pMapIdx+1].count += cUnit->useCounts.elemList[i+1]; - } - } - i += 2; - } else { - i++; - } - } -} - -/* qsort callback function, sort descending */ -int oatSortCounts(const void *val1, const void *val2) -{ - const RefCounts* op1 = (const RefCounts*)val1; - const RefCounts* op2 = (const RefCounts*)val2; - return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1); -} - -void oatDumpCounts(const RefCounts* arr, int size, const char* msg) -{ - LOG(INFO) << msg; - for (int i = 0; i < size; i++) { - LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count; - } -} - -/* - * Note: some portions of this code required even if the kPromoteRegs - * optimization is disabled. - */ -extern void oatDoPromotion(CompilationUnit* cUnit) -{ - int regBias = cUnit->numCompilerTemps + 1; - int dalvikRegs = cUnit->numDalvikRegisters; - int numRegs = dalvikRegs + regBias; - const int promotionThreshold = 2; - - // Allow target code to add any special registers - oatAdjustSpillMask(cUnit); - - /* - * Simple register promotion. Just do a static count of the uses - * of Dalvik registers. Note that we examine the SSA names, but - * count based on original Dalvik register name. Count refs - * separately based on type in order to give allocation - * preference to fp doubles - which must be allocated sequential - * physical single fp registers started with an even-numbered - * reg. - * TUNING: replace with linear scan once we have the ability - * to describe register live ranges for GC. - */ - RefCounts *coreRegs = (RefCounts *) - oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc); - RefCounts *fpRegs = (RefCounts *) - oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc); - // Set ssa names for original Dalvik registers - for (int i = 0; i < dalvikRegs; i++) { - coreRegs[i].sReg = fpRegs[i].sReg = i; - } - // Set ssa name for Method* - coreRegs[dalvikRegs].sReg = cUnit->methodSReg; - fpRegs[dalvikRegs].sReg = cUnit->methodSReg; // For consistecy - // Set ssa names for compilerTemps - for (int i = 1; i <= cUnit->numCompilerTemps; i++) { - CompilerTemp* ct = (CompilerTemp*)cUnit->compilerTemps.elemList[i]; - coreRegs[dalvikRegs + i].sReg = ct->sReg; - fpRegs[dalvikRegs + i].sReg = ct->sReg; - } - - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->blockList, &iterator); - while (true) { - BasicBlock* bb; - bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator); - if (bb == NULL) break; - oatCountRefs(cUnit, bb, coreRegs, fpRegs); - } - - /* - * Ideally, we'd allocate doubles starting with an even-numbered - * register. Bias the counts to try to allocate any vreg that's - * used as the start of a pair first. - */ - for (int i = 0; i < numRegs; i++) { - if (fpRegs[i].doubleStart) { - fpRegs[i].count *= 2; - } - } - - // Sort the count arrays - qsort(coreRegs, numRegs, sizeof(RefCounts), oatSortCounts); - qsort(fpRegs, numRegs, sizeof(RefCounts), oatSortCounts); - - if (cUnit->printMe) { - oatDumpCounts(coreRegs, numRegs, "Core regs after sort"); - oatDumpCounts(fpRegs, numRegs, "Fp regs after sort"); - } - - if (!(cUnit->disableOpt & (1 << kPromoteRegs))) { - // Promote fpRegs - for (int i = 0; (i < numRegs) && - (fpRegs[i].count >= promotionThreshold ); i++) { - int pMapIdx = SRegToPMap(cUnit, fpRegs[i].sReg); - if (cUnit->promotionMap[pMapIdx].fpLocation != kLocPhysReg) { - int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg, - fpRegs[i].doubleStart); - if (reg < 0) { - break; // No more left - } - } - } - - // Promote core regs - for (int i = 0; (i < numRegs) && - (coreRegs[i].count > promotionThreshold); i++) { - int pMapIdx = SRegToPMap(cUnit, coreRegs[i].sReg); - if (cUnit->promotionMap[pMapIdx].coreLocation != - kLocPhysReg) { - int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg); - if (reg < 0) { - break; // No more left - } - } - } - } else if (cUnit->qdMode) { - oatAllocPreservedCoreReg(cUnit, cUnit->methodSReg); - for (int i = 0; i < numRegs; i++) { - int reg = oatAllocPreservedCoreReg(cUnit, i); - if (reg < 0) { - break; // No more left - } - } - } - - - // Now, update SSA names to new home locations - for (int i = 0; i < cUnit->numSSARegs; i++) { - RegLocation *curr = &cUnit->regLocation[i]; - int pMapIdx = SRegToPMap(cUnit, curr->sRegLow); - if (!curr->wide) { - if (curr->fp) { - if (cUnit->promotionMap[pMapIdx].fpLocation == kLocPhysReg) { - curr->location = kLocPhysReg; - curr->lowReg = cUnit->promotionMap[pMapIdx].fpReg; - curr->home = true; - } - } else { - if (cUnit->promotionMap[pMapIdx].coreLocation == kLocPhysReg) { - curr->location = kLocPhysReg; - curr->lowReg = cUnit->promotionMap[pMapIdx].coreReg; - curr->home = true; - } - } - curr->highReg = INVALID_REG; - } else { - if (curr->highWord) { - continue; - } - if (curr->fp) { - if ((cUnit->promotionMap[pMapIdx].fpLocation == kLocPhysReg) && - (cUnit->promotionMap[pMapIdx+1].fpLocation == - kLocPhysReg)) { - int lowReg = cUnit->promotionMap[pMapIdx].fpReg; - int highReg = cUnit->promotionMap[pMapIdx+1].fpReg; - // Doubles require pair of singles starting at even reg - if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) { - curr->location = kLocPhysReg; - curr->lowReg = lowReg; - curr->highReg = highReg; - curr->home = true; - } - } - } else { - if ((cUnit->promotionMap[pMapIdx].coreLocation == kLocPhysReg) - && (cUnit->promotionMap[pMapIdx+1].coreLocation == - kLocPhysReg)) { - curr->location = kLocPhysReg; - curr->lowReg = cUnit->promotionMap[pMapIdx].coreReg; - curr->highReg = cUnit->promotionMap[pMapIdx+1].coreReg; - curr->home = true; - } - } - } - } - if (cUnit->printMe) { - oatDumpPromotionMap(cUnit); - } -} - -/* Returns sp-relative offset in bytes for a VReg */ -extern int oatVRegOffset(CompilationUnit* cUnit, int vReg) -{ - return StackVisitor::GetVRegOffset(cUnit->code_item, cUnit->coreSpillMask, - cUnit->fpSpillMask, cUnit->frameSize, vReg); -} - -/* Returns sp-relative offset in bytes for a SReg */ -extern int oatSRegOffset(CompilationUnit* cUnit, int sReg) -{ - return oatVRegOffset(cUnit, SRegToVReg(cUnit, sReg)); -} - -} // namespace art 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/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc deleted file mode 100644 index 2d4b314d51..0000000000 --- a/src/compiler/codegen/arm/ArchUtility.cc +++ /dev/null @@ -1,512 +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. - */ - -#include "../../CompilerInternals.h" -#include "ArmLIR.h" -#include "../Ralloc.h" - -#include - -namespace art { - -RegLocation locCReturn() -{ - RegLocation res = ARM_LOC_C_RETURN; - return res; -} - -RegLocation locCReturnWide() -{ - RegLocation res = ARM_LOC_C_RETURN_WIDE; - return res; -} - -RegLocation locCReturnFloat() -{ - RegLocation res = ARM_LOC_C_RETURN_FLOAT; - return res; -} - -RegLocation locCReturnDouble() -{ - RegLocation res = ARM_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 = rARM_SELF; break; - case kSuspend: res = rARM_SUSPEND; break; - case kLr: res = rARM_LR; break; - case kPc: res = rARM_PC; break; - case kSp: res = rARM_SP; break; - case kArg0: res = rARM_ARG0; break; - case kArg1: res = rARM_ARG1; break; - case kArg2: res = rARM_ARG2; break; - case kArg3: res = rARM_ARG3; break; - case kFArg0: res = rARM_FARG0; break; - case kFArg1: res = rARM_FARG1; break; - case kFArg2: res = rARM_FARG2; break; - case kFArg3: res = rARM_FARG3; break; - case kRet0: res = rARM_RET0; break; - case kRet1: res = rARM_RET1; break; - case kInvokeTgt: res = rARM_INVOKE_TGT; break; - case kCount: res = rARM_COUNT; break; - } - return res; -} - - -// Create a double from a pair of singles. -int s2d(int lowReg, int highReg) -{ - return ARM_S2D(lowReg, highReg); -} - -// Is reg a single or double? -bool fpReg(int reg) -{ - return ARM_FPREG(reg); -} - -// Is reg a single? -bool singleReg(int reg) -{ - return ARM_SINGLEREG(reg); -} - -// Is reg a double? -bool doubleReg(int reg) -{ - return ARM_DOUBLEREG(reg); -} - -// Return mask to strip off fp reg flags and bias. -uint32_t fpRegMask() -{ - return ARM_FP_REG_MASK; -} - -// True if both regs single, both core or both double. -bool sameRegType(int reg1, int reg2) -{ - return (ARM_REGTYPE(reg1) == ARM_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 = ARM_DOUBLEREG(reg) ? 3 : 1; - /* FP register starts at bit position 16 */ - shift = ARM_FPREG(reg) ? kArmFPReg0 : 0; - /* Expand the double register id into single offset */ - shift += regId; - return (seed << shift); -} - -uint64_t getPCUseDefEncoding() -{ - return ENCODE_ARM_REG_PC; -} - -void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) -{ - DCHECK_EQ(cUnit->instructionSet, kThumb2); - - // Thumb2 specific setup - uint64_t flags = EncodingMap[lir->opcode].flags; - int opcode = lir->opcode; - - if (flags & REG_DEF_SP) { - lir->defMask |= ENCODE_ARM_REG_SP; - } - - if (flags & REG_USE_SP) { - lir->useMask |= ENCODE_ARM_REG_SP; - } - - if (flags & REG_DEF_LIST0) { - lir->defMask |= ENCODE_ARM_REG_LIST(lir->operands[0]); - } - - if (flags & REG_DEF_LIST1) { - lir->defMask |= ENCODE_ARM_REG_LIST(lir->operands[1]); - } - - if (flags & REG_DEF_FPCS_LIST0) { - lir->defMask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); - } - - if (flags & REG_DEF_FPCS_LIST2) { - for (int i = 0; i < lir->operands[2]; i++) { - oatSetupRegMask(cUnit, &lir->defMask, lir->operands[1] + i); - } - } - - if (flags & REG_USE_PC) { - lir->useMask |= ENCODE_ARM_REG_PC; - } - - /* Conservatively treat the IT block */ - if (flags & IS_IT) { - lir->defMask = ENCODE_ALL; - } - - if (flags & REG_USE_LIST0) { - lir->useMask |= ENCODE_ARM_REG_LIST(lir->operands[0]); - } - - if (flags & REG_USE_LIST1) { - lir->useMask |= ENCODE_ARM_REG_LIST(lir->operands[1]); - } - - if (flags & REG_USE_FPCS_LIST0) { - lir->useMask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); - } - - if (flags & REG_USE_FPCS_LIST2) { - for (int i = 0; i < lir->operands[2]; i++) { - oatSetupRegMask(cUnit, &lir->useMask, lir->operands[1] + i); - } - } - /* Fixup for kThumbPush/lr and kThumbPop/pc */ - if (opcode == kThumbPush || opcode == kThumbPop) { - u8 r8Mask = oatGetRegMaskCommon(cUnit, r8); - if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) { - lir->useMask &= ~r8Mask; - lir->useMask |= ENCODE_ARM_REG_LR; - } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) { - lir->defMask &= ~r8Mask; - lir->defMask |= ENCODE_ARM_REG_PC; - } - } - if (flags & REG_DEF_LR) { - lir->defMask |= ENCODE_ARM_REG_LR; - } -} - -ArmConditionCode oatArmConditionEncoding(ConditionCode code) -{ - ArmConditionCode res; - switch (code) { - case kCondEq: res = kArmCondEq; break; - case kCondNe: res = kArmCondNe; break; - case kCondCs: res = kArmCondCs; break; - case kCondCc: res = kArmCondCc; break; - case kCondMi: res = kArmCondMi; break; - case kCondPl: res = kArmCondPl; break; - case kCondVs: res = kArmCondVs; break; - case kCondVc: res = kArmCondVc; break; - case kCondHi: res = kArmCondHi; break; - case kCondLs: res = kArmCondLs; break; - case kCondGe: res = kArmCondGe; break; - case kCondLt: res = kArmCondLt; break; - case kCondGt: res = kArmCondGt; break; - case kCondLe: res = kArmCondLe; break; - case kCondAl: res = kArmCondAl; break; - case kCondNv: res = kArmCondNv; break; - default: - LOG(FATAL) << "Bad condition code" << (int)code; - res = (ArmConditionCode)0; // Quiet gcc - } - return res; -} - -static const char* coreRegNames[16] = { - "r0", - "r1", - "r2", - "r3", - "r4", - "r5", - "r6", - "r7", - "r8", - "rSELF", - "r10", - "r11", - "r12", - "sp", - "lr", - "pc", -}; - - -static const char* shiftNames[4] = { - "lsl", - "lsr", - "asr", - "ror"}; - -/* Decode and print a ARM register name */ -char* decodeRegList(int opcode, int vector, char* buf) -{ - int i; - bool printed = false; - buf[0] = 0; - for (i = 0; i < 16; i++, vector >>= 1) { - if (vector & 0x1) { - int regId = i; - if (opcode == kThumbPush && i == 8) { - regId = r14lr; - } else if (opcode == kThumbPop && i == 8) { - regId = r15pc; - } - if (printed) { - sprintf(buf + strlen(buf), ", r%d", regId); - } else { - printed = true; - sprintf(buf, "r%d", regId); - } - } - } - return buf; -} - -char* decodeFPCSRegList(int count, int base, char* buf) -{ - sprintf(buf, "s%d", base); - for (int i = 1; i < count; i++) { - sprintf(buf + strlen(buf), ", s%d",base + i); - } - return buf; -} - -int expandImmediate(int value) -{ - int mode = (value & 0xf00) >> 8; - u4 bits = value & 0xff; - switch (mode) { - case 0: - return bits; - case 1: - return (bits << 16) | bits; - case 2: - return (bits << 24) | (bits << 8); - case 3: - return (bits << 24) | (bits << 16) | (bits << 8) | bits; - default: - break; - } - bits = (bits | 0x80) << 24; - return bits >> (((value & 0xf80) >> 7) - 8); -} - -const char* ccNames[] = {"eq","ne","cs","cc","mi","pl","vs","vc", - "hi","ls","ge","lt","gt","le","al","nv"}; -/* - * 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]; - const char* name; - 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 'H': - if (operand != 0) { - sprintf(tbuf, ", %s %d",shiftNames[operand & 0x3], operand >> 2); - } else { - strcpy(tbuf,""); - } - break; - case 'B': - switch (operand) { - case kSY: - name = "sy"; - break; - case kST: - name = "st"; - break; - case kISH: - name = "ish"; - break; - case kISHST: - name = "ishst"; - break; - case kNSH: - name = "nsh"; - break; - case kNSHST: - name = "shst"; - break; - default: - name = "DecodeError2"; - break; - } - strcpy(tbuf, name); - break; - case 'b': - strcpy(tbuf,"0000"); - for (i=3; i>= 0; i--) { - tbuf[i] += operand & 1; - operand >>= 1; - } - break; - case 'n': - operand = ~expandImmediate(operand); - sprintf(tbuf,"%d [%#x]", operand, operand); - break; - case 'm': - operand = expandImmediate(operand); - sprintf(tbuf,"%d [%#x]", operand, operand); - break; - case 's': - sprintf(tbuf,"s%d",operand & ARM_FP_REG_MASK); - break; - case 'S': - sprintf(tbuf,"d%d",(operand & ARM_FP_REG_MASK) >> 1); - break; - case 'h': - sprintf(tbuf,"%04x", operand); - break; - case 'M': - case 'd': - sprintf(tbuf,"%d", operand); - break; - case 'C': - DCHECK_LT(operand, static_cast( - sizeof(coreRegNames)/sizeof(coreRegNames[0]))); - sprintf(tbuf,"%s",coreRegNames[operand]); - break; - case 'E': - sprintf(tbuf,"%d", operand*4); - break; - case 'F': - sprintf(tbuf,"%d", operand*2); - break; - case 'c': - strcpy(tbuf, ccNames[operand]); - break; - case 't': - sprintf(tbuf,"0x%08x (L%p)", - (int) baseAddr + lir->offset + 4 + - (operand << 1), - lir->target); - 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': - decodeRegList(lir->opcode, operand, tbuf); - break; - case 'P': - decodeFPCSRegList(operand, 16, tbuf); - break; - case 'Q': - decodeFPCSRegList(operand, 0, tbuf); - break; - default: - strcpy(tbuf,"DecodeError1"); - break; - } - buf += tbuf; - } - } else { - buf += *fmt++; - } - } - return buf; -} - -void oatDumpResourceMask(LIR* lir, u8 mask, const char* prefix) -{ - char buf[256]; - buf[0] = 0; - LIR* armLIR = (LIR*) lir; - - if (mask == ENCODE_ALL) { - strcpy(buf, "all"); - } else { - char num[8]; - int i; - - for (i = 0; i < kArmRegEnd; 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 (armLIR && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff, - (armLIR->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/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h deleted file mode 100644 index 7eebc835ec..0000000000 --- a/src/compiler/codegen/arm/ArmLIR.h +++ /dev/null @@ -1,617 +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. - */ - -#ifndef ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_ -#define ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_ - -#include "../../Dalvik.h" -#include "../../CompilerInternals.h" - -namespace art { - -/* - * Runtime register usage conventions. - * - * r0-r3: Argument registers in both Dalvik and C/C++ conventions. - * However, for Dalvik->Dalvik calls we'll pass the target's Method* - * pointer in r0 as a hidden arg0. Otherwise used as codegen scratch - * registers. - * r0-r1: As in C/C++ r0 is 32-bit return register and r0/r1 is 64-bit - * r4 : (rARM_SUSPEND) is reserved (suspend check/debugger assist) - * r5 : Callee save (promotion target) - * r6 : Callee save (promotion target) - * r7 : Callee save (promotion target) - * r8 : Callee save (promotion target) - * r9 : (rARM_SELF) is reserved (pointer to thread-local storage) - * r10 : Callee save (promotion target) - * r11 : Callee save (promotion target) - * r12 : Scratch, may be trashed by linkage stubs - * r13 : (sp) is reserved - * r14 : (lr) is reserved - * r15 : (pc) is reserved - * - * 5 core temps that codegen can use (r0, r1, r2, r3, r12) - * 7 core registers that can be used for promotion - * - * Floating pointer registers - * s0-s31 - * d0-d15, where d0={s0,s1}, d1={s2,s3}, ... , d15={s30,s31} - * - * s16-s31 (d8-d15) preserved across C calls - * s0-s15 (d0-d7) trashed across C calls - * - * s0-s15/d0-d7 used as codegen temp/scratch - * s16-s31/d8-d31 can be used for promotion. - * - * Calling convention - * o On a call to a Dalvik method, pass target's Method* in r0 - * o r1-r3 will be used for up to the first 3 words of arguments - * o Arguments past the first 3 words will be placed in appropriate - * out slots by the caller. - * o If a 64-bit argument would span the register/memory argument - * boundary, it will instead be fully passed in the frame. - * o Maintain a 16-byte stack alignment - * - * Stack frame diagram (stack grows down, higher addresses at top): - * - * +------------------------+ - * | IN[ins-1] | {Note: resides in caller's frame} - * | . | - * | IN[0] | - * | caller's Method* | - * +========================+ {Note: start of callee's frame} - * | spill region | {variable sized - will include lr if non-leaf.} - * +------------------------+ - * | ...filler word... | {Note: used as 2nd word of V[locals-1] if long] - * +------------------------+ - * | V[locals-1] | - * | V[locals-2] | - * | . | - * | . | - * | V[1] | - * | V[0] | - * +------------------------+ - * | 0 to 3 words padding | - * +------------------------+ - * | OUT[outs-1] | - * | OUT[outs-2] | - * | . | - * | OUT[0] | - * | curMethod* | <<== sp w/ 16-byte alignment - * +========================+ - */ - -/* Offset to distingish FP regs */ -#define ARM_FP_REG_OFFSET 32 -/* Offset to distinguish DP FP regs */ -#define ARM_FP_DOUBLE 64 -/* First FP callee save */ -#define ARM_FP_CALLEE_SAVE_BASE 16 -/* Reg types */ -#define ARM_REGTYPE(x) (x & (ARM_FP_REG_OFFSET | ARM_FP_DOUBLE)) -#define ARM_FPREG(x) ((x & ARM_FP_REG_OFFSET) == ARM_FP_REG_OFFSET) -#define ARM_LOWREG(x) ((x & 0x7) == x) -#define ARM_DOUBLEREG(x) ((x & ARM_FP_DOUBLE) == ARM_FP_DOUBLE) -#define ARM_SINGLEREG(x) (ARM_FPREG(x) && !ARM_DOUBLEREG(x)) -/* - * Note: the low register of a floating point pair is sufficient to - * create the name of a double, but require both names to be passed to - * allow for asserts to verify that the pair is consecutive if significant - * rework is done in this area. Also, it is a good reminder in the calling - * code that reg locations always describe doubles as a pair of singles. - */ -#define ARM_S2D(x,y) ((x) | ARM_FP_DOUBLE) -/* Mask to strip off fp flags */ -#define ARM_FP_REG_MASK (ARM_FP_REG_OFFSET-1) - -/* RegisterLocation templates return values (r0, or r0/r1) */ -#define ARM_LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r0, INVALID_REG,\ - INVALID_SREG, INVALID_SREG} -#define ARM_LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, \ - INVALID_SREG, INVALID_SREG} -#define ARM_LOC_C_RETURN_FLOAT ARM_LOC_C_RETURN -#define ARM_LOC_C_RETURN_DOUBLE ARM_LOC_C_RETURN_WIDE - -enum ArmResourceEncodingPos { - kArmGPReg0 = 0, - kArmRegSP = 13, - kArmRegLR = 14, - kArmRegPC = 15, - kArmFPReg0 = 16, - kArmFPReg16 = 32, - kArmRegEnd = 48, -}; - -#define ENCODE_ARM_REG_LIST(N) ((u8) N) -#define ENCODE_ARM_REG_SP (1ULL << kArmRegSP) -#define ENCODE_ARM_REG_LR (1ULL << kArmRegLR) -#define ENCODE_ARM_REG_PC (1ULL << kArmRegPC) -#define ENCODE_ARM_REG_FPCS_LIST(N) ((u8)N << kArmFPReg16) - -enum ArmNativeRegisterPool { - r0 = 0, - r1 = 1, - r2 = 2, - r3 = 3, - rARM_SUSPEND = 4, - r5 = 5, - r6 = 6, - r7 = 7, - r8 = 8, - rARM_SELF = 9, - r10 = 10, - r11 = 11, - r12 = 12, - r13sp = 13, - rARM_SP = 13, - r14lr = 14, - rARM_LR = 14, - r15pc = 15, - rARM_PC = 15, - fr0 = 0 + ARM_FP_REG_OFFSET, - fr1 = 1 + ARM_FP_REG_OFFSET, - fr2 = 2 + ARM_FP_REG_OFFSET, - fr3 = 3 + ARM_FP_REG_OFFSET, - fr4 = 4 + ARM_FP_REG_OFFSET, - fr5 = 5 + ARM_FP_REG_OFFSET, - fr6 = 6 + ARM_FP_REG_OFFSET, - fr7 = 7 + ARM_FP_REG_OFFSET, - fr8 = 8 + ARM_FP_REG_OFFSET, - fr9 = 9 + ARM_FP_REG_OFFSET, - fr10 = 10 + ARM_FP_REG_OFFSET, - fr11 = 11 + ARM_FP_REG_OFFSET, - fr12 = 12 + ARM_FP_REG_OFFSET, - fr13 = 13 + ARM_FP_REG_OFFSET, - fr14 = 14 + ARM_FP_REG_OFFSET, - fr15 = 15 + ARM_FP_REG_OFFSET, - fr16 = 16 + ARM_FP_REG_OFFSET, - fr17 = 17 + ARM_FP_REG_OFFSET, - fr18 = 18 + ARM_FP_REG_OFFSET, - fr19 = 19 + ARM_FP_REG_OFFSET, - fr20 = 20 + ARM_FP_REG_OFFSET, - fr21 = 21 + ARM_FP_REG_OFFSET, - fr22 = 22 + ARM_FP_REG_OFFSET, - fr23 = 23 + ARM_FP_REG_OFFSET, - fr24 = 24 + ARM_FP_REG_OFFSET, - fr25 = 25 + ARM_FP_REG_OFFSET, - fr26 = 26 + ARM_FP_REG_OFFSET, - fr27 = 27 + ARM_FP_REG_OFFSET, - fr28 = 28 + ARM_FP_REG_OFFSET, - fr29 = 29 + ARM_FP_REG_OFFSET, - fr30 = 30 + ARM_FP_REG_OFFSET, - fr31 = 31 + ARM_FP_REG_OFFSET, - dr0 = fr0 + ARM_FP_DOUBLE, - dr1 = fr2 + ARM_FP_DOUBLE, - dr2 = fr4 + ARM_FP_DOUBLE, - dr3 = fr6 + ARM_FP_DOUBLE, - dr4 = fr8 + ARM_FP_DOUBLE, - dr5 = fr10 + ARM_FP_DOUBLE, - dr6 = fr12 + ARM_FP_DOUBLE, - dr7 = fr14 + ARM_FP_DOUBLE, - dr8 = fr16 + ARM_FP_DOUBLE, - dr9 = fr18 + ARM_FP_DOUBLE, - dr10 = fr20 + ARM_FP_DOUBLE, - dr11 = fr22 + ARM_FP_DOUBLE, - dr12 = fr24 + ARM_FP_DOUBLE, - dr13 = fr26 + ARM_FP_DOUBLE, - dr14 = fr28 + ARM_FP_DOUBLE, - dr15 = fr30 + ARM_FP_DOUBLE, -}; - -/* Target-independent aliases */ -#define rARM_ARG0 r0 -#define rARM_ARG1 r1 -#define rARM_ARG2 r2 -#define rARM_ARG3 r3 -#define rARM_FARG0 r0 -#define rARM_FARG1 r1 -#define rARM_FARG2 r2 -#define rARM_FARG3 r3 -#define rARM_RET0 r0 -#define rARM_RET1 r1 -#define rARM_INVOKE_TGT rARM_LR -#define rARM_COUNT INVALID_REG - -/* Shift encodings */ -enum ArmShiftEncodings { - kArmLsl = 0x0, - kArmLsr = 0x1, - kArmAsr = 0x2, - kArmRor = 0x3 -}; - -#define isPseudoOpcode(opcode) ((int)(opcode) < 0) - -/* - * The following enum defines the list of supported Thumb instructions by the - * assembler. Their corresponding EncodingMap positions will be defined in - * Assemble.cc. - */ -enum ArmOpcode { - /************************************************************************/ - kArmFirst = 0, - kArm16BitData = kArmFirst, /* DATA [0] rd[15..0] */ - kThumbAdcRR, /* adc [0100000101] rm[5..3] rd[2..0] */ - kThumbAddRRI3, /* add(1) [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/ - kThumbAddRI8, /* add(2) [00110] rd[10..8] imm_8[7..0] */ - kThumbAddRRR, /* add(3) [0001100] rm[8..6] rn[5..3] rd[2..0] */ - kThumbAddRRLH, /* add(4) [01000100] H12[01] rm[5..3] rd[2..0] */ - kThumbAddRRHL, /* add(4) [01001000] H12[10] rm[5..3] rd[2..0] */ - kThumbAddRRHH, /* add(4) [01001100] H12[11] rm[5..3] rd[2..0] */ - kThumbAddPcRel, /* add(5) [10100] rd[10..8] imm_8[7..0] */ - kThumbAddSpRel, /* add(6) [10101] rd[10..8] imm_8[7..0] */ - kThumbAddSpI7, /* add(7) [101100000] imm_7[6..0] */ - kThumbAndRR, /* and [0100000000] rm[5..3] rd[2..0] */ - kThumbAsrRRI5, /* asr(1) [00010] imm_5[10..6] rm[5..3] rd[2..0] */ - kThumbAsrRR, /* asr(2) [0100000100] rs[5..3] rd[2..0] */ - kThumbBCond, /* b(1) [1101] cond[11..8] offset_8[7..0] */ - kThumbBUncond, /* b(2) [11100] offset_11[10..0] */ - kThumbBicRR, /* bic [0100001110] rm[5..3] rd[2..0] */ - kThumbBkpt, /* bkpt [10111110] imm_8[7..0] */ - kThumbBlx1, /* blx(1) [111] H[10] offset_11[10..0] */ - kThumbBlx2, /* blx(1) [111] H[01] offset_11[10..0] */ - kThumbBl1, /* blx(1) [111] H[10] offset_11[10..0] */ - kThumbBl2, /* blx(1) [111] H[11] offset_11[10..0] */ - kThumbBlxR, /* blx(2) [010001111] rm[6..3] [000] */ - kThumbBx, /* bx [010001110] H2[6..6] rm[5..3] SBZ[000] */ - kThumbCmnRR, /* cmn [0100001011] rm[5..3] rd[2..0] */ - kThumbCmpRI8, /* cmp(1) [00101] rn[10..8] imm_8[7..0] */ - kThumbCmpRR, /* cmp(2) [0100001010] rm[5..3] rd[2..0] */ - kThumbCmpLH, /* cmp(3) [01000101] H12[01] rm[5..3] rd[2..0] */ - kThumbCmpHL, /* cmp(3) [01000110] H12[10] rm[5..3] rd[2..0] */ - kThumbCmpHH, /* cmp(3) [01000111] H12[11] rm[5..3] rd[2..0] */ - kThumbEorRR, /* eor [0100000001] rm[5..3] rd[2..0] */ - kThumbLdmia, /* ldmia [11001] rn[10..8] reglist [7..0] */ - kThumbLdrRRI5, /* ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbLdrRRR, /* ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0] */ - kThumbLdrPcRel, /* ldr(3) [01001] rd[10..8] imm_8[7..0] */ - kThumbLdrSpRel, /* ldr(4) [10011] rd[10..8] imm_8[7..0] */ - kThumbLdrbRRI5, /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbLdrbRRR, /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */ - kThumbLdrhRRI5, /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbLdrhRRR, /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */ - kThumbLdrsbRRR, /* ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0] */ - kThumbLdrshRRR, /* ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0] */ - kThumbLslRRI5, /* lsl(1) [00000] imm_5[10..6] rm[5..3] rd[2..0] */ - kThumbLslRR, /* lsl(2) [0100000010] rs[5..3] rd[2..0] */ - kThumbLsrRRI5, /* lsr(1) [00001] imm_5[10..6] rm[5..3] rd[2..0] */ - kThumbLsrRR, /* lsr(2) [0100000011] rs[5..3] rd[2..0] */ - kThumbMovImm, /* mov(1) [00100] rd[10..8] imm_8[7..0] */ - kThumbMovRR, /* mov(2) [0001110000] rn[5..3] rd[2..0] */ - kThumbMovRR_H2H, /* mov(3) [01000111] H12[11] rm[5..3] rd[2..0] */ - kThumbMovRR_H2L, /* mov(3) [01000110] H12[01] rm[5..3] rd[2..0] */ - kThumbMovRR_L2H, /* mov(3) [01000101] H12[10] rm[5..3] rd[2..0] */ - kThumbMul, /* mul [0100001101] rm[5..3] rd[2..0] */ - kThumbMvn, /* mvn [0100001111] rm[5..3] rd[2..0] */ - kThumbNeg, /* neg [0100001001] rm[5..3] rd[2..0] */ - kThumbOrr, /* orr [0100001100] rm[5..3] rd[2..0] */ - kThumbPop, /* pop [1011110] r[8..8] rl[7..0] */ - kThumbPush, /* push [1011010] r[8..8] rl[7..0] */ - kThumbRorRR, /* ror [0100000111] rs[5..3] rd[2..0] */ - kThumbSbc, /* sbc [0100000110] rm[5..3] rd[2..0] */ - kThumbStmia, /* stmia [11000] rn[10..8] reglist [7.. 0] */ - kThumbStrRRI5, /* str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbStrRRR, /* str(2) [0101000] rm[8..6] rn[5..3] rd[2..0] */ - kThumbStrSpRel, /* str(3) [10010] rd[10..8] imm_8[7..0] */ - kThumbStrbRRI5, /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbStrbRRR, /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */ - kThumbStrhRRI5, /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */ - kThumbStrhRRR, /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */ - kThumbSubRRI3, /* sub(1) [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/ - kThumbSubRI8, /* sub(2) [00111] rd[10..8] imm_8[7..0] */ - kThumbSubRRR, /* sub(3) [0001101] rm[8..6] rn[5..3] rd[2..0] */ - kThumbSubSpI7, /* sub(4) [101100001] imm_7[6..0] */ - kThumbSwi, /* swi [11011111] imm_8[7..0] */ - kThumbTst, /* tst [0100001000] rm[5..3] rn[2..0] */ - kThumb2Vldrs, /* vldr low sx [111011011001] rn[19..16] rd[15-12] - [1010] imm_8[7..0] */ - kThumb2Vldrd, /* vldr low dx [111011011001] rn[19..16] rd[15-12] - [1011] imm_8[7..0] */ - kThumb2Vmuls, /* vmul vd, vn, vm [111011100010] rn[19..16] - rd[15-12] [10100000] rm[3..0] */ - kThumb2Vmuld, /* vmul vd, vn, vm [111011100010] rn[19..16] - rd[15-12] [10110000] rm[3..0] */ - kThumb2Vstrs, /* vstr low sx [111011011000] rn[19..16] rd[15-12] - [1010] imm_8[7..0] */ - kThumb2Vstrd, /* vstr low dx [111011011000] rn[19..16] rd[15-12] - [1011] imm_8[7..0] */ - kThumb2Vsubs, /* vsub vd, vn, vm [111011100011] rn[19..16] - rd[15-12] [10100040] rm[3..0] */ - kThumb2Vsubd, /* vsub vd, vn, vm [111011100011] rn[19..16] - rd[15-12] [10110040] rm[3..0] */ - kThumb2Vadds, /* vadd vd, vn, vm [111011100011] rn[19..16] - rd[15-12] [10100000] rm[3..0] */ - kThumb2Vaddd, /* vadd vd, vn, vm [111011100011] rn[19..16] - rd[15-12] [10110000] rm[3..0] */ - kThumb2Vdivs, /* vdiv vd, vn, vm [111011101000] rn[19..16] - rd[15-12] [10100000] rm[3..0] */ - kThumb2Vdivd, /* vdiv vd, vn, vm [111011101000] rn[19..16] - rd[15-12] [10110000] rm[3..0] */ - kThumb2VcvtIF, /* vcvt.F32 vd, vm [1110111010111000] vd[15..12] - [10101100] vm[3..0] */ - kThumb2VcvtID, /* vcvt.F64 vd, vm [1110111010111000] vd[15..12] - [10111100] vm[3..0] */ - kThumb2VcvtFI, /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12] - [10101100] vm[3..0] */ - kThumb2VcvtDI, /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12] - [10111100] vm[3..0] */ - kThumb2VcvtFd, /* vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12] - [10101100] vm[3..0] */ - kThumb2VcvtDF, /* vcvt.F32.F64 vd, vm [1110111010110111] vd[15..12] - [10111100] vm[3..0] */ - kThumb2Vsqrts, /* vsqrt.f32 vd, vm [1110111010110001] vd[15..12] - [10101100] vm[3..0] */ - kThumb2Vsqrtd, /* vsqrt.f64 vd, vm [1110111010110001] vd[15..12] - [10111100] vm[3..0] */ - kThumb2MovImmShift,/* mov(T2) rd, # [11110] i [00001001111] - imm3 rd[11..8] imm8 */ - kThumb2MovImm16, /* mov(T3) rd, # [11110] i [0010100] imm4 [0] - imm3 rd[11..8] imm8 */ - kThumb2StrRRI12, /* str(Imm,T3) rd,[rn,#imm12] [111110001100] - rn[19..16] rt[15..12] imm12[11..0] */ - kThumb2LdrRRI12, /* str(Imm,T3) rd,[rn,#imm12] [111110001100] - rn[19..16] rt[15..12] imm12[11..0] */ - kThumb2StrRRI8Predec, /* str(Imm,T4) rd,[rn,#-imm8] [111110000100] - rn[19..16] rt[15..12] [1100] imm[7..0]*/ - kThumb2LdrRRI8Predec, /* ldr(Imm,T4) rd,[rn,#-imm8] [111110000101] - rn[19..16] rt[15..12] [1100] imm[7..0]*/ - kThumb2Cbnz, /* cbnz rd,