blob: a3cb144223fc794ec138159ad16127b8fe9f335a [file] [log] [blame]
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001/*
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#include "intrinsics.h"
18
19#include "dex/quick/dex_file_method_inliner.h"
20#include "dex/quick/dex_file_to_method_inliner_map.h"
21#include "driver/compiler_driver.h"
22#include "invoke_type.h"
23#include "nodes.h"
24#include "quick/inline_method_analyser.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010025#include "utils.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080026
27namespace art {
28
29// Function that returns whether an intrinsic is static/direct or virtual.
30static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
31 switch (i) {
32 case Intrinsics::kNone:
33 return kInterface; // Non-sensical for intrinsic.
agicsaki57b81ec2015-08-11 17:39:37 -070034#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -080035 case Intrinsics::k ## Name: \
36 return IsStatic;
37#include "intrinsics_list.h"
38INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
39#undef INTRINSICS_LIST
40#undef OPTIMIZING_INTRINSICS
41 }
42 return kInterface;
43}
44
agicsaki57b81ec2015-08-11 17:39:37 -070045// Function that returns whether an intrinsic needs an environment or not.
46static inline IntrinsicNeedsEnvironment IntrinsicNeedsEnvironment(Intrinsics i) {
47 switch (i) {
48 case Intrinsics::kNone:
49 return kNeedsEnvironment; // Non-sensical for intrinsic.
50#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \
51 case Intrinsics::k ## Name: \
52 return NeedsEnvironment;
53#include "intrinsics_list.h"
54INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
55#undef INTRINSICS_LIST
56#undef OPTIMIZING_INTRINSICS
57 }
58 return kNeedsEnvironment;
59}
Andreas Gampe71fb52f2014-12-29 17:43:08 -080060
61static Primitive::Type GetType(uint64_t data, bool is_op_size) {
62 if (is_op_size) {
63 switch (static_cast<OpSize>(data)) {
64 case kSignedByte:
Andreas Gampe878d58c2015-01-15 23:24:00 -080065 return Primitive::kPrimByte;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080066 case kSignedHalf:
Andreas Gampe878d58c2015-01-15 23:24:00 -080067 return Primitive::kPrimShort;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080068 case k32:
Andreas Gampe878d58c2015-01-15 23:24:00 -080069 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080070 case k64:
Andreas Gampe878d58c2015-01-15 23:24:00 -080071 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080072 default:
73 LOG(FATAL) << "Unknown/unsupported op size " << data;
74 UNREACHABLE();
75 }
76 } else {
77 if ((data & kIntrinsicFlagIsLong) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080078 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080079 }
80 if ((data & kIntrinsicFlagIsObject) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080081 return Primitive::kPrimNot;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080082 }
Andreas Gampe878d58c2015-01-15 23:24:00 -080083 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080084 }
85}
86
87static Intrinsics GetIntrinsic(InlineMethod method) {
88 switch (method.opcode) {
89 // Floating-point conversions.
90 case kIntrinsicDoubleCvt:
91 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
92 Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
93 case kIntrinsicFloatCvt:
94 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
95 Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
96
97 // Bit manipulations.
98 case kIntrinsicReverseBits:
99 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800100 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800101 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800102 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800103 return Intrinsics::kLongReverse;
104 default:
105 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
106 UNREACHABLE();
107 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800108 case kIntrinsicReverseBytes:
109 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800110 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800111 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800112 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800113 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800114 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800115 return Intrinsics::kLongReverseBytes;
116 default:
117 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
118 UNREACHABLE();
119 }
Scott Wakeling611d3392015-07-10 11:42:06 +0100120 case kIntrinsicNumberOfLeadingZeros:
121 switch (GetType(method.d.data, true)) {
122 case Primitive::kPrimInt:
123 return Intrinsics::kIntegerNumberOfLeadingZeros;
124 case Primitive::kPrimLong:
125 return Intrinsics::kLongNumberOfLeadingZeros;
126 default:
127 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
128 UNREACHABLE();
129 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800130
131 // Abs.
132 case kIntrinsicAbsDouble:
133 return Intrinsics::kMathAbsDouble;
134 case kIntrinsicAbsFloat:
135 return Intrinsics::kMathAbsFloat;
136 case kIntrinsicAbsInt:
137 return Intrinsics::kMathAbsInt;
138 case kIntrinsicAbsLong:
139 return Intrinsics::kMathAbsLong;
140
141 // Min/max.
142 case kIntrinsicMinMaxDouble:
143 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
144 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
145 case kIntrinsicMinMaxFloat:
146 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
147 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
148 case kIntrinsicMinMaxInt:
149 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
150 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
151 case kIntrinsicMinMaxLong:
152 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
153 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
154
155 // Misc math.
156 case kIntrinsicSqrt:
157 return Intrinsics::kMathSqrt;
158 case kIntrinsicCeil:
159 return Intrinsics::kMathCeil;
160 case kIntrinsicFloor:
161 return Intrinsics::kMathFloor;
162 case kIntrinsicRint:
163 return Intrinsics::kMathRint;
164 case kIntrinsicRoundDouble:
165 return Intrinsics::kMathRoundDouble;
166 case kIntrinsicRoundFloat:
167 return Intrinsics::kMathRoundFloat;
168
169 // System.arraycopy.
170 case kIntrinsicSystemArrayCopyCharArray:
171 return Intrinsics::kSystemArrayCopyChar;
172
173 // Thread.currentThread.
174 case kIntrinsicCurrentThread:
175 return Intrinsics::kThreadCurrentThread;
176
177 // Memory.peek.
178 case kIntrinsicPeek:
179 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800180 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800181 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800182 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800183 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800184 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800185 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800186 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800187 return Intrinsics::kMemoryPeekLongNative;
188 default:
189 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
190 UNREACHABLE();
191 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800192
193 // Memory.poke.
194 case kIntrinsicPoke:
195 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800196 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800197 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800198 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800199 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800200 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800201 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800202 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800203 return Intrinsics::kMemoryPokeLongNative;
204 default:
205 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
206 UNREACHABLE();
207 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800208
209 // String.
210 case kIntrinsicCharAt:
211 return Intrinsics::kStringCharAt;
212 case kIntrinsicCompareTo:
213 return Intrinsics::kStringCompareTo;
Jeff Hao848f70a2014-01-15 13:49:50 -0800214 case kIntrinsicGetCharsNoCheck:
215 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800216 case kIntrinsicIsEmptyOrLength:
Razvan A Lupusoru3e90a962015-03-27 13:44:44 -0700217 // The inliner can handle these two cases - and this is the preferred approach
218 // since after inlining the call is no longer visible (as opposed to waiting
219 // until codegen to handle intrinsic).
220 return Intrinsics::kNone;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800221 case kIntrinsicIndexOf:
222 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
223 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800224 case kIntrinsicNewStringFromBytes:
225 return Intrinsics::kStringNewStringFromBytes;
226 case kIntrinsicNewStringFromChars:
227 return Intrinsics::kStringNewStringFromChars;
228 case kIntrinsicNewStringFromString:
229 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800230
231 case kIntrinsicCas:
232 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800233 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800234 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800235 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800236 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800237 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800238 return Intrinsics::kUnsafeCASLong;
239 default:
240 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
241 UNREACHABLE();
242 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800243 case kIntrinsicUnsafeGet: {
244 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
245 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800246 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800247 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800248 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800249 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800250 case Primitive::kPrimNot:
251 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800252 default:
253 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
254 UNREACHABLE();
255 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800256 }
257 case kIntrinsicUnsafePut: {
258 enum Sync { kNoSync, kVolatile, kOrdered };
259 const Sync sync =
260 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
261 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
262 kNoSync;
263 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800264 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800265 switch (sync) {
266 case kNoSync:
267 return Intrinsics::kUnsafePut;
268 case kVolatile:
269 return Intrinsics::kUnsafePutVolatile;
270 case kOrdered:
271 return Intrinsics::kUnsafePutOrdered;
272 }
273 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800274 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800275 switch (sync) {
276 case kNoSync:
277 return Intrinsics::kUnsafePutLong;
278 case kVolatile:
279 return Intrinsics::kUnsafePutLongVolatile;
280 case kOrdered:
281 return Intrinsics::kUnsafePutLongOrdered;
282 }
283 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800284 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800285 switch (sync) {
286 case kNoSync:
287 return Intrinsics::kUnsafePutObject;
288 case kVolatile:
289 return Intrinsics::kUnsafePutObjectVolatile;
290 case kOrdered:
291 return Intrinsics::kUnsafePutObjectOrdered;
292 }
293 break;
294 default:
295 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
296 UNREACHABLE();
297 }
298 break;
299 }
300
301 // Virtual cases.
302
303 case kIntrinsicReferenceGetReferent:
304 return Intrinsics::kReferenceGetReferent;
305
306 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
307 // compiler to warn on missing cases.
308
309 case kInlineOpNop:
310 case kInlineOpReturnArg:
311 case kInlineOpNonWideConst:
312 case kInlineOpIGet:
313 case kInlineOpIPut:
314 return Intrinsics::kNone;
315
Jeff Hao848f70a2014-01-15 13:49:50 -0800316 // String init cases, not intrinsics.
317
318 case kInlineStringInit:
319 return Intrinsics::kNone;
320
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800321 // No default case to make the compiler warn on missing cases.
322 }
323 return Intrinsics::kNone;
324}
325
326static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
327 // The DexFileMethodInliner should have checked whether the methods are agreeing with
328 // what we expect, i.e., static methods are called as such. Add another check here for
329 // our expectations:
330 // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
331 // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
332 // functions that will perform a check inline. If the precise type is known, however,
333 // the instruction will be sharpened to an InvokeStaticOrDirect.
334 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
335 InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
336 invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
337 invoke->IsInvokeVirtual() ? kVirtual : kSuper;
338 switch (intrinsic_type) {
339 case kStatic:
340 return (invoke_type == kStatic);
341 case kDirect:
342 return (invoke_type == kDirect);
343 case kVirtual:
344 // Call might be devirtualized.
345 return (invoke_type == kVirtual || invoke_type == kDirect);
346
347 default:
348 return false;
349 }
350}
351
352// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
353void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800354 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
355 HBasicBlock* block = it.Current();
356 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
357 inst_it.Advance()) {
358 HInstruction* inst = inst_it.Current();
359 if (inst->IsInvoke()) {
360 HInvoke* invoke = inst->AsInvoke();
361 InlineMethod method;
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100362 DexFileMethodInliner* inliner =
363 driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
364 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800365 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
366 Intrinsics intrinsic = GetIntrinsic(method);
367
368 if (intrinsic != Intrinsics::kNone) {
369 if (!CheckInvokeType(intrinsic, invoke)) {
370 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
371 << intrinsic << " for "
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100372 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800373 } else {
agicsaki57b81ec2015-08-11 17:39:37 -0700374 invoke->SetIntrinsic(intrinsic, IntrinsicNeedsEnvironment(intrinsic));
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800375 }
376 }
377 }
378 }
379 }
380 }
381}
382
383std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
384 switch (intrinsic) {
385 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100386 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800387 break;
agicsaki57b81ec2015-08-11 17:39:37 -0700388#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800389 case Intrinsics::k ## Name: \
390 os << # Name; \
391 break;
392#include "intrinsics_list.h"
393INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
394#undef STATIC_INTRINSICS_LIST
395#undef VIRTUAL_INTRINSICS_LIST
396#undef OPTIMIZING_INTRINSICS
397 }
398 return os;
399}
400
401} // namespace art