mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-09 13:09:43 +00:00
8344306: RISC-V: Add zicond
Reviewed-by: fyang, luhenry, mli
This commit is contained in:
parent
d33ad07c32
commit
edfe28541a
@ -3107,6 +3107,38 @@ public:
|
||||
|
||||
#undef INSN
|
||||
|
||||
// -------------- Zicond Instruction Definitions --------------
|
||||
// Zicond conditional operations extension
|
||||
private:
|
||||
enum CZERO_OP : unsigned int {
|
||||
CZERO_NEZ = 0b111,
|
||||
CZERO_EQZ = 0b101
|
||||
};
|
||||
|
||||
template <CZERO_OP OP_VALUE>
|
||||
void czero(Register Rd, Register Rs1, Register Rs2) {
|
||||
assert_cond(UseZicond);
|
||||
uint32_t insn = 0;
|
||||
patch ((address)&insn, 6, 0, 0b0110011); // bits: 7, name: 0x33, attr: ['OP']
|
||||
patch_reg((address)&insn, 7, Rd); // bits: 5, name: 'rd'
|
||||
patch ((address)&insn, 14, 12, OP_VALUE); // bits: 3, name: 0x7, attr: ['CZERO.NEZ'] / 0x5, attr: ['CZERO.EQZ']}
|
||||
patch_reg((address)&insn, 15, Rs1); // bits: 5, name: 'rs1', attr: ['value']
|
||||
patch_reg((address)&insn, 20, Rs2); // bits: 5, name: 'rs2', attr: ['condition']
|
||||
patch ((address)&insn, 31, 25, 0b0000111); // bits: 7, name: 0x7, attr: ['CZERO']
|
||||
emit_int32(insn);
|
||||
}
|
||||
|
||||
public:
|
||||
// Moves zero to a register rd, if the condition rs2 is equal to zero, otherwise moves rs1 to rd.
|
||||
void czero_eqz(Register rd, Register rs1_value, Register rs2_condition) {
|
||||
czero<CZERO_EQZ>(rd, rs1_value, rs2_condition);
|
||||
}
|
||||
|
||||
// Moves zero to a register rd, if the condition rs2 is nonzero, otherwise moves rs1 to rd.
|
||||
void czero_nez(Register rd, Register rs1_value, Register rs2_condition) {
|
||||
czero<CZERO_NEZ>(rd, rs1_value, rs2_condition);
|
||||
}
|
||||
|
||||
// -------------- ZCB Instruction Definitions --------------
|
||||
// Zcb additional C instructions
|
||||
private:
|
||||
|
||||
@ -870,6 +870,7 @@ void LIR_Assembler::emit_op3(LIR_Op3* op) {
|
||||
}
|
||||
}
|
||||
|
||||
// Consider using cmov (Zicond)
|
||||
void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type,
|
||||
LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) {
|
||||
Label label;
|
||||
|
||||
@ -2003,10 +2003,48 @@ void C2_MacroAssembler::enc_cmpEqNe_imm0_branch(int cmpFlag, Register op1, Label
|
||||
}
|
||||
|
||||
void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Register dst, Register src) {
|
||||
Label L;
|
||||
cmp_branch(cmpFlag ^ (1 << neg_cond_bits), op1, op2, L);
|
||||
mv(dst, src);
|
||||
bind(L);
|
||||
bool is_unsigned = (cmpFlag & unsigned_branch_mask) == unsigned_branch_mask;
|
||||
int op_select = cmpFlag & (~unsigned_branch_mask);
|
||||
|
||||
switch (op_select) {
|
||||
case BoolTest::eq:
|
||||
cmov_eq(op1, op2, dst, src);
|
||||
break;
|
||||
case BoolTest::ne:
|
||||
cmov_ne(op1, op2, dst, src);
|
||||
break;
|
||||
case BoolTest::le:
|
||||
if (is_unsigned) {
|
||||
cmov_leu(op1, op2, dst, src);
|
||||
} else {
|
||||
cmov_le(op1, op2, dst, src);
|
||||
}
|
||||
break;
|
||||
case BoolTest::ge:
|
||||
if (is_unsigned) {
|
||||
cmov_geu(op1, op2, dst, src);
|
||||
} else {
|
||||
cmov_ge(op1, op2, dst, src);
|
||||
}
|
||||
break;
|
||||
case BoolTest::lt:
|
||||
if (is_unsigned) {
|
||||
cmov_ltu(op1, op2, dst, src);
|
||||
} else {
|
||||
cmov_lt(op1, op2, dst, src);
|
||||
}
|
||||
break;
|
||||
case BoolTest::gt:
|
||||
if (is_unsigned) {
|
||||
cmov_gtu(op1, op2, dst, src);
|
||||
} else {
|
||||
cmov_gt(op1, op2, dst, src);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false, "unsupported compare condition");
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
// Set dst to NaN if any NaN input.
|
||||
|
||||
@ -98,7 +98,6 @@
|
||||
|
||||
// refer to conditional_branches and float_conditional_branches
|
||||
static const int bool_test_bits = 3;
|
||||
static const int neg_cond_bits = 2;
|
||||
static const int unsigned_branch_mask = 1 << bool_test_bits;
|
||||
static const int double_branch_mask = 1 << bool_test_bits;
|
||||
|
||||
|
||||
@ -110,6 +110,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \
|
||||
product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \
|
||||
product(bool, UseZicboz, false, EXPERIMENTAL, "Use Zicboz instructions") \
|
||||
product(bool, UseZicond, false, DIAGNOSTIC, "Use Zicond instructions") \
|
||||
product(bool, UseZihintpause, false, EXPERIMENTAL, \
|
||||
"Use Zihintpause instructions") \
|
||||
product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model") \
|
||||
|
||||
@ -1128,6 +1128,147 @@ void MacroAssembler::wrap_label(Register r1, Register r2, Label &L,
|
||||
|
||||
#undef INSN
|
||||
|
||||
// cmov
|
||||
void MacroAssembler::cmov_eq(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
xorr(t0, cmp1, cmp2);
|
||||
czero_eqz(dst, dst, t0);
|
||||
czero_nez(t0 , src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bne(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_ne(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
xorr(t0, cmp1, cmp2);
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0 , src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
beq(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_le(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
slt(t0, cmp2, cmp1);
|
||||
czero_eqz(dst, dst, t0);
|
||||
czero_nez(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bgt(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_leu(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
sltu(t0, cmp2, cmp1);
|
||||
czero_eqz(dst, dst, t0);
|
||||
czero_nez(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bgtu(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_ge(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
slt(t0, cmp1, cmp2);
|
||||
czero_eqz(dst, dst, t0);
|
||||
czero_nez(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
blt(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_geu(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
sltu(t0, cmp1, cmp2);
|
||||
czero_eqz(dst, dst, t0);
|
||||
czero_nez(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bltu(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_lt(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
slt(t0, cmp1, cmp2);
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bge(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_ltu(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
sltu(t0, cmp1, cmp2);
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bgeu(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_gt(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
slt(t0, cmp2, cmp1);
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
ble(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Register src) {
|
||||
if (UseZicond) {
|
||||
sltu(t0, cmp2, cmp1);
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0, src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
bleu(cmp1, cmp2, no_set);
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
// Float compare branch instructions
|
||||
|
||||
#define INSN(NAME, FLOATCMP, BRANCH) \
|
||||
|
||||
@ -626,6 +626,17 @@ class MacroAssembler: public Assembler {
|
||||
void bltz(Register Rs, const address dest);
|
||||
void bgtz(Register Rs, const address dest);
|
||||
|
||||
void cmov_eq(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_ne(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_le(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_leu(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_ge(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_geu(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_lt(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_ltu(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_gt(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
void cmov_gtu(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
|
||||
public:
|
||||
// We try to follow risc-v asm menomics.
|
||||
// But as we don't layout a reachable GOT,
|
||||
|
||||
@ -116,6 +116,8 @@ class VM_Version : public Abstract_VM_Version {
|
||||
//
|
||||
// Zfh Half-Precision Floating-Point instructions
|
||||
//
|
||||
// Zicond Conditional operations
|
||||
//
|
||||
// Zicsr Control and Status Register (CSR) Instructions
|
||||
// Zifencei Instruction-Fetch Fence
|
||||
// Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space.
|
||||
@ -164,6 +166,7 @@ class VM_Version : public Abstract_VM_Version {
|
||||
decl(ext_Zvbb , "Zvbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvbb)) \
|
||||
decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvfh)) \
|
||||
decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvkn)) \
|
||||
decl(ext_Zicond , "Zicond" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \
|
||||
decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
|
||||
@ -223,6 +226,7 @@ class VM_Version : public Abstract_VM_Version {
|
||||
RV_ENABLE_EXTENSION(UseZicbom) \
|
||||
RV_ENABLE_EXTENSION(UseZicbop) \
|
||||
RV_ENABLE_EXTENSION(UseZicboz) \
|
||||
RV_ENABLE_EXTENSION(UseZicond) \
|
||||
RV_ENABLE_EXTENSION(UseZihintpause) \
|
||||
|
||||
static void useRVA23U64Profile();
|
||||
|
||||
@ -181,6 +181,9 @@ void RiscvHwprobe::add_features_from_query_result() {
|
||||
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVFH)) {
|
||||
VM_Version::ext_Zvfh.enable_feature();
|
||||
}
|
||||
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) {
|
||||
VM_Version::ext_Zicond.enable_feature();
|
||||
}
|
||||
if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) {
|
||||
VM_Version::unaligned_access.enable_feature(
|
||||
query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK);
|
||||
|
||||
109
test/hotspot/gtest/riscv/test_assembler_riscv.cpp
Normal file
109
test/hotspot/gtest/riscv/test_assembler_riscv.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, Rivos Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#if (defined(RISCV) || defined(RISCV64)) && !defined(ZERO)
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
typedef int64_t (*zicond_func)(int64_t cmp1, int64_t cmp2, int64_t dst, int64_t src);
|
||||
typedef void (MacroAssembler::*cmov_func)(Register cmp1, Register cmp2, Register dst, Register src);
|
||||
|
||||
class CmovTester {
|
||||
public:
|
||||
static void test(cmov_func func, int64_t a0, int64_t a1, int64_t a2, int64_t a3, int64_t result) {
|
||||
BufferBlob* bb = BufferBlob::create("riscvTest", 128);
|
||||
CodeBuffer code(bb);
|
||||
MacroAssembler _masm(&code);
|
||||
address entry = _masm.pc();
|
||||
{
|
||||
((&_masm)->*func)(c_rarg0, c_rarg1, c_rarg2, c_rarg3);
|
||||
_masm.mv(c_rarg0, c_rarg2);
|
||||
_masm.ret();
|
||||
}
|
||||
_masm.flush();
|
||||
OrderAccess::cross_modify_fence();
|
||||
int64_t ret = ((zicond_func)entry)(a0, a1, a2, a3);
|
||||
ASSERT_EQ(ret, result);
|
||||
BufferBlob::free(bb);
|
||||
}
|
||||
};
|
||||
|
||||
void run_cmov_tests() {
|
||||
// If 42(a0) eq 42(a1): assign dest(a2/66) the src(a3/77), expect result: 77
|
||||
CmovTester::test(&MacroAssembler::cmov_eq, 42, 42, 66, 77, 77);
|
||||
// If 41(a0) eq 42(a1): assign dest(a2/66) the src(a3/77), expect result: 66
|
||||
CmovTester::test(&MacroAssembler::cmov_eq, 41, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_ne, 41, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_ne, 42, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_le, 41, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_le, 42, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_le, 42, -1, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_leu, 41, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_leu, 42, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_leu, -1, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_ge, 43, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_ge, 42, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_ge, -1, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_geu, 43, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_geu, 42, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_geu, 42, -1, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_lt, 41, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_lt, 42, 42, 66, 77, 66);
|
||||
CmovTester::test(&MacroAssembler::cmov_lt, 42, -1, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_ltu, 41, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_ltu, 42, 42, 66, 77, 66);
|
||||
CmovTester::test(&MacroAssembler::cmov_ltu, -1, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_gt, 43, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_gt, 42, 42, 66, 77, 66);
|
||||
CmovTester::test(&MacroAssembler::cmov_gt, -1, 42, 66, 77, 66);
|
||||
|
||||
CmovTester::test(&MacroAssembler::cmov_gtu, 43, 42, 66, 77, 77);
|
||||
CmovTester::test(&MacroAssembler::cmov_gtu, 42, 42, 66, 77, 66);
|
||||
CmovTester::test(&MacroAssembler::cmov_gtu, 42, -1, 66, 77, 66);
|
||||
}
|
||||
|
||||
TEST_VM(RiscV, cmov) {
|
||||
run_cmov_tests();
|
||||
if (UseZicond) {
|
||||
UseZicond = false;
|
||||
run_cmov_tests();
|
||||
UseZicond = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RISCV
|
||||
Loading…
x
Reference in New Issue
Block a user