diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 883170315622b..a70c7a0309485 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -330,7 +330,110 @@ class InternalAddress: public Address { }; class Assembler : public AbstractAssembler { -public: +private: + + bool static zfa_zli_lookup_double(uint64_t value, int* Rs = nullptr) { + int dummy; + if (Rs == nullptr) { + Rs = &dummy; + } + (*Rs) = -1; + switch(value) { + case 0xbff0000000000000 : (*Rs) = 0; return true; + case 0x0010000000000000 : (*Rs) = 1; return true; + case 0x3ef0000000000000 : (*Rs) = 2; return true; + case 0x3f00000000000000 : (*Rs) = 3; return true; + case 0x3f70000000000000 : (*Rs) = 4; return true; + case 0x3f80000000000000 : (*Rs) = 5; return true; + case 0x3fb0000000000000 : (*Rs) = 6; return true; + case 0x3fc0000000000000 : (*Rs) = 7; return true; + case 0x3fd0000000000000 : (*Rs) = 8; return true; + case 0x3fd4000000000000 : (*Rs) = 9; return true; + case 0x3fd8000000000000 : (*Rs) = 10; return true; + case 0x3fdc000000000000 : (*Rs) = 11; return true; + case 0x3fe0000000000000 : (*Rs) = 12; return true; + case 0x3fe4000000000000 : (*Rs) = 13; return true; + case 0x3fe8000000000000 : (*Rs) = 14; return true; + case 0x3fec000000000000 : (*Rs) = 15; return true; + case 0x3ff0000000000000 : (*Rs) = 16; return true; + case 0x3ff4000000000000 : (*Rs) = 17; return true; + case 0x3ff8000000000000 : (*Rs) = 18; return true; + case 0x3ffc000000000000 : (*Rs) = 19; return true; + case 0x4000000000000000 : (*Rs) = 20; return true; + case 0x4004000000000000 : (*Rs) = 21; return true; + case 0x4008000000000000 : (*Rs) = 22; return true; + case 0x4010000000000000 : (*Rs) = 23; return true; + case 0x4020000000000000 : (*Rs) = 24; return true; + case 0x4030000000000000 : (*Rs) = 25; return true; + case 0x4060000000000000 : (*Rs) = 26; return true; + case 0x4070000000000000 : (*Rs) = 27; return true; + case 0x40e0000000000000 : (*Rs) = 28; return true; + case 0x40f0000000000000 : (*Rs) = 29; return true; + case 0x7ff0000000000000 : (*Rs) = 30; return true; + case 0x7ff8000000000000 : (*Rs) = 31; return true; + default: break; + } + return false; + } + + + bool static zfa_zli_lookup_float(uint32_t value, int* Rs = nullptr) { + (*Rs) = -1; + switch(value) { + case 0xbf800000 : (*Rs) = 0; return true; + case 0x00800000 : (*Rs) = 1; return true; + case 0x37800000 : (*Rs) = 2; return true; + case 0x38000000 : (*Rs) = 3; return true; + case 0x3b800000 : (*Rs) = 4; return true; + case 0x3c000000 : (*Rs) = 5; return true; + case 0x3d800000 : (*Rs) = 6; return true; + case 0x3e000000 : (*Rs) = 7; return true; + case 0x3e800000 : (*Rs) = 8; return true; + case 0x3ea00000 : (*Rs) = 9; return true; + case 0x3ec00000 : (*Rs) = 10; return true; + case 0x3ee00000 : (*Rs) = 11; return true; + case 0x3f000000 : (*Rs) = 12; return true; + case 0x3f200000 : (*Rs) = 13; return true; + case 0x3f400000 : (*Rs) = 14; return true; + case 0x3f600000 : (*Rs) = 15; return true; + case 0x3f800000 : (*Rs) = 16; return true; + case 0x3fa00000 : (*Rs) = 17; return true; + case 0x3fc00000 : (*Rs) = 18; return true; + case 0x3fe00000 : (*Rs) = 19; return true; + case 0x40000000 : (*Rs) = 20; return true; + case 0x40200000 : (*Rs) = 21; return true; + case 0x40400000 : (*Rs) = 22; return true; + case 0x40800000 : (*Rs) = 23; return true; + case 0x41000000 : (*Rs) = 24; return true; + case 0x41800000 : (*Rs) = 25; return true; + case 0x43000000 : (*Rs) = 26; return true; + case 0x43800000 : (*Rs) = 27; return true; + case 0x47000000 : (*Rs) = 28; return true; + case 0x47800000 : (*Rs) = 29; return true; + case 0x7f800000 : (*Rs) = 30; return true; + case 0x7fc00000 : (*Rs) = 31; return true; + default: break; + } + return false; + } + + public: + + bool static can_zfa_zli_float(jfloat f, int* Rs) { + if (!UseZfa) { + return false; + } + uint32_t f_bits = (uint32_t)jint_cast(f); + return zfa_zli_lookup_float(f_bits, Rs); + } + + bool static can_zfa_zli_double(jdouble d, int* Rs) { + if (!UseZfa) { + return false; + } + uint64_t d_bits = (uint64_t)julong_cast(d); + return zfa_zli_lookup_double(d_bits, Rs); + } enum { instruction_size = 4, @@ -1091,6 +1194,30 @@ enum operand_size { int8, int16, int32, uint32, int64 }; #undef INSN + void _fli_s(FloatRegister Rd, uint8_t Rs1) { + guarantee(is_uimm5(Rs1), "uimm is invalid"); + unsigned insn = 0; + patch((address)&insn, 6, 0, 0b1010011); + patch_reg((address)&insn, 7, Rd); + patch((address)&insn, 14, 12, 0b000); + patch((address)&insn, 19, 15, Rs1); + patch((address)&insn, 20, 0b00001); + patch((address)&insn, 31, 25, 0b1111000); + emit(insn); + } + + void _fli_d(FloatRegister Rd, uint8_t Rs1) { + guarantee(is_uimm5(Rs1), "uimm is invalid"); + unsigned insn = 0; + patch((address)&insn, 6, 0, 0b1010011); + patch_reg((address)&insn, 7, Rd); + patch((address)&insn, 14, 12, 0b000); + patch((address)&insn, 19, 15, Rs1); + patch((address)&insn, 20, 0b00001); + patch((address)&insn, 31, 25, 0b1111001); + emit(insn); + } + enum fclass_mask { minf = 1 << 0, // negative infinite mnorm = 1 << 1, // negative normal number diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 6ac3ebe518497..93cf55be3dae2 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -426,6 +426,8 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod assert(dest->is_register(), "should not call otherwise"); LIR_Const* c = src->as_constant_ptr(); address const_addr = nullptr; + jfloat fconst; + jdouble dconst; switch (c->type()) { case T_INT: @@ -461,15 +463,25 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod break; case T_FLOAT: - const_addr = float_constant(c->as_jfloat()); - assert(const_addr != nullptr, "must create float constant in the constant table"); - __ flw(dest->as_float_reg(), InternalAddress(const_addr)); + fconst = c->as_jfloat(); + if (MacroAssembler::can_fp_imm_load(fconst)) { + __ fli_s(dest->as_float_reg(), fconst); + } else { + const_addr = float_constant(fconst); + assert(const_addr != nullptr, "must create float constant in the constant table"); + __ flw(dest->as_float_reg(), InternalAddress(const_addr)); + } break; case T_DOUBLE: - const_addr = double_constant(c->as_jdouble()); - assert(const_addr != nullptr, "must create double constant in the constant table"); - __ fld(dest->as_double_reg(), InternalAddress(const_addr)); + dconst = c->as_jdouble(); + if (MacroAssembler::can_dp_imm_load(dconst)) { + __ fli_d(dest->as_double_reg(), dconst); + } else { + const_addr = double_constant(c->as_jdouble()); + assert(const_addr != nullptr, "must create double constant in the constant table"); + __ fld(dest->as_double_reg(), InternalAddress(const_addr)); + } break; default: diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 806cca16269ea..70cdbf480ffd9 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -103,6 +103,7 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseZba, false, DIAGNOSTIC, "Use Zba instructions") \ product(bool, UseZbb, false, DIAGNOSTIC, "Use Zbb instructions") \ product(bool, UseZbs, false, DIAGNOSTIC, "Use Zbs instructions") \ + product(bool, UseZfa, false, DIAGNOSTIC, "Use Zfa instructions") \ product(bool, UseZfh, false, DIAGNOSTIC, "Use Zfh instructions") \ product(bool, UseZacas, false, EXPERIMENTAL, "Use Zacas instructions") \ product(bool, UseZcb, false, EXPERIMENTAL, "Use Zcb instructions") \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 24504472509d1..4756e8ab06260 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2605,6 +2605,47 @@ void MacroAssembler::movptr2(Register Rd, uint64_t addr, int32_t &offset, Regist offset = lower12; } + // float imm move +bool MacroAssembler::can_fp_imm_load(float imm) { + jint f_bits = jint_cast(imm); + if (f_bits == 0) { + return true; + } + int dummy; + return can_zfa_zli_float(imm, &dummy); +} + +bool MacroAssembler::can_dp_imm_load(double imm) { + julong d_bits = julong_cast(imm); + if (d_bits == 0) { + return true; + } + int dummy; + return can_zfa_zli_double(imm, &dummy); +} + +void MacroAssembler::fli_s(FloatRegister Rd, float imm) { + jint f_bits = jint_cast(imm); + if (f_bits == 0) { + fmv_w_x(Rd, zr); + return; + } + int Rs = -1; + can_zfa_zli_float(imm, &Rs); + _fli_s(Rd, Rs); +} + +void MacroAssembler::fli_d(FloatRegister Rd, double imm) { + uint64_t d_bits = (uint64_t)julong_cast(imm); + if (d_bits == 0) { + fmv_d_x(Rd, zr); + return; + } + int Rs = -1; + can_zfa_zli_double(imm, &Rs); + _fli_d(Rd, Rs); +} + void MacroAssembler::add(Register Rd, Register Rn, int64_t increment, Register tmp) { if (is_simm12(increment)) { addi(Rd, Rn, increment); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 04b95ba355b1e..eb56fbb22b6f4 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -884,6 +884,11 @@ class MacroAssembler: public Assembler { void movptr1(Register Rd, uintptr_t addr, int32_t &offset); void movptr2(Register Rd, uintptr_t addr, int32_t &offset, Register tmp); public: + // float imm move + static bool can_fp_imm_load(float imm); + static bool can_dp_imm_load(double imm); + void fli_s(FloatRegister Rd, float imm); + void fli_d(FloatRegister Rd, double imm); // arith void add (Register Rd, Register Rn, int64_t increment, Register tmp = t0); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index a9b48fd18c406..4696b15aabb6c 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -4920,7 +4920,11 @@ instruct loadConF(fRegF dst, immF con) %{ %} ins_encode %{ - __ flw(as_FloatRegister($dst$$reg), $constantaddress($con)); + if (MacroAssembler::can_fp_imm_load($con$$constant)) { + __ fli_s(as_FloatRegister($dst$$reg), $con$$constant); + } else { + __ flw(as_FloatRegister($dst$$reg), $constantaddress($con)); + } %} ins_pipe(fp_load_constant_s); @@ -4950,7 +4954,11 @@ instruct loadConD(fRegD dst, immD con) %{ %} ins_encode %{ - __ fld(as_FloatRegister($dst$$reg), $constantaddress($con)); + if (MacroAssembler::can_dp_imm_load($con$$constant)) { + __ fli_d(as_FloatRegister($dst$$reg), $con$$constant); + } else { + __ fld(as_FloatRegister($dst$$reg), $constantaddress($con)); + } %} ins_pipe(fp_load_constant_d); diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 59b41892fef0c..878b977daa76c 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -156,6 +156,7 @@ class VM_Version : public Abstract_VM_Version { decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \ + decl(ext_Zfa , "Zfa" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \ decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ @@ -223,6 +224,7 @@ class VM_Version : public Abstract_VM_Version { RV_ENABLE_EXTENSION(UseZbb) \ RV_ENABLE_EXTENSION(UseZbs) \ RV_ENABLE_EXTENSION(UseZcb) \ + RV_ENABLE_EXTENSION(UseZfa) \ RV_ENABLE_EXTENSION(UseZic64b) \ RV_ENABLE_EXTENSION(UseZicbom) \ RV_ENABLE_EXTENSION(UseZicbop) \