| /* |
| * Copyright (C) 2023 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_riscv64.h" |
| |
| #include "code_generator_riscv64.h" |
| |
| namespace art HIDDEN { |
| namespace riscv64 { |
| |
| bool IntrinsicLocationsBuilderRISCV64::TryDispatch(HInvoke* invoke) { |
| Dispatch(invoke); |
| LocationSummary* res = invoke->GetLocations(); |
| if (res == nullptr) { |
| return false; |
| } |
| return res->Intrinsified(); |
| } |
| |
| Riscv64Assembler* IntrinsicCodeGeneratorRISCV64::GetAssembler() { |
| return codegen_->GetAssembler(); |
| } |
| |
| #define __ GetAssembler()-> |
| |
| static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { |
| LocationSummary* locations = |
| new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); |
| locations->SetInAt(0, Location::RequiresFpuRegister()); |
| locations->SetOut(Location::RequiresRegister()); |
| } |
| |
| static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { |
| LocationSummary* locations = |
| new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); |
| locations->SetInAt(0, Location::RequiresRegister()); |
| locations->SetOut(Location::RequiresFpuRegister()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { |
| CreateFPToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| __ FMvXD(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsFpuRegister<FRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitDoubleLongBitsToDouble(HInvoke* invoke) { |
| CreateIntToFPLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitDoubleLongBitsToDouble(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| __ FMvDX(locations->Out().AsFpuRegister<FRegister>(), locations->InAt(0).AsRegister<XRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { |
| CreateFPToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| __ FMvXW(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsFpuRegister<FRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitFloatIntBitsToFloat(HInvoke* invoke) { |
| CreateIntToFPLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitFloatIntBitsToFloat(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| __ FMvWX(locations->Out().AsFpuRegister<FRegister>(), locations->InAt(0).AsRegister<XRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitDoubleIsInfinite(HInvoke* invoke) { |
| CreateFPToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitDoubleIsInfinite(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| XRegister out = locations->Out().AsRegister<XRegister>(); |
| __ FClassD(out, locations->InAt(0).AsFpuRegister<FRegister>()); |
| __ Andi(out, out, kPositiveInfinity | kNegativeInfinity); |
| __ Snez(out, out); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitFloatIsInfinite(HInvoke* invoke) { |
| CreateFPToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitFloatIsInfinite(HInvoke* invoke) { |
| LocationSummary* locations = invoke->GetLocations(); |
| XRegister out = locations->Out().AsRegister<XRegister>(); |
| __ FClassS(out, locations->InAt(0).AsFpuRegister<FRegister>()); |
| __ Andi(out, out, kPositiveInfinity | kNegativeInfinity); |
| __ Snez(out, out); |
| } |
| |
| static void CreateIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { |
| LocationSummary* locations = |
| new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); |
| locations->SetInAt(0, Location::RequiresRegister()); |
| locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); |
| } |
| |
| template <typename EmitOp> |
| void EmitMemoryPeek(HInvoke* invoke, EmitOp&& emit_op) { |
| LocationSummary* locations = invoke->GetLocations(); |
| emit_op(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekByte(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekByte(HInvoke* invoke) { |
| EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lb(rd, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekIntNative(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekIntNative(HInvoke* invoke) { |
| EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lw(rd, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekLongNative(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekLongNative(HInvoke* invoke) { |
| EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Ld(rd, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekShortNative(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekShortNative(HInvoke* invoke) { |
| EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lh(rd, rs1, 0); }); |
| } |
| |
| static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) { |
| LocationSummary* locations = |
| new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); |
| locations->SetInAt(0, Location::RequiresRegister()); |
| locations->SetInAt(1, Location::RequiresRegister()); |
| } |
| |
| template <typename EmitOp> |
| void EmitMemoryPoke(HInvoke* invoke, EmitOp&& emit_op) { |
| LocationSummary* locations = invoke->GetLocations(); |
| emit_op(locations->InAt(1).AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeByte(HInvoke* invoke) { |
| CreateIntIntToVoidLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeByte(HInvoke* invoke) { |
| EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sb(rs2, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeIntNative(HInvoke* invoke) { |
| CreateIntIntToVoidLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeIntNative(HInvoke* invoke) { |
| EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sw(rs2, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeLongNative(HInvoke* invoke) { |
| CreateIntIntToVoidLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeLongNative(HInvoke* invoke) { |
| EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sd(rs2, rs1, 0); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeShortNative(HInvoke* invoke) { |
| CreateIntIntToVoidLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeShortNative(HInvoke* invoke) { |
| EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sh(rs2, rs1, 0); }); |
| } |
| |
| template <typename EmitOp> |
| void EmitIntegralUnOp(HInvoke* invoke, EmitOp&& emit_op) { |
| LocationSummary* locations = invoke->GetLocations(); |
| emit_op(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>()); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerReverseBytes(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerReverseBytes(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| // There is no 32-bit reverse bytes instruction. |
| __ Rev8(rd, rs1); |
| __ Srai(rd, rd, 32); |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongReverseBytes(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongReverseBytes(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Rev8(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitShortReverseBytes(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitShortReverseBytes(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| // There is no 16-bit reverse bytes instruction. |
| __ Rev8(rd, rs1); |
| __ Srai(rd, rd, 48); |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerBitCount(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerBitCount(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Cpopw(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongBitCount(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongBitCount(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Cpop(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerHighestOneBit(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerHighestOneBit(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| ScratchRegisterScope srs(GetAssembler()); |
| XRegister tmp = srs.AllocateXRegister(); |
| XRegister tmp2 = srs.AllocateXRegister(); |
| __ Clzw(tmp, rs1); |
| __ Li(tmp2, INT64_C(-0x80000000)); |
| __ Srlw(tmp2, tmp2, tmp); |
| __ And(rd, rs1, tmp2); // Make sure the result is zero if the input is zero. |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongHighestOneBit(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongHighestOneBit(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| ScratchRegisterScope srs(GetAssembler()); |
| XRegister tmp = srs.AllocateXRegister(); |
| XRegister tmp2 = srs.AllocateXRegister(); |
| __ Clz(tmp, rs1); |
| __ Li(tmp2, INT64_C(-0x8000000000000000)); |
| __ Srl(tmp2, tmp2, tmp); |
| __ And(rd, rs1, tmp2); // Make sure the result is zero if the input is zero. |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerLowestOneBit(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerLowestOneBit(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| ScratchRegisterScope srs(GetAssembler()); |
| XRegister tmp = srs.AllocateXRegister(); |
| __ NegW(tmp, rs1); |
| __ And(rd, rs1, tmp); |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongLowestOneBit(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongLowestOneBit(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { |
| ScratchRegisterScope srs(GetAssembler()); |
| XRegister tmp = srs.AllocateXRegister(); |
| __ Neg(tmp, rs1); |
| __ And(rd, rs1, tmp); |
| }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Clzw(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Clz(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Ctzw(rd, rs1); }); |
| } |
| |
| void IntrinsicLocationsBuilderRISCV64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { |
| CreateIntToIntLocations(allocator_, invoke); |
| } |
| |
| void IntrinsicCodeGeneratorRISCV64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { |
| EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Ctz(rd, rs1); }); |
| } |
| |
| #define MARK_UNIMPLEMENTED(Name) UNIMPLEMENTED_INTRINSIC(RISCV64, Name) |
| UNIMPLEMENTED_INTRINSIC_LIST_RISCV64(MARK_UNIMPLEMENTED); |
| #undef MARK_UNIMPLEMENTED |
| |
| UNREACHABLE_INTRINSICS(RISCV64) |
| |
| } // namespace riscv64 |
| } // namespace art |