/*
 * Similar to loadValueDirect, but clobbers and allocates the target
 * registers.  Should be used when loading to a fixed registers (for example,
 * loading arguments to an out of line call.
 */
static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
                                     int regLo, int regHi)
{
    dvmCompilerClobber(cUnit, regLo);
    dvmCompilerClobber(cUnit, regHi);
    dvmCompilerMarkInUse(cUnit, regLo);
    dvmCompilerMarkInUse(cUnit, regHi);
    loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
}
Example #2
0
extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
{
    RegLocation res = LOC_C_RETURN_WIDE;
    dvmCompilerClobber(cUnit, r0);
    dvmCompilerClobber(cUnit, r1);
    dvmCompilerMarkInUse(cUnit, r0);
    dvmCompilerMarkInUse(cUnit, r1);
    dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
    return res;
}
Example #3
0
/* Clobber all of the temps that might be used by a handler. */
extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
{
    //TUNING: reduce the set of regs used by handlers.  Only a few need lots.
    dvmCompilerClobberCallRegs(cUnit);
    dvmCompilerClobber(cUnit, r4PC);
    dvmCompilerClobber(cUnit, r7);
    dvmCompilerClobber(cUnit, r8);
    dvmCompilerClobber(cUnit, r9);
    dvmCompilerClobber(cUnit, r10);
}
static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
                       RegLocation rlSrc)
{
    LIR *defStart;
    LIR *defEnd;
    assert(!rlDest.wide);
    assert(!rlSrc.wide);
    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    if (rlSrc.location == kLocPhysReg) {
        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
            (rlDest.location == kLocPhysReg)) {
            // Src is live or Dest has assigned reg.
            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
            genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
        } else {
            // Just re-assign the registers.  Dest gets Src's regs
            rlDest.lowReg = rlSrc.lowReg;
            dvmCompilerClobber(cUnit, rlSrc.lowReg);
        }
    } else {
        // Load Src either into promoted Dest or temps allocated for Dest
        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
        loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
    }

    // Dest is now live and dirty (until/if we flush it to home location)
    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);


    if (rlDest.location == kLocRetval) {
        storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
                      rlDest.lowReg, kWord);
        dvmCompilerClobber(cUnit, rlDest.lowReg);
    } else {
        dvmCompilerResetDefLoc(cUnit, rlDest);
        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
            defStart = (LIR *)cUnit->lastLIRInsn;
            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
            storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
            defEnd = (LIR *)cUnit->lastLIRInsn;
            dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
        }
    }
}
Example #5
0
/*
 * Load a class pointer value into a fixed or temp register.  Target
 * register is clobbered, and marked inUse.
 */
static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
{
    ArmLIR *res;
    cUnit->hasClassLiterals = true;
    if (dvmCompilerIsTemp(cUnit, rDest)) {
        dvmCompilerClobber(cUnit, rDest);
        dvmCompilerMarkInUse(cUnit, rDest);
    }
    ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0);
    if (dataTarget == NULL) {
        dataTarget = addWordData(cUnit, &cUnit->classPointerList, value);
        /* Counts the number of class pointers in this translation */
        cUnit->numClassPointers++;
    }
    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
    loadPcRel->opcode = kThumbLdrPcRel;
    loadPcRel->generic.target = (LIR *) dataTarget;
    loadPcRel->operands[0] = rDest;
    setupResourceMasks(loadPcRel);
    setMemRefType(loadPcRel, true, kLiteral);
    loadPcRel->aliasInfo = dataTarget->operands[0];
    res = loadPcRel;
    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
    return res;
}
Example #6
0
extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
{
    RegLocation res = LOC_C_RETURN;
    dvmCompilerClobber(cUnit, r0);
    dvmCompilerMarkInUse(cUnit, r0);
    return res;
}
Example #7
0
/*
 * Load an immediate value into a fixed or temp register.  Target
 * register is clobbered, and marked inUse.
 */
