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,
     41                        OptimizingCompilerStats* stats,
     42                        const char* name = kIntrinsicsRecognizerPassName)
     43       : HOptimization(graph, name, stats) {}
     44 
     45   void Run() OVERRIDE;
     46 
     47   // Static helper that recognizes intrinsic call. Returns true on success.
     48   // If it fails due to invoke type mismatch, wrong_invoke_type is set.
     49   // Useful to recognize intrinsics on individual calls outside this full pass.
     50   static bool Recognize(HInvoke* invoke, ArtMethod* method, /*out*/ bool* wrong_invoke_type)
     51       REQUIRES_SHARED(Locks::mutator_lock_);
     52 
     53   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
     54 
     55  private:
     56   DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
     57 };
     58 
     59 class IntrinsicVisitor : public ValueObject {
     60  public:
     61   virtual ~IntrinsicVisitor() {}
     62 
     63   // Dispatch logic.
     64 
     65   void Dispatch(HInvoke* invoke) {
     66     switch (invoke->GetIntrinsic()) {
     67       case Intrinsics::kNone:
     68         return;
     69 #define OPTIMIZING_INTRINSICS(Name, ...) \
     70       case Intrinsics::k ## Name: \
     71         Visit ## Name(invoke);    \
     72         return;
     73 #include "intrinsics_list.h"
     74         INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
     75 #undef INTRINSICS_LIST
     76 #undef OPTIMIZING_INTRINSICS
     77 
     78       // Do not put a default case. That way the compiler will complain if we missed a case.
     79     }
     80   }
     81 
     82   // Define visitor methods.
     83 
     84 #define OPTIMIZING_INTRINSICS(Name, ...) \
     85   virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
     86   }
     87 #include "intrinsics_list.h"
     88   INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
     89 #undef INTRINSICS_LIST
     90 #undef OPTIMIZING_INTRINSICS
     91 
     92   static void MoveArguments(HInvoke* invoke,
     93                             CodeGenerator* codegen,
     94                             InvokeDexCallingConventionVisitor* calling_convention_visitor) {
     95     if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) {
     96       HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
     97       // Explicit clinit checks triggered by static invokes must have been
     98       // pruned by art::PrepareForRegisterAllocation.
     99       DCHECK(!invoke_static_or_direct->IsStaticWithExplicitClinitCheck());
    100     }
    101 
    102     if (invoke->GetNumberOfArguments() == 0) {
    103       // No argument to move.
    104       return;
    105     }
    106 
    107     LocationSummary* locations = invoke->GetLocations();
    108 
    109     // We're moving potentially two or more locations to locations that could overlap, so we need
    110     // a parallel move resolver.
    111     HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
    112 
    113     for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
    114       HInstruction* input = invoke->InputAt(i);
    115       Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType());
    116       Location actual_loc = locations->InAt(i);
    117 
    118       parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr);
    119     }
    120 
    121     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
    122   }
    123 
    124   static void ComputeIntegerValueOfLocations(HInvoke* invoke,
    125                                              CodeGenerator* codegen,
    126                                              Location return_location,
    127                                              Location first_argument_location);
    128 
    129   // Temporary data structure for holding Integer.valueOf useful data. We only
    130   // use it if the mirror::Class* are in the boot image, so it is fine to keep raw
    131   // mirror::Class pointers in this structure.
    132   struct IntegerValueOfInfo {
    133     IntegerValueOfInfo()
    134         : integer_cache(nullptr),
    135           integer(nullptr),
    136           cache(nullptr),
    137           low(0),
    138           high(0),
    139           value_offset(0) {}
    140 
    141     // The java.lang.IntegerCache class.
    142     mirror::Class* integer_cache;
    143     // The java.lang.Integer class.
    144     mirror::Class* integer;
    145     // Value of java.lang.IntegerCache#cache.
    146     mirror::ObjectArray<mirror::Object>* cache;
    147     // Value of java.lang.IntegerCache#low.
    148     int32_t low;
    149     // Value of java.lang.IntegerCache#high.
    150     int32_t high;
    151     // The offset of java.lang.Integer.value.
    152     int32_t value_offset;
    153   };
    154 
    155   static IntegerValueOfInfo ComputeIntegerValueOfInfo();
    156 
    157  protected:
    158   IntrinsicVisitor() {}
    159 
    160  private:
    161   DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor);
    162 };
    163 
    164 #define GENERIC_OPTIMIZATION(name, bit)                \
    165 public:                                                \
    166 void Set##name() { SetBit(k##name); }                  \
    167 bool Get##name() const { return IsBitSet(k##name); }   \
    168 private:                                               \
    169 static constexpr size_t k##name = bit
    170 
    171 class IntrinsicOptimizations : public ValueObject {
    172  public:
    173   explicit IntrinsicOptimizations(HInvoke* invoke)
    174       : value_(invoke->GetIntrinsicOptimizations()) {}
    175   explicit IntrinsicOptimizations(const HInvoke& invoke)
    176       : value_(invoke.GetIntrinsicOptimizations()) {}
    177 
    178   static constexpr int kNumberOfGenericOptimizations = 2;
    179   GENERIC_OPTIMIZATION(DoesNotNeedDexCache, 0);
    180   GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 1);
    181 
    182  protected:
    183   bool IsBitSet(uint32_t bit) const {
    184     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
    185     return (*value_ & (1 << bit)) != 0u;
    186   }
    187 
    188   void SetBit(uint32_t bit) {
    189     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
    190     *(const_cast<uint32_t* const>(value_)) |= (1 << bit);
    191   }
    192 
    193  private:
    194   const uint32_t* const value_;
    195 
    196   DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations);
    197 };
    198 
    199 #undef GENERIC_OPTIMIZATION
    200 
    201 #define INTRINSIC_OPTIMIZATION(name, bit)                             \
    202 public:                                                               \
    203 void Set##name() { SetBit(k##name); }                                 \
    204 bool Get##name() const { return IsBitSet(k##name); }                  \
    205 private:                                                              \
    206 static constexpr size_t k##name = (bit) + kNumberOfGenericOptimizations
    207 
    208 class StringEqualsOptimizations : public IntrinsicOptimizations {
    209  public:
    210   explicit StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
    211 
    212   INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
    213   INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
    214   INTRINSIC_OPTIMIZATION(NoReadBarrierForStringClass, 2);
    215 
    216  private:
    217   DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
    218 };
    219 
    220 class SystemArrayCopyOptimizations : public IntrinsicOptimizations {
    221  public:
    222   explicit SystemArrayCopyOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
    223 
    224   INTRINSIC_OPTIMIZATION(SourceIsNotNull, 0);
    225   INTRINSIC_OPTIMIZATION(DestinationIsNotNull, 1);
    226   INTRINSIC_OPTIMIZATION(DestinationIsSource, 2);
    227   INTRINSIC_OPTIMIZATION(CountIsSourceLength, 3);
    228   INTRINSIC_OPTIMIZATION(CountIsDestinationLength, 4);
    229   INTRINSIC_OPTIMIZATION(DoesNotNeedTypeCheck, 5);
    230   INTRINSIC_OPTIMIZATION(DestinationIsTypedObjectArray, 6);
    231   INTRINSIC_OPTIMIZATION(DestinationIsNonPrimitiveArray, 7);
    232   INTRINSIC_OPTIMIZATION(DestinationIsPrimitiveArray, 8);
    233   INTRINSIC_OPTIMIZATION(SourceIsNonPrimitiveArray, 9);
    234   INTRINSIC_OPTIMIZATION(SourceIsPrimitiveArray, 10);
    235 
    236  private:
    237   DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations);
    238 };
    239 
    240 #undef INTRISIC_OPTIMIZATION
    241 
    242 //
    243 // Macros for use in the intrinsics code generators.
    244 //
    245 
    246 // Defines an unimplemented intrinsic: that is, a method call that is recognized as an
    247 // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled
    248 // by this architecture-specific intrinsics code generator. Eventually it is implemented
    249 // as a true method call.
    250 #define UNIMPLEMENTED_INTRINSIC(Arch, Name)                                               \
    251 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
    252 }                                                                                         \
    253 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
    254 }
    255 
    256 // Defines a list of unreached intrinsics: that is, method calls that are recognized as
    257 // an intrinsic, and then always converted into HIR instructions before they reach any
    258 // architecture-specific intrinsics code generator.
    259 #define UNREACHABLE_INTRINSIC(Arch, Name)                                \
    260 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \
    261   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
    262              << " should have been converted to HIR";                    \
    263 }                                                                        \
    264 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) {    \
    265   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
    266              << " should have been converted to HIR";                    \
    267 }
    268 #define UNREACHABLE_INTRINSICS(Arch)                            \
    269 UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)                \
    270 UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits)             \
    271 UNREACHABLE_INTRINSIC(Arch, FloatIsNaN)                         \
    272 UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN)                        \
    273 UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft)                  \
    274 UNREACHABLE_INTRINSIC(Arch, LongRotateLeft)                     \
    275 UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight)                 \
    276 UNREACHABLE_INTRINSIC(Arch, LongRotateRight)                    \
    277 UNREACHABLE_INTRINSIC(Arch, IntegerCompare)                     \
    278 UNREACHABLE_INTRINSIC(Arch, LongCompare)                        \
    279 UNREACHABLE_INTRINSIC(Arch, IntegerSignum)                      \
    280 UNREACHABLE_INTRINSIC(Arch, LongSignum)                         \
    281 UNREACHABLE_INTRINSIC(Arch, StringCharAt)                       \
    282 UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)                      \
    283 UNREACHABLE_INTRINSIC(Arch, StringLength)                       \
    284 UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)                    \
    285 UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)                   \
    286 UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)                    \
    287 UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence)                 \
    288 UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence)              \
    289 UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence)              \
    290 UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence)             \
    291 UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)           \
    292 UNREACHABLE_INTRINSIC(Arch, MethodHandleInvokeExact)            \
    293 UNREACHABLE_INTRINSIC(Arch, MethodHandleInvoke)                 \
    294 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchange)        \
    295 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeAcquire) \
    296 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeRelease) \
    297 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndSet)             \
    298 UNREACHABLE_INTRINSIC(Arch, VarHandleGet)                       \
    299 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAcquire)                \
    300 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAdd)                 \
    301 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddAcquire)          \
    302 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddRelease)          \
    303 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAnd)          \
    304 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndAcquire)   \
    305 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndRelease)   \
    306 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOr)           \
    307 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrAcquire)    \
    308 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrRelease)    \
    309 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXor)          \
    310 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorAcquire)   \
    311 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorRelease)   \
    312 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSet)                 \
    313 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetAcquire)          \
    314 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetRelease)          \
    315 UNREACHABLE_INTRINSIC(Arch, VarHandleGetOpaque)                 \
    316 UNREACHABLE_INTRINSIC(Arch, VarHandleGetVolatile)               \
    317 UNREACHABLE_INTRINSIC(Arch, VarHandleSet)                       \
    318 UNREACHABLE_INTRINSIC(Arch, VarHandleSetOpaque)                 \
    319 UNREACHABLE_INTRINSIC(Arch, VarHandleSetRelease)                \
    320 UNREACHABLE_INTRINSIC(Arch, VarHandleSetVolatile)               \
    321 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSet)         \
    322 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetAcquire)  \
    323 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetPlain)    \
    324 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetRelease)
    325 
    326 template <typename IntrinsicLocationsBuilder, typename Codegenerator>
    327 bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
    328   if (invoke->GetIntrinsic() != Intrinsics::kNone) {
    329     // This invoke may have intrinsic code generation defined. However, we must
    330     // now also determine if this code generation is truly there and call-free
    331     // (not unimplemented, no bail on instruction features, or call on slow path).
    332     // This is done by actually calling the locations builder on the instruction
    333     // and clearing out the locations once result is known. We assume this
    334     // call only has creating locations as side effects!
    335     // TODO: Avoid wasting Arena memory.
    336     IntrinsicLocationsBuilder builder(codegen);
    337     bool success = builder.TryDispatch(invoke) && !invoke->GetLocations()->CanCall();
    338     invoke->SetLocations(nullptr);
    339     return success;
    340   }
    341   return false;
    342 }
    343 
    344 }  // namespace art
    345 
    346 #endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_H_
    347