;; Machine description for RISC-V Bit Manipulation operations.
;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GCC 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 for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; .
;; ZBA extension.
(define_insn "*zero_extendsidi2_bitmanip"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m")))]
"TARGET_64BIT && TARGET_ZBA"
"@
zext.w\t%0,%1
lwu\t%0,%1"
[(set_attr "type" "bitmanip,load")
(set_attr "mode" "DI")])
(define_insn "*shNadd"
[(set (match_operand:X 0 "register_operand" "=r")
(plus:X (ashift:X (match_operand:X 1 "register_operand" "r")
(match_operand:QI 2 "imm123_operand" "Ds3"))
(match_operand:X 3 "register_operand" "r")))]
"TARGET_ZBA"
"sh%2add\t%0,%1,%3"
[(set_attr "type" "bitmanip")
(set_attr "mode" "")])
(define_insn "*shNadduw"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI
(and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:QI 2 "imm123_operand" "Ds3"))
(match_operand 3 "immediate_operand" "n"))
(match_operand:DI 4 "register_operand" "r")))]
"TARGET_64BIT && TARGET_ZBA
&& (INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff"
"sh%2add.uw\t%0,%1,%4"
[(set_attr "type" "bitmanip")
(set_attr "mode" "DI")])
;; During combine, we may encounter an attempt to combine
;; slli rtmp, rs, #imm
;; zext.w rtmp, rtmp
;; sh[123]add rd, rtmp, rs2
;; which will lead to the immediate not satisfying the above constraints.
;; By splitting the compound expression, we can simplify to a slli and a
;; sh[123]add.uw.
(define_split
[(set (match_operand:DI 0 "register_operand")
(plus:DI (and:DI (ashift:DI (match_operand:DI 1 "register_operand")
(match_operand:QI 2 "immediate_operand"))
(match_operand:DI 3 "consecutive_bits_operand"))
(match_operand:DI 4 "register_operand")))
(clobber (match_operand:DI 5 "register_operand"))]
"TARGET_64BIT && TARGET_ZBA"
[(set (match_dup 5) (ashift:DI (match_dup 1) (match_dup 6)))
(set (match_dup 0) (plus:DI (and:DI (ashift:DI (match_dup 5)
(match_dup 7))
(match_dup 8))
(match_dup 4)))]
{
unsigned HOST_WIDE_INT mask = UINTVAL (operands[3]);
/* scale: shift within the sh[123]add.uw */
unsigned HOST_WIDE_INT scale = 32 - clz_hwi (mask);
/* bias: pre-scale amount (i.e. the prior shift amount) */
int bias = ctz_hwi (mask) - scale;
/* If the bias + scale don't add up to operand[2], reject. */
if ((scale + bias) != UINTVAL (operands[2]))
FAIL;
/* If the shift-amount is out-of-range for sh[123]add.uw, reject. */
if ((scale < 1) || (scale > 3))
FAIL;
/* If there's no bias, the '*shNadduw' pattern should have matched. */
if (bias == 0)
FAIL;
operands[6] = GEN_INT (bias);
operands[7] = GEN_INT (scale);
operands[8] = GEN_INT (0xffffffffULL << scale);
})
(define_insn "*add.uw"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (zero_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))]
"TARGET_64BIT && TARGET_ZBA"
"add.uw\t%0,%1,%2"
[(set_attr "type" "bitmanip")
(set_attr "mode" "DI")])
(define_insn "*slliuw"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:QI 2 "immediate_operand" "I"))
(match_operand 3 "immediate_operand" "n")))]
"TARGET_64BIT && TARGET_ZBA
&& (INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff"
"slli.uw\t%0,%1,%2"
[(set_attr "type" "bitmanip")
(set_attr "mode" "DI")])
;; ZBB extension.
(define_insn "*_not"
[(set (match_operand:X 0 "register_operand" "=r")
(bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r"))
(match_operand:X 2 "register_operand" "r")))]
"TARGET_ZBB"
"n\t%0,%2,%1"
[(set_attr "type" "bitmanip")
(set_attr "mode" "")])
(define_insn "*xor_not"
[(set (match_operand:X 0 "register_operand" "=r")
(not:X (xor:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "register_operand" "r"))))]
"TARGET_ZBB"
"xnor\t%0,%1,%2"
[(set_attr "type" "bitmanip")
(set_attr "mode" "")])
(define_insn "si2"
[(set (match_operand:SI 0 "register_operand" "=r")
(clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r")))]
"TARGET_ZBB"
"%~\t%0,%1"
[(set_attr "type" "bitmanip")
(set_attr "mode" "SI")])
(define_insn "*disi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r"))))]
"TARGET_64BIT && TARGET_ZBB"
"w\t%0,%1"
[(set_attr "type" "bitmanip")
(set_attr "mode" "SI")])
(define_insn "di2"
[(set (match_operand:DI 0 "register_operand" "=r")
(clz_ctz_pcnt:DI (match_operand:DI 1 "register_operand" "r")))]
"TARGET_64BIT && TARGET_ZBB"
"\t%0,%1"
[(set_attr "type" "bitmanip")
(set_attr "mode" "DI")])
(define_insn "*zero_extendhi2_bitmanip"
[(set (match_operand:GPR 0 "register_operand" "=r,r")
(zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
"TARGET_ZBB"
"@
zext.h\t%0,%1
lhu\t%0,%1"
[(set_attr "type" "bitmanip,load")
(set_attr "mode" "")])
(define_insn "*extend2_zbb"
[(set (match_operand:SUPERQI 0 "register_operand" "=r,r")
(sign_extend:SUPERQI
(match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
"TARGET_ZBB"
"@
sext.\t%0,%1
l\t%0,%1"
[(set_attr "type" "bitmanip,load")
(set_attr "mode" "")])
(define_insn "*zero_extendhi2_zbb"
[(set (match_operand:GPR 0 "register_operand" "=r,r")
(zero_extend:GPR
(match_operand:HI 1 "nonimmediate_operand" " r,m")))]
"TARGET_ZBB"
"@
zext.h\t%0,%1
lhu\t%0,%1"
[(set_attr "type" "bitmanip,load")
(set_attr "mode" "HI")])
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "arith_operand" "rI")))]
"TARGET_ZBB"
"ror%i2%~\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "rotrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(rotatert:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:QI 2 "arith_operand" "rI")))]
"TARGET_64BIT && TARGET_ZBB"
"ror%i2\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "rotrsi3_sext"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r"))))]
"TARGET_64BIT && TARGET_ZBB"
"rorw\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotate:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r")))]
"TARGET_ZBB"
"rol%~\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "rotldi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(rotate:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r")))]
"TARGET_64BIT && TARGET_ZBB"
"rol\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "rotlsi3_sext"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (rotate:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r"))))]
"TARGET_64BIT && TARGET_ZBB"
"rolw\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "bswap2"
[(set (match_operand:X 0 "register_operand" "=r")
(bswap:X (match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBB"
"rev8\t%0,%1"
[(set_attr "type" "bitmanip")])
;; HI bswap can be emulated using SI/DI bswap followed
;; by a logical shift right
;; SI bswap for TARGET_64BIT is already similarly in
;; the common code.
(define_expand "bswaphi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(bswap:HI (match_operand:HI 1 "register_operand" "r")))]
"TARGET_ZBB"
{
rtx tmp = gen_reg_rtx (word_mode);
rtx newop1 = gen_lowpart (word_mode, operands[1]);
if (TARGET_64BIT)
emit_insn (gen_bswapdi2 (tmp, newop1));
else
emit_insn (gen_bswapsi2 (tmp, newop1));
rtx tmp1 = gen_reg_rtx (word_mode);
if (TARGET_64BIT)
emit_insn (gen_lshrdi3 (tmp1, tmp, GEN_INT (64 - 16)));
else
emit_insn (gen_lshrsi3 (tmp1, tmp, GEN_INT (32 - 16)));
emit_move_insn (operands[0], gen_lowpart (HImode, tmp1));
DONE;
})
(define_insn "3"
[(set (match_operand:X 0 "register_operand" "=r")
(bitmanip_minmax:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "register_operand" "r")))]
"TARGET_ZBB"
"\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
;; ZBS extension.
(define_insn "*bset"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (ashift:X (const_int 1)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "*bset_mask"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (ashift:X (const_int 1)
(subreg:QI
(and:X (match_operand:X 2 "register_operand" "r")
(match_operand 3 "" "")) 0))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "*bset_1"
[(set (match_operand:X 0 "register_operand" "=r")
(ashift:X (const_int 1)
(match_operand:QI 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,x0,%1"
[(set_attr "type" "bitmanip")])
(define_insn "*bset_1_mask"
[(set (match_operand:X 0 "register_operand" "=r")
(ashift:X (const_int 1)
(subreg:QI
(and:X (match_operand:X 1 "register_operand" "r")
(match_operand 2 "" "")) 0)))]
"TARGET_ZBS"
"bset\t%0,x0,%1"
[(set_attr "type" "bitmanip")])
(define_insn "*bseti"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "single_bit_mask_operand" "DbS")))]
"TARGET_ZBS"
"bseti\t%0,%1,%S2"
[(set_attr "type" "bitmanip")])
(define_insn "*bclr"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (rotate:X (const_int -2)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bclr\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "*bclri"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "not_single_bit_mask_operand" "DnS")))]
"TARGET_ZBS"
"bclri\t%0,%1,%T2"
[(set_attr "type" "bitmanip")])
(define_insn "*binv"
[(set (match_operand:X 0 "register_operand" "=r")
(xor:X (ashift:X (const_int 1)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"binv\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "*binvi"
[(set (match_operand:X 0 "register_operand" "=r")
(xor:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "single_bit_mask_operand" "DbS")))]
"TARGET_ZBS"
"binvi\t%0,%1,%S2"
[(set_attr "type" "bitmanip")])
(define_insn "*bext"
[(set (match_operand:X 0 "register_operand" "=r")
(zero_extract:X (match_operand:X 1 "register_operand" "r")
(const_int 1)
(zero_extend:X
(match_operand:QI 2 "register_operand" "r"))))]
"TARGET_ZBS"
"bext\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
(define_insn "*bexti"
[(set (match_operand:X 0 "register_operand" "=r")
(zero_extract:X (match_operand:X 1 "register_operand" "r")
(const_int 1)
(match_operand 2 "immediate_operand" "n")))]
"TARGET_ZBS && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)"
"bexti\t%0,%1,%2"
[(set_attr "type" "bitmanip")])