static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
{
    if (dvmCompilerIsTemp(cUnit, rDest)) {
        dvmCompilerClobber(cUnit, rDest);
        dvmCompilerMarkInUse(cUnit, rDest);
    }
    return loadConstantNoClobber(cUnit, rDest, value);
}
Example #8
0
extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
{
    RegLocation res = LOC_C_RETURN;
    res.lowReg = r1;
    dvmCompilerClobber(cUnit, r1);
    dvmCompilerMarkInUse(cUnit, r1);
    return res;
}
Example #9
0
/* Clobber all regs that might be used by an external C call */
extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
{
    dvmCompilerClobber(cUnit, r0);
    dvmCompilerClobber(cUnit, r1);
    dvmCompilerClobber(cUnit, r2);
    dvmCompilerClobber(cUnit, r3);
    dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative
    dvmCompilerClobber(cUnit, r11);
    dvmCompilerClobber(cUnit, r12);
    dvmCompilerClobber(cUnit, r14lr);
}
Example #10
0
static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
                         OpKind secondOp, RegLocation rlDest,
                         RegLocation rlSrc1, RegLocation rlSrc2)
{
    RegLocation rlResult;
    if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
        partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
        partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
        // Rare case - not enough registers to properly handle
        genInterpSingleStep(cUnit, mir);
    } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
        // Already 2-operand
        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
        storeValueWide(cUnit, rlDest, rlResult);
    } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
        // Bad case - must use/clobber Src1 and reassign Dest
        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
        opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
        opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
        // Old reg assignments are now invalid
        dvmCompilerClobber(cUnit, rlResult.lowReg);
        dvmCompilerClobber(cUnit, rlResult.highReg);
        dvmCompilerClobber(cUnit, rlSrc1.lowReg);
        dvmCompilerClobber(cUnit, rlSrc1.highReg);
        rlDest.location = kLocDalvikFrame;
        assert(rlSrc1.location == kLocPhysReg);
        // Reassign registers - rlDest will now get rlSrc1's old regs
        storeValueWide(cUnit, rlDest, rlSrc1);
    } else {
        // Copy Src1 to Dest
        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, false);
        loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
                            rlResult.highReg);
        rlResult.location = kLocPhysReg;
        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
        storeValueWide(cUnit, rlDest, rlResult);
    }
}
Example #11
0
static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
                             RegLocation rlDest, RegLocation rlSrc1,
                             RegLocation rlSrc2)
{
    TemplateOpCode opCode;

    switch (mir->dalvikInsn.opCode) {
        case OP_ADD_DOUBLE_2ADDR:
        case OP_ADD_DOUBLE:
            opCode = TEMPLATE_ADD_DOUBLE_VFP;
            break;
        case OP_SUB_DOUBLE_2ADDR:
        case OP_SUB_DOUBLE:
            opCode = TEMPLATE_SUB_DOUBLE_VFP;
            break;
        case OP_DIV_DOUBLE_2ADDR:
        case OP_DIV_DOUBLE:
            opCode = TEMPLATE_DIV_DOUBLE_VFP;
            break;
        case OP_MUL_DOUBLE_2ADDR:
        case OP_MUL_DOUBLE:
            opCode = TEMPLATE_MUL_DOUBLE_VFP;
            break;
        case OP_REM_DOUBLE_2ADDR:
        case OP_REM_DOUBLE:
        case OP_NEG_DOUBLE: {
            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
                                               rlSrc2);
        }
        default:
            return true;
    }
    loadValueAddressDirect(cUnit, rlDest, r0);
    loadValueAddressDirect(cUnit, rlSrc1, r1);
    loadValueAddressDirect(cUnit, rlSrc2, r2);
    genDispatchToHandler(cUnit, opCode);
    rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
    if (rlDest.location == kLocPhysReg) {
        dvmCompilerClobber(cUnit, rlDest.lowReg);
        dvmCompilerClobber(cUnit, rlDest.highReg);
    }
    return false;
}
static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
                                 RegisterClass opKind)
{
    assert(rlSrc.wide);
    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    if (rlSrc.location == kLocDalvikFrame) {
        loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
        rlSrc.location = kLocPhysReg;
        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
        dvmCompilerMarkLive(cUnit, rlSrc.highReg,
                            dvmCompilerSRegHi(rlSrc.sRegLow));
    } else if (rlSrc.location == kLocRetval) {
        loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
                         rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
        rlSrc.location = kLocPhysReg;
        dvmCompilerClobber(cUnit, rlSrc.lowReg);
        dvmCompilerClobber(cUnit, rlSrc.highReg);
    }
    return rlSrc;
}
Example #13
0
static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
{
    int offset = offsetof(InterpState, retval);
    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
    int signMask = dvmCompilerAllocTemp(cUnit);
    loadConstant(cUnit, signMask, 0x7fffffff);
    newLIR2(cUnit, kThumbAndRR, reg0, signMask);
    dvmCompilerFreeTemp(cUnit, signMask);
    storeWordDisp(cUnit, rGLUE, offset, reg0);
    //TUNING: rewrite this to not clobber
    dvmCompilerClobber(cUnit, reg0);
    return true;
}
static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
                             RegisterClass opKind)
{
    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    if (rlSrc.location == kLocDalvikFrame) {
        loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
        rlSrc.location = kLocPhysReg;
        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
    } else if (rlSrc.location == kLocRetval) {
        loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
        rlSrc.location = kLocPhysReg;
        dvmCompilerClobber(cUnit, rlSrc.lowReg);
    }
    return rlSrc;
}
Example #15
0
static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
{
    int offset = offsetof(Thread, interpSave.retval);
    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
    int reglo = regSrc.lowReg;
    int reghi = regSrc.highReg;
    int signMask = dvmCompilerAllocTemp(cUnit);
    loadConstant(cUnit, signMask, 0x7fffffff);
    storeWordDisp(cUnit, r6SELF, offset, reglo);
    newLIR2(cUnit, kThumbAndRR, reghi, signMask);
    dvmCompilerFreeTemp(cUnit, signMask);
    storeWordDisp(cUnit, r6SELF, offset + 4, reghi);
    //TUNING: rewrite this to not clobber
    dvmCompilerClobber(cUnit, reghi);
    return false;
}
Example #16
0
/*
 * TUNING: On some implementations, it is quicker to pass addresses
 * to the handlers rather than load the operands into core registers
 * and then move the values to FP regs in the handlers.  Other implementations
 * may prefer passing data in registers (and the latter approach would
 * yeild cleaner register handling - avoiding the requirement that operands
 * be flushed to memory prior to the call).
 */
