@@ -355,6 +355,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"xcvmac", ISA_SPEC_CLASS_NONE, 1, 0},
{"xcvalu", ISA_SPEC_CLASS_NONE, 1, 0},
{"xcvelw", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"xcvmem", ISA_SPEC_CLASS_NONE, 1, 0},
{"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
{"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1730,6 +1731,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
{"xcvmac", &gcc_options::x_riscv_xcv_subext, MASK_XCVMAC},
{"xcvalu", &gcc_options::x_riscv_xcv_subext, MASK_XCVALU},
{"xcvelw", &gcc_options::x_riscv_xcv_subext, MASK_XCVELW},
+ {"xcvmem", &gcc_options::x_riscv_xcv_subext, MASK_XCVMEM},
{"xtheadba", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
{"xtheadbb", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
@@ -262,3 +262,32 @@
(and (match_code "const_int")
(and (match_test "IN_RANGE (ival, 0, 1073741823)")
(match_test "exact_log2 (ival + 1) != -1"))))
+
+(define_memory_constraint "CV_mem_plus"
+ "@internal
+ An address for reg+reg stores and loads"
+ (and (match_code "mem")
+ (match_test "GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG")))
+
+(define_memory_constraint "CV_mem_post"
+ "@internal
+ An address for post-modify or reg+reg stores and loads"
+ (and (match_code "mem")
+ (match_test "(GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+ || GET_CODE (XEXP (op, 0)) == POST_MODIFY")))
+
+(define_memory_constraint "CV_mem_nopm"
+ "@internal
+ An address that is not base reg + index reg or post modify."
+ (and (match_code "mem")
+ (and (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+ MEM_ADDR_SPACE (op))")
+ (not (match_test "((GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+ || GET_CODE (XEXP (op, 0)) == POST_MODIFY)
+ && TARGET_XCVMEM")))))
@@ -706,3 +706,273 @@
[(set_attr "type" "load")
(set_attr "mode" "SI")])
+
+;; CORE-V Post Increment Load/ Store Instructions
+;; Post Increment Register-Immediate and Register-Register Load/Store
+
+(define_insn "*cv_load<mode>_postinc"
+ [(set (match_operand:ANYI 0 "register_operand" "=r")
+ (match_operand:ANYI 1 "mem_post_inc" "CV_mem_post"))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+ "cv.<load>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load_<optab><SHORT:mode>_postinc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_extend:SI (match_operand:SHORT 1 "mem_post_inc" "CV_mem_post")))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+ "cv.<load><u>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>_postinc"
+ [(set (match_operand:ANYF 0 "register_operand" "=r")
+ (match_operand:ANYF 1 "mem_post_inc" "CV_mem_post"))]
+ "TARGET_XCVMEM
+ && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+ && (register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode))"
+ "cv.<load>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>_postinc"
+ [(set (match_operand:ANYI 0 "mem_post_inc" "=CV_mem_post")
+ (match_operand:ANYI 1 "register_operand" "r"))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+ "cv.<store>\t%1,%0"
+ [(set_attr "type" "store")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>_postinc"
+ [(set (match_operand:ANYF 0 "mem_post_inc" "=CV_mem_post")
+ (match_operand:ANYF 1 "register_operand" "r"))]
+ "TARGET_XCVMEM
+ && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+ && (register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode))"
+ "cv.<store>\t%1,%0"
+ [(set_attr "type" "store")
+ (set_attr "mode" "<MODE>")])
+
+;; Normal Register-Register Load/Store
+(define_insn "*cv_load<mode>"
+ [(set (match_operand:ANYI 0 "register_operand" "=r")
+ (match_operand:ANYI 1 "mem_plus_reg" "CV_mem_plus"))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+ "cv.<load>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<optab><SHORT:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_extend:SI (match_operand:SHORT 1 "mem_plus_reg" "CV_mem_plus")))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+ "cv.<load><u>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>"
+ [(set (match_operand:ANYF 0 "register_operand" "=r")
+ (match_operand:ANYF 1 "mem_plus_reg" "CV_mem_plus"))]
+ "TARGET_XCVMEM
+ && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+ && (register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode))"
+ "cv.<load>\t%0,%1"
+ [(set_attr "type" "load")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>"
+ [(set (match_operand:ANYI 0 "mem_plus_reg" "=CV_mem_plus")
+ (match_operand:ANYI 1 "register_operand" "r"))]
+ "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+ "cv.<store>\t%1,%0"
+ [(set_attr "type" "store")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>"
+ [(set (match_operand:ANYF 0 "mem_plus_reg" "=CV_mem_plus")
+ (match_operand:ANYF 1 "register_operand" " r"))]
+ "TARGET_XCVMEM
+ && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+ && (register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode))"
+ "cv.<store>\t%1,%0"
+ [(set_attr "move_type" "store")
+ (set_attr "mode" "<MODE>")])
+
+;;
+;; Generic RISC-V moves for XCVMEM
+;;
+
+(define_insn "*movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm, *f,*f,*r,*CV_mem_nopm,r")
+ (match_operand:SI 1 "move_operand" " r,T,CV_mem_nopm,rJ,*r*J,*CV_mem_nopm,*f,*f,vp"))]
+ "TARGET_XCVMEM && (register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))
+ && !(register_operand (operands[1], SImode)
+ && reg_or_subregno (operands[1]) == VL_REGNUM)"
+ { return riscv_output_move (operands[0], operands[1]); }
+ [(set_attr "move_type" "move,const,load,store,mtc,fpload,mfc,fpstore,rdvlenb")
+ (set_attr "mode" "SI")
+ (set_attr "type" "move")
+ (set_attr "ext" "base,base,base,base,f,f,f,f,vector")])
+
+(define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm, *f,*r,r")
+ (match_operand:HI 1 "move_operand" " r,T,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+ "TARGET_XCVMEM && (register_operand (operands[0], HImode)
+ || reg_or_0_operand (operands[1], HImode))"
+ { return riscv_output_move (operands[0], operands[1]); }
+ [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+ (set_attr "mode" "HI")
+ (set_attr "type" "move")
+ (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm, *f,*r,r")
+ (match_operand:QI 1 "move_operand" " r,I,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+ "TARGET_XCVMEM && (register_operand (operands[0], QImode)
+ || reg_or_0_operand (operands[1], QImode))"
+ { return riscv_output_move (operands[0], operands[1]); }
+ [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+ (set_attr "mode" "QI")
+ (set_attr "type" "move")
+ (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movhf_hardfloat"
+ [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f, f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r, *r,*r,*CV_mem_nopm")
+ (match_operand:HF 1 "move_operand" " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+ "TARGET_ZFHMIN && TARGET_XCVMEM
+ && (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,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "HF")])
+
+(define_insn "*movhf_softfloat"
+ [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f, r,r,CV_mem_nopm,*f,*r")
+ (match_operand:HF 1 "move_operand" " f,Gr,CV_mem_nopm,r,*r,*f"))]
+ "!TARGET_ZFHMIN && TARGET_XCVMEM
+ && (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,move,load,store,mtc,mfc")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "HF")])
+
+(define_insn_and_split "*zero_extendhi<GPR:mode>2"
+ [(set (match_operand:GPR 0 "register_operand" "=r,r")
+ (zero_extend:GPR
+ (match_operand:HI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+ "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+ "@
+ #
+ 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:MODE>mode, operands[1]);
+ operands[2] = GEN_INT(GET_MODE_BITSIZE(<GPR:MODE>mode) - 16);
+ }
+ [(set_attr "move_type" "shift_shift,load")
+ (set_attr "type" "load")
+ (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*zero_extendqi<SUPERQI:mode>2_internal"
+ [(set (match_operand:SUPERQI 0 "register_operand" "=r,r")
+ (zero_extend:SUPERQI
+ (match_operand:QI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+ "!TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+ "@
+ andi\t%0,%1,0xff
+ lbu\t%0,%1"
+ [(set_attr "move_type" "andi,load")
+ (set_attr "type" "multi")
+ (set_attr "mode" "<SUPERQI:MODE>")])
+
+(define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
+ [(set (match_operand:SUPERQI 0 "register_operand" "=r,r")
+ (sign_extend:SUPERQI
+ (match_operand:SHORT 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+ "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+ "@
+ #
+ l<SHORT: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:MODE>mode));
+}
+ [(set_attr "move_type" "shift_shift,load")
+ (set_attr "type" "load")
+ (set_attr "mode" "SI")])
+
+(define_insn "*movdf_hardfloat_rv32"
+ [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f, f,f,f,CV_mem_nopm,CV_mem_nopm,*zmvf,*zmvr, *r,*r,*CV_mem_nopm")
+ (match_operand:DF 1 "move_operand" " f,zfli,G,CV_mem_nopm,f,G,*zmvr,*zmvf,*r*G,*CV_mem_nopm,*r"))]
+ "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+ && (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,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "DF")])
+
+(define_insn "*movdf_hardfloat_rv64"
+ [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f, f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r, *r,*r,*CV_mem_nopm")
+ (match_operand:DF 1 "move_operand" " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*r*G,*CV_mem_nopm,*r"))]
+ "TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+ && (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,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "DF")])
+
+(define_insn "*movdf_softfloat"
+ [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+ (match_operand:DF 1 "move_operand" " rG,CV_mem_nopm,rG"))]
+ "!TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+ && (register_operand (operands[0], DFmode)
+ || reg_or_0_operand (operands[1], DFmode))"
+ { return riscv_output_move (operands[0], operands[1]); }
+ [(set_attr "move_type" "move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "DF")])
+
+(define_insn "*movsf_hardfloat"
+ [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "=f, f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r, *r,*r,*CV_mem_nopm")
+ (match_operand:SF 1 "move_operand" " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+ "TARGET_HARD_FLOAT && TARGET_XCVMEM
+ && (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,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "SF")])
+
+(define_insn "*movsf_softfloat"
+ [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+ (match_operand:SF 1 "move_operand" " Gr,CV_mem_nopm,r"))]
+ "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+ && (register_operand (operands[0], SFmode)
+ || reg_or_0_operand (operands[1], SFmode))"
+ { return riscv_output_move (operands[0], operands[1]); }
+ [(set_attr "move_type" "move,load,store")
+ (set_attr "type" "fmove")
+ (set_attr "mode" "SF")])
@@ -252,8 +252,22 @@
return false;
})
+(define_predicate "mem_post_inc"
+ (and (match_code "mem")
+ (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == POST_MODIFY
+ && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4")))
+
+(define_predicate "mem_plus_reg"
+ (and (match_code "mem")
+ (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4
+ && REG_P (XEXP (XEXP (op, 0), 1))
+ && REG_P (XEXP (XEXP (op, 0), 0))")))
+
(define_predicate "move_operand"
- (match_operand 0 "general_operand")
+ (and (match_operand 0 "general_operand")
+ (and (not (match_operand 0 "mem_post_inc"))
+ (not (match_operand 0 "mem_plus_reg"))))
{
enum riscv_symbol_type symbol_type;
@@ -425,6 +439,10 @@
(ior (match_operand 0 "register_operand")
(match_code "const_int")))
+(define_predicate "nonimmediate_nonpostinc"
+ (and (match_operand 0 "nonimmediate_operand")
+ (not (match_operand 0 "mem_post_inc"))))
+
;; Predicates for the V extension.
(define_special_predicate "vector_length_operand"
(ior (match_operand 0 "pmode_register_operand")
@@ -69,7 +69,8 @@ enum riscv_address_type {
ADDRESS_REG_WB,
ADDRESS_LO_SUM,
ADDRESS_CONST_INT,
- ADDRESS_SYMBOLIC
+ ADDRESS_SYMBOLIC,
+ ADDRESS_REG_INC
};
/* Information about an address described by riscv_address_type.
@@ -92,7 +93,13 @@ enum riscv_address_type {
is the type of symbol it references.
ADDRESS_SYMBOLIC
- SYMBOL_TYPE is the type of symbol that the address references. */
+ SYMBOL_TYPE is the type of symbol that the address references.
+
+ ADDRESS_REG_INC:
+ A base register + offset address access with post modify side-effect
+ (base register += offset). The offset is an immediate or index
+ register.
+ */
struct riscv_address_info {
enum riscv_address_type type;
rtx reg;
@@ -102,6 +109,7 @@ struct riscv_address_info {
};
/* Routines implemented in riscv.cc. */
+bool riscv_legitimate_xcvmem_address_p (machine_mode, rtx, bool);
extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
extern int riscv_float_const_rtx_index_for_fli (rtx);
@@ -1176,7 +1176,7 @@ riscv_regno_mode_ok_for_base_p (int regno,
enum reg_class
riscv_index_reg_class ()
{
- if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
+ if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX || TARGET_XCVMEM)
return GR_REGS;
return NO_REGS;
@@ -1452,6 +1452,16 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
info->offset = const0_rtx;
return riscv_valid_base_register_p (info->reg, mode, strict_p);
+ case POST_MODIFY:
+ /* For instructions using post inc, the offset can either be register
+ * or 12-bit immediate. */
+ info->type = ADDRESS_REG_INC;
+ info->reg = XEXP (x, 0);
+ info->offset = XEXP ((XEXP (x, 1)), 1);
+ return (riscv_valid_base_register_p (info->reg, mode, strict_p)
+ && (riscv_valid_base_register_p (info->offset, mode, strict_p)
+ || riscv_valid_offset_p (info->offset, mode)));
+
case PLUS:
/* RVV load/store disallow any offset. */
if (riscv_v_ext_mode_p (mode))
@@ -1461,7 +1471,8 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
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));
+ && (riscv_valid_offset_p (info->offset, mode)
+ || (TARGET_XCVMEM && riscv_valid_base_register_p (info->offset, mode, strict_p))));
case LO_SUM:
/* RVV load/store disallow LO_SUM. */
@@ -2615,6 +2626,30 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
REG_NOTES (insn) = dwarf;
}
+/* Check if post inc instructions are valid. If not, make the address
+ * vaild. */
+bool
+riscv_legitimate_xcvmem_address_p (machine_mode mode, rtx x, bool strict_p)
+{
+ struct riscv_address_info addr;
+
+ switch (GET_CODE (x))
+ {
+ case POST_MODIFY:
+ if (riscv_classify_address (&addr, x, mode, strict_p))
+ return addr.type == ADDRESS_REG_INC;
+ return false;
+
+ case PLUS:
+ if (REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)) && riscv_classify_address (&addr, x, mode, strict_p))
+ return addr.type == ADDRESS_REG;
+ return false;
+
+ default:
+ return false;
+ }
+}
+
/* If (set DEST SRC) is not a valid move instruction, emit an equivalent
sequence that is valid. */
@@ -5966,7 +6001,8 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
switch (addr.type)
{
case ADDRESS_REG:
- output_addr_const (file, riscv_strip_unspec_address (addr.offset));
+ if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+ else output_addr_const (file, riscv_strip_unspec_address (addr.offset));
fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
return;
@@ -5984,6 +6020,12 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
output_addr_const (file, riscv_strip_unspec_address (x));
return;
+ case ADDRESS_REG_INC:
+ fprintf (file, "(%s),", reg_names[REGNO (addr.reg)]);
+ if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+ else output_addr_const (file, addr.offset);
+ return;
+
default:
gcc_unreachable ();
}
@@ -1212,7 +1212,9 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
e.g. RVVMF64BI vs RVVMF1BI on zvl512b, which is [1, 1] vs [64, 64]. */
#define MAX_POLY_VARIANT 64
-#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX
+#define HAVE_POST_MODIFY_DISP (TARGET_XTHEADMEMIDX || TARGET_XCVMEM)
#define HAVE_PRE_MODIFY_DISP TARGET_XTHEADMEMIDX
+#define HAVE_POST_MODIFY_REG TARGET_XCVMEM
+
#endif /* ! GCC_RISCV_H */
@@ -1777,7 +1777,7 @@
[(set (match_operand:GPR 0 "register_operand" "=r,r")
(zero_extend:GPR
(match_operand:HI 1 "nonimmediate_operand" " r,m")))]
- "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+ "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
"@
#
lhu\t%0,%1"
@@ -1806,7 +1806,7 @@
[(set (match_operand:SUPERQI 0 "register_operand" "=r,r")
(zero_extend:SUPERQI
(match_operand:QI 1 "nonimmediate_operand" " r,m")))]
- "!TARGET_XTHEADMEMIDX"
+ "!TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
"@
andi\t%0,%1,0xff
lbu\t%0,%1"
@@ -1848,7 +1848,7 @@
[(set (match_operand:SUPERQI 0 "register_operand" "=r,r")
(sign_extend:SUPERQI
(match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
- "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+ "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
"@
#
l<SHORT:size>\t%0,%1"
@@ -1908,7 +1908,7 @@
(define_insn "*movhf_hardfloat"
[(set (match_operand:HF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m")
(match_operand:HF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
- "TARGET_ZFHMIN
+ "TARGET_ZFHMIN && !TARGET_XCVMEM
&& (register_operand (operands[0], HFmode)
|| reg_or_0_operand (operands[1], HFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -1919,7 +1919,7 @@
(define_insn "*movhf_softfloat"
[(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
(match_operand:HF 1 "move_operand" " f,Gr,m,r,*r,*f"))]
- "!TARGET_ZFHMIN
+ "!TARGET_ZFHMIN && !TARGET_XCVMEM
&& (register_operand (operands[0], HFmode)
|| reg_or_0_operand (operands[1], HFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -2186,7 +2186,7 @@
(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m, *f,*f,*r,*m,r")
(match_operand:SI 1 "move_operand" " r,T,m,rJ,*r*J,*m,*f,*f,vp"))]
- "(register_operand (operands[0], SImode)
+ "!TARGET_XCVMEM && (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))
&& !(register_operand (operands[1], SImode)
&& reg_or_subregno (operands[1]) == VL_REGNUM)"
@@ -2215,7 +2215,7 @@
(define_insn "*movhi_internal"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m, *f,*r,r")
(match_operand:HI 1 "move_operand" " r,T,m,rJ,*r*J,*f,vp"))]
- "(register_operand (operands[0], HImode)
+ "!TARGET_XCVMEM && (register_operand (operands[0], HImode)
|| reg_or_0_operand (operands[1], HImode))"
{ return riscv_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2259,7 +2259,7 @@
(define_insn "*movqi_internal"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r, m, *f,*r,r")
(match_operand:QI 1 "move_operand" " r,I,m,rJ,*r*J,*f,vp"))]
- "(register_operand (operands[0], QImode)
+ "!TARGET_XCVMEM && (register_operand (operands[0], QImode)
|| reg_or_0_operand (operands[1], QImode))"
{ return riscv_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2281,7 +2281,7 @@
(define_insn "*movsf_hardfloat"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m")
(match_operand:SF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
- "TARGET_HARD_FLOAT
+ "TARGET_HARD_FLOAT && !TARGET_XCVMEM
&& (register_operand (operands[0], SFmode)
|| reg_or_0_operand (operands[1], SFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -2292,7 +2292,7 @@
(define_insn "*movsf_softfloat"
[(set (match_operand:SF 0 "nonimmediate_operand" "= r,r,m")
(match_operand:SF 1 "move_operand" " Gr,m,r"))]
- "!TARGET_HARD_FLOAT
+ "!TARGET_HARD_FLOAT && !TARGET_XCVMEM
&& (register_operand (operands[0], SFmode)
|| reg_or_0_operand (operands[1], SFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -2317,7 +2317,7 @@
(define_insn "*movdf_hardfloat_rv32"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*zmvf,*zmvr, *r,*r,*m")
(match_operand:DF 1 "move_operand" " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
- "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
+ "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
&& (register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -2328,7 +2328,7 @@
(define_insn "*movdf_hardfloat_rv64"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m")
(match_operand:DF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
- "TARGET_64BIT && TARGET_DOUBLE_FLOAT
+ "TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
&& (register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -2339,7 +2339,7 @@
(define_insn "*movdf_softfloat"
[(set (match_operand:DF 0 "nonimmediate_operand" "= r,r, m")
(match_operand:DF 1 "move_operand" " rG,m,rG"))]
- "!TARGET_DOUBLE_FLOAT
+ "!TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
&& (register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))"
{ return riscv_output_move (operands[0], operands[1]); }
@@ -425,6 +425,8 @@ Mask(XCVALU) Var(riscv_xcv_subext)
Mask(XCVELW) Var(riscv_xcv_subext)
+Mask(XCVMEM) Var(riscv_xcv_subext)
+
TargetVariable
int riscv_xthead_subext
@@ -2505,6 +2505,9 @@ Test system has support for the CORE-V ALU extension.
@item cv_elw
Test system has support for the CORE-V ELW extension.
+@item cv_mem
+Test system has support for the CORE-V MEM extension.
+
@end table
@subsubsection Other hardware attributes
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+ int char_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ char_sum += array_char[i];
+ }
+
+ return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+ int char_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ char_sum += *array_char;
+ array_char+=j*sizeof(array_char);
+ }
+
+ return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+ return array_char[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+ int uns_char_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ uns_char_sum += array_uchar[i];
+ }
+
+ return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+ int uns_char_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ uns_char_sum += *array_uchar;
+ array_uchar+=j*sizeof(array_uchar);
+ }
+
+ return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+ return array_uchar[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+ int short_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ short_sum += array_short[i];
+ }
+
+ return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+ int short_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ short_sum += *array_short;
+ array_short+=j*sizeof(array_short);
+ }
+
+ return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+ return array_short[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+ int uns_short_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ uns_short_sum += array_ushort[i];
+ }
+
+ return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+ int uns_short_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ uns_short_sum += *array_ushort;
+ array_ushort+=j*sizeof(array_ushort);
+ }
+
+ return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+ return array_ushort[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* We don't generate for some optimization levels. TODO: should support for Os,
+ Oz and Og */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } { "" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+ int int_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ int_sum += array_int[i];
+ }
+
+ return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+ int uns_int_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ uns_int_sum += array_uint[i];
+ }
+
+ return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+ int int_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ int_sum += *array_int;
+ array_int+=j*sizeof(array_int);
+ }
+
+ return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+ int uns_int_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ uns_int_sum += *array_uint;
+ array_uint+=j*sizeof(array_uint);
+ }
+
+ return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
new file mode 100644
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+ return array_int[i+j];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+ return array_uint[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (plus:SI (reg reg)))`.
+ */
+
+struct {
+ double a[3];
+} * b;
+int c;
+
+int
+foo (void)
+{
+ b[0].a[c] -= b[0].a[c];
+}
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (post_modify:SI (reg reg)))`.
+ */
+
+int bar (double);
+
+int
+foo (void)
+{
+ double *b;
+ int c = 0;
+ for (;; c++)
+ bar (b[c]);
+}
+
new file mode 100644
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2 -Wno-int-conversion" } */
+
+/*
+ * Test for illegal XCVmem specific operand in loads.
+ * Instruction `lbu reg,reg(reg)`.
+ */
+
+int a;
+int bar (char);
+
+int
+foo (void)
+{
+ short *d;
+ char *e = (char *)foo;
+ for (;;) {
+ char c = d++;
+ bar (c);
+ short b = e[0] + b;
+ if (b)
+ a = 5;
+ e += 2;
+ }
+}
+
+/* { dg-final { scan-assembler-not "lbu\t\[a-z\]\[0-99\],\[a-z\]\[0-99\]\\(\[a-z\]\[0-99\]\\)" } } */
new file mode 100644
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32if_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in flw.
+ * Error: illegal operands `flw fa5,a5(a4)'
+ */
+
+int b, e;
+float *m;
+
+int
+foo (void) {
+ m[1] = m[b];
+ m[b] = e;
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "flw\tfa5,a5\\(a4\\)" } } */
new file mode 100644
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32" } */
+
+/*
+ * Tests that stores can generate regular reg:imm operands.
+ */
+
+int a[1];
+int b, c, d, e, f;
+float g;
+
+int
+foo (void)
+{
+ int h;
+ for (;; d++)
+ switch (c) {
+ case 8:
+ g = e == f;
+ a[h + d] = g;
+ g = e < f;
+ b = g;
+ }
+}
new file mode 100644
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+
+/*
+ * Test for illegal XCVmem specific operands in lw.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+ return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+ return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.lw\t" } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for illegal XCVmem specific operands in register-immediate sw.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i)
+{
+ array_int [3] = i;
+ return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i)
+{
+ array_uint [3] = i;
+ return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.sw\t" } } */
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in sw.
+ */
+
+int a;
+float *b;
+
+int
+foo (void)
+{
+ int c;
+ for (c = 0; c < 10; c++)
+ b[c] = a;
+}
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+ int char_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_char[i] += char_sum;
+ }
+
+ return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+ int uns_char_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_uchar[i] += uns_char_sum;
+ }
+
+ return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 2 } } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+ int char_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_char += char_sum;
+ array_char+=j*sizeof(array_char);
+ }
+
+ return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+ int uns_char_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_uchar += uns_char_sum;
+ array_uchar+=j*sizeof(array_uchar);
+ }
+
+ return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+ int char_sum = 1;
+
+ array_char[i+j] += char_sum;
+
+ return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+ int uns_char_sum = 1;
+
+ array_uchar[i+j] += uns_char_sum;
+
+ return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+ int short_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_short[i] += short_sum;
+ }
+
+ return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+ int uns_short_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_ushort[i] += uns_short_sum;
+ }
+
+ return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 2 } } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+ int short_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_short += short_sum;
+ array_short+=j*sizeof(array_short);
+ }
+
+ return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+ int uns_short_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_ushort += uns_short_sum;
+ array_ushort+=j*sizeof(array_ushort);
+ }
+
+ return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+ int short_sum = 1;
+
+ array_short[i+j] = short_sum;
+
+ return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+ int uns_short_sum = 1;
+
+ array_ushort[i+j] += uns_short_sum;
+
+ return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+ int int_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_int[i] += int_sum;
+ }
+
+ return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+ int uns_int_sum = 1;
+
+ for(int i=0; i<n; i++)
+ {
+ array_uint[i] += uns_int_sum;
+ }
+
+ return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+ int int_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_int += int_sum;
+ array_int+=j*sizeof(array_int);
+ }
+
+ return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+ int uns_int_sum = 1;
+
+ for(int i=0; i<n; i+=j)
+ {
+ *array_uint += uns_int_sum;
+ array_uint+=j*sizeof(array_uint);
+ }
+
+ return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+ int int_sum = 1;
+
+ array_int[i+j] = int_sum;
+
+ return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+ int uns_int_sum = 1;
+
+ array_uint[i+j] = uns_int_sum;
+
+ return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
@@ -13307,6 +13307,19 @@ proc check_effective_target_cv_elw { } {
} "-march=rv32i_xcvelw" ]
}
+# Return 1 if the CORE-V MEM extension is available.
+proc check_effective_target_cv_mem { } {
+ if { !([istarget riscv*-*-*]) } {
+ return 0
+ }
+ return [check_no_compiler_messages cv_mem object {
+ void foo (void)
+ {
+ asm ("cv.lw t0, (t1), 4");
+ }
+ } "-march=rv32i_xcvmem" ]
+}
+
proc check_effective_target_loongarch_sx { } {
return [check_no_compiler_messages loongarch_lsx assembly {
#if !defined(__loongarch_sx)