summaryrefslogtreecommitdiff
path: root/src/compiler/codegen/arm/MethodCodegenDriver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/codegen/arm/MethodCodegenDriver.cc')
-rw-r--r--src/compiler/codegen/arm/MethodCodegenDriver.cc1978
1 files changed, 0 insertions, 1978 deletions
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
deleted file mode 100644
index 4efa27ab3b..0000000000
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ /dev/null
@@ -1,1978 +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 {
-
-#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
- (1 << kDebugDisplayMissingTargets))
-
-STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
- INVALID_REG, INVALID_SREG};
-
-/* Mark register usage state and return long retloc */
-STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
-{
- RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
- oatLockTemp(cUnit, res.lowReg);
- oatLockTemp(cUnit, res.highReg);
- oatMarkPair(cUnit, res.lowReg, res.highReg);
- return res;
-}
-
-STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
-{
- RegLocation res = LOC_DALVIK_RETURN_VAL;
- oatLockTemp(cUnit, res.lowReg);
- return res;
-}
-
-/*
- * Let helper function take care of everything. Will call
- * Array::AllocFromCode(type_idx, method, count);
- * Note: AllocFromCode will handle checks for errNegativeArraySize.
- */
-STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
- RegLocation rlSrc)
-{
- oatFlushAllRegs(cUnit); /* Everything to home location */
- uint32_t type_idx = mir->dalvikInsn.vC;
- if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
- cUnit->dex_cache,
- *cUnit->dex_file,
- type_idx)) {
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
- } else {
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
- }
- loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
- loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
- loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
- callRuntimeHelper(cUnit, rLR);
- RegLocation rlResult = oatGetReturn(cUnit);
- 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'.
- */
-STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
-{
- DecodedInstruction* dInsn = &mir->dalvikInsn;
- int elems = dInsn->vA;
- int typeId = dInsn->vB;
- oatFlushAllRegs(cUnit); /* Everything to home location */
- if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
- cUnit->dex_cache,
- *cUnit->dex_file,
- typeId)) {
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
- } else {
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
- }
- loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
- loadConstant(cUnit, r0, typeId); // arg0 <- type_id
- loadConstant(cUnit, r2, elems); // arg2 <- count
- callRuntimeHelper(cUnit, rLR);
- /*
- * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
- * return region. Because AllocFromCode placed the new array
- * in r0, 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, r0);
-
- // Having a range of 0 is legal
- if (isRange && (dInsn->vA > 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 (unsigned int i = 0; i < dInsn->vA; i++) {
- RegLocation loc = oatUpdateLoc(cUnit,
- oatGetSrc(cUnit, mir, i));
- if (loc.location == kLocPhysReg) {
- storeBaseDisp(cUnit, rSP, 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 = rLR; // Using a lot of temps, rLR is known free here
- // Set up source pointer
- RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
- opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
- oatSRegOffset(cUnit, rlFirst.sRegLow));
- // Set up the target pointer
- opRegRegImm(cUnit, kOpAdd, rDst, r0,
- Array::DataOffset().Int32Value());
- // Set up the loop counter (known to be > 0)
- loadConstant(cUnit, rIdx, dInsn->vA - 1);
- // Generate the copy loop. Going backwards for convenience
- ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
- target->defMask = ENCODE_ALL;
- // Copy next element
- loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
- storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
- // Use setflags encoding here
- newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
- ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
- branch->generic.target = (LIR*)target;
- } else if (!isRange) {
- // TUNING: interleave
- for (unsigned int i = 0; i < dInsn->vA; i++) {
- RegLocation rlArg = loadValue(cUnit,
- oatGetSrc(cUnit, mir, i), kCoreReg);
- storeBaseDisp(cUnit, r0,
- Array::DataOffset().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);
- }
- }
- }
-}
-
-STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
- bool isLongOrDouble, bool isObject)
-{
- int fieldOffset;
- int ssbIndex;
- bool isVolatile;
- bool isReferrersClass;
- uint32_t fieldIdx = mir->dalvikInsn.vB;
- bool fastPath =
- cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
- fieldOffset, ssbIndex,
- isReferrersClass, isVolatile, true);
- if (fastPath && !SLOW_FIELD_PATH) {
- DCHECK_GE(fieldOffset, 0);
- int rBase;
- int rMethod;
- if (isReferrersClass) {
- // Fast path, static storage base is this method's class
- rMethod = loadCurrMethod(cUnit);
- rBase = oatAllocTemp(cUnit);
- loadWordDisp(cUnit, rMethod,
- Method::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.
- rMethod = r1;
- oatLockTemp(cUnit, rMethod);
- loadCurrMethodDirect(cUnit, rMethod);
- rBase = r0;
- oatLockTemp(cUnit, rBase);
- loadWordDisp(cUnit, rMethod,
- Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
- rBase);
- loadWordDisp(cUnit, rBase,
- Array::DataOffset().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
- ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
- loadConstant(cUnit, r0, ssbIndex);
- callRuntimeHelper(cUnit, rLR);
- ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
- skipTarget->defMask = ENCODE_ALL;
- branchOver->generic.target = (LIR*)skipTarget;
- }
- // rBase now holds static storage base
- oatFreeTemp(cUnit, rMethod);
- if (isLongOrDouble) {
- rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
- rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
- } else {
- rlSrc = oatGetSrc(cUnit, mir, 0);
- rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
- }
- 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 ? OFFSETOF_MEMBER(Thread, pSet64Static) :
- (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
- : OFFSETOF_MEMBER(Thread, pSet32Static));
- loadWordDisp(cUnit, rSELF, setterOffset, rLR);
- loadConstant(cUnit, r0, fieldIdx);
- if (isLongOrDouble) {
- loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
- } else {
- loadValueDirect(cUnit, rlSrc, r1);
- }
- callRuntimeHelper(cUnit, rLR);
- }
-}
-
-STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
- bool isLongOrDouble, bool isObject)
-{
- int fieldOffset;
- int ssbIndex;
- bool isVolatile;
- bool isReferrersClass;
- uint32_t fieldIdx = mir->dalvikInsn.vB;
- bool fastPath =
- cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
- fieldOffset, ssbIndex,
- isReferrersClass, isVolatile, false);
- if (fastPath && !SLOW_FIELD_PATH) {
- DCHECK_GE(fieldOffset, 0);
- int rBase;
- int rMethod;
- if (isReferrersClass) {
- // Fast path, static storage base is this method's class
- rMethod = loadCurrMethod(cUnit);
- rBase = oatAllocTemp(cUnit);
- loadWordDisp(cUnit, rMethod,
- Method::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
- rMethod = r1;
- oatLockTemp(cUnit, rMethod);
- loadCurrMethodDirect(cUnit, rMethod);
- rBase = r0;
- oatLockTemp(cUnit, rBase);
- loadWordDisp(cUnit, rMethod,
- Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
- rBase);
- loadWordDisp(cUnit, rBase,
- Array::DataOffset().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
- ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
- loadConstant(cUnit, r0, ssbIndex);
- callRuntimeHelper(cUnit, rLR);
- ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
- skipTarget->defMask = ENCODE_ALL;
- branchOver->generic.target = (LIR*)skipTarget;
- }
- // rBase now holds static storage base
- oatFreeTemp(cUnit, rMethod);
- rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
- : oatGetDest(cUnit, mir, 0);
- RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- if (isVolatile) {
- oatGenMemBarrier(cUnit, kSY);
- }
- if (isLongOrDouble) {
- loadBaseDispWide(cUnit, NULL, 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 ? OFFSETOF_MEMBER(Thread, pGet64Static) :
- (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
- : OFFSETOF_MEMBER(Thread, pGet32Static));
- loadWordDisp(cUnit, rSELF, getterOffset, rLR);
- loadConstant(cUnit, r0, fieldIdx);
- callRuntimeHelper(cUnit, rLR);
- if (isLongOrDouble) {
- RegLocation rlResult = oatGetReturnWide(cUnit);
- storeValueWide(cUnit, rlDest, rlResult);
- } else {
- RegLocation rlResult = oatGetReturn(cUnit);
- storeValue(cUnit, rlDest, rlResult);
- }
- }
-}
-
-typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
- uint32_t methodIdx);
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in static & direct invoke sequences.
- */
-STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t unused)
-{
- switch(state) {
- case 0: // Get the current Method* [sets r0]
- loadCurrMethodDirect(cUnit, r0);
- break;
- case 1: // Get method->code_and_direct_methods_
- loadWordDisp(cUnit, r0,
- Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
- r0);
- break;
- case 2: // Grab target method* and target code_
- loadWordDisp(cUnit, r0,
- CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
- loadWordDisp(cUnit, r0,
- CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
- break;
- default:
- return -1;
- }
- return state + 1;
-}
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in a virtual invoke sequence.
- * We can use rLR as a temp prior to target address loading
- * Note also that we'll load the first argument ("this") into
- * r1 here rather than the standard loadArgRegs.
- */
-STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- RegLocation rlArg;
- /*
- * This is the fast path in which the target virtual method is
- * fully resolved at compile time.
- */
- switch(state) {
- case 0: // Get "this" [set r1]
- rlArg = oatGetSrc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlArg, r1);
- break;
- case 1: // Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- // get this->klass_ [use r1, set rLR]
- loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
- break;
- case 2: // Get this->klass_->vtable [usr rLR, set rLR]
- loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
- break;
- case 3: // Get target method [use rLR, set r0]
- loadWordDisp(cUnit, rLR, (methodIdx * 4) +
- Array::DataOffset().Int32Value(), r0);
- break;
- case 4: // Get the target compiled code address [uses r0, sets rLR]
- loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
- break;
- default:
- return -1;
- }
- return state + 1;
-}
-
-/*
- * Interleave launch code for INVOKE_SUPER. See comments
- * for nextVCallIns.
- */
-STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- /*
- * This is the fast path in which the target virtual method is
- * fully resolved at compile time. Note also that this path assumes
- * that the check to verify that the target method index falls
- * within the size of the super's vtable has been done at compile-time.
- */
- RegLocation rlArg;
- switch(state) {
- case 0: // Get current Method* [set r0]
- loadCurrMethodDirect(cUnit, r0);
- // Load "this" [set r1]
- rlArg = oatGetSrc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlArg, r1);
- // Get method->declaring_class_ [use r0, set rLR]
- loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
- rLR);
- // Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- break;
- case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
- loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
- rLR);
- break;
- case 2: // Get ...->super_class_->vtable [u/s rLR]
- loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
- break;
- case 3: // Get target method [use rLR, set r0]
- loadWordDisp(cUnit, rLR, (methodIdx * 4) +
- Array::DataOffset().Int32Value(), r0);
- break;
- case 4: // Get the target compiled code address [uses r0, sets rLR]
- loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
- break;
- default:
- return -1;
- }
- return state + 1;
-}
-
-STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, 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) {
- // Load trampoline target
- loadWordDisp(cUnit, rSELF, trampoline, rLR);
- // Load r0 with method index
- loadConstant(cUnit, r0, dexIdx);
- return 1;
- }
- return -1;
-}
-
-STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t methodIdx)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
- int state, uint32_t dexIdx, uint32_t unused)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
- MIR* mir, int state,
- uint32_t dexIdx,
- uint32_t unused)
-{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
- return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int callState,
- NextCallInsn nextCallInsn, uint32_t dexIdx,
- uint32_t methodIdx, bool skipThis)
-{
- int nextReg = r1;
- int nextArg = 0;
- if (skipThis) {
- nextReg++;
- nextArg++;
- }
- for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
- RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
- rlArg = oatUpdateRawLoc(cUnit, rlArg);
- if (rlArg.wide && (nextReg <= r2)) {
- loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
- nextReg++;
- nextArg++;
- } else {
- rlArg.wide = false;
- loadValueDirectFixed(cUnit, rlArg, nextReg);
- }
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- }
- return callState;
-}
-
-/*
- * Load up to 5 arguments, the first three of which will be in
- * r1 .. r3. On entry r0 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.
- */
-STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int callState,
- ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
- uint32_t dexIdx, uint32_t methodIdx,
- bool skipThis)
-{
- RegLocation rlArg;
-
- /* If no arguments, just return */
- if (dInsn->vA == 0)
- return callState;
-
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-
- DCHECK_LE(dInsn->vA, 5U);
- if (dInsn->vA > 3) {
- uint32_t nextUse = 3;
- //Detect special case of wide arg spanning arg3/arg4
- RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
- RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
- RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
- if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
- rlUse2.wide) {
- int reg;
- // Wide spans, we need the 2nd half of uses[2].
- rlArg = oatUpdateLocWide(cUnit, rlUse2);
- if (rlArg.location == kLocPhysReg) {
- reg = rlArg.highReg;
- } else {
- // r2 & r3 can safely be used here
- reg = r3;
- loadWordDisp(cUnit, rSP,
- oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
- callState = nextCallInsn(cUnit, mir, callState, dexIdx,
- methodIdx);
- }
- storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
- storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- nextUse++;
- }
- // Loop through the rest
- while (nextUse < dInsn->vA) {
- int lowReg;
- int highReg;
- rlArg = oatGetRawSrc(cUnit, mir, nextUse);
- rlArg = oatUpdateRawLoc(cUnit, rlArg);
- if (rlArg.location == kLocPhysReg) {
- lowReg = rlArg.lowReg;
- highReg = rlArg.highReg;
- } else {
- lowReg = r2;
- highReg = r3;
- if (rlArg.wide) {
- loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
- } else {
- loadValueDirectFixed(cUnit, rlArg, lowReg);
- }
- callState = nextCallInsn(cUnit, mir, callState, dexIdx,
- methodIdx);
- }
- int outsOffset = (nextUse + 1) * 4;
- if (rlArg.wide) {
- storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
- nextUse += 2;
- } else {
- storeWordDisp(cUnit, rSP, outsOffset, lowReg);
- nextUse++;
- }
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- }
- }
-
- callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
- dexIdx, methodIdx, skipThis);
-
- if (pcrLabel) {
- *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- }
- 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 r1-r3
- * If 20+ arguments
- * Pass args arg19+ using memcpy block copy
- * Pass arg0, arg1 & arg2 in r1-r3
- *
- */
-STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int callState,
- ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
- uint32_t dexIdx, uint32_t methodIdx,
- bool skipThis)
-{
- int firstArg = dInsn->vC;
- int numArgs = dInsn->vA;
-
- // If we can treat it as non-range (Jumbo ops will use range form)
- if (numArgs <= 5)
- return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
- nextCallInsn, dexIdx, methodIdx,
- skipThis);
- /*
- * Make sure range list doesn't span the break between in normal
- * Dalvik vRegs and the ins.
- */
- int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
- int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
- if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
- LOG(FATAL) << "Argument list spanned locals & args";
- }
-
- /*
- * 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 < numArgs;) {
- RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
- if (loc.wide) {
- loc = oatUpdateLocWide(cUnit, loc);
- if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
- storeBaseDispWide(cUnit, rSP,
- oatSRegOffset(cUnit, loc.sRegLow),
- loc.lowReg, loc.highReg);
- }
- nextArg += 2;
- } else {
- loc = oatUpdateLoc(cUnit, loc);
- if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
- storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
- loc.lowReg, kWord);
- }
- nextArg++;
- }
- }
-
- int startOffset = oatSRegOffset(cUnit,
- cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
- int outsOffset = 4 /* Method* */ + (3 * 4);
- if (numArgs >= 20) {
- // Generate memcpy
- opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
- opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
- loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
- loadConstant(cUnit, r2, (numArgs - 3) * 4);
- callRuntimeHelper(cUnit, rLR);
- // Restore Method*
- loadCurrMethodDirect(cUnit, r0);
- } else {
- // Use vldm/vstm pair using r3 as a temp
- int regsLeft = std::min(numArgs - 3, 16);
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
- ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
- //TUNING: loosen barrier
- ld->defMask = ENCODE_ALL;
- setMemRefType(ld, true /* isLoad */, kDalvikReg);
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
- setMemRefType(st, false /* isLoad */, kDalvikReg);
- st->defMask = ENCODE_ALL;
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- }
-
- callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
- dexIdx, methodIdx, skipThis);
-
- callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
- if (pcrLabel) {
- *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- }
- return callState;
-}
-
-// Debugging routine - if null target, branch to DebugMe
-STATIC void genShowTarget(CompilationUnit* cUnit)
-{
- ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
- ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
- target->defMask = -1;
- branchOver->generic.target = (LIR*)target;
-}
-
-STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
- InvokeType type, bool isRange)
-{
- DecodedInstruction* dInsn = &mir->dalvikInsn;
- int callState = 0;
- ArmLIR* nullCk;
- ArmLIR** pNullCk = NULL;
- NextCallInsn nextCallInsn;
- oatFlushAllRegs(cUnit); /* Everything to home location */
- // Explicit register usage
- oatLockCallTemps(cUnit);
-
- uint32_t dexMethodIdx = dInsn->vB;
- int vtableIdx;
- bool skipThis;
- bool fastPath =
- cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
- vtableIdx)
- && !SLOW_INVOKE_PATH;
- if (type == kInterface) {
- nextCallInsn = fastPath ? nextInterfaceCallInsn
- : nextInterfaceCallInsnWithAccessCheck;
- skipThis = false;
- } else if (type == kDirect) {
- if (fastPath) {
- pNullCk = &nullCk;
- }
- nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
- skipThis = false;
- } else if (type == kStatic) {
- nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
- skipThis = false;
- } else if (type == kSuper) {
- nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
- skipThis = fastPath;
- } else {
- DCHECK_EQ(type, kVirtual);
- nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
- skipThis = fastPath;
- }
- if (!isRange) {
- callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
- nextCallInsn, dexMethodIdx,
- vtableIdx, skipThis);
- } else {
- callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
- nextCallInsn, dexMethodIdx, vtableIdx,
- skipThis);
- }
- // Finish up any of the call sequence not interleaved in arg loading
- while (callState >= 0) {
- callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
- vtableIdx);
- }
- if (DISPLAY_MISSING_TARGETS) {
- genShowTarget(cUnit);
- }
- opReg(cUnit, kOpBlx, rLR);
- oatClobberCalleeSave(cUnit);
-}
-
-STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
- BasicBlock* bb, ArmLIR* labelList)
-{
- bool res = false; // Assume success
- RegLocation rlSrc[3];
- RegLocation rlDest = badLoc;
- RegLocation rlResult = badLoc;
- Opcode opcode = mir->dalvikInsn.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) {
- rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
- nextSreg++;
- } else if (attrs & DF_UA_WIDE) {
- rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
- nextSreg + 1);
- nextSreg+= 2;
- }
- if (attrs & DF_UB) {
- rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
- nextSreg++;
- } else if (attrs & DF_UB_WIDE) {
- rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
- nextSreg + 1);
- nextSreg+= 2;
- }
- if (attrs & DF_UC) {
- rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
- } else if (attrs & DF_UC_WIDE) {
- rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
- nextSreg + 1);
- }
- if (attrs & DF_DA) {
- rlDest = oatGetDest(cUnit, mir, 0);
- } else if (attrs & DF_DA_WIDE) {
- rlDest = oatGetDestWide(cUnit, mir, 0, 1);
- }
-
- switch(opcode) {
- case OP_NOP:
- break;
-
- case OP_MOVE_EXCEPTION:
- int exOffset;
- int resetReg;
- exOffset = Thread::ExceptionOffset().Int32Value();
- resetReg = oatAllocTemp(cUnit);
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
- loadConstant(cUnit, resetReg, 0);
- storeWordDisp(cUnit, rSELF, exOffset, resetReg);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_RETURN_VOID:
- genSuspendTest(cUnit, mir);
- break;
-
- case OP_RETURN:
- case OP_RETURN_OBJECT:
- genSuspendTest(cUnit, mir);
- storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
- break;
-
- case OP_RETURN_WIDE:
- genSuspendTest(cUnit, mir);
- storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
- break;
-
- case OP_MOVE_RESULT_WIDE:
- if (mir->optimizationFlags & MIR_INLINED)
- break; // Nop - combined w/ previous invoke
- storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
- break;
-
- case OP_MOVE_RESULT:
- case OP_MOVE_RESULT_OBJECT:
- if (mir->optimizationFlags & MIR_INLINED)
- break; // Nop - combined w/ previous invoke
- storeValue(cUnit, rlDest, getRetLoc(cUnit));
- break;
-
- case OP_MOVE:
- case OP_MOVE_OBJECT:
- case OP_MOVE_16:
- case OP_MOVE_OBJECT_16:
- case OP_MOVE_FROM16:
- case OP_MOVE_OBJECT_FROM16:
- storeValue(cUnit, rlDest, rlSrc[0]);
- break;
-
- case OP_MOVE_WIDE:
- case OP_MOVE_WIDE_16:
- case OP_MOVE_WIDE_FROM16:
- storeValueWide(cUnit, rlDest, rlSrc[0]);
- break;
-
- case OP_CONST:
- case OP_CONST_4:
- case OP_CONST_16:
- rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_CONST_HIGH16:
- rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantNoClobber(cUnit, rlResult.lowReg,
- mir->dalvikInsn.vB << 16);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_CONST_WIDE_16:
- case OP_CONST_WIDE_32:
- rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
- mir->dalvikInsn.vB,
- (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
- storeValueWide(cUnit, rlDest, rlResult);
- break;
-
- case OP_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 OP_CONST_WIDE_HIGH16:
- rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
- 0, mir->dalvikInsn.vB << 16);
- storeValueWide(cUnit, rlDest, rlResult);
- break;
-
- case OP_MONITOR_ENTER:
- genMonitorEnter(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_MONITOR_EXIT:
- genMonitorExit(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_CHECK_CAST:
- genCheckCast(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_INSTANCE_OF:
- genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
- case OP_NEW_INSTANCE:
- genNewInstance(cUnit, mir, rlDest);
- break;
-
- case OP_THROW:
- genThrow(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_THROW_VERIFICATION_ERROR:
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
- loadConstant(cUnit, r0, mir->dalvikInsn.vA);
- loadConstant(cUnit, r1, mir->dalvikInsn.vB);
- callRuntimeHelper(cUnit, rLR);
- break;
-
- case OP_ARRAY_LENGTH:
- int lenOffset;
- lenOffset = Array::LengthOffset().Int32Value();
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
- rlResult.lowReg);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_CONST_STRING:
- case OP_CONST_STRING_JUMBO:
- genConstString(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
- case OP_CONST_CLASS:
- genConstClass(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
- case OP_FILL_ARRAY_DATA:
- genFillArrayData(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_FILLED_NEW_ARRAY:
- genFilledNewArray(cUnit, mir, false /* not range */);
- break;
-
- case OP_FILLED_NEW_ARRAY_RANGE:
- genFilledNewArray(cUnit, mir, true /* range */);
- break;
-
- case OP_NEW_ARRAY:
- genNewArray(cUnit, mir, rlDest, rlSrc[0]);
- break;
-
- case OP_GOTO:
- case OP_GOTO_16:
- case OP_GOTO_32:
- if (bb->taken->startOffset <= mir->offset) {
- genSuspendTest(cUnit, mir);
- }
- genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
- break;
-
- case OP_PACKED_SWITCH:
- genPackedSwitch(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_SPARSE_SWITCH:
- genSparseSwitch(cUnit, mir, rlSrc[0]);
- break;
-
- case OP_CMPL_FLOAT:
- case OP_CMPG_FLOAT:
- case OP_CMPL_DOUBLE:
- case OP_CMPG_DOUBLE:
- res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_CMP_LONG:
- genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_IF_EQ:
- case OP_IF_NE:
- case OP_IF_LT:
- case OP_IF_GE:
- case OP_IF_GT:
- case OP_IF_LE: {
- bool backwardBranch;
- ArmConditionCode cond;
- backwardBranch = (bb->taken->startOffset <= mir->offset);
- if (backwardBranch) {
- genSuspendTest(cUnit, mir);
- }
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
- opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
- switch(opcode) {
- case OP_IF_EQ:
- cond = kArmCondEq;
- break;
- case OP_IF_NE:
- cond = kArmCondNe;
- break;
- case OP_IF_LT:
- cond = kArmCondLt;
- break;
- case OP_IF_GE:
- cond = kArmCondGe;
- break;
- case OP_IF_GT:
- cond = kArmCondGt;
- break;
- case OP_IF_LE:
- cond = kArmCondLe;
- break;
- default:
- cond = (ArmConditionCode)0;
- LOG(FATAL) << "Unexpected opcode " << (int)opcode;
- }
- genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
- genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
- break;
- }
-
- case OP_IF_EQZ:
- case OP_IF_NEZ:
- case OP_IF_LTZ:
- case OP_IF_GEZ:
- case OP_IF_GTZ:
- case OP_IF_LEZ: {
- bool backwardBranch;
- ArmConditionCode cond;
- backwardBranch = (bb->taken->startOffset <= mir->offset);
- if (backwardBranch) {
- genSuspendTest(cUnit, mir);
- }
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
- switch(opcode) {
- case OP_IF_EQZ:
- cond = kArmCondEq;
- break;
- case OP_IF_NEZ:
- cond = kArmCondNe;
- break;
- case OP_IF_LTZ:
- cond = kArmCondLt;
- break;
- case OP_IF_GEZ:
- cond = kArmCondGe;
- break;
- case OP_IF_GTZ:
- cond = kArmCondGt;
- break;
- case OP_IF_LEZ:
- cond = kArmCondLe;
- break;
- default:
- cond = (ArmConditionCode)0;
- LOG(FATAL) << "Unexpected opcode " << (int)opcode;
- }
- genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
- genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
- break;
- }
-
- case OP_AGET_WIDE:
- genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
- break;
- case OP_AGET:
- case OP_AGET_OBJECT:
- genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
- break;
- case OP_AGET_BOOLEAN:
- genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
- rlDest, 0);
- break;
- case OP_AGET_BYTE:
- genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
- break;
- case OP_AGET_CHAR:
- genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
- rlDest, 1);
- break;
- case OP_AGET_SHORT:
- genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
- break;
- case OP_APUT_WIDE:
- genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
- break;
- case OP_APUT:
- genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
- break;
- case OP_APUT_OBJECT:
- genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
- break;
- case OP_APUT_SHORT:
- case OP_APUT_CHAR:
- genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
- rlSrc[0], 1);
- break;
- case OP_APUT_BYTE:
- case OP_APUT_BOOLEAN:
- genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
- rlSrc[0], 0);
- break;
-
- case OP_IGET_OBJECT:
- case OP_IGET_OBJECT_VOLATILE:
- genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
- break;
-
- case OP_IGET_WIDE:
- case OP_IGET_WIDE_VOLATILE:
- genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
- break;
-
- case OP_IGET:
- case OP_IGET_VOLATILE:
- genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
- break;
-
- case OP_IGET_CHAR:
- genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
- break;
-
- case OP_IGET_SHORT:
- genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
- break;
-
- case OP_IGET_BOOLEAN:
- case OP_IGET_BYTE:
- genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
- break;
-
- case OP_IPUT_WIDE:
- case OP_IPUT_WIDE_VOLATILE:
- genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
- break;
-
- case OP_IPUT_OBJECT:
- case OP_IPUT_OBJECT_VOLATILE:
- genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
- break;
-
- case OP_IPUT:
- case OP_IPUT_VOLATILE:
- genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case OP_IPUT_BOOLEAN:
- case OP_IPUT_BYTE:
- genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case OP_IPUT_CHAR:
- genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case OP_IPUT_SHORT:
- genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
- break;
-
- case OP_SGET_OBJECT:
- genSget(cUnit, mir, rlDest, false, true);
- break;
- case OP_SGET:
- case OP_SGET_BOOLEAN:
- case OP_SGET_BYTE:
- case OP_SGET_CHAR:
- case OP_SGET_SHORT:
- genSget(cUnit, mir, rlDest, false, false);
- break;
-
- case OP_SGET_WIDE:
- genSget(cUnit, mir, rlDest, true, false);
- break;
-
- case OP_SPUT_OBJECT:
- genSput(cUnit, mir, rlSrc[0], false, true);
- break;
-
- case OP_SPUT:
- case OP_SPUT_BOOLEAN:
- case OP_SPUT_BYTE:
- case OP_SPUT_CHAR:
- case OP_SPUT_SHORT:
- genSput(cUnit, mir, rlSrc[0], false, false);
- break;
-
- case OP_SPUT_WIDE:
- genSput(cUnit, mir, rlSrc[0], true, false);
- break;
-
- case OP_INVOKE_STATIC_RANGE:
- genInvoke(cUnit, mir, kStatic, true /*range*/);
- break;
- case OP_INVOKE_STATIC:
- genInvoke(cUnit, mir, kStatic, false /*range*/);
- break;
-
- case OP_INVOKE_DIRECT:
- genInvoke(cUnit, mir, kDirect, false /*range*/);
- break;
- case OP_INVOKE_DIRECT_RANGE:
- genInvoke(cUnit, mir, kDirect, true /*range*/);
- break;
-
- case OP_INVOKE_VIRTUAL:
- genInvoke(cUnit, mir, kVirtual, false /*range*/);
- break;
- case OP_INVOKE_VIRTUAL_RANGE:
- genInvoke(cUnit, mir, kVirtual, true /*range*/);
- break;
-
- case OP_INVOKE_SUPER:
- genInvoke(cUnit, mir, kSuper, false /*range*/);
- break;
- case OP_INVOKE_SUPER_RANGE:
- genInvoke(cUnit, mir, kSuper, true /*range*/);
- break;
-
- case OP_INVOKE_INTERFACE:
- genInvoke(cUnit, mir, kInterface, false /*range*/);
- break;
- case OP_INVOKE_INTERFACE_RANGE:
- genInvoke(cUnit, mir, kInterface, true /*range*/);
- break;
-
- case OP_NEG_INT:
- case OP_NOT_INT:
- res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
- break;
-
- case OP_NEG_LONG:
- case OP_NOT_LONG:
- res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
- break;
-
- case OP_NEG_FLOAT:
- res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
- break;
-
- case OP_NEG_DOUBLE:
- res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
- break;
-
- case OP_INT_TO_LONG:
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- if (rlSrc[0].location == kLocPhysReg) {
- genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
- } else {
- loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
- }
- opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
- rlResult.lowReg, 31);
- storeValueWide(cUnit, rlDest, rlResult);
- break;
-
- case OP_LONG_TO_INT:
- rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
- rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
- storeValue(cUnit, rlDest, rlSrc[0]);
- break;
-
- case OP_INT_TO_BYTE:
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_INT_TO_SHORT:
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_INT_TO_CHAR:
- rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
- storeValue(cUnit, rlDest, rlResult);
- break;
-
- case OP_INT_TO_FLOAT:
- case OP_INT_TO_DOUBLE:
- case OP_LONG_TO_FLOAT:
- case OP_LONG_TO_DOUBLE:
- case OP_FLOAT_TO_INT:
- case OP_FLOAT_TO_LONG:
- case OP_FLOAT_TO_DOUBLE:
- case OP_DOUBLE_TO_INT:
- case OP_DOUBLE_TO_LONG:
- case OP_DOUBLE_TO_FLOAT:
- genConversion(cUnit, mir);
- break;
-
- case OP_ADD_INT:
- case OP_SUB_INT:
- case OP_MUL_INT:
- case OP_DIV_INT:
- case OP_REM_INT:
- case OP_AND_INT:
- case OP_OR_INT:
- case OP_XOR_INT:
- case OP_SHL_INT:
- case OP_SHR_INT:
- case OP_USHR_INT:
- case OP_ADD_INT_2ADDR:
- case OP_SUB_INT_2ADDR:
- case OP_MUL_INT_2ADDR:
- case OP_DIV_INT_2ADDR:
- case OP_REM_INT_2ADDR:
- case OP_AND_INT_2ADDR:
- case OP_OR_INT_2ADDR:
- case OP_XOR_INT_2ADDR:
- case OP_SHL_INT_2ADDR:
- case OP_SHR_INT_2ADDR:
- case OP_USHR_INT_2ADDR:
- genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_ADD_LONG:
- case OP_SUB_LONG:
- case OP_MUL_LONG:
- case OP_DIV_LONG:
- case OP_REM_LONG:
- case OP_AND_LONG:
- case OP_OR_LONG:
- case OP_XOR_LONG:
- case OP_ADD_LONG_2ADDR:
- case OP_SUB_LONG_2ADDR:
- case OP_MUL_LONG_2ADDR:
- case OP_DIV_LONG_2ADDR:
- case OP_REM_LONG_2ADDR:
- case OP_AND_LONG_2ADDR:
- case OP_OR_LONG_2ADDR:
- case OP_XOR_LONG_2ADDR:
- genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_SHL_LONG:
- case OP_SHR_LONG:
- case OP_USHR_LONG:
- case OP_SHL_LONG_2ADDR:
- case OP_SHR_LONG_2ADDR:
- case OP_USHR_LONG_2ADDR:
- genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_ADD_FLOAT:
- case OP_SUB_FLOAT:
- case OP_MUL_FLOAT:
- case OP_DIV_FLOAT:
- case OP_REM_FLOAT:
- case OP_ADD_FLOAT_2ADDR:
- case OP_SUB_FLOAT_2ADDR:
- case OP_MUL_FLOAT_2ADDR:
- case OP_DIV_FLOAT_2ADDR:
- case OP_REM_FLOAT_2ADDR:
- genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_ADD_DOUBLE:
- case OP_SUB_DOUBLE:
- case OP_MUL_DOUBLE:
- case OP_DIV_DOUBLE:
- case OP_REM_DOUBLE:
- case OP_ADD_DOUBLE_2ADDR:
- case OP_SUB_DOUBLE_2ADDR:
- case OP_MUL_DOUBLE_2ADDR:
- case OP_DIV_DOUBLE_2ADDR:
- case OP_REM_DOUBLE_2ADDR:
- genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
- break;
-
- case OP_RSUB_INT:
- case OP_ADD_INT_LIT16:
- case OP_MUL_INT_LIT16:
- case OP_DIV_INT_LIT16:
- case OP_REM_INT_LIT16:
- case OP_AND_INT_LIT16:
- case OP_OR_INT_LIT16:
- case OP_XOR_INT_LIT16:
- case OP_ADD_INT_LIT8:
- case OP_RSUB_INT_LIT8:
- case OP_MUL_INT_LIT8:
- case OP_DIV_INT_LIT8:
- case OP_REM_INT_LIT8:
- case OP_AND_INT_LIT8:
- case OP_OR_INT_LIT8:
- case OP_XOR_INT_LIT8:
- case OP_SHL_INT_LIT8:
- case OP_SHR_INT_LIT8:
- case OP_USHR_INT_LIT8:
- genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
- break;
-
- default:
- res = true;
- }
- return res;
-}
-
-STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
- "kMirOpPhi",
- "kMirOpNullNRangeUpCheck",
- "kMirOpNullNRangeDownCheck",
- "kMirOpLowerBound",
- "kMirOpPunt",
- "kMirOpCheckInlinePrediction",
-};
-
-/* Extended MIR instructions like PHI */
-STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, 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]);
- }
- ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (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, kArmPseudoSSARep, (int) ssaString);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * 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.
- */
-STATIC void flushIns(CompilationUnit* cUnit)
-{
- if (cUnit->numIns == 0)
- return;
- int firstArgReg = r1;
- int lastArgReg = r3;
- int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
- /*
- * Arguments passed in registers should be flushed
- * to their backing locations in the frame for now.
- * Also, we need to do initial assignment for promoted
- * arguments. 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. In those
- * cases, copy argument to both. This will be uncommon
- * enough that it isn't worth attempting to optimize.
- */
- for (int i = 0; i < cUnit->numIns; i++) {
- PromotionMap vMap = cUnit->promotionMap[startVReg + i];
- if (i <= (lastArgReg - firstArgReg)) {
- // If arriving in register
- if (vMap.coreLocation == kLocPhysReg) {
- genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
- }
- if (vMap.fpLocation == kLocPhysReg) {
- genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
- }
- // Also put a copy in memory in case we're partially promoted
- storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
- firstArgReg + i, kWord);
- } else {
- // If arriving in frame & promoted
- if (vMap.coreLocation == kLocPhysReg) {
- loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
- vMap.coreReg);
- }
- if (vMap.fpLocation == kLocPhysReg) {
- loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
- vMap.fpReg);
- }
- }
- }
-}
-
-/* Handle the content in each basic block */
-STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
-{
- MIR* mir;
- ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
- int blockId = bb->id;
-
- cUnit->curBlock = bb;
- labelList[blockId].operands[0] = bb->startOffset;
-
- /* Insert the block label */
- labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
- oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
-
- /* Reset local optimization data on block boundaries */
- oatResetRegPool(cUnit);
- oatClobberAllRegs(cUnit);
- oatResetDefTracking(cUnit);
-
- ArmLIR* headLIR = NULL;
-
- int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
- if (bb->blockType == kEntryBlock) {
- /*
- * 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, kArmPseudoMethodEntry);
- if (!skipOverflowCheck) {
- /* Load stack limit */
- loadWordDisp(cUnit, rSELF,
- 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, rLR, rSP,
- cUnit->frameSize - (spillCount * 4));
- genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
- kArmThrowStackOverflow);
- genRegCopy(cUnit, rSP, rLR); // Establish stack
- } else {
- opRegImm(cUnit, kOpSub, rSP,
- cUnit->frameSize - (spillCount * 4));
- }
- storeBaseDisp(cUnit, rSP, 0, r0, kWord);
- flushIns(cUnit);
-
- if (cUnit->genDebugger) {
- // Refresh update debugger callout
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
- genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
- }
-
- oatFreeTemp(cUnit, r0);
- oatFreeTemp(cUnit, r1);
- oatFreeTemp(cUnit, r2);
- oatFreeTemp(cUnit, r3);
- } else if (bb->blockType == kExitBlock) {
- /*
- * 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, kArmPseudoMethodExit);
- /* If we're compiling for the debugger, generate an update callout */
- if (cUnit->genDebugger) {
- genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
- }
- opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
- /* Need to restore any FP callee saves? */
- if (cUnit->numFPSpills) {
- newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
- }
- if (cUnit->coreSpillMask & (1 << rLR)) {
- /* Unspill rLR to rPC */
- cUnit->coreSpillMask &= ~(1 << rLR);
- cUnit->coreSpillMask |= (1 << rPC);
- }
- newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
- if (!(cUnit->coreSpillMask & (1 << rPC))) {
- /* We didn't pop to rPC, so must do a bv rLR */
- newLIR1(cUnit, kThumbBx, rLR);
- }
- }
-
- for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-
- oatResetRegPool(cUnit);
- if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
- oatClobberAllRegs(cUnit);
- }
-
- if (cUnit->disableOpt & (1 << kSuppressLoads)) {
- oatResetDefTracking(cUnit);
- }
-
- if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
- handleExtendedMethodMIR(cUnit, mir);
- continue;
- }
-
- cUnit->currentDalvikOffset = mir->offset;
-
- Opcode dalvikOpcode = mir->dalvikInsn.opcode;
- InstructionFormat dalvikFormat =
- dexGetFormatFromOpcode(dalvikOpcode);
-
- ArmLIR* boundaryLIR;
-
- /* Mark the beginning of a Dalvik instruction for line tracking */
- char* instStr = cUnit->printMe ?
- oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
- boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
- (intptr_t) instStr);
- cUnit->boundaryMap.insert(std::make_pair(mir->offset,
- (LIR*)boundaryLIR));
- /* Remember the first LIR for this block */
- if (headLIR == NULL) {
- headLIR = boundaryLIR;
- /* Set the first boundaryLIR as a scheduling barrier */
- headLIR->defMask = ENCODE_ALL;
- }
-
- /* If we're compiling for the debugger, generate an update callout */
- if (cUnit->genDebugger) {
- genDebuggerUpdate(cUnit, mir->offset);
- }
-
- /* Don't generate the SSA annotation unless verbose mode is on */
- if (cUnit->printMe && mir->ssaRep) {
- char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
- newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
- }
-
- bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
-
- if (notHandled) {
- char buf[100];
- snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
- mir->offset,
- dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
- dalvikFormat);
- LOG(FATAL) << buf;
- }
- }
-
- 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) {
- genUnconditionalBranch(cUnit,
- &labelList[bb->fallThrough->id]);
- }
- }
- return false;
-}
-
-/*
- * 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)
-{
- ArmLIR* thisLIR;
-
- for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
- thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
- thisLIR = NEXT_LIR(thisLIR)) {
-
- /* Branch to the next instruction */
- if ((thisLIR->opcode == kThumbBUncond) ||
- (thisLIR->opcode == kThumb2BUncond)) {
- ArmLIR* nextLIR = thisLIR;
-
- while (true) {
- nextLIR = NEXT_LIR(nextLIR);
-
- /*
- * Is the branch target the next instruction?
- */
- if (nextLIR == (ArmLIR*) thisLIR->generic.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 = (ArmLIR*) cUnit->lastLIRInsn))
- break;
- }
- }
- }
-}
-
-STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
-{
- ArmLIR** suspendLabel =
- (ArmLIR **) cUnit->suspendLaunchpads.elemList;
- int numElems = cUnit->suspendLaunchpads.numUsed;
-
- for (int i = 0; i < numElems; i++) {
- /* TUNING: move suspend count load into helper */
- ArmLIR* lab = suspendLabel[i];
- ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
- cUnit->currentDalvikOffset = lab->operands[1];
- oatAppendLIR(cUnit, (LIR *)lab);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
- if (!cUnit->genDebugger) {
- // use rSUSPEND for suspend count
- loadWordDisp(cUnit, rSELF,
- Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
- }
- opReg(cUnit, kOpBlx, rLR);
- if ( cUnit->genDebugger) {
- // use rSUSPEND for update debugger
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
- }
- genUnconditionalBranch(cUnit, resumeLab);
- }
-}
-
-STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
-{
- ArmLIR** throwLabel =
- (ArmLIR **) cUnit->throwLaunchpads.elemList;
- int numElems = cUnit->throwLaunchpads.numUsed;
- int i;
-
- for (i = 0; i < numElems; i++) {
- ArmLIR* lab = throwLabel[i];
- cUnit->currentDalvikOffset = lab->operands[1];
- oatAppendLIR(cUnit, (LIR *)lab);
- int funcOffset = 0;
- int v1 = lab->operands[2];
- int v2 = lab->operands[3];
- switch(lab->operands[0]) {
- case kArmThrowNullPointer:
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
- break;
- case kArmThrowArrayBounds:
- if (v2 != r0) {
- genRegCopy(cUnit, r0, v1);
- genRegCopy(cUnit, r1, v2);
- } else {
- if (v1 == r1) {
- genRegCopy(cUnit, r12, v1);
- genRegCopy(cUnit, r1, v2);
- genRegCopy(cUnit, r0, r12);
- } else {
- genRegCopy(cUnit, r1, v2);
- genRegCopy(cUnit, r0, v1);
- }
- }
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
- break;
- case kArmThrowDivZero:
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
- break;
- case kArmThrowVerificationError:
- loadConstant(cUnit, r0, v1);
- loadConstant(cUnit, r1, v2);
- funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
- break;
- case kArmThrowNegArraySize:
- genRegCopy(cUnit, r0, v1);
- funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
- break;
- case kArmThrowNoSuchMethod:
- genRegCopy(cUnit, r0, v1);
- funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
- break;
- case kArmThrowStackOverflow:
- funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
- // Restore stack alignment
- opRegImm(cUnit, kOpAdd, rSP,
- (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
- break;
- default:
- LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
- }
- loadWordDisp(cUnit, rSELF, funcOffset, rLR);
- callRuntimeHelper(cUnit, rLR);
- }
-}
-
-void oatMethodMIR2LIR(CompilationUnit* cUnit)
-{
- /* Used to hold the labels of each block */
- cUnit->blockLabelList =
- (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
- kAllocLIR);
-
- oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
- kPreOrderDFSTraversal, false /* Iterative */);
- handleSuspendLaunchpads(cUnit);
-
- handleThrowLaunchpads(cUnit);
-
- removeRedundantBranches(cUnit);
-}
-
-/* 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();
-}
-
-/* Needed by the Assembler */
-void oatSetupResourceMasks(ArmLIR* lir)
-{
- setupResourceMasks(lir);
-}
-
-/* Needed by the ld/st optmizatons */
-ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
-{
- return genRegCopyNoInsert(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
-{
- return genRegCopy(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
- int srcLo, int srcHi)
-{
- genRegCopyWide(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