Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_H_
     18 #define ART_COMPILER_OPTIMIZING_INTRINSICS_H_
     19 
     20 #include "code_generator.h"
     21 #include "nodes.h"
     22 #include "optimization.h"
     23 #include "parallel_move_resolver.h"
     24 
     25 namespace art {
     26 
     27 class CompilerDriver;
     28 class DexFile;
     29 
     30 // Positive floating-point infinities.
     31 static constexpr uint32_t kPositiveInfinityFloat = 0x7f800000U;
     32 static constexpr uint64_t kPositiveInfinityDouble = UINT64_C(0x7ff0000000000000);
     33 
     34 static constexpr uint32_t kNanFloat = 0x7fc00000U;
     35 static constexpr uint64_t kNanDouble = 0x7ff8000000000000;
     36 
     37 // Recognize intrinsics from HInvoke nodes.
     38 class IntrinsicsRecognizer : public HOptimization {
     39  public:
     40   IntrinsicsRecognizer(HGraph* graph, OptimizingCompilerStats* stats)
     41       : HOptimization(graph, kIntrinsicsRecognizerPassName, stats) {}
     42 
     43   void Run() OVERRIDE;
     44 
     45   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
     46 
     47  private:
     48   DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
     49 };
     50 
     51 class IntrinsicVisitor : public ValueObject {
     52  public:
     53   virtual ~IntrinsicVisitor() {}
     54 
     55   // Dispatch logic.
     56 
     57   void Dispatch(HInvoke* invoke) {
     58     switch (invoke->GetIntrinsic()) {
     59       case Intrinsics::kNone:
     60         return;
     61 #define OPTIMIZING_INTRINSICS(Name, ...) \
     62       case Intrinsics::k ## Name: \
     63         Visit ## Name(invoke);    \
     64         return;
     65 #include "intrinsics_list.h"
     66 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
     67 #undef INTRINSICS_LIST
     68 #undef OPTIMIZING_INTRINSICS
     69 
     70       // Do not put a default case. That way the compiler will complain if we missed a case.
     71     }
     72   }
     73 
     74   // Define visitor methods.
     75 
     76 #define OPTIMIZING_INTRINSICS(Name, ...) \
     77   virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
     78   }
     79 #include "intrinsics_list.h"
     80 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
     81 #undef INTRINSICS_LIST
     82 #undef OPTIMIZING_INTRINSICS
     83 
     84   static void MoveArguments(HInvoke* invoke,
     85                             CodeGenerator* codegen,
     86                             InvokeDexCallingConventionVisitor* calling_convention_visitor) {
     87     if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) {
     88       HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
     89       // Explicit clinit checks triggered by static invokes must have been
     90       // pruned by art::PrepareForRegisterAllocation.
     91       DCHECK(!invoke_static_or_direct->IsStaticWithExplicitClinitCheck());
     92     }
     93 
     94     if (invoke->GetNumberOfArguments() == 0) {
     95       // No argument to move.
     96       return;
     97     }
     98 
     99     LocationSummary* locations = invoke->GetLocations();
    100 
    101     // We're moving potentially two or more locations to locations that could overlap, so we need
    102     // a parallel move resolver.
    103     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
    104 
    105     for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
    106       HInstruction* input = invoke->InputAt(i);
    107       Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType());
    108       Location actual_loc = locations->InAt(i);
    109 
    110       parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr);
    111     }
    112 
    113     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
    114   }
    115 
    116   static void ComputeIntegerValueOfLocations(HInvoke* invoke,
    117                                              CodeGenerator* codegen,
    118                                              Location return_location,
    119                                              Location first_argument_location);
    120 
    121   // Temporary data structure for holding Integer.valueOf useful data. We only
    122   // use it if the mirror::Class* are in the boot image, so it is fine to keep raw
    123   // mirror::Class pointers in this structure.
    124   struct IntegerValueOfInfo {
    125     IntegerValueOfInfo()
    126         : integer_cache(nullptr),
    127           integer(nullptr),
    128           cache(nullptr),
    129           low(0),
    130           high(0),
    131           value_offset(0) {}
    132 
    133     // The java.lang.IntegerCache class.
    134     mirror::Class* integer_cache;
    135     // The java.lang.Integer class.
    136     mirror::Class* integer;
    137     // Value of java.lang.IntegerCache#cache.
    138     mirror::ObjectArray<mirror::Object>* cache;
    139     // Value of java.lang.IntegerCache#low.
    140     int32_t low;
    141     // Value of java.lang.IntegerCache#high.
    142     int32_t high;
    143     // The offset of java.lang.Integer.value.
    144     int32_t value_offset;
    145   };
    146 
    147   static IntegerValueOfInfo ComputeIntegerValueOfInfo();
    148 
    149  protected:
    150   IntrinsicVisitor() {}
    151 
    152  private:
    153   DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor);
    154 };
    155 
    156 #define GENERIC_OPTIMIZATION(name, bit)                \
    157 public:                                                \
    158 void Set##name() { SetBit(k##name); }                  \
    159 bool Get##name() const { return IsBitSet(k##name); }   \
    160 private:                                               \
    161 static constexpr size_t k##name = bit
    162 
    163 class IntrinsicOptimizations : public ValueObject {
    164  public:
    165   explicit IntrinsicOptimizations(HInvoke* invoke)
    166       : value_(invoke->GetIntrinsicOptimizations()) {}
    167   explicit IntrinsicOptimizations(const HInvoke& invoke)
    168       : value_(invoke.GetIntrinsicOptimizations()) {}
    169 
    170   static constexpr int kNumberOfGenericOptimizations = 2;
    171   GENERIC_OPTIMIZATION(DoesNotNeedDexCache, 0);
    172   GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 1);
    173 
    174  protected:
    175   bool IsBitSet(uint32_t bit) const {
    176     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
    177     return (*value_ & (1 << bit)) != 0u;
    178   }
    179 
    180   void SetBit(uint32_t bit) {
    181     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
    182     *(const_cast<uint32_t* const>(value_)) |= (1 << bit);
    183   }
    184 
    185  private:
    186   const uint32_t* const value_;
    187 
    188   DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations);
    189 };
    190 
    191 #undef GENERIC_OPTIMIZATION
    192 
    193 #define INTRINSIC_OPTIMIZATION(name, bit)                             \
    194 public:                                                               \
    195 void Set##name() { SetBit(k##name); }                                 \
    196 bool Get##name() const { return IsBitSet(k##name); }                  \
    197 private:                                                              \
    198 static constexpr size_t k##name = (bit) + kNumberOfGenericOptimizations
    199 
    200 class StringEqualsOptimizations : public IntrinsicOptimizations {
    201  public:
    202   explicit StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
    203 
    204   INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
    205   INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
    206 
    207  private:
    208   DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
    209 };
    210 
    211 class SystemArrayCopyOptimizations : public IntrinsicOptimizations {
    212  public:
    213   explicit SystemArrayCopyOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
    214 
    215   INTRINSIC_OPTIMIZATION(SourceIsNotNull, 0);
    216   INTRINSIC_OPTIMIZATION(DestinationIsNotNull, 1);
    217   INTRINSIC_OPTIMIZATION(DestinationIsSource, 2);
    218   INTRINSIC_OPTIMIZATION(CountIsSourceLength, 3);
    219   INTRINSIC_OPTIMIZATION(CountIsDestinationLength, 4);
    220   INTRINSIC_OPTIMIZATION(DoesNotNeedTypeCheck, 5);
    221   INTRINSIC_OPTIMIZATION(DestinationIsTypedObjectArray, 6);
    222   INTRINSIC_OPTIMIZATION(DestinationIsNonPrimitiveArray, 7);
    223   INTRINSIC_OPTIMIZATION(DestinationIsPrimitiveArray, 8);
    224   INTRINSIC_OPTIMIZATION(SourceIsNonPrimitiveArray, 9);
    225   INTRINSIC_OPTIMIZATION(SourceIsPrimitiveArray, 10);
    226 
    227  private:
    228   DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations);
    229 };
    230 
    231 #undef INTRISIC_OPTIMIZATION
    232 
    233 //
    234 // Macros for use in the intrinsics code generators.
    235 //
    236 
    237 // Defines an unimplemented intrinsic: that is, a method call that is recognized as an
    238 // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled
    239 // by this architecture-specific intrinsics code generator. Eventually it is implemented
    240 // as a true method call.
    241 #define UNIMPLEMENTED_INTRINSIC(Arch, Name)                                               \
    242 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
    243 }                                                                                         \
    244 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
    245 }
    246 
    247 // Defines a list of unreached intrinsics: that is, method calls that are recognized as
    248 // an intrinsic, and then always converted into HIR instructions before they reach any
    249 // architecture-specific intrinsics code generator.
    250 #define UNREACHABLE_INTRINSIC(Arch, Name)                                \
    251 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \
    252   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
    253              << " should have been converted to HIR";                    \
    254 }                                                                        \
    255 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) {    \
    256   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
    257              << " should have been converted to HIR";                    \
    258 }
    259 #define UNREACHABLE_INTRINSICS(Arch)                \
    260 UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)    \
    261 UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
    262 UNREACHABLE_INTRINSIC(Arch, FloatIsNaN)             \
    263 UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN)            \
    264 UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft)      \
    265 UNREACHABLE_INTRINSIC(Arch, LongRotateLeft)         \
    266 UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight)     \
    267 UNREACHABLE_INTRINSIC(Arch, LongRotateRight)        \
    268 UNREACHABLE_INTRINSIC(Arch, IntegerCompare)         \
    269 UNREACHABLE_INTRINSIC(Arch, LongCompare)            \
    270 UNREACHABLE_INTRINSIC(Arch, IntegerSignum)          \
    271 UNREACHABLE_INTRINSIC(Arch, LongSignum)             \
    272 UNREACHABLE_INTRINSIC(Arch, StringCharAt)           \
    273 UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)          \
    274 UNREACHABLE_INTRINSIC(Arch, StringLength)           \
    275 UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)        \
    276 UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)       \
    277 UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)
    278 
    279 template <typename IntrinsicLocationsBuilder, typename Codegenerator>
    280 bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
    281   if (invoke->GetIntrinsic() != Intrinsics::kNone) {
    282     // This invoke may have intrinsic code generation defined. However, we must
    283     // now also determine if this code generation is truly there and call-free
    284     // (not unimplemented, no bail on instruction features, or call on slow path).
    285     // This is done by actually calling the locations builder on the instruction
    286     // and clearing out the locations once result is known. We assume this
    287     // call only has creating locations as side effects!
    288     // TODO: Avoid wasting Arena memory.
    289     IntrinsicLocationsBuilder builder(codegen);
    290     bool success = builder.TryDispatch(invoke) && !invoke->GetLocations()->CanCall();
    291     invoke->SetLocations(nullptr);
    292     return success;
    293   }
    294   return false;
    295 }
    296 
    297 }  // namespace art
    298 
    299 #endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_H_
    300