Quick compiler: division by literal fix

The constant propagation optimization pass attempts to identify
constants in Dalvik virtual registers and handle them more efficiently.
The use of small constants in divison, though, was handled incorrectly
in that the high level code correctly detected the use of a constant,
but the actual code generation routine was only expecting the use of
a special constant form opcode.

see b/10503566

Change-Id: I88aa4d2eafebb2b1af1a1e88049f1845aefae261
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index f1ccfa0..291319f 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -26,7 +26,7 @@
     ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
     int LoadHelper(ThreadOffset offset);
     LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index c258019..f2ff58e 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -415,7 +415,7 @@
 };
 
 // Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
-bool ArmMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
   if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
     return false;
@@ -425,7 +425,7 @@
     return false;
   }
   // Tuning: add rem patterns
-  if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
+  if (!is_div) {
     return false;
   }
 
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index e5c7fb1..f018c61 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -1358,25 +1358,23 @@
 
 // Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
 // and store the result in 'rl_dest'.
-bool Mir2Lir::HandleEasyDivide(Instruction::Code dalvik_opcode,
+bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                RegLocation rl_src, RegLocation rl_dest, int lit) {
   if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
     return false;
   }
   // No divide instruction for Arm, so check for more special cases
   if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
-    return SmallLiteralDivide(dalvik_opcode, rl_src, rl_dest, lit);
+    return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
   }
   int k = LowestSetBit(lit);
   if (k >= 30) {
     // Avoid special cases.
     return false;
   }
-  bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
-      dalvik_opcode == Instruction::DIV_INT_LIT16);
   rl_src = LoadValue(rl_src, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  if (div) {
+  if (is_div) {
     int t_reg = AllocTemp();
     if (lit == 2) {
       // Division by 2 is by far the most common division by constant.
@@ -1544,17 +1542,17 @@
         GenImmedCheck(kCondAl, 0, 0, kThrowDivZero);
         return;
       }
-      if (HandleEasyDivide(opcode, rl_src, rl_dest, lit)) {
-        return;
-      }
-      if ((opcode == Instruction::DIV_INT_LIT8) ||
-          (opcode == Instruction::DIV_INT) ||
+      if ((opcode == Instruction::DIV_INT) ||
           (opcode == Instruction::DIV_INT_2ADDR) ||
+          (opcode == Instruction::DIV_INT_LIT8) ||
           (opcode == Instruction::DIV_INT_LIT16)) {
         is_div = true;
       } else {
         is_div = false;
       }
+      if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) {
+        return;
+      }
       if (cu_->instruction_set == kMips) {
         rl_src = LoadValue(rl_src, kCoreReg);
         rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 6100396..b9cb720 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -27,7 +27,7 @@
     MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen utilities.
-    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
     int LoadHelper(ThreadOffset offset);
     LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 4a48c87..6ce5750 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -314,7 +314,7 @@
   return OpCmpImmBranch(c_code, reg, 0, target);
 }
 
-bool MipsMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                      RegLocation rl_src, RegLocation rl_dest, int lit) {
   LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
   return false;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 517fc66..a37ebd1 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -376,7 +376,7 @@
     RegLocation GetReturn(bool is_float);
 
     // Shared by all targets - implemented in gen_common.cc.
-    bool HandleEasyDivide(Instruction::Code dalvik_opcode,
+    bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                           RegLocation rl_src, RegLocation rl_dest, int lit);
     bool HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit);
     void HandleSuspendLaunchPads();
@@ -525,7 +525,7 @@
 
 
     // Required for target - codegen helpers.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode,
+    virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
     virtual int LoadHelper(ThreadOffset offset) = 0;
     virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg) = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 21328d5..478654d 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -27,7 +27,7 @@
     X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
     int LoadHelper(ThreadOffset offset);
     LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 377d134..14be7dd 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -295,7 +295,7 @@
   return OpCmpImmBranch(c_code, reg, 0, target);
 }
 
-bool X86Mir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
   LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
   return false;