;; Machine description for T-Head vendor extensions ;; 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 ;; http://www.gnu.org/licenses/.
;; XTheadBa
(define_insn “*th_addsl4” [(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_XTHEADBA” “th.addsl\t%0,%3,%1,%2” [(set_attr “type” “bitmanip”) (set_attr “mode” “<X:MODE>”)])
;; XTheadBb
(define_insn “*th_srri3” [(set (match_operand:GPR 0 “register_operand” “=r”) (rotatert:GPR (match_operand:GPR 1 “register_operand” “r”) (match_operand 2 “const_int_operand” “n”)))] “TARGET_XTHEADBB && (TARGET_64BIT || mode == SImode)” { bool wform = TARGET_64BIT && (mode == SImode); operands[2] = GEN_INT (INTVAL (operands[2]) & (GET_MODE_BITSIZE (mode) - 1)); return wform ? “th.srriw\t%0,%1,%2” : “th.srri\t%0,%1,%2”; } [(set_attr “type” “bitmanip”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*th_ext4” [(set (match_operand:GPR 0 “register_operand” “=r”) (sign_extract:GPR (match_operand:GPR 1 “register_operand” “r”) (match_operand 2 “const_int_operand”) (match_operand 3 “const_int_operand”)))] “TARGET_XTHEADBB” { operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1); return “th.ext\t%0,%1,%2,%3”; } [(set_attr “type” “bitmanip”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*extendhiSUPERQI:mode2_th_ext” [(set (match_operand:SUPERQI 0 “register_operand” “=r,r”) (sign_extend:SUPERQI (match_operand:HI 1 “nonimmediate_operand” “r,m”)))] “TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX” “@ th.ext\t%0,%1,15,0 lh\t%0,%1” [(set_attr “type” “bitmanip,load”) (set_attr “mode” “SUPERQI:MODE”)])
(define_insn “*extendqiSUPERQI:mode2_th_ext” [(set (match_operand:SUPERQI 0 “register_operand” “=r,r”) (sign_extend:SUPERQI (match_operand:QI 1 “nonimmediate_operand” “r,m”)))] “TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX” “@ th.ext\t%0,%1,7,0 lb\t%0,%1” [(set_attr “type” “bitmanip,load”) (set_attr “mode” “SUPERQI:MODE”)])
(define_insn “*th_extu4” [(set (match_operand:GPR 0 “register_operand” “=r”) (zero_extract:GPR (match_operand:GPR 1 “register_operand” “r”) (match_operand 2 “const_int_operand”) (match_operand 3 “const_int_operand”)))] “TARGET_XTHEADBB” { operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1); return “th.extu\t%0,%1,%2,%3”; } [(set_attr “type” “bitmanip”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*zero_extendsidi2_th_extu” [(set (match_operand:DI 0 “register_operand” “=r,r”) (zero_extend:DI (match_operand:SI 1 “nonimmediate_operand” “r,m”)))] “TARGET_64BIT && TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX” “@ th.extu\t%0,%1,31,0 lwu\t%0,%1” [(set_attr “type” “bitmanip,load”) (set_attr “mode” “DI”)])
(define_insn “*zero_extendhiGPR:mode2_th_extu” [(set (match_operand:GPR 0 “register_operand” “=r,r”) (zero_extend:GPR (match_operand:HI 1 “nonimmediate_operand” “r,m”)))] “TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX” “@ th.extu\t%0,%1,15,0 lhu\t%0,%1” [(set_attr “type” “bitmanip,load”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*th_clz2” [(set (match_operand:X 0 “register_operand” “=r”) (clz:X (match_operand:X 1 “register_operand” “r”)))] “TARGET_XTHEADBB” “th.ff1\t%0,%1” [(set_attr “type” “bitmanip”) (set_attr “mode” “<X:MODE>”)])
(define_insn “th_rev2” [(set (match_operand:GPR 0 “register_operand” “=r”) (bswap:GPR (match_operand:GPR 1 “register_operand” “r”)))] “TARGET_XTHEADBB && (TARGET_64BIT || mode == SImode)” { bool wform = TARGET_64BIT && (mode == SImode); return wform ? “th.revw\t%0,%1” : “th.rev\t%0,%1”; } [(set_attr “type” “bitmanip”) (set_attr “mode” “GPR:MODE”)])
(define_insn “th_tstnbz2” [(set (match_operand:X 0 “register_operand” “=r”) (unspec:X [(match_operand:X 1 “register_operand” “r”)] UNSPEC_ORC_B))] “TARGET_XTHEADBB” “th.tstnbz\t%0,%1” [(set_attr “type” “bitmanip”)])
;; XTheadBs
(define_insn “*th_tst3” [(set (match_operand:X 0 “register_operand” “=r”) (zero_extract:X (match_operand:X 1 “register_operand” “r”) (const_int 1) (match_operand 2 “const_int_operand” “n”)))] “TARGET_XTHEADBS && UINTVAL (operands[2]) < GET_MODE_BITSIZE (mode)” “th.tst\t%0,%1,%2” [(set_attr “type” “bitmanip”)])
;; XTheadCondMov
(define_insn “*th_cond_movGPR:modeGPR2:mode” [(set (match_operand:GPR 0 “register_operand” “=r,r”) (if_then_else:GPR (match_operator 4 “equality_operator” [(match_operand:GPR2 1 “register_operand” “r,r”) (const_int 0)]) (match_operand:GPR 2 “reg_or_0_operand” “rJ,0”) (match_operand:GPR 3 “reg_or_0_operand” “0,rJ”)))] “TARGET_XTHEADCONDMOV” { if (which_alternative == 0) return “th.mv%C4z\t%0,%z2,%1”;
/* Invert the condition and take else-block. */ rtx_code code = GET_CODE (operands[4]); code = (code == EQ) ? NE : EQ; operands[4] = gen_rtx_fmt_ee (code, VOIDmode, operands[1], const0_rtx); return “th.mv%C4z\t%0,%z3,%1”; } [(set_attr “type” “condmove”) (set_attr “mode” “GPR:MODE”)])
;; XTheadFmv
;; In RV32, we lack fmv.x.d and fmv.d.x, but XTheadFmv has instructions ;; that cover this case.
(define_insn “th_fmv_hw_w_x” [(set (match_operand:DF 0 “register_operand” “=f”) (unspec:DF [(match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)] UNSPEC_XTHEADFMV))] “!TARGET_64BIT && TARGET_XTHEADFMV” “fmv.w.x\t%0,%2\n\tth.fmv.hw.x\t%0,%1” [(set_attr “move_type” “move”) (set_attr “type” “fmove”) (set_attr “mode” “DF”)])
(define_insn “th_fmv_x_w” [(set (match_operand:SI 0 “register_operand” “=r”) (unspec:SI [(match_operand:DF 1 “register_operand” “f”)] UNSPEC_XTHEADFMV))] “!TARGET_64BIT && TARGET_XTHEADFMV” “fmv.x.w\t%0,%1” [(set_attr “move_type” “move”) (set_attr “type” “fmove”) (set_attr “mode” “DF”)])
(define_insn “th_fmv_x_hw” [(set (match_operand:SI 0 “register_operand” “=r”) (unspec:SI [(match_operand:DF 1 “register_operand” “f”)] UNSPEC_XTHEADFMV_HW))] “!TARGET_64BIT && TARGET_XTHEADFMV” “th.fmv.x.hw\t%0,%1” [(set_attr “move_type” “move”) (set_attr “type” “fmove”) (set_attr “mode” “DF”)])
;; XTheadMac
(define_insn “*th_mula” [(set (match_operand:X 0 “register_operand” “=r”) (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:X 2 “register_operand” “r”)) (match_operand:X 3 “register_operand” “0”)))] “TARGET_XTHEADMAC” “th.mula\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “”)] )
(define_insn “*th_mulawsi” [(set (match_operand:DI 0 “register_operand” “=r”) (sign_extend:DI (plus:SI (mult:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)) (match_operand:SI 3 “register_operand” “0”))))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulaw\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_mulawsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (mult:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)) (match_operand:SI 3 “register_operand” “0”)))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulaw\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_maddhisi4” [(set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (mult:SI (sign_extend:SI (match_operand:HI 1 “register_operand” " r")) (sign_extend:SI (match_operand:HI 2 “register_operand” " r"))) (match_operand:SI 3 “register_operand” " 0")))] “TARGET_XTHEADMAC” “th.mulah\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_sextw_maddhisi4” [(set (match_operand:DI 0 “register_operand” “=r”) (sign_extend:DI (plus:SI (mult:SI (sign_extend:SI (match_operand:HI 1 “register_operand” " r")) (sign_extend:SI (match_operand:HI 2 “register_operand” " r"))) (match_operand:SI 3 “register_operand” " 0"))))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulah\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_muls” [(set (match_operand:X 0 “register_operand” “=r”) (minus:X (match_operand:X 3 “register_operand” “0”) (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:X 2 “register_operand” “r”))))] “TARGET_XTHEADMAC” “th.muls\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “”)] )
(define_insn “*th_mulswsi” [(set (match_operand:DI 0 “register_operand” “=r”) (sign_extend:DI (minus:SI (match_operand:SI 3 “register_operand” “0”) (mult:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”)))))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulsw\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_mulswsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (minus:SI (match_operand:SI 3 “register_operand” “0”) (mult:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “register_operand” “r”))))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulsw\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_msubhisi4” [(set (match_operand:SI 0 “register_operand” “=r”) (minus:SI (match_operand:SI 3 “register_operand” " 0") (mult:SI (sign_extend:SI (match_operand:HI 1 “register_operand” " r")) (sign_extend:SI (match_operand:HI 2 “register_operand” " r")))))] “TARGET_XTHEADMAC” “th.mulsh\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
(define_insn “*th_sextw_msubhisi4” [(set (match_operand:DI 0 “register_operand” “=r”) (sign_extend:DI (minus:SI (match_operand:SI 3 “register_operand” " 0") (mult:SI (sign_extend:SI (match_operand:HI 1 “register_operand” " r")) (sign_extend:SI (match_operand:HI 2 “register_operand” " r"))))))] “TARGET_XTHEADMAC && TARGET_64BIT” “th.mulsh\t%0,%1,%2” [(set_attr “type” “imul”) (set_attr “mode” “SI”)] )
;; XTheadMemPair
;; MEMPAIR load 64/32 bit (define_insn “*th_mempair_load_GPR:mode2” [(set (match_operand:GPR 0 “register_operand” “=r”) (match_operand:GPR 1 “memory_operand” “m”)) (set (match_operand:GPR 2 “register_operand” “=r”) (match_operand:GPR 3 “memory_operand” “m”))] “TARGET_XTHEADMEMPAIR && reload_completed && th_mempair_operands_p (operands, true, GPR:MODEmode)” { return th_mempair_output_move (operands, true, GPR:MODEmode, UNKNOWN); } [(set_attr “move_type” “load”) (set_attr “type” “load”) (set_attr “mode” “GPR:MODE”)])
;; MEMPAIR store 64/32 bit (define_insn “*th_mempair_store_GPR:mode2” [(set (match_operand:GPR 0 “memory_operand” “=m”) (match_operand:GPR 1 “register_operand” “r”)) (set (match_operand:GPR 2 “memory_operand” “=m”) (match_operand:GPR 3 “register_operand” “r”))] “TARGET_XTHEADMEMPAIR && reload_completed && th_mempair_operands_p (operands, false, GPR:MODEmode)” { return th_mempair_output_move (operands, false, GPR:MODEmode, UNKNOWN); } [(set_attr “move_type” “store”) (set_attr “type” “store”) (set_attr “mode” “GPR:MODE”)])
;; MEMPAIR load DI extended signed SI (define_insn “*th_mempair_load_extendsidi2” [(set (match_operand:DI 0 “register_operand” “=r”) (sign_extend:DI (match_operand:SI 1 “memory_operand” “m”))) (set (match_operand:DI 2 “register_operand” “=r”) (sign_extend:DI (match_operand:SI 3 “memory_operand” “m”)))] “TARGET_XTHEADMEMPAIR && TARGET_64BIT && reload_completed && th_mempair_operands_p (operands, true, SImode)” { return th_mempair_output_move (operands, true, SImode, SIGN_EXTEND); } [(set_attr “move_type” “load”) (set_attr “type” “load”) (set_attr “mode” “DI”) (set_attr “length” “8”)])
;; MEMPAIR load DI extended unsigned SI (define_insn “*th_mempair_load_zero_extendsidi2” [(set (match_operand:DI 0 “register_operand” “=r”) (zero_extend:DI (match_operand:SI 1 “memory_operand” “m”))) (set (match_operand:DI 2 “register_operand” “=r”) (zero_extend:DI (match_operand:SI 3 “memory_operand” “m”)))] “TARGET_XTHEADMEMPAIR && TARGET_64BIT && reload_completed && th_mempair_operands_p (operands, true, SImode)” { return th_mempair_output_move (operands, true, SImode, ZERO_EXTEND); } [(set_attr “move_type” “load”) (set_attr “type” “load”) (set_attr “mode” “DI”) (set_attr “length” “8”)])
;; XTheadMemIdx
;; Help reload to add a displacement for the base register. ;; In the case zext(*(uN*)(base+(zext(rN)<<1)))
LRA splits ;; off two new instructions: a) new_base = base + disp
, and ;; b) index = zext(rN)<<1
. The index calculation has no ;; corresponding instruction pattern and needs this insn_and_split ;; to recover.
(define_insn_and_split “*th_memidx_operand” [(set (match_operand:DI 0 “register_operand” “=r”) (ashift:DI (zero_extend:DI (subreg:SI (match_operand:DI 1 “register_operand” “r”) 0)) (match_operand 2 “const_int_operand” “n”)))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && lra_in_progress” “#” "" [(set (match_dup 0) (zero_extend:DI (subreg:SI (match_dup 1) 0))) (set (match_dup 0) (ashift:DI (match_dup 0) (match_dup 2)))] "" [(set_attr “type” “bitmanip”)])
(define_insn “*th_memidx_zero_extendqiSUPERQI:mode2” [(set (match_operand:SUPERQI 0 “register_operand” “=r,r,r,r,r,r”) (zero_extend:SUPERQI (match_operand:QI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX” “@ andi\t%0,%1,0xff th.lbuia\t%0,%1 th.lbuib\t%0,%1 th.lrbu\t%0,%1 th.lurbu\t%0,%1 lbu\t%0,%1” [(set_attr “move_type” “andi,load,load,load,load,load”) (set_attr “mode” “SUPERQI:MODE”)])
(define_insn “*th_memidx_extendsidi2” [(set (match_operand:DI 0 “register_operand” “=r,r,r,r,r,r”) (sign_extend:DI (match_operand:SI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_64BIT && TARGET_XTHEADMEMIDX” “@ sext.w\t%0,%1 th.lwia\t%0,%1 th.lwib\t%0,%1 th.lrw\t%0,%1 th.lurw\t%0,%1 lw\t%0,%1” [(set_attr “move_type” “move,load,load,load,load,load”) (set_attr “mode” “DI”)])
;; XTheadMemIdx (without XTheadBb)
(define_insn_and_split “*th_memidx_zero_extendsidi2” [(set (match_operand:DI 0 “register_operand” “=r,r,r,r,r,r”) (zero_extend:DI (match_operand:SI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && !TARGET_XTHEADBB” "@
th.lwuia\t%0,%1 th.lwuib\t%0,%1 th.lrwu\t%0,%1 th.lurwu\t%0,%1 lwu\t%0,%1" “&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])” [(set (match_dup 0) (ashift:DI (match_dup 1) (const_int 32))) (set (match_dup 0) (lshiftrt:DI (match_dup 0) (const_int 32)))] { operands[1] = gen_lowpart (DImode, operands[1]); } [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “DI”)])
(define_insn_and_split “*th_memidx_zero_extendhiGPR:mode2” [(set (match_operand:GPR 0 “register_operand” “=r,r,r,r,r,r”) (zero_extend:GPR (match_operand:HI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX && !TARGET_XTHEADBB” "@
th.lhuia\t%0,%1 th.lhuib\t%0,%1 th.lrhu\t%0,%1 th.lurhu\t%0,%1 lhu\t%0,%1" “&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])” [(set (match_dup 0) (ashift:GPR (match_dup 1) (match_dup 2))) (set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))] { operands[1] = gen_lowpart (GPR:MODEmode, operands[1]); operands[2] = GEN_INT(GET_MODE_BITSIZE(GPR:MODEmode) - 16); } [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “GPR:MODE”)])
(define_insn_and_split “*th_memidx_extendSHORT:modeSUPERQI:mode2” [(set (match_operand:SUPERQI 0 “register_operand” “=r,r,r,r,r,r”) (sign_extend:SUPERQI (match_operand:SHORT 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX && !TARGET_XTHEADBB” "@
th.lSHORT:sizeia\t%0,%1 th.lSHORT:sizeib\t%0,%1 th.lrSHORT:size\t%0,%1 th.lurSHORT:size\t%0,%1 lSHORT:size\t%0,%1" “&& reload_completed && REG_P (operands[1]) && !paradoxical_subreg_p (operands[0])” [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))] { operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (SHORT:MODEmode)); } [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “SI”)])
;; XTheadMemIdx (with XTheadBb)
(define_insn “*th_memidx_bb_zero_extendsidi2” [(set (match_operand:DI 0 “register_operand” “=r,r,r,r,r,r”) (zero_extend:DI (match_operand:SI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADBB” “@ th.extu\t%0,%1,31,0 th.lwuia\t%0,%1 th.lwuib\t%0,%1 th.lrwu\t%0,%1 th.lurwu\t%0,%1 lwu\t%0,%1” [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “DI”)])
(define_insn “*th_memidx_bb_zero_extendhiGPR:mode2” [(set (match_operand:GPR 0 “register_operand” “=r,r,r,r,r,r”) (zero_extend:GPR (match_operand:HI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX && TARGET_XTHEADBB” “@ th.extu\t%0,%1,15,0 th.lhuia\t%0,%1 th.lhuib\t%0,%1 th.lrhu\t%0,%1 th.lurhu\t%0,%1 lhu\t%0,%1” [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*th_memidx_bb_extendhiGPR:mode2” [(set (match_operand:GPR 0 “register_operand” “=r,r,r,r,r,r”) (sign_extend:GPR (match_operand:HI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX && TARGET_XTHEADBB” “@ th.ext\t%0,%1,15,0 th.lhia\t%0,%1 th.lhib\t%0,%1 th.lrh\t%0,%1 th.lurh\t%0,%1 lh\t%0,%1” [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “GPR:MODE”)])
(define_insn “*th_memidx_bb_extendqiSUPERQI:mode2” [(set (match_operand:SUPERQI 0 “register_operand” “=r,r,r,r,r,r”) (sign_extend:SUPERQI (match_operand:QI 1 “nonimmediate_operand” " r,th_m_mia,th_m_mib,th_m_mir,th_m_miu,m")))] “TARGET_XTHEADMEMIDX && TARGET_XTHEADBB” “@ th.ext\t%0,%1,7,0 th.lbia\t%0,%1 th.lbib\t%0,%1 th.lrb\t%0,%1 th.lurb\t%0,%1 lb\t%0,%1” [(set_attr “move_type” “shift_shift,load,load,load,load,load”) (set_attr “mode” “SUPERQI:MODE”)])
;; All modes that are supported by XTheadMemIdx (define_mode_iterator TH_M_ANYI [(QI “TARGET_XTHEADMEMIDX”) (HI “TARGET_XTHEADMEMIDX”) (SI “TARGET_XTHEADMEMIDX”) (DI “TARGET_64BIT && TARGET_XTHEADMEMIDX”)])
;; All modes that are supported by XTheadFMemIdx (define_mode_iterator TH_M_ANYF [(SF “TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX”) (DF “TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX”)])
;; All non-extension modes that are supported by XTheadMemIdx (define_mode_iterator TH_M_NOEXTI [(SI “!TARGET_64BIT && TARGET_XTHEADMEMIDX”) (DI “TARGET_64BIT && TARGET_XTHEADMEMIDX”)])
;; All non-extension modes that are supported by XTheadFMemIdx (define_mode_iterator TH_M_NOEXTF [(SF “TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX”) (DF “TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX”)])
;; XTheadMemIdx optimizations ;; All optimizations attempt to improve the operand utilization of ;; XTheadMemIdx instructions, where one sign or zero extended ;; register-index-operand can be shifted left by a 2-bit immediate. ;; ;; The basic idea is the following optimization: ;; (set (reg 0) (op (reg 1) (imm 2))) ;; (set (reg 3) (mem (plus (reg 0) (reg 4))) ;; ==> ;; (set (reg 3) (mem (plus (reg 4) (op2 (reg 1) (imm 2)))) ;; This optimization only valid if (reg 0) has no further uses. ;; ;; The three-instruction case is as follows: ;; (set (reg 0) (op1 (reg 1) (imm 2))) ;; (set (reg 3) (op2 (reg 0) (imm 4))) ;; (set (reg 5) (mem (plus (reg 3) (reg 6))) ;; ==> ;; (set (reg 5) (mem (plus (reg 6) (op2 (reg 1) (imm 2/4))))) ;; This optimization is only valid if (reg 0) and (reg 3) have no further uses. ;; ;; The optimization cases are: ;; I) fold 2-bit ashift of register offset into mem-plus RTX ;; US) fold 32-bit zero-extended (shift) offset into mem-plus ;; UZ) fold 32-bit zero-extended (zext) offset into mem-plus ;; ;; The first optimization case is targeting the th.lr instructions. ;; The other optimization cases are targeting the th.lur instructions ;; and have to consider two forms of zero-extensions: ;; - ashift-32 + lshiftrt-{29..32} if there are no zero-extension instructions. ;; Left-shift amounts of 29..31 indicate a left-shifted zero-extended value. ;; - zero-extend32 if there are zero-extension instructions (XTheadBb or Zbb). ;; ;; We always have three peephole passes per optimization case: ;; a) no-extended (X) word-load ;; b) any-extend (SUBX) word-load ;; c) store ;; ;; Note, that SHIFTs will be converted to MULTs during combine.
(define_insn_and_split “*th_memidx_I_a” [(set (match_operand:TH_M_NOEXTI 0 “register_operand” “=r”) (mem:TH_M_NOEXTI (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:X 3 “register_operand” “r”))))] “TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTI (plus:X (match_dup 3) (ashift:X (match_dup 1) (match_dup 2)))))] { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_I_b” [(set (match_operand:X 0 “register_operand” “=r”) (any_extend:X (mem:SUBX (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:X 3 “register_operand” “r”)))))] “TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)” “#” “&& 1” [(set (match_dup 0) (any_extend:X (mem:SUBX (plus:X (match_dup 3) (ashift:X (match_dup 1) (match_dup 2))))))] { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_I_c” [(set (mem:TH_M_ANYI (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:X 3 “register_operand” “r”))) (match_operand:TH_M_ANYI 0 “register_operand” “r”))] “TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)” “#” “&& 1” [(set (mem:TH_M_ANYI (plus:X (match_dup 3) (ashift:X (match_dup 1) (match_dup 2)))) (match_dup 0))] { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_US_a” [(set (match_operand:TH_M_NOEXTI 0 “register_operand” “=r”) (mem:TH_M_NOEXTI (plus:DI (and:DI (mult:DI (match_operand:DI 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:DI 3 “immediate_operand” “i”)) (match_operand:DI 4 “register_operand” “r”))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3) && CONST_INT_P (operands[3]) && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTI (plus:DI (match_dup 4) (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))))] { operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_US_b” [(set (match_operand:X 0 “register_operand” “=r”) (any_extend:X (mem:SUBX (plus:DI (and:DI (mult:DI (match_operand:DI 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:DI 3 “immediate_operand” “i”)) (match_operand:DI 4 “register_operand” “r”)))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3) && CONST_INT_P (operands[3]) && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff” “#” “&& 1” [(set (match_dup 0) (any_extend:X (mem:SUBX (plus:DI (match_dup 4) (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2))))))] { operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_US_c” [(set (mem:TH_M_ANYI (plus:DI (and:DI (mult:DI (match_operand:DI 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:DI 3 “immediate_operand” “i”)) (match_operand:DI 4 “register_operand” “r”))) (match_operand:TH_M_ANYI 0 “register_operand” “r”))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3) && CONST_INT_P (operands[3]) && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff” “#” “&& 1” [(set (mem:TH_M_ANYI (plus:DI (match_dup 4) (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))) (match_dup 0))] { operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_memidx_UZ_a” [(set (match_operand:TH_M_NOEXTI 0 “register_operand” “=r”) (mem:TH_M_NOEXTI (plus:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (match_operand:DI 2 “register_operand” “r”))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTI (plus:DI (match_dup 2) (zero_extend:DI (match_dup 1)))))] )
(define_insn_and_split “*th_memidx_UZ_b” [(set (match_operand:X 0 “register_operand” “=r”) (any_extend:X (mem:SUBX (plus:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (match_operand:DI 2 “register_operand” “r”)))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX” “#” “&& 1” [(set (match_dup 0) (any_extend:X (mem:SUBX (plus:DI (match_dup 2) (zero_extend:DI (match_dup 1))))))] )
(define_insn_and_split “*th_memidx_UZ_c” [(set (mem:TH_M_ANYI (plus:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (match_operand:DI 2 “register_operand” “r”))) (match_operand:TH_M_ANYI 0 “register_operand” “r”))] “TARGET_64BIT && TARGET_XTHEADMEMIDX” “#” “&& 1” [(set (mem:TH_M_ANYI (plus:DI (match_dup 2) (zero_extend:DI (match_dup 1)))) (match_dup 0))] )
;; XTheadFMemIdx
(define_insn “*th_fmemidx_movsf_hardfloat” [(set (match_operand:SF 0 “nonimmediate_operand” “=f,th_m_mir,f,th_m_miu”) (match_operand:SF 1 “move_operand” " th_m_mir,f,th_m_miu,f"))] “TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))” { return riscv_output_move (operands[0], operands[1]); } [(set_attr “move_type” “fpload,fpstore,fpload,fpstore”) (set_attr “mode” “SF”)])
(define_insn “*th_fmemidx_movdf_hardfloat_rv64” [(set (match_operand:DF 0 “nonimmediate_operand” “=f,th_m_mir,f,th_m_miu”) (match_operand:DF 1 “move_operand” " th_m_mir,f,th_m_miu,f"))] “TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX && (register_operand (operands[0], DFmode) || reg_or_0_operand (operands[1], DFmode))” { return riscv_output_move (operands[0], operands[1]); } [(set_attr “move_type” “fpload,fpstore,fpload,fpstore”) (set_attr “mode” “DF”)])
;; XTheadFMemIdx optimizations ;; Similar like XTheadMemIdx optimizations, but less cases. ;; Note, that we might get GP registers in FP-mode (reg:DF a2) ;; which cannot be handled by the XTheadFMemIdx instructions. ;; This might even happend after register allocation. ;; We could implement splitters that undo the combiner results ;; if “after_reload && !HARDFP_REG_P (operands[0])”, but this ;; raises even more questions (e.g. split into what?). ;; So let's solve this by simply requiring XTheadMemIdx ;; which provides the necessary instructions to cover this case.
(define_insn_and_split “*th_fmemidx_I_a” [(set (match_operand:TH_M_NOEXTF 0 “register_operand” “=f”) (mem:TH_M_NOEXTF (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:X 3 “register_operand” “r”))))] “TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTF (plus:X (match_dup 3) (ashift:X (match_dup 1) (match_dup 2)))))] { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_fmemidx_I_c” [(set (mem:TH_M_ANYF (plus:X (mult:X (match_operand:X 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:X 3 “register_operand” “r”))) (match_operand:TH_M_ANYF 0 “register_operand” “f”))] “TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)” “#” “&& 1” [(set (mem:TH_M_ANYF (plus:X (match_dup 3) (ashift:X (match_dup 1) (match_dup 2)))) (match_dup 0))] { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_fmemidx_US_a” [(set (match_operand:TH_M_NOEXTF 0 “register_operand” “=f”) (mem:TH_M_NOEXTF (plus:DI (and:DI (mult:DI (match_operand:DI 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:DI 3 “immediate_operand” “i”)) (match_operand:DI 4 “register_operand” “r”))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3) && CONST_INT_P (operands[3]) && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTF (plus:DI (match_dup 4) (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))))] { operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_fmemidx_US_c” [(set (mem:TH_M_ANYF (plus:DI (and:DI (mult:DI (match_operand:DI 1 “register_operand” “r”) (match_operand:QI 2 “immediate_operand” “i”)) (match_operand:DI 3 “immediate_operand” “i”)) (match_operand:DI 4 “register_operand” “r”))) (match_operand:TH_M_ANYF 0 “register_operand” “f”))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX && CONST_INT_P (operands[2]) && pow2p_hwi (INTVAL (operands[2])) && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3) && CONST_INT_P (operands[3]) && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff” “#” “&& 1” [(set (mem:TH_M_ANYF (plus:DI (match_dup 4) (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))) (match_dup 0))] { operands[1] = gen_lowpart (SImode, operands[1]); operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2]))); } )
(define_insn_and_split “*th_fmemidx_UZ_a” [(set (match_operand:TH_M_NOEXTF 0 “register_operand” “=f”) (mem:TH_M_NOEXTF (plus:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (match_operand:DI 2 “register_operand” “r”))))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX && (!HARD_REGISTER_NUM_P (REGNO (operands[0])) || HARDFP_REG_P (REGNO (operands[0])))” “#” “&& 1” [(set (match_dup 0) (mem:TH_M_NOEXTF (plus:DI (match_dup 2) (zero_extend:DI (match_dup 1)))))] )
(define_insn_and_split “*th_fmemidx_UZ_c” [(set (mem:TH_M_ANYF (plus:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (match_operand:DI 2 “register_operand” “r”))) (match_operand:TH_M_ANYF 0 “register_operand” “f”))] “TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX” “#” “&& 1” [(set (mem:TH_M_ANYF (plus:DI (match_dup 2) (zero_extend:DI (match_dup 1)))) (match_dup 0))] )
(include “thead-peephole.md”)