Jit: shift bug fix - 2296099
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
new file mode 100644
index 0000000..780f71b
--- /dev/null
+++ b/tests/083-jit-regressions/expected.txt
@@ -0,0 +1 @@
+b2296099 Passes
diff --git a/tests/083-jit-regressions/info.txt b/tests/083-jit-regressions/info.txt
new file mode 100644
index 0000000..42d3cd9
--- /dev/null
+++ b/tests/083-jit-regressions/info.txt
@@ -0,0 +1,8 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+This test covers JIT regressions
+
+http://b/issue?id=2296099 JIT shift bug
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
new file mode 100644
index 0000000..e6a18ba
--- /dev/null
+++ b/tests/083-jit-regressions/src/Main.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/**
+ * Test for Jit regressions.
+ */
+public class Main {
+    public static void main(String args[]) throws Exception {
+        b2296099Test();
+    }
+
+    static void b2296099Test() throws Exception {
+       int x = -1190771042;
+       int dist = 360530809;
+       int xl = -1190771042;
+       int distl = 360530809;
+
+       for (int i = 0; i < 100000; i++) {
+           int b = rotateLeft(x, dist);
+           if (b != 1030884493)
+               throw new RuntimeException("Unexpected value: " + b
+                       + " after " + i + " iterations");
+       }
+       for (int i = 0; i < 100000; i++) {
+           long bl = rotateLeft(xl, distl);
+           if (bl != 1030884493)
+               throw new RuntimeException("Unexpected value: " + bl
+                       + " after " + i + " iterations");
+       }
+       System.out.println("b2296099 Passes");
+   }
+
+   static int rotateLeft(int i, int distance) {
+       return ((i << distance) | (i >>> (-distance)));
+   }
+}
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 37fd65f..f3648b9 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1091,6 +1091,7 @@
     int retReg = r0;
     void *callTgt;
     RegLocation rlResult;
+    bool shiftOp = false;
 
     /* TODO - find proper .h file to declare these */
     int __aeabi_idivmod(int op1, int op2);
@@ -1146,14 +1147,17 @@
             break;
         case OP_SHL_INT:
         case OP_SHL_INT_2ADDR:
+            shiftOp = true;
             op = kOpLsl;
             break;
         case OP_SHR_INT:
         case OP_SHR_INT_2ADDR:
+            shiftOp = true;
             op = kOpAsr;
             break;
         case OP_USHR_INT:
         case OP_USHR_INT_2ADDR:
+            shiftOp = true;
             op = kOpLsr;
             break;
         default:
@@ -1169,9 +1173,18 @@
                      rlSrc1.lowReg);
         } else {
             rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
-            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegRegReg(cUnit, op, rlResult.lowReg,
-                        rlSrc1.lowReg, rlSrc2.lowReg);
+            if (shiftOp) {
+                int tReg = allocTemp(cUnit);
+                opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
+                rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+                opRegRegReg(cUnit, op, rlResult.lowReg,
+                            rlSrc1.lowReg, tReg);
+                freeTemp(cUnit, tReg);
+            } else {
+                rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+                opRegRegReg(cUnit, op, rlResult.lowReg,
+                            rlSrc1.lowReg, rlSrc2.lowReg);
+            }
         }
         storeValue(cUnit, rlDest, rlResult);
     } else {
@@ -2315,14 +2328,17 @@
             op = kOpXor;
             break;
         case OP_SHL_INT_LIT8:
+            lit &= 31;
             shiftOp = true;
             op = kOpLsl;
             break;
         case OP_SHR_INT_LIT8:
+            lit &= 31;
             shiftOp = true;
             op = kOpAsr;
             break;
         case OP_USHR_INT_LIT8:
+            lit &= 31;
             shiftOp = true;
             op = kOpLsr;
             break;