diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 59 | 
1 files changed, 58 insertions, 1 deletions
| diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index a75639f3c5..6ff71f2d3e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -24,6 +24,7 @@  #include "intrinsics.h"  #include "intrinsics_utils.h"  #include "mirror/class-inl.h" +#include "optimizing/data_type.h"  #include "optimizing/nodes.h"  #include "scoped_thread_state_change-inl.h"  #include "sharpening.h" @@ -112,7 +113,6 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {    void VisitDeoptimize(HDeoptimize* deoptimize) override;    void VisitVecMul(HVecMul* instruction) override;    void VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet* instruction) override; -    void SimplifySystemArrayCopy(HInvoke* invoke);    void SimplifyStringEquals(HInvoke* invoke);    void SimplifyFP2Int(HInvoke* invoke); @@ -1185,6 +1185,33 @@ static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type r        !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);  } +static bool CanRemoveRedundantAnd(HConstant* and_right, +                                  HConstant* shr_right, +                                  DataType::Type result_type) { +  int64_t and_cst = Int64FromConstant(and_right); +  int64_t shr_cst = Int64FromConstant(shr_right); + +  // In the following sequence A is the input value, D is the result: +  // B := A & x +  // C := B >> r +  // D := TypeConv(n-bit type) C + +  // The value of D is entirely dependent on the bits [n-1:0] of C, which in turn are dependent +  // on bits [r+n-1:r] of B. +  // Therefore, if the AND does not change bits [r+n-1:r] of A then it will not affect D. +  // This can be checked by ensuring that bits [r+n-1:r] of the AND Constant are 1. + +  // For example: return (byte) ((value & 0xff00) >> 8) +  //              return (byte) ((value & 0xff000000) >> 31) + +  // The mask sets bits [r+n-1:r] to 1, and all others to 0. +  int64_t mask = DataType::MaxValueOfIntegralType(DataType::ToUnsigned(result_type)) << shr_cst; + +  // If the result of a bitwise AND between the mask and the AND constant is the original mask, then +  // the AND does not change bits [r+n-1:r], meaning that it is redundant and can be removed. +  return ((and_cst & mask) == mask); +} +  static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataType::Type new_type) {    if (maybe_get->IsInstanceFieldGet()) {      maybe_get->AsInstanceFieldGet()->SetType(new_type); @@ -1305,6 +1332,36 @@ void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruct          return;        }      } +  } else if (input->IsShr() && DataType::IsIntegralType(result_type) && +            // Optimization only applies to lossy Type Conversions. +            !IsTypeConversionLossless(input_type, result_type)) { +    DCHECK(DataType::IsIntegralType(input_type)); +    HShr* shr_op = input->AsShr(); +    HConstant* shr_right = shr_op->GetConstantRight(); +    HInstruction* shr_left = shr_op->GetLeastConstantLeft(); +    if (shr_right != nullptr && shr_left->IsAnd()) { +      // Optimization needs AND -> SHR -> TypeConversion pattern. +      HAnd* and_op = shr_left->AsAnd(); +      HConstant* and_right = and_op->GetConstantRight(); +      HInstruction* and_left = and_op->GetLeastConstantLeft(); +      DataType::Type and_left_type = and_left->GetType(); +      if (!DataType::IsUnsignedType(and_left_type) && +          !DataType::IsUnsignedType(result_type) && +          !DataType::IsUnsignedType(and_right->GetType()) && +          (DataType::Size(and_left_type) < 8) && +          (DataType::Size(result_type) == 1)) { +        // TODO: Support Unsigned Types. +        // TODO: Support Long Types. +        // TODO: Support result types other than byte. +        if (and_right != nullptr && and_op->HasOnlyOneNonEnvironmentUse() && +            CanRemoveRedundantAnd(and_right, shr_right, result_type)) { +          and_op->ReplaceWith(and_left); +          and_op->GetBlock()->RemoveInstruction(and_op); +          RecordSimplification(); +          return; +        } +      } +    }    } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) {      DCHECK(DataType::IsIntegralType(input_type));      HAnd* input_and = input->AsAnd(); |