blob: c268ef90529d4c5fab1e141cd791f26a52c08f54 [file] [log] [blame]
Chris Larsen701566a2015-10-27 15:29:13 -07001/*
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_mips.h"
18
19#include "arch/mips/instruction_set_features_mips.h"
20#include "art_method.h"
21#include "code_generator_mips.h"
22#include "entrypoints/quick/quick_entrypoints.h"
Andreas Gampe09659c22017-09-18 18:23:32 -070023#include "heap_poisoning.h"
Chris Larsen701566a2015-10-27 15:29:13 -070024#include "intrinsics.h"
25#include "mirror/array-inl.h"
Andreas Gampe895f9222017-07-05 09:53:32 -070026#include "mirror/object_array-inl.h"
Chris Larsen701566a2015-10-27 15:29:13 -070027#include "mirror/string.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070028#include "scoped_thread_state_change-inl.h"
Chris Larsen701566a2015-10-27 15:29:13 -070029#include "thread.h"
30#include "utils/mips/assembler_mips.h"
31#include "utils/mips/constants_mips.h"
32
33namespace art {
34
35namespace mips {
36
37IntrinsicLocationsBuilderMIPS::IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS* codegen)
Vladimir Markoca6fff82017-10-03 14:49:14 +010038 : codegen_(codegen), allocator_(codegen->GetGraph()->GetAllocator()) {
Chris Larsen701566a2015-10-27 15:29:13 -070039}
40
41MipsAssembler* IntrinsicCodeGeneratorMIPS::GetAssembler() {
42 return reinterpret_cast<MipsAssembler*>(codegen_->GetAssembler());
43}
44
45ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() {
Vladimir Markoca6fff82017-10-03 14:49:14 +010046 return codegen_->GetGraph()->GetAllocator();
Chris Larsen701566a2015-10-27 15:29:13 -070047}
48
Alexey Frunzebb9863a2016-01-11 15:51:16 -080049inline bool IntrinsicCodeGeneratorMIPS::IsR2OrNewer() const {
Chris Larsene16ce5a2015-11-18 12:30:20 -080050 return codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
51}
52
Alexey Frunzebb9863a2016-01-11 15:51:16 -080053inline bool IntrinsicCodeGeneratorMIPS::IsR6() const {
Chris Larsene16ce5a2015-11-18 12:30:20 -080054 return codegen_->GetInstructionSetFeatures().IsR6();
55}
56
Alexey Frunzebb9863a2016-01-11 15:51:16 -080057inline bool IntrinsicCodeGeneratorMIPS::Is32BitFPU() const {
58 return codegen_->GetInstructionSetFeatures().Is32BitFloatingPoint();
59}
60
Lena Djokic0d2cab52018-03-06 15:20:45 +010061inline bool IntrinsicCodeGeneratorMIPS::HasMsa() const {
62 return codegen_->GetInstructionSetFeatures().HasMsa();
63}
64
Chris Larsen701566a2015-10-27 15:29:13 -070065#define __ codegen->GetAssembler()->
66
67static void MoveFromReturnRegister(Location trg,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010068 DataType::Type type,
Chris Larsen701566a2015-10-27 15:29:13 -070069 CodeGeneratorMIPS* codegen) {
70 if (!trg.IsValid()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010071 DCHECK_EQ(type, DataType::Type::kVoid);
Chris Larsen701566a2015-10-27 15:29:13 -070072 return;
73 }
74
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010075 DCHECK_NE(type, DataType::Type::kVoid);
Chris Larsen701566a2015-10-27 15:29:13 -070076
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010077 if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
Chris Larsen701566a2015-10-27 15:29:13 -070078 Register trg_reg = trg.AsRegister<Register>();
79 if (trg_reg != V0) {
80 __ Move(V0, trg_reg);
81 }
82 } else {
83 FRegister trg_reg = trg.AsFpuRegister<FRegister>();
84 if (trg_reg != F0) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010085 if (type == DataType::Type::kFloat32) {
Chris Larsen701566a2015-10-27 15:29:13 -070086 __ MovS(F0, trg_reg);
87 } else {
88 __ MovD(F0, trg_reg);
89 }
90 }
91 }
92}
93
94static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
95 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
96 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
97}
98
99// Slow-path for fallback (calling the managed code to handle the
100// intrinsic) in an intrinsified call. This will copy the arguments
101// into the positions for a regular call.
102//
103// Note: The actual parameters are required to be in the locations
104// given by the invoke's location summary. If an intrinsic
105// modifies those locations before a slowpath call, they must be
106// restored!
107class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
108 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000109 explicit IntrinsicSlowPathMIPS(HInvoke* invoke) : SlowPathCodeMIPS(invoke), invoke_(invoke) { }
Chris Larsen701566a2015-10-27 15:29:13 -0700110
111 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
112 CodeGeneratorMIPS* codegen = down_cast<CodeGeneratorMIPS*>(codegen_in);
113
114 __ Bind(GetEntryLabel());
115
116 SaveLiveRegisters(codegen, invoke_->GetLocations());
117
118 MoveArguments(invoke_, codegen);
119
120 if (invoke_->IsInvokeStaticOrDirect()) {
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100121 codegen->GenerateStaticOrDirectCall(
122 invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0), this);
Chris Larsen701566a2015-10-27 15:29:13 -0700123 } else {
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100124 codegen->GenerateVirtualCall(
125 invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0), this);
Chris Larsen701566a2015-10-27 15:29:13 -0700126 }
127
128 // Copy the result back to the expected output.
129 Location out = invoke_->GetLocations()->Out();
130 if (out.IsValid()) {
131 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory.
132 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
133 MoveFromReturnRegister(out, invoke_->GetType(), codegen);
134 }
135
136 RestoreLiveRegisters(codegen, invoke_->GetLocations());
137 __ B(GetExitLabel());
138 }
139
140 const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS"; }
141
142 private:
143 // The instruction where this slow path is happening.
144 HInvoke* const invoke_;
145
146 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS);
147};
148
149#undef __
150
151bool IntrinsicLocationsBuilderMIPS::TryDispatch(HInvoke* invoke) {
152 Dispatch(invoke);
153 LocationSummary* res = invoke->GetLocations();
154 return res != nullptr && res->Intrinsified();
155}
156
157#define __ assembler->
158
Vladimir Markoca6fff82017-10-03 14:49:14 +0100159static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
160 LocationSummary* locations =
161 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700162 locations->SetInAt(0, Location::RequiresFpuRegister());
163 locations->SetOut(Location::RequiresRegister());
164}
165
166static void MoveFPToInt(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
167 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
168
169 if (is64bit) {
170 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
171 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
172
173 __ Mfc1(out_lo, in);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800174 __ MoveFromFpuHigh(out_hi, in);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700175 } else {
176 Register out = locations->Out().AsRegister<Register>();
177
178 __ Mfc1(out, in);
179 }
180}
181
182// long java.lang.Double.doubleToRawLongBits(double)
183void IntrinsicLocationsBuilderMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100184 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700185}
186
187void IntrinsicCodeGeneratorMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000188 MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700189}
190
191// int java.lang.Float.floatToRawIntBits(float)
192void IntrinsicLocationsBuilderMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100193 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700194}
195
196void IntrinsicCodeGeneratorMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000197 MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700198}
199
Vladimir Markoca6fff82017-10-03 14:49:14 +0100200static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
201 LocationSummary* locations =
202 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700203 locations->SetInAt(0, Location::RequiresRegister());
204 locations->SetOut(Location::RequiresFpuRegister());
205}
206
207static void MoveIntToFP(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
208 FRegister out = locations->Out().AsFpuRegister<FRegister>();
209
210 if (is64bit) {
211 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
212 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
213
214 __ Mtc1(in_lo, out);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800215 __ MoveToFpuHigh(in_hi, out);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700216 } else {
217 Register in = locations->InAt(0).AsRegister<Register>();
218
219 __ Mtc1(in, out);
220 }
221}
222
223// double java.lang.Double.longBitsToDouble(long)
224void IntrinsicLocationsBuilderMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100225 CreateIntToFPLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700226}
227
228void IntrinsicCodeGeneratorMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000229 MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700230}
231
232// float java.lang.Float.intBitsToFloat(int)
233void IntrinsicLocationsBuilderMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100234 CreateIntToFPLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700235}
236
237void IntrinsicCodeGeneratorMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000238 MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700239}
240
Vladimir Markoca6fff82017-10-03 14:49:14 +0100241static void CreateIntToIntLocations(ArenaAllocator* allocator,
Chris Larsen86829602015-11-18 12:27:52 -0800242 HInvoke* invoke,
243 Location::OutputOverlap overlaps = Location::kNoOutputOverlap) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100244 LocationSummary* locations =
245 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700246 locations->SetInAt(0, Location::RequiresRegister());
Chris Larsen86829602015-11-18 12:27:52 -0800247 locations->SetOut(Location::RequiresRegister(), overlaps);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700248}
249
Chris Larsen70014c82015-11-18 12:26:08 -0800250static void GenReverse(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100251 DataType::Type type,
Chris Larsen70014c82015-11-18 12:26:08 -0800252 bool isR2OrNewer,
253 bool isR6,
254 bool reverseBits,
255 MipsAssembler* assembler) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100256 DCHECK(type == DataType::Type::kInt16 ||
257 type == DataType::Type::kInt32 ||
258 type == DataType::Type::kInt64);
259 DCHECK(type != DataType::Type::kInt16 || !reverseBits);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700260
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100261 if (type == DataType::Type::kInt16) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700262 Register in = locations->InAt(0).AsRegister<Register>();
263 Register out = locations->Out().AsRegister<Register>();
264
265 if (isR2OrNewer) {
266 __ Wsbh(out, in);
267 __ Seh(out, out);
268 } else {
269 __ Sll(TMP, in, 24);
270 __ Sra(TMP, TMP, 16);
271 __ Sll(out, in, 16);
272 __ Srl(out, out, 24);
273 __ Or(out, out, TMP);
274 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100275 } else if (type == DataType::Type::kInt32) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700276 Register in = locations->InAt(0).AsRegister<Register>();
277 Register out = locations->Out().AsRegister<Register>();
278
279 if (isR2OrNewer) {
280 __ Rotr(out, in, 16);
281 __ Wsbh(out, out);
282 } else {
283 // MIPS32r1
284 // __ Rotr(out, in, 16);
285 __ Sll(TMP, in, 16);
286 __ Srl(out, in, 16);
287 __ Or(out, out, TMP);
288 // __ Wsbh(out, out);
289 __ LoadConst32(AT, 0x00FF00FF);
290 __ And(TMP, out, AT);
291 __ Sll(TMP, TMP, 8);
292 __ Srl(out, out, 8);
293 __ And(out, out, AT);
294 __ Or(out, out, TMP);
295 }
Chris Larsen70014c82015-11-18 12:26:08 -0800296 if (reverseBits) {
297 if (isR6) {
298 __ Bitswap(out, out);
299 } else {
300 __ LoadConst32(AT, 0x0F0F0F0F);
301 __ And(TMP, out, AT);
302 __ Sll(TMP, TMP, 4);
303 __ Srl(out, out, 4);
304 __ And(out, out, AT);
305 __ Or(out, TMP, out);
306 __ LoadConst32(AT, 0x33333333);
307 __ And(TMP, out, AT);
308 __ Sll(TMP, TMP, 2);
309 __ Srl(out, out, 2);
310 __ And(out, out, AT);
311 __ Or(out, TMP, out);
312 __ LoadConst32(AT, 0x55555555);
313 __ And(TMP, out, AT);
314 __ Sll(TMP, TMP, 1);
315 __ Srl(out, out, 1);
316 __ And(out, out, AT);
317 __ Or(out, TMP, out);
318 }
319 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100320 } else if (type == DataType::Type::kInt64) {
Chris Larsen3f8bf652015-10-28 10:08:56 -0700321 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
322 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
323 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
324 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
325
326 if (isR2OrNewer) {
327 __ Rotr(AT, in_hi, 16);
328 __ Rotr(TMP, in_lo, 16);
329 __ Wsbh(out_lo, AT);
330 __ Wsbh(out_hi, TMP);
331 } else {
332 // When calling CreateIntToIntLocations() we promised that the
333 // use of the out_lo/out_hi wouldn't overlap with the use of
334 // in_lo/in_hi. Be very careful not to write to out_lo/out_hi
335 // until we're completely done reading from in_lo/in_hi.
336 // __ Rotr(TMP, in_lo, 16);
337 __ Sll(TMP, in_lo, 16);
338 __ Srl(AT, in_lo, 16);
339 __ Or(TMP, TMP, AT); // Hold in TMP until it's safe
340 // to write to out_hi.
341 // __ Rotr(out_lo, in_hi, 16);
342 __ Sll(AT, in_hi, 16);
343 __ Srl(out_lo, in_hi, 16); // Here we are finally done reading
344 // from in_lo/in_hi so it's okay to
345 // write to out_lo/out_hi.
346 __ Or(out_lo, out_lo, AT);
347 // __ Wsbh(out_hi, out_hi);
348 __ LoadConst32(AT, 0x00FF00FF);
349 __ And(out_hi, TMP, AT);
350 __ Sll(out_hi, out_hi, 8);
351 __ Srl(TMP, TMP, 8);
352 __ And(TMP, TMP, AT);
353 __ Or(out_hi, out_hi, TMP);
354 // __ Wsbh(out_lo, out_lo);
355 __ And(TMP, out_lo, AT); // AT already holds the correct mask value
356 __ Sll(TMP, TMP, 8);
357 __ Srl(out_lo, out_lo, 8);
358 __ And(out_lo, out_lo, AT);
359 __ Or(out_lo, out_lo, TMP);
360 }
Chris Larsen70014c82015-11-18 12:26:08 -0800361 if (reverseBits) {
362 if (isR6) {
363 __ Bitswap(out_hi, out_hi);
364 __ Bitswap(out_lo, out_lo);
365 } else {
366 __ LoadConst32(AT, 0x0F0F0F0F);
367 __ And(TMP, out_hi, AT);
368 __ Sll(TMP, TMP, 4);
369 __ Srl(out_hi, out_hi, 4);
370 __ And(out_hi, out_hi, AT);
371 __ Or(out_hi, TMP, out_hi);
372 __ And(TMP, out_lo, AT);
373 __ Sll(TMP, TMP, 4);
374 __ Srl(out_lo, out_lo, 4);
375 __ And(out_lo, out_lo, AT);
376 __ Or(out_lo, TMP, out_lo);
377 __ LoadConst32(AT, 0x33333333);
378 __ And(TMP, out_hi, AT);
379 __ Sll(TMP, TMP, 2);
380 __ Srl(out_hi, out_hi, 2);
381 __ And(out_hi, out_hi, AT);
382 __ Or(out_hi, TMP, out_hi);
383 __ And(TMP, out_lo, AT);
384 __ Sll(TMP, TMP, 2);
385 __ Srl(out_lo, out_lo, 2);
386 __ And(out_lo, out_lo, AT);
387 __ Or(out_lo, TMP, out_lo);
388 __ LoadConst32(AT, 0x55555555);
389 __ And(TMP, out_hi, AT);
390 __ Sll(TMP, TMP, 1);
391 __ Srl(out_hi, out_hi, 1);
392 __ And(out_hi, out_hi, AT);
393 __ Or(out_hi, TMP, out_hi);
394 __ And(TMP, out_lo, AT);
395 __ Sll(TMP, TMP, 1);
396 __ Srl(out_lo, out_lo, 1);
397 __ And(out_lo, out_lo, AT);
398 __ Or(out_lo, TMP, out_lo);
399 }
400 }
Chris Larsen3f8bf652015-10-28 10:08:56 -0700401 }
402}
403
404// int java.lang.Integer.reverseBytes(int)
405void IntrinsicLocationsBuilderMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100406 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700407}
408
409void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
Chris Larsen70014c82015-11-18 12:26:08 -0800410 GenReverse(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100411 DataType::Type::kInt32,
Chris Larsene16ce5a2015-11-18 12:30:20 -0800412 IsR2OrNewer(),
413 IsR6(),
Chris Larsenb74353a2015-11-20 09:07:09 -0800414 /* reverseBits */ false,
Chris Larsen70014c82015-11-18 12:26:08 -0800415 GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700416}
417
418// long java.lang.Long.reverseBytes(long)
419void IntrinsicLocationsBuilderMIPS::VisitLongReverseBytes(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100420 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700421}
422
423void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) {
Chris Larsen70014c82015-11-18 12:26:08 -0800424 GenReverse(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100425 DataType::Type::kInt64,
Chris Larsene16ce5a2015-11-18 12:30:20 -0800426 IsR2OrNewer(),
427 IsR6(),
Chris Larsenb74353a2015-11-20 09:07:09 -0800428 /* reverseBits */ false,
Chris Larsen70014c82015-11-18 12:26:08 -0800429 GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700430}
431
432// short java.lang.Short.reverseBytes(short)
433void IntrinsicLocationsBuilderMIPS::VisitShortReverseBytes(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100434 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700435}
436
437void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) {
Chris Larsen70014c82015-11-18 12:26:08 -0800438 GenReverse(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100439 DataType::Type::kInt16,
Chris Larsene16ce5a2015-11-18 12:30:20 -0800440 IsR2OrNewer(),
441 IsR6(),
Chris Larsenb74353a2015-11-20 09:07:09 -0800442 /* reverseBits */ false,
Chris Larsen70014c82015-11-18 12:26:08 -0800443 GetAssembler());
444}
445
Chris Larsene3845472015-11-18 12:27:15 -0800446static void GenNumberOfLeadingZeroes(LocationSummary* locations,
447 bool is64bit,
448 bool isR6,
449 MipsAssembler* assembler) {
450 Register out = locations->Out().AsRegister<Register>();
451 if (is64bit) {
452 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
453 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
454
455 if (isR6) {
456 __ ClzR6(AT, in_hi);
457 __ ClzR6(TMP, in_lo);
458 __ Seleqz(TMP, TMP, in_hi);
459 } else {
460 __ ClzR2(AT, in_hi);
461 __ ClzR2(TMP, in_lo);
462 __ Movn(TMP, ZERO, in_hi);
463 }
464 __ Addu(out, AT, TMP);
465 } else {
466 Register in = locations->InAt(0).AsRegister<Register>();
467
468 if (isR6) {
469 __ ClzR6(out, in);
470 } else {
471 __ ClzR2(out, in);
472 }
473 }
474}
475
476// int java.lang.Integer.numberOfLeadingZeros(int i)
477void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100478 CreateIntToIntLocations(allocator_, invoke);
Chris Larsene3845472015-11-18 12:27:15 -0800479}
480
481void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800482 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
Chris Larsene3845472015-11-18 12:27:15 -0800483}
484
485// int java.lang.Long.numberOfLeadingZeros(long i)
486void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100487 CreateIntToIntLocations(allocator_, invoke);
Chris Larsene3845472015-11-18 12:27:15 -0800488}
489
490void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800491 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
Chris Larsene3845472015-11-18 12:27:15 -0800492}
493
Chris Larsen86829602015-11-18 12:27:52 -0800494static void GenNumberOfTrailingZeroes(LocationSummary* locations,
495 bool is64bit,
496 bool isR6,
Chris Larsen86829602015-11-18 12:27:52 -0800497 MipsAssembler* assembler) {
498 Register out = locations->Out().AsRegister<Register>();
499 Register in_lo;
500 Register in;
501
502 if (is64bit) {
Chris Larsen86829602015-11-18 12:27:52 -0800503 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
504
505 in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
506
507 // If in_lo is zero then count the number of trailing zeroes in in_hi;
508 // otherwise count the number of trailing zeroes in in_lo.
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800509 // out = in_lo ? in_lo : in_hi;
Chris Larsen86829602015-11-18 12:27:52 -0800510 if (isR6) {
511 __ Seleqz(out, in_hi, in_lo);
512 __ Selnez(TMP, in_lo, in_lo);
513 __ Or(out, out, TMP);
514 } else {
515 __ Movz(out, in_hi, in_lo);
516 __ Movn(out, in_lo, in_lo);
517 }
518
519 in = out;
520 } else {
521 in = locations->InAt(0).AsRegister<Register>();
522 // Give in_lo a dummy value to keep the compiler from complaining.
523 // Since we only get here in the 32-bit case, this value will never
524 // be used.
525 in_lo = in;
526 }
527
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800528 if (isR6) {
529 // We don't have an instruction to count the number of trailing zeroes.
530 // Start by flipping the bits end-for-end so we can count the number of
531 // leading zeroes instead.
Chris Larsen86829602015-11-18 12:27:52 -0800532 __ Rotr(out, in, 16);
533 __ Wsbh(out, out);
Chris Larsen86829602015-11-18 12:27:52 -0800534 __ Bitswap(out, out);
535 __ ClzR6(out, out);
536 } else {
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800537 // Convert trailing zeroes to trailing ones, and bits to their left
538 // to zeroes.
539 __ Addiu(TMP, in, -1);
540 __ Xor(out, TMP, in);
541 __ And(out, out, TMP);
542 // Count number of leading zeroes.
Chris Larsen86829602015-11-18 12:27:52 -0800543 __ ClzR2(out, out);
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800544 // Subtract number of leading zeroes from 32 to get number of trailing ones.
545 // Remember that the trailing ones were formerly trailing zeroes.
546 __ LoadConst32(TMP, 32);
547 __ Subu(out, TMP, out);
Chris Larsen86829602015-11-18 12:27:52 -0800548 }
549
550 if (is64bit) {
551 // If in_lo is zero, then we counted the number of trailing zeroes in in_hi so we must add the
552 // number of trailing zeroes in in_lo (32) to get the correct final count
553 __ LoadConst32(TMP, 32);
554 if (isR6) {
555 __ Seleqz(TMP, TMP, in_lo);
556 } else {
557 __ Movn(TMP, ZERO, in_lo);
558 }
559 __ Addu(out, out, TMP);
560 }
561}
562
563// int java.lang.Integer.numberOfTrailingZeros(int i)
564void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100565 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen86829602015-11-18 12:27:52 -0800566}
567
568void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800569 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
Chris Larsen86829602015-11-18 12:27:52 -0800570}
571
572// int java.lang.Long.numberOfTrailingZeros(long i)
573void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100574 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen86829602015-11-18 12:27:52 -0800575}
576
577void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
Chris Larsenbbb2ebe2016-02-17 17:44:58 -0800578 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
Chris Larsene16ce5a2015-11-18 12:30:20 -0800579}
580
Chris Larsen70014c82015-11-18 12:26:08 -0800581// int java.lang.Integer.reverse(int)
582void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100583 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen70014c82015-11-18 12:26:08 -0800584}
585
586void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) {
587 GenReverse(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100588 DataType::Type::kInt32,
Chris Larsene16ce5a2015-11-18 12:30:20 -0800589 IsR2OrNewer(),
590 IsR6(),
Chris Larsenb74353a2015-11-20 09:07:09 -0800591 /* reverseBits */ true,
Chris Larsen70014c82015-11-18 12:26:08 -0800592 GetAssembler());
593}
594
595// long java.lang.Long.reverse(long)
596void IntrinsicLocationsBuilderMIPS::VisitLongReverse(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100597 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen70014c82015-11-18 12:26:08 -0800598}
599
600void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
601 GenReverse(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100602 DataType::Type::kInt64,
Chris Larsene16ce5a2015-11-18 12:30:20 -0800603 IsR2OrNewer(),
604 IsR6(),
Chris Larsenb74353a2015-11-20 09:07:09 -0800605 /* reverseBits */ true,
Chris Larsen70014c82015-11-18 12:26:08 -0800606 GetAssembler());
Chris Larsen3f8bf652015-10-28 10:08:56 -0700607}
608
Vladimir Markoca6fff82017-10-03 14:49:14 +0100609static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
610 LocationSummary* locations =
611 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenb74353a2015-11-20 09:07:09 -0800612 locations->SetInAt(0, Location::RequiresFpuRegister());
613 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
614}
615
Chris Larsenedc16452016-02-12 17:59:00 -0800616static void GenBitCount(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100617 DataType::Type type,
Chris Larsenedc16452016-02-12 17:59:00 -0800618 bool isR6,
Lena Djokic0d2cab52018-03-06 15:20:45 +0100619 bool hasMsa,
Chris Larsenedc16452016-02-12 17:59:00 -0800620 MipsAssembler* assembler) {
Chris Larsenedc16452016-02-12 17:59:00 -0800621 Register out = locations->Out().AsRegister<Register>();
622
623 // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
624 //
625 // A generalization of the best bit counting method to integers of
626 // bit-widths up to 128 (parameterized by type T) is this:
627 //
628 // v = v - ((v >> 1) & (T)~(T)0/3); // temp
629 // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
630 // v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
631 // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
632 //
633 // For comparison, for 32-bit quantities, this algorithm can be executed
634 // using 20 MIPS instructions (the calls to LoadConst32() generate two
635 // machine instructions each for the values being used in this algorithm).
636 // A(n unrolled) loop-based algorithm required 25 instructions.
637 //
638 // For 64-bit quantities, this algorithm gets executed twice, (once
639 // for in_lo, and again for in_hi), but saves a few instructions
640 // because the mask values only have to be loaded once. Using this
Chris Larsen8ca4f972016-04-14 16:16:29 -0700641 // algorithm the count for a 64-bit operand can be performed in 29
Chris Larsenedc16452016-02-12 17:59:00 -0800642 // instructions compared to a loop-based algorithm which required 47
643 // instructions.
644
Lena Djokic0d2cab52018-03-06 15:20:45 +0100645 if (hasMsa) {
646 if (type == DataType::Type::kInt32) {
647 Register in = locations->InAt(0).AsRegister<Register>();
648 __ Mtc1(in, FTMP);
649 __ PcntW(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP));
650 __ Mfc1(out, FTMP);
Chris Larsenedc16452016-02-12 17:59:00 -0800651 } else {
Lena Djokic0d2cab52018-03-06 15:20:45 +0100652 DCHECK_EQ(type, DataType::Type::kInt64);
653 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
654 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
655 __ Mtc1(in_lo, FTMP);
656 __ Mthc1(in_hi, FTMP);
657 __ PcntD(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP));
658 __ Mfc1(out, FTMP);
Chris Larsenedc16452016-02-12 17:59:00 -0800659 }
Roland Levillainfa3912e2016-04-01 18:21:55 +0100660 } else {
Lena Djokic0d2cab52018-03-06 15:20:45 +0100661 if (type == DataType::Type::kInt32) {
662 Register in = locations->InAt(0).AsRegister<Register>();
Chris Larsenedc16452016-02-12 17:59:00 -0800663
Lena Djokic0d2cab52018-03-06 15:20:45 +0100664 __ Srl(TMP, in, 1);
665 __ LoadConst32(AT, 0x55555555);
666 __ And(TMP, TMP, AT);
667 __ Subu(TMP, in, TMP);
668 __ LoadConst32(AT, 0x33333333);
669 __ And(out, TMP, AT);
670 __ Srl(TMP, TMP, 2);
671 __ And(TMP, TMP, AT);
672 __ Addu(TMP, out, TMP);
673 __ Srl(out, TMP, 4);
674 __ Addu(out, out, TMP);
675 __ LoadConst32(AT, 0x0F0F0F0F);
676 __ And(out, out, AT);
677 __ LoadConst32(TMP, 0x01010101);
678 if (isR6) {
679 __ MulR6(out, out, TMP);
680 } else {
681 __ MulR2(out, out, TMP);
682 }
683 __ Srl(out, out, 24);
Chris Larsenedc16452016-02-12 17:59:00 -0800684 } else {
Lena Djokic0d2cab52018-03-06 15:20:45 +0100685 DCHECK_EQ(type, DataType::Type::kInt64);
686 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
687 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
688 Register tmp_hi = locations->GetTemp(0).AsRegister<Register>();
689 Register out_hi = locations->GetTemp(1).AsRegister<Register>();
690 Register tmp_lo = TMP;
691 Register out_lo = out;
Chris Larsenedc16452016-02-12 17:59:00 -0800692
Lena Djokic0d2cab52018-03-06 15:20:45 +0100693 __ Srl(tmp_lo, in_lo, 1);
694 __ Srl(tmp_hi, in_hi, 1);
695
696 __ LoadConst32(AT, 0x55555555);
697
698 __ And(tmp_lo, tmp_lo, AT);
699 __ Subu(tmp_lo, in_lo, tmp_lo);
700
701 __ And(tmp_hi, tmp_hi, AT);
702 __ Subu(tmp_hi, in_hi, tmp_hi);
703
704 __ LoadConst32(AT, 0x33333333);
705
706 __ And(out_lo, tmp_lo, AT);
707 __ Srl(tmp_lo, tmp_lo, 2);
708 __ And(tmp_lo, tmp_lo, AT);
709 __ Addu(tmp_lo, out_lo, tmp_lo);
710
711 __ And(out_hi, tmp_hi, AT);
712 __ Srl(tmp_hi, tmp_hi, 2);
713 __ And(tmp_hi, tmp_hi, AT);
714 __ Addu(tmp_hi, out_hi, tmp_hi);
715
716 // Here we deviate from the original algorithm a bit. We've reached
717 // the stage where the bitfields holding the subtotals are large
718 // enough to hold the combined subtotals for both the low word, and
719 // the high word. This means that we can add the subtotals for the
720 // the high, and low words into a single word, and compute the final
721 // result for both the high, and low words using fewer instructions.
722 __ LoadConst32(AT, 0x0F0F0F0F);
723
724 __ Addu(TMP, tmp_hi, tmp_lo);
725
726 __ Srl(out, TMP, 4);
727 __ And(out, out, AT);
728 __ And(TMP, TMP, AT);
729 __ Addu(out, out, TMP);
730
731 __ LoadConst32(AT, 0x01010101);
732
733 if (isR6) {
734 __ MulR6(out, out, AT);
735 } else {
736 __ MulR2(out, out, AT);
737 }
738
739 __ Srl(out, out, 24);
740 }
Chris Larsenedc16452016-02-12 17:59:00 -0800741 }
742}
743
744// int java.lang.Integer.bitCount(int)
745void IntrinsicLocationsBuilderMIPS::VisitIntegerBitCount(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100746 CreateIntToIntLocations(allocator_, invoke);
Chris Larsenedc16452016-02-12 17:59:00 -0800747}
748
749void IntrinsicCodeGeneratorMIPS::VisitIntegerBitCount(HInvoke* invoke) {
Lena Djokic0d2cab52018-03-06 15:20:45 +0100750 GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), HasMsa(), GetAssembler());
Chris Larsenedc16452016-02-12 17:59:00 -0800751}
752
753// int java.lang.Long.bitCount(int)
754void IntrinsicLocationsBuilderMIPS::VisitLongBitCount(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100755 LocationSummary* locations =
756 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenedc16452016-02-12 17:59:00 -0800757 locations->SetInAt(0, Location::RequiresRegister());
758 locations->SetOut(Location::RequiresRegister());
759 locations->AddTemp(Location::RequiresRegister());
760 locations->AddTemp(Location::RequiresRegister());
761}
762
763void IntrinsicCodeGeneratorMIPS::VisitLongBitCount(HInvoke* invoke) {
Lena Djokic0d2cab52018-03-06 15:20:45 +0100764 GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), HasMsa(), GetAssembler());
Chris Larsenedc16452016-02-12 17:59:00 -0800765}
766
Chris Larsenb74353a2015-11-20 09:07:09 -0800767static void GenMinMaxFP(LocationSummary* locations,
768 bool is_min,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100769 DataType::Type type,
Chris Larsenb74353a2015-11-20 09:07:09 -0800770 bool is_R6,
771 MipsAssembler* assembler) {
772 FRegister out = locations->Out().AsFpuRegister<FRegister>();
773 FRegister a = locations->InAt(0).AsFpuRegister<FRegister>();
774 FRegister b = locations->InAt(1).AsFpuRegister<FRegister>();
775
776 if (is_R6) {
777 MipsLabel noNaNs;
778 MipsLabel done;
779 FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
780
781 // When Java computes min/max it prefers a NaN to a number; the
782 // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
783 // the inputs is a NaN and the other is a valid number, the MIPS
784 // instruction will return the number; Java wants the NaN value
785 // returned. This is why there is extra logic preceding the use of
786 // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
787 // NaN, return the NaN, otherwise return the min/max.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100788 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800789 __ CmpUnD(FTMP, a, b);
790 __ Bc1eqz(FTMP, &noNaNs);
791
792 // One of the inputs is a NaN
793 __ CmpEqD(ftmp, a, a);
794 // If a == a then b is the NaN, otherwise a is the NaN.
795 __ SelD(ftmp, a, b);
796
797 if (ftmp != out) {
798 __ MovD(out, ftmp);
799 }
800
801 __ B(&done);
802
803 __ Bind(&noNaNs);
804
805 if (is_min) {
806 __ MinD(out, a, b);
807 } else {
808 __ MaxD(out, a, b);
809 }
810 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100811 DCHECK_EQ(type, DataType::Type::kFloat32);
Chris Larsenb74353a2015-11-20 09:07:09 -0800812 __ CmpUnS(FTMP, a, b);
813 __ Bc1eqz(FTMP, &noNaNs);
814
815 // One of the inputs is a NaN
816 __ CmpEqS(ftmp, a, a);
817 // If a == a then b is the NaN, otherwise a is the NaN.
818 __ SelS(ftmp, a, b);
819
820 if (ftmp != out) {
821 __ MovS(out, ftmp);
822 }
823
824 __ B(&done);
825
826 __ Bind(&noNaNs);
827
828 if (is_min) {
829 __ MinS(out, a, b);
830 } else {
831 __ MaxS(out, a, b);
832 }
833 }
834
835 __ Bind(&done);
836 } else {
837 MipsLabel ordered;
838 MipsLabel compare;
839 MipsLabel select;
840 MipsLabel done;
841
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100842 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800843 __ CunD(a, b);
844 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100845 DCHECK_EQ(type, DataType::Type::kFloat32);
Chris Larsenb74353a2015-11-20 09:07:09 -0800846 __ CunS(a, b);
847 }
848 __ Bc1f(&ordered);
849
850 // a or b (or both) is a NaN. Return one, which is a NaN.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100851 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800852 __ CeqD(b, b);
853 } else {
854 __ CeqS(b, b);
855 }
856 __ B(&select);
857
858 __ Bind(&ordered);
859
860 // Neither is a NaN.
861 // a == b? (-0.0 compares equal with +0.0)
862 // If equal, handle zeroes, else compare further.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100863 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800864 __ CeqD(a, b);
865 } else {
866 __ CeqS(a, b);
867 }
868 __ Bc1f(&compare);
869
870 // a == b either bit for bit or one is -0.0 and the other is +0.0.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100871 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800872 __ MoveFromFpuHigh(TMP, a);
873 __ MoveFromFpuHigh(AT, b);
874 } else {
875 __ Mfc1(TMP, a);
876 __ Mfc1(AT, b);
877 }
878
879 if (is_min) {
880 // -0.0 prevails over +0.0.
881 __ Or(TMP, TMP, AT);
882 } else {
883 // +0.0 prevails over -0.0.
884 __ And(TMP, TMP, AT);
885 }
886
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100887 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800888 __ Mfc1(AT, a);
889 __ Mtc1(AT, out);
890 __ MoveToFpuHigh(TMP, out);
891 } else {
892 __ Mtc1(TMP, out);
893 }
894 __ B(&done);
895
896 __ Bind(&compare);
897
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100898 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800899 if (is_min) {
900 // return (a <= b) ? a : b;
901 __ ColeD(a, b);
902 } else {
903 // return (a >= b) ? a : b;
904 __ ColeD(b, a); // b <= a
905 }
906 } else {
907 if (is_min) {
908 // return (a <= b) ? a : b;
909 __ ColeS(a, b);
910 } else {
911 // return (a >= b) ? a : b;
912 __ ColeS(b, a); // b <= a
913 }
914 }
915
916 __ Bind(&select);
917
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100918 if (type == DataType::Type::kFloat64) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800919 __ MovtD(out, a);
920 __ MovfD(out, b);
921 } else {
922 __ MovtS(out, a);
923 __ MovfS(out, b);
924 }
925
926 __ Bind(&done);
927 }
928}
929
Vladimir Markoca6fff82017-10-03 14:49:14 +0100930static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
931 LocationSummary* locations =
932 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenb74353a2015-11-20 09:07:09 -0800933 locations->SetInAt(0, Location::RequiresFpuRegister());
934 locations->SetInAt(1, Location::RequiresFpuRegister());
935 locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap);
936}
937
938// double java.lang.Math.min(double, double)
939void IntrinsicLocationsBuilderMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100940 CreateFPFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -0800941}
942
943void IntrinsicCodeGeneratorMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
944 GenMinMaxFP(invoke->GetLocations(),
945 /* is_min */ true,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100946 DataType::Type::kFloat64,
Chris Larsenb74353a2015-11-20 09:07:09 -0800947 IsR6(),
948 GetAssembler());
949}
950
951// float java.lang.Math.min(float, float)
952void IntrinsicLocationsBuilderMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100953 CreateFPFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -0800954}
955
956void IntrinsicCodeGeneratorMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
957 GenMinMaxFP(invoke->GetLocations(),
958 /* is_min */ true,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100959 DataType::Type::kFloat32,
Chris Larsenb74353a2015-11-20 09:07:09 -0800960 IsR6(),
961 GetAssembler());
962}
963
964// double java.lang.Math.max(double, double)
965void IntrinsicLocationsBuilderMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100966 CreateFPFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -0800967}
968
969void IntrinsicCodeGeneratorMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
970 GenMinMaxFP(invoke->GetLocations(),
971 /* is_min */ false,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100972 DataType::Type::kFloat64,
Chris Larsenb74353a2015-11-20 09:07:09 -0800973 IsR6(),
974 GetAssembler());
975}
976
977// float java.lang.Math.max(float, float)
978void IntrinsicLocationsBuilderMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100979 CreateFPFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -0800980}
981
982void IntrinsicCodeGeneratorMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
983 GenMinMaxFP(invoke->GetLocations(),
984 /* is_min */ false,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100985 DataType::Type::kFloat32,
Chris Larsenb74353a2015-11-20 09:07:09 -0800986 IsR6(),
987 GetAssembler());
988}
989
Vladimir Markoca6fff82017-10-03 14:49:14 +0100990static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
991 LocationSummary* locations =
992 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenb74353a2015-11-20 09:07:09 -0800993 locations->SetInAt(0, Location::RequiresRegister());
994 locations->SetInAt(1, Location::RequiresRegister());
995 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
996}
997
998static void GenMinMax(LocationSummary* locations,
999 bool is_min,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001000 DataType::Type type,
Chris Larsenb74353a2015-11-20 09:07:09 -08001001 bool is_R6,
1002 MipsAssembler* assembler) {
1003 if (is_R6) {
1004 // Some architectures, such as ARM and MIPS (prior to r6), have a
1005 // conditional move instruction which only changes the target
1006 // (output) register if the condition is true (MIPS prior to r6 had
1007 // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions
1008 // always change the target (output) register. If the condition is
1009 // true the output register gets the contents of the "rs" register;
1010 // otherwise, the output register is set to zero. One consequence
1011 // of this is that to implement something like "rd = c==0 ? rs : rt"
1012 // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions.
1013 // After executing this pair of instructions one of the output
1014 // registers from the pair will necessarily contain zero. Then the
1015 // code ORs the output registers from the SELEQZ/SELNEZ instructions
1016 // to get the final result.
1017 //
1018 // The initial test to see if the output register is same as the
1019 // first input register is needed to make sure that value in the
1020 // first input register isn't clobbered before we've finished
1021 // computing the output value. The logic in the corresponding else
1022 // clause performs the same task but makes sure the second input
1023 // register isn't clobbered in the event that it's the same register
1024 // as the output register; the else clause also handles the case
1025 // where the output register is distinct from both the first, and the
1026 // second input registers.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001027 if (type == DataType::Type::kInt64) {
Chris Larsenb74353a2015-11-20 09:07:09 -08001028 Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1029 Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1030 Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
1031 Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
1032 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1033 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1034
1035 MipsLabel compare_done;
1036
1037 if (a_lo == b_lo) {
1038 if (out_lo != a_lo) {
1039 __ Move(out_lo, a_lo);
1040 __ Move(out_hi, a_hi);
1041 }
1042 } else {
1043 __ Slt(TMP, b_hi, a_hi);
1044 __ Bne(b_hi, a_hi, &compare_done);
1045
1046 __ Sltu(TMP, b_lo, a_lo);
1047
1048 __ Bind(&compare_done);
1049
1050 if (is_min) {
1051 __ Seleqz(AT, a_lo, TMP);
1052 __ Selnez(out_lo, b_lo, TMP); // Safe even if out_lo == a_lo/b_lo
1053 // because at this point we're
1054 // done using a_lo/b_lo.
1055 } else {
1056 __ Selnez(AT, a_lo, TMP);
1057 __ Seleqz(out_lo, b_lo, TMP); // ditto
1058 }
1059 __ Or(out_lo, out_lo, AT);
1060 if (is_min) {
1061 __ Seleqz(AT, a_hi, TMP);
1062 __ Selnez(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi
1063 } else {
1064 __ Selnez(AT, a_hi, TMP);
1065 __ Seleqz(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi
1066 }
1067 __ Or(out_hi, out_hi, AT);
1068 }
1069 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001070 DCHECK_EQ(type, DataType::Type::kInt32);
Chris Larsenb74353a2015-11-20 09:07:09 -08001071 Register a = locations->InAt(0).AsRegister<Register>();
1072 Register b = locations->InAt(1).AsRegister<Register>();
1073 Register out = locations->Out().AsRegister<Register>();
1074
1075 if (a == b) {
1076 if (out != a) {
1077 __ Move(out, a);
1078 }
1079 } else {
1080 __ Slt(AT, b, a);
1081 if (is_min) {
1082 __ Seleqz(TMP, a, AT);
1083 __ Selnez(AT, b, AT);
1084 } else {
1085 __ Selnez(TMP, a, AT);
1086 __ Seleqz(AT, b, AT);
1087 }
1088 __ Or(out, TMP, AT);
1089 }
1090 }
1091 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001092 if (type == DataType::Type::kInt64) {
Chris Larsenb74353a2015-11-20 09:07:09 -08001093 Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1094 Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1095 Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
1096 Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
1097 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1098 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1099
1100 MipsLabel compare_done;
1101
1102 if (a_lo == b_lo) {
1103 if (out_lo != a_lo) {
1104 __ Move(out_lo, a_lo);
1105 __ Move(out_hi, a_hi);
1106 }
1107 } else {
1108 __ Slt(TMP, a_hi, b_hi);
1109 __ Bne(a_hi, b_hi, &compare_done);
1110
1111 __ Sltu(TMP, a_lo, b_lo);
1112
1113 __ Bind(&compare_done);
1114
1115 if (is_min) {
1116 if (out_lo != a_lo) {
1117 __ Movn(out_hi, a_hi, TMP);
1118 __ Movn(out_lo, a_lo, TMP);
1119 }
1120 if (out_lo != b_lo) {
1121 __ Movz(out_hi, b_hi, TMP);
1122 __ Movz(out_lo, b_lo, TMP);
1123 }
1124 } else {
1125 if (out_lo != a_lo) {
1126 __ Movz(out_hi, a_hi, TMP);
1127 __ Movz(out_lo, a_lo, TMP);
1128 }
1129 if (out_lo != b_lo) {
1130 __ Movn(out_hi, b_hi, TMP);
1131 __ Movn(out_lo, b_lo, TMP);
1132 }
1133 }
1134 }
1135 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001136 DCHECK_EQ(type, DataType::Type::kInt32);
Chris Larsenb74353a2015-11-20 09:07:09 -08001137 Register a = locations->InAt(0).AsRegister<Register>();
1138 Register b = locations->InAt(1).AsRegister<Register>();
1139 Register out = locations->Out().AsRegister<Register>();
1140
1141 if (a == b) {
1142 if (out != a) {
1143 __ Move(out, a);
1144 }
1145 } else {
1146 __ Slt(AT, a, b);
1147 if (is_min) {
1148 if (out != a) {
1149 __ Movn(out, a, AT);
1150 }
1151 if (out != b) {
1152 __ Movz(out, b, AT);
1153 }
1154 } else {
1155 if (out != a) {
1156 __ Movz(out, a, AT);
1157 }
1158 if (out != b) {
1159 __ Movn(out, b, AT);
1160 }
1161 }
1162 }
1163 }
1164 }
1165}
1166
1167// int java.lang.Math.min(int, int)
1168void IntrinsicLocationsBuilderMIPS::VisitMathMinIntInt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001169 CreateIntIntToIntLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -08001170}
1171
1172void IntrinsicCodeGeneratorMIPS::VisitMathMinIntInt(HInvoke* invoke) {
1173 GenMinMax(invoke->GetLocations(),
1174 /* is_min */ true,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001175 DataType::Type::kInt32,
Chris Larsenb74353a2015-11-20 09:07:09 -08001176 IsR6(),
1177 GetAssembler());
1178}
1179
1180// long java.lang.Math.min(long, long)
1181void IntrinsicLocationsBuilderMIPS::VisitMathMinLongLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001182 CreateIntIntToIntLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -08001183}
1184
1185void IntrinsicCodeGeneratorMIPS::VisitMathMinLongLong(HInvoke* invoke) {
1186 GenMinMax(invoke->GetLocations(),
1187 /* is_min */ true,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001188 DataType::Type::kInt64,
Chris Larsenb74353a2015-11-20 09:07:09 -08001189 IsR6(),
1190 GetAssembler());
1191}
1192
1193// int java.lang.Math.max(int, int)
1194void IntrinsicLocationsBuilderMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001195 CreateIntIntToIntLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -08001196}
1197
1198void IntrinsicCodeGeneratorMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
1199 GenMinMax(invoke->GetLocations(),
1200 /* is_min */ false,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001201 DataType::Type::kInt32,
Chris Larsenb74353a2015-11-20 09:07:09 -08001202 IsR6(),
1203 GetAssembler());
1204}
1205
1206// long java.lang.Math.max(long, long)
1207void IntrinsicLocationsBuilderMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001208 CreateIntIntToIntLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -08001209}
1210
1211void IntrinsicCodeGeneratorMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
1212 GenMinMax(invoke->GetLocations(),
1213 /* is_min */ false,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001214 DataType::Type::kInt64,
Chris Larsenb74353a2015-11-20 09:07:09 -08001215 IsR6(),
1216 GetAssembler());
1217}
1218
1219// double java.lang.Math.sqrt(double)
1220void IntrinsicLocationsBuilderMIPS::VisitMathSqrt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001221 CreateFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -08001222}
1223
1224void IntrinsicCodeGeneratorMIPS::VisitMathSqrt(HInvoke* invoke) {
1225 LocationSummary* locations = invoke->GetLocations();
1226 MipsAssembler* assembler = GetAssembler();
1227 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
1228 FRegister out = locations->Out().AsFpuRegister<FRegister>();
1229
1230 __ SqrtD(out, in);
1231}
1232
Chris Larsen3acee732015-11-18 13:31:08 -08001233// byte libcore.io.Memory.peekByte(long address)
1234void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001235 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001236}
1237
1238void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
1239 MipsAssembler* assembler = GetAssembler();
1240 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1241 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1242
1243 __ Lb(out, adr, 0);
1244}
1245
1246// short libcore.io.Memory.peekShort(long address)
1247void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001248 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001249}
1250
1251void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
1252 MipsAssembler* assembler = GetAssembler();
1253 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1254 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1255
1256 if (IsR6()) {
1257 __ Lh(out, adr, 0);
1258 } else if (IsR2OrNewer()) {
1259 // Unlike for words, there are no lhl/lhr instructions to load
1260 // unaligned halfwords so the code loads individual bytes, in case
1261 // the address isn't halfword-aligned, and assembles them into a
1262 // signed halfword.
1263 __ Lb(AT, adr, 1); // This byte must be sign-extended.
1264 __ Lb(out, adr, 0); // This byte can be either sign-extended, or
1265 // zero-extended because the following
1266 // instruction overwrites the sign bits.
1267 __ Ins(out, AT, 8, 24);
1268 } else {
1269 __ Lbu(AT, adr, 0); // This byte must be zero-extended. If it's not
1270 // the "or" instruction below will destroy the upper
1271 // 24 bits of the final result.
1272 __ Lb(out, adr, 1); // This byte must be sign-extended.
1273 __ Sll(out, out, 8);
1274 __ Or(out, out, AT);
1275 }
1276}
1277
1278// int libcore.io.Memory.peekInt(long address)
1279void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001280 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen3acee732015-11-18 13:31:08 -08001281}
1282
1283void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
1284 MipsAssembler* assembler = GetAssembler();
1285 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1286 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1287
1288 if (IsR6()) {
1289 __ Lw(out, adr, 0);
1290 } else {
1291 __ Lwr(out, adr, 0);
1292 __ Lwl(out, adr, 3);
1293 }
1294}
1295
1296// long libcore.io.Memory.peekLong(long address)
1297void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001298 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen3acee732015-11-18 13:31:08 -08001299}
1300
1301void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
1302 MipsAssembler* assembler = GetAssembler();
1303 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1304 Register out_lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
1305 Register out_hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
1306
1307 if (IsR6()) {
1308 __ Lw(out_lo, adr, 0);
1309 __ Lw(out_hi, adr, 4);
1310 } else {
1311 __ Lwr(out_lo, adr, 0);
1312 __ Lwl(out_lo, adr, 3);
1313 __ Lwr(out_hi, adr, 4);
1314 __ Lwl(out_hi, adr, 7);
1315 }
1316}
1317
Vladimir Markoca6fff82017-10-03 14:49:14 +01001318static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
1319 LocationSummary* locations =
1320 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen3acee732015-11-18 13:31:08 -08001321 locations->SetInAt(0, Location::RequiresRegister());
1322 locations->SetInAt(1, Location::RequiresRegister());
1323}
1324
1325// void libcore.io.Memory.pokeByte(long address, byte value)
1326void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001327 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001328}
1329
1330void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
1331 MipsAssembler* assembler = GetAssembler();
1332 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1333 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1334
1335 __ Sb(val, adr, 0);
1336}
1337
1338// void libcore.io.Memory.pokeShort(long address, short value)
1339void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001340 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001341}
1342
1343void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
1344 MipsAssembler* assembler = GetAssembler();
1345 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1346 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1347
1348 if (IsR6()) {
1349 __ Sh(val, adr, 0);
1350 } else {
1351 // Unlike for words, there are no shl/shr instructions to store
1352 // unaligned halfwords so the code stores individual bytes, in case
1353 // the address isn't halfword-aligned.
1354 __ Sb(val, adr, 0);
1355 __ Srl(AT, val, 8);
1356 __ Sb(AT, adr, 1);
1357 }
1358}
1359
1360// void libcore.io.Memory.pokeInt(long address, int value)
1361void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001362 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001363}
1364
1365void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
1366 MipsAssembler* assembler = GetAssembler();
1367 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1368 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1369
1370 if (IsR6()) {
1371 __ Sw(val, adr, 0);
1372 } else {
1373 __ Swr(val, adr, 0);
1374 __ Swl(val, adr, 3);
1375 }
1376}
1377
1378// void libcore.io.Memory.pokeLong(long address, long value)
1379void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001380 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -08001381}
1382
1383void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
1384 MipsAssembler* assembler = GetAssembler();
1385 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1386 Register val_lo = invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>();
1387 Register val_hi = invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>();
1388
1389 if (IsR6()) {
1390 __ Sw(val_lo, adr, 0);
1391 __ Sw(val_hi, adr, 4);
1392 } else {
1393 __ Swr(val_lo, adr, 0);
1394 __ Swl(val_lo, adr, 3);
1395 __ Swr(val_hi, adr, 4);
1396 __ Swl(val_hi, adr, 7);
1397 }
1398}
1399
Chris Larsencf283da2016-01-19 16:45:35 -08001400// Thread java.lang.Thread.currentThread()
1401void IntrinsicLocationsBuilderMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001402 LocationSummary* locations =
1403 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001404 locations->SetOut(Location::RequiresRegister());
1405}
1406
1407void IntrinsicCodeGeneratorMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
1408 MipsAssembler* assembler = GetAssembler();
1409 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1410
1411 __ LoadFromOffset(kLoadWord,
1412 out,
1413 TR,
1414 Thread::PeerOffset<kMipsPointerSize>().Int32Value());
1415}
1416
Vladimir Markoca6fff82017-10-03 14:49:14 +01001417static void CreateIntIntIntToIntLocations(ArenaAllocator* allocator,
Alexey Frunze15958152017-02-09 19:08:30 -08001418 HInvoke* invoke,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001419 DataType::Type type) {
Alexey Frunze15958152017-02-09 19:08:30 -08001420 bool can_call = kEmitCompilerReadBarrier &&
1421 (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
1422 invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001423 LocationSummary* locations =
1424 new (allocator) LocationSummary(invoke,
1425 can_call
1426 ? LocationSummary::kCallOnSlowPath
1427 : LocationSummary::kNoCall,
1428 kIntrinsified);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001429 if (can_call && kUseBakerReadBarrier) {
1430 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
1431 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001432 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1433 locations->SetInAt(1, Location::RequiresRegister());
1434 locations->SetInAt(2, Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08001435 locations->SetOut(Location::RequiresRegister(),
1436 (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001437 if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze15958152017-02-09 19:08:30 -08001438 // We need a temporary register for the read barrier marking slow
1439 // path in InstructionCodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier.
1440 locations->AddTemp(Location::RequiresRegister());
1441 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001442}
1443
Alexey Frunze15958152017-02-09 19:08:30 -08001444// Note that the caller must supply a properly aligned memory address.
1445// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001446static void GenUnsafeGet(HInvoke* invoke,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001447 DataType::Type type,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001448 bool is_volatile,
1449 bool is_R6,
1450 CodeGeneratorMIPS* codegen) {
1451 LocationSummary* locations = invoke->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001452 DCHECK((type == DataType::Type::kInt32) ||
1453 (type == DataType::Type::kInt64) ||
1454 (type == DataType::Type::kReference)) << type;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001455 MipsAssembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001456 // Target register.
1457 Location trg_loc = locations->Out();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001458 // Object pointer.
Alexey Frunze15958152017-02-09 19:08:30 -08001459 Location base_loc = locations->InAt(1);
1460 Register base = base_loc.AsRegister<Register>();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001461 // The "offset" argument is passed as a "long". Since this code is for
1462 // a 32-bit processor, we can only use 32-bit addresses, so we only
1463 // need the low 32-bits of offset.
Alexey Frunze15958152017-02-09 19:08:30 -08001464 Location offset_loc = locations->InAt(2);
1465 Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001466
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001467 if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == DataType::Type::kReference))) {
Alexey Frunze15958152017-02-09 19:08:30 -08001468 __ Addu(TMP, base, offset_lo);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001469 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001470
Alexey Frunze15958152017-02-09 19:08:30 -08001471 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001472 case DataType::Type::kInt64: {
Alexey Frunze15958152017-02-09 19:08:30 -08001473 Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
1474 Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
1475 CHECK(!is_volatile); // TODO: support atomic 8-byte volatile loads.
1476 if (is_R6) {
1477 __ Lw(trg_lo, TMP, 0);
1478 __ Lw(trg_hi, TMP, 4);
1479 } else {
1480 __ Lwr(trg_lo, TMP, 0);
1481 __ Lwl(trg_lo, TMP, 3);
1482 __ Lwr(trg_hi, TMP, 4);
1483 __ Lwl(trg_hi, TMP, 7);
1484 }
1485 break;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001486 }
Alexey Frunzec061de12017-02-14 13:27:23 -08001487
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001488 case DataType::Type::kInt32: {
Alexey Frunze15958152017-02-09 19:08:30 -08001489 Register trg = trg_loc.AsRegister<Register>();
1490 if (is_R6) {
1491 __ Lw(trg, TMP, 0);
1492 } else {
1493 __ Lwr(trg, TMP, 0);
1494 __ Lwl(trg, TMP, 3);
1495 }
1496 if (is_volatile) {
1497 __ Sync(0);
1498 }
1499 break;
Alexey Frunzec061de12017-02-14 13:27:23 -08001500 }
Alexey Frunze15958152017-02-09 19:08:30 -08001501
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001502 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08001503 Register trg = trg_loc.AsRegister<Register>();
1504 if (kEmitCompilerReadBarrier) {
1505 if (kUseBakerReadBarrier) {
1506 Location temp = locations->GetTemp(0);
1507 codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
1508 trg_loc,
1509 base,
1510 /* offset */ 0U,
1511 /* index */ offset_loc,
1512 TIMES_1,
1513 temp,
1514 /* needs_null_check */ false);
1515 if (is_volatile) {
1516 __ Sync(0);
1517 }
1518 } else {
1519 if (is_R6) {
1520 __ Lw(trg, TMP, 0);
1521 } else {
1522 __ Lwr(trg, TMP, 0);
1523 __ Lwl(trg, TMP, 3);
1524 }
1525 if (is_volatile) {
1526 __ Sync(0);
1527 }
1528 codegen->GenerateReadBarrierSlow(invoke,
1529 trg_loc,
1530 trg_loc,
1531 base_loc,
1532 /* offset */ 0U,
1533 /* index */ offset_loc);
1534 }
1535 } else {
1536 if (is_R6) {
1537 __ Lw(trg, TMP, 0);
1538 } else {
1539 __ Lwr(trg, TMP, 0);
1540 __ Lwl(trg, TMP, 3);
1541 }
1542 if (is_volatile) {
1543 __ Sync(0);
1544 }
1545 __ MaybeUnpoisonHeapReference(trg);
1546 }
1547 break;
1548 }
1549
1550 default:
1551 LOG(FATAL) << "Unexpected type " << type;
1552 UNREACHABLE();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001553 }
1554}
1555
1556// int sun.misc.Unsafe.getInt(Object o, long offset)
1557void IntrinsicLocationsBuilderMIPS::VisitUnsafeGet(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001558 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001559}
1560
1561void IntrinsicCodeGeneratorMIPS::VisitUnsafeGet(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001562 GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001563}
1564
1565// int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
1566void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001567 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001568}
1569
1570void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001571 GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001572}
1573
1574// long sun.misc.Unsafe.getLong(Object o, long offset)
1575void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001576 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt64);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001577}
1578
1579void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001580 GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001581}
1582
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001583// Object sun.misc.Unsafe.getObject(Object o, long offset)
1584void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001585 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001586}
1587
1588void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001589 GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001590}
1591
1592// Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
1593void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001594 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001595}
1596
1597void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001598 GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001599}
1600
Vladimir Markoca6fff82017-10-03 14:49:14 +01001601static void CreateIntIntIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
1602 LocationSummary* locations =
1603 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001604 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1605 locations->SetInAt(1, Location::RequiresRegister());
1606 locations->SetInAt(2, Location::RequiresRegister());
1607 locations->SetInAt(3, Location::RequiresRegister());
1608}
1609
Alexey Frunze15958152017-02-09 19:08:30 -08001610// Note that the caller must supply a properly aligned memory address.
1611// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001612static void GenUnsafePut(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001613 DataType::Type type,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001614 bool is_volatile,
1615 bool is_ordered,
1616 bool is_R6,
1617 CodeGeneratorMIPS* codegen) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001618 DCHECK((type == DataType::Type::kInt32) ||
1619 (type == DataType::Type::kInt64) ||
1620 (type == DataType::Type::kReference)) << type;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001621 MipsAssembler* assembler = codegen->GetAssembler();
1622 // Object pointer.
1623 Register base = locations->InAt(1).AsRegister<Register>();
1624 // The "offset" argument is passed as a "long", i.e., it's 64-bits in
1625 // size. Since this code is for a 32-bit processor, we can only use
1626 // 32-bit addresses, so we only need the low 32-bits of offset.
1627 Register offset_lo = locations->InAt(2).AsRegisterPairLow<Register>();
1628
1629 __ Addu(TMP, base, offset_lo);
1630 if (is_volatile || is_ordered) {
1631 __ Sync(0);
1632 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001633 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001634 Register value = locations->InAt(3).AsRegister<Register>();
1635
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001636 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001637 __ PoisonHeapReference(AT, value);
1638 value = AT;
1639 }
1640
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001641 if (is_R6) {
1642 __ Sw(value, TMP, 0);
1643 } else {
1644 __ Swr(value, TMP, 0);
1645 __ Swl(value, TMP, 3);
1646 }
1647 } else {
1648 Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
1649 Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001650 CHECK(!is_volatile); // TODO: support atomic 8-byte volatile stores.
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001651 if (is_R6) {
1652 __ Sw(value_lo, TMP, 0);
1653 __ Sw(value_hi, TMP, 4);
1654 } else {
1655 __ Swr(value_lo, TMP, 0);
1656 __ Swl(value_lo, TMP, 3);
1657 __ Swr(value_hi, TMP, 4);
1658 __ Swl(value_hi, TMP, 7);
1659 }
1660 }
1661
1662 if (is_volatile) {
1663 __ Sync(0);
1664 }
1665
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001666 if (type == DataType::Type::kReference) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01001667 bool value_can_be_null = true; // TODO: Worth finding out this information?
1668 codegen->MarkGCCard(base, locations->InAt(3).AsRegister<Register>(), value_can_be_null);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001669 }
1670}
1671
1672// void sun.misc.Unsafe.putInt(Object o, long offset, int x)
1673void IntrinsicLocationsBuilderMIPS::VisitUnsafePut(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001674 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001675}
1676
1677void IntrinsicCodeGeneratorMIPS::VisitUnsafePut(HInvoke* invoke) {
1678 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001679 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001680 /* is_volatile */ false,
1681 /* is_ordered */ false,
1682 IsR6(),
1683 codegen_);
1684}
1685
1686// void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
1687void IntrinsicLocationsBuilderMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001688 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001689}
1690
1691void IntrinsicCodeGeneratorMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
1692 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001693 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001694 /* is_volatile */ false,
1695 /* is_ordered */ true,
1696 IsR6(),
1697 codegen_);
1698}
1699
1700// void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
1701void IntrinsicLocationsBuilderMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001702 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001703}
1704
1705void IntrinsicCodeGeneratorMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
1706 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001707 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001708 /* is_volatile */ true,
1709 /* is_ordered */ false,
1710 IsR6(),
1711 codegen_);
1712}
1713
1714// void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
1715void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObject(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001716 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001717}
1718
1719void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObject(HInvoke* invoke) {
1720 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001721 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001722 /* is_volatile */ false,
1723 /* is_ordered */ false,
1724 IsR6(),
1725 codegen_);
1726}
1727
1728// void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
1729void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001730 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001731}
1732
1733void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1734 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001735 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001736 /* is_volatile */ false,
1737 /* is_ordered */ true,
1738 IsR6(),
1739 codegen_);
1740}
1741
1742// void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
1743void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001744 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001745}
1746
1747void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1748 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001749 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001750 /* is_volatile */ true,
1751 /* is_ordered */ false,
1752 IsR6(),
1753 codegen_);
1754}
1755
1756// void sun.misc.Unsafe.putLong(Object o, long offset, long x)
1757void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001758 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001759}
1760
1761void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLong(HInvoke* invoke) {
1762 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001763 DataType::Type::kInt64,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001764 /* is_volatile */ false,
1765 /* is_ordered */ false,
1766 IsR6(),
1767 codegen_);
1768}
1769
1770// void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
1771void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001772 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001773}
1774
1775void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1776 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001777 DataType::Type::kInt64,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001778 /* is_volatile */ false,
1779 /* is_ordered */ true,
1780 IsR6(),
1781 codegen_);
1782}
1783
Vladimir Markoca6fff82017-10-03 14:49:14 +01001784static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* allocator, HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001785 bool can_call = kEmitCompilerReadBarrier &&
1786 kUseBakerReadBarrier &&
1787 (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001788 LocationSummary* locations =
1789 new (allocator) LocationSummary(invoke,
1790 can_call
1791 ? LocationSummary::kCallOnSlowPath
1792 : LocationSummary::kNoCall,
1793 kIntrinsified);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001794 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1795 locations->SetInAt(1, Location::RequiresRegister());
1796 locations->SetInAt(2, Location::RequiresRegister());
1797 locations->SetInAt(3, Location::RequiresRegister());
1798 locations->SetInAt(4, Location::RequiresRegister());
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001799 locations->SetOut(Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08001800
1801 // Temporary register used in CAS by (Baker) read barrier.
1802 if (can_call) {
1803 locations->AddTemp(Location::RequiresRegister());
1804 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001805}
1806
Alexey Frunze15958152017-02-09 19:08:30 -08001807// Note that the caller must supply a properly aligned memory address.
1808// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001809static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorMIPS* codegen) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001810 MipsAssembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001811 LocationSummary* locations = invoke->GetLocations();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001812 bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
1813 Register base = locations->InAt(1).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001814 Location offset_loc = locations->InAt(2);
1815 Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001816 Register expected = locations->InAt(3).AsRegister<Register>();
1817 Register value = locations->InAt(4).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001818 Location out_loc = locations->Out();
1819 Register out = out_loc.AsRegister<Register>();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001820
1821 DCHECK_NE(base, out);
1822 DCHECK_NE(offset_lo, out);
1823 DCHECK_NE(expected, out);
1824
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001825 if (type == DataType::Type::kReference) {
Alexey Frunze15958152017-02-09 19:08:30 -08001826 // The only read barrier implementation supporting the
1827 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1828 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1829
1830 // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
1831 // object and scan the receiver at the next GC for nothing.
Goran Jakovljevice114da22016-12-26 14:21:43 +01001832 bool value_can_be_null = true; // TODO: Worth finding out this information?
1833 codegen->MarkGCCard(base, value, value_can_be_null);
Alexey Frunze15958152017-02-09 19:08:30 -08001834
1835 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1836 Location temp = locations->GetTemp(0);
1837 // Need to make sure the reference stored in the field is a to-space
1838 // one before attempting the CAS or the CAS could fail incorrectly.
1839 codegen->GenerateReferenceLoadWithBakerReadBarrier(
1840 invoke,
1841 out_loc, // Unused, used only as a "temporary" within the read barrier.
1842 base,
1843 /* offset */ 0u,
1844 /* index */ offset_loc,
1845 ScaleFactor::TIMES_1,
1846 temp,
1847 /* needs_null_check */ false,
1848 /* always_update_field */ true);
1849 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001850 }
1851
Alexey Frunzec061de12017-02-14 13:27:23 -08001852 MipsLabel loop_head, exit_loop;
1853 __ Addu(TMP, base, offset_lo);
1854
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001855 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001856 __ PoisonHeapReference(expected);
1857 // Do not poison `value`, if it is the same register as
1858 // `expected`, which has just been poisoned.
1859 if (value != expected) {
1860 __ PoisonHeapReference(value);
1861 }
1862 }
1863
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001864 // do {
1865 // tmp_value = [tmp_ptr] - expected;
1866 // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
1867 // result = tmp_value != 0;
1868
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001869 __ Sync(0);
1870 __ Bind(&loop_head);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001871 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001872 if (isR6) {
1873 __ LlR6(out, TMP);
1874 } else {
1875 __ LlR2(out, TMP);
1876 }
1877 } else {
Alexey Frunzec061de12017-02-14 13:27:23 -08001878 LOG(FATAL) << "Unsupported op size " << type;
1879 UNREACHABLE();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001880 }
1881 __ Subu(out, out, expected); // If we didn't get the 'expected'
1882 __ Sltiu(out, out, 1); // value, set 'out' to false, and
1883 __ Beqz(out, &exit_loop); // return.
1884 __ Move(out, value); // Use 'out' for the 'store conditional' instruction.
1885 // If we use 'value' directly, we would lose 'value'
1886 // in the case that the store fails. Whether the
1887 // store succeeds, or fails, it will load the
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001888 // correct Boolean value into the 'out' register.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001889 // This test isn't really necessary. We only support DataType::Type::kInt,
1890 // DataType::Type::kReference, and we already verified that we're working on one
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001891 // of those two types. It's left here in case the code needs to support
1892 // other types in the future.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001893 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001894 if (isR6) {
1895 __ ScR6(out, TMP);
1896 } else {
1897 __ ScR2(out, TMP);
1898 }
1899 }
1900 __ Beqz(out, &loop_head); // If we couldn't do the read-modify-write
1901 // cycle atomically then retry.
1902 __ Bind(&exit_loop);
1903 __ Sync(0);
Alexey Frunzec061de12017-02-14 13:27:23 -08001904
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001905 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001906 __ UnpoisonHeapReference(expected);
1907 // Do not unpoison `value`, if it is the same register as
1908 // `expected`, which has just been unpoisoned.
1909 if (value != expected) {
1910 __ UnpoisonHeapReference(value);
1911 }
1912 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001913}
1914
1915// boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
1916void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001917 CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001918}
1919
1920void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001921 GenCas(invoke, DataType::Type::kInt32, codegen_);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001922}
1923
1924// boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
1925void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001926 // The only read barrier implementation supporting the
1927 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1928 if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
1929 return;
1930 }
1931
Vladimir Markoca6fff82017-10-03 14:49:14 +01001932 CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001933}
1934
1935void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001936 // The only read barrier implementation supporting the
1937 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1938 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1939
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001940 GenCas(invoke, DataType::Type::kReference, codegen_);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001941}
1942
Chris Larsencf283da2016-01-19 16:45:35 -08001943// int java.lang.String.compareTo(String anotherString)
1944void IntrinsicLocationsBuilderMIPS::VisitStringCompareTo(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001945 LocationSummary* locations = new (allocator_) LocationSummary(
1946 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001947 InvokeRuntimeCallingConvention calling_convention;
1948 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1949 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001950 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001951 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1952}
1953
1954void IntrinsicCodeGeneratorMIPS::VisitStringCompareTo(HInvoke* invoke) {
1955 MipsAssembler* assembler = GetAssembler();
1956 LocationSummary* locations = invoke->GetLocations();
1957
1958 // Note that the null check must have been done earlier.
1959 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1960
1961 Register argument = locations->InAt(1).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01001962 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001963 codegen_->AddSlowPath(slow_path);
1964 __ Beqz(argument, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01001965 codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08001966 __ Bind(slow_path->GetExitLabel());
1967}
1968
Chris Larsen16ba2b42015-11-02 10:58:31 -08001969// boolean java.lang.String.equals(Object anObject)
1970void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
Vladimir Markoda283052017-11-07 21:17:24 +00001971 if (kEmitCompilerReadBarrier &&
1972 !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
1973 !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
1974 // No support for this odd case (String class is moveable, not in the boot image).
1975 return;
1976 }
1977
Vladimir Markoca6fff82017-10-03 14:49:14 +01001978 LocationSummary* locations =
1979 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen16ba2b42015-11-02 10:58:31 -08001980 locations->SetInAt(0, Location::RequiresRegister());
1981 locations->SetInAt(1, Location::RequiresRegister());
1982 locations->SetOut(Location::RequiresRegister());
1983
1984 // Temporary registers to store lengths of strings and for calculations.
1985 locations->AddTemp(Location::RequiresRegister());
1986 locations->AddTemp(Location::RequiresRegister());
1987 locations->AddTemp(Location::RequiresRegister());
1988}
1989
1990void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) {
1991 MipsAssembler* assembler = GetAssembler();
1992 LocationSummary* locations = invoke->GetLocations();
1993
1994 Register str = locations->InAt(0).AsRegister<Register>();
1995 Register arg = locations->InAt(1).AsRegister<Register>();
1996 Register out = locations->Out().AsRegister<Register>();
1997
1998 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
1999 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2000 Register temp3 = locations->GetTemp(2).AsRegister<Register>();
2001
2002 MipsLabel loop;
2003 MipsLabel end;
2004 MipsLabel return_true;
2005 MipsLabel return_false;
2006
2007 // Get offsets of count, value, and class fields within a string object.
2008 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2009 const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
2010 const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
2011
2012 // Note that the null check must have been done earlier.
2013 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2014
2015 // If the register containing the pointer to "this", and the register
2016 // containing the pointer to "anObject" are the same register then
2017 // "this", and "anObject" are the same object and we can
2018 // short-circuit the logic to a true result.
2019 if (str == arg) {
2020 __ LoadConst32(out, 1);
2021 return;
2022 }
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01002023 StringEqualsOptimizations optimizations(invoke);
2024 if (!optimizations.GetArgumentNotNull()) {
2025 // Check if input is null, return false if it is.
2026 __ Beqz(arg, &return_false);
2027 }
Chris Larsen16ba2b42015-11-02 10:58:31 -08002028
2029 // Reference equality check, return true if same reference.
2030 __ Beq(str, arg, &return_true);
2031
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01002032 if (!optimizations.GetArgumentIsString()) {
2033 // Instanceof check for the argument by comparing class fields.
2034 // All string objects must have the same type since String cannot be subclassed.
2035 // Receiver must be a string object, so its class field is equal to all strings' class fields.
2036 // If the argument is a string object, its class field must be equal to receiver's class field.
2037 __ Lw(temp1, str, class_offset);
2038 __ Lw(temp2, arg, class_offset);
2039 __ Bne(temp1, temp2, &return_false);
2040 }
Chris Larsen16ba2b42015-11-02 10:58:31 -08002041
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002042 // Load `count` fields of this and argument strings.
Chris Larsen16ba2b42015-11-02 10:58:31 -08002043 __ Lw(temp1, str, count_offset);
2044 __ Lw(temp2, arg, count_offset);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002045 // Check if `count` fields are equal, return false if they're not.
2046 // Also compares the compression style, if differs return false.
Chris Larsen16ba2b42015-11-02 10:58:31 -08002047 __ Bne(temp1, temp2, &return_false);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002048 // Return true if both strings are empty. Even with string compression `count == 0` means empty.
2049 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2050 "Expecting 0=compressed, 1=uncompressed");
Chris Larsen16ba2b42015-11-02 10:58:31 -08002051 __ Beqz(temp1, &return_true);
2052
2053 // Don't overwrite input registers
2054 __ Move(TMP, str);
2055 __ Move(temp3, arg);
2056
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002057 // Assertions that must hold in order to compare strings 4 bytes at a time.
Chris Larsen16ba2b42015-11-02 10:58:31 -08002058 DCHECK_ALIGNED(value_offset, 4);
2059 static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
2060
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002061 // For string compression, calculate the number of bytes to compare (not chars).
2062 if (mirror::kUseStringCompression) {
2063 // Extract compression flag.
2064 if (IsR2OrNewer()) {
2065 __ Ext(temp2, temp1, 0, 1);
2066 } else {
2067 __ Sll(temp2, temp1, 31);
2068 __ Srl(temp2, temp2, 31);
2069 }
2070 __ Srl(temp1, temp1, 1); // Extract length.
2071 __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed.
2072 }
2073
2074 // Loop to compare strings 4 bytes at a time starting at the beginning of the string.
2075 // Ok to do this because strings are zero-padded to kObjectAlignment.
Chris Larsen16ba2b42015-11-02 10:58:31 -08002076 __ Bind(&loop);
2077 __ Lw(out, TMP, value_offset);
2078 __ Lw(temp2, temp3, value_offset);
2079 __ Bne(out, temp2, &return_false);
2080 __ Addiu(TMP, TMP, 4);
2081 __ Addiu(temp3, temp3, 4);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002082 // With string compression, we have compared 4 bytes, otherwise 2 chars.
2083 __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -4 : -2);
Chris Larsen16ba2b42015-11-02 10:58:31 -08002084 __ Bgtz(temp1, &loop);
2085
2086 // Return true and exit the function.
2087 // If loop does not result in returning false, we return true.
2088 __ Bind(&return_true);
2089 __ LoadConst32(out, 1);
2090 __ B(&end);
2091
2092 // Return false and exit the function.
2093 __ Bind(&return_false);
2094 __ LoadConst32(out, 0);
2095 __ Bind(&end);
2096}
2097
Chris Larsencf283da2016-01-19 16:45:35 -08002098static void GenerateStringIndexOf(HInvoke* invoke,
2099 bool start_at_zero,
2100 MipsAssembler* assembler,
Vladimir Marko174b2e22017-10-12 13:34:49 +01002101 CodeGeneratorMIPS* codegen) {
Chris Larsencf283da2016-01-19 16:45:35 -08002102 LocationSummary* locations = invoke->GetLocations();
2103 Register tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<Register>() : TMP;
2104
2105 // Note that the null check must have been done earlier.
2106 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2107
Vladimir Markofb6c90a2016-05-06 15:52:12 +01002108 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
2109 // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
Chris Larsencf283da2016-01-19 16:45:35 -08002110 SlowPathCodeMIPS* slow_path = nullptr;
Vladimir Markofb6c90a2016-05-06 15:52:12 +01002111 HInstruction* code_point = invoke->InputAt(1);
2112 if (code_point->IsIntConstant()) {
Vladimir Markoda051082016-05-17 16:10:20 +01002113 if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
Chris Larsencf283da2016-01-19 16:45:35 -08002114 // Always needs the slow-path. We could directly dispatch to it,
2115 // but this case should be rare, so for simplicity just put the
2116 // full slow-path down and branch unconditionally.
Vladimir Marko174b2e22017-10-12 13:34:49 +01002117 slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08002118 codegen->AddSlowPath(slow_path);
2119 __ B(slow_path->GetEntryLabel());
2120 __ Bind(slow_path->GetExitLabel());
2121 return;
2122 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002123 } else if (code_point->GetType() != DataType::Type::kUint16) {
Chris Larsencf283da2016-01-19 16:45:35 -08002124 Register char_reg = locations->InAt(1).AsRegister<Register>();
2125 // The "bltu" conditional branch tests to see if the character value
2126 // fits in a valid 16-bit (MIPS halfword) value. If it doesn't then
2127 // the character being searched for, if it exists in the string, is
2128 // encoded using UTF-16 and stored in the string as two (16-bit)
2129 // halfwords. Currently the assembly code used to implement this
2130 // intrinsic doesn't support searching for a character stored as
2131 // two halfwords so we fallback to using the generic implementation
2132 // of indexOf().
2133 __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
Vladimir Marko174b2e22017-10-12 13:34:49 +01002134 slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08002135 codegen->AddSlowPath(slow_path);
2136 __ Bltu(tmp_reg, char_reg, slow_path->GetEntryLabel());
2137 }
2138
2139 if (start_at_zero) {
2140 DCHECK_EQ(tmp_reg, A2);
2141 // Start-index = 0.
2142 __ Clear(tmp_reg);
2143 }
2144
Serban Constantinescufca16662016-07-14 09:21:59 +01002145 codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08002146 if (slow_path != nullptr) {
2147 __ Bind(slow_path->GetExitLabel());
2148 }
2149}
2150
2151// int java.lang.String.indexOf(int ch)
2152void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002153 LocationSummary* locations = new (allocator_) LocationSummary(
2154 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08002155 // We have a hand-crafted assembly stub that follows the runtime
2156 // calling convention. So it's best to align the inputs accordingly.
2157 InvokeRuntimeCallingConvention calling_convention;
2158 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2159 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002160 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08002161 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2162
2163 // Need a temp for slow-path codepoint compare, and need to send start-index=0.
2164 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2165}
2166
2167void IntrinsicCodeGeneratorMIPS::VisitStringIndexOf(HInvoke* invoke) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01002168 GenerateStringIndexOf(invoke, /* start_at_zero */ true, GetAssembler(), codegen_);
Chris Larsencf283da2016-01-19 16:45:35 -08002169}
2170
2171// int java.lang.String.indexOf(int ch, int fromIndex)
2172void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002173 LocationSummary* locations = new (allocator_) LocationSummary(
2174 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08002175 // We have a hand-crafted assembly stub that follows the runtime
2176 // calling convention. So it's best to align the inputs accordingly.
2177 InvokeRuntimeCallingConvention calling_convention;
2178 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2179 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2180 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002181 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08002182 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2183
2184 // Need a temp for slow-path codepoint compare.
2185 locations->AddTemp(Location::RequiresRegister());
2186}
2187
2188void IntrinsicCodeGeneratorMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01002189 GenerateStringIndexOf(invoke, /* start_at_zero */ false, GetAssembler(), codegen_);
Chris Larsencf283da2016-01-19 16:45:35 -08002190}
2191
2192// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
2193void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002194 LocationSummary* locations = new (allocator_) LocationSummary(
2195 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08002196 InvokeRuntimeCallingConvention calling_convention;
2197 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2198 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2199 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2200 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002201 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08002202 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2203}
2204
2205void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
2206 MipsAssembler* assembler = GetAssembler();
2207 LocationSummary* locations = invoke->GetLocations();
2208
2209 Register byte_array = locations->InAt(0).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01002210 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08002211 codegen_->AddSlowPath(slow_path);
2212 __ Beqz(byte_array, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01002213 codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08002214 __ Bind(slow_path->GetExitLabel());
2215}
2216
2217// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
2218void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002219 LocationSummary* locations =
2220 new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08002221 InvokeRuntimeCallingConvention calling_convention;
2222 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2223 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2224 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002225 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08002226 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2227}
2228
2229void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
Chris Larsencf283da2016-01-19 16:45:35 -08002230 // No need to emit code checking whether `locations->InAt(2)` is a null
2231 // pointer, as callers of the native method
2232 //
2233 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
2234 //
2235 // all include a null check on `data` before calling that method.
Serban Constantinescufca16662016-07-14 09:21:59 +01002236 codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
Chris Larsencf283da2016-01-19 16:45:35 -08002237}
2238
2239// java.lang.StringFactory.newStringFromString(String toCopy)
2240void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002241 LocationSummary* locations = new (allocator_) LocationSummary(
2242 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08002243 InvokeRuntimeCallingConvention calling_convention;
2244 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002245 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08002246 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2247}
2248
2249void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
2250 MipsAssembler* assembler = GetAssembler();
2251 LocationSummary* locations = invoke->GetLocations();
2252
2253 Register string_to_copy = locations->InAt(0).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01002254 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08002255 codegen_->AddSlowPath(slow_path);
2256 __ Beqz(string_to_copy, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01002257 codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc());
Chris Larsencf283da2016-01-19 16:45:35 -08002258 __ Bind(slow_path->GetExitLabel());
2259}
2260
Chris Larsen2714fe62016-02-11 14:23:53 -08002261static void GenIsInfinite(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002262 const DataType::Type type,
Chris Larsen2714fe62016-02-11 14:23:53 -08002263 const bool isR6,
2264 MipsAssembler* assembler) {
2265 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2266 Register out = locations->Out().AsRegister<Register>();
2267
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002268 DCHECK(type == DataType::Type::kFloat32 || type == DataType::Type::kFloat64);
Chris Larsen2714fe62016-02-11 14:23:53 -08002269
2270 if (isR6) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002271 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08002272 __ ClassD(FTMP, in);
2273 } else {
2274 __ ClassS(FTMP, in);
2275 }
2276 __ Mfc1(out, FTMP);
2277 __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
2278 __ Sltu(out, ZERO, out);
2279 } else {
2280 // If one, or more, of the exponent bits is zero, then the number can't be infinite.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002281 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08002282 __ MoveFromFpuHigh(TMP, in);
Anton Kirilova3ffea22016-04-07 17:02:37 +01002283 __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble));
Chris Larsen2714fe62016-02-11 14:23:53 -08002284 } else {
2285 __ Mfc1(TMP, in);
Anton Kirilova3ffea22016-04-07 17:02:37 +01002286 __ LoadConst32(AT, kPositiveInfinityFloat);
Chris Larsen2714fe62016-02-11 14:23:53 -08002287 }
2288 __ Xor(TMP, TMP, AT);
2289
2290 __ Sll(TMP, TMP, 1);
2291
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002292 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08002293 __ Mfc1(AT, in);
2294 __ Or(TMP, TMP, AT);
2295 }
2296 // If any of the significand bits are one, then the number is not infinite.
2297 __ Sltiu(out, TMP, 1);
2298 }
2299}
2300
2301// boolean java.lang.Float.isInfinite(float)
2302void IntrinsicLocationsBuilderMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002303 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen2714fe62016-02-11 14:23:53 -08002304}
2305
2306void IntrinsicCodeGeneratorMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002307 GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat32, IsR6(), GetAssembler());
Chris Larsen2714fe62016-02-11 14:23:53 -08002308}
2309
2310// boolean java.lang.Double.isInfinite(double)
2311void IntrinsicLocationsBuilderMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002312 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen2714fe62016-02-11 14:23:53 -08002313}
2314
2315void IntrinsicCodeGeneratorMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002316 GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat64, IsR6(), GetAssembler());
Chris Larsen2714fe62016-02-11 14:23:53 -08002317}
2318
Chris Larsen97759342016-02-16 17:10:40 -08002319static void GenHighestOneBit(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002320 const DataType::Type type,
Chris Larsen97759342016-02-16 17:10:40 -08002321 bool isR6,
2322 MipsAssembler* assembler) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002323 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
Chris Larsen97759342016-02-16 17:10:40 -08002324
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002325 if (type == DataType::Type::kInt64) {
Chris Larsen97759342016-02-16 17:10:40 -08002326 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
2327 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
2328 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
2329 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
2330
2331 if (isR6) {
2332 __ ClzR6(TMP, in_hi);
2333 } else {
2334 __ ClzR2(TMP, in_hi);
2335 }
2336 __ LoadConst32(AT, 0x80000000);
2337 __ Srlv(out_hi, AT, TMP);
2338 __ And(out_hi, out_hi, in_hi);
2339 if (isR6) {
2340 __ ClzR6(TMP, in_lo);
2341 } else {
2342 __ ClzR2(TMP, in_lo);
2343 }
2344 __ Srlv(out_lo, AT, TMP);
2345 __ And(out_lo, out_lo, in_lo);
2346 if (isR6) {
2347 __ Seleqz(out_lo, out_lo, out_hi);
2348 } else {
2349 __ Movn(out_lo, ZERO, out_hi);
2350 }
2351 } else {
2352 Register in = locations->InAt(0).AsRegister<Register>();
2353 Register out = locations->Out().AsRegister<Register>();
2354
2355 if (isR6) {
2356 __ ClzR6(TMP, in);
2357 } else {
2358 __ ClzR2(TMP, in);
2359 }
2360 __ LoadConst32(AT, 0x80000000);
2361 __ Srlv(AT, AT, TMP); // Srlv shifts in the range of [0;31] bits (lower 5 bits of arg).
2362 __ And(out, AT, in); // So this is required for 0 (=shift by 32).
2363 }
2364}
2365
2366// int java.lang.Integer.highestOneBit(int)
2367void IntrinsicLocationsBuilderMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002368 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08002369}
2370
2371void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002372 GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08002373}
2374
2375// long java.lang.Long.highestOneBit(long)
2376void IntrinsicLocationsBuilderMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002377 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen97759342016-02-16 17:10:40 -08002378}
2379
2380void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002381 GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08002382}
2383
2384static void GenLowestOneBit(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002385 const DataType::Type type,
Chris Larsen97759342016-02-16 17:10:40 -08002386 bool isR6,
2387 MipsAssembler* assembler) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002388 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
Chris Larsen97759342016-02-16 17:10:40 -08002389
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002390 if (type == DataType::Type::kInt64) {
Chris Larsen97759342016-02-16 17:10:40 -08002391 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
2392 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
2393 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
2394 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
2395
2396 __ Subu(TMP, ZERO, in_lo);
2397 __ And(out_lo, TMP, in_lo);
2398 __ Subu(TMP, ZERO, in_hi);
2399 __ And(out_hi, TMP, in_hi);
2400 if (isR6) {
2401 __ Seleqz(out_hi, out_hi, out_lo);
2402 } else {
2403 __ Movn(out_hi, ZERO, out_lo);
2404 }
2405 } else {
2406 Register in = locations->InAt(0).AsRegister<Register>();
2407 Register out = locations->Out().AsRegister<Register>();
2408
2409 __ Subu(TMP, ZERO, in);
2410 __ And(out, TMP, in);
2411 }
2412}
2413
2414// int java.lang.Integer.lowestOneBit(int)
2415void IntrinsicLocationsBuilderMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002416 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08002417}
2418
2419void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002420 GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08002421}
2422
2423// long java.lang.Long.lowestOneBit(long)
2424void IntrinsicLocationsBuilderMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002425 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08002426}
2427
2428void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002429 GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08002430}
2431
Chris Larsenf09d5322016-04-22 12:06:34 -07002432// int java.lang.Math.round(float)
2433void IntrinsicLocationsBuilderMIPS::VisitMathRoundFloat(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002434 LocationSummary* locations =
2435 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenf09d5322016-04-22 12:06:34 -07002436 locations->SetInAt(0, Location::RequiresFpuRegister());
2437 locations->AddTemp(Location::RequiresFpuRegister());
2438 locations->SetOut(Location::RequiresRegister());
2439}
2440
2441void IntrinsicCodeGeneratorMIPS::VisitMathRoundFloat(HInvoke* invoke) {
2442 LocationSummary* locations = invoke->GetLocations();
2443 MipsAssembler* assembler = GetAssembler();
2444 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2445 FRegister half = locations->GetTemp(0).AsFpuRegister<FRegister>();
2446 Register out = locations->Out().AsRegister<Register>();
2447
2448 MipsLabel done;
Chris Larsenf09d5322016-04-22 12:06:34 -07002449
Chris Larsenf09d5322016-04-22 12:06:34 -07002450 if (IsR6()) {
Lena Djokicf4e23a82017-05-09 15:43:45 +02002451 // out = floor(in);
2452 //
2453 // if (out != MAX_VALUE && out != MIN_VALUE) {
2454 // TMP = ((in - out) >= 0.5) ? 1 : 0;
2455 // return out += TMP;
2456 // }
2457 // return out;
Chris Larsenf09d5322016-04-22 12:06:34 -07002458
Lena Djokicf4e23a82017-05-09 15:43:45 +02002459 // out = floor(in);
2460 __ FloorWS(FTMP, in);
2461 __ Mfc1(out, FTMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002462
Lena Djokicf4e23a82017-05-09 15:43:45 +02002463 // if (out != MAX_VALUE && out != MIN_VALUE)
2464 __ Addiu(TMP, out, 1);
2465 __ Aui(TMP, TMP, 0x8000); // TMP = out + 0x8000 0001
2466 // or out - 0x7FFF FFFF.
2467 // IOW, TMP = 1 if out = Int.MIN_VALUE
2468 // or TMP = 0 if out = Int.MAX_VALUE.
2469 __ Srl(TMP, TMP, 1); // TMP = 0 if out = Int.MIN_VALUE
2470 // or out = Int.MAX_VALUE.
2471 __ Beqz(TMP, &done);
Chris Larsenf09d5322016-04-22 12:06:34 -07002472
Lena Djokicf4e23a82017-05-09 15:43:45 +02002473 // TMP = (0.5f <= (in - out)) ? -1 : 0;
2474 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
2475 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
2476 __ SubS(FTMP, in, FTMP);
2477 __ Mtc1(AT, half);
Chris Larsenf09d5322016-04-22 12:06:34 -07002478
Chris Larsenf09d5322016-04-22 12:06:34 -07002479 __ CmpLeS(FTMP, half, FTMP);
Chris Larsen07f712f2016-06-10 16:06:02 -07002480 __ Mfc1(TMP, FTMP);
Lena Djokicf4e23a82017-05-09 15:43:45 +02002481
2482 // Return out -= TMP.
2483 __ Subu(out, out, TMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002484 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +02002485 // if (in.isNaN) {
2486 // return 0;
2487 // }
2488 //
2489 // out = floor.w.s(in);
2490 //
2491 // /*
2492 // * This "if" statement is only needed for the pre-R6 version of floor.w.s
2493 // * which outputs Integer.MAX_VALUE for negative numbers with magnitudes
2494 // * too large to fit in a 32-bit integer.
2495 // */
2496 // if (out == Integer.MAX_VALUE) {
2497 // TMP = (in < 0.0f) ? 1 : 0;
2498 // /*
2499 // * If TMP is 1, then adding it to out will wrap its value from
2500 // * Integer.MAX_VALUE to Integer.MIN_VALUE.
2501 // */
2502 // return out += TMP;
2503 // }
2504 //
2505 // /*
2506 // * For negative values not handled by the previous "if" statement the
2507 // * test here will correctly set the value of TMP.
2508 // */
2509 // TMP = ((in - out) >= 0.5f) ? 1 : 0;
2510 // return out += TMP;
2511
2512 MipsLabel finite;
2513 MipsLabel add;
2514
2515 // Test for NaN.
2516 __ CunS(in, in);
2517
2518 // Return zero for NaN.
2519 __ Move(out, ZERO);
2520 __ Bc1t(&done);
2521
2522 // out = floor(in);
2523 __ FloorWS(FTMP, in);
2524 __ Mfc1(out, FTMP);
2525
2526 __ LoadConst32(TMP, -1);
2527
2528 // TMP = (out = java.lang.Integer.MAX_VALUE) ? -1 : 0;
2529 __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
2530 __ Bne(AT, out, &finite);
2531
2532 __ Mtc1(ZERO, FTMP);
2533 __ ColtS(in, FTMP);
2534
2535 __ B(&add);
2536
2537 __ Bind(&finite);
2538
2539 // TMP = (0.5f <= (in - out)) ? -1 : 0;
2540 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
2541 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
2542 __ SubS(FTMP, in, FTMP);
2543 __ Mtc1(AT, half);
Chris Larsenf09d5322016-04-22 12:06:34 -07002544 __ ColeS(half, FTMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002545
Lena Djokicf4e23a82017-05-09 15:43:45 +02002546 __ Bind(&add);
Chris Larsenf09d5322016-04-22 12:06:34 -07002547
Chris Larsenf09d5322016-04-22 12:06:34 -07002548 __ Movf(TMP, ZERO);
Lena Djokicf4e23a82017-05-09 15:43:45 +02002549
2550 // Return out -= TMP.
2551 __ Subu(out, out, TMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002552 }
Chris Larsenf09d5322016-04-22 12:06:34 -07002553 __ Bind(&done);
2554}
2555
Chris Larsen692235e2016-11-21 16:04:53 -08002556// void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
2557void IntrinsicLocationsBuilderMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002558 LocationSummary* locations =
2559 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen692235e2016-11-21 16:04:53 -08002560 locations->SetInAt(0, Location::RequiresRegister());
2561 locations->SetInAt(1, Location::RequiresRegister());
2562 locations->SetInAt(2, Location::RequiresRegister());
2563 locations->SetInAt(3, Location::RequiresRegister());
2564 locations->SetInAt(4, Location::RequiresRegister());
2565
Chris Larsenfe4ff442017-03-23 11:25:12 -07002566 locations->AddTemp(Location::RequiresRegister());
2567 locations->AddTemp(Location::RequiresRegister());
2568 locations->AddTemp(Location::RequiresRegister());
Chris Larsen692235e2016-11-21 16:04:53 -08002569}
2570
2571void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2572 MipsAssembler* assembler = GetAssembler();
2573 LocationSummary* locations = invoke->GetLocations();
2574
2575 // Check assumption that sizeof(Char) is 2 (used in scaling below).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002576 const size_t char_size = DataType::Size(DataType::Type::kUint16);
Chris Larsen692235e2016-11-21 16:04:53 -08002577 DCHECK_EQ(char_size, 2u);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002578 const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
Chris Larsen692235e2016-11-21 16:04:53 -08002579
2580 Register srcObj = locations->InAt(0).AsRegister<Register>();
2581 Register srcBegin = locations->InAt(1).AsRegister<Register>();
2582 Register srcEnd = locations->InAt(2).AsRegister<Register>();
2583 Register dstObj = locations->InAt(3).AsRegister<Register>();
2584 Register dstBegin = locations->InAt(4).AsRegister<Register>();
2585
2586 Register dstPtr = locations->GetTemp(0).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002587 Register srcPtr = locations->GetTemp(1).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002588 Register numChrs = locations->GetTemp(2).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002589
2590 MipsLabel done;
Chris Larsenfe4ff442017-03-23 11:25:12 -07002591 MipsLabel loop;
Chris Larsen692235e2016-11-21 16:04:53 -08002592
2593 // Location of data in char array buffer.
2594 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2595
2596 // Get offset of value field within a string object.
2597 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2598
2599 __ Beq(srcEnd, srcBegin, &done); // No characters to move.
2600
2601 // Calculate number of characters to be copied.
2602 __ Subu(numChrs, srcEnd, srcBegin);
2603
2604 // Calculate destination address.
2605 __ Addiu(dstPtr, dstObj, data_offset);
Chris Larsencd0295d2017-03-31 15:26:54 -07002606 __ ShiftAndAdd(dstPtr, dstBegin, dstPtr, char_shift);
Chris Larsen692235e2016-11-21 16:04:53 -08002607
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002608 if (mirror::kUseStringCompression) {
2609 MipsLabel uncompressed_copy, compressed_loop;
2610 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2611 // Load count field and extract compression flag.
2612 __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
2613 __ Sll(TMP, TMP, 31);
2614
Chris Larsenfe4ff442017-03-23 11:25:12 -07002615 // If string is uncompressed, use uncompressed path.
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002616 __ Bnez(TMP, &uncompressed_copy);
2617
2618 // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
2619 __ Addu(srcPtr, srcObj, srcBegin);
2620 __ Bind(&compressed_loop);
2621 __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
2622 __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
2623 __ Addiu(numChrs, numChrs, -1);
2624 __ Addiu(srcPtr, srcPtr, 1);
2625 __ Addiu(dstPtr, dstPtr, 2);
2626 __ Bnez(numChrs, &compressed_loop);
2627
2628 __ B(&done);
2629 __ Bind(&uncompressed_copy);
2630 }
2631
Chris Larsen692235e2016-11-21 16:04:53 -08002632 // Calculate source address.
2633 __ Addiu(srcPtr, srcObj, value_offset);
Chris Larsencd0295d2017-03-31 15:26:54 -07002634 __ ShiftAndAdd(srcPtr, srcBegin, srcPtr, char_shift);
Chris Larsen692235e2016-11-21 16:04:53 -08002635
Chris Larsenfe4ff442017-03-23 11:25:12 -07002636 __ Bind(&loop);
2637 __ Lh(AT, srcPtr, 0);
2638 __ Addiu(numChrs, numChrs, -1);
2639 __ Addiu(srcPtr, srcPtr, char_size);
2640 __ Sh(AT, dstPtr, 0);
2641 __ Addiu(dstPtr, dstPtr, char_size);
2642 __ Bnez(numChrs, &loop);
Chris Larsen692235e2016-11-21 16:04:53 -08002643
2644 __ Bind(&done);
2645}
2646
Vladimir Markoca6fff82017-10-03 14:49:14 +01002647static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2648 LocationSummary* locations =
2649 new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002650 InvokeRuntimeCallingConvention calling_convention;
2651
2652 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002653 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
Chris Larsenb9005fa2017-03-24 12:11:54 -07002654}
2655
Vladimir Markoca6fff82017-10-03 14:49:14 +01002656static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2657 LocationSummary* locations =
2658 new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002659 InvokeRuntimeCallingConvention calling_convention;
2660
2661 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2662 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002663 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
Chris Larsenb9005fa2017-03-24 12:11:54 -07002664}
2665
2666static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
2667 LocationSummary* locations = invoke->GetLocations();
2668 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2669 DCHECK_EQ(in, F12);
2670 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2671 DCHECK_EQ(out, F0);
2672
2673 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2674}
2675
2676static void GenFPFPToFPCall(HInvoke* invoke,
2677 CodeGeneratorMIPS* codegen,
2678 QuickEntrypointEnum entry) {
2679 LocationSummary* locations = invoke->GetLocations();
2680 FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
2681 DCHECK_EQ(in0, F12);
2682 FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
2683 DCHECK_EQ(in1, F14);
2684 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2685 DCHECK_EQ(out, F0);
2686
2687 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2688}
2689
2690// static double java.lang.Math.cos(double a)
2691void IntrinsicLocationsBuilderMIPS::VisitMathCos(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002692 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002693}
2694
2695void IntrinsicCodeGeneratorMIPS::VisitMathCos(HInvoke* invoke) {
2696 GenFPToFPCall(invoke, codegen_, kQuickCos);
2697}
2698
2699// static double java.lang.Math.sin(double a)
2700void IntrinsicLocationsBuilderMIPS::VisitMathSin(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002701 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002702}
2703
2704void IntrinsicCodeGeneratorMIPS::VisitMathSin(HInvoke* invoke) {
2705 GenFPToFPCall(invoke, codegen_, kQuickSin);
2706}
2707
2708// static double java.lang.Math.acos(double a)
2709void IntrinsicLocationsBuilderMIPS::VisitMathAcos(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002710 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002711}
2712
2713void IntrinsicCodeGeneratorMIPS::VisitMathAcos(HInvoke* invoke) {
2714 GenFPToFPCall(invoke, codegen_, kQuickAcos);
2715}
2716
2717// static double java.lang.Math.asin(double a)
2718void IntrinsicLocationsBuilderMIPS::VisitMathAsin(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002719 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002720}
2721
2722void IntrinsicCodeGeneratorMIPS::VisitMathAsin(HInvoke* invoke) {
2723 GenFPToFPCall(invoke, codegen_, kQuickAsin);
2724}
2725
2726// static double java.lang.Math.atan(double a)
2727void IntrinsicLocationsBuilderMIPS::VisitMathAtan(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002728 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002729}
2730
2731void IntrinsicCodeGeneratorMIPS::VisitMathAtan(HInvoke* invoke) {
2732 GenFPToFPCall(invoke, codegen_, kQuickAtan);
2733}
2734
2735// static double java.lang.Math.atan2(double y, double x)
2736void IntrinsicLocationsBuilderMIPS::VisitMathAtan2(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002737 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002738}
2739
2740void IntrinsicCodeGeneratorMIPS::VisitMathAtan2(HInvoke* invoke) {
2741 GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
2742}
2743
Vladimir Marko4d179872018-01-19 14:50:10 +00002744// static double java.lang.Math.pow(double y, double x)
2745void IntrinsicLocationsBuilderMIPS::VisitMathPow(HInvoke* invoke) {
2746 CreateFPFPToFPCallLocations(allocator_, invoke);
2747}
2748
2749void IntrinsicCodeGeneratorMIPS::VisitMathPow(HInvoke* invoke) {
2750 GenFPFPToFPCall(invoke, codegen_, kQuickPow);
2751}
2752
Chris Larsenb9005fa2017-03-24 12:11:54 -07002753// static double java.lang.Math.cbrt(double a)
2754void IntrinsicLocationsBuilderMIPS::VisitMathCbrt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002755 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002756}
2757
2758void IntrinsicCodeGeneratorMIPS::VisitMathCbrt(HInvoke* invoke) {
2759 GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2760}
2761
2762// static double java.lang.Math.cosh(double x)
2763void IntrinsicLocationsBuilderMIPS::VisitMathCosh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002764 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002765}
2766
2767void IntrinsicCodeGeneratorMIPS::VisitMathCosh(HInvoke* invoke) {
2768 GenFPToFPCall(invoke, codegen_, kQuickCosh);
2769}
2770
2771// static double java.lang.Math.exp(double a)
2772void IntrinsicLocationsBuilderMIPS::VisitMathExp(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002773 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002774}
2775
2776void IntrinsicCodeGeneratorMIPS::VisitMathExp(HInvoke* invoke) {
2777 GenFPToFPCall(invoke, codegen_, kQuickExp);
2778}
2779
2780// static double java.lang.Math.expm1(double x)
2781void IntrinsicLocationsBuilderMIPS::VisitMathExpm1(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002782 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002783}
2784
2785void IntrinsicCodeGeneratorMIPS::VisitMathExpm1(HInvoke* invoke) {
2786 GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2787}
2788
2789// static double java.lang.Math.hypot(double x, double y)
2790void IntrinsicLocationsBuilderMIPS::VisitMathHypot(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002791 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002792}
2793
2794void IntrinsicCodeGeneratorMIPS::VisitMathHypot(HInvoke* invoke) {
2795 GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
2796}
2797
2798// static double java.lang.Math.log(double a)
2799void IntrinsicLocationsBuilderMIPS::VisitMathLog(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002800 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002801}
2802
2803void IntrinsicCodeGeneratorMIPS::VisitMathLog(HInvoke* invoke) {
2804 GenFPToFPCall(invoke, codegen_, kQuickLog);
2805}
2806
2807// static double java.lang.Math.log10(double x)
2808void IntrinsicLocationsBuilderMIPS::VisitMathLog10(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002809 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002810}
2811
2812void IntrinsicCodeGeneratorMIPS::VisitMathLog10(HInvoke* invoke) {
2813 GenFPToFPCall(invoke, codegen_, kQuickLog10);
2814}
2815
2816// static double java.lang.Math.nextAfter(double start, double direction)
2817void IntrinsicLocationsBuilderMIPS::VisitMathNextAfter(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002818 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002819}
2820
2821void IntrinsicCodeGeneratorMIPS::VisitMathNextAfter(HInvoke* invoke) {
2822 GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
2823}
2824
2825// static double java.lang.Math.sinh(double x)
2826void IntrinsicLocationsBuilderMIPS::VisitMathSinh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002827 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002828}
2829
2830void IntrinsicCodeGeneratorMIPS::VisitMathSinh(HInvoke* invoke) {
2831 GenFPToFPCall(invoke, codegen_, kQuickSinh);
2832}
2833
2834// static double java.lang.Math.tan(double a)
2835void IntrinsicLocationsBuilderMIPS::VisitMathTan(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002836 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002837}
2838
2839void IntrinsicCodeGeneratorMIPS::VisitMathTan(HInvoke* invoke) {
2840 GenFPToFPCall(invoke, codegen_, kQuickTan);
2841}
2842
2843// static double java.lang.Math.tanh(double x)
2844void IntrinsicLocationsBuilderMIPS::VisitMathTanh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002845 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002846}
2847
2848void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
2849 GenFPToFPCall(invoke, codegen_, kQuickTanh);
2850}
2851
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002852// static void java.lang.System.arraycopy(Object src, int srcPos,
2853// Object dest, int destPos,
2854// int length)
2855void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
2856 HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
2857 HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
2858 HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
2859
2860 // As long as we are checking, we might as well check to see if the src and dest
2861 // positions are >= 0.
2862 if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2863 (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
2864 // We will have to fail anyways.
2865 return;
2866 }
2867
2868 // And since we are already checking, check the length too.
2869 if (length != nullptr) {
2870 int32_t len = length->GetValue();
2871 if (len < 0) {
2872 // Just call as normal.
2873 return;
2874 }
2875 }
2876
2877 // Okay, it is safe to generate inline code.
2878 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002879 new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002880 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
2881 locations->SetInAt(0, Location::RequiresRegister());
2882 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
2883 locations->SetInAt(2, Location::RequiresRegister());
2884 locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
2885 locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
2886
2887 locations->AddTemp(Location::RequiresRegister());
2888 locations->AddTemp(Location::RequiresRegister());
2889 locations->AddTemp(Location::RequiresRegister());
2890}
2891
2892// Utility routine to verify that "length(input) - pos >= length"
2893static void EnoughItems(MipsAssembler* assembler,
2894 Register length_input_minus_pos,
2895 Location length,
2896 SlowPathCodeMIPS* slow_path) {
2897 if (length.IsConstant()) {
2898 int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
2899
2900 if (IsInt<16>(length_constant)) {
2901 __ Slti(TMP, length_input_minus_pos, length_constant);
2902 __ Bnez(TMP, slow_path->GetEntryLabel());
2903 } else {
2904 __ LoadConst32(TMP, length_constant);
2905 __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
2906 }
2907 } else {
2908 __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
2909 }
2910}
2911
2912static void CheckPosition(MipsAssembler* assembler,
2913 Location pos,
2914 Register input,
2915 Location length,
2916 SlowPathCodeMIPS* slow_path,
2917 bool length_is_input_length = false) {
2918 // Where is the length in the Array?
2919 const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
2920
2921 // Calculate length(input) - pos.
2922 if (pos.IsConstant()) {
2923 int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
2924 if (pos_const == 0) {
2925 if (!length_is_input_length) {
2926 // Check that length(input) >= length.
2927 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2928 EnoughItems(assembler, AT, length, slow_path);
2929 }
2930 } else {
2931 // Check that (length(input) - pos) >= zero.
2932 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2933 DCHECK_GT(pos_const, 0);
2934 __ Addiu32(AT, AT, -pos_const, TMP);
2935 __ Bltz(AT, slow_path->GetEntryLabel());
2936
2937 // Verify that (length(input) - pos) >= length.
2938 EnoughItems(assembler, AT, length, slow_path);
2939 }
2940 } else if (length_is_input_length) {
2941 // The only way the copy can succeed is if pos is zero.
2942 Register pos_reg = pos.AsRegister<Register>();
2943 __ Bnez(pos_reg, slow_path->GetEntryLabel());
2944 } else {
2945 // Verify that pos >= 0.
2946 Register pos_reg = pos.AsRegister<Register>();
2947 __ Bltz(pos_reg, slow_path->GetEntryLabel());
2948
2949 // Check that (length(input) - pos) >= zero.
2950 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2951 __ Subu(AT, AT, pos_reg);
2952 __ Bltz(AT, slow_path->GetEntryLabel());
2953
2954 // Verify that (length(input) - pos) >= length.
2955 EnoughItems(assembler, AT, length, slow_path);
2956 }
2957}
2958
2959void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
2960 MipsAssembler* assembler = GetAssembler();
2961 LocationSummary* locations = invoke->GetLocations();
2962
2963 Register src = locations->InAt(0).AsRegister<Register>();
2964 Location src_pos = locations->InAt(1);
2965 Register dest = locations->InAt(2).AsRegister<Register>();
2966 Location dest_pos = locations->InAt(3);
2967 Location length = locations->InAt(4);
2968
2969 MipsLabel loop;
2970
2971 Register dest_base = locations->GetTemp(0).AsRegister<Register>();
2972 Register src_base = locations->GetTemp(1).AsRegister<Register>();
2973 Register count = locations->GetTemp(2).AsRegister<Register>();
2974
Vladimir Marko174b2e22017-10-12 13:34:49 +01002975 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002976 codegen_->AddSlowPath(slow_path);
2977
2978 // Bail out if the source and destination are the same (to handle overlap).
2979 __ Beq(src, dest, slow_path->GetEntryLabel());
2980
2981 // Bail out if the source is null.
2982 __ Beqz(src, slow_path->GetEntryLabel());
2983
2984 // Bail out if the destination is null.
2985 __ Beqz(dest, slow_path->GetEntryLabel());
2986
2987 // Load length into register for count.
2988 if (length.IsConstant()) {
2989 __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
2990 } else {
2991 // If the length is negative, bail out.
2992 // We have already checked in the LocationsBuilder for the constant case.
2993 __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
2994
2995 __ Move(count, length.AsRegister<Register>());
2996 }
2997
2998 // Validity checks: source.
2999 CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
3000
3001 // Validity checks: dest.
3002 CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
3003
3004 // If count is zero, we're done.
3005 __ Beqz(count, slow_path->GetExitLabel());
3006
3007 // Okay, everything checks out. Finally time to do the copy.
3008 // Check assumption that sizeof(Char) is 2 (used in scaling below).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003009 const size_t char_size = DataType::Size(DataType::Type::kUint16);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07003010 DCHECK_EQ(char_size, 2u);
3011
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003012 const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07003013
3014 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
3015
3016 // Calculate source and destination addresses.
3017 if (src_pos.IsConstant()) {
3018 int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
3019
3020 __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
3021 } else {
3022 __ Addiu32(src_base, src, data_offset, TMP);
3023 __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
3024 }
3025 if (dest_pos.IsConstant()) {
3026 int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
3027
3028 __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
3029 } else {
3030 __ Addiu32(dest_base, dest, data_offset, TMP);
3031 __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
3032 }
3033
3034 __ Bind(&loop);
3035 __ Lh(TMP, src_base, 0);
3036 __ Addiu(src_base, src_base, char_size);
3037 __ Addiu(count, count, -1);
3038 __ Sh(TMP, dest_base, 0);
3039 __ Addiu(dest_base, dest_base, char_size);
3040 __ Bnez(count, &loop);
3041
3042 __ Bind(slow_path->GetExitLabel());
3043}
3044
Chris Larsen5633ce72017-04-10 15:47:40 -07003045// long java.lang.Integer.valueOf(long)
3046void IntrinsicLocationsBuilderMIPS::VisitIntegerValueOf(HInvoke* invoke) {
3047 InvokeRuntimeCallingConvention calling_convention;
3048 IntrinsicVisitor::ComputeIntegerValueOfLocations(
3049 invoke,
3050 codegen_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003051 calling_convention.GetReturnLocation(DataType::Type::kReference),
Chris Larsen5633ce72017-04-10 15:47:40 -07003052 Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3053}
3054
3055void IntrinsicCodeGeneratorMIPS::VisitIntegerValueOf(HInvoke* invoke) {
3056 IntrinsicVisitor::IntegerValueOfInfo info = IntrinsicVisitor::ComputeIntegerValueOfInfo();
3057 LocationSummary* locations = invoke->GetLocations();
3058 MipsAssembler* assembler = GetAssembler();
3059 InstructionCodeGeneratorMIPS* icodegen =
3060 down_cast<InstructionCodeGeneratorMIPS*>(codegen_->GetInstructionVisitor());
3061
3062 Register out = locations->Out().AsRegister<Register>();
3063 InvokeRuntimeCallingConvention calling_convention;
3064 if (invoke->InputAt(0)->IsConstant()) {
3065 int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
3066 if (value >= info.low && value <= info.high) {
3067 // Just embed the j.l.Integer in the code.
3068 ScopedObjectAccess soa(Thread::Current());
3069 mirror::Object* boxed = info.cache->Get(value + (-info.low));
3070 DCHECK(boxed != nullptr && Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
3071 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(boxed));
3072 __ LoadConst32(out, address);
3073 } else {
3074 // Allocate and initialize a new j.l.Integer.
3075 // TODO: If we JIT, we could allocate the j.l.Integer now, and store it in the
3076 // JIT object table.
3077 uint32_t address =
3078 dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
3079 __ LoadConst32(calling_convention.GetRegisterAt(0), address);
3080 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
3081 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
3082 __ StoreConstToOffset(kStoreWord, value, out, info.value_offset, TMP);
3083 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
3084 // one.
3085 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3086 }
3087 } else {
3088 Register in = locations->InAt(0).AsRegister<Register>();
3089 MipsLabel allocate, done;
3090 int32_t count = static_cast<uint32_t>(info.high) - info.low + 1;
3091
3092 // Is (info.low <= in) && (in <= info.high)?
3093 __ Addiu32(out, in, -info.low);
3094 // As unsigned quantities is out < (info.high - info.low + 1)?
3095 if (IsInt<16>(count)) {
3096 __ Sltiu(AT, out, count);
3097 } else {
3098 __ LoadConst32(AT, count);
3099 __ Sltu(AT, out, AT);
3100 }
3101 // Branch if out >= (info.high - info.low + 1).
3102 // This means that "in" is outside of the range [info.low, info.high].
3103 __ Beqz(AT, &allocate);
3104
3105 // If the value is within the bounds, load the j.l.Integer directly from the array.
3106 uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
3107 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
3108 __ LoadConst32(TMP, data_offset + address);
3109 __ ShiftAndAdd(out, out, TMP, TIMES_4);
3110 __ Lw(out, out, 0);
3111 __ MaybeUnpoisonHeapReference(out);
3112 __ B(&done);
3113
3114 __ Bind(&allocate);
3115 // Otherwise allocate and initialize a new j.l.Integer.
3116 address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
3117 __ LoadConst32(calling_convention.GetRegisterAt(0), address);
3118 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
3119 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
3120 __ StoreToOffset(kStoreWord, in, out, info.value_offset);
3121 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
3122 // one.
3123 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3124 __ Bind(&done);
3125 }
3126}
3127
Chris Larsenb065b032017-11-02 12:13:20 -07003128// static boolean java.lang.Thread.interrupted()
3129void IntrinsicLocationsBuilderMIPS::VisitThreadInterrupted(HInvoke* invoke) {
3130 LocationSummary* locations =
3131 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3132 locations->SetOut(Location::RequiresRegister());
3133}
3134
3135void IntrinsicCodeGeneratorMIPS::VisitThreadInterrupted(HInvoke* invoke) {
3136 MipsAssembler* assembler = GetAssembler();
3137 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
3138 int32_t offset = Thread::InterruptedOffset<kMipsPointerSize>().Int32Value();
3139 __ LoadFromOffset(kLoadWord, out, TR, offset);
3140 MipsLabel done;
3141 __ Beqz(out, &done);
3142 __ Sync(0);
3143 __ StoreToOffset(kStoreWord, ZERO, TR, offset);
3144 __ Sync(0);
3145 __ Bind(&done);
3146}
3147
Chris Larsen2714fe62016-02-11 14:23:53 -08003148// Unimplemented intrinsics.
3149
Aart Bik2f9fcc92016-03-01 15:16:54 -08003150UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
3151UNIMPLEMENTED_INTRINSIC(MIPS, MathFloor)
3152UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
3153UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
Alexey Frunze15958152017-02-09 19:08:30 -08003154UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetLongVolatile);
3155UNIMPLEMENTED_INTRINSIC(MIPS, UnsafePutLongVolatile);
Aart Bik2f9fcc92016-03-01 15:16:54 -08003156UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
Chris Larsen701566a2015-10-27 15:29:13 -07003157
Aart Bik2f9fcc92016-03-01 15:16:54 -08003158UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
Aart Bik2f9fcc92016-03-01 15:16:54 -08003159UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
Aart Bik3f67e692016-01-15 14:35:12 -08003160
Aart Bikff7d89c2016-11-07 08:49:28 -08003161UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
3162UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
Aart Bik71bf7b42016-11-16 10:17:46 -08003163UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
3164UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferLength);
3165UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferToString);
3166UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderAppend);
3167UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderLength);
3168UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderToString);
Aart Bikff7d89c2016-11-07 08:49:28 -08003169
Aart Bik0e54c012016-03-04 12:08:31 -08003170// 1.8.
3171UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddInt)
3172UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddLong)
3173UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt)
3174UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong)
3175UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject)
Chris Larsen701566a2015-10-27 15:29:13 -07003176
Aart Bik0e54c012016-03-04 12:08:31 -08003177UNREACHABLE_INTRINSICS(MIPS)
Chris Larsen2714fe62016-02-11 14:23:53 -08003178
Chris Larsen701566a2015-10-27 15:29:13 -07003179#undef __
3180
3181} // namespace mips
3182} // namespace art