/* Information about a function's frame layout. */
struct GTY(()) riscv_frame_info {
/* The size of the frame in bytes. */
- HOST_WIDE_INT total_size;
+ poly_int64 total_size;
/* Bit X is set if the function saves or restores GPR X. */
unsigned int mask;
unsigned save_libcall_adjustment;
/* Offsets of fixed-point and floating-point save areas from frame bottom */
- HOST_WIDE_INT gp_sp_offset;
- HOST_WIDE_INT fp_sp_offset;
+ poly_int64 gp_sp_offset;
+ poly_int64 fp_sp_offset;
/* Offset of virtual frame pointer from stack pointer/frame bottom */
- HOST_WIDE_INT frame_pointer_offset;
+ poly_int64 frame_pointer_offset;
/* Offset of hard frame pointer from stack pointer/frame bottom */
- HOST_WIDE_INT hard_frame_pointer_offset;
+ poly_int64 hard_frame_pointer_offset;
/* The offset of arg_pointer_rtx from the bottom of the frame. */
- HOST_WIDE_INT arg_pointer_offset;
+ poly_int64 arg_pointer_offset;
};
enum riscv_privilege_levels {
/* Which automaton to use for tuning. */
enum riscv_microarchitecture_type riscv_microarchitecture;
+/* The number of chunks in a single vector register. */
+poly_uint16 riscv_vector_chunks;
+
+/* The number of bytes in a vector chunk. */
+unsigned riscv_bytes_per_vector_chunk;
+
/* Index R is the smallest register class that contains register R. */
const enum reg_class riscv_regno_to_class[FIRST_PSEUDO_REGISTER] = {
GR_REGS, GR_REGS, GR_REGS, GR_REGS,
/* We may need to split multiword moves, so make sure that every word
is accessible. */
- if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
- && !SMALL_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode) - UNITS_PER_WORD))
+ if (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
+ && !SMALL_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode).to_constant () - UNITS_PER_WORD))
return false;
return true;
else
{
align = GET_MODE_ALIGNMENT (mode);
- size = GET_MODE_BITSIZE (mode);
+ size = GET_MODE_BITSIZE (mode).to_constant ();
}
/* We may need to split multiword moves, so make sure that each word
/* BLKmode is used for single unaligned loads and stores and should
not count as a multiword mode. */
if (mode != BLKmode && might_split_p)
- n += (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ n += (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (addr.type == ADDRESS_LO_SUM)
n += riscv_symbol_insns (addr.symbol_type) - 1;
/* Try to prove that INSN does not need to be split. */
might_split_p = true;
- if (GET_MODE_BITSIZE (mode) <= 32)
+ if (GET_MODE_BITSIZE (mode).to_constant () <= 32)
might_split_p = false;
- else if (GET_MODE_BITSIZE (mode) == 64)
+ else if (GET_MODE_BITSIZE (mode).to_constant () == 64)
{
set = single_set (insn);
if (set && !riscv_split_64bit_move_p (SET_DEST (set), SET_SRC (set)))
(set (reg:QI target) (subreg:QI (reg:DI temp) 0))
with auto-sign/zero extend. */
if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD
+ && GET_MODE_SIZE (mode).to_constant () < UNITS_PER_WORD
&& can_create_pseudo_p ()
&& MEM_P (src))
{
improve cse. */
machine_mode promoted_mode = mode;
if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+ && GET_MODE_SIZE (mode).to_constant () < UNITS_PER_WORD)
promoted_mode = word_mode;
if (splittable_const_int_operand (src, mode))
static int
riscv_binary_cost (rtx x, int single_insns, int double_insns)
{
- if (GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD * 2)
+ if (GET_MODE_SIZE (GET_MODE (x)).to_constant () == UNITS_PER_WORD * 2)
return COSTS_N_INSNS (double_insns);
return COSTS_N_INSNS (single_insns);
}
return false;
case NOT:
- *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) > UNITS_PER_WORD ? 2 : 1);
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD ? 2 : 1);
return false;
case AND:
if (float_mode_p)
*total = tune_param->fp_add[mode == DFmode];
else
- *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) > UNITS_PER_WORD ? 4 : 1);
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD ? 4 : 1);
return false;
case MULT:
else if (!TARGET_MUL)
/* Estimate the cost of a library call. */
*total = COSTS_N_INSNS (speed ? 32 : 6);
- else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ else if (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD)
*total = 3 * tune_param->int_mul[0] + COSTS_N_INSNS (2);
else if (!speed)
*total = COSTS_N_INSNS (1);
dest_code = GET_CODE (dest);
src_code = GET_CODE (src);
mode = GET_MODE (dest);
- dbl_p = (GET_MODE_SIZE (mode) == 8);
- width = GET_MODE_SIZE (mode);
+ dbl_p = (GET_MODE_SIZE (mode).to_constant () == 8);
+ width = GET_MODE_SIZE (mode).to_constant ();
if (dbl_p && riscv_split_64bit_move_p (dest, src))
return "#";
riscv_extend_comparands (rtx_code code, rtx *op0, rtx *op1)
{
/* Comparisons consider all XLEN bits, so extend sub-XLEN values. */
- if (GET_MODE_SIZE (word_mode) > GET_MODE_SIZE (GET_MODE (*op0)))
+ if (GET_MODE_SIZE (word_mode) > GET_MODE_SIZE (GET_MODE (*op0)).to_constant ())
{
/* It is more profitable to zero-extend QImode values. But not if the
first operand has already been sign-extended, and the second one is
if (n != 0)
return -1;
- HOST_WIDE_INT elt_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type)));
+ HOST_WIDE_INT elt_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type))).to_constant ();
if (elt_size <= UNITS_PER_FP_ARG)
{
default:
if (n < 2
&& ((SCALAR_FLOAT_TYPE_P (type)
- && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FP_ARG)
+ && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_FP_ARG)
|| (INTEGRAL_TYPE_P (type)
- && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD)))
+ && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_WORD)))
{
fields[n].type = type;
fields[n].offset = offset;
}
/* Work out the size of the argument. */
- num_bytes = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+ num_bytes = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode).to_constant ();
num_words = (num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
/* Doubleword-aligned varargs start on an even register boundary. */
static bool
riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg)
{
- HOST_WIDE_INT size = arg.type_size_in_bytes ();
+ HOST_WIDE_INT size = arg.type_size_in_bytes ().to_constant ();;
struct riscv_arg_info info;
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
{
section *s = default_elf_select_rtx_section (mode, x, align);
- if (riscv_size_ok_for_small_data_p (GET_MODE_SIZE (mode)))
+ if (riscv_size_ok_for_small_data_p (GET_MODE_SIZE (mode).to_constant ()))
{
if (startswith (s->named.name, ".rodata.cst"))
{
static HOST_WIDE_INT riscv_first_stack_step (struct riscv_frame_info *frame);
+/* Handle stack align for poly_int. */
+static poly_int64
+riscv_stack_align (poly_int64 value)
+{
+ return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8);
+}
+
+static HOST_WIDE_INT
+riscv_stack_align (HOST_WIDE_INT value)
+{
+ return RISCV_STACK_ALIGN (value);
+}
+
static void
riscv_compute_frame_info (void)
{
struct riscv_frame_info *frame;
- HOST_WIDE_INT offset;
+ poly_int64 offset;
bool interrupt_save_prologue_temp = false;
unsigned int regno, i, num_x_saved = 0, num_f_saved = 0;
if (cfun->machine->interrupt_handler_p)
{
HOST_WIDE_INT step1 = riscv_first_stack_step (frame);
- if (! SMALL_OPERAND (frame->total_size - step1))
+ if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1)))
interrupt_save_prologue_temp = true;
}
}
/* At the bottom of the frame are any outgoing stack arguments. */
- offset = RISCV_STACK_ALIGN (crtl->outgoing_args_size);
+ offset = riscv_stack_align (crtl->outgoing_args_size);
/* Next are local stack variables. */
- offset += RISCV_STACK_ALIGN (get_frame_size ());
+ offset += riscv_stack_align (get_frame_size ());
/* The virtual frame pointer points above the local variables. */
frame->frame_pointer_offset = offset;
/* Next are the callee-saved FPRs. */
if (frame->fmask)
- offset += RISCV_STACK_ALIGN (num_f_saved * UNITS_PER_FP_REG);
+ offset += riscv_stack_align (num_f_saved * UNITS_PER_FP_REG);
frame->fp_sp_offset = offset - UNITS_PER_FP_REG;
/* Next are the callee-saved GPRs. */
if (frame->mask)
{
- unsigned x_save_size = RISCV_STACK_ALIGN (num_x_saved * UNITS_PER_WORD);
+ unsigned x_save_size = riscv_stack_align (num_x_saved * UNITS_PER_WORD);
unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
/* Only use save/restore routines if they don't alter the stack size. */
- if (RISCV_STACK_ALIGN (num_save_restore * UNITS_PER_WORD) == x_save_size)
+ if (riscv_stack_align (num_save_restore * UNITS_PER_WORD) == x_save_size)
{
/* Libcall saves/restores 3 registers at once, so we need to
allocate 12 bytes for callee-saved register. */
/* The hard frame pointer points above the callee-saved GPRs. */
frame->hard_frame_pointer_offset = offset;
/* Above the hard frame pointer is the callee-allocated varags save area. */
- offset += RISCV_STACK_ALIGN (cfun->machine->varargs_size);
+ offset += riscv_stack_align (cfun->machine->varargs_size);
/* Next is the callee-allocated area for pretend stack arguments. */
- offset += RISCV_STACK_ALIGN (crtl->args.pretend_args_size);
+ offset += riscv_stack_align (crtl->args.pretend_args_size);
/* Arg pointer must be below pretend args, but must be above alignment
padding. */
frame->arg_pointer_offset = offset - crtl->args.pretend_args_size;
/* Next points the incoming stack pointer and any incoming arguments. */
/* Only use save/restore routines when the GPRs are atop the frame. */
- if (frame->hard_frame_pointer_offset != frame->total_size)
+ if (known_ne (frame->hard_frame_pointer_offset, frame->total_size))
frame->save_libcall_adjustment = 0;
}
or argument pointer. TO is either the stack pointer or hard frame
pointer. */
-HOST_WIDE_INT
+poly_int64
riscv_initial_elimination_offset (int from, int to)
{
- HOST_WIDE_INT src, dest;
+ poly_int64 src, dest;
riscv_compute_frame_info ();
gcc_assert (BITSET_P (cfun->machine->frame.mask, RETURN_ADDR_REGNUM));
slot_address = riscv_add_offset (scratch, stack_pointer_rtx,
- cfun->machine->frame.gp_sp_offset);
+ cfun->machine->frame.gp_sp_offset.to_constant());
riscv_emit_move (gen_frame_mem (GET_MODE (address), slot_address), address);
}
of the frame. */
static void
-riscv_for_each_saved_reg (HOST_WIDE_INT sp_offset, riscv_save_restore_fn fn,
+riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
bool epilogue, bool maybe_eh_return)
{
HOST_WIDE_INT offset;
/* Save the link register and s-registers. */
- offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+ offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ();
for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
{
/* This loop must iterate over the same space as its companion in
riscv_compute_frame_info. */
- offset = cfun->machine->frame.fp_sp_offset - sp_offset;
+ offset = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant ();
for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
{
machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
riscv_save_restore_reg (mode, regno, offset, fn);
- offset -= GET_MODE_SIZE (mode);
+ offset -= GET_MODE_SIZE (mode).to_constant ();
}
}
static HOST_WIDE_INT
riscv_first_stack_step (struct riscv_frame_info *frame)
{
- if (SMALL_OPERAND (frame->total_size))
- return frame->total_size;
+ if (SMALL_OPERAND (frame->total_size.to_constant()))
+ return frame->total_size.to_constant();
HOST_WIDE_INT min_first_step =
- RISCV_STACK_ALIGN (frame->total_size - frame->fp_sp_offset);
+ RISCV_STACK_ALIGN ((frame->total_size - frame->fp_sp_offset).to_constant());
HOST_WIDE_INT max_first_step = IMM_REACH / 2 - PREFERRED_STACK_BOUNDARY / 8;
- HOST_WIDE_INT min_second_step = frame->total_size - max_first_step;
+ HOST_WIDE_INT min_second_step = frame->total_size.to_constant() - max_first_step;
gcc_assert (min_first_step <= max_first_step);
/* As an optimization, use the least-significant bits of the total frame
size, so that the second adjustment step is just LUI + ADD. */
if (!SMALL_OPERAND (min_second_step)
- && frame->total_size % IMM_REACH < IMM_REACH / 2
- && frame->total_size % IMM_REACH >= min_first_step)
- return frame->total_size % IMM_REACH;
+ && frame->total_size.to_constant() % IMM_REACH < IMM_REACH / 2
+ && frame->total_size.to_constant() % IMM_REACH >= min_first_step)
+ return frame->total_size.to_constant() % IMM_REACH;
if (TARGET_RVC)
{
riscv_expand_prologue (void)
{
struct riscv_frame_info *frame = &cfun->machine->frame;
- HOST_WIDE_INT size = frame->total_size;
+ HOST_WIDE_INT size = frame->total_size.to_constant ();
unsigned mask = frame->mask;
rtx insn;
if (frame_pointer_needed)
{
insn = gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx,
- GEN_INT (frame->hard_frame_pointer_offset - size));
+ GEN_INT ((frame->hard_frame_pointer_offset - size).to_constant ()));
RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
riscv_emit_stack_tie ();
Start off by assuming that no registers need to be restored. */
struct riscv_frame_info *frame = &cfun->machine->frame;
unsigned mask = frame->mask;
- HOST_WIDE_INT step1 = frame->total_size;
+ HOST_WIDE_INT step1 = frame->total_size.to_constant ();
HOST_WIDE_INT step2 = 0;
bool use_restore_libcall = ((style == NORMAL_RETURN)
&& riscv_use_save_libcall (frame));
rtx insn;
/* We need to add memory barrier to prevent read from deallocated stack. */
- bool need_barrier_p = (get_frame_size ()
- + cfun->machine->frame.arg_pointer_offset) != 0;
+ bool need_barrier_p
+ = known_ne (get_frame_size (), cfun->machine->frame.arg_pointer_offset);
if (cfun->machine->naked_p)
{
riscv_emit_stack_tie ();
need_barrier_p = false;
- rtx adjust = GEN_INT (-frame->hard_frame_pointer_offset);
+ rtx adjust = GEN_INT (-frame->hard_frame_pointer_offset.to_constant ());
if (!SMALL_OPERAND (INTVAL (adjust)))
{
riscv_emit_move (RISCV_PROLOGUE_TEMP (Pmode), adjust);
rtx dwarf = NULL_RTX;
rtx cfa_adjust_value = gen_rtx_PLUS (
Pmode, hard_frame_pointer_rtx,
- GEN_INT (-frame->hard_frame_pointer_offset));
+ GEN_INT (-frame->hard_frame_pointer_offset.to_constant ()));
rtx cfa_adjust_rtx = gen_rtx_SET (stack_pointer_rtx, cfa_adjust_value);
dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, cfa_adjust_rtx, dwarf);
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Set TARGET to BASE + STEP1. */
- if (step1 > 0)
+ if (known_gt (step1, 0))
{
/* Emit a barrier to prevent loads from a deallocated stack. */
riscv_emit_stack_tie ();
bool
riscv_can_use_return_insn (void)
{
- return (reload_completed && cfun->machine->frame.total_size == 0
+ return (reload_completed && known_eq (cfun->machine->frame.total_size, 0)
&& ! cfun->machine->interrupt_handler_p);
}
riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1,
reg_class_t class2)
{
- return (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+ return (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
&& (class1 == FP_REGS) != (class2 == FP_REGS));
}
riscv_hard_regno_nregs (unsigned int regno, machine_mode mode)
{
if (FP_REG_P (regno))
- return (GET_MODE_SIZE (mode) + UNITS_PER_FP_REG - 1) / UNITS_PER_FP_REG;
+ return (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_FP_REG - 1) / UNITS_PER_FP_REG;
/* All other registers are word-sized. */
- return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ return (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}
/* Implement TARGET_HARD_REGNO_MODE_OK. */
return ggc_cleared_alloc<machine_function> ();
}
+/* Return the VLEN value associated with -march.
+ TODO: So far we only support length-agnostic value. */
+static poly_uint16
+riscv_convert_vector_bits (void)
+{
+ /* The runtime invariant is only meaningful when vector is enabled. */
+ if (!TARGET_VECTOR)
+ return 0;
+
+ if (TARGET_VECTOR_ELEN_64 || TARGET_VECTOR_ELEN_FP_64)
+ {
+ /* When targetting Zve64* (ELEN = 64) extensions, we should use 64-bit
+ chunk size. Runtime invariant: The single indeterminate represent the
+ number of 64-bit chunks in a vector beyond minimum length of 64 bits.
+ Thus the number of bytes in a vector is 8 + 8 * x1 which is
+ riscv_vector_chunks * 8 = poly_int (8, 8). */
+ riscv_bytes_per_vector_chunk = 8;
+ }
+ else
+ {
+ /* When targetting Zve32* (ELEN = 32) extensions, we should use 32-bit
+ chunk size. Runtime invariant: The single indeterminate represent the
+ number of 32-bit chunks in a vector beyond minimum length of 32 bits.
+ Thus the number of bytes in a vector is 4 + 4 * x1 which is
+ riscv_vector_chunks * 4 = poly_int (4, 4). */
+ riscv_bytes_per_vector_chunk = 4;
+ }
+
+ return poly_uint16 (1, 1);
+}
+
/* Implement TARGET_OPTION_OVERRIDE. */
static void
riscv_stack_protector_guard_offset = offs;
}
+ /* Convert -march to a chunks count. */
+ riscv_vector_chunks = riscv_convert_vector_bits ();
}
/* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
return promote_mode (type, mode, punsignedp);
unsignedp = *punsignedp;
- PROMOTE_MODE (mode, unsignedp, type);
+ PROMOTE_MODE (as_a <scalar_mode> (mode), unsignedp, type);
*punsignedp = unsignedp;
return mode;
}