/* RTL utility routines.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GCC.
"b" is a pointer to a bitmap header.
"B" is a basic block pointer.
"t" is a tree pointer.
- "r" a register. */
+ "r" a register.
+ "p" is a poly_uint16 offset. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT ,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
+/* Whether rtxs with the given code code store data in the hwint field. */
+
+#define RTX_CODE_HWINT_P_1(ENUM) \
+ ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \
+ || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)
+#ifdef GENERATOR_FILE
+#define RTX_CODE_HWINT_P(ENUM) \
+ (RTX_CODE_HWINT_P_1 (ENUM) || (ENUM) == EQ_ATTR_ALT)
+#else
+#define RTX_CODE_HWINT_P RTX_CODE_HWINT_P_1
+#endif
+
/* Indexed by rtx code, gives the size of the rtx in bytes. */
const unsigned char rtx_code_size[NUM_RTX_CODE] = {
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \
- (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \
- || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT) \
+ (RTX_CODE_HWINT_P (ENUM) \
? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \
: (ENUM) == REG \
? RTX_HDR_SIZE + sizeof (reg_info) \
#undef DEF_REG_NOTE
};
-static int rtx_alloc_counts[(int) LAST_AND_UNUSED_RTX_CODE];
-static int rtx_alloc_sizes[(int) LAST_AND_UNUSED_RTX_CODE];
-static int rtvec_alloc_counts;
-static int rtvec_alloc_sizes;
+static size_t rtx_alloc_counts[(int) LAST_AND_UNUSED_RTX_CODE];
+static size_t rtx_alloc_sizes[(int) LAST_AND_UNUSED_RTX_CODE];
+static size_t rtvec_alloc_counts;
+static size_t rtvec_alloc_sizes;
\f
/* Allocate an rtx vector of N elements.
+ sizeof (struct hwivec_def)
+ ((CONST_WIDE_INT_NUNITS (x) - 1)
* sizeof (HOST_WIDE_INT)));
+ if (CONST_POLY_INT_P (x))
+ return (RTX_HDR_SIZE
+ + sizeof (struct const_poly_int_def)
+ + CONST_POLY_INT_COEFFS (x).extra_size ());
if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
return RTX_HDR_SIZE + sizeof (struct block_symbol);
return RTX_CODE_SIZE (GET_CODE (x));
rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) + extra
PASS_MEM_STAT);
- /* We want to clear everything up to the FLD array. Normally, this
- is one int, but we don't want to assume that and it isn't very
- portable anyway; this is. */
-
- memset (rt, 0, RTX_HDR_SIZE);
- PUT_CODE (rt, code);
+ rtx_init (rt, code);
if (GATHER_STATISTICS)
{
all the rest is initialized to zero. */
rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc (RTX_CODE code MEM_STAT_DECL)
{
return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
}
/* CONST can be shared if it contains a SYMBOL_REF. If it contains
a LABEL_REF, it isn't sharable. */
+ poly_int64 offset;
return (GET_CODE (XEXP (orig, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
- && CONST_INT_P (XEXP (XEXP (orig, 0), 1)));
+ && poly_int_rtx_p (XEXP (XEXP (orig, 0), 1), &offset));
}
us to explicitly document why we are *not* copying a flag. */
copy = shallow_copy_rtx (orig);
- /* We do not copy the USED flag, which is used as a mark bit during
- walks over the RTL. */
- RTX_FLAG (copy, used) = 0;
-
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
case 't':
case 'w':
case 'i':
+ case 'p':
case 's':
case 'S':
case 'T':
/* Create a new copy of an rtx. Only copy just one level. */
rtx
-shallow_copy_rtx_stat (const_rtx orig MEM_STAT_DECL)
+shallow_copy_rtx (const_rtx orig MEM_STAT_DECL)
{
const unsigned int size = rtx_size (orig);
rtx const copy = ggc_alloc_rtx_def_stat (size PASS_MEM_STAT);
- return (rtx) memcpy (copy, orig, size);
+ memcpy (copy, orig, size);
+ switch (GET_CODE (orig))
+ {
+ /* RTX codes copy_rtx_if_shared_1 considers are shareable,
+ the used flag is often used for other purposes. */
+ case REG:
+ case DEBUG_EXPR:
+ case VALUE:
+ CASE_CONST_ANY:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case RETURN:
+ case SIMPLE_RETURN:
+ case SCRATCH:
+ break;
+ default:
+ /* For all other RTXes clear the used flag on the copy. */
+ RTX_FLAG (copy, used) = 0;
+ break;
+ }
+ return copy;
}
\f
/* Nonzero when we are generating CONCATs. */
return (REGNO (x) == REGNO (y));
case LABEL_REF:
- return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
+ return label_ref_label (x) == label_ref_label (y);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
case DEBUG_PARAMETER_REF:
return DEBUG_PARAMETER_REF_DECL (x)
- == DEBUG_PARAMETER_REF_DECL (x);
+ == DEBUG_PARAMETER_REF_DECL (y);
case ENTRY_VALUE:
return rtx_equal_p_cb (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y), cb);
}
break;
+ case 'p':
+ if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
+ return 0;
+ break;
+
case 'V':
case 'E':
/* Two vectors must have the same length. */
return (REGNO (x) == REGNO (y));
case LABEL_REF:
- return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
+ return label_ref_label (x) == label_ref_label (y);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
}
break;
+ case 'p':
+ if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
+ return 0;
+ break;
+
case 'V':
case 'E':
/* Two vectors must have the same length. */
return 1;
}
+/* Return true if all elements of VEC are equal. */
+
+bool
+rtvec_all_equal_p (const_rtvec vec)
+{
+ const_rtx first = RTVEC_ELT (vec, 0);
+ /* Optimize the important special case of a vector of constants.
+ The main use of this function is to detect whether every element
+ of CONST_VECTOR is the same. */
+ switch (GET_CODE (first))
+ {
+ CASE_CONST_UNIQUE:
+ for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i)
+ if (first != RTVEC_ELT (vec, i))
+ return false;
+ return true;
+
+ default:
+ for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i)
+ if (!rtx_equal_p (first, RTVEC_ELT (vec, i)))
+ return false;
+ return true;
+ }
+}
+
/* Return an indication of which type of insn should have X as a body.
In generator files, this can be UNKNOWN if the answer is only known
at (GCC) runtime. Otherwise the value is CODE_LABEL, INSN, CALL_INSN
return CALL_INSN;
if (ANY_RETURN_P (x))
return JUMP_INSN;
+ if (GET_CODE (x) == ASM_OPERANDS && ASM_OPERANDS_LABEL_VEC (x))
+ return JUMP_INSN;
if (GET_CODE (x) == SET)
{
if (GET_CODE (SET_DEST (x)) == PC)
if (GET_CODE (x) == PARALLEL)
{
int j;
+ bool has_return_p = false;
for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (x, 0, j)) == CALL)
return CALL_INSN;
+ else if (ANY_RETURN_P (XVECEXP (x, 0, j)))
+ has_return_p = true;
else if (GET_CODE (XVECEXP (x, 0, j)) == SET
&& GET_CODE (SET_DEST (XVECEXP (x, 0, j))) == PC)
return JUMP_INSN;
else if (GET_CODE (XVECEXP (x, 0, j)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL)
return CALL_INSN;
+ if (has_return_p)
+ return JUMP_INSN;
+ if (GET_CODE (XVECEXP (x, 0, 0)) == ASM_OPERANDS
+ && ASM_OPERANDS_LABEL_VEC (XVECEXP (x, 0, 0)))
+ return JUMP_INSN;
}
#ifdef GENERATOR_FILE
if (GET_CODE (x) == MATCH_OPERAND
return INSN;
}
+/* Comparator of indices based on rtx_alloc_counts. */
+
+static int
+rtx_count_cmp (const void *p1, const void *p2)
+{
+ const unsigned *n1 = (const unsigned *)p1;
+ const unsigned *n2 = (const unsigned *)p2;
+
+ return rtx_alloc_counts[*n1] - rtx_alloc_counts[*n2];
+}
+
void
dump_rtx_statistics (void)
{
- int i;
int total_counts = 0;
int total_sizes = 0;
return;
}
- fprintf (stderr, "\nRTX Kind Count Bytes\n");
- fprintf (stderr, "---------------------------------------\n");
- for (i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++)
- if (rtx_alloc_counts[i])
- {
- fprintf (stderr, "%-20s %7d %10d\n", GET_RTX_NAME (i),
- rtx_alloc_counts[i], rtx_alloc_sizes[i]);
- total_counts += rtx_alloc_counts[i];
- total_sizes += rtx_alloc_sizes[i];
- }
+ fprintf (stderr, "\nRTX Kind Count Bytes\n");
+ fprintf (stderr, "-------------------------------------------\n");
+
+ auto_vec<unsigned> indices (LAST_AND_UNUSED_RTX_CODE);
+ for (unsigned i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++)
+ indices.quick_push (i);
+ indices.qsort (rtx_count_cmp);
+
+ for (unsigned i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++)
+ {
+ unsigned j = indices[i];
+ if (rtx_alloc_counts[j])
+ {
+ fprintf (stderr, "%-24s " PRsa (6) " " PRsa (9) "\n",
+ GET_RTX_NAME (j),
+ SIZE_AMOUNT (rtx_alloc_counts[j]),
+ SIZE_AMOUNT (rtx_alloc_sizes[j]));
+ total_counts += rtx_alloc_counts[j];
+ total_sizes += rtx_alloc_sizes[j];
+ }
+ }
+
if (rtvec_alloc_counts)
{
- fprintf (stderr, "%-20s %7d %10d\n", "rtvec",
- rtvec_alloc_counts, rtvec_alloc_sizes);
+ fprintf (stderr, "%-24s " PRsa (6) " " PRsa (9) "\n", "rtvec",
+ SIZE_AMOUNT (rtvec_alloc_counts),
+ SIZE_AMOUNT (rtvec_alloc_sizes));
total_counts += rtvec_alloc_counts;
total_sizes += rtvec_alloc_sizes;
}
- fprintf (stderr, "---------------------------------------\n");
- fprintf (stderr, "%-20s %7d %10d\n",
- "Total", total_counts, total_sizes);
- fprintf (stderr, "---------------------------------------\n");
+ fprintf (stderr, "-----------------------------------------------\n");
+ fprintf (stderr, "%-24s " PRsa (6) " " PRsa (9) "\n",
+ "Total", SIZE_AMOUNT (total_counts),
+ SIZE_AMOUNT (total_sizes));
+ fprintf (stderr, "-----------------------------------------------\n");
}
\f
#if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
func, trim_filename (file), line);
}
+void
+rtl_check_failed_code3 (const_rtx r, enum rtx_code code1, enum rtx_code code2,
+ enum rtx_code code3, const char *file, int line,
+ const char *func)
+{
+ internal_error
+ ("RTL check: expected code '%s', '%s' or '%s', have '%s' in %s, at %s:%d",
+ GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (code3),
+ GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
+}
+
void
rtl_check_failed_code_mode (const_rtx r, enum rtx_code code, machine_mode mode,
bool not_mode, const char *file, int line,