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(¶llel_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