diff options
Diffstat (limited to 'compiler/dex/quick')
| -rw-r--r-- | compiler/dex/quick/arm/codegen_arm.h | 3 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/int_arm.cc | 11 | ||||
| -rw-r--r-- | compiler/dex/quick/gen_common.cc | 6 | ||||
| -rw-r--r-- | compiler/dex/quick/mips/codegen_mips.h | 3 | ||||
| -rw-r--r-- | compiler/dex/quick/mips/int_mips.cc | 11 | ||||
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 19 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 9 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 28 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/int_x86.cc | 243 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/x86_lir.h | 1 | 
10 files changed, 330 insertions, 4 deletions
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index bf85d9163e..10cff38872 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -195,6 +195,9 @@ class ArmMir2Lir : public Mir2Lir {      void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);      void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);      void AssignDataOffsets(); +    RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                          RegLocation rl_src2, bool is_div, bool check_zero); +    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);  };  }  // namespace art diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index e02382bbc5..71c3492db4 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -444,6 +444,17 @@ LIR* ArmMir2Lir::GenRegMemCheck(ConditionCode c_code,    return NULL;  } +RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                      RegLocation rl_src2, bool is_div, bool check_zero) { +  LOG(FATAL) << "Unexpected use of GenDivRem for Arm"; +  return rl_dest; +} + +RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) { +  LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm"; +  return rl_dest; +} +  RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,                                       bool is_div) {    RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index f2807c6209..1f00b2a6a5 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1382,6 +1382,9 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,        }        rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);        done = true; +    } else if (cu_->instruction_set == kX86) { +      rl_result = GenDivRem(rl_dest, rl_src1, rl_src2, op == kOpDiv, check_zero); +      done = true;      } else if (cu_->instruction_set == kThumb2) {        if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {          // Use ARM SDIV instruction for division.  For remainder we also need to @@ -1650,6 +1653,9 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re          rl_src = LoadValue(rl_src, kCoreReg);          rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);          done = true; +      } else if (cu_->instruction_set == kX86) { +        rl_result = GenDivRemLit(rl_dest, rl_src, lit, is_div); +        done = true;        } else if (cu_->instruction_set == kThumb2) {          if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {            // Use ARM SDIV instruction for division.  For remainder we also need to diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 1f99e10f31..aca93f51d3 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -175,6 +175,9 @@ class MipsMir2Lir : public Mir2Lir {    private:      void ConvertShortToLongBranch(LIR* lir); +    RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                          RegLocation rl_src2, bool is_div, bool check_zero); +    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);  };  }  // namespace art diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc index 3410ecb398..013041a9a5 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -250,6 +250,17 @@ RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,    return rl_result;  } +RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                      RegLocation rl_src2, bool is_div, bool check_zero) { +  LOG(FATAL) << "Unexpected use of GenDivRem for Mips"; +  return rl_dest; +} + +RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) { +  LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips"; +  return rl_dest; +} +  void MipsMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {    LOG(FATAL) << "Unexpected use of OpLea for Arm";  } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index c6c500060d..b59ec5ef5e 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -758,6 +758,25 @@ class Mir2Lir : public Backend {                                    bool is_div) = 0;      virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit,                                       bool is_div) = 0; +    /* +     * @brief Generate an integer div or rem operation by a literal. +     * @param rl_dest Destination Location. +     * @param rl_src1 Numerator Location. +     * @param rl_src2 Divisor Location. +     * @param is_div 'true' if this is a division, 'false' for a remainder. +     * @param check_zero 'true' if an exception should be generated if the divisor is 0. +     */ +    virtual RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                                  RegLocation rl_src2, bool is_div, bool check_zero) = 0; +    /* +     * @brief Generate an integer div or rem operation by a literal. +     * @param rl_dest Destination Location. +     * @param rl_src Numerator Location. +     * @param lit Divisor. +     * @param is_div 'true' if this is a division, 'false' for a remainder. +     */ +    virtual RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, +                                     int lit, bool is_div) = 0;      virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,                              RegLocation rl_src2) = 0; diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 1dcff652ba..5e1c4d1e9f 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -242,12 +242,13 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,    UNARY_ENCODING_MAP(Not, 0x2, IS_STORE, 0,           R, kReg, IS_UNARY_OP | REG_DEF0_USE0, M, kMem, IS_BINARY_OP | REG_USE0, A, kArray, IS_QUAD_OP | REG_USE01, 0, 0, 0, 0, "", "", ""),    UNARY_ENCODING_MAP(Neg, 0x3, IS_STORE, SETS_CCODES, R, kReg, IS_UNARY_OP | REG_DEF0_USE0, M, kMem, IS_BINARY_OP | REG_USE0, A, kArray, IS_QUAD_OP | REG_USE01, 0, 0, 0, 0, "", "", ""), -  UNARY_ENCODING_MAP(Mul,     0x4, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA,  REG_DEFAD_USEA,  "ax,al,", "dx:ax,ax,", "edx:eax,eax,"), -  UNARY_ENCODING_MAP(Imul,    0x5, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA,  REG_DEFAD_USEA,  "ax,al,", "dx:ax,ax,", "edx:eax,eax,"), -  UNARY_ENCODING_MAP(Divmod,  0x6, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"), -  UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"), +  UNARY_ENCODING_MAP(Mul,     0x4, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA,  REG_DEFAD_USEA,  "ax,al,", "dx:ax,ax,", "edx:eax,eax,"), +  UNARY_ENCODING_MAP(Imul,    0x5, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA,  REG_DEFAD_USEA,  "ax,al,", "dx:ax,ax,", "edx:eax,eax,"), +  UNARY_ENCODING_MAP(Divmod,  0x6, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"), +  UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),  #undef UNARY_ENCODING_MAP +  { kx86Cdq32Da, kRegOpcode, NO_OPERAND | REG_DEFAD_USEA,                                  { 0, 0, 0x99, 0, 0, 0, 0, 0 }, "Cdq", "" },    { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0,                                 { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },    { kX86Push32R,  kRegOpcode, IS_UNARY_OP | REG_USE0 | REG_USE_SP | REG_DEF_SP | IS_STORE, { 0, 0, 0x50, 0,    0, 0, 0, 0 }, "Push32R",  "!0r" },    { kX86Pop32R,   kRegOpcode, IS_UNARY_OP | REG_DEF0 | REG_USE_SP | REG_DEF_SP | IS_LOAD,  { 0, 0, 0x58, 0,    0, 0, 0, 0 }, "Pop32R",   "!0r" }, diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 53e82c3196..9cc4efd113 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -309,6 +309,34 @@ class X86Mir2Lir : public Mir2Lir {       * @param loc Register location to dump       */      static void DumpRegLocation(RegLocation loc); + +    /** +     * @brief Calculate magic number and shift for a given divisor +     * @param divisor divisor number for calculation +     * @param magic hold calculated magic number +     * @param shift hold calculated shift +     */ +    void CalculateMagicAndShift(int divisor, int& magic, int& shift); + +    /* +     * @brief Generate an integer div or rem operation. +     * @param rl_dest Destination Location. +     * @param rl_src1 Numerator Location. +     * @param rl_src2 Divisor Location. +     * @param is_div 'true' if this is a division, 'false' for a remainder. +     * @param check_zero 'true' if an exception should be generated if the divisor is 0. +     */ +    RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                                  RegLocation rl_src2, bool is_div, bool check_zero); + +    /* +     * @brief Generate an integer div or rem operation by a literal. +     * @param rl_dest Destination Location. +     * @param rl_src Numerator Location. +     * @param lit Divisor. +     * @param is_div 'true' if this is a division, 'false' for a remainder. +     */ +    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src, int lit, bool is_div);  };  }  // namespace art diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 79820c925c..ccae130637 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -284,18 +284,261 @@ void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,    OpCmpImmBranch(ccode, low_reg, val_lo, taken);  } +void X86Mir2Lir::CalculateMagicAndShift(int divisor, int& magic, int& shift) { +  // It does not make sense to calculate magic and shift for zero divisor. +  DCHECK_NE(divisor, 0); + +  /* According to H.S.Warren's Hacker's Delight Chapter 10 and +   * T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication. +   * The magic number M and shift S can be calculated in the following way: +   * Let nc be the most positive value of numerator(n) such that nc = kd - 1, +   * where divisor(d) >=2. +   * Let nc be the most negative value of numerator(n) such that nc = kd + 1, +   * where divisor(d) <= -2. +   * Thus nc can be calculated like: +   * nc = 2^31 + 2^31 % d - 1, where d >= 2 +   * nc = -2^31 + (2^31 + 1) % d, where d >= 2. +   * +   * So the shift p is the smallest p satisfying +   * 2^p > nc * (d - 2^p % d), where d >= 2 +   * 2^p > nc * (d + 2^p % d), where d <= -2. +   * +   * the magic number M is calcuated by +   * M = (2^p + d - 2^p % d) / d, where d >= 2 +   * M = (2^p - d - 2^p % d) / d, where d <= -2. +   * +   * Notice that p is always bigger than or equal to 32, so we just return 32-p as +   * the shift number S. +   */ + +  int32_t p = 31; +  const uint32_t two31 = 0x80000000U; + +  // Initialize the computations. +  uint32_t abs_d = (divisor >= 0) ? divisor : -divisor; +  uint32_t tmp = two31 + (static_cast<uint32_t>(divisor) >> 31); +  uint32_t abs_nc = tmp - 1 - tmp % abs_d; +  uint32_t quotient1 = two31 / abs_nc; +  uint32_t remainder1 = two31 % abs_nc; +  uint32_t quotient2 = two31 / abs_d; +  uint32_t remainder2 = two31 % abs_d; + +  /* +   * To avoid handling both positive and negative divisor, Hacker's Delight +   * introduces a method to handle these 2 cases together to avoid duplication. +   */ +  uint32_t delta; +  do { +    p++; +    quotient1 = 2 * quotient1; +    remainder1 = 2 * remainder1; +    if (remainder1 >= abs_nc) { +      quotient1++; +      remainder1 = remainder1 - abs_nc; +    } +    quotient2 = 2 * quotient2; +    remainder2 = 2 * remainder2; +    if (remainder2 >= abs_d) { +      quotient2++; +      remainder2 = remainder2 - abs_d; +    } +    delta = abs_d - remainder2; +  } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0)); + +  magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1); +  shift = p - 32; +} +  RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo,                                       int lit, bool is_div) {    LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";    return rl_dest;  } +RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src, +                                     int imm, bool is_div) { +  // Use a multiply (and fixup) to perform an int div/rem by a constant. + +  // We have to use fixed registers, so flush all the temps. +  FlushAllRegs(); +  LockCallTemps();  // Prepare for explicit register usage. + +  // Assume that the result will be in EDX. +  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, +                          r2, INVALID_REG, INVALID_SREG, INVALID_SREG}; + +  // handle 0x80000000 / -1 special case. +  LIR *minint_branch = 0; +  if (imm == -1) { +    if (is_div) { +      LoadValueDirectFixed(rl_src, r0); +      OpRegImm(kOpCmp, r0, 0x80000000); +      minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq); + +      // for x != MIN_INT, x / -1 == -x. +      NewLIR1(kX86Neg32R, r0); + +      LIR* branch_around = NewLIR1(kX86Jmp8, 0); +      // The target for cmp/jmp above. +      minint_branch->target = NewLIR0(kPseudoTargetLabel); +      // EAX already contains the right value (0x80000000), +      branch_around->target = NewLIR0(kPseudoTargetLabel); +    } else { +      // x % -1 == 0. +      LoadConstantNoClobber(r0, 0); +    } +    // For this case, return the result in EAX. +    rl_result.low_reg = r0; +  } else { +    DCHECK(imm <= -2 || imm >= 2); +    // Use H.S.Warren's Hacker's Delight Chapter 10 and +    // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication. +    int magic, shift; +    CalculateMagicAndShift(imm, magic, shift); + +    /* +     * For imm >= 2, +     *     int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0 +     *     int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0. +     * For imm <= -2, +     *     int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0 +     *     int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0. +     * We implement this algorithm in the following way: +     * 1. multiply magic number m and numerator n, get the higher 32bit result in EDX +     * 2. if imm > 0 and magic < 0, add numerator to EDX +     *    if imm < 0 and magic > 0, sub numerator from EDX +     * 3. if S !=0, SAR S bits for EDX +     * 4. add 1 to EDX if EDX < 0 +     * 5. Thus, EDX is the quotient +     */ + +    // Numerator into EAX. +    int numerator_reg = -1; +    if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) { +      // We will need the value later. +      if (rl_src.location == kLocPhysReg) { +        // We can use it directly. +        DCHECK(rl_src.low_reg != r0 && rl_src.low_reg != r2); +        numerator_reg = rl_src.low_reg; +      } else { +        LoadValueDirectFixed(rl_src, r1); +        numerator_reg = r1; +      } +      OpRegCopy(r0, numerator_reg); +    } else { +      // Only need this once.  Just put it into EAX. +      LoadValueDirectFixed(rl_src, r0); +    } + +    // EDX = magic. +    LoadConstantNoClobber(r2, magic); + +    // EDX:EAX = magic & dividend. +    NewLIR1(kX86Imul32DaR, r2); + +    if (imm > 0 && magic < 0) { +      // Add numerator to EDX. +      DCHECK_NE(numerator_reg, -1); +      NewLIR2(kX86Add32RR, r2, numerator_reg); +    } else if (imm < 0 && magic > 0) { +      DCHECK_NE(numerator_reg, -1); +      NewLIR2(kX86Sub32RR, r2, numerator_reg); +    } + +    // Do we need the shift? +    if (shift != 0) { +      // Shift EDX by 'shift' bits. +      NewLIR2(kX86Sar32RI, r2, shift); +    } + +    // Add 1 to EDX if EDX < 0. + +    // Move EDX to EAX. +    OpRegCopy(r0, r2); + +    // Move sign bit to bit 0, zeroing the rest. +    NewLIR2(kX86Shr32RI, r2, 31); + +    // EDX = EDX + EAX. +    NewLIR2(kX86Add32RR, r2, r0); + +    // Quotient is in EDX. +    if (!is_div) { +      // We need to compute the remainder. +      // Remainder is divisor - (quotient * imm). +      DCHECK_NE(numerator_reg, -1); +      OpRegCopy(r0, numerator_reg); + +      // EAX = numerator * imm. +      OpRegRegImm(kOpMul, r2, r2, imm); + +      // EDX -= EAX. +      NewLIR2(kX86Sub32RR, r0, r2); + +      // For this case, return the result in EAX. +      rl_result.low_reg = r0; +    } +  } + +  return rl_result; +} +  RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo,                                    int reg_hi, bool is_div) {    LOG(FATAL) << "Unexpected use of GenDivRem for x86";    return rl_dest;  } +RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, +                                  RegLocation rl_src2, bool is_div, bool check_zero) { +  // We have to use fixed registers, so flush all the temps. +  FlushAllRegs(); +  LockCallTemps();  // Prepare for explicit register usage. + +  // Load LHS into EAX. +  LoadValueDirectFixed(rl_src1, r0); + +  // Load RHS into EBX. +  LoadValueDirectFixed(rl_src2, r1); + +  // Copy LHS sign bit into EDX. +  NewLIR0(kx86Cdq32Da); + +  if (check_zero) { +    // Handle division by zero case. +    GenImmedCheck(kCondEq, r1, 0, kThrowDivZero); +  } + +  // Have to catch 0x80000000/-1 case, or we will get an exception! +  OpRegImm(kOpCmp, r1, -1); +  LIR *minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); + +  // RHS is -1. +  OpRegImm(kOpCmp, r0, 0x80000000); +  LIR * minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); + +  // In 0x80000000/-1 case. +  if (!is_div) { +    // For DIV, EAX is already right. For REM, we need EDX 0. +    LoadConstantNoClobber(r2, 0); +  } +  LIR* done = NewLIR1(kX86Jmp8, 0); + +  // Expected case. +  minus_one_branch->target = NewLIR0(kPseudoTargetLabel); +  minint_branch->target = minus_one_branch->target; +  NewLIR1(kX86Idivmod32DaR, r1); +  done->target = NewLIR0(kPseudoTargetLabel); + +  // Result is in EAX for div and EDX for rem. +  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, +                          r0, INVALID_REG, INVALID_SREG, INVALID_SREG}; +  if (!is_div) { +    rl_result.low_reg = r2; +  } +  return rl_result; +} +  bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {    DCHECK_EQ(cu_->instruction_set, kX86); diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h index 1488f5d557..d7f61fc027 100644 --- a/compiler/dex/quick/x86/x86_lir.h +++ b/compiler/dex/quick/x86/x86_lir.h @@ -316,6 +316,7 @@ enum X86OpCode {    UnaryOpcode(kX86Imul, DaR, DaM, DaA),    UnaryOpcode(kX86Divmod,  DaR, DaM, DaA),    UnaryOpcode(kX86Idivmod, DaR, DaM, DaA), +  kx86Cdq32Da,    kX86Bswap32R,    kX86Push32R, kX86Pop32R,  #undef UnaryOpcode  |