blob: ae248a3e5c72c75fd66c2b028b7ac8d09cb850e4 [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 -0800767// double java.lang.Math.sqrt(double)
768void IntrinsicLocationsBuilderMIPS::VisitMathSqrt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100769 CreateFPToFPLocations(allocator_, invoke);
Chris Larsenb74353a2015-11-20 09:07:09 -0800770}
771
772void IntrinsicCodeGeneratorMIPS::VisitMathSqrt(HInvoke* invoke) {
773 LocationSummary* locations = invoke->GetLocations();
774 MipsAssembler* assembler = GetAssembler();
775 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
776 FRegister out = locations->Out().AsFpuRegister<FRegister>();
777
778 __ SqrtD(out, in);
779}
780
Chris Larsen3acee732015-11-18 13:31:08 -0800781// byte libcore.io.Memory.peekByte(long address)
782void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100783 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800784}
785
786void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
787 MipsAssembler* assembler = GetAssembler();
788 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
789 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
790
791 __ Lb(out, adr, 0);
792}
793
794// short libcore.io.Memory.peekShort(long address)
795void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100796 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800797}
798
799void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
800 MipsAssembler* assembler = GetAssembler();
801 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
802 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
803
804 if (IsR6()) {
805 __ Lh(out, adr, 0);
806 } else if (IsR2OrNewer()) {
807 // Unlike for words, there are no lhl/lhr instructions to load
808 // unaligned halfwords so the code loads individual bytes, in case
809 // the address isn't halfword-aligned, and assembles them into a
810 // signed halfword.
811 __ Lb(AT, adr, 1); // This byte must be sign-extended.
812 __ Lb(out, adr, 0); // This byte can be either sign-extended, or
813 // zero-extended because the following
814 // instruction overwrites the sign bits.
815 __ Ins(out, AT, 8, 24);
816 } else {
817 __ Lbu(AT, adr, 0); // This byte must be zero-extended. If it's not
818 // the "or" instruction below will destroy the upper
819 // 24 bits of the final result.
820 __ Lb(out, adr, 1); // This byte must be sign-extended.
821 __ Sll(out, out, 8);
822 __ Or(out, out, AT);
823 }
824}
825
826// int libcore.io.Memory.peekInt(long address)
827void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100828 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen3acee732015-11-18 13:31:08 -0800829}
830
831void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
832 MipsAssembler* assembler = GetAssembler();
833 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
834 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
835
836 if (IsR6()) {
837 __ Lw(out, adr, 0);
838 } else {
839 __ Lwr(out, adr, 0);
840 __ Lwl(out, adr, 3);
841 }
842}
843
844// long libcore.io.Memory.peekLong(long address)
845void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100846 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen3acee732015-11-18 13:31:08 -0800847}
848
849void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
850 MipsAssembler* assembler = GetAssembler();
851 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
852 Register out_lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
853 Register out_hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
854
855 if (IsR6()) {
856 __ Lw(out_lo, adr, 0);
857 __ Lw(out_hi, adr, 4);
858 } else {
859 __ Lwr(out_lo, adr, 0);
860 __ Lwl(out_lo, adr, 3);
861 __ Lwr(out_hi, adr, 4);
862 __ Lwl(out_hi, adr, 7);
863 }
864}
865
Vladimir Markoca6fff82017-10-03 14:49:14 +0100866static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
867 LocationSummary* locations =
868 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen3acee732015-11-18 13:31:08 -0800869 locations->SetInAt(0, Location::RequiresRegister());
870 locations->SetInAt(1, Location::RequiresRegister());
871}
872
873// void libcore.io.Memory.pokeByte(long address, byte value)
874void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100875 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800876}
877
878void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
879 MipsAssembler* assembler = GetAssembler();
880 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
881 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
882
883 __ Sb(val, adr, 0);
884}
885
886// void libcore.io.Memory.pokeShort(long address, short value)
887void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100888 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800889}
890
891void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
892 MipsAssembler* assembler = GetAssembler();
893 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
894 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
895
896 if (IsR6()) {
897 __ Sh(val, adr, 0);
898 } else {
899 // Unlike for words, there are no shl/shr instructions to store
900 // unaligned halfwords so the code stores individual bytes, in case
901 // the address isn't halfword-aligned.
902 __ Sb(val, adr, 0);
903 __ Srl(AT, val, 8);
904 __ Sb(AT, adr, 1);
905 }
906}
907
908// void libcore.io.Memory.pokeInt(long address, int value)
909void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100910 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800911}
912
913void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
914 MipsAssembler* assembler = GetAssembler();
915 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
916 Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
917
918 if (IsR6()) {
919 __ Sw(val, adr, 0);
920 } else {
921 __ Swr(val, adr, 0);
922 __ Swl(val, adr, 3);
923 }
924}
925
926// void libcore.io.Memory.pokeLong(long address, long value)
927void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100928 CreateIntIntToVoidLocations(allocator_, invoke);
Chris Larsen3acee732015-11-18 13:31:08 -0800929}
930
931void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
932 MipsAssembler* assembler = GetAssembler();
933 Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
934 Register val_lo = invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>();
935 Register val_hi = invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>();
936
937 if (IsR6()) {
938 __ Sw(val_lo, adr, 0);
939 __ Sw(val_hi, adr, 4);
940 } else {
941 __ Swr(val_lo, adr, 0);
942 __ Swl(val_lo, adr, 3);
943 __ Swr(val_hi, adr, 4);
944 __ Swl(val_hi, adr, 7);
945 }
946}
947
Chris Larsencf283da2016-01-19 16:45:35 -0800948// Thread java.lang.Thread.currentThread()
949void IntrinsicLocationsBuilderMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100950 LocationSummary* locations =
951 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -0800952 locations->SetOut(Location::RequiresRegister());
953}
954
955void IntrinsicCodeGeneratorMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
956 MipsAssembler* assembler = GetAssembler();
957 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
958
959 __ LoadFromOffset(kLoadWord,
960 out,
961 TR,
962 Thread::PeerOffset<kMipsPointerSize>().Int32Value());
963}
964
Vladimir Markoca6fff82017-10-03 14:49:14 +0100965static void CreateIntIntIntToIntLocations(ArenaAllocator* allocator,
Alexey Frunze15958152017-02-09 19:08:30 -0800966 HInvoke* invoke,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100967 DataType::Type type) {
Alexey Frunze15958152017-02-09 19:08:30 -0800968 bool can_call = kEmitCompilerReadBarrier &&
969 (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
970 invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100971 LocationSummary* locations =
972 new (allocator) LocationSummary(invoke,
973 can_call
974 ? LocationSummary::kCallOnSlowPath
975 : LocationSummary::kNoCall,
976 kIntrinsified);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700977 if (can_call && kUseBakerReadBarrier) {
978 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
979 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -0800980 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
981 locations->SetInAt(1, Location::RequiresRegister());
982 locations->SetInAt(2, Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -0800983 locations->SetOut(Location::RequiresRegister(),
984 (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100985 if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze15958152017-02-09 19:08:30 -0800986 // We need a temporary register for the read barrier marking slow
987 // path in InstructionCodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier.
988 locations->AddTemp(Location::RequiresRegister());
989 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -0800990}
991
Alexey Frunze15958152017-02-09 19:08:30 -0800992// Note that the caller must supply a properly aligned memory address.
993// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen4fdc6d92015-12-14 13:26:14 -0800994static void GenUnsafeGet(HInvoke* invoke,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100995 DataType::Type type,
Chris Larsen4fdc6d92015-12-14 13:26:14 -0800996 bool is_volatile,
997 bool is_R6,
998 CodeGeneratorMIPS* codegen) {
999 LocationSummary* locations = invoke->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001000 DCHECK((type == DataType::Type::kInt32) ||
1001 (type == DataType::Type::kInt64) ||
1002 (type == DataType::Type::kReference)) << type;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001003 MipsAssembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001004 // Target register.
1005 Location trg_loc = locations->Out();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001006 // Object pointer.
Alexey Frunze15958152017-02-09 19:08:30 -08001007 Location base_loc = locations->InAt(1);
1008 Register base = base_loc.AsRegister<Register>();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001009 // The "offset" argument is passed as a "long". Since this code is for
1010 // a 32-bit processor, we can only use 32-bit addresses, so we only
1011 // need the low 32-bits of offset.
Alexey Frunze15958152017-02-09 19:08:30 -08001012 Location offset_loc = locations->InAt(2);
1013 Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001014
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001015 if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == DataType::Type::kReference))) {
Alexey Frunze15958152017-02-09 19:08:30 -08001016 __ Addu(TMP, base, offset_lo);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001017 }
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001018
Alexey Frunze15958152017-02-09 19:08:30 -08001019 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001020 case DataType::Type::kInt64: {
Alexey Frunze15958152017-02-09 19:08:30 -08001021 Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
1022 Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
1023 CHECK(!is_volatile); // TODO: support atomic 8-byte volatile loads.
1024 if (is_R6) {
1025 __ Lw(trg_lo, TMP, 0);
1026 __ Lw(trg_hi, TMP, 4);
1027 } else {
1028 __ Lwr(trg_lo, TMP, 0);
1029 __ Lwl(trg_lo, TMP, 3);
1030 __ Lwr(trg_hi, TMP, 4);
1031 __ Lwl(trg_hi, TMP, 7);
1032 }
1033 break;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001034 }
Alexey Frunzec061de12017-02-14 13:27:23 -08001035
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001036 case DataType::Type::kInt32: {
Alexey Frunze15958152017-02-09 19:08:30 -08001037 Register trg = trg_loc.AsRegister<Register>();
1038 if (is_R6) {
1039 __ Lw(trg, TMP, 0);
1040 } else {
1041 __ Lwr(trg, TMP, 0);
1042 __ Lwl(trg, TMP, 3);
1043 }
1044 if (is_volatile) {
1045 __ Sync(0);
1046 }
1047 break;
Alexey Frunzec061de12017-02-14 13:27:23 -08001048 }
Alexey Frunze15958152017-02-09 19:08:30 -08001049
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001050 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08001051 Register trg = trg_loc.AsRegister<Register>();
1052 if (kEmitCompilerReadBarrier) {
1053 if (kUseBakerReadBarrier) {
1054 Location temp = locations->GetTemp(0);
1055 codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
1056 trg_loc,
1057 base,
1058 /* offset */ 0U,
1059 /* index */ offset_loc,
1060 TIMES_1,
1061 temp,
1062 /* needs_null_check */ false);
1063 if (is_volatile) {
1064 __ Sync(0);
1065 }
1066 } else {
1067 if (is_R6) {
1068 __ Lw(trg, TMP, 0);
1069 } else {
1070 __ Lwr(trg, TMP, 0);
1071 __ Lwl(trg, TMP, 3);
1072 }
1073 if (is_volatile) {
1074 __ Sync(0);
1075 }
1076 codegen->GenerateReadBarrierSlow(invoke,
1077 trg_loc,
1078 trg_loc,
1079 base_loc,
1080 /* offset */ 0U,
1081 /* index */ offset_loc);
1082 }
1083 } else {
1084 if (is_R6) {
1085 __ Lw(trg, TMP, 0);
1086 } else {
1087 __ Lwr(trg, TMP, 0);
1088 __ Lwl(trg, TMP, 3);
1089 }
1090 if (is_volatile) {
1091 __ Sync(0);
1092 }
1093 __ MaybeUnpoisonHeapReference(trg);
1094 }
1095 break;
1096 }
1097
1098 default:
1099 LOG(FATAL) << "Unexpected type " << type;
1100 UNREACHABLE();
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001101 }
1102}
1103
1104// int sun.misc.Unsafe.getInt(Object o, long offset)
1105void IntrinsicLocationsBuilderMIPS::VisitUnsafeGet(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001106 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001107}
1108
1109void IntrinsicCodeGeneratorMIPS::VisitUnsafeGet(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001110 GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001111}
1112
1113// int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
1114void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001115 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001116}
1117
1118void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001119 GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001120}
1121
1122// long sun.misc.Unsafe.getLong(Object o, long offset)
1123void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001124 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt64);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001125}
1126
1127void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001128 GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001129}
1130
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001131// Object sun.misc.Unsafe.getObject(Object o, long offset)
1132void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001133 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001134}
1135
1136void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001137 GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001138}
1139
1140// Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
1141void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001142 CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001143}
1144
1145void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001146 GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, IsR6(), codegen_);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001147}
1148
Vladimir Markoca6fff82017-10-03 14:49:14 +01001149static void CreateIntIntIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
1150 LocationSummary* locations =
1151 new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001152 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1153 locations->SetInAt(1, Location::RequiresRegister());
1154 locations->SetInAt(2, Location::RequiresRegister());
1155 locations->SetInAt(3, Location::RequiresRegister());
1156}
1157
Alexey Frunze15958152017-02-09 19:08:30 -08001158// Note that the caller must supply a properly aligned memory address.
1159// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001160static void GenUnsafePut(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001161 DataType::Type type,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001162 bool is_volatile,
1163 bool is_ordered,
1164 bool is_R6,
1165 CodeGeneratorMIPS* codegen) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001166 DCHECK((type == DataType::Type::kInt32) ||
1167 (type == DataType::Type::kInt64) ||
1168 (type == DataType::Type::kReference)) << type;
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001169 MipsAssembler* assembler = codegen->GetAssembler();
1170 // Object pointer.
1171 Register base = locations->InAt(1).AsRegister<Register>();
1172 // The "offset" argument is passed as a "long", i.e., it's 64-bits in
1173 // size. Since this code is for a 32-bit processor, we can only use
1174 // 32-bit addresses, so we only need the low 32-bits of offset.
1175 Register offset_lo = locations->InAt(2).AsRegisterPairLow<Register>();
1176
1177 __ Addu(TMP, base, offset_lo);
1178 if (is_volatile || is_ordered) {
1179 __ Sync(0);
1180 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001181 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001182 Register value = locations->InAt(3).AsRegister<Register>();
1183
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001184 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001185 __ PoisonHeapReference(AT, value);
1186 value = AT;
1187 }
1188
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001189 if (is_R6) {
1190 __ Sw(value, TMP, 0);
1191 } else {
1192 __ Swr(value, TMP, 0);
1193 __ Swl(value, TMP, 3);
1194 }
1195 } else {
1196 Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
1197 Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001198 CHECK(!is_volatile); // TODO: support atomic 8-byte volatile stores.
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001199 if (is_R6) {
1200 __ Sw(value_lo, TMP, 0);
1201 __ Sw(value_hi, TMP, 4);
1202 } else {
1203 __ Swr(value_lo, TMP, 0);
1204 __ Swl(value_lo, TMP, 3);
1205 __ Swr(value_hi, TMP, 4);
1206 __ Swl(value_hi, TMP, 7);
1207 }
1208 }
1209
1210 if (is_volatile) {
1211 __ Sync(0);
1212 }
1213
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001214 if (type == DataType::Type::kReference) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01001215 bool value_can_be_null = true; // TODO: Worth finding out this information?
1216 codegen->MarkGCCard(base, locations->InAt(3).AsRegister<Register>(), value_can_be_null);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001217 }
1218}
1219
1220// void sun.misc.Unsafe.putInt(Object o, long offset, int x)
1221void IntrinsicLocationsBuilderMIPS::VisitUnsafePut(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001222 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001223}
1224
1225void IntrinsicCodeGeneratorMIPS::VisitUnsafePut(HInvoke* invoke) {
1226 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001227 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001228 /* is_volatile */ false,
1229 /* is_ordered */ false,
1230 IsR6(),
1231 codegen_);
1232}
1233
1234// void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
1235void IntrinsicLocationsBuilderMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001236 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001237}
1238
1239void IntrinsicCodeGeneratorMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
1240 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001241 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001242 /* is_volatile */ false,
1243 /* is_ordered */ true,
1244 IsR6(),
1245 codegen_);
1246}
1247
1248// void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
1249void IntrinsicLocationsBuilderMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001250 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001251}
1252
1253void IntrinsicCodeGeneratorMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
1254 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001255 DataType::Type::kInt32,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001256 /* is_volatile */ true,
1257 /* is_ordered */ false,
1258 IsR6(),
1259 codegen_);
1260}
1261
1262// void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
1263void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObject(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001264 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001265}
1266
1267void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObject(HInvoke* invoke) {
1268 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001269 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001270 /* is_volatile */ false,
1271 /* is_ordered */ false,
1272 IsR6(),
1273 codegen_);
1274}
1275
1276// void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
1277void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001278 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001279}
1280
1281void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1282 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001283 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001284 /* is_volatile */ false,
1285 /* is_ordered */ true,
1286 IsR6(),
1287 codegen_);
1288}
1289
1290// void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
1291void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001292 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001293}
1294
1295void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1296 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001297 DataType::Type::kReference,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001298 /* is_volatile */ true,
1299 /* is_ordered */ false,
1300 IsR6(),
1301 codegen_);
1302}
1303
1304// void sun.misc.Unsafe.putLong(Object o, long offset, long x)
1305void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLong(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001306 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001307}
1308
1309void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLong(HInvoke* invoke) {
1310 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001311 DataType::Type::kInt64,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001312 /* is_volatile */ false,
1313 /* is_ordered */ false,
1314 IsR6(),
1315 codegen_);
1316}
1317
1318// void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
1319void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001320 CreateIntIntIntIntToVoidLocations(allocator_, invoke);
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001321}
1322
1323void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1324 GenUnsafePut(invoke->GetLocations(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001325 DataType::Type::kInt64,
Chris Larsen4fdc6d92015-12-14 13:26:14 -08001326 /* is_volatile */ false,
1327 /* is_ordered */ true,
1328 IsR6(),
1329 codegen_);
1330}
1331
Vladimir Markoca6fff82017-10-03 14:49:14 +01001332static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* allocator, HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001333 bool can_call = kEmitCompilerReadBarrier &&
1334 kUseBakerReadBarrier &&
1335 (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001336 LocationSummary* locations =
1337 new (allocator) LocationSummary(invoke,
1338 can_call
1339 ? LocationSummary::kCallOnSlowPath
1340 : LocationSummary::kNoCall,
1341 kIntrinsified);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001342 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1343 locations->SetInAt(1, Location::RequiresRegister());
1344 locations->SetInAt(2, Location::RequiresRegister());
1345 locations->SetInAt(3, Location::RequiresRegister());
1346 locations->SetInAt(4, Location::RequiresRegister());
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001347 locations->SetOut(Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08001348
1349 // Temporary register used in CAS by (Baker) read barrier.
1350 if (can_call) {
1351 locations->AddTemp(Location::RequiresRegister());
1352 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001353}
1354
Alexey Frunze15958152017-02-09 19:08:30 -08001355// Note that the caller must supply a properly aligned memory address.
1356// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001357static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorMIPS* codegen) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001358 MipsAssembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001359 LocationSummary* locations = invoke->GetLocations();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001360 bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
1361 Register base = locations->InAt(1).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001362 Location offset_loc = locations->InAt(2);
1363 Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001364 Register expected = locations->InAt(3).AsRegister<Register>();
1365 Register value = locations->InAt(4).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08001366 Location out_loc = locations->Out();
1367 Register out = out_loc.AsRegister<Register>();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001368
1369 DCHECK_NE(base, out);
1370 DCHECK_NE(offset_lo, out);
1371 DCHECK_NE(expected, out);
1372
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001373 if (type == DataType::Type::kReference) {
Alexey Frunze15958152017-02-09 19:08:30 -08001374 // The only read barrier implementation supporting the
1375 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1376 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1377
1378 // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
1379 // object and scan the receiver at the next GC for nothing.
Goran Jakovljevice114da22016-12-26 14:21:43 +01001380 bool value_can_be_null = true; // TODO: Worth finding out this information?
1381 codegen->MarkGCCard(base, value, value_can_be_null);
Alexey Frunze15958152017-02-09 19:08:30 -08001382
1383 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1384 Location temp = locations->GetTemp(0);
1385 // Need to make sure the reference stored in the field is a to-space
1386 // one before attempting the CAS or the CAS could fail incorrectly.
1387 codegen->GenerateReferenceLoadWithBakerReadBarrier(
1388 invoke,
1389 out_loc, // Unused, used only as a "temporary" within the read barrier.
1390 base,
1391 /* offset */ 0u,
1392 /* index */ offset_loc,
1393 ScaleFactor::TIMES_1,
1394 temp,
1395 /* needs_null_check */ false,
1396 /* always_update_field */ true);
1397 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001398 }
1399
Alexey Frunzec061de12017-02-14 13:27:23 -08001400 MipsLabel loop_head, exit_loop;
1401 __ Addu(TMP, base, offset_lo);
1402
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001403 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001404 __ PoisonHeapReference(expected);
1405 // Do not poison `value`, if it is the same register as
1406 // `expected`, which has just been poisoned.
1407 if (value != expected) {
1408 __ PoisonHeapReference(value);
1409 }
1410 }
1411
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001412 // do {
1413 // tmp_value = [tmp_ptr] - expected;
1414 // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
1415 // result = tmp_value != 0;
1416
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001417 __ Sync(0);
1418 __ Bind(&loop_head);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001419 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001420 if (isR6) {
1421 __ LlR6(out, TMP);
1422 } else {
1423 __ LlR2(out, TMP);
1424 }
1425 } else {
Alexey Frunzec061de12017-02-14 13:27:23 -08001426 LOG(FATAL) << "Unsupported op size " << type;
1427 UNREACHABLE();
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001428 }
1429 __ Subu(out, out, expected); // If we didn't get the 'expected'
1430 __ Sltiu(out, out, 1); // value, set 'out' to false, and
1431 __ Beqz(out, &exit_loop); // return.
1432 __ Move(out, value); // Use 'out' for the 'store conditional' instruction.
1433 // If we use 'value' directly, we would lose 'value'
1434 // in the case that the store fails. Whether the
1435 // store succeeds, or fails, it will load the
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001436 // correct Boolean value into the 'out' register.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001437 // This test isn't really necessary. We only support DataType::Type::kInt,
1438 // DataType::Type::kReference, and we already verified that we're working on one
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001439 // of those two types. It's left here in case the code needs to support
1440 // other types in the future.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001441 if ((type == DataType::Type::kInt32) || (type == DataType::Type::kReference)) {
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001442 if (isR6) {
1443 __ ScR6(out, TMP);
1444 } else {
1445 __ ScR2(out, TMP);
1446 }
1447 }
1448 __ Beqz(out, &loop_head); // If we couldn't do the read-modify-write
1449 // cycle atomically then retry.
1450 __ Bind(&exit_loop);
1451 __ Sync(0);
Alexey Frunzec061de12017-02-14 13:27:23 -08001452
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001453 if (kPoisonHeapReferences && type == DataType::Type::kReference) {
Alexey Frunzec061de12017-02-14 13:27:23 -08001454 __ UnpoisonHeapReference(expected);
1455 // Do not unpoison `value`, if it is the same register as
1456 // `expected`, which has just been unpoisoned.
1457 if (value != expected) {
1458 __ UnpoisonHeapReference(value);
1459 }
1460 }
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001461}
1462
1463// boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
1464void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001465 CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001466}
1467
1468void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001469 GenCas(invoke, DataType::Type::kInt32, codegen_);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001470}
1471
1472// boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
1473void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001474 // The only read barrier implementation supporting the
1475 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1476 if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
1477 return;
1478 }
1479
Vladimir Markoca6fff82017-10-03 14:49:14 +01001480 CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001481}
1482
1483void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001484 // The only read barrier implementation supporting the
1485 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1486 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1487
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001488 GenCas(invoke, DataType::Type::kReference, codegen_);
Alexey Frunze51aff3a2016-03-17 17:21:45 -07001489}
1490
Chris Larsencf283da2016-01-19 16:45:35 -08001491// int java.lang.String.compareTo(String anotherString)
1492void IntrinsicLocationsBuilderMIPS::VisitStringCompareTo(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001493 LocationSummary* locations = new (allocator_) LocationSummary(
1494 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001495 InvokeRuntimeCallingConvention calling_convention;
1496 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1497 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001498 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001499 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1500}
1501
1502void IntrinsicCodeGeneratorMIPS::VisitStringCompareTo(HInvoke* invoke) {
1503 MipsAssembler* assembler = GetAssembler();
1504 LocationSummary* locations = invoke->GetLocations();
1505
1506 // Note that the null check must have been done earlier.
1507 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1508
1509 Register argument = locations->InAt(1).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01001510 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001511 codegen_->AddSlowPath(slow_path);
1512 __ Beqz(argument, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01001513 codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08001514 __ Bind(slow_path->GetExitLabel());
1515}
1516
Chris Larsen16ba2b42015-11-02 10:58:31 -08001517// boolean java.lang.String.equals(Object anObject)
1518void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
Vladimir Markoda283052017-11-07 21:17:24 +00001519 if (kEmitCompilerReadBarrier &&
1520 !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
1521 !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
1522 // No support for this odd case (String class is moveable, not in the boot image).
1523 return;
1524 }
1525
Vladimir Markoca6fff82017-10-03 14:49:14 +01001526 LocationSummary* locations =
1527 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen16ba2b42015-11-02 10:58:31 -08001528 locations->SetInAt(0, Location::RequiresRegister());
1529 locations->SetInAt(1, Location::RequiresRegister());
1530 locations->SetOut(Location::RequiresRegister());
1531
1532 // Temporary registers to store lengths of strings and for calculations.
1533 locations->AddTemp(Location::RequiresRegister());
1534 locations->AddTemp(Location::RequiresRegister());
1535 locations->AddTemp(Location::RequiresRegister());
1536}
1537
1538void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) {
1539 MipsAssembler* assembler = GetAssembler();
1540 LocationSummary* locations = invoke->GetLocations();
1541
1542 Register str = locations->InAt(0).AsRegister<Register>();
1543 Register arg = locations->InAt(1).AsRegister<Register>();
1544 Register out = locations->Out().AsRegister<Register>();
1545
1546 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
1547 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
1548 Register temp3 = locations->GetTemp(2).AsRegister<Register>();
1549
1550 MipsLabel loop;
1551 MipsLabel end;
1552 MipsLabel return_true;
1553 MipsLabel return_false;
1554
1555 // Get offsets of count, value, and class fields within a string object.
1556 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1557 const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1558 const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
1559
1560 // Note that the null check must have been done earlier.
1561 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1562
1563 // If the register containing the pointer to "this", and the register
1564 // containing the pointer to "anObject" are the same register then
1565 // "this", and "anObject" are the same object and we can
1566 // short-circuit the logic to a true result.
1567 if (str == arg) {
1568 __ LoadConst32(out, 1);
1569 return;
1570 }
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01001571 StringEqualsOptimizations optimizations(invoke);
1572 if (!optimizations.GetArgumentNotNull()) {
1573 // Check if input is null, return false if it is.
1574 __ Beqz(arg, &return_false);
1575 }
Chris Larsen16ba2b42015-11-02 10:58:31 -08001576
1577 // Reference equality check, return true if same reference.
1578 __ Beq(str, arg, &return_true);
1579
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01001580 if (!optimizations.GetArgumentIsString()) {
1581 // Instanceof check for the argument by comparing class fields.
1582 // All string objects must have the same type since String cannot be subclassed.
1583 // Receiver must be a string object, so its class field is equal to all strings' class fields.
1584 // If the argument is a string object, its class field must be equal to receiver's class field.
1585 __ Lw(temp1, str, class_offset);
1586 __ Lw(temp2, arg, class_offset);
1587 __ Bne(temp1, temp2, &return_false);
1588 }
Chris Larsen16ba2b42015-11-02 10:58:31 -08001589
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001590 // Load `count` fields of this and argument strings.
Chris Larsen16ba2b42015-11-02 10:58:31 -08001591 __ Lw(temp1, str, count_offset);
1592 __ Lw(temp2, arg, count_offset);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001593 // Check if `count` fields are equal, return false if they're not.
1594 // Also compares the compression style, if differs return false.
Chris Larsen16ba2b42015-11-02 10:58:31 -08001595 __ Bne(temp1, temp2, &return_false);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001596 // Return true if both strings are empty. Even with string compression `count == 0` means empty.
1597 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1598 "Expecting 0=compressed, 1=uncompressed");
Chris Larsen16ba2b42015-11-02 10:58:31 -08001599 __ Beqz(temp1, &return_true);
1600
1601 // Don't overwrite input registers
1602 __ Move(TMP, str);
1603 __ Move(temp3, arg);
1604
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001605 // Assertions that must hold in order to compare strings 4 bytes at a time.
Chris Larsen16ba2b42015-11-02 10:58:31 -08001606 DCHECK_ALIGNED(value_offset, 4);
1607 static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
1608
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001609 // For string compression, calculate the number of bytes to compare (not chars).
1610 if (mirror::kUseStringCompression) {
1611 // Extract compression flag.
1612 if (IsR2OrNewer()) {
1613 __ Ext(temp2, temp1, 0, 1);
1614 } else {
1615 __ Sll(temp2, temp1, 31);
1616 __ Srl(temp2, temp2, 31);
1617 }
1618 __ Srl(temp1, temp1, 1); // Extract length.
1619 __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed.
1620 }
1621
1622 // Loop to compare strings 4 bytes at a time starting at the beginning of the string.
1623 // Ok to do this because strings are zero-padded to kObjectAlignment.
Chris Larsen16ba2b42015-11-02 10:58:31 -08001624 __ Bind(&loop);
1625 __ Lw(out, TMP, value_offset);
1626 __ Lw(temp2, temp3, value_offset);
1627 __ Bne(out, temp2, &return_false);
1628 __ Addiu(TMP, TMP, 4);
1629 __ Addiu(temp3, temp3, 4);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001630 // With string compression, we have compared 4 bytes, otherwise 2 chars.
1631 __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -4 : -2);
Chris Larsen16ba2b42015-11-02 10:58:31 -08001632 __ Bgtz(temp1, &loop);
1633
1634 // Return true and exit the function.
1635 // If loop does not result in returning false, we return true.
1636 __ Bind(&return_true);
1637 __ LoadConst32(out, 1);
1638 __ B(&end);
1639
1640 // Return false and exit the function.
1641 __ Bind(&return_false);
1642 __ LoadConst32(out, 0);
1643 __ Bind(&end);
1644}
1645
Chris Larsencf283da2016-01-19 16:45:35 -08001646static void GenerateStringIndexOf(HInvoke* invoke,
1647 bool start_at_zero,
1648 MipsAssembler* assembler,
Vladimir Marko174b2e22017-10-12 13:34:49 +01001649 CodeGeneratorMIPS* codegen) {
Chris Larsencf283da2016-01-19 16:45:35 -08001650 LocationSummary* locations = invoke->GetLocations();
1651 Register tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<Register>() : TMP;
1652
1653 // Note that the null check must have been done earlier.
1654 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1655
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001656 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
1657 // 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 -08001658 SlowPathCodeMIPS* slow_path = nullptr;
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001659 HInstruction* code_point = invoke->InputAt(1);
1660 if (code_point->IsIntConstant()) {
Vladimir Markoda051082016-05-17 16:10:20 +01001661 if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
Chris Larsencf283da2016-01-19 16:45:35 -08001662 // Always needs the slow-path. We could directly dispatch to it,
1663 // but this case should be rare, so for simplicity just put the
1664 // full slow-path down and branch unconditionally.
Vladimir Marko174b2e22017-10-12 13:34:49 +01001665 slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001666 codegen->AddSlowPath(slow_path);
1667 __ B(slow_path->GetEntryLabel());
1668 __ Bind(slow_path->GetExitLabel());
1669 return;
1670 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001671 } else if (code_point->GetType() != DataType::Type::kUint16) {
Chris Larsencf283da2016-01-19 16:45:35 -08001672 Register char_reg = locations->InAt(1).AsRegister<Register>();
1673 // The "bltu" conditional branch tests to see if the character value
1674 // fits in a valid 16-bit (MIPS halfword) value. If it doesn't then
1675 // the character being searched for, if it exists in the string, is
1676 // encoded using UTF-16 and stored in the string as two (16-bit)
1677 // halfwords. Currently the assembly code used to implement this
1678 // intrinsic doesn't support searching for a character stored as
1679 // two halfwords so we fallback to using the generic implementation
1680 // of indexOf().
1681 __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
Vladimir Marko174b2e22017-10-12 13:34:49 +01001682 slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001683 codegen->AddSlowPath(slow_path);
1684 __ Bltu(tmp_reg, char_reg, slow_path->GetEntryLabel());
1685 }
1686
1687 if (start_at_zero) {
1688 DCHECK_EQ(tmp_reg, A2);
1689 // Start-index = 0.
1690 __ Clear(tmp_reg);
1691 }
1692
Serban Constantinescufca16662016-07-14 09:21:59 +01001693 codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08001694 if (slow_path != nullptr) {
1695 __ Bind(slow_path->GetExitLabel());
1696 }
1697}
1698
1699// int java.lang.String.indexOf(int ch)
1700void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001701 LocationSummary* locations = new (allocator_) LocationSummary(
1702 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001703 // We have a hand-crafted assembly stub that follows the runtime
1704 // calling convention. So it's best to align the inputs accordingly.
1705 InvokeRuntimeCallingConvention calling_convention;
1706 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1707 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001708 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001709 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1710
1711 // Need a temp for slow-path codepoint compare, and need to send start-index=0.
1712 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1713}
1714
1715void IntrinsicCodeGeneratorMIPS::VisitStringIndexOf(HInvoke* invoke) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001716 GenerateStringIndexOf(invoke, /* start_at_zero */ true, GetAssembler(), codegen_);
Chris Larsencf283da2016-01-19 16:45:35 -08001717}
1718
1719// int java.lang.String.indexOf(int ch, int fromIndex)
1720void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001721 LocationSummary* locations = new (allocator_) LocationSummary(
1722 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001723 // We have a hand-crafted assembly stub that follows the runtime
1724 // calling convention. So it's best to align the inputs accordingly.
1725 InvokeRuntimeCallingConvention calling_convention;
1726 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1727 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1728 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001729 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001730 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1731
1732 // Need a temp for slow-path codepoint compare.
1733 locations->AddTemp(Location::RequiresRegister());
1734}
1735
1736void IntrinsicCodeGeneratorMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001737 GenerateStringIndexOf(invoke, /* start_at_zero */ false, GetAssembler(), codegen_);
Chris Larsencf283da2016-01-19 16:45:35 -08001738}
1739
1740// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
1741void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001742 LocationSummary* locations = new (allocator_) LocationSummary(
1743 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001744 InvokeRuntimeCallingConvention calling_convention;
1745 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1746 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1747 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1748 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001749 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001750 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1751}
1752
1753void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
1754 MipsAssembler* assembler = GetAssembler();
1755 LocationSummary* locations = invoke->GetLocations();
1756
1757 Register byte_array = locations->InAt(0).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01001758 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001759 codegen_->AddSlowPath(slow_path);
1760 __ Beqz(byte_array, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01001761 codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
Chris Larsencf283da2016-01-19 16:45:35 -08001762 __ Bind(slow_path->GetExitLabel());
1763}
1764
1765// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1766void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001767 LocationSummary* locations =
1768 new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001769 InvokeRuntimeCallingConvention calling_convention;
1770 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1771 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1772 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001773 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001774 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1775}
1776
1777void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
Chris Larsencf283da2016-01-19 16:45:35 -08001778 // No need to emit code checking whether `locations->InAt(2)` is a null
1779 // pointer, as callers of the native method
1780 //
1781 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1782 //
1783 // all include a null check on `data` before calling that method.
Serban Constantinescufca16662016-07-14 09:21:59 +01001784 codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
Chris Larsencf283da2016-01-19 16:45:35 -08001785}
1786
1787// java.lang.StringFactory.newStringFromString(String toCopy)
1788void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001789 LocationSummary* locations = new (allocator_) LocationSummary(
1790 invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
Chris Larsencf283da2016-01-19 16:45:35 -08001791 InvokeRuntimeCallingConvention calling_convention;
1792 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001793 Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
Chris Larsencf283da2016-01-19 16:45:35 -08001794 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
1795}
1796
1797void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
1798 MipsAssembler* assembler = GetAssembler();
1799 LocationSummary* locations = invoke->GetLocations();
1800
1801 Register string_to_copy = locations->InAt(0).AsRegister<Register>();
Vladimir Marko174b2e22017-10-12 13:34:49 +01001802 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsencf283da2016-01-19 16:45:35 -08001803 codegen_->AddSlowPath(slow_path);
1804 __ Beqz(string_to_copy, slow_path->GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +01001805 codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc());
Chris Larsencf283da2016-01-19 16:45:35 -08001806 __ Bind(slow_path->GetExitLabel());
1807}
1808
Chris Larsen2714fe62016-02-11 14:23:53 -08001809static void GenIsInfinite(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001810 const DataType::Type type,
Chris Larsen2714fe62016-02-11 14:23:53 -08001811 const bool isR6,
1812 MipsAssembler* assembler) {
1813 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
1814 Register out = locations->Out().AsRegister<Register>();
1815
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001816 DCHECK(type == DataType::Type::kFloat32 || type == DataType::Type::kFloat64);
Chris Larsen2714fe62016-02-11 14:23:53 -08001817
1818 if (isR6) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001819 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08001820 __ ClassD(FTMP, in);
1821 } else {
1822 __ ClassS(FTMP, in);
1823 }
1824 __ Mfc1(out, FTMP);
1825 __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
1826 __ Sltu(out, ZERO, out);
1827 } else {
1828 // If one, or more, of the exponent bits is zero, then the number can't be infinite.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001829 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08001830 __ MoveFromFpuHigh(TMP, in);
Anton Kirilova3ffea22016-04-07 17:02:37 +01001831 __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble));
Chris Larsen2714fe62016-02-11 14:23:53 -08001832 } else {
1833 __ Mfc1(TMP, in);
Anton Kirilova3ffea22016-04-07 17:02:37 +01001834 __ LoadConst32(AT, kPositiveInfinityFloat);
Chris Larsen2714fe62016-02-11 14:23:53 -08001835 }
1836 __ Xor(TMP, TMP, AT);
1837
1838 __ Sll(TMP, TMP, 1);
1839
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001840 if (type == DataType::Type::kFloat64) {
Chris Larsen2714fe62016-02-11 14:23:53 -08001841 __ Mfc1(AT, in);
1842 __ Or(TMP, TMP, AT);
1843 }
1844 // If any of the significand bits are one, then the number is not infinite.
1845 __ Sltiu(out, TMP, 1);
1846 }
1847}
1848
1849// boolean java.lang.Float.isInfinite(float)
1850void IntrinsicLocationsBuilderMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001851 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen2714fe62016-02-11 14:23:53 -08001852}
1853
1854void IntrinsicCodeGeneratorMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001855 GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat32, IsR6(), GetAssembler());
Chris Larsen2714fe62016-02-11 14:23:53 -08001856}
1857
1858// boolean java.lang.Double.isInfinite(double)
1859void IntrinsicLocationsBuilderMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001860 CreateFPToIntLocations(allocator_, invoke);
Chris Larsen2714fe62016-02-11 14:23:53 -08001861}
1862
1863void IntrinsicCodeGeneratorMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001864 GenIsInfinite(invoke->GetLocations(), DataType::Type::kFloat64, IsR6(), GetAssembler());
Chris Larsen2714fe62016-02-11 14:23:53 -08001865}
1866
Chris Larsen97759342016-02-16 17:10:40 -08001867static void GenHighestOneBit(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001868 const DataType::Type type,
Chris Larsen97759342016-02-16 17:10:40 -08001869 bool isR6,
1870 MipsAssembler* assembler) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001871 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
Chris Larsen97759342016-02-16 17:10:40 -08001872
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001873 if (type == DataType::Type::kInt64) {
Chris Larsen97759342016-02-16 17:10:40 -08001874 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1875 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1876 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1877 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1878
1879 if (isR6) {
1880 __ ClzR6(TMP, in_hi);
1881 } else {
1882 __ ClzR2(TMP, in_hi);
1883 }
1884 __ LoadConst32(AT, 0x80000000);
1885 __ Srlv(out_hi, AT, TMP);
1886 __ And(out_hi, out_hi, in_hi);
1887 if (isR6) {
1888 __ ClzR6(TMP, in_lo);
1889 } else {
1890 __ ClzR2(TMP, in_lo);
1891 }
1892 __ Srlv(out_lo, AT, TMP);
1893 __ And(out_lo, out_lo, in_lo);
1894 if (isR6) {
1895 __ Seleqz(out_lo, out_lo, out_hi);
1896 } else {
1897 __ Movn(out_lo, ZERO, out_hi);
1898 }
1899 } else {
1900 Register in = locations->InAt(0).AsRegister<Register>();
1901 Register out = locations->Out().AsRegister<Register>();
1902
1903 if (isR6) {
1904 __ ClzR6(TMP, in);
1905 } else {
1906 __ ClzR2(TMP, in);
1907 }
1908 __ LoadConst32(AT, 0x80000000);
1909 __ Srlv(AT, AT, TMP); // Srlv shifts in the range of [0;31] bits (lower 5 bits of arg).
1910 __ And(out, AT, in); // So this is required for 0 (=shift by 32).
1911 }
1912}
1913
1914// int java.lang.Integer.highestOneBit(int)
1915void IntrinsicLocationsBuilderMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001916 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08001917}
1918
1919void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001920 GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08001921}
1922
1923// long java.lang.Long.highestOneBit(long)
1924void IntrinsicLocationsBuilderMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001925 CreateIntToIntLocations(allocator_, invoke, Location::kOutputOverlap);
Chris Larsen97759342016-02-16 17:10:40 -08001926}
1927
1928void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001929 GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08001930}
1931
1932static void GenLowestOneBit(LocationSummary* locations,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001933 const DataType::Type type,
Chris Larsen97759342016-02-16 17:10:40 -08001934 bool isR6,
1935 MipsAssembler* assembler) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001936 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
Chris Larsen97759342016-02-16 17:10:40 -08001937
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001938 if (type == DataType::Type::kInt64) {
Chris Larsen97759342016-02-16 17:10:40 -08001939 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1940 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1941 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1942 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1943
1944 __ Subu(TMP, ZERO, in_lo);
1945 __ And(out_lo, TMP, in_lo);
1946 __ Subu(TMP, ZERO, in_hi);
1947 __ And(out_hi, TMP, in_hi);
1948 if (isR6) {
1949 __ Seleqz(out_hi, out_hi, out_lo);
1950 } else {
1951 __ Movn(out_hi, ZERO, out_lo);
1952 }
1953 } else {
1954 Register in = locations->InAt(0).AsRegister<Register>();
1955 Register out = locations->Out().AsRegister<Register>();
1956
1957 __ Subu(TMP, ZERO, in);
1958 __ And(out, TMP, in);
1959 }
1960}
1961
1962// int java.lang.Integer.lowestOneBit(int)
1963void IntrinsicLocationsBuilderMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001964 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08001965}
1966
1967void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001968 GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08001969}
1970
1971// long java.lang.Long.lowestOneBit(long)
1972void IntrinsicLocationsBuilderMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001973 CreateIntToIntLocations(allocator_, invoke);
Chris Larsen97759342016-02-16 17:10:40 -08001974}
1975
1976void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001977 GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler());
Chris Larsen97759342016-02-16 17:10:40 -08001978}
1979
Chris Larsenf09d5322016-04-22 12:06:34 -07001980// int java.lang.Math.round(float)
1981void IntrinsicLocationsBuilderMIPS::VisitMathRoundFloat(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001982 LocationSummary* locations =
1983 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsenf09d5322016-04-22 12:06:34 -07001984 locations->SetInAt(0, Location::RequiresFpuRegister());
1985 locations->AddTemp(Location::RequiresFpuRegister());
1986 locations->SetOut(Location::RequiresRegister());
1987}
1988
1989void IntrinsicCodeGeneratorMIPS::VisitMathRoundFloat(HInvoke* invoke) {
1990 LocationSummary* locations = invoke->GetLocations();
1991 MipsAssembler* assembler = GetAssembler();
1992 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
1993 FRegister half = locations->GetTemp(0).AsFpuRegister<FRegister>();
1994 Register out = locations->Out().AsRegister<Register>();
1995
1996 MipsLabel done;
Chris Larsenf09d5322016-04-22 12:06:34 -07001997
Chris Larsenf09d5322016-04-22 12:06:34 -07001998 if (IsR6()) {
Lena Djokicf4e23a82017-05-09 15:43:45 +02001999 // out = floor(in);
2000 //
2001 // if (out != MAX_VALUE && out != MIN_VALUE) {
2002 // TMP = ((in - out) >= 0.5) ? 1 : 0;
2003 // return out += TMP;
2004 // }
2005 // return out;
Chris Larsenf09d5322016-04-22 12:06:34 -07002006
Lena Djokicf4e23a82017-05-09 15:43:45 +02002007 // out = floor(in);
2008 __ FloorWS(FTMP, in);
2009 __ Mfc1(out, FTMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002010
Lena Djokicf4e23a82017-05-09 15:43:45 +02002011 // if (out != MAX_VALUE && out != MIN_VALUE)
2012 __ Addiu(TMP, out, 1);
2013 __ Aui(TMP, TMP, 0x8000); // TMP = out + 0x8000 0001
2014 // or out - 0x7FFF FFFF.
2015 // IOW, TMP = 1 if out = Int.MIN_VALUE
2016 // or TMP = 0 if out = Int.MAX_VALUE.
2017 __ Srl(TMP, TMP, 1); // TMP = 0 if out = Int.MIN_VALUE
2018 // or out = Int.MAX_VALUE.
2019 __ Beqz(TMP, &done);
Chris Larsenf09d5322016-04-22 12:06:34 -07002020
Lena Djokicf4e23a82017-05-09 15:43:45 +02002021 // TMP = (0.5f <= (in - out)) ? -1 : 0;
2022 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
2023 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
2024 __ SubS(FTMP, in, FTMP);
2025 __ Mtc1(AT, half);
Chris Larsenf09d5322016-04-22 12:06:34 -07002026
Chris Larsenf09d5322016-04-22 12:06:34 -07002027 __ CmpLeS(FTMP, half, FTMP);
Chris Larsen07f712f2016-06-10 16:06:02 -07002028 __ Mfc1(TMP, FTMP);
Lena Djokicf4e23a82017-05-09 15:43:45 +02002029
2030 // Return out -= TMP.
2031 __ Subu(out, out, TMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002032 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +02002033 // if (in.isNaN) {
2034 // return 0;
2035 // }
2036 //
2037 // out = floor.w.s(in);
2038 //
2039 // /*
2040 // * This "if" statement is only needed for the pre-R6 version of floor.w.s
2041 // * which outputs Integer.MAX_VALUE for negative numbers with magnitudes
2042 // * too large to fit in a 32-bit integer.
2043 // */
2044 // if (out == Integer.MAX_VALUE) {
2045 // TMP = (in < 0.0f) ? 1 : 0;
2046 // /*
2047 // * If TMP is 1, then adding it to out will wrap its value from
2048 // * Integer.MAX_VALUE to Integer.MIN_VALUE.
2049 // */
2050 // return out += TMP;
2051 // }
2052 //
2053 // /*
2054 // * For negative values not handled by the previous "if" statement the
2055 // * test here will correctly set the value of TMP.
2056 // */
2057 // TMP = ((in - out) >= 0.5f) ? 1 : 0;
2058 // return out += TMP;
2059
2060 MipsLabel finite;
2061 MipsLabel add;
2062
2063 // Test for NaN.
2064 __ CunS(in, in);
2065
2066 // Return zero for NaN.
2067 __ Move(out, ZERO);
2068 __ Bc1t(&done);
2069
2070 // out = floor(in);
2071 __ FloorWS(FTMP, in);
2072 __ Mfc1(out, FTMP);
2073
2074 __ LoadConst32(TMP, -1);
2075
2076 // TMP = (out = java.lang.Integer.MAX_VALUE) ? -1 : 0;
2077 __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
2078 __ Bne(AT, out, &finite);
2079
2080 __ Mtc1(ZERO, FTMP);
2081 __ ColtS(in, FTMP);
2082
2083 __ B(&add);
2084
2085 __ Bind(&finite);
2086
2087 // TMP = (0.5f <= (in - out)) ? -1 : 0;
2088 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
2089 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
2090 __ SubS(FTMP, in, FTMP);
2091 __ Mtc1(AT, half);
Chris Larsenf09d5322016-04-22 12:06:34 -07002092 __ ColeS(half, FTMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002093
Lena Djokicf4e23a82017-05-09 15:43:45 +02002094 __ Bind(&add);
Chris Larsenf09d5322016-04-22 12:06:34 -07002095
Chris Larsenf09d5322016-04-22 12:06:34 -07002096 __ Movf(TMP, ZERO);
Lena Djokicf4e23a82017-05-09 15:43:45 +02002097
2098 // Return out -= TMP.
2099 __ Subu(out, out, TMP);
Chris Larsenf09d5322016-04-22 12:06:34 -07002100 }
Chris Larsenf09d5322016-04-22 12:06:34 -07002101 __ Bind(&done);
2102}
2103
Chris Larsen692235e2016-11-21 16:04:53 -08002104// void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
2105void IntrinsicLocationsBuilderMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002106 LocationSummary* locations =
2107 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
Chris Larsen692235e2016-11-21 16:04:53 -08002108 locations->SetInAt(0, Location::RequiresRegister());
2109 locations->SetInAt(1, Location::RequiresRegister());
2110 locations->SetInAt(2, Location::RequiresRegister());
2111 locations->SetInAt(3, Location::RequiresRegister());
2112 locations->SetInAt(4, Location::RequiresRegister());
2113
Chris Larsenfe4ff442017-03-23 11:25:12 -07002114 locations->AddTemp(Location::RequiresRegister());
2115 locations->AddTemp(Location::RequiresRegister());
2116 locations->AddTemp(Location::RequiresRegister());
Chris Larsen692235e2016-11-21 16:04:53 -08002117}
2118
2119void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2120 MipsAssembler* assembler = GetAssembler();
2121 LocationSummary* locations = invoke->GetLocations();
2122
2123 // Check assumption that sizeof(Char) is 2 (used in scaling below).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002124 const size_t char_size = DataType::Size(DataType::Type::kUint16);
Chris Larsen692235e2016-11-21 16:04:53 -08002125 DCHECK_EQ(char_size, 2u);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002126 const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
Chris Larsen692235e2016-11-21 16:04:53 -08002127
2128 Register srcObj = locations->InAt(0).AsRegister<Register>();
2129 Register srcBegin = locations->InAt(1).AsRegister<Register>();
2130 Register srcEnd = locations->InAt(2).AsRegister<Register>();
2131 Register dstObj = locations->InAt(3).AsRegister<Register>();
2132 Register dstBegin = locations->InAt(4).AsRegister<Register>();
2133
2134 Register dstPtr = locations->GetTemp(0).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002135 Register srcPtr = locations->GetTemp(1).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002136 Register numChrs = locations->GetTemp(2).AsRegister<Register>();
Chris Larsen692235e2016-11-21 16:04:53 -08002137
2138 MipsLabel done;
Chris Larsenfe4ff442017-03-23 11:25:12 -07002139 MipsLabel loop;
Chris Larsen692235e2016-11-21 16:04:53 -08002140
2141 // Location of data in char array buffer.
2142 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2143
2144 // Get offset of value field within a string object.
2145 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2146
2147 __ Beq(srcEnd, srcBegin, &done); // No characters to move.
2148
2149 // Calculate number of characters to be copied.
2150 __ Subu(numChrs, srcEnd, srcBegin);
2151
2152 // Calculate destination address.
2153 __ Addiu(dstPtr, dstObj, data_offset);
Chris Larsencd0295d2017-03-31 15:26:54 -07002154 __ ShiftAndAdd(dstPtr, dstBegin, dstPtr, char_shift);
Chris Larsen692235e2016-11-21 16:04:53 -08002155
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002156 if (mirror::kUseStringCompression) {
2157 MipsLabel uncompressed_copy, compressed_loop;
2158 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2159 // Load count field and extract compression flag.
2160 __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
2161 __ Sll(TMP, TMP, 31);
2162
Chris Larsenfe4ff442017-03-23 11:25:12 -07002163 // If string is uncompressed, use uncompressed path.
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002164 __ Bnez(TMP, &uncompressed_copy);
2165
2166 // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
2167 __ Addu(srcPtr, srcObj, srcBegin);
2168 __ Bind(&compressed_loop);
2169 __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
2170 __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
2171 __ Addiu(numChrs, numChrs, -1);
2172 __ Addiu(srcPtr, srcPtr, 1);
2173 __ Addiu(dstPtr, dstPtr, 2);
2174 __ Bnez(numChrs, &compressed_loop);
2175
2176 __ B(&done);
2177 __ Bind(&uncompressed_copy);
2178 }
2179
Chris Larsen692235e2016-11-21 16:04:53 -08002180 // Calculate source address.
2181 __ Addiu(srcPtr, srcObj, value_offset);
Chris Larsencd0295d2017-03-31 15:26:54 -07002182 __ ShiftAndAdd(srcPtr, srcBegin, srcPtr, char_shift);
Chris Larsen692235e2016-11-21 16:04:53 -08002183
Chris Larsenfe4ff442017-03-23 11:25:12 -07002184 __ Bind(&loop);
2185 __ Lh(AT, srcPtr, 0);
2186 __ Addiu(numChrs, numChrs, -1);
2187 __ Addiu(srcPtr, srcPtr, char_size);
2188 __ Sh(AT, dstPtr, 0);
2189 __ Addiu(dstPtr, dstPtr, char_size);
2190 __ Bnez(numChrs, &loop);
Chris Larsen692235e2016-11-21 16:04:53 -08002191
2192 __ Bind(&done);
2193}
2194
Vladimir Markoca6fff82017-10-03 14:49:14 +01002195static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2196 LocationSummary* locations =
2197 new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002198 InvokeRuntimeCallingConvention calling_convention;
2199
2200 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002201 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
Chris Larsenb9005fa2017-03-24 12:11:54 -07002202}
2203
Vladimir Markoca6fff82017-10-03 14:49:14 +01002204static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2205 LocationSummary* locations =
2206 new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002207 InvokeRuntimeCallingConvention calling_convention;
2208
2209 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2210 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002211 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
Chris Larsenb9005fa2017-03-24 12:11:54 -07002212}
2213
2214static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
2215 LocationSummary* locations = invoke->GetLocations();
2216 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2217 DCHECK_EQ(in, F12);
2218 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2219 DCHECK_EQ(out, F0);
2220
2221 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2222}
2223
2224static void GenFPFPToFPCall(HInvoke* invoke,
2225 CodeGeneratorMIPS* codegen,
2226 QuickEntrypointEnum entry) {
2227 LocationSummary* locations = invoke->GetLocations();
2228 FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
2229 DCHECK_EQ(in0, F12);
2230 FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
2231 DCHECK_EQ(in1, F14);
2232 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2233 DCHECK_EQ(out, F0);
2234
2235 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2236}
2237
2238// static double java.lang.Math.cos(double a)
2239void IntrinsicLocationsBuilderMIPS::VisitMathCos(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002240 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002241}
2242
2243void IntrinsicCodeGeneratorMIPS::VisitMathCos(HInvoke* invoke) {
2244 GenFPToFPCall(invoke, codegen_, kQuickCos);
2245}
2246
2247// static double java.lang.Math.sin(double a)
2248void IntrinsicLocationsBuilderMIPS::VisitMathSin(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002249 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002250}
2251
2252void IntrinsicCodeGeneratorMIPS::VisitMathSin(HInvoke* invoke) {
2253 GenFPToFPCall(invoke, codegen_, kQuickSin);
2254}
2255
2256// static double java.lang.Math.acos(double a)
2257void IntrinsicLocationsBuilderMIPS::VisitMathAcos(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002258 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002259}
2260
2261void IntrinsicCodeGeneratorMIPS::VisitMathAcos(HInvoke* invoke) {
2262 GenFPToFPCall(invoke, codegen_, kQuickAcos);
2263}
2264
2265// static double java.lang.Math.asin(double a)
2266void IntrinsicLocationsBuilderMIPS::VisitMathAsin(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002267 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002268}
2269
2270void IntrinsicCodeGeneratorMIPS::VisitMathAsin(HInvoke* invoke) {
2271 GenFPToFPCall(invoke, codegen_, kQuickAsin);
2272}
2273
2274// static double java.lang.Math.atan(double a)
2275void IntrinsicLocationsBuilderMIPS::VisitMathAtan(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002276 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002277}
2278
2279void IntrinsicCodeGeneratorMIPS::VisitMathAtan(HInvoke* invoke) {
2280 GenFPToFPCall(invoke, codegen_, kQuickAtan);
2281}
2282
2283// static double java.lang.Math.atan2(double y, double x)
2284void IntrinsicLocationsBuilderMIPS::VisitMathAtan2(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002285 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002286}
2287
2288void IntrinsicCodeGeneratorMIPS::VisitMathAtan2(HInvoke* invoke) {
2289 GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
2290}
2291
Vladimir Marko4d179872018-01-19 14:50:10 +00002292// static double java.lang.Math.pow(double y, double x)
2293void IntrinsicLocationsBuilderMIPS::VisitMathPow(HInvoke* invoke) {
2294 CreateFPFPToFPCallLocations(allocator_, invoke);
2295}
2296
2297void IntrinsicCodeGeneratorMIPS::VisitMathPow(HInvoke* invoke) {
2298 GenFPFPToFPCall(invoke, codegen_, kQuickPow);
2299}
2300
Chris Larsenb9005fa2017-03-24 12:11:54 -07002301// static double java.lang.Math.cbrt(double a)
2302void IntrinsicLocationsBuilderMIPS::VisitMathCbrt(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002303 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002304}
2305
2306void IntrinsicCodeGeneratorMIPS::VisitMathCbrt(HInvoke* invoke) {
2307 GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2308}
2309
2310// static double java.lang.Math.cosh(double x)
2311void IntrinsicLocationsBuilderMIPS::VisitMathCosh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002312 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002313}
2314
2315void IntrinsicCodeGeneratorMIPS::VisitMathCosh(HInvoke* invoke) {
2316 GenFPToFPCall(invoke, codegen_, kQuickCosh);
2317}
2318
2319// static double java.lang.Math.exp(double a)
2320void IntrinsicLocationsBuilderMIPS::VisitMathExp(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002321 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002322}
2323
2324void IntrinsicCodeGeneratorMIPS::VisitMathExp(HInvoke* invoke) {
2325 GenFPToFPCall(invoke, codegen_, kQuickExp);
2326}
2327
2328// static double java.lang.Math.expm1(double x)
2329void IntrinsicLocationsBuilderMIPS::VisitMathExpm1(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002330 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002331}
2332
2333void IntrinsicCodeGeneratorMIPS::VisitMathExpm1(HInvoke* invoke) {
2334 GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2335}
2336
2337// static double java.lang.Math.hypot(double x, double y)
2338void IntrinsicLocationsBuilderMIPS::VisitMathHypot(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002339 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002340}
2341
2342void IntrinsicCodeGeneratorMIPS::VisitMathHypot(HInvoke* invoke) {
2343 GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
2344}
2345
2346// static double java.lang.Math.log(double a)
2347void IntrinsicLocationsBuilderMIPS::VisitMathLog(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002348 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002349}
2350
2351void IntrinsicCodeGeneratorMIPS::VisitMathLog(HInvoke* invoke) {
2352 GenFPToFPCall(invoke, codegen_, kQuickLog);
2353}
2354
2355// static double java.lang.Math.log10(double x)
2356void IntrinsicLocationsBuilderMIPS::VisitMathLog10(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002357 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002358}
2359
2360void IntrinsicCodeGeneratorMIPS::VisitMathLog10(HInvoke* invoke) {
2361 GenFPToFPCall(invoke, codegen_, kQuickLog10);
2362}
2363
2364// static double java.lang.Math.nextAfter(double start, double direction)
2365void IntrinsicLocationsBuilderMIPS::VisitMathNextAfter(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002366 CreateFPFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002367}
2368
2369void IntrinsicCodeGeneratorMIPS::VisitMathNextAfter(HInvoke* invoke) {
2370 GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
2371}
2372
2373// static double java.lang.Math.sinh(double x)
2374void IntrinsicLocationsBuilderMIPS::VisitMathSinh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002375 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002376}
2377
2378void IntrinsicCodeGeneratorMIPS::VisitMathSinh(HInvoke* invoke) {
2379 GenFPToFPCall(invoke, codegen_, kQuickSinh);
2380}
2381
2382// static double java.lang.Math.tan(double a)
2383void IntrinsicLocationsBuilderMIPS::VisitMathTan(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002384 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002385}
2386
2387void IntrinsicCodeGeneratorMIPS::VisitMathTan(HInvoke* invoke) {
2388 GenFPToFPCall(invoke, codegen_, kQuickTan);
2389}
2390
2391// static double java.lang.Math.tanh(double x)
2392void IntrinsicLocationsBuilderMIPS::VisitMathTanh(HInvoke* invoke) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002393 CreateFPToFPCallLocations(allocator_, invoke);
Chris Larsenb9005fa2017-03-24 12:11:54 -07002394}
2395
2396void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
2397 GenFPToFPCall(invoke, codegen_, kQuickTanh);
2398}
2399
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002400// static void java.lang.System.arraycopy(Object src, int srcPos,
2401// Object dest, int destPos,
2402// int length)
2403void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
2404 HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
2405 HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
2406 HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
2407
2408 // As long as we are checking, we might as well check to see if the src and dest
2409 // positions are >= 0.
2410 if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2411 (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
2412 // We will have to fail anyways.
2413 return;
2414 }
2415
2416 // And since we are already checking, check the length too.
2417 if (length != nullptr) {
2418 int32_t len = length->GetValue();
2419 if (len < 0) {
2420 // Just call as normal.
2421 return;
2422 }
2423 }
2424
2425 // Okay, it is safe to generate inline code.
2426 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002427 new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002428 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
2429 locations->SetInAt(0, Location::RequiresRegister());
2430 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
2431 locations->SetInAt(2, Location::RequiresRegister());
2432 locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
2433 locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
2434
2435 locations->AddTemp(Location::RequiresRegister());
2436 locations->AddTemp(Location::RequiresRegister());
2437 locations->AddTemp(Location::RequiresRegister());
2438}
2439
2440// Utility routine to verify that "length(input) - pos >= length"
2441static void EnoughItems(MipsAssembler* assembler,
2442 Register length_input_minus_pos,
2443 Location length,
2444 SlowPathCodeMIPS* slow_path) {
2445 if (length.IsConstant()) {
2446 int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
2447
2448 if (IsInt<16>(length_constant)) {
2449 __ Slti(TMP, length_input_minus_pos, length_constant);
2450 __ Bnez(TMP, slow_path->GetEntryLabel());
2451 } else {
2452 __ LoadConst32(TMP, length_constant);
2453 __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
2454 }
2455 } else {
2456 __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
2457 }
2458}
2459
2460static void CheckPosition(MipsAssembler* assembler,
2461 Location pos,
2462 Register input,
2463 Location length,
2464 SlowPathCodeMIPS* slow_path,
2465 bool length_is_input_length = false) {
2466 // Where is the length in the Array?
2467 const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
2468
2469 // Calculate length(input) - pos.
2470 if (pos.IsConstant()) {
2471 int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
2472 if (pos_const == 0) {
2473 if (!length_is_input_length) {
2474 // Check that length(input) >= length.
2475 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2476 EnoughItems(assembler, AT, length, slow_path);
2477 }
2478 } else {
2479 // Check that (length(input) - pos) >= zero.
2480 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2481 DCHECK_GT(pos_const, 0);
2482 __ Addiu32(AT, AT, -pos_const, TMP);
2483 __ Bltz(AT, slow_path->GetEntryLabel());
2484
2485 // Verify that (length(input) - pos) >= length.
2486 EnoughItems(assembler, AT, length, slow_path);
2487 }
2488 } else if (length_is_input_length) {
2489 // The only way the copy can succeed is if pos is zero.
2490 Register pos_reg = pos.AsRegister<Register>();
2491 __ Bnez(pos_reg, slow_path->GetEntryLabel());
2492 } else {
2493 // Verify that pos >= 0.
2494 Register pos_reg = pos.AsRegister<Register>();
2495 __ Bltz(pos_reg, slow_path->GetEntryLabel());
2496
2497 // Check that (length(input) - pos) >= zero.
2498 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2499 __ Subu(AT, AT, pos_reg);
2500 __ Bltz(AT, slow_path->GetEntryLabel());
2501
2502 // Verify that (length(input) - pos) >= length.
2503 EnoughItems(assembler, AT, length, slow_path);
2504 }
2505}
2506
2507void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
2508 MipsAssembler* assembler = GetAssembler();
2509 LocationSummary* locations = invoke->GetLocations();
2510
2511 Register src = locations->InAt(0).AsRegister<Register>();
2512 Location src_pos = locations->InAt(1);
2513 Register dest = locations->InAt(2).AsRegister<Register>();
2514 Location dest_pos = locations->InAt(3);
2515 Location length = locations->InAt(4);
2516
2517 MipsLabel loop;
2518
2519 Register dest_base = locations->GetTemp(0).AsRegister<Register>();
2520 Register src_base = locations->GetTemp(1).AsRegister<Register>();
2521 Register count = locations->GetTemp(2).AsRegister<Register>();
2522
Vladimir Marko174b2e22017-10-12 13:34:49 +01002523 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS(invoke);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002524 codegen_->AddSlowPath(slow_path);
2525
2526 // Bail out if the source and destination are the same (to handle overlap).
2527 __ Beq(src, dest, slow_path->GetEntryLabel());
2528
2529 // Bail out if the source is null.
2530 __ Beqz(src, slow_path->GetEntryLabel());
2531
2532 // Bail out if the destination is null.
2533 __ Beqz(dest, slow_path->GetEntryLabel());
2534
2535 // Load length into register for count.
2536 if (length.IsConstant()) {
2537 __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
2538 } else {
2539 // If the length is negative, bail out.
2540 // We have already checked in the LocationsBuilder for the constant case.
2541 __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
2542
2543 __ Move(count, length.AsRegister<Register>());
2544 }
2545
2546 // Validity checks: source.
2547 CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
2548
2549 // Validity checks: dest.
2550 CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
2551
2552 // If count is zero, we're done.
2553 __ Beqz(count, slow_path->GetExitLabel());
2554
2555 // Okay, everything checks out. Finally time to do the copy.
2556 // Check assumption that sizeof(Char) is 2 (used in scaling below).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002557 const size_t char_size = DataType::Size(DataType::Type::kUint16);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002558 DCHECK_EQ(char_size, 2u);
2559
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002560 const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
Chris Larsen2f6ad9d2017-03-23 15:37:03 -07002561
2562 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2563
2564 // Calculate source and destination addresses.
2565 if (src_pos.IsConstant()) {
2566 int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
2567
2568 __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
2569 } else {
2570 __ Addiu32(src_base, src, data_offset, TMP);
2571 __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
2572 }
2573 if (dest_pos.IsConstant()) {
2574 int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
2575
2576 __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
2577 } else {
2578 __ Addiu32(dest_base, dest, data_offset, TMP);
2579 __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
2580 }
2581
2582 __ Bind(&loop);
2583 __ Lh(TMP, src_base, 0);
2584 __ Addiu(src_base, src_base, char_size);
2585 __ Addiu(count, count, -1);
2586 __ Sh(TMP, dest_base, 0);
2587 __ Addiu(dest_base, dest_base, char_size);
2588 __ Bnez(count, &loop);
2589
2590 __ Bind(slow_path->GetExitLabel());
2591}
2592
Chris Larsen5633ce72017-04-10 15:47:40 -07002593// long java.lang.Integer.valueOf(long)
2594void IntrinsicLocationsBuilderMIPS::VisitIntegerValueOf(HInvoke* invoke) {
2595 InvokeRuntimeCallingConvention calling_convention;
2596 IntrinsicVisitor::ComputeIntegerValueOfLocations(
2597 invoke,
2598 codegen_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002599 calling_convention.GetReturnLocation(DataType::Type::kReference),
Chris Larsen5633ce72017-04-10 15:47:40 -07002600 Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2601}
2602
2603void IntrinsicCodeGeneratorMIPS::VisitIntegerValueOf(HInvoke* invoke) {
2604 IntrinsicVisitor::IntegerValueOfInfo info = IntrinsicVisitor::ComputeIntegerValueOfInfo();
2605 LocationSummary* locations = invoke->GetLocations();
2606 MipsAssembler* assembler = GetAssembler();
2607 InstructionCodeGeneratorMIPS* icodegen =
2608 down_cast<InstructionCodeGeneratorMIPS*>(codegen_->GetInstructionVisitor());
2609
2610 Register out = locations->Out().AsRegister<Register>();
2611 InvokeRuntimeCallingConvention calling_convention;
2612 if (invoke->InputAt(0)->IsConstant()) {
2613 int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
2614 if (value >= info.low && value <= info.high) {
2615 // Just embed the j.l.Integer in the code.
2616 ScopedObjectAccess soa(Thread::Current());
2617 mirror::Object* boxed = info.cache->Get(value + (-info.low));
2618 DCHECK(boxed != nullptr && Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
2619 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(boxed));
2620 __ LoadConst32(out, address);
2621 } else {
2622 // Allocate and initialize a new j.l.Integer.
2623 // TODO: If we JIT, we could allocate the j.l.Integer now, and store it in the
2624 // JIT object table.
2625 uint32_t address =
2626 dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
2627 __ LoadConst32(calling_convention.GetRegisterAt(0), address);
2628 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
2629 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
2630 __ StoreConstToOffset(kStoreWord, value, out, info.value_offset, TMP);
2631 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
2632 // one.
2633 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2634 }
2635 } else {
2636 Register in = locations->InAt(0).AsRegister<Register>();
2637 MipsLabel allocate, done;
2638 int32_t count = static_cast<uint32_t>(info.high) - info.low + 1;
2639
2640 // Is (info.low <= in) && (in <= info.high)?
2641 __ Addiu32(out, in, -info.low);
2642 // As unsigned quantities is out < (info.high - info.low + 1)?
2643 if (IsInt<16>(count)) {
2644 __ Sltiu(AT, out, count);
2645 } else {
2646 __ LoadConst32(AT, count);
2647 __ Sltu(AT, out, AT);
2648 }
2649 // Branch if out >= (info.high - info.low + 1).
2650 // This means that "in" is outside of the range [info.low, info.high].
2651 __ Beqz(AT, &allocate);
2652
2653 // If the value is within the bounds, load the j.l.Integer directly from the array.
2654 uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
2655 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
2656 __ LoadConst32(TMP, data_offset + address);
2657 __ ShiftAndAdd(out, out, TMP, TIMES_4);
2658 __ Lw(out, out, 0);
2659 __ MaybeUnpoisonHeapReference(out);
2660 __ B(&done);
2661
2662 __ Bind(&allocate);
2663 // Otherwise allocate and initialize a new j.l.Integer.
2664 address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
2665 __ LoadConst32(calling_convention.GetRegisterAt(0), address);
2666 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
2667 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
2668 __ StoreToOffset(kStoreWord, in, out, info.value_offset);
2669 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
2670 // one.
2671 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2672 __ Bind(&done);
2673 }
2674}
2675
Chris Larsenb065b032017-11-02 12:13:20 -07002676// static boolean java.lang.Thread.interrupted()
2677void IntrinsicLocationsBuilderMIPS::VisitThreadInterrupted(HInvoke* invoke) {
2678 LocationSummary* locations =
2679 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2680 locations->SetOut(Location::RequiresRegister());
2681}
2682
2683void IntrinsicCodeGeneratorMIPS::VisitThreadInterrupted(HInvoke* invoke) {
2684 MipsAssembler* assembler = GetAssembler();
2685 Register out = invoke->GetLocations()->Out().AsRegister<Register>();
2686 int32_t offset = Thread::InterruptedOffset<kMipsPointerSize>().Int32Value();
2687 __ LoadFromOffset(kLoadWord, out, TR, offset);
2688 MipsLabel done;
2689 __ Beqz(out, &done);
2690 __ Sync(0);
2691 __ StoreToOffset(kStoreWord, ZERO, TR, offset);
2692 __ Sync(0);
2693 __ Bind(&done);
2694}
2695
Hans Boehmc7b28de2018-03-09 17:05:28 -08002696void IntrinsicLocationsBuilderMIPS::VisitReachabilityFence(HInvoke* invoke) {
2697 LocationSummary* locations =
2698 new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2699 locations->SetInAt(0, Location::Any());
2700}
2701
2702void IntrinsicCodeGeneratorMIPS::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { }
2703
Chris Larsen2714fe62016-02-11 14:23:53 -08002704// Unimplemented intrinsics.
2705
Aart Bik2f9fcc92016-03-01 15:16:54 -08002706UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
2707UNIMPLEMENTED_INTRINSIC(MIPS, MathFloor)
2708UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
2709UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
Alexey Frunze15958152017-02-09 19:08:30 -08002710UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetLongVolatile);
2711UNIMPLEMENTED_INTRINSIC(MIPS, UnsafePutLongVolatile);
Aart Bik2f9fcc92016-03-01 15:16:54 -08002712UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
Chris Larsen701566a2015-10-27 15:29:13 -07002713
Aart Bik2f9fcc92016-03-01 15:16:54 -08002714UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
Aart Bik2f9fcc92016-03-01 15:16:54 -08002715UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
Aart Bik3f67e692016-01-15 14:35:12 -08002716
Aart Bikff7d89c2016-11-07 08:49:28 -08002717UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
2718UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
Aart Bik71bf7b42016-11-16 10:17:46 -08002719UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
2720UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferLength);
2721UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferToString);
2722UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderAppend);
2723UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderLength);
2724UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderToString);
Aart Bikff7d89c2016-11-07 08:49:28 -08002725
Aart Bik0e54c012016-03-04 12:08:31 -08002726// 1.8.
2727UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddInt)
2728UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddLong)
2729UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt)
2730UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong)
2731UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject)
Chris Larsen701566a2015-10-27 15:29:13 -07002732
Aart Bik0e54c012016-03-04 12:08:31 -08002733UNREACHABLE_INTRINSICS(MIPS)
Chris Larsen2714fe62016-02-11 14:23:53 -08002734
Chris Larsen701566a2015-10-27 15:29:13 -07002735#undef __
2736
2737} // namespace mips
2738} // namespace art