| // |
| // Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. |
| // Copyright (c) 2022, Huawei Technologies Co., Ltd. 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. |
| // |
| // |
| |
| // RISCV Bit-Manipulation Extension Architecture Description File |
| |
| instruct rorI_imm_b(iRegINoSp dst, iRegI src, immI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateRight src shift)); |
| |
| format %{ "roriw $dst, $src, ($shift & 0x1f)\t#@rorI_imm_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ roriw(as_Register($dst$$reg), as_Register($src$$reg), $shift$$constant & 0x1f); |
| %} |
| |
| ins_pipe(ialu_reg_shift); |
| %} |
| |
| instruct rorL_imm_b(iRegLNoSp dst, iRegL src, immI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateRight src shift)); |
| |
| format %{ "rori $dst, $src, ($shift & 0x3f)\t#@rorL_imm_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ rori(as_Register($dst$$reg), as_Register($src$$reg), $shift$$constant & 0x3f); |
| %} |
| |
| ins_pipe(ialu_reg_shift); |
| %} |
| |
| instruct rorI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateRight src shift)); |
| |
| format %{ "rorw $dst, $src, $shift\t#@rorI_reg_b" %} |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ rorw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); |
| %} |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateRight src shift)); |
| |
| format %{ "ror $dst, $src, $shift\t#@rorL_reg_b" %} |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ ror(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); |
| %} |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct rolI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateLeft src shift)); |
| |
| format %{ "rolw $dst, $src, $shift\t#@rolI_reg_b" %} |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ rolw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); |
| %} |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct rolL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ |
| predicate(UseZbb); |
| match(Set dst (RotateLeft src shift)); |
| |
| format %{ "rol $dst, $src, $shift\t#@rolL_reg_b" %} |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ rol(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); |
| %} |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // Convert oop into int for vectors alignment masking |
| instruct convP2I_b(iRegINoSp dst, iRegP src) %{ |
| predicate(UseZba); |
| match(Set dst (ConvL2I (CastP2X src))); |
| |
| format %{ "zext.w $dst, $src\t# ptr -> int @convP2I_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // byte to int |
| instruct convB2I_reg_reg_b(iRegINoSp dst, iRegIorL2I src, immI_24 lshift, immI_24 rshift) %{ |
| predicate(UseZbb); |
| match(Set dst (RShiftI (LShiftI src lshift) rshift)); |
| |
| format %{ "sext.b $dst, $src\t# b2i, #@convB2I_reg_reg_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ sext_b(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // int to short |
| instruct convI2S_reg_reg_b(iRegINoSp dst, iRegIorL2I src, immI_16 lshift, immI_16 rshift) %{ |
| predicate(UseZbb); |
| match(Set dst (RShiftI (LShiftI src lshift) rshift)); |
| |
| format %{ "sext.h $dst, $src\t# i2s, #@convI2S_reg_reg_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ sext_h(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // short to unsigned int |
| instruct convS2UI_reg_reg_b(iRegINoSp dst, iRegIorL2I src, immI_16bits mask) %{ |
| predicate(UseZbb); |
| match(Set dst (AndI src mask)); |
| |
| format %{ "zext.h $dst, $src\t# s2ui, #@convS2UI_reg_reg_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ zext_h(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // int to unsigned long (zero extend) |
| instruct convI2UL_reg_reg_b(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) %{ |
| predicate(UseZba); |
| match(Set dst (AndL (ConvI2L src) mask)); |
| |
| format %{ "zext.w $dst, $src\t# i2ul, #@convI2UL_reg_reg_b" %} |
| |
| ins_cost(ALU_COST); |
| ins_encode %{ |
| __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_shift); |
| %} |
| |
| // BSWAP instructions |
| instruct bytes_reverse_int_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UseZbb); |
| match(Set dst (ReverseBytesI src)); |
| |
| ins_cost(ALU_COST * 2); |
| format %{ "revb_w_w $dst, $src\t#@bytes_reverse_int_b" %} |
| |
| ins_encode %{ |
| __ revb_w_w(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct bytes_reverse_long_b(iRegLNoSp dst, iRegL src) %{ |
| predicate(UseZbb); |
| match(Set dst (ReverseBytesL src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "rev8 $dst, $src\t#@bytes_reverse_long_b" %} |
| |
| ins_encode %{ |
| __ rev8(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct bytes_reverse_unsigned_short_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UseZbb); |
| match(Set dst (ReverseBytesUS src)); |
| |
| ins_cost(ALU_COST * 2); |
| format %{ "revb_h_h_u $dst, $src\t#@bytes_reverse_unsigned_short_b" %} |
| |
| ins_encode %{ |
| __ revb_h_h_u(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct bytes_reverse_short_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UseZbb); |
| match(Set dst (ReverseBytesS src)); |
| |
| ins_cost(ALU_COST * 2); |
| format %{ "revb_h_h $dst, $src\t#@bytes_reverse_short_b" %} |
| |
| ins_encode %{ |
| __ revb_h_h(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // Shift Add Pointer |
| instruct shaddP_reg_reg_b(iRegPNoSp dst, iRegP src1, iRegL src2, immIScale imm) %{ |
| predicate(UseZba); |
| match(Set dst (AddP src1 (LShiftL src2 imm))); |
| |
| ins_cost(ALU_COST); |
| format %{ "shadd $dst, $src2, $src1, $imm\t# ptr, #@shaddP_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ shadd(as_Register($dst$$reg), |
| as_Register($src2$$reg), |
| as_Register($src1$$reg), |
| t0, |
| $imm$$constant); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct shaddP_reg_reg_ext_b(iRegPNoSp dst, iRegP src1, iRegI src2, immIScale imm) %{ |
| predicate(UseZba); |
| match(Set dst (AddP src1 (LShiftL (ConvI2L src2) imm))); |
| |
| ins_cost(ALU_COST); |
| format %{ "shadd $dst, $src2, $src1, $imm\t# ptr, #@shaddP_reg_reg_ext_b" %} |
| |
| ins_encode %{ |
| __ shadd(as_Register($dst$$reg), |
| as_Register($src2$$reg), |
| as_Register($src1$$reg), |
| t0, |
| $imm$$constant); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // Shift Add Long |
| instruct shaddL_reg_reg_b(iRegLNoSp dst, iRegL src1, iRegL src2, immIScale imm) %{ |
| predicate(UseZba); |
| match(Set dst (AddL src1 (LShiftL src2 imm))); |
| |
| ins_cost(ALU_COST); |
| format %{ "shadd $dst, $src2, $src1, $imm\t#@shaddL_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ shadd(as_Register($dst$$reg), |
| as_Register($src2$$reg), |
| as_Register($src1$$reg), |
| t0, |
| $imm$$constant); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct shaddL_reg_reg_ext_b(iRegLNoSp dst, iRegL src1, iRegI src2, immIScale imm) %{ |
| predicate(UseZba); |
| match(Set dst (AddL src1 (LShiftL (ConvI2L src2) imm))); |
| |
| ins_cost(ALU_COST); |
| format %{ "shadd $dst, $src2, $src1, $imm\t#@shaddL_reg_reg_ext_b" %} |
| |
| ins_encode %{ |
| __ shadd(as_Register($dst$$reg), |
| as_Register($src2$$reg), |
| as_Register($src1$$reg), |
| t0, |
| $imm$$constant); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // Zeros Count instructions |
| instruct countLeadingZerosI_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UseZbb); |
| match(Set dst (CountLeadingZerosI src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "clzw $dst, $src\t#@countLeadingZerosI_b" %} |
| |
| ins_encode %{ |
| __ clzw(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct countLeadingZerosL_b(iRegINoSp dst, iRegL src) %{ |
| predicate(UseZbb); |
| match(Set dst (CountLeadingZerosL src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "clz $dst, $src\t#@countLeadingZerosL_b" %} |
| |
| ins_encode %{ |
| __ clz(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct countTrailingZerosI_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UseZbb); |
| match(Set dst (CountTrailingZerosI src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "ctzw $dst, $src\t#@countTrailingZerosI_b" %} |
| |
| ins_encode %{ |
| __ ctzw(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| instruct countTrailingZerosL_b(iRegINoSp dst, iRegL src) %{ |
| predicate(UseZbb); |
| match(Set dst (CountTrailingZerosL src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "ctz $dst, $src\t#@countTrailingZerosL_b" %} |
| |
| ins_encode %{ |
| __ ctz(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // Population Count instructions |
| instruct popCountI_b(iRegINoSp dst, iRegIorL2I src) %{ |
| predicate(UsePopCountInstruction); |
| match(Set dst (PopCountI src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "cpopw $dst, $src\t#@popCountI_b" %} |
| |
| ins_encode %{ |
| __ cpopw(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // Note: Long/bitCount(long) returns an int. |
| instruct popCountL_b(iRegINoSp dst, iRegL src) %{ |
| predicate(UsePopCountInstruction); |
| match(Set dst (PopCountL src)); |
| |
| ins_cost(ALU_COST); |
| format %{ "cpop $dst, $src\t#@popCountL_b" %} |
| |
| ins_encode %{ |
| __ cpop(as_Register($dst$$reg), as_Register($src$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // Max and Min |
| instruct minI_reg_reg_b(iRegINoSp dst, iRegI src1, iRegI src2) %{ |
| predicate(UseZbb); |
| match(Set dst (MinI src1 src2)); |
| |
| ins_cost(ALU_COST); |
| format %{ "min $dst, $src1, $src2\t#@minI_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ min(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct maxI_reg_reg_b(iRegINoSp dst, iRegI src1, iRegI src2) %{ |
| predicate(UseZbb); |
| match(Set dst (MaxI src1 src2)); |
| |
| ins_cost(ALU_COST); |
| format %{ "max $dst, $src1, $src2\t#@maxI_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ max(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // special case for comparing with zero |
| // n.b. this is selected in preference to the rule above because it |
| // avoids loading constant 0 into a source register |
| |
| instruct minI_reg_zero_b(iRegINoSp dst, iRegI src1, immI0 zero) %{ |
| predicate(UseZbb); |
| match(Set dst (MinI src1 zero)); |
| match(Set dst (MinI zero src1)); |
| |
| ins_cost(ALU_COST); |
| format %{ "min $dst, $src1, zr\t#@minI_reg_zero_b" %} |
| |
| ins_encode %{ |
| __ min(as_Register($dst$$reg), as_Register($src1$$reg), zr); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct maxI_reg_zero_b(iRegINoSp dst, iRegI src1, immI0 zero) %{ |
| predicate(UseZbb); |
| match(Set dst (MaxI src1 zero)); |
| match(Set dst (MaxI zero src1)); |
| |
| ins_cost(ALU_COST); |
| format %{ "max $dst, $src1, zr\t#@maxI_reg_zero_b" %} |
| |
| ins_encode %{ |
| __ max(as_Register($dst$$reg), as_Register($src1$$reg), zr); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // Abs |
| instruct absI_reg_b(iRegINoSp dst, iRegI src) %{ |
| predicate(UseZbb); |
| match(Set dst (AbsI src)); |
| |
| ins_cost(ALU_COST * 2); |
| format %{ |
| "negw t0, $src\n\t" |
| "max $dst, $src, t0\t#@absI_reg_b" |
| %} |
| |
| ins_encode %{ |
| __ negw(t0, as_Register($src$$reg)); |
| __ max(as_Register($dst$$reg), as_Register($src$$reg), t0); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct absL_reg_b(iRegLNoSp dst, iRegL src) %{ |
| predicate(UseZbb); |
| match(Set dst (AbsL src)); |
| |
| ins_cost(ALU_COST * 2); |
| format %{ |
| "neg t0, $src\n\t" |
| "max $dst, $src, t0\t#@absL_reg_b" |
| %} |
| |
| ins_encode %{ |
| __ neg(t0, as_Register($src$$reg)); |
| __ max(as_Register($dst$$reg), as_Register($src$$reg), t0); |
| %} |
| |
| ins_pipe(ialu_reg); |
| %} |
| |
| // And Not |
| instruct andnI_reg_reg_b(iRegINoSp dst, iRegI src1, iRegI src2, immI_M1 m1) %{ |
| predicate(UseZbb); |
| match(Set dst (AndI src1 (XorI src2 m1))); |
| |
| ins_cost(ALU_COST); |
| format %{ "andn $dst, $src1, $src2\t#@andnI_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ andn(as_Register($dst$$reg), |
| as_Register($src1$$reg), |
| as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct andnL_reg_reg_b(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ |
| predicate(UseZbb); |
| match(Set dst (AndL src1 (XorL src2 m1))); |
| |
| ins_cost(ALU_COST); |
| format %{ "andn $dst, $src1, $src2\t#@andnL_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ andn(as_Register($dst$$reg), |
| as_Register($src1$$reg), |
| as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // Or Not |
| instruct ornI_reg_reg_b(iRegINoSp dst, iRegI src1, iRegI src2, immI_M1 m1) %{ |
| predicate(UseZbb); |
| match(Set dst (OrI src1 (XorI src2 m1))); |
| |
| ins_cost(ALU_COST); |
| format %{ "orn $dst, $src1, $src2\t#@ornI_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ orn(as_Register($dst$$reg), |
| as_Register($src1$$reg), |
| as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| instruct ornL_reg_reg_b(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ |
| predicate(UseZbb); |
| match(Set dst (OrL src1 (XorL src2 m1))); |
| |
| ins_cost(ALU_COST); |
| format %{ "orn $dst, $src1, $src2\t#@ornL_reg_reg_b" %} |
| |
| ins_encode %{ |
| __ orn(as_Register($dst$$reg), |
| as_Register($src1$$reg), |
| as_Register($src2$$reg)); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |
| |
| // AndI 0b0..010..0 + ConvI2B |
| instruct convI2Bool_andI_reg_immIpowerOf2(iRegINoSp dst, iRegIorL2I src, immIpowerOf2 mask) %{ |
| predicate(UseZbs); |
| match(Set dst (Conv2B (AndI src mask))); |
| ins_cost(ALU_COST); |
| |
| format %{ "bexti $dst, $src, $mask\t#@convI2Bool_andI_reg_immIpowerOf2" %} |
| ins_encode %{ |
| __ bexti($dst$$Register, $src$$Register, exact_log2((juint)($mask$$constant))); |
| %} |
| |
| ins_pipe(ialu_reg_reg); |
| %} |