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 // Temporary measure until we have caught up with the Java 7 definition of Math.round. b/26327751 31 static constexpr bool kRoundIsPlusPointFive = false; 32 33 // Recognize intrinsics from HInvoke nodes. 34 class IntrinsicsRecognizer : public HOptimization { 35 public: 36 IntrinsicsRecognizer(HGraph* graph, CompilerDriver* driver, OptimizingCompilerStats* stats) 37 : HOptimization(graph, kIntrinsicsRecognizerPassName, stats), 38 driver_(driver) {} 39 40 void Run() OVERRIDE; 41 42 static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition"; 43 44 private: 45 CompilerDriver* driver_; 46 47 DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer); 48 }; 49 50 class IntrinsicVisitor : public ValueObject { 51 public: 52 virtual ~IntrinsicVisitor() {} 53 54 // Dispatch logic. 55 56 void Dispatch(HInvoke* invoke) { 57 switch (invoke->GetIntrinsic()) { 58 case Intrinsics::kNone: 59 return; 60 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \ 61 case Intrinsics::k ## Name: \ 62 Visit ## Name(invoke); \ 63 return; 64 #include "intrinsics_list.h" 65 INTRINSICS_LIST(OPTIMIZING_INTRINSICS) 66 #undef INTRINSICS_LIST 67 #undef OPTIMIZING_INTRINSICS 68 69 // Do not put a default case. That way the compiler will complain if we missed a case. 70 } 71 } 72 73 // Define visitor methods. 74 75 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \ 76 virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 77 } 78 #include "intrinsics_list.h" 79 INTRINSICS_LIST(OPTIMIZING_INTRINSICS) 80 #undef INTRINSICS_LIST 81 #undef OPTIMIZING_INTRINSICS 82 83 static void MoveArguments(HInvoke* invoke, 84 CodeGenerator* codegen, 85 InvokeDexCallingConventionVisitor* calling_convention_visitor) { 86 if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) { 87 HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect(); 88 // Explicit clinit checks triggered by static invokes must have been 89 // pruned by art::PrepareForRegisterAllocation. 90 DCHECK(!invoke_static_or_direct->IsStaticWithExplicitClinitCheck()); 91 } 92 93 if (invoke->GetNumberOfArguments() == 0) { 94 // No argument to move. 95 return; 96 } 97 98 LocationSummary* locations = invoke->GetLocations(); 99 100 // We're moving potentially two or more locations to locations that could overlap, so we need 101 // a parallel move resolver. 102 HParallelMove parallel_move(codegen->GetGraph()->GetArena()); 103 104 for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { 105 HInstruction* input = invoke->InputAt(i); 106 Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType()); 107 Location actual_loc = locations->InAt(i); 108 109 parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr); 110 } 111 112 codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); 113 } 114 115 protected: 116 IntrinsicVisitor() {} 117 118 private: 119 DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor); 120 }; 121 122 #define GENERIC_OPTIMIZATION(name, bit) \ 123 public: \ 124 void Set##name() { SetBit(k##name); } \ 125 bool Get##name() const { return IsBitSet(k##name); } \ 126 private: \ 127 static constexpr size_t k##name = bit 128 129 class IntrinsicOptimizations : public ValueObject { 130 public: 131 explicit IntrinsicOptimizations(HInvoke* invoke) 132 : value_(invoke->GetIntrinsicOptimizations()) {} 133 explicit IntrinsicOptimizations(const HInvoke& invoke) 134 : value_(invoke.GetIntrinsicOptimizations()) {} 135 136 static constexpr int kNumberOfGenericOptimizations = 2; 137 GENERIC_OPTIMIZATION(DoesNotNeedDexCache, 0); 138 GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 1); 139 140 protected: 141 bool IsBitSet(uint32_t bit) const { 142 DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte); 143 return (*value_ & (1 << bit)) != 0u; 144 } 145 146 void SetBit(uint32_t bit) { 147 DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte); 148 *(const_cast<uint32_t* const>(value_)) |= (1 << bit); 149 } 150 151 private: 152 const uint32_t* const value_; 153 154 DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations); 155 }; 156 157 #undef GENERIC_OPTIMIZATION 158 159 #define INTRINSIC_OPTIMIZATION(name, bit) \ 160 public: \ 161 void Set##name() { SetBit(k##name); } \ 162 bool Get##name() const { return IsBitSet(k##name); } \ 163 private: \ 164 static constexpr size_t k##name = bit + kNumberOfGenericOptimizations 165 166 class StringEqualsOptimizations : public IntrinsicOptimizations { 167 public: 168 explicit StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {} 169 170 INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0); 171 INTRINSIC_OPTIMIZATION(ArgumentIsString, 1); 172 173 private: 174 DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations); 175 }; 176 177 class SystemArrayCopyOptimizations : public IntrinsicOptimizations { 178 public: 179 explicit SystemArrayCopyOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {} 180 181 INTRINSIC_OPTIMIZATION(SourceIsNotNull, 0); 182 INTRINSIC_OPTIMIZATION(DestinationIsNotNull, 1); 183 INTRINSIC_OPTIMIZATION(DestinationIsSource, 2); 184 INTRINSIC_OPTIMIZATION(CountIsSourceLength, 3); 185 INTRINSIC_OPTIMIZATION(CountIsDestinationLength, 4); 186 INTRINSIC_OPTIMIZATION(DoesNotNeedTypeCheck, 5); 187 INTRINSIC_OPTIMIZATION(DestinationIsTypedObjectArray, 6); 188 INTRINSIC_OPTIMIZATION(DestinationIsNonPrimitiveArray, 7); 189 INTRINSIC_OPTIMIZATION(DestinationIsPrimitiveArray, 8); 190 INTRINSIC_OPTIMIZATION(SourceIsNonPrimitiveArray, 9); 191 INTRINSIC_OPTIMIZATION(SourceIsPrimitiveArray, 10); 192 193 private: 194 DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations); 195 }; 196 197 #undef INTRISIC_OPTIMIZATION 198 199 // 200 // Macros for use in the intrinsics code generators. 201 // 202 203 // Defines an unimplemented intrinsic: that is, a method call that is recognized as an 204 // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled 205 // by this architecture-specific intrinsics code generator. Eventually it is implemented 206 // as a true method call. 207 #define UNIMPLEMENTED_INTRINSIC(Arch, Name) \ 208 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 209 } \ 210 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 211 } 212 213 // Defines a list of unreached intrinsics: that is, method calls that are recognized as 214 // an intrinsic, and then always converted into HIR instructions before they reach any 215 // architecture-specific intrinsics code generator. 216 #define UNREACHABLE_INTRINSIC(Arch, Name) \ 217 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \ 218 LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \ 219 << " should have been converted to HIR"; \ 220 } \ 221 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) { \ 222 LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \ 223 << " should have been converted to HIR"; \ 224 } 225 #define UNREACHABLE_INTRINSICS(Arch) \ 226 UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \ 227 UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \ 228 UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \ 229 UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \ 230 UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \ 231 UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \ 232 UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \ 233 UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \ 234 UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \ 235 UNREACHABLE_INTRINSIC(Arch, LongCompare) \ 236 UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \ 237 UNREACHABLE_INTRINSIC(Arch, LongSignum) \ 238 UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \ 239 UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \ 240 UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) 241 242 } // namespace art 243 244 #endif // ART_COMPILER_OPTIMIZING_INTRINSICS_H_ 245