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/CompilerIR.h b/src/compiler/CompilerIR.h
index afddf07..429772a 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -45,6 +45,7 @@
     kLocDalvikFrame = 0, // Normal Dalvik register
     kLocPhysReg,
     kLocCompilerTemp,
+    kLocInvalid
 };
 
 struct PromotionMap {
@@ -553,6 +554,7 @@
     kIPutChar,
     kIPutShort,
     kIPutWide,
+    kIdentity,
 };
 
 struct CodePattern {
@@ -580,6 +582,9 @@
     {{Instruction::IPUT_CHAR, Instruction::RETURN_VOID}, kIPutChar},
     {{Instruction::IPUT_SHORT, Instruction::RETURN_VOID}, kIPutShort},
     {{Instruction::IPUT_WIDE, Instruction::RETURN_VOID}, kIPutWide},
+    {{Instruction::RETURN}, kIdentity},
+    {{Instruction::RETURN_OBJECT}, kIdentity},
+    {{Instruction::RETURN_WIDE}, kIdentity},
 };
 
 BasicBlock* oatNewBB(CompilationUnit* cUnit, BBType blockType, int blockId);
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;
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
new file mode 100644
index 0000000..abfd60f
--- /dev/null
+++ b/test/083-compiler-regressions/expected.txt
@@ -0,0 +1,11 @@
+b2296099 passes
+b2302318 passes
+b2487514 passes
+b5884080 passes
+largeFrame passes
+largeFrameFloat passes
+getterSetterTest passes
+identityTest passes
+wideGetterSetterTest passes
+wideIdentityTest passes
+returnConstantTest passes
diff --git a/test/083-jit-regressions/info.txt b/test/083-compiler-regressions/info.txt
similarity index 100%
rename from test/083-jit-regressions/info.txt
rename to test/083-compiler-regressions/info.txt
diff --git a/test/083-jit-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
similarity index 96%
rename from test/083-jit-regressions/src/Main.java
rename to test/083-compiler-regressions/src/Main.java
index e6080c5..cf082e1 100644
--- a/test/083-jit-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -20,6 +20,14 @@
  * Test for Jit regressions.
  */
 public class Main {
+    public static int const0x1234() {
+        return 0x1234;
+    }
+
+    public static long const0x123443211234() {
+        return 0x123443211234L;
+    }
+
     public static void main(String args[]) throws Exception {
         b2296099Test();
         b2302318Test();
@@ -27,6 +35,106 @@
         b5884080Test();
         largeFrameTest();
         largeFrameTestFloat();
+        getterSetterTest();
+        identityTest();
+        wideGetterSetterTest();
+        wideIdentityTest();
+        returnConstantTest();
+    }
+
+    public static void returnConstantTest() {
+        long res = const0x1234();
+        res += const0x123443211234();
+        Foo foo = new Foo();
+        res += foo.iConst0x1234();
+        res += foo.iConst0x123443211234();
+        if (res == 40031347689680L) {
+            System.out.println("returnConstantTest passes");
+        }
+        else {
+            System.out.println("returnConstantTest fails: " + res +
+                               " (expecting 40031347689680)");
+        }
+    }
+
+    static void wideIdentityTest() {
+        Foo foo = new Foo();
+        long i = 1;
+        i += foo.wideIdent0(i);
+        i += foo.wideIdent1(0,i);
+        i += foo.wideIdent2(0,0,i);
+        i += foo.wideIdent3(0,0,0,i);
+        i += foo.wideIdent4(0,0,0,0,i);
+        i += foo.wideIdent5(0,0,0,0,0,i);
+        if (i == 64) {
+            System.out.println("wideIdentityTest passes");
+        }
+        else {
+            System.out.println("wideIdentityTest fails: " + i +
+                               " (expecting 64)");
+        }
+    }
+
+    static void wideGetterSetterTest() {
+        Foo foo = new Foo();
+        long sum = foo.wideGetBar0();
+        sum += foo.wideGetBar1(1);
+        foo.wideSetBar1(sum);
+        sum += foo.wideGetBar2(1,2);
+        foo.wideSetBar2(0,sum);
+        sum += foo.wideGetBar3(1,2,3);
+        foo.wideSetBar3(0,0,sum);
+        sum += foo.wideGetBar4(1,2,3,4);
+        foo.wideSetBar4(0,0,0,sum);
+        sum += foo.wideGetBar5(1,2,3,4,5);
+        foo.wideSetBar5(0,0,0,0,sum);
+        if (foo.wideGetBar0() == 39488) {
+            System.out.println("wideGetterSetterTest passes");
+        }
+        else {
+            System.out.println("wideGetterSetterTest fails: " +
+                                foo.wideGetBar0() + " (expecting 39488)");
+        }
+    }
+
+    static void identityTest() {
+        Foo foo = new Foo();
+        int i = 1;
+        i += foo.ident0(i);
+        i += foo.ident1(0,i);
+        i += foo.ident2(0,0,i);
+        i += foo.ident3(0,0,0,i);
+        i += foo.ident4(0,0,0,0,i);
+        i += foo.ident5(0,0,0,0,0,i);
+        if (i == 64) {
+            System.out.println("identityTest passes");
+        }
+        else {
+            System.out.println("identityTest fails: " + i +
+                               " (expecting 64)");
+        }
+    }
+
+    static void getterSetterTest() {
+        Foo foo = new Foo();
+        int sum = foo.getBar0();
+        sum += foo.getBar1(1);
+        foo.setBar1(sum);
+        sum += foo.getBar2(1,2);
+        foo.setBar2(0,sum);
+        sum += foo.getBar3(1,2,3);
+        foo.setBar3(0,0,sum);
+        sum += foo.getBar4(1,2,3,4);
+        foo.setBar4(0,0,0,sum);
+        sum += foo.getBar5(1,2,3,4,5);
+        foo.setBar5(0,0,0,0,sum);
+        if (foo.getBar0() == 39488) {
+            System.out.println("getterSetterTest passes");
+        }
+        else {
+            System.out.println("getterSetterTest fails: " + foo.getBar0() +
+                               " (expecting 39488)");
+        }
     }
 
     static void b2296099Test() throws Exception {
@@ -8165,3 +8273,134 @@
         while (true) {}
     }
 }
