• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "intrinsics_arm.h"
18 
19 #include "arch/arm/instruction_set_features_arm.h"
20 #include "art_method.h"
21 #include "code_generator_arm.h"
22 #include "entrypoints/quick/quick_entrypoints.h"
23 #include "intrinsics.h"
24 #include "intrinsics_utils.h"
25 #include "mirror/array-inl.h"
26 #include "mirror/string.h"
27 #include "thread.h"
28 #include "utils/arm/assembler_arm.h"
29 
30 namespace art {
31 
32 namespace arm {
33 
GetAssembler()34 ArmAssembler* IntrinsicCodeGeneratorARM::GetAssembler() {
35   return codegen_->GetAssembler();
36 }
37 
GetAllocator()38 ArenaAllocator* IntrinsicCodeGeneratorARM::GetAllocator() {
39   return codegen_->GetGraph()->GetArena();
40 }
41 
42 using IntrinsicSlowPathARM = IntrinsicSlowPath<InvokeDexCallingConventionVisitorARM>;
43 
TryDispatch(HInvoke * invoke)44 bool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) {
45   Dispatch(invoke);
46   LocationSummary* res = invoke->GetLocations();
47   if (res == nullptr) {
48     return false;
49   }
50   if (kEmitCompilerReadBarrier && res->CanCall()) {
51     // Generating an intrinsic for this HInvoke may produce an
52     // IntrinsicSlowPathARM slow path.  Currently this approach
53     // does not work when using read barriers, as the emitted
54     // calling sequence will make use of another slow path
55     // (ReadBarrierForRootSlowPathARM for HInvokeStaticOrDirect,
56     // ReadBarrierSlowPathARM for HInvokeVirtual).  So we bail
57     // out in this case.
58     //
59     // TODO: Find a way to have intrinsics work with read barriers.
60     invoke->SetLocations(nullptr);
61     return false;
62   }
63   return res->Intrinsified();
64 }
65 
66 #define __ assembler->
67 
CreateFPToIntLocations(ArenaAllocator * arena,HInvoke * invoke)68 static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
69   LocationSummary* locations = new (arena) LocationSummary(invoke,
70                                                            LocationSummary::kNoCall,
71                                                            kIntrinsified);
72   locations->SetInAt(0, Location::RequiresFpuRegister());
73   locations->SetOut(Location::RequiresRegister());
74 }
75 
CreateIntToFPLocations(ArenaAllocator * arena,HInvoke * invoke)76 static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
77   LocationSummary* locations = new (arena) LocationSummary(invoke,
78                                                            LocationSummary::kNoCall,
79                                                            kIntrinsified);
80   locations->SetInAt(0, Location::RequiresRegister());
81   locations->SetOut(Location::RequiresFpuRegister());
82 }
83 
MoveFPToInt(LocationSummary * locations,bool is64bit,ArmAssembler * assembler)84 static void MoveFPToInt(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
85   Location input = locations->InAt(0);
86   Location output = locations->Out();
87   if (is64bit) {
88     __ vmovrrd(output.AsRegisterPairLow<Register>(),
89                output.AsRegisterPairHigh<Register>(),
90                FromLowSToD(input.AsFpuRegisterPairLow<SRegister>()));
91   } else {
92     __ vmovrs(output.AsRegister<Register>(), input.AsFpuRegister<SRegister>());
93   }
94 }
95 
MoveIntToFP(LocationSummary * locations,bool is64bit,ArmAssembler * assembler)96 static void MoveIntToFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
97   Location input = locations->InAt(0);
98   Location output = locations->Out();
99   if (is64bit) {
100     __ vmovdrr(FromLowSToD(output.AsFpuRegisterPairLow<SRegister>()),
101                input.AsRegisterPairLow<Register>(),
102                input.AsRegisterPairHigh<Register>());
103   } else {
104     __ vmovsr(output.AsFpuRegister<SRegister>(), input.AsRegister<Register>());
105   }
106 }
107 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)108 void IntrinsicLocationsBuilderARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
109   CreateFPToIntLocations(arena_, invoke);
110 }
VisitDoubleLongBitsToDouble(HInvoke * invoke)111 void IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
112   CreateIntToFPLocations(arena_, invoke);
113 }
114 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)115 void IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
116   MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
117 }
VisitDoubleLongBitsToDouble(HInvoke * invoke)118 void IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
119   MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
120 }
121 
VisitFloatFloatToRawIntBits(HInvoke * invoke)122 void IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
123   CreateFPToIntLocations(arena_, invoke);
124 }
VisitFloatIntBitsToFloat(HInvoke * invoke)125 void IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) {
126   CreateIntToFPLocations(arena_, invoke);
127 }
128 
VisitFloatFloatToRawIntBits(HInvoke * invoke)129 void IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
130   MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
131 }
VisitFloatIntBitsToFloat(HInvoke * invoke)132 void IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) {
133   MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
134 }
135 
CreateIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke)136 static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
137   LocationSummary* locations = new (arena) LocationSummary(invoke,
138                                                            LocationSummary::kNoCall,
139                                                            kIntrinsified);
140   locations->SetInAt(0, Location::RequiresRegister());
141   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
142 }
143 
CreateFPToFPLocations(ArenaAllocator * arena,HInvoke * invoke)144 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
145   LocationSummary* locations = new (arena) LocationSummary(invoke,
146                                                            LocationSummary::kNoCall,
147                                                            kIntrinsified);
148   locations->SetInAt(0, Location::RequiresFpuRegister());
149   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
150 }
151 
GenNumberOfLeadingZeros(LocationSummary * locations,Primitive::Type type,ArmAssembler * assembler)152 static void GenNumberOfLeadingZeros(LocationSummary* locations,
153                                     Primitive::Type type,
154                                     ArmAssembler* assembler) {
155   Location in = locations->InAt(0);
156   Register out = locations->Out().AsRegister<Register>();
157 
158   DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong));
159 
160   if (type == Primitive::kPrimLong) {
161     Register in_reg_lo = in.AsRegisterPairLow<Register>();
162     Register in_reg_hi = in.AsRegisterPairHigh<Register>();
163     Label end;
164     __ clz(out, in_reg_hi);
165     __ CompareAndBranchIfNonZero(in_reg_hi, &end);
166     __ clz(out, in_reg_lo);
167     __ AddConstant(out, 32);
168     __ Bind(&end);
169   } else {
170     __ clz(out, in.AsRegister<Register>());
171   }
172 }
173 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)174 void IntrinsicLocationsBuilderARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
175   CreateIntToIntLocations(arena_, invoke);
176 }
177 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)178 void IntrinsicCodeGeneratorARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
179   GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
180 }
181 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)182 void IntrinsicLocationsBuilderARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
183   LocationSummary* locations = new (arena_) LocationSummary(invoke,
184                                                            LocationSummary::kNoCall,
185                                                            kIntrinsified);
186   locations->SetInAt(0, Location::RequiresRegister());
187   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
188 }
189 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)190 void IntrinsicCodeGeneratorARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
191   GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
192 }
193 
GenNumberOfTrailingZeros(LocationSummary * locations,Primitive::Type type,ArmAssembler * assembler)194 static void GenNumberOfTrailingZeros(LocationSummary* locations,
195                                      Primitive::Type type,
196                                      ArmAssembler* assembler) {
197   DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong));
198 
199   Register out = locations->Out().AsRegister<Register>();
200 
201   if (type == Primitive::kPrimLong) {
202     Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
203     Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
204     Label end;
205     __ rbit(out, in_reg_lo);
206     __ clz(out, out);
207     __ CompareAndBranchIfNonZero(in_reg_lo, &end);
208     __ rbit(out, in_reg_hi);
209     __ clz(out, out);
210     __ AddConstant(out, 32);
211     __ Bind(&end);
212   } else {
213     Register in = locations->InAt(0).AsRegister<Register>();
214     __ rbit(out, in);
215     __ clz(out, out);
216   }
217 }
218 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)219 void IntrinsicLocationsBuilderARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
220   LocationSummary* locations = new (arena_) LocationSummary(invoke,
221                                                             LocationSummary::kNoCall,
222                                                             kIntrinsified);
223   locations->SetInAt(0, Location::RequiresRegister());
224   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
225 }
226 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)227 void IntrinsicCodeGeneratorARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
228   GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
229 }
230 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)231 void IntrinsicLocationsBuilderARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
232   LocationSummary* locations = new (arena_) LocationSummary(invoke,
233                                                             LocationSummary::kNoCall,
234                                                             kIntrinsified);
235   locations->SetInAt(0, Location::RequiresRegister());
236   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
237 }
238 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)239 void IntrinsicCodeGeneratorARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
240   GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
241 }
242 
MathAbsFP(LocationSummary * locations,bool is64bit,ArmAssembler * assembler)243 static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
244   Location in = locations->InAt(0);
245   Location out = locations->Out();
246 
247   if (is64bit) {
248     __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
249              FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
250   } else {
251     __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
252   }
253 }
254 
VisitMathAbsDouble(HInvoke * invoke)255 void IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) {
256   CreateFPToFPLocations(arena_, invoke);
257 }
258 
VisitMathAbsDouble(HInvoke * invoke)259 void IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) {
260   MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
261 }
262 
VisitMathAbsFloat(HInvoke * invoke)263 void IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) {
264   CreateFPToFPLocations(arena_, invoke);
265 }
266 
VisitMathAbsFloat(HInvoke * invoke)267 void IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) {
268   MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
269 }
270 
CreateIntToIntPlusTemp(ArenaAllocator * arena,HInvoke * invoke)271 static void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) {
272   LocationSummary* locations = new (arena) LocationSummary(invoke,
273                                                            LocationSummary::kNoCall,
274                                                            kIntrinsified);
275   locations->SetInAt(0, Location::RequiresRegister());
276   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
277 
278   locations->AddTemp(Location::RequiresRegister());
279 }
280 
GenAbsInteger(LocationSummary * locations,bool is64bit,ArmAssembler * assembler)281 static void GenAbsInteger(LocationSummary* locations,
282                           bool is64bit,
283                           ArmAssembler* assembler) {
284   Location in = locations->InAt(0);
285   Location output = locations->Out();
286 
287   Register mask = locations->GetTemp(0).AsRegister<Register>();
288 
289   if (is64bit) {
290     Register in_reg_lo = in.AsRegisterPairLow<Register>();
291     Register in_reg_hi = in.AsRegisterPairHigh<Register>();
292     Register out_reg_lo = output.AsRegisterPairLow<Register>();
293     Register out_reg_hi = output.AsRegisterPairHigh<Register>();
294 
295     DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected.";
296 
297     __ Asr(mask, in_reg_hi, 31);
298     __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask));
299     __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask));
300     __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo));
301     __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi));
302   } else {
303     Register in_reg = in.AsRegister<Register>();
304     Register out_reg = output.AsRegister<Register>();
305 
306     __ Asr(mask, in_reg, 31);
307     __ add(out_reg, in_reg, ShifterOperand(mask));
308     __ eor(out_reg, mask, ShifterOperand(out_reg));
309   }
310 }
311 
VisitMathAbsInt(HInvoke * invoke)312 void IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) {
313   CreateIntToIntPlusTemp(arena_, invoke);
314 }
315 
VisitMathAbsInt(HInvoke * invoke)316 void IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) {
317   GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
318 }
319 
320 
VisitMathAbsLong(HInvoke * invoke)321 void IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) {
322   CreateIntToIntPlusTemp(arena_, invoke);
323 }
324 
VisitMathAbsLong(HInvoke * invoke)325 void IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) {
326   GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
327 }
328 
GenMinMax(LocationSummary * locations,bool is_min,ArmAssembler * assembler)329 static void GenMinMax(LocationSummary* locations,
330                       bool is_min,
331                       ArmAssembler* assembler) {
332   Register op1 = locations->InAt(0).AsRegister<Register>();
333   Register op2 = locations->InAt(1).AsRegister<Register>();
334   Register out = locations->Out().AsRegister<Register>();
335 
336   __ cmp(op1, ShifterOperand(op2));
337 
338   __ it((is_min) ? Condition::LT : Condition::GT, kItElse);
339   __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT);
340   __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE);
341 }
342 
CreateIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke)343 static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
344   LocationSummary* locations = new (arena) LocationSummary(invoke,
345                                                            LocationSummary::kNoCall,
346                                                            kIntrinsified);
347   locations->SetInAt(0, Location::RequiresRegister());
348   locations->SetInAt(1, Location::RequiresRegister());
349   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
350 }
351 
VisitMathMinIntInt(HInvoke * invoke)352 void IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) {
353   CreateIntIntToIntLocations(arena_, invoke);
354 }
355 
VisitMathMinIntInt(HInvoke * invoke)356 void IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) {
357   GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
358 }
359 
VisitMathMaxIntInt(HInvoke * invoke)360 void IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) {
361   CreateIntIntToIntLocations(arena_, invoke);
362 }
363 
VisitMathMaxIntInt(HInvoke * invoke)364 void IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) {
365   GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
366 }
367 
VisitMathSqrt(HInvoke * invoke)368 void IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) {
369   CreateFPToFPLocations(arena_, invoke);
370 }
371 
VisitMathSqrt(HInvoke * invoke)372 void IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) {
373   LocationSummary* locations = invoke->GetLocations();
374   ArmAssembler* assembler = GetAssembler();
375   __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
376             FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
377 }
378 
VisitMemoryPeekByte(HInvoke * invoke)379 void IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) {
380   CreateIntToIntLocations(arena_, invoke);
381 }
382 
VisitMemoryPeekByte(HInvoke * invoke)383 void IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) {
384   ArmAssembler* assembler = GetAssembler();
385   // Ignore upper 4B of long address.
386   __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(),
387            Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
388 }
389 
VisitMemoryPeekIntNative(HInvoke * invoke)390 void IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) {
391   CreateIntToIntLocations(arena_, invoke);
392 }
393 
VisitMemoryPeekIntNative(HInvoke * invoke)394 void IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) {
395   ArmAssembler* assembler = GetAssembler();
396   // Ignore upper 4B of long address.
397   __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(),
398          Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
399 }
400 
VisitMemoryPeekLongNative(HInvoke * invoke)401 void IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) {
402   CreateIntToIntLocations(arena_, invoke);
403 }
404 
VisitMemoryPeekLongNative(HInvoke * invoke)405 void IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) {
406   ArmAssembler* assembler = GetAssembler();
407   // Ignore upper 4B of long address.
408   Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
409   // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
410   // exception. So we can't use ldrd as addr may be unaligned.
411   Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
412   Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
413   if (addr == lo) {
414     __ ldr(hi, Address(addr, 4));
415     __ ldr(lo, Address(addr, 0));
416   } else {
417     __ ldr(lo, Address(addr, 0));
418     __ ldr(hi, Address(addr, 4));
419   }
420 }
421 
VisitMemoryPeekShortNative(HInvoke * invoke)422 void IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) {
423   CreateIntToIntLocations(arena_, invoke);
424 }
425 
VisitMemoryPeekShortNative(HInvoke * invoke)426 void IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) {
427   ArmAssembler* assembler = GetAssembler();
428   // Ignore upper 4B of long address.
429   __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(),
430            Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
431 }
432 
CreateIntIntToVoidLocations(ArenaAllocator * arena,HInvoke * invoke)433 static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
434   LocationSummary* locations = new (arena) LocationSummary(invoke,
435                                                            LocationSummary::kNoCall,
436                                                            kIntrinsified);
437   locations->SetInAt(0, Location::RequiresRegister());
438   locations->SetInAt(1, Location::RequiresRegister());
439 }
440 
VisitMemoryPokeByte(HInvoke * invoke)441 void IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) {
442   CreateIntIntToVoidLocations(arena_, invoke);
443 }
444 
VisitMemoryPokeByte(HInvoke * invoke)445 void IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) {
446   ArmAssembler* assembler = GetAssembler();
447   __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
448           Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
449 }
450 
VisitMemoryPokeIntNative(HInvoke * invoke)451 void IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) {
452   CreateIntIntToVoidLocations(arena_, invoke);
453 }
454 
VisitMemoryPokeIntNative(HInvoke * invoke)455 void IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) {
456   ArmAssembler* assembler = GetAssembler();
457   __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
458          Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
459 }
460 
VisitMemoryPokeLongNative(HInvoke * invoke)461 void IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) {
462   CreateIntIntToVoidLocations(arena_, invoke);
463 }
464 
VisitMemoryPokeLongNative(HInvoke * invoke)465 void IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) {
466   ArmAssembler* assembler = GetAssembler();
467   // Ignore upper 4B of long address.
468   Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
469   // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
470   // exception. So we can't use ldrd as addr may be unaligned.
471   __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0));
472   __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4));
473 }
474 
VisitMemoryPokeShortNative(HInvoke * invoke)475 void IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) {
476   CreateIntIntToVoidLocations(arena_, invoke);
477 }
478 
VisitMemoryPokeShortNative(HInvoke * invoke)479 void IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) {
480   ArmAssembler* assembler = GetAssembler();
481   __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
482           Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
483 }
484 
VisitThreadCurrentThread(HInvoke * invoke)485 void IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) {
486   LocationSummary* locations = new (arena_) LocationSummary(invoke,
487                                                             LocationSummary::kNoCall,
488                                                             kIntrinsified);
489   locations->SetOut(Location::RequiresRegister());
490 }
491 
VisitThreadCurrentThread(HInvoke * invoke)492 void IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) {
493   ArmAssembler* assembler = GetAssembler();
494   __ LoadFromOffset(kLoadWord,
495                     invoke->GetLocations()->Out().AsRegister<Register>(),
496                     TR,
497                     Thread::PeerOffset<kArmPointerSize>().Int32Value());
498 }
499 
GenUnsafeGet(HInvoke * invoke,Primitive::Type type,bool is_volatile,CodeGeneratorARM * codegen)500 static void GenUnsafeGet(HInvoke* invoke,
501                          Primitive::Type type,
502                          bool is_volatile,
503                          CodeGeneratorARM* codegen) {
504   LocationSummary* locations = invoke->GetLocations();
505   ArmAssembler* assembler = codegen->GetAssembler();
506   Location base_loc = locations->InAt(1);
507   Register base = base_loc.AsRegister<Register>();             // Object pointer.
508   Location offset_loc = locations->InAt(2);
509   Register offset = offset_loc.AsRegisterPairLow<Register>();  // Long offset, lo part only.
510   Location trg_loc = locations->Out();
511 
512   switch (type) {
513     case Primitive::kPrimInt: {
514       Register trg = trg_loc.AsRegister<Register>();
515       __ ldr(trg, Address(base, offset));
516       if (is_volatile) {
517         __ dmb(ISH);
518       }
519       break;
520     }
521 
522     case Primitive::kPrimNot: {
523       Register trg = trg_loc.AsRegister<Register>();
524       if (kEmitCompilerReadBarrier) {
525         if (kUseBakerReadBarrier) {
526           Location temp = locations->GetTemp(0);
527           codegen->GenerateArrayLoadWithBakerReadBarrier(
528               invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
529           if (is_volatile) {
530             __ dmb(ISH);
531           }
532         } else {
533           __ ldr(trg, Address(base, offset));
534           if (is_volatile) {
535             __ dmb(ISH);
536           }
537           codegen->GenerateReadBarrierSlow(invoke, trg_loc, trg_loc, base_loc, 0U, offset_loc);
538         }
539       } else {
540         __ ldr(trg, Address(base, offset));
541         if (is_volatile) {
542           __ dmb(ISH);
543         }
544         __ MaybeUnpoisonHeapReference(trg);
545       }
546       break;
547     }
548 
549     case Primitive::kPrimLong: {
550       Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
551       __ add(IP, base, ShifterOperand(offset));
552       if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) {
553         Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
554         __ ldrexd(trg_lo, trg_hi, IP);
555       } else {
556         __ ldrd(trg_lo, Address(IP));
557       }
558       if (is_volatile) {
559         __ dmb(ISH);
560       }
561       break;
562     }
563 
564     default:
565       LOG(FATAL) << "Unexpected type " << type;
566       UNREACHABLE();
567   }
568 }
569 
CreateIntIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke,Primitive::Type type)570 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
571                                           HInvoke* invoke,
572                                           Primitive::Type type) {
573   bool can_call = kEmitCompilerReadBarrier &&
574       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
575        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
576   LocationSummary* locations = new (arena) LocationSummary(invoke,
577                                                            can_call ?
578                                                                LocationSummary::kCallOnSlowPath :
579                                                                LocationSummary::kNoCall,
580                                                            kIntrinsified);
581   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
582   locations->SetInAt(1, Location::RequiresRegister());
583   locations->SetInAt(2, Location::RequiresRegister());
584   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
585   if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
586     // We need a temporary register for the read barrier marking slow
587     // path in InstructionCodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
588     locations->AddTemp(Location::RequiresRegister());
589   }
590 }
591 
VisitUnsafeGet(HInvoke * invoke)592 void IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) {
593   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
594 }
VisitUnsafeGetVolatile(HInvoke * invoke)595 void IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) {
596   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
597 }
VisitUnsafeGetLong(HInvoke * invoke)598 void IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) {
599   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
600 }
VisitUnsafeGetLongVolatile(HInvoke * invoke)601 void IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
602   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
603 }
VisitUnsafeGetObject(HInvoke * invoke)604 void IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) {
605   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
606 }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)607 void IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
608   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
609 }
610 
VisitUnsafeGet(HInvoke * invoke)611 void IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) {
612   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
613 }
VisitUnsafeGetVolatile(HInvoke * invoke)614 void IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) {
615   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
616 }
VisitUnsafeGetLong(HInvoke * invoke)617 void IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) {
618   GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
619 }
VisitUnsafeGetLongVolatile(HInvoke * invoke)620 void IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
621   GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
622 }
VisitUnsafeGetObject(HInvoke * invoke)623 void IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) {
624   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
625 }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)626 void IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
627   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
628 }
629 
CreateIntIntIntIntToVoid(ArenaAllocator * arena,const ArmInstructionSetFeatures & features,Primitive::Type type,bool is_volatile,HInvoke * invoke)630 static void CreateIntIntIntIntToVoid(ArenaAllocator* arena,
631                                      const ArmInstructionSetFeatures& features,
632                                      Primitive::Type type,
633                                      bool is_volatile,
634                                      HInvoke* invoke) {
635   LocationSummary* locations = new (arena) LocationSummary(invoke,
636                                                            LocationSummary::kNoCall,
637                                                            kIntrinsified);
638   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
639   locations->SetInAt(1, Location::RequiresRegister());
640   locations->SetInAt(2, Location::RequiresRegister());
641   locations->SetInAt(3, Location::RequiresRegister());
642 
643   if (type == Primitive::kPrimLong) {
644     // Potentially need temps for ldrexd-strexd loop.
645     if (is_volatile && !features.HasAtomicLdrdAndStrd()) {
646       locations->AddTemp(Location::RequiresRegister());  // Temp_lo.
647       locations->AddTemp(Location::RequiresRegister());  // Temp_hi.
648     }
649   } else if (type == Primitive::kPrimNot) {
650     // Temps for card-marking.
651     locations->AddTemp(Location::RequiresRegister());  // Temp.
652     locations->AddTemp(Location::RequiresRegister());  // Card.
653   }
654 }
655 
VisitUnsafePut(HInvoke * invoke)656 void IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) {
657   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke);
658 }
VisitUnsafePutOrdered(HInvoke * invoke)659 void IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) {
660   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke);
661 }
VisitUnsafePutVolatile(HInvoke * invoke)662 void IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) {
663   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ true, invoke);
664 }
VisitUnsafePutObject(HInvoke * invoke)665 void IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) {
666   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke);
667 }
VisitUnsafePutObjectOrdered(HInvoke * invoke)668 void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
669   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke);
670 }
VisitUnsafePutObjectVolatile(HInvoke * invoke)671 void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
672   CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ true, invoke);
673 }
VisitUnsafePutLong(HInvoke * invoke)674 void IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) {
675   CreateIntIntIntIntToVoid(
676       arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke);
677 }
VisitUnsafePutLongOrdered(HInvoke * invoke)678 void IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) {
679   CreateIntIntIntIntToVoid(
680       arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke);
681 }
VisitUnsafePutLongVolatile(HInvoke * invoke)682 void IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) {
683   CreateIntIntIntIntToVoid(
684       arena_, features_, Primitive::kPrimLong, /* is_volatile */ true, invoke);
685 }
686 
GenUnsafePut(LocationSummary * locations,Primitive::Type type,bool is_volatile,bool is_ordered,CodeGeneratorARM * codegen)687 static void GenUnsafePut(LocationSummary* locations,
688                          Primitive::Type type,
689                          bool is_volatile,
690                          bool is_ordered,
691                          CodeGeneratorARM* codegen) {
692   ArmAssembler* assembler = codegen->GetAssembler();
693 
694   Register base = locations->InAt(1).AsRegister<Register>();           // Object pointer.
695   Register offset = locations->InAt(2).AsRegisterPairLow<Register>();  // Long offset, lo part only.
696   Register value;
697 
698   if (is_volatile || is_ordered) {
699     __ dmb(ISH);
700   }
701 
702   if (type == Primitive::kPrimLong) {
703     Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
704     value = value_lo;
705     if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) {
706       Register temp_lo = locations->GetTemp(0).AsRegister<Register>();
707       Register temp_hi = locations->GetTemp(1).AsRegister<Register>();
708       Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
709 
710       __ add(IP, base, ShifterOperand(offset));
711       Label loop_head;
712       __ Bind(&loop_head);
713       __ ldrexd(temp_lo, temp_hi, IP);
714       __ strexd(temp_lo, value_lo, value_hi, IP);
715       __ cmp(temp_lo, ShifterOperand(0));
716       __ b(&loop_head, NE);
717     } else {
718       __ add(IP, base, ShifterOperand(offset));
719       __ strd(value_lo, Address(IP));
720     }
721   } else {
722     value = locations->InAt(3).AsRegister<Register>();
723     Register source = value;
724     if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
725       Register temp = locations->GetTemp(0).AsRegister<Register>();
726       __ Mov(temp, value);
727       __ PoisonHeapReference(temp);
728       source = temp;
729     }
730     __ str(source, Address(base, offset));
731   }
732 
733   if (is_volatile) {
734     __ dmb(ISH);
735   }
736 
737   if (type == Primitive::kPrimNot) {
738     Register temp = locations->GetTemp(0).AsRegister<Register>();
739     Register card = locations->GetTemp(1).AsRegister<Register>();
740     bool value_can_be_null = true;  // TODO: Worth finding out this information?
741     codegen->MarkGCCard(temp, card, base, value, value_can_be_null);
742   }
743 }
744 
VisitUnsafePut(HInvoke * invoke)745 void IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) {
746   GenUnsafePut(invoke->GetLocations(),
747                Primitive::kPrimInt,
748                /* is_volatile */ false,
749                /* is_ordered */ false,
750                codegen_);
751 }
VisitUnsafePutOrdered(HInvoke * invoke)752 void IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) {
753   GenUnsafePut(invoke->GetLocations(),
754                Primitive::kPrimInt,
755                /* is_volatile */ false,
756                /* is_ordered */ true,
757                codegen_);
758 }
VisitUnsafePutVolatile(HInvoke * invoke)759 void IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) {
760   GenUnsafePut(invoke->GetLocations(),
761                Primitive::kPrimInt,
762                /* is_volatile */ true,
763                /* is_ordered */ false,
764                codegen_);
765 }
VisitUnsafePutObject(HInvoke * invoke)766 void IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) {
767   GenUnsafePut(invoke->GetLocations(),
768                Primitive::kPrimNot,
769                /* is_volatile */ false,
770                /* is_ordered */ false,
771                codegen_);
772 }
VisitUnsafePutObjectOrdered(HInvoke * invoke)773 void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
774   GenUnsafePut(invoke->GetLocations(),
775                Primitive::kPrimNot,
776                /* is_volatile */ false,
777                /* is_ordered */ true,
778                codegen_);
779 }
VisitUnsafePutObjectVolatile(HInvoke * invoke)780 void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
781   GenUnsafePut(invoke->GetLocations(),
782                Primitive::kPrimNot,
783                /* is_volatile */ true,
784                /* is_ordered */ false,
785                codegen_);
786 }
VisitUnsafePutLong(HInvoke * invoke)787 void IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) {
788   GenUnsafePut(invoke->GetLocations(),
789                Primitive::kPrimLong,
790                /* is_volatile */ false,
791                /* is_ordered */ false,
792                codegen_);
793 }
VisitUnsafePutLongOrdered(HInvoke * invoke)794 void IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) {
795   GenUnsafePut(invoke->GetLocations(),
796                Primitive::kPrimLong,
797                /* is_volatile */ false,
798                /* is_ordered */ true,
799                codegen_);
800 }
VisitUnsafePutLongVolatile(HInvoke * invoke)801 void IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) {
802   GenUnsafePut(invoke->GetLocations(),
803                Primitive::kPrimLong,
804                /* is_volatile */ true,
805                /* is_ordered */ false,
806                codegen_);
807 }
808 
CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator * arena,HInvoke * invoke,Primitive::Type type)809 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena,
810                                                 HInvoke* invoke,
811                                                 Primitive::Type type) {
812   LocationSummary* locations = new (arena) LocationSummary(invoke,
813                                                            LocationSummary::kNoCall,
814                                                            kIntrinsified);
815   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
816   locations->SetInAt(1, Location::RequiresRegister());
817   locations->SetInAt(2, Location::RequiresRegister());
818   locations->SetInAt(3, Location::RequiresRegister());
819   locations->SetInAt(4, Location::RequiresRegister());
820 
821   // If heap poisoning is enabled, we don't want the unpoisoning
822   // operations to potentially clobber the output.
823   Location::OutputOverlap overlaps = (kPoisonHeapReferences && type == Primitive::kPrimNot)
824       ? Location::kOutputOverlap
825       : Location::kNoOutputOverlap;
826   locations->SetOut(Location::RequiresRegister(), overlaps);
827 
828   locations->AddTemp(Location::RequiresRegister());  // Pointer.
829   locations->AddTemp(Location::RequiresRegister());  // Temp 1.
830 }
831 
GenCas(LocationSummary * locations,Primitive::Type type,CodeGeneratorARM * codegen)832 static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) {
833   DCHECK_NE(type, Primitive::kPrimLong);
834 
835   ArmAssembler* assembler = codegen->GetAssembler();
836 
837   Register out = locations->Out().AsRegister<Register>();              // Boolean result.
838 
839   Register base = locations->InAt(1).AsRegister<Register>();           // Object pointer.
840   Register offset = locations->InAt(2).AsRegisterPairLow<Register>();  // Offset (discard high 4B).
841   Register expected_lo = locations->InAt(3).AsRegister<Register>();    // Expected.
842   Register value_lo = locations->InAt(4).AsRegister<Register>();       // Value.
843 
844   Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>();     // Pointer to actual memory.
845   Register tmp_lo = locations->GetTemp(1).AsRegister<Register>();      // Value in memory.
846 
847   if (type == Primitive::kPrimNot) {
848     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
849     // object and scan the receiver at the next GC for nothing.
850     bool value_can_be_null = true;  // TODO: Worth finding out this information?
851     codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null);
852   }
853 
854   // Prevent reordering with prior memory operations.
855   // Emit a DMB ISH instruction instead of an DMB ISHST one, as the
856   // latter allows a preceding load to be delayed past the STXR
857   // instruction below.
858   __ dmb(ISH);
859 
860   __ add(tmp_ptr, base, ShifterOperand(offset));
861 
862   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
863     codegen->GetAssembler()->PoisonHeapReference(expected_lo);
864     if (value_lo == expected_lo) {
865       // Do not poison `value_lo`, as it is the same register as
866       // `expected_lo`, which has just been poisoned.
867     } else {
868       codegen->GetAssembler()->PoisonHeapReference(value_lo);
869     }
870   }
871 
872   // do {
873   //   tmp = [r_ptr] - expected;
874   // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
875   // result = tmp != 0;
876 
877   Label loop_head;
878   __ Bind(&loop_head);
879 
880   // TODO: When `type == Primitive::kPrimNot`, add a read barrier for
881   // the reference stored in the object before attempting the CAS,
882   // similar to the one in the art::Unsafe_compareAndSwapObject JNI
883   // implementation.
884   //
885   // Note that this code is not (yet) used when read barriers are
886   // enabled (see IntrinsicLocationsBuilderARM::VisitUnsafeCASObject).
887   DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier));
888   __ ldrex(tmp_lo, tmp_ptr);
889 
890   __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo));
891 
892   __ it(EQ, ItState::kItT);
893   __ strex(tmp_lo, value_lo, tmp_ptr, EQ);
894   __ cmp(tmp_lo, ShifterOperand(1), EQ);
895 
896   __ b(&loop_head, EQ);
897 
898   __ dmb(ISH);
899 
900   __ rsbs(out, tmp_lo, ShifterOperand(1));
901   __ it(CC);
902   __ mov(out, ShifterOperand(0), CC);
903 
904   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
905     codegen->GetAssembler()->UnpoisonHeapReference(expected_lo);
906     if (value_lo == expected_lo) {
907       // Do not unpoison `value_lo`, as it is the same register as
908       // `expected_lo`, which has just been unpoisoned.
909     } else {
910       codegen->GetAssembler()->UnpoisonHeapReference(value_lo);
911     }
912   }
913 }
914 
VisitUnsafeCASInt(HInvoke * invoke)915 void IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) {
916   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimInt);
917 }
VisitUnsafeCASObject(HInvoke * invoke)918 void IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) {
919   // The UnsafeCASObject intrinsic is missing a read barrier, and
920   // therefore sometimes does not work as expected (b/25883050).
921   // Turn it off temporarily as a quick fix, until the read barrier is
922   // implemented (see TODO in GenCAS below).
923   //
924   // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers.
925   if (kEmitCompilerReadBarrier) {
926     return;
927   }
928 
929   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimNot);
930 }
VisitUnsafeCASInt(HInvoke * invoke)931 void IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) {
932   GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_);
933 }
VisitUnsafeCASObject(HInvoke * invoke)934 void IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) {
935   GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_);
936 }
937 
VisitStringCharAt(HInvoke * invoke)938 void IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) {
939   LocationSummary* locations = new (arena_) LocationSummary(invoke,
940                                                             LocationSummary::kCallOnSlowPath,
941                                                             kIntrinsified);
942   locations->SetInAt(0, Location::RequiresRegister());
943   locations->SetInAt(1, Location::RequiresRegister());
944   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
945 
946   locations->AddTemp(Location::RequiresRegister());
947   locations->AddTemp(Location::RequiresRegister());
948 }
949 
VisitStringCharAt(HInvoke * invoke)950 void IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) {
951   ArmAssembler* assembler = GetAssembler();
952   LocationSummary* locations = invoke->GetLocations();
953 
954   // Location of reference to data array
955   const MemberOffset value_offset = mirror::String::ValueOffset();
956   // Location of count
957   const MemberOffset count_offset = mirror::String::CountOffset();
958 
959   Register obj = locations->InAt(0).AsRegister<Register>();  // String object pointer.
960   Register idx = locations->InAt(1).AsRegister<Register>();  // Index of character.
961   Register out = locations->Out().AsRegister<Register>();    // Result character.
962 
963   Register temp = locations->GetTemp(0).AsRegister<Register>();
964   Register array_temp = locations->GetTemp(1).AsRegister<Register>();
965 
966   // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
967   //       the cost.
968   // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
969   //       we will not optimize the code for constants (which would save a register).
970 
971   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
972   codegen_->AddSlowPath(slow_path);
973 
974   __ ldr(temp, Address(obj, count_offset.Int32Value()));          // temp = str.length.
975   codegen_->MaybeRecordImplicitNullCheck(invoke);
976   __ cmp(idx, ShifterOperand(temp));
977   __ b(slow_path->GetEntryLabel(), CS);
978 
979   __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value()));  // array_temp := str.value.
980 
981   // Load the value.
982   __ ldrh(out, Address(array_temp, idx, LSL, 1));                 // out := array_temp[idx].
983 
984   __ Bind(slow_path->GetExitLabel());
985 }
986 
VisitStringCompareTo(HInvoke * invoke)987 void IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) {
988   // The inputs plus one temp.
989   LocationSummary* locations = new (arena_) LocationSummary(invoke,
990                                                             LocationSummary::kCall,
991                                                             kIntrinsified);
992   InvokeRuntimeCallingConvention calling_convention;
993   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
994   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
995   locations->SetOut(Location::RegisterLocation(R0));
996 }
997 
VisitStringCompareTo(HInvoke * invoke)998 void IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) {
999   ArmAssembler* assembler = GetAssembler();
1000   LocationSummary* locations = invoke->GetLocations();
1001 
1002   // Note that the null check must have been done earlier.
1003   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1004 
1005   Register argument = locations->InAt(1).AsRegister<Register>();
1006   __ cmp(argument, ShifterOperand(0));
1007   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
1008   codegen_->AddSlowPath(slow_path);
1009   __ b(slow_path->GetEntryLabel(), EQ);
1010 
1011   __ LoadFromOffset(
1012       kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value());
1013   __ blx(LR);
1014   __ Bind(slow_path->GetExitLabel());
1015 }
1016 
VisitStringEquals(HInvoke * invoke)1017 void IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) {
1018   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1019                                                             LocationSummary::kNoCall,
1020                                                             kIntrinsified);
1021   InvokeRuntimeCallingConvention calling_convention;
1022   locations->SetInAt(0, Location::RequiresRegister());
1023   locations->SetInAt(1, Location::RequiresRegister());
1024   // Temporary registers to store lengths of strings and for calculations.
1025   // Using instruction cbz requires a low register, so explicitly set a temp to be R0.
1026   locations->AddTemp(Location::RegisterLocation(R0));
1027   locations->AddTemp(Location::RequiresRegister());
1028   locations->AddTemp(Location::RequiresRegister());
1029 
1030   locations->SetOut(Location::RequiresRegister());
1031 }
1032 
VisitStringEquals(HInvoke * invoke)1033 void IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) {
1034   ArmAssembler* assembler = GetAssembler();
1035   LocationSummary* locations = invoke->GetLocations();
1036 
1037   Register str = locations->InAt(0).AsRegister<Register>();
1038   Register arg = locations->InAt(1).AsRegister<Register>();
1039   Register out = locations->Out().AsRegister<Register>();
1040 
1041   Register temp = locations->GetTemp(0).AsRegister<Register>();
1042   Register temp1 = locations->GetTemp(1).AsRegister<Register>();
1043   Register temp2 = locations->GetTemp(2).AsRegister<Register>();
1044 
1045   Label loop;
1046   Label end;
1047   Label return_true;
1048   Label return_false;
1049 
1050   // Get offsets of count, value, and class fields within a string object.
1051   const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1052   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1053   const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
1054 
1055   // Note that the null check must have been done earlier.
1056   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1057 
1058   // Check if input is null, return false if it is.
1059   __ CompareAndBranchIfZero(arg, &return_false);
1060 
1061   // Instanceof check for the argument by comparing class fields.
1062   // All string objects must have the same type since String cannot be subclassed.
1063   // Receiver must be a string object, so its class field is equal to all strings' class fields.
1064   // If the argument is a string object, its class field must be equal to receiver's class field.
1065   __ ldr(temp, Address(str, class_offset));
1066   __ ldr(temp1, Address(arg, class_offset));
1067   __ cmp(temp, ShifterOperand(temp1));
1068   __ b(&return_false, NE);
1069 
1070   // Load lengths of this and argument strings.
1071   __ ldr(temp, Address(str, count_offset));
1072   __ ldr(temp1, Address(arg, count_offset));
1073   // Check if lengths are equal, return false if they're not.
1074   __ cmp(temp, ShifterOperand(temp1));
1075   __ b(&return_false, NE);
1076   // Return true if both strings are empty.
1077   __ cbz(temp, &return_true);
1078 
1079   // Reference equality check, return true if same reference.
1080   __ cmp(str, ShifterOperand(arg));
1081   __ b(&return_true, EQ);
1082 
1083   // Assertions that must hold in order to compare strings 2 characters at a time.
1084   DCHECK_ALIGNED(value_offset, 4);
1085   static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
1086 
1087   __ LoadImmediate(temp1, value_offset);
1088 
1089   // Loop to compare strings 2 characters at a time starting at the front of the string.
1090   // Ok to do this because strings with an odd length are zero-padded.
1091   __ Bind(&loop);
1092   __ ldr(out, Address(str, temp1));
1093   __ ldr(temp2, Address(arg, temp1));
1094   __ cmp(out, ShifterOperand(temp2));
1095   __ b(&return_false, NE);
1096   __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t)));
1097   __ subs(temp, temp, ShifterOperand(sizeof(uint32_t) /  sizeof(uint16_t)));
1098   __ b(&loop, GT);
1099 
1100   // Return true and exit the function.
1101   // If loop does not result in returning false, we return true.
1102   __ Bind(&return_true);
1103   __ LoadImmediate(out, 1);
1104   __ b(&end);
1105 
1106   // Return false and exit the function.
1107   __ Bind(&return_false);
1108   __ LoadImmediate(out, 0);
1109   __ Bind(&end);
1110 }
1111 
GenerateVisitStringIndexOf(HInvoke * invoke,ArmAssembler * assembler,CodeGeneratorARM * codegen,ArenaAllocator * allocator,bool start_at_zero)1112 static void GenerateVisitStringIndexOf(HInvoke* invoke,
1113                                        ArmAssembler* assembler,
1114                                        CodeGeneratorARM* codegen,
1115                                        ArenaAllocator* allocator,
1116                                        bool start_at_zero) {
1117   LocationSummary* locations = invoke->GetLocations();
1118   Register tmp_reg = locations->GetTemp(0).AsRegister<Register>();
1119 
1120   // Note that the null check must have been done earlier.
1121   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1122 
1123   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
1124   // or directly dispatch if we have a constant.
1125   SlowPathCode* slow_path = nullptr;
1126   if (invoke->InputAt(1)->IsIntConstant()) {
1127     if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) >
1128         std::numeric_limits<uint16_t>::max()) {
1129       // Always needs the slow-path. We could directly dispatch to it, but this case should be
1130       // rare, so for simplicity just put the full slow-path down and branch unconditionally.
1131       slow_path = new (allocator) IntrinsicSlowPathARM(invoke);
1132       codegen->AddSlowPath(slow_path);
1133       __ b(slow_path->GetEntryLabel());
1134       __ Bind(slow_path->GetExitLabel());
1135       return;
1136     }
1137   } else {
1138     Register char_reg = locations->InAt(1).AsRegister<Register>();
1139     __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max());
1140     __ cmp(char_reg, ShifterOperand(tmp_reg));
1141     slow_path = new (allocator) IntrinsicSlowPathARM(invoke);
1142     codegen->AddSlowPath(slow_path);
1143     __ b(slow_path->GetEntryLabel(), HI);
1144   }
1145 
1146   if (start_at_zero) {
1147     DCHECK_EQ(tmp_reg, R2);
1148     // Start-index = 0.
1149     __ LoadImmediate(tmp_reg, 0);
1150   }
1151 
1152   __ LoadFromOffset(kLoadWord, LR, TR,
1153                     QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value());
1154   CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
1155   __ blx(LR);
1156 
1157   if (slow_path != nullptr) {
1158     __ Bind(slow_path->GetExitLabel());
1159   }
1160 }
1161 
VisitStringIndexOf(HInvoke * invoke)1162 void IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) {
1163   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1164                                                             LocationSummary::kCall,
1165                                                             kIntrinsified);
1166   // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
1167   // best to align the inputs accordingly.
1168   InvokeRuntimeCallingConvention calling_convention;
1169   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1170   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1171   locations->SetOut(Location::RegisterLocation(R0));
1172 
1173   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
1174   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1175 }
1176 
VisitStringIndexOf(HInvoke * invoke)1177 void IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) {
1178   GenerateVisitStringIndexOf(
1179       invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true);
1180 }
1181 
VisitStringIndexOfAfter(HInvoke * invoke)1182 void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) {
1183   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1184                                                             LocationSummary::kCall,
1185                                                             kIntrinsified);
1186   // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
1187   // best to align the inputs accordingly.
1188   InvokeRuntimeCallingConvention calling_convention;
1189   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1190   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1191   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1192   locations->SetOut(Location::RegisterLocation(R0));
1193 
1194   // Need a temp for slow-path codepoint compare.
1195   locations->AddTemp(Location::RequiresRegister());
1196 }
1197 
VisitStringIndexOfAfter(HInvoke * invoke)1198 void IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) {
1199   GenerateVisitStringIndexOf(
1200       invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false);
1201 }
1202 
VisitStringNewStringFromBytes(HInvoke * invoke)1203 void IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
1204   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1205                                                             LocationSummary::kCall,
1206                                                             kIntrinsified);
1207   InvokeRuntimeCallingConvention calling_convention;
1208   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1209   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1210   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1211   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1212   locations->SetOut(Location::RegisterLocation(R0));
1213 }
1214 
VisitStringNewStringFromBytes(HInvoke * invoke)1215 void IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
1216   ArmAssembler* assembler = GetAssembler();
1217   LocationSummary* locations = invoke->GetLocations();
1218 
1219   Register byte_array = locations->InAt(0).AsRegister<Register>();
1220   __ cmp(byte_array, ShifterOperand(0));
1221   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
1222   codegen_->AddSlowPath(slow_path);
1223   __ b(slow_path->GetEntryLabel(), EQ);
1224 
1225   __ LoadFromOffset(
1226       kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value());
1227   CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
1228   __ blx(LR);
1229   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1230   __ Bind(slow_path->GetExitLabel());
1231 }
1232 
VisitStringNewStringFromChars(HInvoke * invoke)1233 void IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) {
1234   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1235                                                             LocationSummary::kCall,
1236                                                             kIntrinsified);
1237   InvokeRuntimeCallingConvention calling_convention;
1238   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1239   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1240   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1241   locations->SetOut(Location::RegisterLocation(R0));
1242 }
1243 
VisitStringNewStringFromChars(HInvoke * invoke)1244 void IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) {
1245   ArmAssembler* assembler = GetAssembler();
1246 
1247   // No need to emit code checking whether `locations->InAt(2)` is a null
1248   // pointer, as callers of the native method
1249   //
1250   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1251   //
1252   // all include a null check on `data` before calling that method.
1253   __ LoadFromOffset(
1254       kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value());
1255   CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
1256   __ blx(LR);
1257   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1258 }
1259 
VisitStringNewStringFromString(HInvoke * invoke)1260 void IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) {
1261   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1262                                                             LocationSummary::kCall,
1263                                                             kIntrinsified);
1264   InvokeRuntimeCallingConvention calling_convention;
1265   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1266   locations->SetOut(Location::RegisterLocation(R0));
1267 }
1268 
VisitStringNewStringFromString(HInvoke * invoke)1269 void IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) {
1270   ArmAssembler* assembler = GetAssembler();
1271   LocationSummary* locations = invoke->GetLocations();
1272 
1273   Register string_to_copy = locations->InAt(0).AsRegister<Register>();
1274   __ cmp(string_to_copy, ShifterOperand(0));
1275   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
1276   codegen_->AddSlowPath(slow_path);
1277   __ b(slow_path->GetEntryLabel(), EQ);
1278 
1279   __ LoadFromOffset(kLoadWord,
1280       LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value());
1281   CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
1282   __ blx(LR);
1283   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1284   __ Bind(slow_path->GetExitLabel());
1285 }
1286 
VisitSystemArrayCopy(HInvoke * invoke)1287 void IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) {
1288   CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke);
1289   LocationSummary* locations = invoke->GetLocations();
1290   if (locations == nullptr) {
1291     return;
1292   }
1293 
1294   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
1295   HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
1296   HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
1297 
1298   if (src_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(src_pos->GetValue())) {
1299     locations->SetInAt(1, Location::RequiresRegister());
1300   }
1301   if (dest_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(dest_pos->GetValue())) {
1302     locations->SetInAt(3, Location::RequiresRegister());
1303   }
1304   if (length != nullptr && !assembler_->ShifterOperandCanAlwaysHold(length->GetValue())) {
1305     locations->SetInAt(4, Location::RequiresRegister());
1306   }
1307 }
1308 
CheckPosition(ArmAssembler * assembler,Location pos,Register input,Location length,SlowPathCode * slow_path,Register input_len,Register temp,bool length_is_input_length=false)1309 static void CheckPosition(ArmAssembler* assembler,
1310                           Location pos,
1311                           Register input,
1312                           Location length,
1313                           SlowPathCode* slow_path,
1314                           Register input_len,
1315                           Register temp,
1316                           bool length_is_input_length = false) {
1317   // Where is the length in the Array?
1318   const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
1319 
1320   if (pos.IsConstant()) {
1321     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
1322     if (pos_const == 0) {
1323       if (!length_is_input_length) {
1324         // Check that length(input) >= length.
1325         __ LoadFromOffset(kLoadWord, temp, input, length_offset);
1326         if (length.IsConstant()) {
1327           __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
1328         } else {
1329           __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
1330         }
1331         __ b(slow_path->GetEntryLabel(), LT);
1332       }
1333     } else {
1334       // Check that length(input) >= pos.
1335       __ LoadFromOffset(kLoadWord, input_len, input, length_offset);
1336       __ subs(temp, input_len, ShifterOperand(pos_const));
1337       __ b(slow_path->GetEntryLabel(), LT);
1338 
1339       // Check that (length(input) - pos) >= length.
1340       if (length.IsConstant()) {
1341         __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
1342       } else {
1343         __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
1344       }
1345       __ b(slow_path->GetEntryLabel(), LT);
1346     }
1347   } else if (length_is_input_length) {
1348     // The only way the copy can succeed is if pos is zero.
1349     Register pos_reg = pos.AsRegister<Register>();
1350     __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel());
1351   } else {
1352     // Check that pos >= 0.
1353     Register pos_reg = pos.AsRegister<Register>();
1354     __ cmp(pos_reg, ShifterOperand(0));
1355     __ b(slow_path->GetEntryLabel(), LT);
1356 
1357     // Check that pos <= length(input).
1358     __ LoadFromOffset(kLoadWord, temp, input, length_offset);
1359     __ subs(temp, temp, ShifterOperand(pos_reg));
1360     __ b(slow_path->GetEntryLabel(), LT);
1361 
1362     // Check that (length(input) - pos) >= length.
1363     if (length.IsConstant()) {
1364       __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
1365     } else {
1366       __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
1367     }
1368     __ b(slow_path->GetEntryLabel(), LT);
1369   }
1370 }
1371 
1372 // TODO: Implement read barriers in the SystemArrayCopy intrinsic.
1373 // Note that this code path is not used (yet) because we do not
1374 // intrinsify methods that can go into the IntrinsicSlowPathARM
1375 // slow path.
VisitSystemArrayCopy(HInvoke * invoke)1376 void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) {
1377   ArmAssembler* assembler = GetAssembler();
1378   LocationSummary* locations = invoke->GetLocations();
1379 
1380   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1381   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
1382   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
1383   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
1384 
1385   Register src = locations->InAt(0).AsRegister<Register>();
1386   Location src_pos = locations->InAt(1);
1387   Register dest = locations->InAt(2).AsRegister<Register>();
1388   Location dest_pos = locations->InAt(3);
1389   Location length = locations->InAt(4);
1390   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
1391   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
1392   Register temp3 = locations->GetTemp(2).AsRegister<Register>();
1393 
1394   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
1395   codegen_->AddSlowPath(slow_path);
1396 
1397   Label conditions_on_positions_validated;
1398   SystemArrayCopyOptimizations optimizations(invoke);
1399 
1400   if (!optimizations.GetDestinationIsSource() &&
1401       (!src_pos.IsConstant() || !dest_pos.IsConstant())) {
1402     __ cmp(src, ShifterOperand(dest));
1403   }
1404   // If source and destination are the same, we go to slow path if we need to do
1405   // forward copying.
1406   if (src_pos.IsConstant()) {
1407     int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
1408     if (dest_pos.IsConstant()) {
1409       // Checked when building locations.
1410       DCHECK(!optimizations.GetDestinationIsSource()
1411              || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue()));
1412     } else {
1413       if (!optimizations.GetDestinationIsSource()) {
1414         __ b(&conditions_on_positions_validated, NE);
1415       }
1416       __ cmp(dest_pos.AsRegister<Register>(), ShifterOperand(src_pos_constant));
1417       __ b(slow_path->GetEntryLabel(), GT);
1418     }
1419   } else {
1420     if (!optimizations.GetDestinationIsSource()) {
1421       __ b(&conditions_on_positions_validated, NE);
1422     }
1423     if (dest_pos.IsConstant()) {
1424       int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
1425       __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos_constant));
1426     } else {
1427       __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos.AsRegister<Register>()));
1428     }
1429     __ b(slow_path->GetEntryLabel(), LT);
1430   }
1431 
1432   __ Bind(&conditions_on_positions_validated);
1433 
1434   if (!optimizations.GetSourceIsNotNull()) {
1435     // Bail out if the source is null.
1436     __ CompareAndBranchIfZero(src, slow_path->GetEntryLabel());
1437   }
1438 
1439   if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
1440     // Bail out if the destination is null.
1441     __ CompareAndBranchIfZero(dest, slow_path->GetEntryLabel());
1442   }
1443 
1444   // If the length is negative, bail out.
1445   // We have already checked in the LocationsBuilder for the constant case.
1446   if (!length.IsConstant() &&
1447       !optimizations.GetCountIsSourceLength() &&
1448       !optimizations.GetCountIsDestinationLength()) {
1449     __ cmp(length.AsRegister<Register>(), ShifterOperand(0));
1450     __ b(slow_path->GetEntryLabel(), LT);
1451   }
1452 
1453   // Validity checks: source.
1454   CheckPosition(assembler,
1455                 src_pos,
1456                 src,
1457                 length,
1458                 slow_path,
1459                 temp1,
1460                 temp2,
1461                 optimizations.GetCountIsSourceLength());
1462 
1463   // Validity checks: dest.
1464   CheckPosition(assembler,
1465                 dest_pos,
1466                 dest,
1467                 length,
1468                 slow_path,
1469                 temp1,
1470                 temp2,
1471                 optimizations.GetCountIsDestinationLength());
1472 
1473   if (!optimizations.GetDoesNotNeedTypeCheck()) {
1474     // Check whether all elements of the source array are assignable to the component
1475     // type of the destination array. We do two checks: the classes are the same,
1476     // or the destination is Object[]. If none of these checks succeed, we go to the
1477     // slow path.
1478     __ LoadFromOffset(kLoadWord, temp1, dest, class_offset);
1479     __ LoadFromOffset(kLoadWord, temp2, src, class_offset);
1480     bool did_unpoison = false;
1481     if (!optimizations.GetDestinationIsNonPrimitiveArray() ||
1482         !optimizations.GetSourceIsNonPrimitiveArray()) {
1483       // One or two of the references need to be unpoisoned. Unpoison them
1484       // both to make the identity check valid.
1485       __ MaybeUnpoisonHeapReference(temp1);
1486       __ MaybeUnpoisonHeapReference(temp2);
1487       did_unpoison = true;
1488     }
1489 
1490     if (!optimizations.GetDestinationIsNonPrimitiveArray()) {
1491       // Bail out if the destination is not a non primitive array.
1492       // /* HeapReference<Class> */ temp3 = temp1->component_type_
1493       __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset);
1494       __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
1495       __ MaybeUnpoisonHeapReference(temp3);
1496       __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
1497       static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
1498       __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
1499     }
1500 
1501     if (!optimizations.GetSourceIsNonPrimitiveArray()) {
1502       // Bail out if the source is not a non primitive array.
1503       // /* HeapReference<Class> */ temp3 = temp2->component_type_
1504       __ LoadFromOffset(kLoadWord, temp3, temp2, component_offset);
1505       __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
1506       __ MaybeUnpoisonHeapReference(temp3);
1507       __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
1508       static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
1509       __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
1510     }
1511 
1512     __ cmp(temp1, ShifterOperand(temp2));
1513 
1514     if (optimizations.GetDestinationIsTypedObjectArray()) {
1515       Label do_copy;
1516       __ b(&do_copy, EQ);
1517       if (!did_unpoison) {
1518         __ MaybeUnpoisonHeapReference(temp1);
1519       }
1520       // /* HeapReference<Class> */ temp1 = temp1->component_type_
1521       __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
1522       __ MaybeUnpoisonHeapReference(temp1);
1523       // /* HeapReference<Class> */ temp1 = temp1->super_class_
1524       __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
1525       // No need to unpoison the result, we're comparing against null.
1526       __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
1527       __ Bind(&do_copy);
1528     } else {
1529       __ b(slow_path->GetEntryLabel(), NE);
1530     }
1531   } else if (!optimizations.GetSourceIsNonPrimitiveArray()) {
1532     DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
1533     // Bail out if the source is not a non primitive array.
1534     // /* HeapReference<Class> */ temp1 = src->klass_
1535     __ LoadFromOffset(kLoadWord, temp1, src, class_offset);
1536     __ MaybeUnpoisonHeapReference(temp1);
1537     // /* HeapReference<Class> */ temp3 = temp1->component_type_
1538     __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset);
1539     __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
1540     __ MaybeUnpoisonHeapReference(temp3);
1541     __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
1542     static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
1543     __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
1544   }
1545 
1546   // Compute base source address, base destination address, and end source address.
1547 
1548   uint32_t element_size = sizeof(int32_t);
1549   uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value();
1550   if (src_pos.IsConstant()) {
1551     int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
1552     __ AddConstant(temp1, src, element_size * constant + offset);
1553   } else {
1554     __ add(temp1, src, ShifterOperand(src_pos.AsRegister<Register>(), LSL, 2));
1555     __ AddConstant(temp1, offset);
1556   }
1557 
1558   if (dest_pos.IsConstant()) {
1559     int32_t constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
1560     __ AddConstant(temp2, dest, element_size * constant + offset);
1561   } else {
1562     __ add(temp2, dest, ShifterOperand(dest_pos.AsRegister<Register>(), LSL, 2));
1563     __ AddConstant(temp2, offset);
1564   }
1565 
1566   if (length.IsConstant()) {
1567     int32_t constant = length.GetConstant()->AsIntConstant()->GetValue();
1568     __ AddConstant(temp3, temp1, element_size * constant);
1569   } else {
1570     __ add(temp3, temp1, ShifterOperand(length.AsRegister<Register>(), LSL, 2));
1571   }
1572 
1573   // Iterate over the arrays and do a raw copy of the objects. We don't need to
1574   // poison/unpoison, nor do any read barrier as the next uses of the destination
1575   // array will do it.
1576   Label loop, done;
1577   __ cmp(temp1, ShifterOperand(temp3));
1578   __ b(&done, EQ);
1579   __ Bind(&loop);
1580   __ ldr(IP, Address(temp1, element_size, Address::PostIndex));
1581   __ str(IP, Address(temp2, element_size, Address::PostIndex));
1582   __ cmp(temp1, ShifterOperand(temp3));
1583   __ b(&loop, NE);
1584   __ Bind(&done);
1585 
1586   // We only need one card marking on the destination array.
1587   codegen_->MarkGCCard(temp1,
1588                        temp2,
1589                        dest,
1590                        Register(kNoRegister),
1591                        /* value_can_be_null */ false);
1592 
1593   __ Bind(slow_path->GetExitLabel());
1594 }
1595 
CreateFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)1596 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
1597   // If the graph is debuggable, all callee-saved floating-point registers are blocked by
1598   // the code generator. Furthermore, the register allocator creates fixed live intervals
1599   // for all caller-saved registers because we are doing a function call. As a result, if
1600   // the input and output locations are unallocated, the register allocator runs out of
1601   // registers and fails; however, a debuggable graph is not the common case.
1602   if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
1603     return;
1604   }
1605 
1606   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
1607   DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
1608   DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
1609 
1610   LocationSummary* const locations = new (arena) LocationSummary(invoke,
1611                                                                  LocationSummary::kCall,
1612                                                                  kIntrinsified);
1613   const InvokeRuntimeCallingConvention calling_convention;
1614 
1615   locations->SetInAt(0, Location::RequiresFpuRegister());
1616   locations->SetOut(Location::RequiresFpuRegister());
1617   // Native code uses the soft float ABI.
1618   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1619   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1620 }
1621 
CreateFPFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)1622 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
1623   // If the graph is debuggable, all callee-saved floating-point registers are blocked by
1624   // the code generator. Furthermore, the register allocator creates fixed live intervals
1625   // for all caller-saved registers because we are doing a function call. As a result, if
1626   // the input and output locations are unallocated, the register allocator runs out of
1627   // registers and fails; however, a debuggable graph is not the common case.
1628   if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
1629     return;
1630   }
1631 
1632   DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
1633   DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
1634   DCHECK_EQ(invoke->InputAt(1)->GetType(), Primitive::kPrimDouble);
1635   DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
1636 
1637   LocationSummary* const locations = new (arena) LocationSummary(invoke,
1638                                                                  LocationSummary::kCall,
1639                                                                  kIntrinsified);
1640   const InvokeRuntimeCallingConvention calling_convention;
1641 
1642   locations->SetInAt(0, Location::RequiresFpuRegister());
1643   locations->SetInAt(1, Location::RequiresFpuRegister());
1644   locations->SetOut(Location::RequiresFpuRegister());
1645   // Native code uses the soft float ABI.
1646   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1647   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1648   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1649   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1650 }
1651 
GenFPToFPCall(HInvoke * invoke,ArmAssembler * assembler,CodeGeneratorARM * codegen,QuickEntrypointEnum entry)1652 static void GenFPToFPCall(HInvoke* invoke,
1653                           ArmAssembler* assembler,
1654                           CodeGeneratorARM* codegen,
1655                           QuickEntrypointEnum entry) {
1656   LocationSummary* const locations = invoke->GetLocations();
1657   const InvokeRuntimeCallingConvention calling_convention;
1658 
1659   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
1660   DCHECK(locations->WillCall() && locations->Intrinsified());
1661   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
1662   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
1663 
1664   __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
1665   // Native code uses the soft float ABI.
1666   __ vmovrrd(calling_convention.GetRegisterAt(0),
1667              calling_convention.GetRegisterAt(1),
1668              FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
1669   __ blx(LR);
1670   codegen->RecordPcInfo(invoke, invoke->GetDexPc());
1671   __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
1672              calling_convention.GetRegisterAt(0),
1673              calling_convention.GetRegisterAt(1));
1674 }
1675 
GenFPFPToFPCall(HInvoke * invoke,ArmAssembler * assembler,CodeGeneratorARM * codegen,QuickEntrypointEnum entry)1676 static void GenFPFPToFPCall(HInvoke* invoke,
1677                           ArmAssembler* assembler,
1678                           CodeGeneratorARM* codegen,
1679                           QuickEntrypointEnum entry) {
1680   LocationSummary* const locations = invoke->GetLocations();
1681   const InvokeRuntimeCallingConvention calling_convention;
1682 
1683   DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
1684   DCHECK(locations->WillCall() && locations->Intrinsified());
1685   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
1686   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
1687   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(2)));
1688   DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(3)));
1689 
1690   __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
1691   // Native code uses the soft float ABI.
1692   __ vmovrrd(calling_convention.GetRegisterAt(0),
1693              calling_convention.GetRegisterAt(1),
1694              FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
1695   __ vmovrrd(calling_convention.GetRegisterAt(2),
1696              calling_convention.GetRegisterAt(3),
1697              FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()));
1698   __ blx(LR);
1699   codegen->RecordPcInfo(invoke, invoke->GetDexPc());
1700   __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
1701              calling_convention.GetRegisterAt(0),
1702              calling_convention.GetRegisterAt(1));
1703 }
1704 
VisitMathCos(HInvoke * invoke)1705 void IntrinsicLocationsBuilderARM::VisitMathCos(HInvoke* invoke) {
1706   CreateFPToFPCallLocations(arena_, invoke);
1707 }
1708 
VisitMathCos(HInvoke * invoke)1709 void IntrinsicCodeGeneratorARM::VisitMathCos(HInvoke* invoke) {
1710   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCos);
1711 }
1712 
VisitMathSin(HInvoke * invoke)1713 void IntrinsicLocationsBuilderARM::VisitMathSin(HInvoke* invoke) {
1714   CreateFPToFPCallLocations(arena_, invoke);
1715 }
1716 
VisitMathSin(HInvoke * invoke)1717 void IntrinsicCodeGeneratorARM::VisitMathSin(HInvoke* invoke) {
1718   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSin);
1719 }
1720 
VisitMathAcos(HInvoke * invoke)1721 void IntrinsicLocationsBuilderARM::VisitMathAcos(HInvoke* invoke) {
1722   CreateFPToFPCallLocations(arena_, invoke);
1723 }
1724 
VisitMathAcos(HInvoke * invoke)1725 void IntrinsicCodeGeneratorARM::VisitMathAcos(HInvoke* invoke) {
1726   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAcos);
1727 }
1728 
VisitMathAsin(HInvoke * invoke)1729 void IntrinsicLocationsBuilderARM::VisitMathAsin(HInvoke* invoke) {
1730   CreateFPToFPCallLocations(arena_, invoke);
1731 }
1732 
VisitMathAsin(HInvoke * invoke)1733 void IntrinsicCodeGeneratorARM::VisitMathAsin(HInvoke* invoke) {
1734   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAsin);
1735 }
1736 
VisitMathAtan(HInvoke * invoke)1737 void IntrinsicLocationsBuilderARM::VisitMathAtan(HInvoke* invoke) {
1738   CreateFPToFPCallLocations(arena_, invoke);
1739 }
1740 
VisitMathAtan(HInvoke * invoke)1741 void IntrinsicCodeGeneratorARM::VisitMathAtan(HInvoke* invoke) {
1742   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan);
1743 }
1744 
VisitMathCbrt(HInvoke * invoke)1745 void IntrinsicLocationsBuilderARM::VisitMathCbrt(HInvoke* invoke) {
1746   CreateFPToFPCallLocations(arena_, invoke);
1747 }
1748 
VisitMathCbrt(HInvoke * invoke)1749 void IntrinsicCodeGeneratorARM::VisitMathCbrt(HInvoke* invoke) {
1750   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCbrt);
1751 }
1752 
VisitMathCosh(HInvoke * invoke)1753 void IntrinsicLocationsBuilderARM::VisitMathCosh(HInvoke* invoke) {
1754   CreateFPToFPCallLocations(arena_, invoke);
1755 }
1756 
VisitMathCosh(HInvoke * invoke)1757 void IntrinsicCodeGeneratorARM::VisitMathCosh(HInvoke* invoke) {
1758   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCosh);
1759 }
1760 
VisitMathExp(HInvoke * invoke)1761 void IntrinsicLocationsBuilderARM::VisitMathExp(HInvoke* invoke) {
1762   CreateFPToFPCallLocations(arena_, invoke);
1763 }
1764 
VisitMathExp(HInvoke * invoke)1765 void IntrinsicCodeGeneratorARM::VisitMathExp(HInvoke* invoke) {
1766   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExp);
1767 }
1768 
VisitMathExpm1(HInvoke * invoke)1769 void IntrinsicLocationsBuilderARM::VisitMathExpm1(HInvoke* invoke) {
1770   CreateFPToFPCallLocations(arena_, invoke);
1771 }
1772 
VisitMathExpm1(HInvoke * invoke)1773 void IntrinsicCodeGeneratorARM::VisitMathExpm1(HInvoke* invoke) {
1774   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExpm1);
1775 }
1776 
VisitMathLog(HInvoke * invoke)1777 void IntrinsicLocationsBuilderARM::VisitMathLog(HInvoke* invoke) {
1778   CreateFPToFPCallLocations(arena_, invoke);
1779 }
1780 
VisitMathLog(HInvoke * invoke)1781 void IntrinsicCodeGeneratorARM::VisitMathLog(HInvoke* invoke) {
1782   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog);
1783 }
1784 
VisitMathLog10(HInvoke * invoke)1785 void IntrinsicLocationsBuilderARM::VisitMathLog10(HInvoke* invoke) {
1786   CreateFPToFPCallLocations(arena_, invoke);
1787 }
1788 
VisitMathLog10(HInvoke * invoke)1789 void IntrinsicCodeGeneratorARM::VisitMathLog10(HInvoke* invoke) {
1790   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog10);
1791 }
1792 
VisitMathSinh(HInvoke * invoke)1793 void IntrinsicLocationsBuilderARM::VisitMathSinh(HInvoke* invoke) {
1794   CreateFPToFPCallLocations(arena_, invoke);
1795 }
1796 
VisitMathSinh(HInvoke * invoke)1797 void IntrinsicCodeGeneratorARM::VisitMathSinh(HInvoke* invoke) {
1798   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSinh);
1799 }
1800 
VisitMathTan(HInvoke * invoke)1801 void IntrinsicLocationsBuilderARM::VisitMathTan(HInvoke* invoke) {
1802   CreateFPToFPCallLocations(arena_, invoke);
1803 }
1804 
VisitMathTan(HInvoke * invoke)1805 void IntrinsicCodeGeneratorARM::VisitMathTan(HInvoke* invoke) {
1806   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTan);
1807 }
1808 
VisitMathTanh(HInvoke * invoke)1809 void IntrinsicLocationsBuilderARM::VisitMathTanh(HInvoke* invoke) {
1810   CreateFPToFPCallLocations(arena_, invoke);
1811 }
1812 
VisitMathTanh(HInvoke * invoke)1813 void IntrinsicCodeGeneratorARM::VisitMathTanh(HInvoke* invoke) {
1814   GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTanh);
1815 }
1816 
VisitMathAtan2(HInvoke * invoke)1817 void IntrinsicLocationsBuilderARM::VisitMathAtan2(HInvoke* invoke) {
1818   CreateFPFPToFPCallLocations(arena_, invoke);
1819 }
1820 
VisitMathAtan2(HInvoke * invoke)1821 void IntrinsicCodeGeneratorARM::VisitMathAtan2(HInvoke* invoke) {
1822   GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan2);
1823 }
1824 
VisitMathHypot(HInvoke * invoke)1825 void IntrinsicLocationsBuilderARM::VisitMathHypot(HInvoke* invoke) {
1826   CreateFPFPToFPCallLocations(arena_, invoke);
1827 }
1828 
VisitMathHypot(HInvoke * invoke)1829 void IntrinsicCodeGeneratorARM::VisitMathHypot(HInvoke* invoke) {
1830   GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickHypot);
1831 }
1832 
VisitMathNextAfter(HInvoke * invoke)1833 void IntrinsicLocationsBuilderARM::VisitMathNextAfter(HInvoke* invoke) {
1834   CreateFPFPToFPCallLocations(arena_, invoke);
1835 }
1836 
VisitMathNextAfter(HInvoke * invoke)1837 void IntrinsicCodeGeneratorARM::VisitMathNextAfter(HInvoke* invoke) {
1838   GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickNextAfter);
1839 }
1840 
VisitIntegerReverse(HInvoke * invoke)1841 void IntrinsicLocationsBuilderARM::VisitIntegerReverse(HInvoke* invoke) {
1842   CreateIntToIntLocations(arena_, invoke);
1843 }
1844 
VisitIntegerReverse(HInvoke * invoke)1845 void IntrinsicCodeGeneratorARM::VisitIntegerReverse(HInvoke* invoke) {
1846   ArmAssembler* assembler = GetAssembler();
1847   LocationSummary* locations = invoke->GetLocations();
1848 
1849   Register out = locations->Out().AsRegister<Register>();
1850   Register in  = locations->InAt(0).AsRegister<Register>();
1851 
1852   __ rbit(out, in);
1853 }
1854 
VisitLongReverse(HInvoke * invoke)1855 void IntrinsicLocationsBuilderARM::VisitLongReverse(HInvoke* invoke) {
1856   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1857                                                             LocationSummary::kNoCall,
1858                                                             kIntrinsified);
1859   locations->SetInAt(0, Location::RequiresRegister());
1860   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1861 }
1862 
VisitLongReverse(HInvoke * invoke)1863 void IntrinsicCodeGeneratorARM::VisitLongReverse(HInvoke* invoke) {
1864   ArmAssembler* assembler = GetAssembler();
1865   LocationSummary* locations = invoke->GetLocations();
1866 
1867   Register in_reg_lo  = locations->InAt(0).AsRegisterPairLow<Register>();
1868   Register in_reg_hi  = locations->InAt(0).AsRegisterPairHigh<Register>();
1869   Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
1870   Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
1871 
1872   __ rbit(out_reg_lo, in_reg_hi);
1873   __ rbit(out_reg_hi, in_reg_lo);
1874 }
1875 
VisitIntegerReverseBytes(HInvoke * invoke)1876 void IntrinsicLocationsBuilderARM::VisitIntegerReverseBytes(HInvoke* invoke) {
1877   CreateIntToIntLocations(arena_, invoke);
1878 }
1879 
VisitIntegerReverseBytes(HInvoke * invoke)1880 void IntrinsicCodeGeneratorARM::VisitIntegerReverseBytes(HInvoke* invoke) {
1881   ArmAssembler* assembler = GetAssembler();
1882   LocationSummary* locations = invoke->GetLocations();
1883 
1884   Register out = locations->Out().AsRegister<Register>();
1885   Register in  = locations->InAt(0).AsRegister<Register>();
1886 
1887   __ rev(out, in);
1888 }
1889 
VisitLongReverseBytes(HInvoke * invoke)1890 void IntrinsicLocationsBuilderARM::VisitLongReverseBytes(HInvoke* invoke) {
1891   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1892                                                             LocationSummary::kNoCall,
1893                                                             kIntrinsified);
1894   locations->SetInAt(0, Location::RequiresRegister());
1895   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1896 }
1897 
VisitLongReverseBytes(HInvoke * invoke)1898 void IntrinsicCodeGeneratorARM::VisitLongReverseBytes(HInvoke* invoke) {
1899   ArmAssembler* assembler = GetAssembler();
1900   LocationSummary* locations = invoke->GetLocations();
1901 
1902   Register in_reg_lo  = locations->InAt(0).AsRegisterPairLow<Register>();
1903   Register in_reg_hi  = locations->InAt(0).AsRegisterPairHigh<Register>();
1904   Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
1905   Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
1906 
1907   __ rev(out_reg_lo, in_reg_hi);
1908   __ rev(out_reg_hi, in_reg_lo);
1909 }
1910 
VisitShortReverseBytes(HInvoke * invoke)1911 void IntrinsicLocationsBuilderARM::VisitShortReverseBytes(HInvoke* invoke) {
1912   CreateIntToIntLocations(arena_, invoke);
1913 }
1914 
VisitShortReverseBytes(HInvoke * invoke)1915 void IntrinsicCodeGeneratorARM::VisitShortReverseBytes(HInvoke* invoke) {
1916   ArmAssembler* assembler = GetAssembler();
1917   LocationSummary* locations = invoke->GetLocations();
1918 
1919   Register out = locations->Out().AsRegister<Register>();
1920   Register in  = locations->InAt(0).AsRegister<Register>();
1921 
1922   __ revsh(out, in);
1923 }
1924 
VisitStringGetCharsNoCheck(HInvoke * invoke)1925 void IntrinsicLocationsBuilderARM::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1926   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1927                                                             LocationSummary::kNoCall,
1928                                                             kIntrinsified);
1929   locations->SetInAt(0, Location::RequiresRegister());
1930   locations->SetInAt(1, Location::RequiresRegister());
1931   locations->SetInAt(2, Location::RequiresRegister());
1932   locations->SetInAt(3, Location::RequiresRegister());
1933   locations->SetInAt(4, Location::RequiresRegister());
1934 
1935   locations->AddTemp(Location::RequiresRegister());
1936   locations->AddTemp(Location::RequiresRegister());
1937   locations->AddTemp(Location::RequiresRegister());
1938   locations->AddTemp(Location::RequiresRegister());
1939 }
1940 
VisitStringGetCharsNoCheck(HInvoke * invoke)1941 void IntrinsicCodeGeneratorARM::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1942   ArmAssembler* assembler = GetAssembler();
1943   LocationSummary* locations = invoke->GetLocations();
1944 
1945   // Check assumption that sizeof(Char) is 2 (used in scaling below).
1946   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
1947   DCHECK_EQ(char_size, 2u);
1948 
1949   // Location of data in char array buffer.
1950   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
1951 
1952   // Location of char array data in string.
1953   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1954 
1955   // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1956   // Since getChars() calls getCharsNoCheck() - we use registers rather than constants.
1957   Register srcObj = locations->InAt(0).AsRegister<Register>();
1958   Register srcBegin = locations->InAt(1).AsRegister<Register>();
1959   Register srcEnd = locations->InAt(2).AsRegister<Register>();
1960   Register dstObj = locations->InAt(3).AsRegister<Register>();
1961   Register dstBegin = locations->InAt(4).AsRegister<Register>();
1962 
1963   Register src_ptr = locations->GetTemp(0).AsRegister<Register>();
1964   Register src_ptr_end = locations->GetTemp(1).AsRegister<Register>();
1965   Register dst_ptr = locations->GetTemp(2).AsRegister<Register>();
1966   Register tmp = locations->GetTemp(3).AsRegister<Register>();
1967 
1968   // src range to copy.
1969   __ add(src_ptr, srcObj, ShifterOperand(value_offset));
1970   __ add(src_ptr_end, src_ptr, ShifterOperand(srcEnd, LSL, 1));
1971   __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1));
1972 
1973   // dst to be copied.
1974   __ add(dst_ptr, dstObj, ShifterOperand(data_offset));
1975   __ add(dst_ptr, dst_ptr, ShifterOperand(dstBegin, LSL, 1));
1976 
1977   // Do the copy.
1978   Label loop, done;
1979   __ Bind(&loop);
1980   __ cmp(src_ptr, ShifterOperand(src_ptr_end));
1981   __ b(&done, EQ);
1982   __ ldrh(tmp, Address(src_ptr, char_size, Address::PostIndex));
1983   __ strh(tmp, Address(dst_ptr, char_size, Address::PostIndex));
1984   __ b(&loop);
1985   __ Bind(&done);
1986 }
1987 
1988 UNIMPLEMENTED_INTRINSIC(ARM, IntegerBitCount)
1989 UNIMPLEMENTED_INTRINSIC(ARM, LongBitCount)
1990 UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble)
1991 UNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat)
1992 UNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble)
1993 UNIMPLEMENTED_INTRINSIC(ARM, MathMaxFloatFloat)
1994 UNIMPLEMENTED_INTRINSIC(ARM, MathMinLongLong)
1995 UNIMPLEMENTED_INTRINSIC(ARM, MathMaxLongLong)
1996 UNIMPLEMENTED_INTRINSIC(ARM, MathCeil)          // Could be done by changing rounding mode, maybe?
1997 UNIMPLEMENTED_INTRINSIC(ARM, MathFloor)         // Could be done by changing rounding mode, maybe?
1998 UNIMPLEMENTED_INTRINSIC(ARM, MathRint)
1999 UNIMPLEMENTED_INTRINSIC(ARM, MathRoundDouble)   // Could be done by changing rounding mode, maybe?
2000 UNIMPLEMENTED_INTRINSIC(ARM, MathRoundFloat)    // Could be done by changing rounding mode, maybe?
2001 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeCASLong)     // High register pressure.
2002 UNIMPLEMENTED_INTRINSIC(ARM, SystemArrayCopyChar)
2003 UNIMPLEMENTED_INTRINSIC(ARM, ReferenceGetReferent)
2004 UNIMPLEMENTED_INTRINSIC(ARM, FloatIsInfinite)
2005 UNIMPLEMENTED_INTRINSIC(ARM, DoubleIsInfinite)
2006 UNIMPLEMENTED_INTRINSIC(ARM, IntegerHighestOneBit)
2007 UNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit)
2008 UNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit)
2009 UNIMPLEMENTED_INTRINSIC(ARM, LongLowestOneBit)
2010 
2011 // 1.8.
2012 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddInt)
2013 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddLong)
2014 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetInt)
2015 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetLong)
2016 UNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetObject)
2017 
2018 UNREACHABLE_INTRINSICS(ARM)
2019 
2020 #undef __
2021 
2022 }  // namespace arm
2023 }  // namespace art
2024