static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
                            RegLocation rlDest, RegLocation rlSrc1,
                            RegLocation rlSrc2)
{
    TemplateOpCode opCode;

    /*
     * Don't attempt to optimize register usage since these opcodes call out to
     * the handlers.
     */
    switch (mir->dalvikInsn.opCode) {
        case OP_ADD_FLOAT_2ADDR:
        case OP_ADD_FLOAT:
            opCode = TEMPLATE_ADD_FLOAT_VFP;
            break;
        case OP_SUB_FLOAT_2ADDR:
        case OP_SUB_FLOAT:
            opCode = TEMPLATE_SUB_FLOAT_VFP;
            break;
        case OP_DIV_FLOAT_2ADDR:
        case OP_DIV_FLOAT:
            opCode = TEMPLATE_DIV_FLOAT_VFP;
            break;
        case OP_MUL_FLOAT_2ADDR:
        case OP_MUL_FLOAT:
            opCode = TEMPLATE_MUL_FLOAT_VFP;
            break;
        case OP_REM_FLOAT_2ADDR:
        case OP_REM_FLOAT:
        case OP_NEG_FLOAT: {
            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
        }
        default:
            return true;
    }
    loadValueAddressDirect(cUnit, rlDest, r0);
    loadValueAddressDirect(cUnit, rlSrc1, r1);
    loadValueAddressDirect(cUnit, rlSrc2, r2);
    genDispatchToHandler(cUnit, opCode);
    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    if (rlDest.location == kLocPhysReg) {
        dvmCompilerClobber(cUnit, rlDest.lowReg);
    }
    return false;
}
Example #17
0
/*
 * Take the address of a Dalvik register and store it into rDest.
 * Clobber any live values associated either with the Dalvik value
 * or the target register and lock the target fixed register.
 */
