RISC-V: Support poly move manipulation and selftests.
gcc/ChangeLog: * common/config/riscv/riscv-common.cc: Change "static void" to "void". * config.gcc: Add riscv-selftests.o * config/riscv/predicates.md: Allow const_poly_int. * config/riscv/riscv-protos.h (riscv_reinit): New function. (riscv_parse_arch_string): change as exten function. (riscv_run_selftests): New function. * config/riscv/riscv.cc (riscv_cannot_force_const_mem): Don't allow poly into const pool. (riscv_report_v_required): New function. (riscv_expand_op): New function. (riscv_expand_mult_with_const_int): New function. (riscv_legitimize_poly_move): Ditto. (riscv_legitimize_move): New function. (riscv_hard_regno_mode_ok): Add VL/VTYPE register allocation and fix vector RA. (riscv_convert_vector_bits): Fix riscv_vector_chunks configuration for -marh no 'v'. (riscv_reinit): New function. (TARGET_RUN_TARGET_SELFTESTS): New target hook support. * config/riscv/t-riscv: Add riscv-selftests.o. * config/riscv/riscv-selftests.cc: New file. gcc/testsuite/ChangeLog: * selftests/riscv/empty-func.rtl: New test.
This commit is contained in:
parent
ab98b4c072
commit
b4feb49cf3
8 changed files with 560 additions and 7 deletions
|
@ -1224,7 +1224,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
|
|||
/* Parse a RISC-V ISA string into an option mask. Must clear or set all arch
|
||||
dependent mask bits, in case more than one -march string is passed. */
|
||||
|
||||
static void
|
||||
void
|
||||
riscv_parse_arch_string (const char *isa,
|
||||
struct gcc_options *opts,
|
||||
location_t loc)
|
||||
|
|
|
@ -515,7 +515,7 @@ pru-*-*)
|
|||
;;
|
||||
riscv*)
|
||||
cpu_type=riscv
|
||||
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o"
|
||||
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o"
|
||||
d_target_objs="riscv-d.o"
|
||||
;;
|
||||
rs6000*-*-*)
|
||||
|
|
|
@ -146,6 +146,9 @@
|
|||
case CONST_INT:
|
||||
return !splittable_const_int_operand (op, mode);
|
||||
|
||||
case CONST_POLY_INT:
|
||||
return known_eq (rtx_to_poly_int64 (op), BYTES_PER_RISCV_VECTOR);
|
||||
|
||||
case CONST:
|
||||
case SYMBOL_REF:
|
||||
case LABEL_REF:
|
||||
|
|
|
@ -74,6 +74,7 @@ extern bool riscv_expand_block_move (rtx, rtx, rtx);
|
|||
extern bool riscv_store_data_bypass_p (rtx_insn *, rtx_insn *);
|
||||
extern rtx riscv_gen_gpr_save_insn (struct riscv_frame_info *);
|
||||
extern bool riscv_gpr_save_operation_p (rtx);
|
||||
extern void riscv_reinit (void);
|
||||
|
||||
/* Routines implemented in riscv-c.cc. */
|
||||
void riscv_cpu_cpp_builtins (cpp_reader *);
|
||||
|
@ -86,6 +87,7 @@ extern void riscv_init_builtins (void);
|
|||
|
||||
/* Routines implemented in riscv-common.cc. */
|
||||
extern std::string riscv_arch_str (bool version_p = true);
|
||||
extern void riscv_parse_arch_string (const char *, struct gcc_options *, location_t);
|
||||
|
||||
extern bool riscv_hard_regno_rename_ok (unsigned, unsigned);
|
||||
|
||||
|
@ -105,4 +107,11 @@ struct riscv_cpu_info {
|
|||
|
||||
extern const riscv_cpu_info *riscv_find_cpu (const char *);
|
||||
|
||||
/* Routines implemented in riscv-selftests.cc. */
|
||||
#if CHECKING_P
|
||||
namespace selftest {
|
||||
extern void riscv_run_selftests (void);
|
||||
} // namespace selftest
|
||||
#endif
|
||||
|
||||
#endif /* ! GCC_RISCV_PROTOS_H */
|
||||
|
|
241
gcc/config/riscv/riscv-selftests.cc
Normal file
241
gcc/config/riscv/riscv-selftests.cc
Normal file
|
@ -0,0 +1,241 @@
|
|||
/* 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/>. */
|
||||
|
||||
#define IN_TARGET_CODE 1
|
||||
|
||||
#define INCLUDE_STRING
|
||||
#define INCLUDE_MAP
|
||||
#define INCLUDE_VECTOR
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "rtl.h"
|
||||
#include "tree.h"
|
||||
#include "stringpool.h"
|
||||
#include "function.h"
|
||||
#include "memmodel.h"
|
||||
#include "emit-rtl.h"
|
||||
#include "tm_p.h"
|
||||
#include "expr.h"
|
||||
#include "selftest.h"
|
||||
#include "selftest-rtl.h"
|
||||
|
||||
#if CHECKING_P
|
||||
using namespace selftest;
|
||||
class riscv_selftest_arch_abi_setter
|
||||
{
|
||||
private:
|
||||
std::string m_arch_backup;
|
||||
enum riscv_abi_type m_abi_backup;
|
||||
|
||||
public:
|
||||
riscv_selftest_arch_abi_setter (const char *arch, enum riscv_abi_type abi)
|
||||
: m_arch_backup (riscv_arch_str ()), m_abi_backup (riscv_abi)
|
||||
{
|
||||
riscv_parse_arch_string (arch, &global_options, UNKNOWN_LOCATION);
|
||||
riscv_abi = abi;
|
||||
riscv_reinit ();
|
||||
}
|
||||
~riscv_selftest_arch_abi_setter ()
|
||||
{
|
||||
riscv_parse_arch_string (m_arch_backup.c_str (), &global_options,
|
||||
UNKNOWN_LOCATION);
|
||||
riscv_abi = m_abi_backup;
|
||||
riscv_reinit ();
|
||||
}
|
||||
};
|
||||
|
||||
static poly_int64
|
||||
eval_value (rtx x, std::map<unsigned, rtx> ®no_to_rtx)
|
||||
{
|
||||
if (!REG_P (x))
|
||||
{
|
||||
debug (x);
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
rtx expr = NULL_RTX;
|
||||
unsigned regno = REGNO (x);
|
||||
expr = regno_to_rtx[regno];
|
||||
|
||||
poly_int64 op1_val = 0;
|
||||
poly_int64 op2_val = 0;
|
||||
if (UNARY_P (expr))
|
||||
{
|
||||
op1_val = eval_value (XEXP (expr, 0), regno_to_rtx);
|
||||
}
|
||||
if (BINARY_P (expr))
|
||||
{
|
||||
op1_val = eval_value (XEXP (expr, 0), regno_to_rtx);
|
||||
op2_val = eval_value (XEXP (expr, 1), regno_to_rtx);
|
||||
}
|
||||
|
||||
switch (GET_CODE (expr))
|
||||
{
|
||||
case CONST_POLY_INT:
|
||||
return rtx_to_poly_int64 (expr);
|
||||
case CONST_INT:
|
||||
return INTVAL (expr);
|
||||
|
||||
case MULT:
|
||||
if (op1_val.is_constant ())
|
||||
return op1_val.to_constant () * op2_val;
|
||||
else if (op2_val.is_constant ())
|
||||
return op1_val * op2_val.to_constant ();
|
||||
else
|
||||
gcc_unreachable ();
|
||||
case PLUS:
|
||||
return op1_val + op2_val;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the value of x register in the sequence. */
|
||||
static poly_int64
|
||||
calculate_x_in_sequence (rtx reg)
|
||||
{
|
||||
std::map<unsigned, rtx> regno_to_rtx;
|
||||
rtx_insn *insn;
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
rtx pat = PATTERN (insn);
|
||||
rtx dest = SET_DEST (pat);
|
||||
|
||||
if (GET_CODE (pat) == CLOBBER)
|
||||
continue;
|
||||
|
||||
if (SUBREG_P (dest))
|
||||
continue;
|
||||
|
||||
gcc_assert (REG_P (dest));
|
||||
rtx note = find_reg_equal_equiv_note (insn);
|
||||
unsigned regno = REGNO (dest);
|
||||
if (note)
|
||||
regno_to_rtx[regno] = XEXP (note, 0);
|
||||
else
|
||||
regno_to_rtx[regno] = SET_SRC (pat);
|
||||
}
|
||||
|
||||
return eval_value (reg, regno_to_rtx);
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
POLY_TEST_DIMODE,
|
||||
POLY_TEST_PMODE
|
||||
} poly_test_mode_t;
|
||||
|
||||
static void
|
||||
simple_poly_selftest (const char *arch, enum riscv_abi_type abi,
|
||||
const std::vector<machine_mode> &modes)
|
||||
{
|
||||
riscv_selftest_arch_abi_setter rv (arch, abi);
|
||||
rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
|
||||
set_new_first_and_last_insn (NULL, NULL);
|
||||
|
||||
for (machine_mode mode : modes)
|
||||
emit_move_insn (gen_reg_rtx (mode),
|
||||
gen_int_mode (BYTES_PER_RISCV_VECTOR, mode));
|
||||
}
|
||||
|
||||
static void
|
||||
run_poly_int_selftest (const char *arch, enum riscv_abi_type abi,
|
||||
poly_test_mode_t test_mode,
|
||||
const std::vector<poly_int64> &worklist)
|
||||
{
|
||||
riscv_selftest_arch_abi_setter rv (arch, abi);
|
||||
rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
|
||||
set_new_first_and_last_insn (NULL, NULL);
|
||||
machine_mode mode = VOIDmode;
|
||||
|
||||
switch (test_mode)
|
||||
{
|
||||
case POLY_TEST_DIMODE:
|
||||
mode = DImode;
|
||||
break;
|
||||
case POLY_TEST_PMODE:
|
||||
mode = Pmode;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
for (const poly_int64 &poly_val : worklist)
|
||||
{
|
||||
start_sequence ();
|
||||
rtx dest = gen_reg_rtx (mode);
|
||||
emit_move_insn (dest, gen_int_mode (poly_val, mode));
|
||||
ASSERT_TRUE (known_eq (calculate_x_in_sequence (dest), poly_val));
|
||||
end_sequence ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
run_poly_int_selftests (void)
|
||||
{
|
||||
std::vector<poly_int64> worklist
|
||||
= {BYTES_PER_RISCV_VECTOR, BYTES_PER_RISCV_VECTOR * 8,
|
||||
BYTES_PER_RISCV_VECTOR * 32, -BYTES_PER_RISCV_VECTOR * 8,
|
||||
-BYTES_PER_RISCV_VECTOR * 32, BYTES_PER_RISCV_VECTOR * 7,
|
||||
BYTES_PER_RISCV_VECTOR * 31, -BYTES_PER_RISCV_VECTOR * 7,
|
||||
-BYTES_PER_RISCV_VECTOR * 31, BYTES_PER_RISCV_VECTOR * 9,
|
||||
BYTES_PER_RISCV_VECTOR * 33, -BYTES_PER_RISCV_VECTOR * 9,
|
||||
-BYTES_PER_RISCV_VECTOR * 33, poly_int64 (207, 0),
|
||||
poly_int64 (-207, 0), poly_int64 (0, 207),
|
||||
poly_int64 (0, -207), poly_int64 (5555, 0),
|
||||
poly_int64 (0, 5555), poly_int64 (4096, 4096),
|
||||
poly_int64 (17, 4088), poly_int64 (3889, 4104),
|
||||
poly_int64 (-4096, -4096), poly_int64 (219, -4088),
|
||||
poly_int64 (-4309, -4104), poly_int64 (-7337, 88),
|
||||
poly_int64 (9317, -88), poly_int64 (4, 4),
|
||||
poly_int64 (17, 4), poly_int64 (-7337, 4),
|
||||
poly_int64 (-4, -4), poly_int64 (-389, -4),
|
||||
poly_int64 (4789, -4), poly_int64 (-5977, 1508),
|
||||
poly_int64 (219, -1508), poly_int64 (2, 2),
|
||||
poly_int64 (33, 2), poly_int64 (-7337, 2),
|
||||
poly_int64 (-2, -2), poly_int64 (-389, -2),
|
||||
poly_int64 (4789, -2), poly_int64 (-3567, 954),
|
||||
poly_int64 (945, -954), poly_int64 (1, 1),
|
||||
poly_int64 (977, 1), poly_int64 (-339, 1),
|
||||
poly_int64 (-1, -1), poly_int64 (-12, -1),
|
||||
poly_int64 (44, -1), poly_int64 (9567, 77),
|
||||
poly_int64 (3467, -77)};
|
||||
|
||||
simple_poly_selftest ("rv64imafdv", ABI_LP64D,
|
||||
{QImode, HImode, SImode, DImode});
|
||||
simple_poly_selftest ("rv32imafdv", ABI_ILP32D, {QImode, HImode, SImode});
|
||||
|
||||
run_poly_int_selftest ("rv64imafdv", ABI_LP64D, POLY_TEST_PMODE, worklist);
|
||||
run_poly_int_selftest ("rv64imafd_zve32x1p0", ABI_LP64D, POLY_TEST_PMODE,
|
||||
worklist);
|
||||
run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_PMODE, worklist);
|
||||
run_poly_int_selftest ("rv32imafdv", ABI_ILP32, POLY_TEST_DIMODE, worklist);
|
||||
run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_PMODE,
|
||||
worklist);
|
||||
run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_DIMODE,
|
||||
worklist);
|
||||
}
|
||||
namespace selftest {
|
||||
/* Run all target-specific selftests. */
|
||||
void
|
||||
riscv_run_selftests (void)
|
||||
{
|
||||
run_poly_int_selftests ();
|
||||
}
|
||||
} // namespace selftest
|
||||
#endif /* #if CHECKING_P */
|
|
@ -57,6 +57,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "predict.h"
|
||||
#include "tree-pass.h"
|
||||
#include "opts.h"
|
||||
#include "tm-constrs.h"
|
||||
#include "rtl-iter.h"
|
||||
|
||||
/* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
|
||||
#define UNSPEC_ADDRESS_P(X) \
|
||||
|
@ -778,6 +780,12 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
|
|||
enum riscv_symbol_type type;
|
||||
rtx base, offset;
|
||||
|
||||
/* There's no way to calculate VL-based values using relocations. */
|
||||
subrtx_iterator::array_type array;
|
||||
FOR_EACH_SUBRTX (iter, array, x, ALL)
|
||||
if (GET_CODE (*iter) == CONST_POLY_INT)
|
||||
return true;
|
||||
|
||||
/* There is no assembler syntax for expressing an address-sized
|
||||
high part. */
|
||||
if (GET_CODE (x) == HIGH)
|
||||
|
@ -1684,12 +1692,268 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
|
|||
riscv_emit_move (dest, src);
|
||||
}
|
||||
|
||||
/* Report when we try to do something that requires vector when vector is
|
||||
disabled. This is an error of last resort and isn't very high-quality. It
|
||||
usually involves attempts to measure the vector length in some way. */
|
||||
|
||||
static void
|
||||
riscv_report_v_required (void)
|
||||
{
|
||||
static bool reported_p = false;
|
||||
|
||||
/* Avoid reporting a slew of messages for a single oversight. */
|
||||
if (reported_p)
|
||||
return;
|
||||
|
||||
error ("this operation requires the RVV ISA extension");
|
||||
inform (input_location, "you can enable RVV using the command-line"
|
||||
" option %<-march%>, or by using the %<target%>"
|
||||
" attribute or pragma");
|
||||
reported_p = true;
|
||||
}
|
||||
|
||||
/* Helper function to operation for rtx_code CODE. */
|
||||
static void
|
||||
riscv_expand_op (enum rtx_code code, machine_mode mode, rtx op0, rtx op1,
|
||||
rtx op2)
|
||||
{
|
||||
if (can_create_pseudo_p ())
|
||||
{
|
||||
rtx result;
|
||||
if (GET_RTX_CLASS (code) == RTX_UNARY)
|
||||
result = expand_simple_unop (mode, code, op1, NULL_RTX, false);
|
||||
else
|
||||
result = expand_simple_binop (mode, code, op1, op2, NULL_RTX, false,
|
||||
OPTAB_DIRECT);
|
||||
riscv_emit_move (op0, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtx pat;
|
||||
/* The following implementation is for prologue and epilogue.
|
||||
Because prologue and epilogue can not use pseudo register.
|
||||
We can't using expand_simple_binop or expand_simple_unop. */
|
||||
if (GET_RTX_CLASS (code) == RTX_UNARY)
|
||||
pat = gen_rtx_fmt_e (code, mode, op1);
|
||||
else
|
||||
pat = gen_rtx_fmt_ee (code, mode, op1, op2);
|
||||
emit_insn (gen_rtx_SET (op0, pat));
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand mult operation with constant integer, multiplicand also used as a
|
||||
* temporary register. */
|
||||
|
||||
static void
|
||||
riscv_expand_mult_with_const_int (machine_mode mode, rtx dest, rtx multiplicand,
|
||||
int multiplier)
|
||||
{
|
||||
if (multiplier == 0)
|
||||
{
|
||||
riscv_emit_move (dest, GEN_INT (0));
|
||||
return;
|
||||
}
|
||||
|
||||
bool neg_p = multiplier < 0;
|
||||
int multiplier_abs = abs (multiplier);
|
||||
|
||||
if (multiplier_abs == 1)
|
||||
{
|
||||
if (neg_p)
|
||||
riscv_expand_op (NEG, mode, dest, multiplicand, NULL_RTX);
|
||||
else
|
||||
riscv_emit_move (dest, multiplicand);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pow2p_hwi (multiplier_abs))
|
||||
{
|
||||
/*
|
||||
multiplicand = [BYTES_PER_RISCV_VECTOR].
|
||||
1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 8].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a5, a5, 3
|
||||
2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 8].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a5, a5, 3
|
||||
neg a5, a5
|
||||
*/
|
||||
riscv_expand_op (ASHIFT, mode, dest, multiplicand,
|
||||
gen_int_mode (exact_log2 (multiplier_abs), QImode));
|
||||
if (neg_p)
|
||||
riscv_expand_op (NEG, mode, dest, dest, NULL_RTX);
|
||||
}
|
||||
else if (pow2p_hwi (multiplier_abs + 1))
|
||||
{
|
||||
/*
|
||||
multiplicand = [BYTES_PER_RISCV_VECTOR].
|
||||
1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 7].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a4, a5, 3
|
||||
sub a5, a4, a5
|
||||
2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 7].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a4, a5, 3
|
||||
sub a5, a4, a5 + neg a5, a5 => sub a5, a5, a4
|
||||
*/
|
||||
riscv_expand_op (ASHIFT, mode, dest, multiplicand,
|
||||
gen_int_mode (exact_log2 (multiplier_abs + 1),
|
||||
QImode));
|
||||
if (neg_p)
|
||||
riscv_expand_op (MINUS, mode, dest, multiplicand, dest);
|
||||
else
|
||||
riscv_expand_op (MINUS, mode, dest, dest, multiplicand);
|
||||
}
|
||||
else if (pow2p_hwi (multiplier - 1))
|
||||
{
|
||||
/*
|
||||
multiplicand = [BYTES_PER_RISCV_VECTOR].
|
||||
1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 9].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a4, a5, 3
|
||||
add a5, a4, a5
|
||||
2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 9].
|
||||
Sequence:
|
||||
csrr a5, vlenb
|
||||
slli a4, a5, 3
|
||||
add a5, a4, a5
|
||||
neg a5, a5
|
||||
*/
|
||||
riscv_expand_op (ASHIFT, mode, dest, multiplicand,
|
||||
gen_int_mode (exact_log2 (multiplier_abs - 1),
|
||||
QImode));
|
||||
riscv_expand_op (PLUS, mode, dest, dest, multiplicand);
|
||||
if (neg_p)
|
||||
riscv_expand_op (NEG, mode, dest, dest, NULL_RTX);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We use multiplication for remaining cases. */
|
||||
gcc_assert (
|
||||
TARGET_MUL
|
||||
&& "M-extension must be enabled to calculate the poly_int "
|
||||
"size/offset.");
|
||||
riscv_emit_move (dest, gen_int_mode (multiplier, mode));
|
||||
riscv_expand_op (MULT, mode, dest, dest, multiplicand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Analyze src and emit const_poly_int mov sequence. */
|
||||
|
||||
static void
|
||||
riscv_legitimize_poly_move (machine_mode mode, rtx dest, rtx tmp, rtx src)
|
||||
{
|
||||
poly_int64 value = rtx_to_poly_int64 (src);
|
||||
int offset = value.coeffs[0];
|
||||
int factor = value.coeffs[1];
|
||||
int vlenb = BYTES_PER_RISCV_VECTOR.coeffs[1];
|
||||
int div_factor = 0;
|
||||
/* Calculate (const_poly_int:MODE [m, n]) using scalar instructions.
|
||||
For any (const_poly_int:MODE [m, n]), the calculation formula is as
|
||||
follows.
|
||||
constant = m - n.
|
||||
When minimum VLEN = 32, poly of VLENB = (4, 4).
|
||||
base = vlenb(4, 4) or vlenb/2(2, 2) or vlenb/4(1, 1).
|
||||
When minimum VLEN > 32, poly of VLENB = (8, 8).
|
||||
base = vlenb(8, 8) or vlenb/2(4, 4) or vlenb/4(2, 2) or vlenb/8(1, 1).
|
||||
magn = (n, n) / base.
|
||||
(m, n) = base * magn + constant.
|
||||
This calculation doesn't need div operation. */
|
||||
|
||||
emit_move_insn (tmp, gen_int_mode (BYTES_PER_RISCV_VECTOR, mode));
|
||||
|
||||
if (BYTES_PER_RISCV_VECTOR.is_constant ())
|
||||
{
|
||||
gcc_assert (value.is_constant ());
|
||||
riscv_emit_move (dest, GEN_INT (value.to_constant ()));
|
||||
return;
|
||||
}
|
||||
else if ((factor % vlenb) == 0)
|
||||
div_factor = 1;
|
||||
else if ((factor % (vlenb / 2)) == 0)
|
||||
div_factor = 2;
|
||||
else if ((factor % (vlenb / 4)) == 0)
|
||||
div_factor = 4;
|
||||
else if ((factor % (vlenb / 8)) == 0)
|
||||
div_factor = 8;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
if (div_factor != 1)
|
||||
riscv_expand_op (LSHIFTRT, mode, tmp, tmp,
|
||||
gen_int_mode (exact_log2 (div_factor), QImode));
|
||||
|
||||
riscv_expand_mult_with_const_int (mode, dest, tmp,
|
||||
factor / (vlenb / div_factor));
|
||||
HOST_WIDE_INT constant = offset - factor;
|
||||
|
||||
if (constant == 0)
|
||||
return;
|
||||
else if (SMALL_OPERAND (constant))
|
||||
riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode));
|
||||
else
|
||||
{
|
||||
/* Handle the constant value is not a 12-bit value. */
|
||||
rtx high;
|
||||
|
||||
/* Leave OFFSET as a 16-bit offset and put the excess in HIGH.
|
||||
The addition inside the macro CONST_HIGH_PART may cause an
|
||||
overflow, so we need to force a sign-extension check. */
|
||||
high = gen_int_mode (CONST_HIGH_PART (constant), mode);
|
||||
constant = CONST_LOW_PART (constant);
|
||||
riscv_emit_move (tmp, high);
|
||||
riscv_expand_op (PLUS, mode, dest, tmp, dest);
|
||||
riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode));
|
||||
}
|
||||
}
|
||||
|
||||
/* If (set DEST SRC) is not a valid move instruction, emit an equivalent
|
||||
sequence that is valid. */
|
||||
|
||||
bool
|
||||
riscv_legitimize_move (machine_mode mode, rtx dest, rtx src)
|
||||
{
|
||||
if (CONST_POLY_INT_P (src))
|
||||
{
|
||||
poly_int64 value = rtx_to_poly_int64 (src);
|
||||
if (!value.is_constant () && !TARGET_VECTOR)
|
||||
{
|
||||
riscv_report_v_required ();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (satisfies_constraint_vp (src))
|
||||
return false;
|
||||
|
||||
if (GET_MODE_SIZE (mode).to_constant () < GET_MODE_SIZE (Pmode))
|
||||
{
|
||||
/* In RV32 system, handle (const_poly_int:QI [m, n])
|
||||
(const_poly_int:HI [m, n]).
|
||||
In RV64 system, handle (const_poly_int:QI [m, n])
|
||||
(const_poly_int:HI [m, n])
|
||||
(const_poly_int:SI [m, n]). */
|
||||
rtx tmp = gen_reg_rtx (Pmode);
|
||||
riscv_legitimize_poly_move (Pmode, gen_lowpart (Pmode, dest), tmp,
|
||||
src);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In RV32 system, handle (const_poly_int:SI [m, n])
|
||||
(const_poly_int:DI [m, n]).
|
||||
In RV64 system, handle (const_poly_int:DI [m, n]).
|
||||
FIXME: Maybe we could gen SImode in RV32 and then sign-extend to DImode,
|
||||
the offset should not exceed 4GiB in general. */
|
||||
rtx tmp = gen_reg_rtx (mode);
|
||||
riscv_legitimize_poly_move (mode, dest, tmp, src);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* Expand
|
||||
(set (reg:QI target) (mem:QI (address)))
|
||||
to
|
||||
|
@ -5033,6 +5297,9 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
|
|||
if (!riscv_v_ext_vector_mode_p (mode))
|
||||
return false;
|
||||
|
||||
if (!V_REG_P (regno + nregs - 1))
|
||||
return false;
|
||||
|
||||
/* 3.3.2. LMUL = 2,4,8, register numbers should be multiple of 2,4,8.
|
||||
but for mask vector register, register numbers can be any number. */
|
||||
int lmul = 1;
|
||||
|
@ -5041,6 +5308,8 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
|
|||
if (lmul != 1)
|
||||
return ((regno % lmul) == 0);
|
||||
}
|
||||
else if (regno == VL_REGNUM || regno == VTYPE_REGNUM)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@ -5231,10 +5500,6 @@ riscv_init_machine_status (void)
|
|||
static poly_uint16
|
||||
riscv_convert_vector_bits (void)
|
||||
{
|
||||
/* The runtime invariant is only meaningful when TARGET_VECTOR is enabled. */
|
||||
if (!TARGET_VECTOR)
|
||||
return 0;
|
||||
|
||||
if (TARGET_MIN_VLEN > 32)
|
||||
{
|
||||
/* When targetting minimum VLEN > 32, we should use 64-bit chunk size.
|
||||
|
@ -5255,7 +5520,13 @@ riscv_convert_vector_bits (void)
|
|||
riscv_bytes_per_vector_chunk = 4;
|
||||
}
|
||||
|
||||
return poly_uint16 (1, 1);
|
||||
/* Set riscv_vector_chunks as poly (1, 1) run-time constant if TARGET_VECTOR
|
||||
is enabled. Set riscv_vector_chunks as 1 compile-time constant if
|
||||
TARGET_VECTOR is disabled. riscv_vector_chunks is used in "riscv-modes.def"
|
||||
to set RVV mode size. The RVV machine modes size are run-time constant if
|
||||
TARGET_VECTOR is enabled. The RVV machine modes size remains default
|
||||
compile-time constant if TARGET_VECTOR is disabled. */
|
||||
return TARGET_VECTOR ? poly_uint16 (1, 1) : 1;
|
||||
}
|
||||
|
||||
/* Implement TARGET_OPTION_OVERRIDE. */
|
||||
|
@ -6002,6 +6273,23 @@ riscv_init_libfuncs (void)
|
|||
set_optab_libfunc (unord_optab, HFmode, NULL);
|
||||
}
|
||||
|
||||
#if CHECKING_P
|
||||
void
|
||||
riscv_reinit (void)
|
||||
{
|
||||
riscv_option_override ();
|
||||
init_adjust_machine_modes ();
|
||||
init_derived_machine_modes ();
|
||||
reinit_regs ();
|
||||
init_optabs ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CHECKING_P
|
||||
#undef TARGET_RUN_TARGET_SELFTESTS
|
||||
#define TARGET_RUN_TARGET_SELFTESTS selftest::riscv_run_selftests
|
||||
#endif /* #if CHECKING_P */
|
||||
|
||||
/* Initialize the GCC target structure. */
|
||||
#undef TARGET_ASM_ALIGNED_HI_OP
|
||||
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
|
||||
|
|
|
@ -23,6 +23,10 @@ riscv-shorten-memrefs.o: $(srcdir)/config/riscv/riscv-shorten-memrefs.cc
|
|||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
riscv-selftests.o: $(srcdir)/config/riscv/riscv-selftests.cc
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def
|
||||
|
||||
$(common_out_file): $(srcdir)/config/riscv/riscv-cores.def \
|
||||
|
|
8
gcc/testsuite/selftests/riscv/empty-func.rtl
Normal file
8
gcc/testsuite/selftests/riscv/empty-func.rtl
Normal file
|
@ -0,0 +1,8 @@
|
|||
(function "func"
|
||||
(insn-chain
|
||||
(block 2
|
||||
(edge-from entry (flags "FALLTHRU"))
|
||||
(edge-to exit (flags "FALLTHRU"))
|
||||
) ;; block 2
|
||||
) ;; insn-chain
|
||||
) ;; function
|
Loading…
Add table
Reference in a new issue