blob: 55e964ea8df99aad32eb098b3a73062fdcf7dbaf [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.
34#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
35 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
45
46
47static Primitive::Type GetType(uint64_t data, bool is_op_size) {
48 if (is_op_size) {
49 switch (static_cast<OpSize>(data)) {
50 case kSignedByte:
Andreas Gampe878d58c2015-01-15 23:24:00 -080051 return Primitive::kPrimByte;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080052 case kSignedHalf:
Andreas Gampe878d58c2015-01-15 23:24:00 -080053 return Primitive::kPrimShort;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080054 case k32:
Andreas Gampe878d58c2015-01-15 23:24:00 -080055 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080056 case k64:
Andreas Gampe878d58c2015-01-15 23:24:00 -080057 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080058 default:
59 LOG(FATAL) << "Unknown/unsupported op size " << data;
60 UNREACHABLE();
61 }
62 } else {
63 if ((data & kIntrinsicFlagIsLong) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080064 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080065 }
66 if ((data & kIntrinsicFlagIsObject) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080067 return Primitive::kPrimNot;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080068 }
Andreas Gampe878d58c2015-01-15 23:24:00 -080069 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080070 }
71}
72
73static Intrinsics GetIntrinsic(InlineMethod method) {
74 switch (method.opcode) {
75 // Floating-point conversions.
76 case kIntrinsicDoubleCvt:
77 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
78 Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
79 case kIntrinsicFloatCvt:
80 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
81 Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
82
83 // Bit manipulations.
84 case kIntrinsicReverseBits:
85 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080086 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -080087 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -080088 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -080089 return Intrinsics::kLongReverse;
90 default:
91 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
92 UNREACHABLE();
93 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -080094 case kIntrinsicReverseBytes:
95 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080096 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -080097 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -080098 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -080099 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800100 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800101 return Intrinsics::kLongReverseBytes;
102 default:
103 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
104 UNREACHABLE();
105 }
Scott Wakeling611d3392015-07-10 11:42:06 +0100106 case kIntrinsicNumberOfLeadingZeros:
107 switch (GetType(method.d.data, true)) {
108 case Primitive::kPrimInt:
109 return Intrinsics::kIntegerNumberOfLeadingZeros;
110 case Primitive::kPrimLong:
111 return Intrinsics::kLongNumberOfLeadingZeros;
112 default:
113 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
114 UNREACHABLE();
115 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800116
117 // Abs.
118 case kIntrinsicAbsDouble:
119 return Intrinsics::kMathAbsDouble;
120 case kIntrinsicAbsFloat:
121 return Intrinsics::kMathAbsFloat;
122 case kIntrinsicAbsInt:
123 return Intrinsics::kMathAbsInt;
124 case kIntrinsicAbsLong:
125 return Intrinsics::kMathAbsLong;
126
127 // Min/max.
128 case kIntrinsicMinMaxDouble:
129 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
130 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
131 case kIntrinsicMinMaxFloat:
132 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
133 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
134 case kIntrinsicMinMaxInt:
135 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
136 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
137 case kIntrinsicMinMaxLong:
138 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
139 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
140
141 // Misc math.
142 case kIntrinsicSqrt:
143 return Intrinsics::kMathSqrt;
144 case kIntrinsicCeil:
145 return Intrinsics::kMathCeil;
146 case kIntrinsicFloor:
147 return Intrinsics::kMathFloor;
148 case kIntrinsicRint:
149 return Intrinsics::kMathRint;
150 case kIntrinsicRoundDouble:
151 return Intrinsics::kMathRoundDouble;
152 case kIntrinsicRoundFloat:
153 return Intrinsics::kMathRoundFloat;
154
155 // System.arraycopy.
156 case kIntrinsicSystemArrayCopyCharArray:
157 return Intrinsics::kSystemArrayCopyChar;
158
159 // Thread.currentThread.
160 case kIntrinsicCurrentThread:
161 return Intrinsics::kThreadCurrentThread;
162
163 // Memory.peek.
164 case kIntrinsicPeek:
165 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800166 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800167 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800168 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800169 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800170 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800171 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800172 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800173 return Intrinsics::kMemoryPeekLongNative;
174 default:
175 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
176 UNREACHABLE();
177 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800178
179 // Memory.poke.
180 case kIntrinsicPoke:
181 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800182 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800183 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800184 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800185 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800186 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800187 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800188 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800189 return Intrinsics::kMemoryPokeLongNative;
190 default:
191 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
192 UNREACHABLE();
193 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800194
195 // String.
196 case kIntrinsicCharAt:
197 return Intrinsics::kStringCharAt;
198 case kIntrinsicCompareTo:
199 return Intrinsics::kStringCompareTo;
Jeff Hao848f70a2014-01-15 13:49:50 -0800200 case kIntrinsicGetCharsNoCheck:
201 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800202 case kIntrinsicIsEmptyOrLength:
Razvan A Lupusoru3e90a962015-03-27 13:44:44 -0700203 // The inliner can handle these two cases - and this is the preferred approach
204 // since after inlining the call is no longer visible (as opposed to waiting
205 // until codegen to handle intrinsic).
206 return Intrinsics::kNone;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800207 case kIntrinsicIndexOf:
208 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
209 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800210 case kIntrinsicNewStringFromBytes:
211 return Intrinsics::kStringNewStringFromBytes;
212 case kIntrinsicNewStringFromChars:
213 return Intrinsics::kStringNewStringFromChars;
214 case kIntrinsicNewStringFromString:
215 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800216
217 case kIntrinsicCas:
218 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800219 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800220 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800221 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800222 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800223 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800224 return Intrinsics::kUnsafeCASLong;
225 default:
226 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
227 UNREACHABLE();
228 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800229 case kIntrinsicUnsafeGet: {
230 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
231 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800232 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800233 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800234 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800235 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800236 case Primitive::kPrimNot:
237 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800238 default:
239 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
240 UNREACHABLE();
241 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800242 }
243 case kIntrinsicUnsafePut: {
244 enum Sync { kNoSync, kVolatile, kOrdered };
245 const Sync sync =
246 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
247 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
248 kNoSync;
249 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800250 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800251 switch (sync) {
252 case kNoSync:
253 return Intrinsics::kUnsafePut;
254 case kVolatile:
255 return Intrinsics::kUnsafePutVolatile;
256 case kOrdered:
257 return Intrinsics::kUnsafePutOrdered;
258 }
259 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800260 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800261 switch (sync) {
262 case kNoSync:
263 return Intrinsics::kUnsafePutLong;
264 case kVolatile:
265 return Intrinsics::kUnsafePutLongVolatile;
266 case kOrdered:
267 return Intrinsics::kUnsafePutLongOrdered;
268 }
269 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800270 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800271 switch (sync) {
272 case kNoSync:
273 return Intrinsics::kUnsafePutObject;
274 case kVolatile:
275 return Intrinsics::kUnsafePutObjectVolatile;
276 case kOrdered:
277 return Intrinsics::kUnsafePutObjectOrdered;
278 }
279 break;
280 default:
281 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
282 UNREACHABLE();
283 }
284 break;
285 }
286
287 // Virtual cases.
288
289 case kIntrinsicReferenceGetReferent:
290 return Intrinsics::kReferenceGetReferent;
291
292 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
293 // compiler to warn on missing cases.
294
295 case kInlineOpNop:
296 case kInlineOpReturnArg:
297 case kInlineOpNonWideConst:
298 case kInlineOpIGet:
299 case kInlineOpIPut:
300 return Intrinsics::kNone;
301
Jeff Hao848f70a2014-01-15 13:49:50 -0800302 // String init cases, not intrinsics.
303
304 case kInlineStringInit:
305 return Intrinsics::kNone;
306
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800307 // No default case to make the compiler warn on missing cases.
308 }
309 return Intrinsics::kNone;
310}
311
312static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
313 // The DexFileMethodInliner should have checked whether the methods are agreeing with
314 // what we expect, i.e., static methods are called as such. Add another check here for
315 // our expectations:
316 // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
317 // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
318 // functions that will perform a check inline. If the precise type is known, however,
319 // the instruction will be sharpened to an InvokeStaticOrDirect.
320 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
321 InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
322 invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
323 invoke->IsInvokeVirtual() ? kVirtual : kSuper;
324 switch (intrinsic_type) {
325 case kStatic:
326 return (invoke_type == kStatic);
327 case kDirect:
328 return (invoke_type == kDirect);
329 case kVirtual:
330 // Call might be devirtualized.
331 return (invoke_type == kVirtual || invoke_type == kDirect);
332
333 default:
334 return false;
335 }
336}
337
338// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
339void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800340 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
341 HBasicBlock* block = it.Current();
342 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
343 inst_it.Advance()) {
344 HInstruction* inst = inst_it.Current();
345 if (inst->IsInvoke()) {
346 HInvoke* invoke = inst->AsInvoke();
347 InlineMethod method;
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100348 DexFileMethodInliner* inliner =
349 driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
350 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800351 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
352 Intrinsics intrinsic = GetIntrinsic(method);
353
354 if (intrinsic != Intrinsics::kNone) {
355 if (!CheckInvokeType(intrinsic, invoke)) {
356 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
357 << intrinsic << " for "
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100358 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800359 } else {
360 invoke->SetIntrinsic(intrinsic);
361 }
362 }
363 }
364 }
365 }
366 }
367}
368
369std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
370 switch (intrinsic) {
371 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100372 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800373 break;
374#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
375 case Intrinsics::k ## Name: \
376 os << # Name; \
377 break;
378#include "intrinsics_list.h"
379INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
380#undef STATIC_INTRINSICS_LIST
381#undef VIRTUAL_INTRINSICS_LIST
382#undef OPTIMIZING_INTRINSICS
383 }
384 return os;
385}
386
387} // namespace art