Fix special method codegen
Tightened up the conditions under which we can generate frameless
methods. Added and renamed test case. Added special handling for
identity functions.
Change-Id: I5b04ea222becefc151ef7ff6b255e58922ccd6f2
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 21c995f..1938960 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -26,24 +26,78 @@
namespace art {
-/* Return a RegLocation that describes an in-register argument */
-RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc, int sReg)
+
+/* Return the position of an ssa name within the argument list */
+int inPosition(CompilationUnit* cUnit, int sReg)
{
- loc.location = kLocPhysReg;
- int base = SRegToVReg(cUnit, sReg) - cUnit->numRegs;
- loc.sRegLow = sReg;
- loc.lowReg = rARG1 + base;
- loc.home = true;
+ int vReg = SRegToVReg(cUnit, sReg);
+ return vReg - cUnit->numRegs;
+}
+
+/*
+ * Describe an argument. If it's already in an arg register, just leave it
+ * there. NOTE: all live arg registers must be locked prior to this call
+ * to avoid having them allocated as a temp by downstream utilities.
+ */
+RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc)
+{
+ int argNum = inPosition(cUnit, loc.sRegLow);
if (loc.wide) {
- loc.highReg = loc.lowReg + 1;
- oatLockTemp(cUnit, loc.lowReg);
- oatLockTemp(cUnit, loc.highReg);
+ if (argNum == 2) {
+ // Bad case - half in register, half in frame. Just punt
+ loc.location = kLocInvalid;
+ } else if (argNum < 2) {
+ loc.lowReg = rARG1 + argNum;
+ loc.highReg = loc.lowReg + 1;
+ loc.location = kLocPhysReg;
+ } else {
+ loc.location = kLocDalvikFrame;
+ }
} else {
- oatLockTemp(cUnit, loc.lowReg);
+ if (argNum < 3) {
+ loc.lowReg = rARG1 + argNum;
+ loc.location = kLocPhysReg;
+ } else {
+ loc.location = kLocDalvikFrame;
+ }
}
return loc;
}
+/*
+ * Load an argument. If already in a register, just return. If in
+ * the frame, we can't use the normal loadValue() because it assumed
+ * a proper frame - and we're frameless.
+ */
+RegLocation loadArg(CompilationUnit* cUnit, RegLocation loc)
+{
+ if (loc.location == kLocDalvikFrame) {
+ int start = (inPosition(cUnit, loc.sRegLow) + 1) * sizeof(uint32_t);
+ loc.lowReg = oatAllocTemp(cUnit);
+ loadWordDisp(cUnit, rSP, start, loc.lowReg);
+ if (loc.wide) {
+ loc.highReg = oatAllocTemp(cUnit);
+ loadWordDisp(cUnit, rSP, start + sizeof(uint32_t), loc.highReg);
+ }
+ loc.location = kLocPhysReg;
+ }
+ return loc;
+}
+
+/* Lock any referenced arguments that arrive in registers */
+void lockLiveArgs(CompilationUnit* cUnit, MIR* mir)
+{
+ int firstIn = cUnit->numRegs;
+ const int numArgRegs = 3; // TODO: generalize & move to RegUtil.cc
+ for (int i = 0; i < mir->ssaRep->numUses; i++) {
+ int vReg = SRegToVReg(cUnit, mir->ssaRep->uses[i]);
+ int inPosition = vReg - firstIn;
+ if (inPosition < numArgRegs) {
+ oatLockTemp(cUnit, rARG1 + inPosition);
+ }
+ }
+}
+
/* Find the next MIR, which may be in a following basic block */
MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
{
@@ -98,16 +152,25 @@
if (!fastPath) {
return NULL;
}
- mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
- genPrintLabel(cUnit, mir);
RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
- rlObj = argLoc(cUnit, rlObj, mir->ssaRep->uses[0]);
+ lockLiveArgs(cUnit, mir);
+ rlObj = argLoc(cUnit, rlObj);
+ // Reject if object reference is not "this"
+ if ((rlObj.location == kLocInvalid) ||
+ (inPosition(cUnit, rlObj.sRegLow) != 0)) {
+ oatResetRegPool(cUnit);
+ return NULL;
+ }
RegLocation rlDest;
if (longOrDouble) {
rlDest = oatGetReturnWide(cUnit, false);
} else {
rlDest = oatGetReturn(cUnit, false);
}
+ // Point of no return - no aborts after this
+ mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+ genPrintLabel(cUnit, mir);
+ rlObj = loadArg(cUnit, rlObj);
genIGet(cUnit, mir, size, rlDest, rlObj, longOrDouble, isObject);
return getNextMir(cUnit, bb, mir);
}
@@ -118,35 +181,68 @@
int fieldOffset;
bool isVolatile;
uint32_t fieldIdx = mir->dalvikInsn.vC;
- if (cUnit->numIns > 3) {
- return NULL; // TODO: fix register allocation for many in arguments
- }
bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
false);
if (!fastPath) {
return NULL;
}
- mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
- genPrintLabel(cUnit, mir);
RegLocation rlSrc;
RegLocation rlObj;
- int sSreg = mir->ssaRep->uses[0];
- int oSreg;
+ lockLiveArgs(cUnit, mir);
if (longOrDouble) {
rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
rlObj = oatGetSrc(cUnit, mir, 2);
- oSreg = mir->ssaRep->uses[2];
} else {
rlSrc = oatGetSrc(cUnit, mir, 0);
rlObj = oatGetSrc(cUnit, mir, 1);
- oSreg = mir->ssaRep->uses[1];
}
- rlSrc = argLoc(cUnit, rlSrc, sSreg);
- rlObj = argLoc(cUnit, rlObj, oSreg);
+ rlSrc = argLoc(cUnit, rlSrc);
+ rlObj = argLoc(cUnit, rlObj);
+ // Reject if object reference is not "this"
+ if ((rlObj.location == kLocInvalid) ||
+ (inPosition(cUnit, rlObj.sRegLow) != 0) ||
+ (rlSrc.location == kLocInvalid)) {
+ oatResetRegPool(cUnit);
+ return NULL;
+ }
+ // Point of no return - no aborts after this
+ mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+ genPrintLabel(cUnit, mir);
+ rlObj = loadArg(cUnit, rlObj);
+ rlSrc = loadArg(cUnit, rlSrc);
genIPut(cUnit, mir, size, rlSrc, rlObj, longOrDouble, isObject);
return getNextMir(cUnit, bb, mir);
}
+MIR* specialIdentity(CompilationUnit* cUnit, MIR* mir)
+{
+ RegLocation rlSrc;
+ RegLocation rlDest;
+ bool wide = (mir->ssaRep->numUses == 2);
+ if (wide) {
+ rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+ rlDest = oatGetReturnWide(cUnit, false);
+ } else {
+ rlSrc = oatGetSrc(cUnit, mir, 0);
+ rlDest = oatGetReturn(cUnit, false);
+ }
+ lockLiveArgs(cUnit, mir);
+ rlSrc = argLoc(cUnit, rlSrc);
+ if (rlSrc.location == kLocInvalid) {
+ oatResetRegPool(cUnit);
+ return NULL;
+ }
+ // Point of no return - no aborts after this
+ genPrintLabel(cUnit, mir);
+ rlSrc = loadArg(cUnit, rlSrc);
+ if (wide) {
+ storeValueWide(cUnit, rlDest, rlSrc);
+ } else {
+ storeValue(cUnit, rlDest, rlSrc);
+ }
+ return mir;
+}
+
/*
* Special-case code genration for simple non-throwing leaf methods.
*/
@@ -167,48 +263,53 @@
break;
case kIGet:
nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
- break;;
+ break;
case kIGetBoolean:
case kIGetByte:
nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
- break;;
+ break;
case kIGetObject:
nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
- break;;
+ break;
case kIGetChar:
nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
- break;;
+ break;
case kIGetShort:
nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
- break;;
+ break;
case kIGetWide:
nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
- break;;
+ break;
case kIPut:
nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
- break;;
+ break;
case kIPutBoolean:
case kIPutByte:
nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
- break;;
+ break;
case kIPutObject:
nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
- break;;
+ break;
case kIPutChar:
nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
- break;;
+ break;
case kIPutShort:
nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
- break;;
+ break;
case kIPutWide:
nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
- break;;
+ break;
+ case kIdentity:
+ nextMir = specialIdentity(cUnit, mir);
+ break;
default:
return;
}
if (nextMir != NULL) {
cUnit->currentDalvikOffset = nextMir->offset;
- genPrintLabel(cUnit, nextMir);
+ if (specialCase != kIdentity) {
+ genPrintLabel(cUnit, nextMir);
+ }
newLIR1(cUnit, kThumbBx, rLR);
cUnit->coreSpillMask = 0;
cUnit->numCoreSpills = 0;