static void loadValueAddressDirect(CompilationUnit *cUnit, RegLocation rlSrc,
                                   int rDest)
{
     rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
                          dvmCompilerUpdateLoc(cUnit, rlSrc);
     if (rlSrc.location == kLocPhysReg) {
         if (rlSrc.wide) {
             dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
                                               rlSrc.highReg);
         } else {
             dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
         }
     }
     dvmCompilerClobber(cUnit, rDest);
     dvmCompilerLockTemp(cUnit, rDest);
     opRegRegImm(cUnit, kOpAdd, rDest, rFP,
                 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
}
Example #18
0
/* No select in thumb, so we need to branch.  Thumb2 will do better */
static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
{
    int offset = offsetof(InterpState, retval);
    RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
    RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
    int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
    int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
    newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
    ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
           isMin ? kArmCondLt : kArmCondGt);
    newLIR2(cUnit, kThumbMovRR, reg0, reg1);
    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
    target->defMask = ENCODE_ALL;
    newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
    branch1->generic.target = (LIR *)target;
    //TUNING: rewrite this to not clobber
    dvmCompilerClobber(cUnit,reg0);
    return false;
}
Example #19
0
static void storeValue(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
{
	LOG("rlDest.location is %d\nrlSrc.location is %d\n", rlDest.location, rlSrc.location);
	LIR *defStart;
	LIR *defEnd;
	assert(!rlDest.wide); 
	assert(!rlSrc.wide);  
	//eric 
	//dvmCompilerKillNullCheckedLoc(cUnit, rlDest);   
	rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);    
	//eric:if the register is DalvikFrame, so change it to physical
	rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);  
	LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow);
	if (rlSrc.location == kLocPhysReg) {  
    	LOG(">>>>>>>>>>>>>>>The function is %s<<<<<<<<<<<<<<<<<\n", __func__);   
		LOG(">>>>>>>>>>>>>>>the Src reg is phy<<<<<<<<<<<<<<<<<\n");

        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
			// Src is live or Dest has assigned reg.
			rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); 
			genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
		} else { 
			// Just re-assign the registers.  Dest gets Src's regs 
			rlDest.lowReg = rlSrc.lowReg;
			dvmCompilerClobber(cUnit, rlSrc.lowReg);  
		}
	} else {
    	LOG(">>>>>>>>>>>>>>>The function is %s<<<<<<<<<<<<<<<<<\n", __func__);   
		LOG("the Src reg is not phy\n");

		// Load Src either into promoted Dest or temps allocated for Dest
		rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);   
		loadValueDirect(cUnit, rlSrc, rlDest.lowReg);  
	}

	
	LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow);
	// Dest is now live and dirty (until/if we flush it to home location)
	dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); 
	dvmCompilerMarkDirty(cUnit, rlDest.lowReg); 

	if (rlDest.location == kLocRetval) { 
		//eric
		//storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlDest.lowReg, kWord);
		storeBaseDisp(cUnit, rGLUE, 8, rlDest.lowReg, kWord);
		dvmCompilerClobber(cUnit, rlDest.lowReg); 
	} else {
		dvmCompilerResetDefLoc(cUnit, rlDest); 
		//if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) { 
		if (true) {
//eric
		//	defStart = (LIR *)cUnit->lastLIRInsn;
			LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow);
			int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
			LOG(">>>>>>>>>>>>>vReg is v%d<<<<<<<<<<<<<\n", vReg);
			storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);  
//			storeBaseDisp(cUnit, rFP, 20, rlDest.lowReg, kWord);  
			dvmCompilerMarkClean(cUnit, rlDest.lowReg); 
		//	defEnd = (LIR *)cUnit->lastLIRInsn; 
	//		dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);	

		}
	}
}
Example #20
0
/*
 * Generate array store
 *
 */
static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
                        RegLocation rlArray, RegLocation rlIndex,
                        RegLocation rlSrc, int scale)
{
    RegisterClass regClass = dvmCompilerRegClassBySize(size);
    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);

    int regPtr;
    rlArray = loadValue(cUnit, rlArray, kCoreReg);
    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);

    if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
        dvmCompilerClobber(cUnit, rlArray.lowReg);
        regPtr = rlArray.lowReg;
    } else {
        regPtr = dvmCompilerAllocTemp(cUnit);
        genRegCopy(cUnit, regPtr, rlArray.lowReg);
    }

    /* null object? */
    ArmLIR * pcrLabel = NULL;

    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
                                mir->offset, NULL);
    }

    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
        int regLen = dvmCompilerAllocTemp(cUnit);
        //NOTE: max live temps(4) here.
        /* Get len */
        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
        /* regPtr -> array data */
        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
                       pcrLabel);
        dvmCompilerFreeTemp(cUnit, regLen);
    } else {
        /* regPtr -> array data */
        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
    }
    /* at this point, regPtr points to array, 2 live temps */
    if ((size == kLong) || (size == kDouble)) {
        //TODO: need specific wide routine that can handle fp regs
        if (scale) {
            int rNewIndex = dvmCompilerAllocTemp(cUnit);
            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
        } else {
            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
        }
        rlSrc = loadValueWide(cUnit, rlSrc, regClass);

        HEAP_ACCESS_SHADOW(true);
        storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
        HEAP_ACCESS_SHADOW(false);

        dvmCompilerFreeTemp(cUnit, regPtr);
    } else {
        rlSrc = loadValue(cUnit, rlSrc, regClass);

        HEAP_ACCESS_SHADOW(true);
        storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
                         scale, size);
        HEAP_ACCESS_SHADOW(false);
    }
}