Aarch64: easy division and remainder for long ints.

Also adding test 701 to test easy division and remainder for int and
long integers.

Change-Id: I8212c84e4d9eb3e9f3f4f1f1c3418537bb13dc55
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index ef4c0de..d0633af 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -319,6 +319,7 @@
   kA64Scvtf2fx,      // scvtf  [100111100s100010000000] rn[9-5] rd[4-0].
   kA64Sdiv3rrr,      // sdiv[s0011010110] rm[20-16] [000011] rn[9-5] rd[4-0].
   kA64Smaddl4xwwx,   // smaddl [10011011001] rm[20-16] [0] ra[14-10] rn[9-5] rd[4-0].
+  kA64Smulh3xxx,     // smulh [10011011010] rm[20-16] [011111] rn[9-5] rd[4-0].
   kA64Stp4ffXD,      // stp [0s10110100] imm_7[21-15] rt2[14-10] rn[9-5] rt[4-0].
   kA64Stp4rrXD,      // stp [s010100100] imm_7[21-15] rt2[14-10] rn[9-5] rt[4-0].
   kA64StpPost4rrXD,  // stp [s010100010] imm_7[21-15] rt2[14-10] rn[9-5] rt[4-0].
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index 416a13e..083277d 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -502,6 +502,10 @@
                  kFmtRegX, 4, 0, kFmtRegW, 9, 5, kFmtRegW, 20, 16,
                  kFmtRegX, 14, 10, IS_QUAD_OP | REG_DEF0_USE123,
                  "smaddl", "!0x, !1w, !2w, !3x", kFixupNone),
+    ENCODING_MAP(kA64Smulh3xxx, NO_VARIANTS(0x9b407c00),
+                 kFmtRegX, 4, 0, kFmtRegX, 9, 5, kFmtRegX, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "smulh", "!0x, !1x, !2x", kFixupNone),
     ENCODING_MAP(WIDE(kA64Stp4ffXD), CUSTOM_VARIANTS(0x2d000000, 0x6d000000),
                  kFmtRegF, 4, 0, kFmtRegF, 14, 10, kFmtRegXOrSp, 9, 5,
                  kFmtBitBlt, 21, 15, IS_QUAD_OP | REG_USE012 | IS_STORE,
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 060509b..a38a797 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -65,8 +65,12 @@
     // Required for target - codegen helpers.
     bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                             RegLocation rl_dest, int lit) OVERRIDE;
+    bool SmallLiteralDivRem64(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
+                              RegLocation rl_dest, int64_t lit);
     bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                           RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+    bool HandleEasyDivRem64(Instruction::Code dalvik_opcode, bool is_div,
+                            RegLocation rl_src, RegLocation rl_dest, int64_t lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index f7aa39f..967acb8 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -357,28 +357,31 @@
 
 // Table of magic divisors
 struct MagicTable {
-  uint32_t magic;
+  int magic64_base;
+  int magic64_eor;
+  uint64_t magic64;
+  uint32_t magic32;
   uint32_t shift;
   DividePattern pattern;
 };
 
 static const MagicTable magic_table[] = {
-  {0, 0, DivideNone},        // 0
-  {0, 0, DivideNone},        // 1
-  {0, 0, DivideNone},        // 2
-  {0x55555556, 0, Divide3},  // 3
-  {0, 0, DivideNone},        // 4
-  {0x66666667, 1, Divide5},  // 5
-  {0x2AAAAAAB, 0, Divide3},  // 6
-  {0x92492493, 2, Divide7},  // 7
-  {0, 0, DivideNone},        // 8
-  {0x38E38E39, 1, Divide5},  // 9
-  {0x66666667, 2, Divide5},  // 10
-  {0x2E8BA2E9, 1, Divide5},  // 11
-  {0x2AAAAAAB, 1, Divide5},  // 12
-  {0x4EC4EC4F, 2, Divide5},  // 13
-  {0x92492493, 3, Divide7},  // 14
-  {0x88888889, 3, Divide7},  // 15
+  {   0,      0,                  0,          0, 0, DivideNone},  // 0
+  {   0,      0,                  0,          0, 0, DivideNone},  // 1
+  {   0,      0,                  0,          0, 0, DivideNone},  // 2
+  {0x3c,     -1, 0x5555555555555556, 0x55555556, 0, Divide3},     // 3
+  {   0,      0,                  0,          0, 0, DivideNone},  // 4
+  {0xf9,     -1, 0x6666666666666667, 0x66666667, 1, Divide5},     // 5
+  {0x7c, 0x1041, 0x2AAAAAAAAAAAAAAB, 0x2AAAAAAB, 0, Divide3},     // 6
+  {  -1,     -1, 0x924924924924924A, 0x92492493, 2, Divide7},     // 7
+  {   0,      0,                  0,          0, 0, DivideNone},  // 8
+  {  -1,     -1, 0x38E38E38E38E38E4, 0x38E38E39, 1, Divide5},     // 9
+  {0xf9,     -1, 0x6666666666666667, 0x66666667, 2, Divide5},     // 10
+  {  -1,     -1, 0x2E8BA2E8BA2E8BA3, 0x2E8BA2E9, 1, Divide5},     // 11
+  {0x7c, 0x1041, 0x2AAAAAAAAAAAAAAB, 0x2AAAAAAB, 1, Divide5},     // 12
+  {  -1,     -1, 0x4EC4EC4EC4EC4EC5, 0x4EC4EC4F, 2, Divide5},     // 13
+  {  -1,     -1, 0x924924924924924A, 0x92492493, 3, Divide7},     // 14
+  {0x78,     -1, 0x8888888888888889, 0x88888889, 3, Divide7},     // 15
 };
 
 // Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
@@ -397,7 +400,7 @@
   }
 
   RegStorage r_magic = AllocTemp();
-  LoadConstant(r_magic, magic_table[lit].magic);
+  LoadConstant(r_magic, magic_table[lit].magic32);
   rl_src = LoadValue(rl_src, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   RegStorage r_long_mul = AllocTemp();
@@ -426,49 +429,144 @@
   return true;
 }
 
+bool Arm64Mir2Lir::SmallLiteralDivRem64(Instruction::Code dalvik_opcode, bool is_div,
+                                        RegLocation rl_src, RegLocation rl_dest, int64_t lit) {
+  if ((lit < 0) || (lit >= static_cast<int>(arraysize(magic_table)))) {
+    return false;
+  }
+  DividePattern pattern = magic_table[lit].pattern;
+  if (pattern == DivideNone) {
+    return false;
+  }
+  // Tuning: add rem patterns
+  if (!is_div) {
+    return false;
+  }
+
+  RegStorage r_magic = AllocTempWide();
+  rl_src = LoadValueWide(rl_src, kCoreReg);
+  RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+  RegStorage r_long_mul = AllocTempWide();
+
+  if (magic_table[lit].magic64_base >= 0) {
+    // Check that the entry in the table is correct.
+    if (kIsDebugBuild) {
+      uint64_t reconstructed_imm;
+      uint64_t base = DecodeLogicalImmediate(/*is_wide*/true, magic_table[lit].magic64_base);
+      if (magic_table[lit].magic64_eor >= 0) {
+        uint64_t eor = DecodeLogicalImmediate(/*is_wide*/true, magic_table[lit].magic64_eor);
+        reconstructed_imm = base ^ eor;
+      } else {
+        reconstructed_imm = base + 1;
+      }
+      DCHECK_EQ(reconstructed_imm, magic_table[lit].magic64) << " for literal " << lit;
+    }
+
+    // Load the magic constant in two instructions.
+    NewLIR3(WIDE(kA64Orr3Rrl), r_magic.GetReg(), rxzr, magic_table[lit].magic64_base);
+    if (magic_table[lit].magic64_eor >= 0) {
+      NewLIR3(WIDE(kA64Eor3Rrl), r_magic.GetReg(), r_magic.GetReg(),
+              magic_table[lit].magic64_eor);
+    } else {
+      NewLIR4(WIDE(kA64Add4RRdT), r_magic.GetReg(), r_magic.GetReg(), 1, 0);
+    }
+  } else {
+    LoadConstantWide(r_magic, magic_table[lit].magic64);
+  }
+
+  NewLIR3(kA64Smulh3xxx, r_long_mul.GetReg(), r_magic.GetReg(), rl_src.reg.GetReg());
+  switch (pattern) {
+    case Divide3:
+      OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 63));
+      break;
+    case Divide5:
+      OpRegRegImm(kOpAsr, r_long_mul, r_long_mul, magic_table[lit].shift);
+      OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 63));
+      break;
+    case Divide7:
+      OpRegRegReg(kOpAdd, r_long_mul, rl_src.reg, r_long_mul);
+      OpRegRegImm(kOpAsr, r_long_mul, r_long_mul, magic_table[lit].shift);
+      OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 63));
+      break;
+    default:
+      LOG(FATAL) << "Unexpected pattern: " << pattern;
+  }
+  StoreValueWide(rl_dest, rl_result);
+  return true;
+}
+
 // Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
 // and store the result in 'rl_dest'.
 bool Arm64Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
