/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "intrinsics_mips.h" #include "arch/mips/instruction_set_features_mips.h" #include "art_method.h" #include "code_generator_mips.h" #include "entrypoints/quick/quick_entrypoints.h" #include "intrinsics.h" #include "mirror/array-inl.h" #include "mirror/string.h" #include "thread.h" #include "utils/mips/assembler_mips.h" #include "utils/mips/constants_mips.h" namespace art { namespace mips { IntrinsicLocationsBuilderMIPS::IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS* codegen) : arena_(codegen->GetGraph()->GetArena()) { } MipsAssembler* IntrinsicCodeGeneratorMIPS::GetAssembler() { return reinterpret_cast(codegen_->GetAssembler()); } ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() { return codegen_->GetGraph()->GetArena(); } #define __ codegen->GetAssembler()-> static void MoveFromReturnRegister(Location trg, Primitive::Type type, CodeGeneratorMIPS* codegen) { if (!trg.IsValid()) { DCHECK_EQ(type, Primitive::kPrimVoid); return; } DCHECK_NE(type, Primitive::kPrimVoid); if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) { Register trg_reg = trg.AsRegister(); if (trg_reg != V0) { __ Move(V0, trg_reg); } } else { FRegister trg_reg = trg.AsFpuRegister(); if (trg_reg != F0) { if (type == Primitive::kPrimFloat) { __ MovS(F0, trg_reg); } else { __ MovD(F0, trg_reg); } } } } static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS* codegen) { InvokeDexCallingConventionVisitorMIPS calling_convention_visitor; IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor); } // Slow-path for fallback (calling the managed code to handle the // intrinsic) in an intrinsified call. This will copy the arguments // into the positions for a regular call. // // Note: The actual parameters are required to be in the locations // given by the invoke's location summary. If an intrinsic // modifies those locations before a slowpath call, they must be // restored! class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS { public: explicit IntrinsicSlowPathMIPS(HInvoke* invoke) : invoke_(invoke) { } void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE { CodeGeneratorMIPS* codegen = down_cast(codegen_in); __ Bind(GetEntryLabel()); SaveLiveRegisters(codegen, invoke_->GetLocations()); MoveArguments(invoke_, codegen); if (invoke_->IsInvokeStaticOrDirect()) { codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0)); codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this); } else { UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented"; UNREACHABLE(); } // Copy the result back to the expected output. Location out = invoke_->GetLocations()->Out(); if (out.IsValid()) { DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory. DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg())); MoveFromReturnRegister(out, invoke_->GetType(), codegen); } RestoreLiveRegisters(codegen, invoke_->GetLocations()); __ B(GetExitLabel()); } const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS"; } private: // The instruction where this slow path is happening. HInvoke* const invoke_; DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS); }; #undef __ bool IntrinsicLocationsBuilderMIPS::TryDispatch(HInvoke* invoke) { Dispatch(invoke); LocationSummary* res = invoke->GetLocations(); return res != nullptr && res->Intrinsified(); } #define __ assembler-> // Unimplemented intrinsics. #define UNIMPLEMENTED_INTRINSIC(Name) \ void IntrinsicLocationsBuilderMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ } \ void IntrinsicCodeGeneratorMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ } UNIMPLEMENTED_INTRINSIC(IntegerReverse) UNIMPLEMENTED_INTRINSIC(LongReverse) UNIMPLEMENTED_INTRINSIC(ShortReverseBytes) UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) UNIMPLEMENTED_INTRINSIC(LongReverseBytes) UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros) UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros) UNIMPLEMENTED_INTRINSIC(FloatIntBitsToFloat) UNIMPLEMENTED_INTRINSIC(DoubleLongBitsToDouble) UNIMPLEMENTED_INTRINSIC(FloatFloatToRawIntBits) UNIMPLEMENTED_INTRINSIC(DoubleDoubleToRawLongBits) UNIMPLEMENTED_INTRINSIC(MathAbsDouble) UNIMPLEMENTED_INTRINSIC(MathAbsFloat) UNIMPLEMENTED_INTRINSIC(MathAbsInt) UNIMPLEMENTED_INTRINSIC(MathAbsLong) UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) UNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) UNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat) UNIMPLEMENTED_INTRINSIC(MathMinIntInt) UNIMPLEMENTED_INTRINSIC(MathMinLongLong) UNIMPLEMENTED_INTRINSIC(MathMaxIntInt) UNIMPLEMENTED_INTRINSIC(MathMaxLongLong) UNIMPLEMENTED_INTRINSIC(MathSqrt) UNIMPLEMENTED_INTRINSIC(MathCeil) UNIMPLEMENTED_INTRINSIC(MathFloor) UNIMPLEMENTED_INTRINSIC(MathRint) UNIMPLEMENTED_INTRINSIC(MathRoundDouble) UNIMPLEMENTED_INTRINSIC(MathRoundFloat) UNIMPLEMENTED_INTRINSIC(MemoryPeekByte) UNIMPLEMENTED_INTRINSIC(MemoryPeekIntNative) UNIMPLEMENTED_INTRINSIC(MemoryPeekLongNative) UNIMPLEMENTED_INTRINSIC(MemoryPeekShortNative) UNIMPLEMENTED_INTRINSIC(MemoryPokeByte) UNIMPLEMENTED_INTRINSIC(MemoryPokeIntNative) UNIMPLEMENTED_INTRINSIC(MemoryPokeLongNative) UNIMPLEMENTED_INTRINSIC(MemoryPokeShortNative) UNIMPLEMENTED_INTRINSIC(ThreadCurrentThread) UNIMPLEMENTED_INTRINSIC(UnsafeGet) UNIMPLEMENTED_INTRINSIC(UnsafeGetVolatile) UNIMPLEMENTED_INTRINSIC(UnsafeGetLong) UNIMPLEMENTED_INTRINSIC(UnsafeGetLongVolatile) UNIMPLEMENTED_INTRINSIC(UnsafeGetObject) UNIMPLEMENTED_INTRINSIC(UnsafeGetObjectVolatile) UNIMPLEMENTED_INTRINSIC(UnsafePut) UNIMPLEMENTED_INTRINSIC(UnsafePutOrdered) UNIMPLEMENTED_INTRINSIC(UnsafePutVolatile) UNIMPLEMENTED_INTRINSIC(UnsafePutObject) UNIMPLEMENTED_INTRINSIC(UnsafePutObjectOrdered) UNIMPLEMENTED_INTRINSIC(UnsafePutObjectVolatile) UNIMPLEMENTED_INTRINSIC(UnsafePutLong) UNIMPLEMENTED_INTRINSIC(UnsafePutLongOrdered) UNIMPLEMENTED_INTRINSIC(UnsafePutLongVolatile) UNIMPLEMENTED_INTRINSIC(UnsafeCASInt) UNIMPLEMENTED_INTRINSIC(UnsafeCASLong) UNIMPLEMENTED_INTRINSIC(UnsafeCASObject) UNIMPLEMENTED_INTRINSIC(StringCharAt) UNIMPLEMENTED_INTRINSIC(StringCompareTo) UNIMPLEMENTED_INTRINSIC(StringEquals) UNIMPLEMENTED_INTRINSIC(StringIndexOf) UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter) UNIMPLEMENTED_INTRINSIC(StringNewStringFromBytes) UNIMPLEMENTED_INTRINSIC(StringNewStringFromChars) UNIMPLEMENTED_INTRINSIC(StringNewStringFromString) UNIMPLEMENTED_INTRINSIC(LongRotateLeft) UNIMPLEMENTED_INTRINSIC(LongRotateRight) UNIMPLEMENTED_INTRINSIC(LongNumberOfTrailingZeros) UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) UNIMPLEMENTED_INTRINSIC(IntegerNumberOfTrailingZeros) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) #undef UNIMPLEMENTED_INTRINSIC #undef __ } // namespace mips } // namespace art