blob: a94e3a8c23b26091e63c768ab1d7bb65ec71443a [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"
23#include "intrinsics.h"
24#include "mirror/array-inl.h"
25#include "mirror/string.h"
26#include "thread.h"
27#include "utils/mips/assembler_mips.h"
28#include "utils/mips/constants_mips.h"
29
30namespace art {
31
32namespace mips {
33
34IntrinsicLocationsBuilderMIPS::IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS* codegen)
35 : arena_(codegen->GetGraph()->GetArena()) {
36}
37
38MipsAssembler* IntrinsicCodeGeneratorMIPS::GetAssembler() {
39 return reinterpret_cast<MipsAssembler*>(codegen_->GetAssembler());
40}
41
42ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() {
43 return codegen_->GetGraph()->GetArena();
44}
45
46#define __ codegen->GetAssembler()->
47
48static void MoveFromReturnRegister(Location trg,
49 Primitive::Type type,
50 CodeGeneratorMIPS* codegen) {
51 if (!trg.IsValid()) {
52 DCHECK_EQ(type, Primitive::kPrimVoid);
53 return;
54 }
55
56 DCHECK_NE(type, Primitive::kPrimVoid);
57
58 if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
59 Register trg_reg = trg.AsRegister<Register>();
60 if (trg_reg != V0) {
61 __ Move(V0, trg_reg);
62 }
63 } else {
64 FRegister trg_reg = trg.AsFpuRegister<FRegister>();
65 if (trg_reg != F0) {
66 if (type == Primitive::kPrimFloat) {
67 __ MovS(F0, trg_reg);
68 } else {
69 __ MovD(F0, trg_reg);
70 }
71 }
72 }
73}
74
75static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
76 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
77 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
78}
79
80// Slow-path for fallback (calling the managed code to handle the
81// intrinsic) in an intrinsified call. This will copy the arguments
82// into the positions for a regular call.
83//
84// Note: The actual parameters are required to be in the locations
85// given by the invoke's location summary. If an intrinsic
86// modifies those locations before a slowpath call, they must be
87// restored!
88class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
89 public:
90 explicit IntrinsicSlowPathMIPS(HInvoke* invoke) : invoke_(invoke) { }
91
92 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
93 CodeGeneratorMIPS* codegen = down_cast<CodeGeneratorMIPS*>(codegen_in);
94
95 __ Bind(GetEntryLabel());
96
97 SaveLiveRegisters(codegen, invoke_->GetLocations());
98
99 MoveArguments(invoke_, codegen);
100
101 if (invoke_->IsInvokeStaticOrDirect()) {
102 codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
103 Location::RegisterLocation(A0));
104 codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
105 } else {
106 UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
107 UNREACHABLE();
108 }
109
110 // Copy the result back to the expected output.
111 Location out = invoke_->GetLocations()->Out();
112 if (out.IsValid()) {
113 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory.
114 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
115 MoveFromReturnRegister(out, invoke_->GetType(), codegen);
116 }
117
118 RestoreLiveRegisters(codegen, invoke_->GetLocations());
119 __ B(GetExitLabel());
120 }
121
122 const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS"; }
123
124 private:
125 // The instruction where this slow path is happening.
126 HInvoke* const invoke_;
127
128 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS);
129};
130
131#undef __
132
133bool IntrinsicLocationsBuilderMIPS::TryDispatch(HInvoke* invoke) {
134 Dispatch(invoke);
135 LocationSummary* res = invoke->GetLocations();
136 return res != nullptr && res->Intrinsified();
137}
138
139#define __ assembler->
140
Chris Larsen16ba2b42015-11-02 10:58:31 -0800141// boolean java.lang.String.equals(Object anObject)
142void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
143 LocationSummary* locations = new (arena_) LocationSummary(invoke,
144 LocationSummary::kNoCall,
145 kIntrinsified);
146 locations->SetInAt(0, Location::RequiresRegister());
147 locations->SetInAt(1, Location::RequiresRegister());
148 locations->SetOut(Location::RequiresRegister());
149
150 // Temporary registers to store lengths of strings and for calculations.
151 locations->AddTemp(Location::RequiresRegister());
152 locations->AddTemp(Location::RequiresRegister());
153 locations->AddTemp(Location::RequiresRegister());
154}
155
156void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) {
157 MipsAssembler* assembler = GetAssembler();
158 LocationSummary* locations = invoke->GetLocations();
159
160 Register str = locations->InAt(0).AsRegister<Register>();
161 Register arg = locations->InAt(1).AsRegister<Register>();
162 Register out = locations->Out().AsRegister<Register>();
163
164 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
165 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
166 Register temp3 = locations->GetTemp(2).AsRegister<Register>();
167
168 MipsLabel loop;
169 MipsLabel end;
170 MipsLabel return_true;
171 MipsLabel return_false;
172
173 // Get offsets of count, value, and class fields within a string object.
174 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
175 const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
176 const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
177
178 // Note that the null check must have been done earlier.
179 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
180
181 // If the register containing the pointer to "this", and the register
182 // containing the pointer to "anObject" are the same register then
183 // "this", and "anObject" are the same object and we can
184 // short-circuit the logic to a true result.
185 if (str == arg) {
186 __ LoadConst32(out, 1);
187 return;
188 }
189
190 // Check if input is null, return false if it is.
191 __ Beqz(arg, &return_false);
192
193 // Reference equality check, return true if same reference.
194 __ Beq(str, arg, &return_true);
195
196 // Instanceof check for the argument by comparing class fields.
197 // All string objects must have the same type since String cannot be subclassed.
198 // Receiver must be a string object, so its class field is equal to all strings' class fields.
199 // If the argument is a string object, its class field must be equal to receiver's class field.
200 __ Lw(temp1, str, class_offset);
201 __ Lw(temp2, arg, class_offset);
202 __ Bne(temp1, temp2, &return_false);
203
204 // Load lengths of this and argument strings.
205 __ Lw(temp1, str, count_offset);
206 __ Lw(temp2, arg, count_offset);
207 // Check if lengths are equal, return false if they're not.
208 __ Bne(temp1, temp2, &return_false);
209 // Return true if both strings are empty.
210 __ Beqz(temp1, &return_true);
211
212 // Don't overwrite input registers
213 __ Move(TMP, str);
214 __ Move(temp3, arg);
215
216 // Assertions that must hold in order to compare strings 2 characters at a time.
217 DCHECK_ALIGNED(value_offset, 4);
218 static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
219
220 // Loop to compare strings 2 characters at a time starting at the beginning of the string.
221 // Ok to do this because strings are zero-padded.
222 __ Bind(&loop);
223 __ Lw(out, TMP, value_offset);
224 __ Lw(temp2, temp3, value_offset);
225 __ Bne(out, temp2, &return_false);
226 __ Addiu(TMP, TMP, 4);
227 __ Addiu(temp3, temp3, 4);
228 __ Addiu(temp1, temp1, -2);
229 __ Bgtz(temp1, &loop);
230
231 // Return true and exit the function.
232 // If loop does not result in returning false, we return true.
233 __ Bind(&return_true);
234 __ LoadConst32(out, 1);
235 __ B(&end);
236
237 // Return false and exit the function.
238 __ Bind(&return_false);
239 __ LoadConst32(out, 0);
240 __ Bind(&end);
241}
242
Chris Larsen701566a2015-10-27 15:29:13 -0700243// Unimplemented intrinsics.
244
245#define UNIMPLEMENTED_INTRINSIC(Name) \
246void IntrinsicLocationsBuilderMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
247} \
248void IntrinsicCodeGeneratorMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
249}
250
251UNIMPLEMENTED_INTRINSIC(IntegerReverse)
252UNIMPLEMENTED_INTRINSIC(LongReverse)
253UNIMPLEMENTED_INTRINSIC(ShortReverseBytes)
254UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes)
255UNIMPLEMENTED_INTRINSIC(LongReverseBytes)
256UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
257UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
258UNIMPLEMENTED_INTRINSIC(FloatIntBitsToFloat)
259UNIMPLEMENTED_INTRINSIC(DoubleLongBitsToDouble)
260UNIMPLEMENTED_INTRINSIC(FloatFloatToRawIntBits)
261UNIMPLEMENTED_INTRINSIC(DoubleDoubleToRawLongBits)
262UNIMPLEMENTED_INTRINSIC(MathAbsDouble)
263UNIMPLEMENTED_INTRINSIC(MathAbsFloat)
264UNIMPLEMENTED_INTRINSIC(MathAbsInt)
265UNIMPLEMENTED_INTRINSIC(MathAbsLong)
266UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble)
267UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat)
268UNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble)
269UNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat)
270UNIMPLEMENTED_INTRINSIC(MathMinIntInt)
271UNIMPLEMENTED_INTRINSIC(MathMinLongLong)
272UNIMPLEMENTED_INTRINSIC(MathMaxIntInt)
273UNIMPLEMENTED_INTRINSIC(MathMaxLongLong)
274UNIMPLEMENTED_INTRINSIC(MathSqrt)
275UNIMPLEMENTED_INTRINSIC(MathCeil)
276UNIMPLEMENTED_INTRINSIC(MathFloor)
277UNIMPLEMENTED_INTRINSIC(MathRint)
278UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
279UNIMPLEMENTED_INTRINSIC(MathRoundFloat)
280UNIMPLEMENTED_INTRINSIC(MemoryPeekByte)
281UNIMPLEMENTED_INTRINSIC(MemoryPeekIntNative)
282UNIMPLEMENTED_INTRINSIC(MemoryPeekLongNative)
283UNIMPLEMENTED_INTRINSIC(MemoryPeekShortNative)
284UNIMPLEMENTED_INTRINSIC(MemoryPokeByte)
285UNIMPLEMENTED_INTRINSIC(MemoryPokeIntNative)
286UNIMPLEMENTED_INTRINSIC(MemoryPokeLongNative)
287UNIMPLEMENTED_INTRINSIC(MemoryPokeShortNative)
288UNIMPLEMENTED_INTRINSIC(ThreadCurrentThread)
289UNIMPLEMENTED_INTRINSIC(UnsafeGet)
290UNIMPLEMENTED_INTRINSIC(UnsafeGetVolatile)
291UNIMPLEMENTED_INTRINSIC(UnsafeGetLong)
292UNIMPLEMENTED_INTRINSIC(UnsafeGetLongVolatile)
293UNIMPLEMENTED_INTRINSIC(UnsafeGetObject)
294UNIMPLEMENTED_INTRINSIC(UnsafeGetObjectVolatile)
295UNIMPLEMENTED_INTRINSIC(UnsafePut)
296UNIMPLEMENTED_INTRINSIC(UnsafePutOrdered)
297UNIMPLEMENTED_INTRINSIC(UnsafePutVolatile)
298UNIMPLEMENTED_INTRINSIC(UnsafePutObject)
299UNIMPLEMENTED_INTRINSIC(UnsafePutObjectOrdered)
300UNIMPLEMENTED_INTRINSIC(UnsafePutObjectVolatile)
301UNIMPLEMENTED_INTRINSIC(UnsafePutLong)
302UNIMPLEMENTED_INTRINSIC(UnsafePutLongOrdered)
303UNIMPLEMENTED_INTRINSIC(UnsafePutLongVolatile)
304UNIMPLEMENTED_INTRINSIC(UnsafeCASInt)
305UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
306UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
307UNIMPLEMENTED_INTRINSIC(StringCharAt)
308UNIMPLEMENTED_INTRINSIC(StringCompareTo)
Chris Larsen701566a2015-10-27 15:29:13 -0700309UNIMPLEMENTED_INTRINSIC(StringIndexOf)
310UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter)
311UNIMPLEMENTED_INTRINSIC(StringNewStringFromBytes)
312UNIMPLEMENTED_INTRINSIC(StringNewStringFromChars)
313UNIMPLEMENTED_INTRINSIC(StringNewStringFromString)
314UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
315UNIMPLEMENTED_INTRINSIC(LongRotateRight)
316UNIMPLEMENTED_INTRINSIC(LongNumberOfTrailingZeros)
317UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
318UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
319UNIMPLEMENTED_INTRINSIC(IntegerNumberOfTrailingZeros)
320
321UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
322UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
323UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
324UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
325
326#undef UNIMPLEMENTED_INTRINSIC
327
328#undef __
329
330} // namespace mips
331} // namespace art