+
+class Foo {
+    private int bar = 1234;
+    private long lbar = 1234;
+
+    public int iConst0x1234() {
+        return 0x1234;
+    }
+
+    public long iConst0x123443211234() {
+        return 0x123443211234L;
+    }
+
+    public void setBar1(int a1) {
+        bar = a1;
+    }
+    public void setBar2(int a1, int a2) {
+        bar = a2;
+    }
+    public void setBar3(int a1, int a2, int a3) {
+        bar = a3;
+    }
+    public void setBar4(int a1, int a2, int a3, int a4) {
+        bar = a4;
+    }
+    public void setBar5(int a1, int a2, int a3, int a4, int a5) {
+        bar = a5;
+    }
+    public int getBar0() {
+        return bar;
+    }
+    public int getBar1(int a1) {
+        return bar;
+    }
+    public int getBar2(int a1, int a2) {
+        return bar;
+    }
+    public int getBar3(int a1, int a2, int a3) {
+        return bar;
+    }
+    public int getBar4(int a1, int a2, int a3, int a4) {
+        return bar;
+    }
+    public int getBar5(int a1, int a2, int a3, int a4, int a5) {
+        return bar;
+    }
+
+    public int ident0(int a1) {
+        return a1;
+    }
+
+    public int ident1(int a2, int a1) {
+        return a1;
+    }
+
+    public int ident2(int a3, int a2, int a1) {
+        return a1;
+    }
+
+    public int ident3(int a4, int a3, int a2, int a1) {
+        return a1;
+    }
+
+    public int ident4(int a5, int a4, int a3, int a2, int a1) {
+        return a1;
+    }
+
+    public int ident5(int a6, int a5, int a4, int a3, int a2, int a1) {
+        return a1;
+    }
+
+
+    public void wideSetBar1(long a1) {
+        lbar = a1;
+    }
+    public void wideSetBar2(long a1, long a2) {
+        lbar = a2;
+    }
+    public void wideSetBar3(long a1, long a2, long a3) {
+        lbar = a3;
+    }
+    public void wideSetBar4(long a1, long a2, long a3, long a4) {
+        lbar = a4;
+    }
+    public void wideSetBar5(long a1, long a2, long a3, long a4, long a5) {
+        lbar = a5;
+    }
+    public long wideGetBar0() {
+        return lbar;
+    }
+    public long wideGetBar1(long a1) {
+        return lbar;
+    }
+    public long wideGetBar2(long a1, long a2) {
+        return lbar;
+    }
+    public long wideGetBar3(long a1, long a2, long a3) {
+        return lbar;
+    }
+    public long wideGetBar4(long a1, long a2, long a3, long a4) {
+        return lbar;
+    }
+    public long wideGetBar5(long a1, long a2, long a3, long a4, long a5) {
+        return lbar;
+    }
+
+    public long wideIdent0(long a1) {
+        return a1;
+    }
+
+    public long wideIdent1(int a2, long a1) {
+        return a1;
+    }
+
+    public long wideIdent2(int a3, int a2, long a1) {
+        return a1;
+    }
+
+    public long wideIdent3(int a4, int a3, int a2, long a1) {
+        return a1;
+    }
+
+    public long wideIdent4(int a5, int a4, int a3, int a2, long a1) {
+        return a1;
+    }
+
+    public long wideIdent5(int a6, int a5, int a4, int a3, int a2, long a1) {
+        return a1;
+  }
+
+}
diff --git a/test/083-jit-regressions/expected.txt b/test/083-jit-regressions/expected.txt
deleted file mode 100644
index 13f61ca..0000000
--- a/test/083-jit-regressions/expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-b2296099 passes
-b2302318 passes
-b2487514 passes
-b5884080 passes
-largeFrame passes
-largeFrameFloat passes