xref: /aosp_15_r20/art/compiler/optimizing/intrinsics.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_INTRINSICS_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
21*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
22*795d594fSAndroid Build Coastguard Worker #include "intrinsics_list.h"
23*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
24*795d594fSAndroid Build Coastguard Worker #include "optimization.h"
25*795d594fSAndroid Build Coastguard Worker #include "parallel_move_resolver.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker class DexFile;
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker // Positive floating-point infinities.
32*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kPositiveInfinityFloat = 0x7f800000U;
33*795d594fSAndroid Build Coastguard Worker static constexpr uint64_t kPositiveInfinityDouble = UINT64_C(0x7ff0000000000000);
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kNanFloat = 0x7fc00000U;
36*795d594fSAndroid Build Coastguard Worker static constexpr uint64_t kNanDouble = 0x7ff8000000000000;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker class IntrinsicVisitor : public ValueObject {
39*795d594fSAndroid Build Coastguard Worker  public:
~IntrinsicVisitor()40*795d594fSAndroid Build Coastguard Worker   virtual ~IntrinsicVisitor() {}
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker   // Dispatch logic.
43*795d594fSAndroid Build Coastguard Worker 
Dispatch(HInvoke * invoke)44*795d594fSAndroid Build Coastguard Worker   void Dispatch(HInvoke* invoke) {
45*795d594fSAndroid Build Coastguard Worker     switch (invoke->GetIntrinsic()) {
46*795d594fSAndroid Build Coastguard Worker       case Intrinsics::kNone:
47*795d594fSAndroid Build Coastguard Worker         return;
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR(Name, ...) \
50*795d594fSAndroid Build Coastguard Worker       case Intrinsics::k ## Name:
51*795d594fSAndroid Build Coastguard Worker         ART_INTRINSICS_WITH_SPECIALIZED_HIR_LIST(OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR)
52*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR
53*795d594fSAndroid Build Coastguard Worker         // Note: clang++ can optimize this `switch` to a range check and a virtual dispatch
54*795d594fSAndroid Build Coastguard Worker         // with indexed load from the vtable using an adjusted `invoke->GetIntrinsic()`
55*795d594fSAndroid Build Coastguard Worker         // as the index. However, a non-empty `case` causes clang++ to produce much worse
56*795d594fSAndroid Build Coastguard Worker         // code, so we want to limit this check to debug builds only.
57*795d594fSAndroid Build Coastguard Worker         DCHECK(false) << "Unexpected intrinsic with HIR: " << invoke->GetIntrinsic();
58*795d594fSAndroid Build Coastguard Worker         return;
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS(Name, ...) \
61*795d594fSAndroid Build Coastguard Worker       case Intrinsics::k ## Name: \
62*795d594fSAndroid Build Coastguard Worker         Visit ## Name(invoke);    \
63*795d594fSAndroid Build Coastguard Worker         return;
64*795d594fSAndroid Build Coastguard Worker         ART_INTRINSICS_WITH_HINVOKE_LIST(OPTIMIZING_INTRINSICS)
65*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker       // Do not put a default case. That way the compiler will complain if we missed a case.
68*795d594fSAndroid Build Coastguard Worker     }
69*795d594fSAndroid Build Coastguard Worker   }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker   // Define visitor methods.
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker #define DECLARE_VISIT_INTRINSIC(Name, ...) \
74*795d594fSAndroid Build Coastguard Worker   virtual void Visit##Name([[maybe_unused]] HInvoke* invoke) = 0;
ART_INTRINSICS_WITH_HINVOKE_LIST(DECLARE_VISIT_INTRINSIC)75*795d594fSAndroid Build Coastguard Worker   ART_INTRINSICS_WITH_HINVOKE_LIST(DECLARE_VISIT_INTRINSIC)
76*795d594fSAndroid Build Coastguard Worker #undef DECLARE_VISIT_INTRINSIC
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker   static void MoveArguments(HInvoke* invoke,
79*795d594fSAndroid Build Coastguard Worker                             CodeGenerator* codegen,
80*795d594fSAndroid Build Coastguard Worker                             InvokeDexCallingConventionVisitor* calling_convention_visitor) {
81*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) {
82*795d594fSAndroid Build Coastguard Worker       HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
83*795d594fSAndroid Build Coastguard Worker       // Explicit clinit checks triggered by static invokes must have been
84*795d594fSAndroid Build Coastguard Worker       // pruned by art::PrepareForRegisterAllocation.
85*795d594fSAndroid Build Coastguard Worker       DCHECK(!invoke_static_or_direct->IsStaticWithExplicitClinitCheck());
86*795d594fSAndroid Build Coastguard Worker     }
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker     if (invoke->GetNumberOfArguments() == 0) {
89*795d594fSAndroid Build Coastguard Worker       // No argument to move.
90*795d594fSAndroid Build Coastguard Worker       return;
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = invoke->GetLocations();
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker     // We're moving potentially two or more locations to locations that could overlap, so we need
96*795d594fSAndroid Build Coastguard Worker     // a parallel move resolver.
97*795d594fSAndroid Build Coastguard Worker     HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
100*795d594fSAndroid Build Coastguard Worker       HInstruction* input = invoke->InputAt(i);
101*795d594fSAndroid Build Coastguard Worker       Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType());
102*795d594fSAndroid Build Coastguard Worker       Location actual_loc = locations->InAt(i);
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker       parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr);
105*795d594fSAndroid Build Coastguard Worker     }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker   static void ComputeValueOfLocations(HInvoke* invoke,
111*795d594fSAndroid Build Coastguard Worker                                       CodeGenerator* codegen,
112*795d594fSAndroid Build Coastguard Worker                                       int32_t low,
113*795d594fSAndroid Build Coastguard Worker                                       int32_t length,
114*795d594fSAndroid Build Coastguard Worker                                       Location return_location,
115*795d594fSAndroid Build Coastguard Worker                                       Location first_argument_location);
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker   // Temporary data structure for holding BoxedType.valueOf data for generating code.
118*795d594fSAndroid Build Coastguard Worker   struct ValueOfInfo {
119*795d594fSAndroid Build Coastguard Worker     static constexpr uint32_t kInvalidReference = static_cast<uint32_t>(-1);
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker     ValueOfInfo();
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker     // Offset of the value field of the boxed object for initializing a newly allocated instance.
124*795d594fSAndroid Build Coastguard Worker     uint32_t value_offset;
125*795d594fSAndroid Build Coastguard Worker     // The low value in the cache.
126*795d594fSAndroid Build Coastguard Worker     int32_t low;
127*795d594fSAndroid Build Coastguard Worker     // The length of the cache array.
128*795d594fSAndroid Build Coastguard Worker     uint32_t length;
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker     // This union contains references to the boot image. For app AOT or JIT compilation,
131*795d594fSAndroid Build Coastguard Worker     // these are the boot image offsets of the target. For boot image compilation, the
132*795d594fSAndroid Build Coastguard Worker     // location shall be known only at link time, so we encode a symbolic reference using
133*795d594fSAndroid Build Coastguard Worker     // IntrinsicObjects::EncodePatch().
134*795d594fSAndroid Build Coastguard Worker     union {
135*795d594fSAndroid Build Coastguard Worker       // The target value for a constant input in the cache range. If the constant input
136*795d594fSAndroid Build Coastguard Worker       // is out of range (use `low` and `length` to check), this value is bogus (set to
137*795d594fSAndroid Build Coastguard Worker       // kInvalidReference) and the code must allocate a new Integer.
138*795d594fSAndroid Build Coastguard Worker       uint32_t value_boot_image_reference;
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker       // The cache array data used for a non-constant input in the cache range.
141*795d594fSAndroid Build Coastguard Worker       // If the input is out of range, the code must allocate a new Integer.
142*795d594fSAndroid Build Coastguard Worker       uint32_t array_data_boot_image_reference;
143*795d594fSAndroid Build Coastguard Worker     };
144*795d594fSAndroid Build Coastguard Worker   };
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker   static ValueOfInfo ComputeValueOfInfo(
147*795d594fSAndroid Build Coastguard Worker       HInvoke* invoke,
148*795d594fSAndroid Build Coastguard Worker       const CompilerOptions& compiler_options,
149*795d594fSAndroid Build Coastguard Worker       ArtField* value_field,
150*795d594fSAndroid Build Coastguard Worker       int32_t low,
151*795d594fSAndroid Build Coastguard Worker       int32_t length,
152*795d594fSAndroid Build Coastguard Worker       size_t base);
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker   static MemberOffset GetReferenceDisableIntrinsicOffset();
155*795d594fSAndroid Build Coastguard Worker   static MemberOffset GetReferenceSlowPathEnabledOffset();
156*795d594fSAndroid Build Coastguard Worker   static void CreateReferenceGetReferentLocations(HInvoke* invoke, CodeGenerator* codegen);
157*795d594fSAndroid Build Coastguard Worker   static void CreateReferenceRefersToLocations(HInvoke* invoke, CodeGenerator* codegen);
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker  protected:
IntrinsicVisitor()160*795d594fSAndroid Build Coastguard Worker   IntrinsicVisitor() {}
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker   static void AssertNonMovableStringClass();
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker  private:
165*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor);
166*795d594fSAndroid Build Coastguard Worker };
167*795d594fSAndroid Build Coastguard Worker 
IsIntrinsicWithSpecializedHir(Intrinsics intrinsic)168*795d594fSAndroid Build Coastguard Worker static inline bool IsIntrinsicWithSpecializedHir(Intrinsics intrinsic) {
169*795d594fSAndroid Build Coastguard Worker   switch (intrinsic) {
170*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR(Name, ...) \
171*795d594fSAndroid Build Coastguard Worker     case Intrinsics::k ## Name:
172*795d594fSAndroid Build Coastguard Worker       ART_INTRINSICS_WITH_SPECIALIZED_HIR_LIST(OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR)
173*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS_WITH_SPECIALIZED_HIR
174*795d594fSAndroid Build Coastguard Worker       return true;
175*795d594fSAndroid Build Coastguard Worker     default:
176*795d594fSAndroid Build Coastguard Worker       return false;
177*795d594fSAndroid Build Coastguard Worker   }
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker 
IsValidIntrinsicAfterBuilder(Intrinsics intrinsic)180*795d594fSAndroid Build Coastguard Worker static inline bool IsValidIntrinsicAfterBuilder(Intrinsics intrinsic) {
181*795d594fSAndroid Build Coastguard Worker   return !IsIntrinsicWithSpecializedHir(intrinsic) ||
182*795d594fSAndroid Build Coastguard Worker          // FIXME: The inliner can currently create graphs with any of the intrinsics with HIR.
183*795d594fSAndroid Build Coastguard Worker          // However, we are able to compensate for `StringCharAt` and `StringLength` in the
184*795d594fSAndroid Build Coastguard Worker          // `HInstructionSimplifier`, so we're allowing these two intrinsics for now, preserving
185*795d594fSAndroid Build Coastguard Worker          // the old behavior. Besides fixing the bug, we should also clean up the simplifier
186*795d594fSAndroid Build Coastguard Worker          // and remove `SimplifyStringCharAt` and `SimplifyStringLength`. Bug: 319045458
187*795d594fSAndroid Build Coastguard Worker          intrinsic == Intrinsics::kStringCharAt ||
188*795d594fSAndroid Build Coastguard Worker          intrinsic == Intrinsics::kStringLength;
189*795d594fSAndroid Build Coastguard Worker }
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker #define GENERIC_OPTIMIZATION(name, bit)                \
192*795d594fSAndroid Build Coastguard Worker public:                                                \
193*795d594fSAndroid Build Coastguard Worker void Set##name() { SetBit(k##name); }                  \
194*795d594fSAndroid Build Coastguard Worker bool Get##name() const { return IsBitSet(k##name); }   \
195*795d594fSAndroid Build Coastguard Worker private:                                               \
196*795d594fSAndroid Build Coastguard Worker static constexpr size_t k##name = bit
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker class IntrinsicOptimizations : public ValueObject {
199*795d594fSAndroid Build Coastguard Worker  public:
IntrinsicOptimizations(HInvoke * invoke)200*795d594fSAndroid Build Coastguard Worker   explicit IntrinsicOptimizations(HInvoke* invoke)
201*795d594fSAndroid Build Coastguard Worker       : value_(invoke->GetIntrinsicOptimizations()) {}
IntrinsicOptimizations(const HInvoke & invoke)202*795d594fSAndroid Build Coastguard Worker   explicit IntrinsicOptimizations(const HInvoke& invoke)
203*795d594fSAndroid Build Coastguard Worker       : value_(invoke.GetIntrinsicOptimizations()) {}
204*795d594fSAndroid Build Coastguard Worker 
205*795d594fSAndroid Build Coastguard Worker   static constexpr int kNumberOfGenericOptimizations = 1;
206*795d594fSAndroid Build Coastguard Worker   GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 0);
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker  protected:
IsBitSet(uint32_t bit)209*795d594fSAndroid Build Coastguard Worker   bool IsBitSet(uint32_t bit) const {
210*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
211*795d594fSAndroid Build Coastguard Worker     return (*value_ & (1 << bit)) != 0u;
212*795d594fSAndroid Build Coastguard Worker   }
213*795d594fSAndroid Build Coastguard Worker 
SetBit(uint32_t bit)214*795d594fSAndroid Build Coastguard Worker   void SetBit(uint32_t bit) {
215*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
216*795d594fSAndroid Build Coastguard Worker     *(const_cast<uint32_t* const>(value_)) |= (1 << bit);
217*795d594fSAndroid Build Coastguard Worker   }
218*795d594fSAndroid Build Coastguard Worker 
219*795d594fSAndroid Build Coastguard Worker  private:
220*795d594fSAndroid Build Coastguard Worker   const uint32_t* const value_;
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations);
223*795d594fSAndroid Build Coastguard Worker };
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker #undef GENERIC_OPTIMIZATION
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker #define INTRINSIC_OPTIMIZATION(name, bit)                             \
228*795d594fSAndroid Build Coastguard Worker public:                                                               \
229*795d594fSAndroid Build Coastguard Worker void Set##name() { SetBit(k##name); }                                 \
230*795d594fSAndroid Build Coastguard Worker bool Get##name() const { return IsBitSet(k##name); }                  \
231*795d594fSAndroid Build Coastguard Worker private:                                                              \
232*795d594fSAndroid Build Coastguard Worker static constexpr size_t k##name = (bit) + kNumberOfGenericOptimizations
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker class StringEqualsOptimizations : public IntrinsicOptimizations {
235*795d594fSAndroid Build Coastguard Worker  public:
StringEqualsOptimizations(HInvoke * invoke)236*795d594fSAndroid Build Coastguard Worker   explicit StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
239*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker  private:
242*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
243*795d594fSAndroid Build Coastguard Worker };
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker class SystemArrayCopyOptimizations : public IntrinsicOptimizations {
246*795d594fSAndroid Build Coastguard Worker  public:
SystemArrayCopyOptimizations(HInvoke * invoke)247*795d594fSAndroid Build Coastguard Worker   explicit SystemArrayCopyOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(SourceIsNotNull, 0);
250*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DestinationIsNotNull, 1);
251*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DestinationIsSource, 2);
252*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(CountIsSourceLength, 3);
253*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(CountIsDestinationLength, 4);
254*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DoesNotNeedTypeCheck, 5);
255*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DestinationIsTypedObjectArray, 6);
256*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DestinationIsNonPrimitiveArray, 7);
257*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DestinationIsPrimitiveArray, 8);
258*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(SourceIsNonPrimitiveArray, 9);
259*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(SourceIsPrimitiveArray, 10);
260*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(SourcePositionIsDestinationPosition, 11);
261*795d594fSAndroid Build Coastguard Worker 
262*795d594fSAndroid Build Coastguard Worker  private:
263*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations);
264*795d594fSAndroid Build Coastguard Worker };
265*795d594fSAndroid Build Coastguard Worker 
266*795d594fSAndroid Build Coastguard Worker class VarHandleOptimizations : public IntrinsicOptimizations {
267*795d594fSAndroid Build Coastguard Worker  public:
VarHandleOptimizations(HInvoke * invoke)268*795d594fSAndroid Build Coastguard Worker   explicit VarHandleOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
269*795d594fSAndroid Build Coastguard Worker 
270*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(DoNotIntrinsify, 0);  // One of the checks is statically known to fail.
271*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(SkipObjectNullCheck, 1);  // Not applicable for static fields.
272*795d594fSAndroid Build Coastguard Worker 
273*795d594fSAndroid Build Coastguard Worker   // Use known `VarHandle` from the boot image. To apply this optimization, the following
274*795d594fSAndroid Build Coastguard Worker   // `VarHandle` checks must pass based on static analysis:
275*795d594fSAndroid Build Coastguard Worker   //   - `VarHandle` type check (must match the coordinate count),
276*795d594fSAndroid Build Coastguard Worker   //   - access mode check,
277*795d594fSAndroid Build Coastguard Worker   //   - var type check (including assignability for reference types),
278*795d594fSAndroid Build Coastguard Worker   //   - object type check (except for static field VarHandles that do not take an object).
279*795d594fSAndroid Build Coastguard Worker   // Note that the object null check is controlled by the above flag `SkipObjectNullCheck`
280*795d594fSAndroid Build Coastguard Worker   // and arrays and byte array views (which always need a range check and sometimes also
281*795d594fSAndroid Build Coastguard Worker   // array type check) are currently unsupported.
282*795d594fSAndroid Build Coastguard Worker   INTRINSIC_OPTIMIZATION(UseKnownImageVarHandle, 2);
283*795d594fSAndroid Build Coastguard Worker };
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker #undef INTRISIC_OPTIMIZATION
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker //
288*795d594fSAndroid Build Coastguard Worker // Macros for use in the intrinsics code generators.
289*795d594fSAndroid Build Coastguard Worker //
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker // Defines an unimplemented intrinsic: that is, a method call that is recognized as an
292*795d594fSAndroid Build Coastguard Worker // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled
293*795d594fSAndroid Build Coastguard Worker // by this architecture-specific intrinsics code generator. Eventually it is implemented
294*795d594fSAndroid Build Coastguard Worker // as a true method call.
295*795d594fSAndroid Build Coastguard Worker #define UNIMPLEMENTED_INTRINSIC(Arch, Name)                                              \
296*795d594fSAndroid Build Coastguard Worker   void IntrinsicLocationsBuilder##Arch::Visit##Name([[maybe_unused]] HInvoke* invoke) {} \
297*795d594fSAndroid Build Coastguard Worker   void IntrinsicCodeGenerator##Arch::Visit##Name([[maybe_unused]] HInvoke* invoke) {}
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker // Defines a list of unreached intrinsics: that is, method calls that are recognized as
300*795d594fSAndroid Build Coastguard Worker // an intrinsic, and then always converted into HIR instructions before they reach any
301*795d594fSAndroid Build Coastguard Worker // architecture-specific intrinsics code generator. This only applies to non-baseline
302*795d594fSAndroid Build Coastguard Worker // compilation.
303*795d594fSAndroid Build Coastguard Worker #define UNREACHABLE_INTRINSIC(Arch, Name)                                \
304*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \
305*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current()->IsAotCompiler() &&                             \
306*795d594fSAndroid Build Coastguard Worker       !codegen_->GetCompilerOptions().IsBaseline()) {                    \
307*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()    \
308*795d594fSAndroid Build Coastguard Worker                << " should have been converted to HIR";                  \
309*795d594fSAndroid Build Coastguard Worker   }                                                                      \
310*795d594fSAndroid Build Coastguard Worker }                                                                        \
311*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) {    \
312*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
313*795d594fSAndroid Build Coastguard Worker              << " should have been converted to HIR";                    \
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker #define UNREACHABLE_INTRINSICS(Arch)                            \
316*795d594fSAndroid Build Coastguard Worker UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)                \
317*795d594fSAndroid Build Coastguard Worker UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits)
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker template <typename IntrinsicLocationsBuilder, typename Codegenerator>
IsCallFreeIntrinsic(HInvoke * invoke,Codegenerator * codegen)320*795d594fSAndroid Build Coastguard Worker bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
321*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() != Intrinsics::kNone) {
322*795d594fSAndroid Build Coastguard Worker     // This invoke may have intrinsic code generation defined. However, we must
323*795d594fSAndroid Build Coastguard Worker     // now also determine if this code generation is truly there and call-free
324*795d594fSAndroid Build Coastguard Worker     // (not unimplemented, no bail on instruction features, or call on slow path).
325*795d594fSAndroid Build Coastguard Worker     // This is done by actually calling the locations builder on the instruction
326*795d594fSAndroid Build Coastguard Worker     // and clearing out the locations once result is known. We assume this
327*795d594fSAndroid Build Coastguard Worker     // call only has creating locations as side effects!
328*795d594fSAndroid Build Coastguard Worker     // TODO: Avoid wasting Arena memory.
329*795d594fSAndroid Build Coastguard Worker     IntrinsicLocationsBuilder builder(codegen);
330*795d594fSAndroid Build Coastguard Worker     bool success = builder.TryDispatch(invoke) && !invoke->GetLocations()->CanCall();
331*795d594fSAndroid Build Coastguard Worker     invoke->SetLocations(nullptr);
332*795d594fSAndroid Build Coastguard Worker     return success;
333*795d594fSAndroid Build Coastguard Worker   }
334*795d594fSAndroid Build Coastguard Worker   return false;
335*795d594fSAndroid Build Coastguard Worker }
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker // Insert a `Float.floatToRawIntBits()` or `Double.doubleToRawLongBits()` intrinsic for a
338*795d594fSAndroid Build Coastguard Worker // given input. These fake calls are needed on arm and riscv64 to satisfy type consistency
339*795d594fSAndroid Build Coastguard Worker // checks while passing certain FP args in core registers for direct @CriticalNative calls.
340*795d594fSAndroid Build Coastguard Worker void InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect* invoke, size_t input_index);
341*795d594fSAndroid Build Coastguard Worker 
342*795d594fSAndroid Build Coastguard Worker }  // namespace art
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_H_
345