> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h > index cf0cd669be4..5cd3f7673f0 100644 > --- a/gcc/config/riscv/riscv-opts.h > +++ b/gcc/config/riscv/riscv-opts.h > @@ -215,4 +215,7 @@ enum stack_protector_guard { > #define TARGET_XTHEADMEMPAIR ((riscv_xthead_subext & MASK_XTHEADMEMPAIR) != > 0) > #define TARGET_XTHEADSYNC ((riscv_xthead_subext & MASK_XTHEADSYNC) != 0) > > +#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX > +#define HAVE_PRE_MODIFY_DISP TARGET_XTHEADMEMIDX > + > #endif /* ! GCC_RISCV_OPTS_H */ > diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h > index 1b7ba02726d..019a0e08285 100644 > --- a/gcc/config/riscv/riscv-protos.h > +++ b/gcc/config/riscv/riscv-protos.h > @@ -65,6 +65,24 @@ extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, > rtx); > extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx); > extern void riscv_expand_conditional_branch (rtx, enum rtx_code, rtx, rtx); > #endif > + > +extern bool > +riscv_classify_address_index (struct riscv_address_info *info, rtx x, > + machine_mode mode, bool strict_p); > +extern bool > +riscv_classify_address_modify (struct riscv_address_info *info, rtx x, > + machine_mode mode, bool strict_p); > + > +extern const char * > +riscv_output_move_index (rtx x, machine_mode mode, bool ldr); > +extern const char * > +riscv_output_move_modify (rtx x, machine_mode mode, bool ldi); > + > +extern bool > +riscv_legitimize_address_index_p (rtx x, machine_mode mode, bool uindex); > +extern bool > +riscv_legitimize_address_modify_p (rtx x, machine_mode mode, bool post); > + > extern bool riscv_expand_conditional_move (rtx, rtx, rtx, rtx); > extern rtx riscv_legitimize_call_address (rtx); > extern void riscv_set_return_address (rtx, rtx); > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index 33854393bd2..2980dbd69f9 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -83,6 +83,19 @@ along with GCC; see the file COPYING3. If not see > > /* Classifies an address. > > + ADDRESS_REG_REG > + A base register indexed by (optionally scaled) register. > + > + ADDRESS_REG_UREG > + A base register indexed by (optionally scaled) zero-extended register. > + > + ADDRESS_REG_WB > + A base register indexed by immediate offset with writeback. > + > + ADDRESS_REG > + A natural register + offset address. The register satisfies > + riscv_valid_base_register_p and the offset is a const_arith_operand. > + > ADDRESS_REG > A natural register + offset address. The register satisfies > riscv_valid_base_register_p and the offset is a const_arith_operand. > @@ -97,6 +110,9 @@ along with GCC; see the file COPYING3. If not see > ADDRESS_SYMBOLIC: > A constant symbolic address. */ > enum riscv_address_type { > + ADDRESS_REG_REG, > + ADDRESS_REG_UREG, > + ADDRESS_REG_WB, > ADDRESS_REG, > ADDRESS_LO_SUM, > ADDRESS_CONST_INT, > @@ -201,6 +217,7 @@ struct riscv_address_info { > rtx reg; > rtx offset; > enum riscv_symbol_type symbol_type; > + int shift; > }; > > /* One stage in a constant building sequence. These sequences have > @@ -1025,12 +1042,31 @@ riscv_classify_address (struct riscv_address_info > *info, rtx x, > if (riscv_v_ext_vector_mode_p (mode)) > return false; > > + if (riscv_valid_base_register_p (XEXP (x, 0), mode, strict_p) > + && riscv_classify_address_index (info, XEXP (x, 1), mode, strict_p)) > + { > + info->reg = XEXP (x, 0); > + return true; > + } > + else if (riscv_valid_base_register_p (XEXP (x, 1), mode, strict_p) > + && riscv_classify_address_index (info, XEXP (x, 0), > + mode, strict_p)) > + { > + info->reg = XEXP (x, 1); > + return true; > + } > + > info->type = ADDRESS_REG; > info->reg = XEXP (x, 0); > info->offset = XEXP (x, 1); > return (riscv_valid_base_register_p (info->reg, mode, strict_p) > && riscv_valid_offset_p (info->offset, mode)); > > + case POST_MODIFY: > + case PRE_MODIFY: > + > + return riscv_classify_address_modify (info, x, mode, strict_p); > + > case LO_SUM: > /* RVV load/store disallow LO_SUM. */ > if (riscv_v_ext_vector_mode_p (mode)) > @@ -1269,6 +1305,263 @@ riscv_emit_move (rtx dest, rtx src) > : emit_move_insn_1 (dest, src)); > } > > +/* Return true if address offset is a valid index. If it is, fill in INFO > + appropriately. STRICT_P is true if REG_OK_STRICT is in effect. */ > + > +bool > +riscv_classify_address_index (struct riscv_address_info *info, rtx x, > + machine_mode mode, bool strict_p)
indent > +{ > + enum riscv_address_type type = ADDRESS_REG_REG;; > + rtx index; > + int shift = 0; > + > + if (!TARGET_XTHEADMEMIDX) > + return false; > + > + if (!TARGET_64BIT && mode == DImode) > + return false; > + > + if (SCALAR_FLOAT_MODE_P (mode)) > + { > + if (!TARGET_HARD_FLOAT) > + return false; > + if (GET_MODE_SIZE (mode).to_constant () == 2) > + return false; > + } > + > + /* (reg:P) */ > + if ((REG_P (x) || GET_CODE (x) == SUBREG) > + && GET_MODE (x) == Pmode) > + { > + index = x; > + shift = 0; > + } > + /* (zero_extend:DI (reg:SI)) */ > + else if (GET_CODE (x) == ZERO_EXTEND > + && GET_MODE (x) == DImode > + && GET_MODE (XEXP (x, 0)) == SImode) > + { > + type = ADDRESS_REG_UREG; > + index = XEXP (x, 0); > + shift = 0; > + } > + /* (mult:DI (zero_extend:DI (reg:SI)) (const_int scale)) */ > + else if (GET_CODE (x) == MULT > + && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND > + && GET_MODE (XEXP (x, 0)) == DImode > + && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode > + && CONST_INT_P (XEXP (x, 1))) > + { > + type = ADDRESS_REG_UREG; > + index = XEXP (XEXP (x, 0), 0); > + shift = exact_log2 (INTVAL (XEXP (x, 1))); > + } > + /* (ashift:DI (zero_extend:DI (reg:SI)) (const_int shift)) */ > + else if (GET_CODE (x) == ASHIFT > + && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND > + && GET_MODE (XEXP (x, 0)) == DImode > + && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode > + && CONST_INT_P (XEXP (x, 1))) > + { > + type = ADDRESS_REG_UREG; > + index = XEXP (XEXP (x, 0), 0); > + shift = INTVAL (XEXP (x, 1)); > + } > + /* (mult:P (reg:P) (const_int scale)) */ > + else if (GET_CODE (x) == MULT > + && GET_MODE (x) == Pmode > + && GET_MODE (XEXP (x, 0)) == Pmode > + && CONST_INT_P (XEXP (x, 1))) > + { > + index = XEXP (x, 0); > + shift = exact_log2 (INTVAL (XEXP (x, 1))); > + } > + /* (ashift:P (reg:P) (const_int shift)) */ > + else if (GET_CODE (x) == ASHIFT > + && GET_MODE (x) == Pmode > + && GET_MODE (XEXP (x, 0)) == Pmode > + && CONST_INT_P (XEXP (x, 1))) > + { > + index = XEXP (x, 0); > + shift = INTVAL (XEXP (x, 1)); > + } > + else > + return false; > + > + if (shift != 0 && !IN_RANGE (shift, 1, 3)) > + return false; > + > + if (!strict_p > + && GET_CODE (index) == SUBREG > + && contains_reg_of_mode[GENERAL_REGS][GET_MODE (SUBREG_REG (index))]) > + index = SUBREG_REG (index); > + > + if (riscv_valid_base_register_p (index, mode, strict_p)) > + { > + info->type = type; > + info->offset = index; > + info->shift = shift; > + return true; > + } > + return false; > +} > + > +/* Return true if address is a valid modify. If it is, fill in INFO > + appropriately. STRICT_P is true if REG_OK_STRICT is in effect. */ > + > +bool > +riscv_classify_address_modify (struct riscv_address_info *info, rtx x, > + machine_mode mode, bool strict_p) indent > +{ > + > +#define AM_IMM(BIT) (1LL << (5 + (BIT))) > +#define AM_OFFSET(VALUE, SHIFT) (\ > + ((unsigned HOST_WIDE_INT) (VALUE) + AM_IMM (SHIFT)/2 < AM_IMM (SHIFT)) \ > + && !((unsigned HOST_WIDE_INT) (VALUE) & ((1 << (SHIFT)) - 1)) \ > + ? (SHIFT) + 1 \ > + : 0) Plz extract AM_IMM and AM_OFFSET to function instead of marco. > + > + if (!TARGET_XTHEADMEMIDX) > + return false; > + > + if (!(INTEGRAL_MODE_P (mode) && GET_MODE_SIZE (mode).to_constant () <= 8)) > + return false; > + > + if (!TARGET_64BIT && mode == DImode) > + return false; > + > + if (GET_CODE (x) != POST_MODIFY > + && GET_CODE (x) != PRE_MODIFY) > + return false; > + > + info->type = ADDRESS_REG_WB; > + info->reg = XEXP (x, 0); > + > + if (GET_CODE (XEXP (x, 1)) == PLUS > + && CONST_INT_P (XEXP (XEXP (x, 1), 1)) > + && rtx_equal_p (XEXP (XEXP (x, 1), 0), info->reg) > + && riscv_valid_base_register_p (info->reg, mode, strict_p)) > + { > + info->offset = XEXP (XEXP (x, 1), 1); > + int shift = AM_OFFSET (INTVAL (info->offset), 0); > + if (!shift) > + shift = AM_OFFSET (INTVAL (info->offset), 1); > + if (!shift) > + shift = AM_OFFSET (INTVAL (info->offset), 2); > + if (!shift) > + shift = AM_OFFSET (INTVAL (info->offset), 3); > + if (shift) > + { > + info->shift = shift - 1; > + return true; > + } > + } > + return false; > +} > + > +/* Return TRUE if X is a legitimate address modify. */ > + > +bool > +riscv_legitimize_address_modify_p (rtx x, machine_mode mode, bool post) > +{ > + struct riscv_address_info addr; > + return riscv_classify_address_modify (&addr, x, mode, false) > + && (!post || GET_CODE (x) == POST_MODIFY); > +} > + > +/* Return the LDIB/LDIA and STIB/STIA instructions. Assume > + that X is MEM operand. */ > + > +const char * > +riscv_output_move_modify (rtx x, machine_mode mode, bool ldi) Rename this function with prefix thead_ and create thead.cc and move to that file. > +{ > + static char buf[128] = {0}; > + > + int index = exact_log2 (GET_MODE_SIZE (mode).to_constant ()); > + if (!IN_RANGE (index, 0, 3)) > + return NULL; > + > + if (!riscv_legitimize_address_modify_p (x, mode, false)) > + return NULL; > + > + bool post = riscv_legitimize_address_modify_p (x, mode, true); > + > + const char *const insn[][4] = { > + { > + "th.sbi%s\t%%z1,%%0", > + "th.shi%s\t%%z1,%%0", > + "th.swi%s\t%%z1,%%0", > + "th.sdi%s\t%%z1,%%0" > + }, > + { > + "th.lbui%s\t%%0,%%1", > + "th.lhui%s\t%%0,%%1", > + "th.lwi%s\t%%0,%%1", > + "th.ldi%s\t%%0,%%1" > + } > + }; > + > + snprintf (buf, sizeof (buf), insn[ldi][index], post ? "a" : "b"); > + return buf; > +} > + > +bool > +riscv_legitimize_address_index_p (rtx x, machine_mode mode, bool uindex) > +{ > + struct riscv_address_info addr; > + rtx op0, op1; > + > + if (GET_CODE (x) != PLUS) > + return false; > + > + op0 = XEXP (x, 0); > + op1 = XEXP (x, 1); > + > + return ((riscv_valid_base_register_p (op0, mode, false) > + && riscv_classify_address_index (&addr, op1, mode, false)) > + || (riscv_valid_base_register_p (op1, mode, false) > + && riscv_classify_address_index (&addr, op0, mode, false))) > + && (!uindex || addr.type == ADDRESS_REG_UREG); > +} > + > +/* Return the LDR or STR instructions. Assume > + that X is MEM operand. */ > + > +const char * > +riscv_output_move_index (rtx x, machine_mode mode, bool ldr) Rename this function with prefix thead_ and create thead.cc and move to that file. > +{ > + static char buf[128] = {0}; > + > + int index = exact_log2 (GET_MODE_SIZE (mode).to_constant ()); > + if (!IN_RANGE (index, 0, 3)) > + return NULL; > + > + if (!riscv_legitimize_address_index_p (x, mode, false)) > + return NULL; > + > + bool uindex = riscv_legitimize_address_index_p (x, mode, true); > + > + const char *const insn[][4] = { > + { > + "th.s%srb\t%%z1,%%0", > + "th.s%srh\t%%z1,%%0", > + "th.s%srw\t%%z1,%%0", > + "th.s%srd\t%%z1,%%0" > + }, > + { > + "th.l%srbu\t%%0,%%1", > + "th.l%srhu\t%%0,%%1", > + "th.l%srw\t%%0,%%1", > + "th.l%srd\t%%0,%%1" > + } > + }; > + > + snprintf (buf, sizeof (buf), insn[ldr][index], uindex ? "u" : ""); > + > + return buf; > +} > + > /* Emit an instruction of the form (set TARGET SRC). */ > > static rtx > @@ -1631,6 +1924,42 @@ riscv_legitimize_address (rtx x, rtx oldx > ATTRIBUTE_UNUSED, > if (riscv_split_symbol (NULL, x, mode, &addr, FALSE)) > return riscv_force_address (addr, mode); > > + /* Optimize BASE + OFFSET into BASE + INDEX. */ > + if (TARGET_XTHEADMEMIDX > + && GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) > + && INTVAL (XEXP (x, 1)) != 0 > + && GET_CODE (XEXP (x, 0)) == PLUS) > + { > + rtx base = XEXP (x, 0); > + rtx offset_rtx = XEXP (x, 1); > + > + rtx op0 = XEXP (base, 0); > + rtx op1 = XEXP (base, 1); > + /* Force any scaling into a temp for CSE. */ > + op0 = force_reg (Pmode, op0); > + op1 = force_reg (Pmode, op1); > + > + /* Let the pointer register be in op0. */ > + if (REG_POINTER (op1)) > + std::swap (op0, op1); > + > + unsigned regno = REGNO (op0); > + > + /* If the pointer is virtual or frame related, then we know that > + virtual register instantiation or register elimination is going > + to apply a second constant. We want the two constants folded > + together easily. Therefore, emit as (OP0 + CONST) + OP1. */ > + if ((regno >= FIRST_VIRTUAL_REGISTER > + && regno <= LAST_VIRTUAL_POINTER_REGISTER) > + || regno == FRAME_POINTER_REGNUM > + || regno == ARG_POINTER_REGNUM) > + { > + base = expand_binop (Pmode, add_optab, op0, offset_rtx, > + NULL_RTX, true, OPTAB_DIRECT); > + return gen_rtx_PLUS (Pmode, base, op1); > + } > + } > + > /* Handle BASE + OFFSET. */ > if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) > && INTVAL (XEXP (x, 1)) != 0) > @@ -2408,6 +2737,13 @@ riscv_rtx_costs (rtx x, machine_mode mode, int > outer_code, int opno ATTRIBUTE_UN > *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); > return true; > } > + /* bit extraction pattern (xtheadmemidx, xtheadfmemidx). */ > + if (outer_code == SET > + && TARGET_XTHEADMEMIDX) > + { > + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); > + return true; > + } > gcc_fallthrough (); > case SIGN_EXTRACT: > if (TARGET_XTHEADBB && outer_code == SET > @@ -2826,13 +3162,23 @@ riscv_output_move (rtx dest, rtx src) > } > > if (src_code == MEM) > - switch (width) > - { > - case 1: return "lbu\t%0,%1"; > - case 2: return "lhu\t%0,%1"; > - case 4: return "lw\t%0,%1"; > - case 8: return "ld\t%0,%1"; > - } > + { > + const char *insn = NULL; > + insn = riscv_output_move_index (XEXP (src, 0), GET_MODE (src), > true); > + if (!insn) > + insn = riscv_output_move_modify (XEXP (src, 0), > + GET_MODE (src), true); > + if (insn) > + return insn; Could you introduce thead_riscv_output_move (at thead.cc) and then invoke that at begin of this function? e.g. const char * riscv_output_move (rtx dest, rtx src) { if (insn = thead_riscv_output_move (dest, src)) return insn; > + > + switch (width) > + { > + case 1: return "lbu\t%0,%1"; > + case 2: return "lhu\t%0,%1"; > + case 4: return "lw\t%0,%1"; > + case 8: return "ld\t%0,%1"; > + } > + } > > if (src_code == CONST_INT) > { > @@ -2887,13 +3233,24 @@ riscv_output_move (rtx dest, rtx src) > } > } > if (dest_code == MEM) > - switch (width) > - { > - case 1: return "sb\t%z1,%0"; > - case 2: return "sh\t%z1,%0"; > - case 4: return "sw\t%z1,%0"; > - case 8: return "sd\t%z1,%0"; > - } > + { > + const char *insn = NULL; > + insn = riscv_output_move_index (XEXP (dest, 0), > + GET_MODE (dest), false); > + if (!insn) > + insn = riscv_output_move_modify (XEXP (dest, 0), > + GET_MODE (dest), false); > + if (insn) > + return insn; and those logic also extract to thead_riscv_output_move. > + > + switch (width) > + { > + case 1: return "sb\t%z1,%0"; > + case 2: return "sh\t%z1,%0"; > + case 4: return "sw\t%z1,%0"; > + case 8: return "sd\t%z1,%0"; > + } > + } > } > if (src_code == REG && FP_REG_P (REGNO (src))) > { > @@ -2911,28 +3268,32 @@ riscv_output_move (rtx dest, rtx src) > } > > if (dest_code == MEM) > - switch (width) > - { > - case 2: > - return "fsh\t%1,%0"; > - case 4: > - return "fsw\t%1,%0"; > - case 8: > - return "fsd\t%1,%0"; > - } > + { > + switch (width) > + { > + case 2: > + return "fsh\t%1,%0"; > + case 4: > + return "fsw\t%1,%0"; > + case 8: > + return "fsd\t%1,%0"; > + } > + } Separated NFC patch plz. > } > if (dest_code == REG && FP_REG_P (REGNO (dest))) > { > if (src_code == MEM) > - switch (width) > - { > - case 2: > - return "flh\t%0,%1"; > - case 4: > - return "flw\t%0,%1"; > - case 8: > - return "fld\t%0,%1"; > - } > + { > + switch (width) > + { > + case 2: > + return "flh\t%0,%1"; > + case 4: > + return "flw\t%0,%1"; > + case 8: > + return "fld\t%0,%1"; > + } > + } Separated NFC patch plz. > } > if (dest_code == REG && GP_REG_P (REGNO (dest)) && src_code == > CONST_POLY_INT) > { > @@ -4881,6 +5242,19 @@ riscv_print_operand_address (FILE *file, machine_mode > mode ATTRIBUTE_UNUSED, rtx > case ADDRESS_SYMBOLIC: > output_addr_const (file, riscv_strip_unspec_address (x)); > return; > + > + case ADDRESS_REG_REG: > + case ADDRESS_REG_UREG: > + fprintf (file, "%s,%s,%u", reg_names[REGNO (addr.reg)], > + reg_names[REGNO (addr.offset)], > + addr.shift); > + return; > + > + case ADDRESS_REG_WB: > + fprintf (file, "(%s),%ld,%u", reg_names[REGNO (addr.reg)], > + (long) INTVAL (addr.offset) >> > addr.shift, > + addr.shift); > + return; > } > gcc_unreachable (); > } > diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h > index 5bc7f2f467d..199bb30162e 100644 > --- a/gcc/config/riscv/riscv.h > +++ b/gcc/config/riscv/riscv.h > @@ -535,7 +535,8 @@ enum reg_class > factor or added to another register (as well as added to a > displacement). */ > > -#define INDEX_REG_CLASS NO_REGS > +#define INDEX_REG_CLASS ((TARGET_XTHEADMEMIDX) ? \ > + GR_REGS : NO_REGS) Introduce riscv_index_reg_class function > > /* We generally want to put call-clobbered registers ahead of > call-saved ones. (IRA expects this.) */ > @@ -705,7 +706,10 @@ typedef struct { > > /* Addressing modes, and classification of registers for them. */ > > -#define REGNO_OK_FOR_INDEX_P(REGNO) 0 > +#define REGNO_OK_FOR_INDEX_P(REGNO) \ > + ((TARGET_XTHEADMEMIDX) ? \ > + riscv_regno_mode_ok_for_base_p (REGNO, VOIDmode, 1) : 0) Introduce riscv_regno_mode_ok_for_index_p function > + > #define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ > riscv_regno_mode_ok_for_base_p (REGNO, MODE, 1) > > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md > index 61f175bb62b..df31a1fffff 100644 > --- a/gcc/config/riscv/riscv.md > +++ b/gcc/config/riscv/riscv.md > @@ -1360,12 +1360,17 @@ (define_expand "zero_extendsidi2" > "TARGET_64BIT") > > (define_insn_and_split "*zero_extendsidi2_internal" > - [(set (match_operand:DI 0 "register_operand" "=r,r") > + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") > (zero_extend:DI > - (match_operand:SI 1 "nonimmediate_operand" " r,m")))] > - "TARGET_64BIT && !TARGET_ZBA" > + (match_operand:SI 1 > + "nonimmediate_operand" " r,Qmu,Qmr,Qma,Qmb,m")))] > + "TARGET_64BIT && !(TARGET_ZBA || TARGET_ZBB)" > "@ > # > + th.lurwu\t%0,%1 > + th.lrwu\t%0,%1 > + th.lwuia\t%0,%1 > + th.lwuib\t%0,%1 > lwu\t%0,%1" > "&& reload_completed > && REG_P (operands[1]) > @@ -1375,7 +1380,7 @@ (define_insn_and_split "*zero_extendsidi2_internal" > (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") > + [(set_attr "move_type" "shift_shift,load,load,load,load,load") > (set_attr "mode" "DI")]) Could you use ext attr to control that? e.g. (set_attr "ext" "base,XTheadMemIdx,XTheadMemIdx,XTheadMemIdx,XTheadMemIdx,base") > > (define_expand "zero_extendhi<GPR:mode>2" > @@ -1384,13 +1389,18 @@ (define_expand "zero_extendhi<GPR:mode>2" > (match_operand:HI 1 "nonimmediate_operand")))] > "") > > -(define_insn_and_split "*zero_extendhi<GPR:mode>2" > - [(set (match_operand:GPR 0 "register_operand" "=r,r") > +(define_insn_and_split "*zero_extendhi<GPR:mode>2_internal" > + [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r,r,r") > (zero_extend:GPR > - (match_operand:HI 1 "nonimmediate_operand" " r,m")))] > - "!TARGET_ZBB" > + (match_operand:HI 1 > + "nonimmediate_operand" " r,Qmu,Qmr,Qma,Qmb,m")))] > + "!(TARGET_ZBA || TARGET_ZBB)" > "@ > # > + th.lurhu\t%0,%1 > + th.lrhu\t%0,%1 > + th.lhuia\t%0,%1 > + th.lhuib\t%0,%1 > lhu\t%0,%1" > "&& reload_completed > && REG_P (operands[1]) > @@ -1401,20 +1411,25 @@ (define_insn_and_split "*zero_extendhi<GPR:mode>2" > (lshiftrt:GPR (match_dup 0) (match_dup 2)))] > { > operands[1] = gen_lowpart (<GPR:MODE>mode, operands[1]); > - operands[2] = GEN_INT(GET_MODE_BITSIZE(<GPR:MODE>mode) - 16); > + operands[2] = GEN_INT (GET_MODE_BITSIZE (<GPR:MODE>mode) - 16); > } > - [(set_attr "move_type" "shift_shift,load") > + [(set_attr "move_type" "shift_shift,load,load,load,load,load") > (set_attr "mode" "<GPR:MODE>")]) Use ext attribute here too. > > (define_insn "zero_extendqi<SUPERQI:mode>2" > - [(set (match_operand:SUPERQI 0 "register_operand" "=r,r") > + [(set (match_operand:SUPERQI 0 "register_operand" "=r,r,r,r,r,r") > (zero_extend:SUPERQI > - (match_operand:QI 1 "nonimmediate_operand" " r,m")))] > + (match_operand:QI 1 > + "nonimmediate_operand" " r,Qmu,Qmr,Qma,Qmb,m")))] > "" > "@ > andi\t%0,%1,0xff > + th.lurbu\t%0,%1 > + th.lrbu\t%0,%1 > + th.lbuia\t%0,%1 > + th.lbuib\t%0,%1 > lbu\t%0,%1" > - [(set_attr "move_type" "andi,load") > + [(set_attr "move_type" "andi,load,load,load,load,load") > (set_attr "mode" "<SUPERQI:MODE>")]) Ditto. > ;; > @@ -1425,14 +1440,19 @@ (define_insn "zero_extendqi<SUPERQI:mode>2" > ;; .................... > > (define_insn "extendsidi2" > - [(set (match_operand:DI 0 "register_operand" "=r,r") > + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") > (sign_extend:DI > - (match_operand:SI 1 "nonimmediate_operand" " r,m")))] > + (match_operand:SI 1 > + "nonimmediate_operand" " r,Qmu,Qmr,Qma,Qmb,m")))] > "TARGET_64BIT" > "@ > sext.w\t%0,%1 > + th.lurw\t%0,%1 > + th.lrw\t%0,%1 > + th.lwia\t%0,%1 > + th.lwib\t%0,%1 > lw\t%0,%1" > - [(set_attr "move_type" "move,load") > + [(set_attr "move_type" "move,load,load,load,load,load") > (set_attr "mode" "DI")]) Ditto. > (define_expand "extend<SHORT:mode><SUPERQI:mode>2" > @@ -1441,12 +1461,17 @@ (define_expand "extend<SHORT:mode><SUPERQI:mode>2" > "") > > (define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2" > - [(set (match_operand:SUPERQI 0 "register_operand" "=r,r") > + [(set (match_operand:SUPERQI 0 "register_operand" "=r,r,r,r,r,r") > (sign_extend:SUPERQI > - (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))] > + (match_operand:SHORT 1 > + "nonimmediate_operand" " r,Qmu,Qmr,Qma,Qmb,m")))] > "!TARGET_ZBB" > "@ > # > + th.lur<SHORT:size>\t%0,%1 > + th.lr<SHORT:size>\t%0,%1 > + th.l<SHORT:size>ia\t%0,%1 > + th.l<SHORT:size>ib\t%0,%1 > l<SHORT:size>\t%0,%1" > "&& reload_completed > && REG_P (operands[1]) > @@ -1459,7 +1484,7 @@ (define_insn_and_split > "*extend<SHORT:mode><SUPERQI:mode>2" > operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode) > - GET_MODE_BITSIZE (<SHORT:MODE>mode)); > } > - [(set_attr "move_type" "shift_shift,load") > + [(set_attr "move_type" "shift_shift,load,load,load,load,load") > (set_attr "mode" "SI")]) Ditto. > > (define_insn "extendhfsf2" > @@ -1507,7 +1532,8 @@ (define_insn "*movhf_hardfloat" > && (register_operand (operands[0], HFmode) > || reg_or_0_operand (operands[1], HFmode))" > { return riscv_output_move (operands[0], operands[1]); } > - [(set_attr "move_type" > "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > + [(set_attr "move_type" > + "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > (set_attr "mode" "HF")]) It seems just NFC, don't do that within this patch, plz split that into a separated NFC patch. > (define_insn "*movhf_softfloat" > @@ -1836,7 +1862,8 @@ (define_insn "*movsf_hardfloat" > && (register_operand (operands[0], SFmode) > || reg_or_0_operand (operands[1], SFmode))" > { return riscv_output_move (operands[0], operands[1]); } > - [(set_attr "move_type" > "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > + [(set_attr "move_type" > + "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > (set_attr "mode" "SF")]) > > (define_insn "*movsf_softfloat" Same here. > @@ -1860,7 +1887,6 @@ (define_expand "movdf" > DONE; > }) > > - Same here. > ;; In RV32, we lack fmv.x.d and fmv.d.x. Go through memory instead. > ;; (However, we can still use fcvt.d.w to zero a floating-point register.) > (define_insn "*movdf_hardfloat_rv32" > @@ -1870,7 +1896,8 @@ (define_insn "*movdf_hardfloat_rv32" > && (register_operand (operands[0], DFmode) > || reg_or_0_operand (operands[1], DFmode))" > { return riscv_output_move (operands[0], operands[1]); } > - [(set_attr "move_type" > "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > + [(set_attr "move_type" > + "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") Same here. > (set_attr "mode" "DF")]) > > (define_insn "*movdf_hardfloat_rv64" > @@ -1880,7 +1907,8 @@ (define_insn "*movdf_hardfloat_rv64" > && (register_operand (operands[0], DFmode) > || reg_or_0_operand (operands[1], DFmode))" > { return riscv_output_move (operands[0], operands[1]); } > - [(set_attr "move_type" > "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") > + [(set_attr "move_type" > + "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") Same here. > (set_attr "mode" "DF")]) > > (define_insn "*movdf_softfloat" > @@ -2187,7 +2215,7 @@ (define_split > (and:GPR (match_operand:GPR 1 "register_operand") > (match_operand:GPR 2 "p2m1_shift_operand"))) > (clobber (match_operand:GPR 3 "register_operand"))] > - "" > + "!TARGET_XTHEADMEMIDX" > [(set (match_dup 3) > (ashift:GPR (match_dup 1) (match_dup 2))) > (set (match_dup 0)