+  return HandleEasyDivRem64(dalvik_opcode, is_div, rl_src, rl_dest, static_cast<int>(lit));
+}
+
+// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
+// and store the result in 'rl_dest'.
+bool Arm64Mir2Lir::HandleEasyDivRem64(Instruction::Code dalvik_opcode, bool is_div,
+                                      RegLocation rl_src, RegLocation rl_dest, int64_t lit) {
+  const bool is_64bit = rl_dest.wide;
+  const int nbits = (is_64bit) ? 64 : 32;
+
   if (lit < 2) {
     return false;
   }
   if (!IsPowerOfTwo(lit)) {
-    return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
+    if (is_64bit) {
+      return SmallLiteralDivRem64(dalvik_opcode, is_div, rl_src, rl_dest, lit);
+    } else {
+      return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, static_cast<int32_t>(lit));
+    }
   }
   int k = LowestSetBit(lit);
-  if (k >= 30) {
+  if (k >= nbits - 2) {
     // Avoid special cases.
     return false;
   }
-  rl_src = LoadValue(rl_src, kCoreReg);
-  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+
+  RegLocation rl_result;
+  RegStorage t_reg;
+  if (is_64bit) {
+    rl_src = LoadValueWide(rl_src, kCoreReg);
+    rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+    t_reg = AllocTempWide();
+  } else {
+    rl_src = LoadValue(rl_src, kCoreReg);
+    rl_result = EvalLoc(rl_dest, kCoreReg, true);
+    t_reg = AllocTemp();
+  }
+
+  int shift = EncodeShift(kA64Lsr, nbits - k);
   if (is_div) {
-    RegStorage t_reg = AllocTemp();
     if (lit == 2) {
       // Division by 2 is by far the most common division by constant.
-      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
+      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, shift);
       OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k);
     } else {
-      OpRegRegImm(kOpAsr, t_reg, rl_src.reg, 31);
-      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, t_reg, EncodeShift(kA64Lsr, 32 - k));
+      OpRegRegImm(kOpAsr, t_reg, rl_src.reg, nbits - 1);
+      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, t_reg, shift);
       OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k);
     }
   } else {
-    RegStorage t_reg = AllocTemp();
     if (lit == 2) {
-      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
-      OpRegRegImm(kOpAnd, t_reg, t_reg, lit - 1);
-      OpRegRegRegShift(kOpSub, rl_result.reg, t_reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
+      OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, shift);
+      OpRegRegImm64(kOpAnd, t_reg, t_reg, lit - 1);
+      OpRegRegRegShift(kOpSub, rl_result.reg, t_reg, rl_src.reg, shift);
     } else {
-      RegStorage t_reg2 = AllocTemp();
-      OpRegRegImm(kOpAsr, t_reg, rl_src.reg, 31);
-      OpRegRegRegShift(kOpAdd, t_reg2, rl_src.reg, t_reg, EncodeShift(kA64Lsr, 32 - k));
-      OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1);
-      OpRegRegRegShift(kOpSub, rl_result.reg, t_reg2, t_reg, EncodeShift(kA64Lsr, 32 - k));
+      RegStorage t_reg2 = (is_64bit) ? AllocTempWide() : AllocTemp();
+      OpRegRegImm(kOpAsr, t_reg, rl_src.reg, nbits - 1);
+      OpRegRegRegShift(kOpAdd, t_reg2, rl_src.reg, t_reg, shift);
+      OpRegRegImm64(kOpAnd, t_reg2, t_reg2, lit - 1);
+      OpRegRegRegShift(kOpSub, rl_result.reg, t_reg2, t_reg, shift);
     }
   }
-  StoreValue(rl_dest, rl_result);
+
+  if (is_64bit) {
+    StoreValueWide(rl_dest, rl_result);
+  } else {
+    StoreValue(rl_dest, rl_result);
+  }
   return true;
 }
 
@@ -477,12 +575,6 @@
   return false;
 }
 
-RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                                    RegLocation rl_src2, bool is_div, bool check_zero) {
-  LOG(FATAL) << "Unexpected use of GenDivRem for Arm64";
-  return rl_dest;
-}
-
 RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
   LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm64";
   return rl_dest;
@@ -502,8 +594,14 @@
   return rl_result;
 }
 
+RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+                                    RegLocation rl_src2, bool is_div, bool check_zero) {
+  LOG(FATAL) << "Unexpected use of GenDivRem for Arm64";
+  return rl_dest;
+}
+
 RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage r_src1, RegStorage r_src2,
-                                  bool is_div) {
+                                    bool is_div) {
   CHECK_EQ(r_src1.Is64Bit(), r_src2.Is64Bit());
 
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -785,6 +883,14 @@
 
 void Arm64Mir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest,
                                  RegLocation rl_src1, RegLocation rl_src2, bool is_div) {
+  if (rl_src2.is_const) {
+    DCHECK(rl_src2.wide);
+    int64_t lit = mir_graph_->ConstantValueWide(rl_src2);
+    if (HandleEasyDivRem64(opcode, is_div, rl_src1, rl_dest, lit)) {
+      return;
+    }
+  }
+
   RegLocation rl_result;
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
@@ -1050,7 +1156,7 @@
 }
 
 void Arm64Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
-                                   RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
+                                     RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
   OpKind op = kOpBkpt;
   // Per spec, we only care about low 6 bits of shift amount.
   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
