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:
IntrinsicsRecognizer(HGraph * graph,CompilerDriver * driver,OptimizingCompilerStats * stats)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:
~IntrinsicVisitor()52 virtual ~IntrinsicVisitor() {}
53
54 // Dispatch logic.
55
Dispatch(HInvoke * invoke)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"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)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:
IntrinsicVisitor()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:
IntrinsicOptimizations(HInvoke * invoke)131 explicit IntrinsicOptimizations(HInvoke* invoke)
132 : value_(invoke->GetIntrinsicOptimizations()) {}
IntrinsicOptimizations(const HInvoke & invoke)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:
IsBitSet(uint32_t bit)141 bool IsBitSet(uint32_t bit) const {
142 DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
143 return (*value_ & (1 << bit)) != 0u;
144 }
145
SetBit(uint32_t bit)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:
StringEqualsOptimizations(HInvoke * invoke)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:
SystemArrayCopyOptimizations(HInvoke * invoke)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