diff --git a/test/701-easy-div-rem/expected.txt b/test/701-easy-div-rem/expected.txt
new file mode 100644
index 0000000..97be343
--- /dev/null
+++ b/test/701-easy-div-rem/expected.txt
@@ -0,0 +1,8 @@
+Begin
+Int: checking some equally spaced dividends...
+Int: checking small dividends...
+Int: checking big dividends...
+Long: checking some equally spaced dividends...
+Long: checking small dividends...
+Long: checking big dividends...
+End
diff --git a/test/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py
new file mode 100644
index 0000000..80eac34
--- /dev/null
+++ b/test/701-easy-div-rem/genMain.py
@@ -0,0 +1,155 @@
+# Copyright (C) 2014 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.
+
+all_tests = [
+    ({'@INT@': 'int', '@SUFFIX@':''},
+     [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(31)]),
+      ('CheckDiv', 'idiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
+      ('CheckRem', 'irem_by_pow2_', [2**i for i in range(31)])]),
+    ({'@INT@': 'long', '@SUFFIX@': 'l'},
+     [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(63)]),
+      ('CheckDiv', 'ldiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
+      ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(63)])])
+]
+
+def subst_vars(variables, text):
+    '''Substitute variables in text.'''
+    for key, value in variables.iteritems():
+        text = text.replace(str(key), str(value))
+    return text
+
+# Generate all the function bodies (in decls) and all the function calls (in calls).
+decls, calls = '', {}
+for default_vars, tests in all_tests:
+    local_vars = default_vars.copy()
+    int_type = local_vars['@INT@']
+    for checker, name, values in tests:
+        local_vars['@CHECKER@'] = checker
+        for i, value in enumerate(values):
+            local_vars['@NAME@'] = name + str(i)
+            local_vars['@VALUE@'] = value
+            local_vars['@OP@'] = '/' if 'div' in name else '%'
+
+            # Function body.
+            decls += subst_vars(local_vars, '''
+    public static @INT@ @NAME@(@INT@ x) {return x @OP@ @VALUE@@SUFFIX@;}''')
+
+            # Function call and test.
+            calls[int_type] = calls.get(int_type, '') + subst_vars(local_vars, '''
+        @INT@@CHECKER@("@NAME@", @NAME@(x), x, @VALUE@@SUFFIX@);''')
+
+# Generate the checkers.
+checkers = ''
+local_vars = {}
+for int_type in ('int', 'long'):
+    local_vars['@INT@'] = int_type
+    for op, op_name in (('/', 'Div'), ('%', 'Rem')):
+        local_vars['@OP@'] = op
+        local_vars['@OP_NAME@'] = op_name
+        checkers += subst_vars(local_vars, '''
+    public static void @INT@Check@OP_NAME@(String desc, @INT@ result, @INT@ dividend, @INT@ divisor) {
+        @INT@ correct_result = dividend @OP@ divisor;
+        if (result != correct_result) {
+            reportError(desc + "(" + dividend + ") == " + result +
+                        " should be " + correct_result);
+        }
+    }''')
+
+
+code = \
+'''/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+    public static int num_errors = 0;
+
+    public static void reportError(String message) {
+        if (num_errors == 10) {
+            System.out.println("Omitting other error messages...");
+        } else if (num_errors < 10) {
+            System.out.println(message);
+        }
+        num_errors += 1;
+    }
+%s
+%s
+
+    public static void intCheckAll(int x) {%s
+    }
+
+    public static void longCheckAll(long x) {%s
+    }
+
+    public static void main(String[] args) {
+      int i;
+      long l;
+
+      System.out.println("Begin");
+
+      System.out.println("Int: checking some equally spaced dividends...");
+      for (i = -1000; i < 1000; i += 300) {
+          intCheckAll(i);
+          intCheckAll(-i);
+      }
+
+      System.out.println("Int: checking small dividends...");
+      for (i = 1; i < 100; i += 1) {
+          intCheckAll(i);
+          intCheckAll(-i);
+      }
+
+      System.out.println("Int: checking big dividends...");
+      for (i = 0; i < 100; i += 1) {
+          intCheckAll(Integer.MAX_VALUE - i);
+          intCheckAll(Integer.MIN_VALUE + i);
+      }
+
+      System.out.println("Long: checking some equally spaced dividends...");
+      for (l = 0l; l < 1000000000000l; l += 300000000000l) {
+          longCheckAll(l);
+          longCheckAll(-l);
+      }
+
+      System.out.println("Long: checking small dividends...");
+      for (l = 1l; l < 100l; l += 1l) {
+          longCheckAll(l);
+          longCheckAll(-l);
+      }
+
+      System.out.println("Long: checking big dividends...");
+      for (l = 0l; l < 100l; l += 1l) {
+          longCheckAll(Long.MAX_VALUE - l);
+          longCheckAll(Long.MIN_VALUE + l);
+      }
+
+      System.out.println("End");
+    }
+}
+''' % (checkers, decls, calls['int'], calls['long'])
+
+with open('src/Main.java', 'w') as f:
+    f.write(code)
diff --git a/test/701-easy-div-rem/info.txt b/test/701-easy-div-rem/info.txt
new file mode 100644
index 0000000..56d1786
--- /dev/null
+++ b/test/701-easy-div-rem/info.txt
@@ -0,0 +1 @@
+Simple tests for checking easy division/reminder for int and longs.
diff --git a/test/701-easy-div-rem/src/Main.java b/test/701-easy-div-rem/src/Main.java
new file mode 100644
index 0000000..f995f61
--- /dev/null
+++ b/test/701-easy-div-rem/src/Main.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+    public static int num_errors = 0;
+
+    public static void reportError(String message) {
+        if (num_errors == 10) {
+            System.out.println("Omitting other error messages...");
+        } else if (num_errors < 10) {
+            System.out.println(message);
+        }
+        num_errors += 1;
+    }
+
+    public static void intCheckDiv(String desc, int result, int dividend, int divisor) {
+        int correct_result = dividend / divisor;
+        if (result != correct_result) {
+            reportError(desc + "(" + dividend + ") == " + result +
+                        " should be " + correct_result);
+        }
+    }
+    public static void intCheckRem(String desc, int result, int dividend, int divisor) {
+        int correct_result = dividend % divisor;
+        if (result != correct_result) {
+            reportError(desc + "(" + dividend + ") == " + result +
+                        " should be " + correct_result);
+        }
+    }
+    public static void longCheckDiv(String desc, long result, long dividend, long divisor) {
+        long correct_result = dividend / divisor;
+        if (result != correct_result) {
+            reportError(desc + "(" + dividend + ") == " + result +
+                        " should be " + correct_result);
+        }
+    }
+    public static void longCheckRem(String desc, long result, long dividend, long divisor) {
+        long correct_result = dividend % divisor;
+        if (result != correct_result) {
+            reportError(desc + "(" + dividend + ") == " + result +
+                        " should be " + correct_result);
+        }
+    }
+
+    public static int idiv_by_pow2_0(int x) {return x / 1;}
+    public static int idiv_by_pow2_1(int x) {return x / 2;}
+    public static int idiv_by_pow2_2(int x) {return x / 4;}
+    public static int idiv_by_pow2_3(int x) {return x / 8;}
+    public static int idiv_by_pow2_4(int x) {return x / 16;}
+    public static int idiv_by_pow2_5(int x) {return x / 32;}
+    public static int idiv_by_pow2_6(int x) {return x / 64;}
+    public static int idiv_by_pow2_7(int x) {return x / 128;}
+    public static int idiv_by_pow2_8(int x) {return x / 256;}
+    public static int idiv_by_pow2_9(int x) {return x / 512;}
+    public static int idiv_by_pow2_10(int x) {return x / 1024;}
+    public static int idiv_by_pow2_11(int x) {return x / 2048;}
+    public static int idiv_by_pow2_12(int x) {return x / 4096;}
+    public static int idiv_by_pow2_13(int x) {return x / 8192;}
+    public static int idiv_by_pow2_14(int x) {return x / 16384;}
+    public static int idiv_by_pow2_15(int x) {return x / 32768;}
+    public static int idiv_by_pow2_16(int x) {return x / 65536;}
+    public static int idiv_by_pow2_17(int x) {return x / 131072;}
+    public static int idiv_by_pow2_18(int x) {return x / 262144;}
+    public static int idiv_by_pow2_19(int x) {return x / 524288;}
+    public static int idiv_by_pow2_20(int x) {return x / 1048576;}
+    public static int idiv_by_pow2_21(int x) {return x / 2097152;}
+    public static int idiv_by_pow2_22(int x) {return x / 4194304;}
+    public static int idiv_by_pow2_23(int x) {return x / 8388608;}
+    public static int idiv_by_pow2_24(int x) {return x / 16777216;}
+    public static int idiv_by_pow2_25(int x) {return x / 33554432;}
+    public static int idiv_by_pow2_26(int x) {return x / 67108864;}
+    public static int idiv_by_pow2_27(int x) {return x / 134217728;}
+    public static int idiv_by_pow2_28(int x) {return x / 268435456;}
+    public static int idiv_by_pow2_29(int x) {return x / 536870912;}
+    public static int idiv_by_pow2_30(int x) {return x / 1073741824;}
+    public static int idiv_by_small_0(int x) {return x / 3;}
+    public static int idiv_by_small_1(int x) {return x / 5;}
+    public static int idiv_by_small_2(int x) {return x / 6;}
+    public static int idiv_by_small_3(int x) {return x / 7;}
+    public static int idiv_by_small_4(int x) {return x / 9;}
+    public static int idiv_by_small_5(int x) {return x / 10;}
+    public static int idiv_by_small_6(int x) {return x / 11;}
+    public static int idiv_by_small_7(int x) {return x / 12;}
+    public static int idiv_by_small_8(int x) {return x / 13;}
+    public static int idiv_by_small_9(int x) {return x / 14;}
+    public static int idiv_by_small_10(int x) {return x / 15;}
+    public static int irem_by_pow2_0(int x) {return x % 1;}
+    public static int irem_by_pow2_1(int x) {return x % 2;}
+    public static int irem_by_pow2_2(int x) {return x % 4;}
+    public static int irem_by_pow2_3(int x) {return x % 8;}
+    public static int irem_by_pow2_4(int x) {return x % 16;}
+    public static int irem_by_pow2_5(int x) {return x % 32;}
+    public static int irem_by_pow2_6(int x) {return x % 64;}
+    public static int irem_by_pow2_7(int x) {return x % 128;}
+    public static int irem_by_pow2_8(int x) {return x % 256;}
+    public static int irem_by_pow2_9(int x) {return x % 512;}
+    public static int irem_by_pow2_10(int x) {return x % 1024;}
+    public static int irem_by_pow2_11(int x) {return x % 2048;}
+    public static int irem_by_pow2_12(int x) {return x % 4096;}
+    public static int irem_by_pow2_13(int x) {return x % 8192;}
+    public static int irem_by_pow2_14(int x) {return x % 16384;}
+    public static int irem_by_pow2_15(int x) {return x % 32768;}
+    public static int irem_by_pow2_16(int x) {return x % 65536;}
+    public static int irem_by_pow2_17(int x) {return x % 131072;}
+    public static int irem_by_pow2_18(int x) {return x % 262144;}
+    public static int irem_by_pow2_19(int x) {return x % 524288;}
+    public static int irem_by_pow2_20(int x) {return x % 1048576;}
+    public static int irem_by_pow2_21(int x) {return x % 2097152;}
+    public static int irem_by_pow2_22(int x) {return x % 4194304;}
+    public static int irem_by_pow2_23(int x) {return x % 8388608;}
+    public static int irem_by_pow2_24(int x) {return x % 16777216;}
+    public static int irem_by_pow2_25(int x) {return x % 33554432;}
+    public static int irem_by_pow2_26(int x) {return x % 67108864;}
+    public static int irem_by_pow2_27(int x) {return x % 134217728;}
+    public static int irem_by_pow2_28(int x) {return x % 268435456;}
+    public static int irem_by_pow2_29(int x) {return x % 536870912;}
+    public static int irem_by_pow2_30(int x) {return x % 1073741824;}
+    public static long ldiv_by_pow2_0(long x) {return x / 1l;}
+    public static long ldiv_by_pow2_1(long x) {return x / 2l;}
+    public static long ldiv_by_pow2_2(long x) {return x / 4l;}
+    public static long ldiv_by_pow2_3(long x) {return x / 8l;}
+    public static long ldiv_by_pow2_4(long x) {return x / 16l;}
+    public static long ldiv_by_pow2_5(long x) {return x / 32l;}
+    public static long ldiv_by_pow2_6(long x) {return x / 64l;}
+    public static long ldiv_by_pow2_7(long x) {return x / 128l;}
+    public static long ldiv_by_pow2_8(long x) {return x / 256l;}
+    public static long ldiv_by_pow2_9(long x) {return x / 512l;}
+    public static long ldiv_by_pow2_10(long x) {return x / 1024l;}
+    public static long ldiv_by_pow2_11(long x) {return x / 2048l;}
+    public static long ldiv_by_pow2_12(long x) {return x / 4096l;}
+    public static long ldiv_by_pow2_13(long x) {return x / 8192l;}
+    public static long ldiv_by_pow2_14(long x) {return x / 16384l;}
+    public static long ldiv_by_pow2_15(long x) {return x / 32768l;}
+    public static long ldiv_by_pow2_16(long x) {return x / 65536l;}
+    public static long ldiv_by_pow2_17(long x) {return x / 131072l;}
+    public static long ldiv_by_pow2_18(long x) {return x / 262144l;}
+    public static long ldiv_by_pow2_19(long x) {return x / 524288l;}
+    public static long ldiv_by_pow2_20(long x) {return x / 1048576l;}
+    public static long ldiv_by_pow2_21(long x) {return x / 2097152l;}
+    public static long ldiv_by_pow2_22(long x) {return x / 4194304l;}
+    public static long ldiv_by_pow2_23(long x) {return x / 8388608l;}
+    public static long ldiv_by_pow2_24(long x) {return x / 16777216l;}
+    public static long ldiv_by_pow2_25(long x) {return x / 33554432l;}
+    public static long ldiv_by_pow2_26(long x) {return x / 67108864l;}
+    public static long ldiv_by_pow2_27(long x) {return x / 134217728l;}
+    public static long ldiv_by_pow2_28(long x) {return x / 268435456l;}
+    public static long ldiv_by_pow2_29(long x) {return x / 536870912l;}
+    public static long ldiv_by_pow2_30(long x) {return x / 1073741824l;}
+    public static long ldiv_by_pow2_31(long x) {return x / 2147483648l;}
+    public static long ldiv_by_pow2_32(long x) {return x / 4294967296l;}
+    public static long ldiv_by_pow2_33(long x) {return x / 8589934592l;}
+    public static long ldiv_by_pow2_34(long x) {return x / 17179869184l;}
+    public static long ldiv_by_pow2_35(long x) {return x / 34359738368l;}
+    public static long ldiv_by_pow2_36(long x) {return x / 68719476736l;}
+    public static long ldiv_by_pow2_37(long x) {return x / 137438953472l;}
+    public static long ldiv_by_pow2_38(long x) {return x / 274877906944l;}
+    public static long ldiv_by_pow2_39(long x) {return x / 549755813888l;}
+    public static long ldiv_by_pow2_40(long x) {return x / 1099511627776l;}
+    public static long ldiv_by_pow2_41(long x) {return x / 2199023255552l;}
+    public static long ldiv_by_pow2_42(long x) {return x / 4398046511104l;}
+    public static long ldiv_by_pow2_43(long x) {return x / 8796093022208l;}
+    public static long ldiv_by_pow2_44(long x) {return x / 17592186044416l;}
+    public static long ldiv_by_pow2_45(long x) {return x / 35184372088832l;}
+    public static long ldiv_by_pow2_46(long x) {return x / 70368744177664l;}
+    public static long ldiv_by_pow2_47(long x) {return x / 140737488355328l;}
+    public static long ldiv_by_pow2_48(long x) {return x / 281474976710656l;}
+    public static long ldiv_by_pow2_49(long x) {return x / 562949953421312l;}
+    public static long ldiv_by_pow2_50(long x) {return x / 1125899906842624l;}
+    public static long ldiv_by_pow2_51(long x) {return x / 2251799813685248l;}
+    public static long ldiv_by_pow2_52(long x) {return x / 4503599627370496l;}
+    public static long ldiv_by_pow2_53(long x) {return x / 9007199254740992l;}
+    public static long ldiv_by_pow2_54(long x) {return x / 18014398509481984l;}
+    public static long ldiv_by_pow2_55(long x) {return x / 36028797018963968l;}
+    public static long ldiv_by_pow2_56(long x) {return x / 72057594037927936l;}
+    public static long ldiv_by_pow2_57(long x) {return x / 144115188075855872l;}
+    public static long ldiv_by_pow2_58(long x) {return x / 288230376151711744l;}
+    public static long ldiv_by_pow2_59(long x) {return x / 576460752303423488l;}
+    public static long ldiv_by_pow2_60(long x) {return x / 1152921504606846976l;}
+    public static long ldiv_by_pow2_61(long x) {return x / 2305843009213693952l;}
+    public static long ldiv_by_pow2_62(long x) {return x / 4611686018427387904l;}
+    public static long ldiv_by_small_0(long x) {return x / 3l;}
+    public static long ldiv_by_small_1(long x) {return x / 5l;}
+    public static long ldiv_by_small_2(long x) {return x / 6l;}
+    public static long ldiv_by_small_3(long x) {return x / 7l;}
+    public static long ldiv_by_small_4(long x) {return x / 9l;}
+    public static long ldiv_by_small_5(long x) {return x / 10l;}
+    public static long ldiv_by_small_6(long x) {return x / 11l;}
+    public static long ldiv_by_small_7(long x) {return x / 12l;}
+    public static long ldiv_by_small_8(long x) {return x / 13l;}
+    public static long ldiv_by_small_9(long x) {return x / 14l;}
+    public static long ldiv_by_small_10(long x) {return x / 15l;}
+    public static long lrem_by_pow2_0(long x) {return x % 1l;}
+    public static long lrem_by_pow2_1(long x) {return x % 2l;}
+    public static long lrem_by_pow2_2(long x) {return x % 4l;}
+    public static long lrem_by_pow2_3(long x) {return x % 8l;}
+    public static long lrem_by_pow2_4(long x) {return x % 16l;}
+    public static long lrem_by_pow2_5(long x) {return x % 32l;}
+    public static long lrem_by_pow2_6(long x) {return x % 64l;}
+    public static long lrem_by_pow2_7(long x) {return x % 128l;}
+    public static long lrem_by_pow2_8(long x) {return x % 256l;}
+    public static long lrem_by_pow2_9(long x) {return x % 512l;}
+    public static long lrem_by_pow2_10(long x) {return x % 1024l;}
+    public static long lrem_by_pow2_11(long x) {return x % 2048l;}
+    public static long lrem_by_pow2_12(long x) {return x % 4096l;}
+    public static long lrem_by_pow2_13(long x) {return x % 8192l;}
+    public static long lrem_by_pow2_14(long x) {return x % 16384l;}
+    public static long lrem_by_pow2_15(long x) {return x % 32768l;}
+    public static long lrem_by_pow2_16(long x) {return x % 65536l;}
+    public static long lrem_by_pow2_17(long x) {return x % 131072l;}
+    public static long lrem_by_pow2_18(long x) {return x % 262144l;}
+    public static long lrem_by_pow2_19(long x) {return x % 524288l;}
+    public static long lrem_by_pow2_20(long x) {return x % 1048576l;}
+    public static long lrem_by_pow2_21(long x) {return x % 2097152l;}
+    public static long lrem_by_pow2_22(long x) {return x % 4194304l;}
+    public static long lrem_by_pow2_23(long x) {return x % 8388608l;}
+    public static long lrem_by_pow2_24(long x) {return x % 16777216l;}
+    public static long lrem_by_pow2_25(long x) {return x % 33554432l;}
+    public static long lrem_by_pow2_26(long x) {return x % 67108864l;}
+    public static long lrem_by_pow2_27(long x) {return x % 134217728l;}
+    public static long lrem_by_pow2_28(long x) {return x % 268435456l;}
+    public static long lrem_by_pow2_29(long x) {return x % 536870912l;}
+    public static long lrem_by_pow2_30(long x) {return x % 1073741824l;}
+    public static long lrem_by_pow2_31(long x) {return x % 2147483648l;}
+    public static long lrem_by_pow2_32(long x) {return x % 4294967296l;}
+    public static long lrem_by_pow2_33(long x) {return x % 8589934592l;}
+    public static long lrem_by_pow2_34(long x) {return x % 17179869184l;}
+    public static long lrem_by_pow2_35(long x) {return x % 34359738368l;}
+    public static long lrem_by_pow2_36(long x) {return x % 68719476736l;}
+    public static long lrem_by_pow2_37(long x) {return x % 137438953472l;}
+    public static long lrem_by_pow2_38(long x) {return x % 274877906944l;}
+    public static long lrem_by_pow2_39(long x) {return x % 549755813888l;}
+    public static long lrem_by_pow2_40(long x) {return x % 1099511627776l;}
+    public static long lrem_by_pow2_41(long x) {return x % 2199023255552l;}
+    public static long lrem_by_pow2_42(long x) {return x % 4398046511104l;}
+    public static long lrem_by_pow2_43(long x) {return x % 8796093022208l;}
+    public static long lrem_by_pow2_44(long x) {return x % 17592186044416l;}
+    public static long lrem_by_pow2_45(long x) {return x % 35184372088832l;}
+    public static long lrem_by_pow2_46(long x) {return x % 70368744177664l;}
+    public static long lrem_by_pow2_47(long x) {return x % 140737488355328l;}
+    public static long lrem_by_pow2_48(long x) {return x % 281474976710656l;}
+    public static long lrem_by_pow2_49(long x) {return x % 562949953421312l;}
+    public static long lrem_by_pow2_50(long x) {return x % 1125899906842624l;}
+    public static long lrem_by_pow2_51(long x) {return x % 2251799813685248l;}
+    public static long lrem_by_pow2_52(long x) {return x % 4503599627370496l;}
+    public static long lrem_by_pow2_53(long x) {return x % 9007199254740992l;}
+    public static long lrem_by_pow2_54(long x) {return x % 18014398509481984l;}
+    public static long lrem_by_pow2_55(long x) {return x % 36028797018963968l;}
+    public static long lrem_by_pow2_56(long x) {return x % 72057594037927936l;}
+    public static long lrem_by_pow2_57(long x) {return x % 144115188075855872l;}
+    public static long lrem_by_pow2_58(long x) {return x % 288230376151711744l;}
+    public static long lrem_by_pow2_59(long x) {return x % 576460752303423488l;}
+    public static long lrem_by_pow2_60(long x) {return x % 1152921504606846976l;}
+    public static long lrem_by_pow2_61(long x) {return x % 2305843009213693952l;}
+    public static long lrem_by_pow2_62(long x) {return x % 4611686018427387904l;}
+
+    public static void intCheckAll(int x) {
+        intCheckDiv("idiv_by_pow2_0", idiv_by_pow2_0(x), x, 1);
+        intCheckDiv("idiv_by_pow2_1", idiv_by_pow2_1(x), x, 2);
+        intCheckDiv("idiv_by_pow2_2", idiv_by_pow2_2(x), x, 4);
+        intCheckDiv("idiv_by_pow2_3", idiv_by_pow2_3(x), x, 8);
+        intCheckDiv("idiv_by_pow2_4", idiv_by_pow2_4(x), x, 16);
+        intCheckDiv("idiv_by_pow2_5", idiv_by_pow2_5(x), x, 32);
+        intCheckDiv("idiv_by_pow2_6", idiv_by_pow2_6(x), x, 64);
+        intCheckDiv("idiv_by_pow2_7", idiv_by_pow2_7(x), x, 128);
+        intCheckDiv("idiv_by_pow2_8", idiv_by_pow2_8(x), x, 256);
+        intCheckDiv("idiv_by_pow2_9", idiv_by_pow2_9(x), x, 512);
+        intCheckDiv("idiv_by_pow2_10", idiv_by_pow2_10(x), x, 1024);
+        intCheckDiv("idiv_by_pow2_11", idiv_by_pow2_11(x), x, 2048);
+        intCheckDiv("idiv_by_pow2_12", idiv_by_pow2_12(x), x, 4096);
+        intCheckDiv("idiv_by_pow2_13", idiv_by_pow2_13(x), x, 8192);
+        intCheckDiv("idiv_by_pow2_14", idiv_by_pow2_14(x), x, 16384);
+        intCheckDiv("idiv_by_pow2_15", idiv_by_pow2_15(x), x, 32768);
+        intCheckDiv("idiv_by_pow2_16", idiv_by_pow2_16(x), x, 65536);
+        intCheckDiv("idiv_by_pow2_17", idiv_by_pow2_17(x), x, 131072);
+        intCheckDiv("idiv_by_pow2_18", idiv_by_pow2_18(x), x, 262144);
+        intCheckDiv("idiv_by_pow2_19", idiv_by_pow2_19(x), x, 524288);
+        intCheckDiv("idiv_by_pow2_20", idiv_by_pow2_20(x), x, 1048576);
+        intCheckDiv("idiv_by_pow2_21", idiv_by_pow2_21(x), x, 2097152);
+        intCheckDiv("idiv_by_pow2_22", idiv_by_pow2_22(x), x, 4194304);
+        intCheckDiv("idiv_by_pow2_23", idiv_by_pow2_23(x), x, 8388608);
+        intCheckDiv("idiv_by_pow2_24", idiv_by_pow2_24(x), x, 16777216);
+        intCheckDiv("idiv_by_pow2_25", idiv_by_pow2_25(x), x, 33554432);
+        intCheckDiv("idiv_by_pow2_26", idiv_by_pow2_26(x), x, 67108864);
+        intCheckDiv("idiv_by_pow2_27", idiv_by_pow2_27(x), x, 134217728);
+        intCheckDiv("idiv_by_pow2_28", idiv_by_pow2_28(x), x, 268435456);
+        intCheckDiv("idiv_by_pow2_29", idiv_by_pow2_29(x), x, 536870912);
+        intCheckDiv("idiv_by_pow2_30", idiv_by_pow2_30(x), x, 1073741824);
+        intCheckDiv("idiv_by_small_0", idiv_by_small_0(x), x, 3);
+        intCheckDiv("idiv_by_small_1", idiv_by_small_1(x), x, 5);
+        intCheckDiv("idiv_by_small_2", idiv_by_small_2(x), x, 6);
+        intCheckDiv("idiv_by_small_3", idiv_by_small_3(x), x, 7);
+        intCheckDiv("idiv_by_small_4", idiv_by_small_4(x), x, 9);
+        intCheckDiv("idiv_by_small_5", idiv_by_small_5(x), x, 10);
+        intCheckDiv("idiv_by_small_6", idiv_by_small_6(x), x, 11);
+        intCheckDiv("idiv_by_small_7", idiv_by_small_7(x), x, 12);
+        intCheckDiv("idiv_by_small_8", idiv_by_small_8(x), x, 13);
+        intCheckDiv("idiv_by_small_9", idiv_by_small_9(x), x, 14);
+        intCheckDiv("idiv_by_small_10", idiv_by_small_10(x), x, 15);
+        intCheckRem("irem_by_pow2_0", irem_by_pow2_0(x), x, 1);
+        intCheckRem("irem_by_pow2_1", irem_by_pow2_1(x), x, 2);
+        intCheckRem("irem_by_pow2_2", irem_by_pow2_2(x), x, 4);
+        intCheckRem("irem_by_pow2_3", irem_by_pow2_3(x), x, 8);
+        intCheckRem("irem_by_pow2_4", irem_by_pow2_4(x), x, 16);
+        intCheckRem("irem_by_pow2_5", irem_by_pow2_5(x), x, 32);
+        intCheckRem("irem_by_pow2_6", irem_by_pow2_6(x), x, 64);
+        intCheckRem("irem_by_pow2_7", irem_by_pow2_7(x), x, 128);
+        intCheckRem("irem_by_pow2_8", irem_by_pow2_8(x), x, 256);
+        intCheckRem("irem_by_pow2_9", irem_by_pow2_9(x), x, 512);
+        intCheckRem("irem_by_pow2_10", irem_by_pow2_10(x), x, 1024);
+        intCheckRem("irem_by_pow2_11", irem_by_pow2_11(x), x, 2048);
+        intCheckRem("irem_by_pow2_12", irem_by_pow2_12(x), x, 4096);
+        intCheckRem("irem_by_pow2_13", irem_by_pow2_13(x), x, 8192);
+        intCheckRem("irem_by_pow2_14", irem_by_pow2_14(x), x, 16384);
+        intCheckRem("irem_by_pow2_15", irem_by_pow2_15(x), x, 32768);
+        intCheckRem("irem_by_pow2_16", irem_by_pow2_16(x), x, 65536);
+        intCheckRem("irem_by_pow2_17", irem_by_pow2_17(x), x, 131072);
+        intCheckRem("irem_by_pow2_18", irem_by_pow2_18(x), x, 262144);
+        intCheckRem("irem_by_pow2_19", irem_by_pow2_19(x), x, 524288);
+        intCheckRem("irem_by_pow2_20", irem_by_pow2_20(x), x, 1048576);
+        intCheckRem("irem_by_pow2_21", irem_by_pow2_21(x), x, 2097152);
+        intCheckRem("irem_by_pow2_22", irem_by_pow2_22(x), x, 4194304);
+        intCheckRem("irem_by_pow2_23", irem_by_pow2_23(x), x, 8388608);
+        intCheckRem("irem_by_pow2_24", irem_by_pow2_24(x), x, 16777216);
+        intCheckRem("irem_by_pow2_25", irem_by_pow2_25(x), x, 33554432);
+        intCheckRem("irem_by_pow2_26", irem_by_pow2_26(x), x, 67108864);
+        intCheckRem("irem_by_pow2_27", irem_by_pow2_27(x), x, 134217728);
+        intCheckRem("irem_by_pow2_28", irem_by_pow2_28(x), x, 268435456);
+        intCheckRem("irem_by_pow2_29", irem_by_pow2_29(x), x, 536870912);
+        intCheckRem("irem_by_pow2_30", irem_by_pow2_30(x), x, 1073741824);
+    }
+
+    public static void longCheckAll(long x) {
+        longCheckDiv("ldiv_by_pow2_0", ldiv_by_pow2_0(x), x, 1l);
+        longCheckDiv("ldiv_by_pow2_1", ldiv_by_pow2_1(x), x, 2l);
+        longCheckDiv("ldiv_by_pow2_2", ldiv_by_pow2_2(x), x, 4l);
+        longCheckDiv("ldiv_by_pow2_3", ldiv_by_pow2_3(x), x, 8l);
+        longCheckDiv("ldiv_by_pow2_4", ldiv_by_pow2_4(x), x, 16l);
+        longCheckDiv("ldiv_by_pow2_5", ldiv_by_pow2_5(x), x, 32l);
+        longCheckDiv("ldiv_by_pow2_6", ldiv_by_pow2_6(x), x, 64l);
+        longCheckDiv("ldiv_by_pow2_7", ldiv_by_pow2_7(x), x, 128l);
+        longCheckDiv("ldiv_by_pow2_8", ldiv_by_pow2_8(x), x, 256l);
+        longCheckDiv("ldiv_by_pow2_9", ldiv_by_pow2_9(x), x, 512l);
+        longCheckDiv("ldiv_by_pow2_10", ldiv_by_pow2_10(x), x, 1024l);
+        longCheckDiv("ldiv_by_pow2_11", ldiv_by_pow2_11(x), x, 2048l);
+        longCheckDiv("ldiv_by_pow2_12", ldiv_by_pow2_12(x), x, 4096l);
+        longCheckDiv("ldiv_by_pow2_13", ldiv_by_pow2_13(x), x, 8192l);
+        longCheckDiv("ldiv_by_pow2_14", ldiv_by_pow2_14(x), x, 16384l);
+        longCheckDiv("ldiv_by_pow2_15", ldiv_by_pow2_15(x), x, 32768l);
+        longCheckDiv("ldiv_by_pow2_16", ldiv_by_pow2_16(x), x, 65536l);
+        longCheckDiv("ldiv_by_pow2_17", ldiv_by_pow2_17(x), x, 131072l);
+        longCheckDiv("ldiv_by_pow2_18", ldiv_by_pow2_18(x), x, 262144l);
+        longCheckDiv("ldiv_by_pow2_19", ldiv_by_pow2_19(x), x, 524288l);
+        longCheckDiv("ldiv_by_pow2_20", ldiv_by_pow2_20(x), x, 1048576l);
+        longCheckDiv("ldiv_by_pow2_21", ldiv_by_pow2_21(x), x, 2097152l);
+        longCheckDiv("ldiv_by_pow2_22", ldiv_by_pow2_22(x), x, 4194304l);
+        longCheckDiv("ldiv_by_pow2_23", ldiv_by_pow2_23(x), x, 8388608l);
+        longCheckDiv("ldiv_by_pow2_24", ldiv_by_pow2_24(x), x, 16777216l);
+        longCheckDiv("ldiv_by_pow2_25", ldiv_by_pow2_25(x), x, 33554432l);
+        longCheckDiv("ldiv_by_pow2_26", ldiv_by_pow2_26(x), x, 67108864l);
+        longCheckDiv("ldiv_by_pow2_27", ldiv_by_pow2_27(x), x, 134217728l);
+        longCheckDiv("ldiv_by_pow2_28", ldiv_by_pow2_28(x), x, 268435456l);
+        longCheckDiv("ldiv_by_pow2_29", ldiv_by_pow2_29(x), x, 536870912l);
+        longCheckDiv("ldiv_by_pow2_30", ldiv_by_pow2_30(x), x, 1073741824l);
+        longCheckDiv("ldiv_by_pow2_31", ldiv_by_pow2_31(x), x, 2147483648l);
+        longCheckDiv("ldiv_by_pow2_32", ldiv_by_pow2_32(x), x, 4294967296l);
+        longCheckDiv("ldiv_by_pow2_33", ldiv_by_pow2_33(x), x, 8589934592l);
+        longCheckDiv("ldiv_by_pow2_34", ldiv_by_pow2_34(x), x, 17179869184l);
+        longCheckDiv("ldiv_by_pow2_35", ldiv_by_pow2_35(x), x, 34359738368l);
+        longCheckDiv("ldiv_by_pow2_36", ldiv_by_pow2_36(x), x, 68719476736l);
+        longCheckDiv("ldiv_by_pow2_37", ldiv_by_pow2_37(x), x, 137438953472l);
+        longCheckDiv("ldiv_by_pow2_38", ldiv_by_pow2_38(x), x, 274877906944l);
+        longCheckDiv("ldiv_by_pow2_39", ldiv_by_pow2_39(x), x, 549755813888l);
+        longCheckDiv("ldiv_by_pow2_40", ldiv_by_pow2_40(x), x, 1099511627776l);
+        longCheckDiv("ldiv_by_pow2_41", ldiv_by_pow2_41(x), x, 2199023255552l);
+        longCheckDiv("ldiv_by_pow2_42", ldiv_by_pow2_42(x), x, 4398046511104l);
+        longCheckDiv("ldiv_by_pow2_43", ldiv_by_pow2_43(x), x, 8796093022208l);
+        longCheckDiv("ldiv_by_pow2_44", ldiv_by_pow2_44(x), x, 17592186044416l);
+        longCheckDiv("ldiv_by_pow2_45", ldiv_by_pow2_45(x), x, 35184372088832l);
+        longCheckDiv("ldiv_by_pow2_46", ldiv_by_pow2_46(x), x, 70368744177664l);
+        longCheckDiv("ldiv_by_pow2_47", ldiv_by_pow2_47(x), x, 140737488355328l);
+        longCheckDiv("ldiv_by_pow2_48", ldiv_by_pow2_48(x), x, 281474976710656l);
+        longCheckDiv("ldiv_by_pow2_49", ldiv_by_pow2_49(x), x, 562949953421312l);
+        longCheckDiv("ldiv_by_pow2_50", ldiv_by_pow2_50(x), x, 1125899906842624l);
+        longCheckDiv("ldiv_by_pow2_51", ldiv_by_pow2_51(x), x, 2251799813685248l);
+        longCheckDiv("ldiv_by_pow2_52", ldiv_by_pow2_52(x), x, 4503599627370496l);
+        longCheckDiv("ldiv_by_pow2_53", ldiv_by_pow2_53(x), x, 9007199254740992l);
+        longCheckDiv("ldiv_by_pow2_54", ldiv_by_pow2_54(x), x, 18014398509481984l);
+        longCheckDiv("ldiv_by_pow2_55", ldiv_by_pow2_55(x), x, 36028797018963968l);
+        longCheckDiv("ldiv_by_pow2_56", ldiv_by_pow2_56(x), x, 72057594037927936l);
+        longCheckDiv("ldiv_by_pow2_57", ldiv_by_pow2_57(x), x, 144115188075855872l);
+        longCheckDiv("ldiv_by_pow2_58", ldiv_by_pow2_58(x), x, 288230376151711744l);
+        longCheckDiv("ldiv_by_pow2_59", ldiv_by_pow2_59(x), x, 576460752303423488l);
+        longCheckDiv("ldiv_by_pow2_60", ldiv_by_pow2_60(x), x, 1152921504606846976l);
+        longCheckDiv("ldiv_by_pow2_61", ldiv_by_pow2_61(x), x, 2305843009213693952l);
+        longCheckDiv("ldiv_by_pow2_62", ldiv_by_pow2_62(x), x, 4611686018427387904l);
+        longCheckDiv("ldiv_by_small_0", ldiv_by_small_0(x), x, 3l);
+        longCheckDiv("ldiv_by_small_1", ldiv_by_small_1(x), x, 5l);
+        longCheckDiv("ldiv_by_small_2", ldiv_by_small_2(x), x, 6l);
+        longCheckDiv("ldiv_by_small_3", ldiv_by_small_3(x), x, 7l);
+        longCheckDiv("ldiv_by_small_4", ldiv_by_small_4(x), x, 9l);
+        longCheckDiv("ldiv_by_small_5", ldiv_by_small_5(x), x, 10l);
+        longCheckDiv("ldiv_by_small_6", ldiv_by_small_6(x), x, 11l);
+        longCheckDiv("ldiv_by_small_7", ldiv_by_small_7(x), x, 12l);
+        longCheckDiv("ldiv_by_small_8", ldiv_by_small_8(x), x, 13l);
+        longCheckDiv("ldiv_by_small_9", ldiv_by_small_9(x), x, 14l);
+        longCheckDiv("ldiv_by_small_10", ldiv_by_small_10(x), x, 15l);
+        longCheckRem("lrem_by_pow2_0", lrem_by_pow2_0(x), x, 1l);
+        longCheckRem("lrem_by_pow2_1", lrem_by_pow2_1(x), x, 2l);
+        longCheckRem("lrem_by_pow2_2", lrem_by_pow2_2(x), x, 4l);
+        longCheckRem("lrem_by_pow2_3", lrem_by_pow2_3(x), x, 8l);
+        longCheckRem("lrem_by_pow2_4", lrem_by_pow2_4(x), x, 16l);
+        longCheckRem("lrem_by_pow2_5", lrem_by_pow2_5(x), x, 32l);
+        longCheckRem("lrem_by_pow2_6", lrem_by_pow2_6(x), x, 64l);
+        longCheckRem("lrem_by_pow2_7", lrem_by_pow2_7(x), x, 128l);
+        longCheckRem("lrem_by_pow2_8", lrem_by_pow2_8(x), x, 256l);
+        longCheckRem("lrem_by_pow2_9", lrem_by_pow2_9(x), x, 512l);
+        longCheckRem("lrem_by_pow2_10", lrem_by_pow2_10(x), x, 1024l);
+        longCheckRem("lrem_by_pow2_11", lrem_by_pow2_11(x), x, 2048l);
+        longCheckRem("lrem_by_pow2_12", lrem_by_pow2_12(x), x, 4096l);
+        longCheckRem("lrem_by_pow2_13", lrem_by_pow2_13(x), x, 8192l);
+        longCheckRem("lrem_by_pow2_14", lrem_by_pow2_14(x), x, 16384l);
+        longCheckRem("lrem_by_pow2_15", lrem_by_pow2_15(x), x, 32768l);
+        longCheckRem("lrem_by_pow2_16", lrem_by_pow2_16(x), x, 65536l);
+        longCheckRem("lrem_by_pow2_17", lrem_by_pow2_17(x), x, 131072l);
+        longCheckRem("lrem_by_pow2_18", lrem_by_pow2_18(x), x, 262144l);
+        longCheckRem("lrem_by_pow2_19", lrem_by_pow2_19(x), x, 524288l);
+        longCheckRem("lrem_by_pow2_20", lrem_by_pow2_20(x), x, 1048576l);
+        longCheckRem("lrem_by_pow2_21", lrem_by_pow2_21(x), x, 2097152l);
+        longCheckRem("lrem_by_pow2_22", lrem_by_pow2_22(x), x, 4194304l);
+        longCheckRem("lrem_by_pow2_23", lrem_by_pow2_23(x), x, 8388608l);
+        longCheckRem("lrem_by_pow2_24", lrem_by_pow2_24(x), x, 16777216l);
+        longCheckRem("lrem_by_pow2_25", lrem_by_pow2_25(x), x, 33554432l);
+        longCheckRem("lrem_by_pow2_26", lrem_by_pow2_26(x), x, 67108864l);
+        longCheckRem("lrem_by_pow2_27", lrem_by_pow2_27(x), x, 134217728l);
+        longCheckRem("lrem_by_pow2_28", lrem_by_pow2_28(x), x, 268435456l);
+        longCheckRem("lrem_by_pow2_29", lrem_by_pow2_29(x), x, 536870912l);
+        longCheckRem("lrem_by_pow2_30", lrem_by_pow2_30(x), x, 1073741824l);
+        longCheckRem("lrem_by_pow2_31", lrem_by_pow2_31(x), x, 2147483648l);
+        longCheckRem("lrem_by_pow2_32", lrem_by_pow2_32(x), x, 4294967296l);
+        longCheckRem("lrem_by_pow2_33", lrem_by_pow2_33(x), x, 8589934592l);
+        longCheckRem("lrem_by_pow2_34", lrem_by_pow2_34(x), x, 17179869184l);
+        longCheckRem("lrem_by_pow2_35", lrem_by_pow2_35(x), x, 34359738368l);
+        longCheckRem("lrem_by_pow2_36", lrem_by_pow2_36(x), x, 68719476736l);
+        longCheckRem("lrem_by_pow2_37", lrem_by_pow2_37(x), x, 137438953472l);
+        longCheckRem("lrem_by_pow2_38", lrem_by_pow2_38(x), x, 274877906944l);
+        longCheckRem("lrem_by_pow2_39", lrem_by_pow2_39(x), x, 549755813888l);
+        longCheckRem("lrem_by_pow2_40", lrem_by_pow2_40(x), x, 1099511627776l);
+        longCheckRem("lrem_by_pow2_41", lrem_by_pow2_41(x), x, 2199023255552l);
+        longCheckRem("lrem_by_pow2_42", lrem_by_pow2_42(x), x, 4398046511104l);
+        longCheckRem("lrem_by_pow2_43", lrem_by_pow2_43(x), x, 8796093022208l);
+        longCheckRem("lrem_by_pow2_44", lrem_by_pow2_44(x), x, 17592186044416l);
+        longCheckRem("lrem_by_pow2_45", lrem_by_pow2_45(x), x, 35184372088832l);
+        longCheckRem("lrem_by_pow2_46", lrem_by_pow2_46(x), x, 70368744177664l);
+        longCheckRem("lrem_by_pow2_47", lrem_by_pow2_47(x), x, 140737488355328l);
+        longCheckRem("lrem_by_pow2_48", lrem_by_pow2_48(x), x, 281474976710656l);
+        longCheckRem("lrem_by_pow2_49", lrem_by_pow2_49(x), x, 562949953421312l);
+        longCheckRem("lrem_by_pow2_50", lrem_by_pow2_50(x), x, 1125899906842624l);
+        longCheckRem("lrem_by_pow2_51", lrem_by_pow2_51(x), x, 2251799813685248l);
+        longCheckRem("lrem_by_pow2_52", lrem_by_pow2_52(x), x, 4503599627370496l);
+        longCheckRem("lrem_by_pow2_53", lrem_by_pow2_53(x), x, 9007199254740992l);
+        longCheckRem("lrem_by_pow2_54", lrem_by_pow2_54(x), x, 18014398509481984l);
+        longCheckRem("lrem_by_pow2_55", lrem_by_pow2_55(x), x, 36028797018963968l);
+        longCheckRem("lrem_by_pow2_56", lrem_by_pow2_56(x), x, 72057594037927936l);
+        longCheckRem("lrem_by_pow2_57", lrem_by_pow2_57(x), x, 144115188075855872l);
+        longCheckRem("lrem_by_pow2_58", lrem_by_pow2_58(x), x, 288230376151711744l);
+        longCheckRem("lrem_by_pow2_59", lrem_by_pow2_59(x), x, 576460752303423488l);
+        longCheckRem("lrem_by_pow2_60", lrem_by_pow2_60(x), x, 1152921504606846976l);
+        longCheckRem("lrem_by_pow2_61", lrem_by_pow2_61(x), x, 2305843009213693952l);
+        longCheckRem("lrem_by_pow2_62", lrem_by_pow2_62(x), x, 4611686018427387904l);
+    }
+
+    public static void main(String[] args) {
+      int i;
+      long l;
+
+      System.out.println("Begin");
+
+      System.out.println("Int: checking some equally spaced dividends...");
+      for (i = -1000; i < 1000; i += 300) {
+          intCheckAll(i);
+          intCheckAll(-i);
+      }
+
+      System.out.println("Int: checking small dividends...");
+      for (i = 1; i < 100; i += 1) {
+          intCheckAll(i);
+          intCheckAll(-i);
+      }
+
+      System.out.println("Int: checking big dividends...");
+      for (i = 0; i < 100; i += 1) {
+          intCheckAll(Integer.MAX_VALUE - i);
+          intCheckAll(Integer.MIN_VALUE + i);
+      }
+
+      System.out.println("Long: checking some equally spaced dividends...");
+      for (l = 0l; l < 1000000000000l; l += 300000000000l) {
+          longCheckAll(l);
+          longCheckAll(-l);
+      }
+
+      System.out.println("Long: checking small dividends...");
+      for (l = 1l; l < 100l; l += 1l) {
+          longCheckAll(l);
+          longCheckAll(-l);
+      }
+
+      System.out.println("Long: checking big dividends...");
+      for (l = 0l; l < 100l; l += 1l) {
+          longCheckAll(Long.MAX_VALUE - l);
+          longCheckAll(Long.MIN_VALUE + l);
+      }
+
+      System.out.println("End");
+    }
+}