X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Femit-rtl.c;h=01a224f3b32b341fcfa71ed139d1aa8c8e9b1592;hb=e60a6f7b6c12183ca32dfe2876f09f4b4f4f69c1;hp=717bb4bfdcad6639081a2e3666b9788546ca2885;hpb=011e6b51aaaaa628b204812a1714ada9e8092c87;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 717bb4bfdca..e452c28c2a5 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1,12 +1,13 @@ /* Emit RTL for the GCC expander. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. 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 2, or (at your option) any later +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 @@ -15,9 +16,8 @@ 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 COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* Middle-to-low level generation of rtx code and insns. @@ -50,11 +50,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "insn-config.h" #include "recog.h" #include "real.h" +#include "fixed-value.h" #include "bitmap.h" #include "basic-block.h" #include "ggc.h" #include "debug.h" #include "langhooks.h" +#include "tree-pass.h" +#include "df.h" /* Commonly used modes. */ @@ -63,22 +66,21 @@ enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */ enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */ enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ +/* Datastructures maintained for currently processed function in RTL form. */ -/* This is *not* reset after each function. It gives each CODE_LABEL - in the entire compilation a unique label number. */ - -static GTY(()) int label_num = 1; +struct rtl_data x_rtl; -/* Highest label number in current function. - Zero means use the value of label_num instead. - This is nonzero only when belatedly compiling an inline function. */ +/* Indexed by pseudo register number, gives the rtx for that pseudo. + Allocated in parallel with regno_pointer_align. + FIXME: We could put it into emit_status struct, but gengtype is not able to deal + with length attribute nested in top level structures. */ -static int last_label_num; +rtx * regno_reg_rtx; -/* Value label_num had when set_new_last_label_num was called. - If label_num has not changed since then, last_label_num is valid. */ +/* This is *not* reset after each function. It gives each CODE_LABEL + in the entire compilation a unique label number. */ -static int base_label_num; +static GTY(()) int label_num = 1; /* Nonzero means do not generate NOTEs for source line numbers. */ @@ -108,14 +110,12 @@ rtx const_true_rtx; REAL_VALUE_TYPE dconst0; REAL_VALUE_TYPE dconst1; REAL_VALUE_TYPE dconst2; -REAL_VALUE_TYPE dconst3; -REAL_VALUE_TYPE dconst10; REAL_VALUE_TYPE dconstm1; -REAL_VALUE_TYPE dconstm2; REAL_VALUE_TYPE dconsthalf; -REAL_VALUE_TYPE dconstthird; -REAL_VALUE_TYPE dconstpi; -REAL_VALUE_TYPE dconste; + +/* Record fixed-point constant 0 and 1. */ +FIXED_VALUE_TYPE fconst0[MAX_FCONST0]; +FIXED_VALUE_TYPE fconst1[MAX_FCONST1]; /* All references to the following fixed hard registers go through these unique rtl objects. On machines where the frame-pointer and @@ -168,34 +168,37 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct reg_attrs))) static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) htab_t const_double_htab; -#define first_insn (cfun->emit->x_first_insn) -#define last_insn (cfun->emit->x_last_insn) -#define cur_insn_uid (cfun->emit->x_cur_insn_uid) -#define last_location (cfun->emit->x_last_location) -#define first_label_num (cfun->emit->x_first_label_num) +/* A hash table storing all CONST_FIXEDs. */ +static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) + htab_t const_fixed_htab; + +#define first_insn (crtl->emit.x_first_insn) +#define last_insn (crtl->emit.x_last_insn) +#define cur_insn_uid (crtl->emit.x_cur_insn_uid) +#define last_location (crtl->emit.x_last_location) +#define first_label_num (crtl->emit.x_first_label_num) -static rtx make_jump_insn_raw (rtx); static rtx make_call_insn_raw (rtx); -static rtx find_line_note (rtx); static rtx change_address_1 (rtx, enum machine_mode, rtx, int); -static void unshare_all_decls (tree); -static void reset_used_decls (tree); +static void set_used_decls (tree); static void mark_label_nuses (rtx); static hashval_t const_int_htab_hash (const void *); static int const_int_htab_eq (const void *, const void *); static hashval_t const_double_htab_hash (const void *); static int const_double_htab_eq (const void *, const void *); static rtx lookup_const_double (rtx); +static hashval_t const_fixed_htab_hash (const void *); +static int const_fixed_htab_eq (const void *, const void *); +static rtx lookup_const_fixed (rtx); static hashval_t mem_attrs_htab_hash (const void *); static int mem_attrs_htab_eq (const void *, const void *); -static mem_attrs *get_mem_attrs (HOST_WIDE_INT, tree, rtx, rtx, unsigned int, +static mem_attrs *get_mem_attrs (alias_set_type, tree, rtx, rtx, unsigned int, enum machine_mode); static hashval_t reg_attrs_htab_hash (const void *); static int reg_attrs_htab_eq (const void *, const void *); static reg_attrs *get_reg_attrs (tree, int); static tree component_ref_for_mem_expr (tree); -static rtx gen_const_vector_0 (enum machine_mode); -static rtx gen_complex_constant_part (enum machine_mode, rtx, int); +static rtx gen_const_vector (enum machine_mode, int); static void copy_rtx_if_shared_1 (rtx *orig); /* Probability of the conditional branch currently proceeded by try_split. @@ -207,7 +210,7 @@ int split_branch_probability = -1; static hashval_t const_int_htab_hash (const void *x) { - return (hashval_t) INTVAL ((rtx) x); + return (hashval_t) INTVAL ((const_rtx) x); } /* Returns nonzero if the value represented by X (which is really a @@ -217,14 +220,14 @@ const_int_htab_hash (const void *x) static int const_int_htab_eq (const void *x, const void *y) { - return (INTVAL ((rtx) x) == *((const HOST_WIDE_INT *) y)); + return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y)); } /* Returns a hash code for X (which is really a CONST_DOUBLE). */ static hashval_t const_double_htab_hash (const void *x) { - rtx value = (rtx) x; + const_rtx const value = (const_rtx) x; hashval_t h; if (GET_MODE (value) == VOIDmode) @@ -243,7 +246,7 @@ const_double_htab_hash (const void *x) static int const_double_htab_eq (const void *x, const void *y) { - rtx a = (rtx)x, b = (rtx)y; + const_rtx const a = (const_rtx)x, b = (const_rtx)y; if (GET_MODE (a) != GET_MODE (b)) return 0; @@ -255,17 +258,44 @@ const_double_htab_eq (const void *x, const void *y) CONST_DOUBLE_REAL_VALUE (b)); } +/* Returns a hash code for X (which is really a CONST_FIXED). */ + +static hashval_t +const_fixed_htab_hash (const void *x) +{ + const_rtx const value = (const_rtx) x; + hashval_t h; + + h = fixed_hash (CONST_FIXED_VALUE (value)); + /* MODE is used in the comparison, so it should be in the hash. */ + h ^= GET_MODE (value); + return h; +} + +/* Returns nonzero if the value represented by X (really a ...) + is the same as that represented by Y (really a ...). */ + +static int +const_fixed_htab_eq (const void *x, const void *y) +{ + const_rtx const a = (const_rtx) x, b = (const_rtx) y; + + if (GET_MODE (a) != GET_MODE (b)) + return 0; + return fixed_identical (CONST_FIXED_VALUE (a), CONST_FIXED_VALUE (b)); +} + /* Returns a hash code for X (which is a really a mem_attrs *). */ static hashval_t mem_attrs_htab_hash (const void *x) { - mem_attrs *p = (mem_attrs *) x; + const mem_attrs *const p = (const mem_attrs *) x; return (p->alias ^ (p->align * 1000) ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) - ^ (size_t) p->expr); + ^ (size_t) iterative_hash_expr (p->expr, 0)); } /* Returns nonzero if the value represented by X (which is really a @@ -275,11 +305,14 @@ mem_attrs_htab_hash (const void *x) static int mem_attrs_htab_eq (const void *x, const void *y) { - mem_attrs *p = (mem_attrs *) x; - mem_attrs *q = (mem_attrs *) y; + const mem_attrs *const p = (const mem_attrs *) x; + const mem_attrs *const q = (const mem_attrs *) y; - return (p->alias == q->alias && p->expr == q->expr && p->offset == q->offset - && p->size == q->size && p->align == q->align); + return (p->alias == q->alias && p->offset == q->offset + && p->size == q->size && p->align == q->align + && (p->expr == q->expr + || (p->expr != NULL_TREE && q->expr != NULL_TREE + && operand_equal_p (p->expr, q->expr, 0)))); } /* Allocate a new mem_attrs structure and insert it into the hash table if @@ -287,7 +320,7 @@ mem_attrs_htab_eq (const void *x, const void *y) MEM of mode MODE. */ static mem_attrs * -get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size, +get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, unsigned int align, enum machine_mode mode) { mem_attrs attrs; @@ -316,7 +349,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size, memcpy (*slot, &attrs, sizeof (mem_attrs)); } - return *slot; + return (mem_attrs *) *slot; } /* Returns a hash code for X (which is a really a reg_attrs *). */ @@ -324,7 +357,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size, static hashval_t reg_attrs_htab_hash (const void *x) { - reg_attrs *p = (reg_attrs *) x; + const reg_attrs *const p = (const reg_attrs *) x; return ((p->offset * 1000) ^ (long) p->decl); } @@ -336,8 +369,8 @@ reg_attrs_htab_hash (const void *x) static int reg_attrs_htab_eq (const void *x, const void *y) { - reg_attrs *p = (reg_attrs *) x; - reg_attrs *q = (reg_attrs *) y; + const reg_attrs *const p = (const reg_attrs *) x; + const reg_attrs *const q = (const reg_attrs *) y; return (p->decl == q->decl && p->offset == q->offset); } @@ -365,8 +398,23 @@ get_reg_attrs (tree decl, int offset) memcpy (*slot, &attrs, sizeof (reg_attrs)); } - return *slot; + return (reg_attrs *) *slot; +} + + +#if !HAVE_blockage +/* Generate an empty ASM_INPUT, which is used to block attempts to schedule + across this insn. */ + +rtx +gen_blockage (void) +{ + rtx x = gen_rtx_ASM_INPUT (VOIDmode, ""); + MEM_VOLATILE_P (x) = true; + return x; } +#endif + /* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and don't attempt to share with the various global pieces of rtl (such as @@ -437,11 +485,39 @@ const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode) rtx real = rtx_alloc (CONST_DOUBLE); PUT_MODE (real, mode); - memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE)); + real->u.rv = value; return lookup_const_double (real); } +/* Determine whether FIXED, a CONST_FIXED, already exists in the + hash table. If so, return its counterpart; otherwise add it + to the hash table and return it. */ + +static rtx +lookup_const_fixed (rtx fixed) +{ + void **slot = htab_find_slot (const_fixed_htab, fixed, INSERT); + if (*slot == 0) + *slot = fixed; + + return (rtx) *slot; +} + +/* Return a CONST_FIXED rtx for a fixed-point value specified by + VALUE in mode MODE. */ + +rtx +const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode) +{ + rtx fixed = rtx_alloc (CONST_FIXED); + PUT_MODE (fixed, mode); + + fixed->u.fv = value; + + return lookup_const_fixed (fixed); +} + /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints: I0 is the low-order word and I1 is the high-order word. Do not use this routine for non-integer modes; convert to @@ -453,64 +529,28 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode) rtx value; unsigned int i; + /* There are the following cases (note that there are no modes with + HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode) < 2 * HOST_BITS_PER_WIDE_INT): + + 1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use + gen_int_mode. + 2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of + the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only + from copies of the sign bit, and sign of i0 and i1 are the same), then + we return a CONST_INT for i0. + 3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */ if (mode != VOIDmode) { - int width; - if (GET_MODE_CLASS (mode) != MODE_INT - && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT - /* We can get a 0 for an error mark. */ - && GET_MODE_CLASS (mode) != MODE_VECTOR_INT - && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) - abort (); - - /* We clear out all bits that don't belong in MODE, unless they and - our sign bit are all one. So we get either a reasonable negative - value or a reasonable unsigned value for this mode. */ - width = GET_MODE_BITSIZE (mode); - if (width < HOST_BITS_PER_WIDE_INT - && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1))) - != ((HOST_WIDE_INT) (-1) << (width - 1)))) - i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0; - else if (width == HOST_BITS_PER_WIDE_INT - && ! (i1 == ~0 && i0 < 0)) - i1 = 0; - else if (width > 2 * HOST_BITS_PER_WIDE_INT) - /* We cannot represent this value as a constant. */ - abort (); - - /* If this would be an entire word for the target, but is not for - the host, then sign-extend on the host so that the number will - look the same way on the host that it would on the target. - - For example, when building a 64 bit alpha hosted 32 bit sparc - targeted compiler, then we want the 32 bit unsigned value -1 to be - represented as a 64 bit value -1, and not as 0x00000000ffffffff. - The latter confuses the sparc backend. */ - - if (width < HOST_BITS_PER_WIDE_INT - && (i0 & ((HOST_WIDE_INT) 1 << (width - 1)))) - i0 |= ((HOST_WIDE_INT) (-1) << width); - - /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a - CONST_INT. - - ??? Strictly speaking, this is wrong if we create a CONST_INT for - a large unsigned constant with the size of MODE being - HOST_BITS_PER_WIDE_INT and later try to interpret that constant - in a wider mode. In that case we will mis-interpret it as a - negative number. - - Unfortunately, the only alternative is to make a CONST_DOUBLE for - any constant in any mode if it is an unsigned constant larger - than the maximum signed integer in an int on the host. However, - doing this will break everyone that always expects to see a - CONST_INT for SImode and smaller. - - We have always been making CONST_INTs in this case, so nothing - new is being broken. */ - - if (width <= HOST_BITS_PER_WIDE_INT) - i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0; + gcc_assert (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT + /* We can get a 0 for an error mark. */ + || GET_MODE_CLASS (mode) == MODE_VECTOR_INT + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT); + + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + return gen_int_mode (i0, mode); + + gcc_assert (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT); } /* If this integer fits in one word, return a CONST_INT. */ @@ -607,22 +647,134 @@ gen_rtx_MEM (enum machine_mode mode, rtx addr) return rt; } +/* Generate a memory referring to non-trapping constant memory. */ + rtx -gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) +gen_const_mem (enum machine_mode mode, rtx addr) { - /* This is the most common failure type. - Catch it early so we can see who does it. */ - if ((offset % GET_MODE_SIZE (mode)) != 0) - abort (); + rtx mem = gen_rtx_MEM (mode, addr); + MEM_READONLY_P (mem) = 1; + MEM_NOTRAP_P (mem) = 1; + return mem; +} - /* This check isn't usable right now because combine will - throw arbitrary crap like a CALL into a SUBREG in - gen_lowpart_for_combine so we must just eat it. */ -#if 0 - /* Check for this too. */ - if (offset >= GET_MODE_SIZE (GET_MODE (reg))) - abort (); +/* Generate a MEM referring to fixed portions of the frame, e.g., register + save areas. */ + +rtx +gen_frame_mem (enum machine_mode mode, rtx addr) +{ + rtx mem = gen_rtx_MEM (mode, addr); + MEM_NOTRAP_P (mem) = 1; + set_mem_alias_set (mem, get_frame_alias_set ()); + return mem; +} + +/* Generate a MEM referring to a temporary use of the stack, not part + of the fixed stack frame. For example, something which is pushed + by a target splitter. */ +rtx +gen_tmp_stack_mem (enum machine_mode mode, rtx addr) +{ + rtx mem = gen_rtx_MEM (mode, addr); + MEM_NOTRAP_P (mem) = 1; + if (!cfun->calls_alloca) + set_mem_alias_set (mem, get_frame_alias_set ()); + return mem; +} + +/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if + this construct would be valid, and false otherwise. */ + +bool +validate_subreg (enum machine_mode omode, enum machine_mode imode, + const_rtx reg, unsigned int offset) +{ + unsigned int isize = GET_MODE_SIZE (imode); + unsigned int osize = GET_MODE_SIZE (omode); + + /* All subregs must be aligned. */ + if (offset % osize != 0) + return false; + + /* The subreg offset cannot be outside the inner object. */ + if (offset >= isize) + return false; + + /* ??? This should not be here. Temporarily continue to allow word_mode + subregs of anything. The most common offender is (subreg:SI (reg:DF)). + Generally, backends are doing something sketchy but it'll take time to + fix them all. */ + if (omode == word_mode) + ; + /* ??? Similarly, e.g. with (subreg:DF (reg:TI)). Though store_bit_field + is the culprit here, and not the backends. */ + else if (osize >= UNITS_PER_WORD && isize >= osize) + ; + /* Allow component subregs of complex and vector. Though given the below + extraction rules, it's not always clear what that means. */ + else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) + && GET_MODE_INNER (imode) == omode) + ; + /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs, + i.e. (subreg:V4SF (reg:SF) 0). This surely isn't the cleanest way to + represent this. It's questionable if this ought to be represented at + all -- why can't this all be hidden in post-reload splitters that make + arbitrarily mode changes to the registers themselves. */ + else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode) + ; + /* Subregs involving floating point modes are not allowed to + change size. Therefore (subreg:DI (reg:DF) 0) is fine, but + (subreg:SI (reg:DF) 0) isn't. */ + else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode)) + { + if (isize != osize) + return false; + } + + /* Paradoxical subregs must have offset zero. */ + if (osize > isize) + return offset == 0; + + /* This is a normal subreg. Verify that the offset is representable. */ + + /* For hard registers, we already have most of these rules collected in + subreg_offset_representable_p. */ + if (reg && REG_P (reg) && HARD_REGISTER_P (reg)) + { + unsigned int regno = REGNO (reg); + +#ifdef CANNOT_CHANGE_MODE_CLASS + if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) + && GET_MODE_INNER (imode) == omode) + ; + else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode)) + return false; #endif + + return subreg_offset_representable_p (regno, imode, offset, omode); + } + + /* For pseudo registers, we want most of the same checks. Namely: + If the register no larger than a word, the subreg must be lowpart. + If the register is larger than a word, the subreg must be the lowpart + of a subword. A subreg does *not* perform arbitrary bit extraction. + Given that we've already checked mode/offset alignment, we only have + to check subword subregs here. */ + if (osize < UNITS_PER_WORD) + { + enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode; + unsigned int low_off = subreg_lowpart_offset (omode, wmode); + if (offset % UNITS_PER_WORD != low_off) + return false; + } + return true; +} + +rtx +gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) +{ + gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset)); return gen_rtx_raw_SUBREG (mode, reg, offset); } @@ -641,35 +793,29 @@ gen_lowpart_SUBREG (enum machine_mode mode, rtx reg) subreg_lowpart_offset (mode, inmode)); } -/* gen_rtvec (n, [rt1, ..., rtn]) -** -** This routine creates an rtvec and stores within it the -** pointers to rtx's which are its arguments. -*/ -/*VARARGS1*/ +/* Create an rtvec and stores within it the RTXen passed in the arguments. */ + rtvec gen_rtvec (int n, ...) { - int i, save_n; - rtx *vector; + int i; + rtvec rt_val; va_list p; va_start (p, n); + /* Don't allocate an empty rtvec... */ if (n == 0) - return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + return NULL_RTVEC; - vector = alloca (n * sizeof (rtx)); + rt_val = rtvec_alloc (n); for (i = 0; i < n; i++) - vector[i] = va_arg (p, rtx); + rt_val->elem[i] = va_arg (p, rtx); - /* The definition of VA_* in K&R C causes `n' to go out of scope. */ - save_n = n; va_end (p); - - return gen_rtvec_v (save_n, vector); + return rt_val; } rtvec @@ -678,10 +824,11 @@ gen_rtvec_v (int n, rtx *argp) int i; rtvec rt_val; + /* Don't allocate an empty rtvec... */ if (n == 0) - return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + return NULL_RTVEC; - rt_val = rtvec_alloc (n); /* Allocate an rtvec... */ + rt_val = rtvec_alloc (n); for (i = 0; i < n; i++) rt_val->elem[i] = *argp++; @@ -689,19 +836,40 @@ gen_rtvec_v (int n, rtx *argp) return rt_val; } +/* Return the number of bytes between the start of an OUTER_MODE + in-memory value and the start of an INNER_MODE in-memory value, + given that the former is a lowpart of the latter. It may be a + paradoxical lowpart, in which case the offset will be negative + on big-endian targets. */ + +int +byte_lowpart_offset (enum machine_mode outer_mode, + enum machine_mode inner_mode) +{ + if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode)) + return subreg_lowpart_offset (outer_mode, inner_mode); + else + return -subreg_lowpart_offset (inner_mode, outer_mode); +} + /* Generate a REG rtx for a new pseudo register of mode MODE. This pseudo is assigned the next sequential register number. */ rtx gen_reg_rtx (enum machine_mode mode) { - struct function *f = cfun; rtx val; + unsigned int align = GET_MODE_ALIGNMENT (mode); - /* Don't let anything called after initial flow analysis create new - registers. */ - if (no_new_pseudos) - abort (); + gcc_assert (can_create_pseudo_p ()); + + /* If a virtual register with bigger mode alignment is generated, + increase stack alignment estimation because it might be spilled + to stack later. */ + if (SUPPORTS_STACK_ALIGNMENT + && crtl->stack_alignment_estimated < align + && !crtl->stack_realign_processed) + crtl->stack_alignment_estimated = align; if (generating_concat_p && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT @@ -723,22 +891,21 @@ gen_reg_rtx (enum machine_mode mode) /* Make sure regno_pointer_align, and regno_reg_rtx are large enough to have an element for this pseudo reg number. */ - if (reg_rtx_no == f->emit->regno_pointer_align_length) + if (reg_rtx_no == crtl->emit.regno_pointer_align_length) { - int old_size = f->emit->regno_pointer_align_length; - char *new; + int old_size = crtl->emit.regno_pointer_align_length; + char *tmp; rtx *new1; - new = ggc_realloc (f->emit->regno_pointer_align, old_size * 2); - memset (new + old_size, 0, old_size); - f->emit->regno_pointer_align = (unsigned char *) new; + tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2); + memset (tmp + old_size, 0, old_size); + crtl->emit.regno_pointer_align = (unsigned char *) tmp; - new1 = ggc_realloc (f->emit->x_regno_reg_rtx, - old_size * 2 * sizeof (rtx)); + new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2); memset (new1 + old_size, 0, old_size * sizeof (rtx)); regno_reg_rtx = new1; - f->emit->regno_pointer_align_length = old_size * 2; + crtl->emit.regno_pointer_align_length = old_size * 2; } val = gen_raw_REG (mode, reg_rtx_no); @@ -746,109 +913,92 @@ gen_reg_rtx (enum machine_mode mode) return val; } -/* Generate a register with same attributes as REG, but offsetted by OFFSET. - Do the big endian correction if needed. */ +/* Update NEW with the same attributes as REG, but with OFFSET added + to the REG_OFFSET. */ + +static void +update_reg_offset (rtx new_rtx, rtx reg, int offset) +{ + REG_ATTRS (new_rtx) = get_reg_attrs (REG_EXPR (reg), + REG_OFFSET (reg) + offset); +} + +/* Generate a register with same attributes as REG, but with OFFSET + added to the REG_OFFSET. */ rtx -gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset) +gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, + int offset) { - rtx new = gen_rtx_REG (mode, regno); - tree decl; - HOST_WIDE_INT var_size; - - /* PR middle-end/14084 - The problem appears when a variable is stored in a larger register - and later it is used in the original mode or some mode in between - or some part of variable is accessed. - - On little endian machines there is no problem because - the REG_OFFSET of the start of the variable is the same when - accessed in any mode (it is 0). - - However, this is not true on big endian machines. - The offset of the start of the variable is different when accessed - in different modes. - When we are taking a part of the REG we have to change the OFFSET - from offset WRT size of mode of REG to offset WRT size of variable. - - If we would not do the big endian correction the resulting REG_OFFSET - would be larger than the size of the DECL. - - Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine: - - REG.mode MODE DECL size old offset new offset description - DI SI 4 4 0 int32 in SImode - DI SI 1 4 0 char in SImode - DI QI 1 7 0 char in QImode - DI QI 4 5 1 1st element in QImode - of char[4] - DI HI 4 6 2 1st element in HImode - of int16[2] - - If the size of DECL is equal or greater than the size of REG - we can't do this correction because the register holds the - whole variable or a part of the variable and thus the REG_OFFSET - is already correct. */ - - decl = REG_EXPR (reg); - if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) - && decl != NULL - && offset > 0 - && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode) - && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0 - && var_size < GET_MODE_SIZE (GET_MODE (reg)))) - { - int offset_le; - - /* Convert machine endian to little endian WRT size of mode of REG. */ - if (WORDS_BIG_ENDIAN) - offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + rtx new_rtx = gen_rtx_REG (mode, regno); - if (BYTES_BIG_ENDIAN) - offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - % UNITS_PER_WORD); - else - offset_le += offset % UNITS_PER_WORD; + update_reg_offset (new_rtx, reg, offset); + return new_rtx; +} - if (offset_le >= var_size) - { - /* MODE is wider than the variable so the new reg will cover - the whole variable so the resulting OFFSET should be 0. */ - offset = 0; - } - else - { - /* Convert little endian to machine endian WRT size of variable. */ - if (WORDS_BIG_ENDIAN) - offset = ((var_size - 1 - offset_le) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD; +/* Generate a new pseudo-register with the same attributes as REG, but + with OFFSET added to the REG_OFFSET. */ - if (BYTES_BIG_ENDIAN) - offset += ((var_size - 1 - offset_le) - % UNITS_PER_WORD); - else - offset += offset_le % UNITS_PER_WORD; - } - } +rtx +gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset) +{ + rtx new_rtx = gen_reg_rtx (mode); - REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg), - REG_OFFSET (reg) + offset); - return new; + update_reg_offset (new_rtx, reg, offset); + return new_rtx; +} + +/* Adjust REG in-place so that it has mode MODE. It is assumed that the + new register is a (possibly paradoxical) lowpart of the old one. */ + +void +adjust_reg_mode (rtx reg, enum machine_mode mode) +{ + update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg))); + PUT_MODE (reg, mode); } -/* Set the decl for MEM to DECL. */ +/* Copy REG's attributes from X, if X has any attributes. If REG and X + have different modes, REG is a (possibly paradoxical) lowpart of X. */ void -set_reg_attrs_from_mem (rtx reg, rtx mem) +set_reg_attrs_from_value (rtx reg, rtx x) +{ + int offset; + + /* Hard registers can be reused for multiple purposes within the same + function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN + on them is wrong. */ + if (HARD_REGISTER_P (reg)) + return; + + offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x)); + if (MEM_P (x)) + { + if (MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT) + REG_ATTRS (reg) + = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset); + if (MEM_POINTER (x)) + mark_reg_pointer (reg, 0); + } + else if (REG_P (x)) + { + if (REG_ATTRS (x)) + update_reg_offset (reg, x, offset); + if (REG_POINTER (x)) + mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x))); + } +} + +/* Generate a REG rtx for a new pseudo register, copying the mode + and attributes from X. */ + +rtx +gen_reg_rtx_and_attrs (rtx x) { - if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT) - REG_ATTRS (reg) - = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem))); + rtx reg = gen_reg_rtx (GET_MODE (x)); + set_reg_attrs_from_value (reg, x); + return reg; } /* Set the register attributes for registers contained in PARM_RTX. @@ -858,7 +1008,7 @@ void set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) { if (REG_P (parm_rtx)) - set_reg_attrs_from_mem (parm_rtx, mem); + set_reg_attrs_from_value (parm_rtx, mem); else if (GET_CODE (parm_rtx) == PARALLEL) { /* Check for a NULL entry in the first slot, used to indicate that the @@ -875,54 +1025,21 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) } } -/* Assign the RTX X to declaration T. */ +/* Set the REG_ATTRS for registers in value X, given that X represents + decl T. */ + void -set_decl_rtl (tree t, rtx x) +set_reg_attrs_for_decl_rtl (tree t, rtx x) { - DECL_CHECK (t)->decl.rtl = x; - - if (!x) - return; - /* For register, we maintain the reverse information too. */ - if (REG_P (x)) - REG_ATTRS (x) = get_reg_attrs (t, 0); - else if (GET_CODE (x) == SUBREG) - REG_ATTRS (SUBREG_REG (x)) - = get_reg_attrs (t, -SUBREG_BYTE (x)); - if (GET_CODE (x) == CONCAT) - { - if (REG_P (XEXP (x, 0))) - REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0); - if (REG_P (XEXP (x, 1))) - REG_ATTRS (XEXP (x, 1)) - = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0)))); - } - if (GET_CODE (x) == PARALLEL) + if (GET_CODE (x) == SUBREG) { - int i; - for (i = 0; i < XVECLEN (x, 0); i++) - { - rtx y = XVECEXP (x, 0, i); - if (REG_P (XEXP (y, 0))) - REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1))); - } + gcc_assert (subreg_lowpart_p (x)); + x = SUBREG_REG (x); } -} - -/* Assign the RTX X to parameter declaration T. */ -void -set_decl_incoming_rtl (tree t, rtx x) -{ - DECL_INCOMING_RTL (t) = x; - - if (!x) - return; - /* For register, we maintain the reverse information too. */ if (REG_P (x)) - REG_ATTRS (x) = get_reg_attrs (t, 0); - else if (GET_CODE (x) == SUBREG) - REG_ATTRS (SUBREG_REG (x)) - = get_reg_attrs (t, -SUBREG_BYTE (x)); + REG_ATTRS (x) + = get_reg_attrs (t, byte_lowpart_offset (GET_MODE (x), + DECL_MODE (t))); if (GET_CODE (x) == CONCAT) { if (REG_P (XEXP (x, 0))) @@ -951,6 +1068,27 @@ set_decl_incoming_rtl (tree t, rtx x) } } +/* Assign the RTX X to declaration T. */ + +void +set_decl_rtl (tree t, rtx x) +{ + DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x; + if (x) + set_reg_attrs_for_decl_rtl (t, x); +} + +/* Assign the RTX X to parameter declaration T. BY_REFERENCE_P is true + if the ABI requires the parameter to be passed by reference. */ + +void +set_decl_incoming_rtl (tree t, rtx x, bool by_reference_p) +{ + DECL_INCOMING_RTL (t) = x; + if (x && !by_reference_p) + set_reg_attrs_for_decl_rtl (t, x); +} + /* Identify REG (which may be a CONCAT) as a user register. */ void @@ -961,10 +1099,11 @@ mark_user_reg (rtx reg) REG_USERVAR_P (XEXP (reg, 0)) = 1; REG_USERVAR_P (XEXP (reg, 1)) = 1; } - else if (REG_P (reg)) - REG_USERVAR_P (reg) = 1; else - abort (); + { + gcc_assert (REG_P (reg)); + REG_USERVAR_P (reg) = 1; + } } /* Identify REG as a probable pointer register and show its alignment @@ -998,8 +1137,6 @@ max_reg_num (void) int max_label_num (void) { - if (last_label_num && label_num == base_label_num) - return last_label_num; return label_num; } @@ -1013,7 +1150,7 @@ get_first_label_num (void) /* If the rtx for label was created during the expansion of a nested function, then first_label_num won't include this label number. - Fix this now so that array indicies work later. */ + Fix this now so that array indices work later. */ void maybe_set_first_label_num (rtx x) @@ -1022,40 +1159,6 @@ maybe_set_first_label_num (rtx x) first_label_num = CODE_LABEL_NUMBER (x); } -/* Return the final regno of X, which is a SUBREG of a hard - register. */ -int -subreg_hard_regno (rtx x, int check_mode) -{ - enum machine_mode mode = GET_MODE (x); - unsigned int byte_offset, base_regno, final_regno; - rtx reg = SUBREG_REG (x); - - /* This is where we attempt to catch illegal subregs - created by the compiler. */ - if (GET_CODE (x) != SUBREG - || !REG_P (reg)) - abort (); - base_regno = REGNO (reg); - if (base_regno >= FIRST_PSEUDO_REGISTER) - abort (); - if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg))) - abort (); -#ifdef ENABLE_CHECKING - if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg), - SUBREG_BYTE (x), mode)) - abort (); -#endif - /* Catch non-congruent offsets too. */ - byte_offset = SUBREG_BYTE (x); - if ((byte_offset % GET_MODE_SIZE (mode)) != 0) - abort (); - - final_regno = subreg_regno (x); - - return final_regno; -} - /* Return a value representing some low-order bits of X, where the number of low-order bits is given by MODE. Note that no conversion is done between floating-point and fixed-point values, rather, the bit @@ -1078,15 +1181,15 @@ gen_lowpart_common (enum machine_mode mode, rtx x) /* Unfortunately, this routine doesn't take a parameter for the mode of X, so we have to make one up. Yuk. */ innermode = GET_MODE (x); - if (GET_CODE (x) == CONST_INT && msize <= HOST_BITS_PER_WIDE_INT) + if (GET_CODE (x) == CONST_INT + && msize * BITS_PER_UNIT <= HOST_BITS_PER_WIDE_INT) innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); else if (innermode == VOIDmode) innermode = mode_for_size (HOST_BITS_PER_WIDE_INT * 2, MODE_INT, 0); xsize = GET_MODE_SIZE (innermode); - if (innermode == VOIDmode || innermode == BLKmode) - abort (); + gcc_assert (innermode != VOIDmode && innermode != BLKmode); if (innermode == mode) return x; @@ -1097,7 +1200,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x) return 0; /* Don't allow generating paradoxical FLOAT_MODE subregs. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT && msize > xsize) + if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize) return 0; offset = subreg_lowpart_offset (mode, innermode); @@ -1130,81 +1233,6 @@ gen_lowpart_common (enum machine_mode mode, rtx x) return 0; } -/* Return the constant real or imaginary part (which has mode MODE) - of a complex value X. The IMAGPART_P argument determines whether - the real or complex component should be returned. This function - returns NULL_RTX if the component isn't a constant. */ - -static rtx -gen_complex_constant_part (enum machine_mode mode, rtx x, int imagpart_p) -{ - tree decl, part; - - if (MEM_P (x) - && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) - { - decl = SYMBOL_REF_DECL (XEXP (x, 0)); - if (decl != NULL_TREE && TREE_CODE (decl) == COMPLEX_CST) - { - part = imagpart_p ? TREE_IMAGPART (decl) : TREE_REALPART (decl); - if (TREE_CODE (part) == REAL_CST - || TREE_CODE (part) == INTEGER_CST) - return expand_expr (part, NULL_RTX, mode, 0); - } - } - return NULL_RTX; -} - -/* Return the real part (which has mode MODE) of a complex value X. - This always comes at the low address in memory. */ - -rtx -gen_realpart (enum machine_mode mode, rtx x) -{ - rtx part; - - /* Handle complex constants. */ - part = gen_complex_constant_part (mode, x, 0); - if (part != NULL_RTX) - return part; - - if (WORDS_BIG_ENDIAN - && GET_MODE_BITSIZE (mode) < BITS_PER_WORD - && REG_P (x) - && REGNO (x) < FIRST_PSEUDO_REGISTER) - internal_error - ("can't access real part of complex value in hard register"); - else if (WORDS_BIG_ENDIAN) - return gen_highpart (mode, x); - else - return gen_lowpart (mode, x); -} - -/* Return the imaginary part (which has mode MODE) of a complex value X. - This always comes at the high address in memory. */ - -rtx -gen_imagpart (enum machine_mode mode, rtx x) -{ - rtx part; - - /* Handle complex constants. */ - part = gen_complex_constant_part (mode, x, 1); - if (part != NULL_RTX) - return part; - - if (WORDS_BIG_ENDIAN) - return gen_lowpart (mode, x); - else if (! WORDS_BIG_ENDIAN - && GET_MODE_BITSIZE (mode) < BITS_PER_WORD - && REG_P (x) - && REGNO (x) < FIRST_PSEUDO_REGISTER) - internal_error - ("can't access imaginary part of complex value in hard register"); - else - return gen_highpart (mode, x); -} - rtx gen_highpart (enum machine_mode mode, rtx x) { @@ -1213,21 +1241,22 @@ gen_highpart (enum machine_mode mode, rtx x) /* This case loses if X is a subreg. To catch bugs early, complain if an invalid MODE is used even in other cases. */ - if (msize > UNITS_PER_WORD - && msize != (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x))) - abort (); + gcc_assert (msize <= UNITS_PER_WORD + || msize == (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x))); result = simplify_gen_subreg (mode, x, GET_MODE (x), subreg_highpart_offset (mode, GET_MODE (x))); - + gcc_assert (result); + /* simplify_gen_subreg is not guaranteed to return a valid operand for the target if we have a MEM. gen_highpart must return a valid operand, emitting code if necessary to do so. */ - if (result != NULL_RTX && MEM_P (result)) - result = validize_mem (result); - - if (!result) - abort (); + if (MEM_P (result)) + { + result = validize_mem (result); + gcc_assert (result); + } + return result; } @@ -1238,16 +1267,14 @@ gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx { if (GET_MODE (exp) != VOIDmode) { - if (GET_MODE (exp) != innermode) - abort (); + gcc_assert (GET_MODE (exp) == innermode); return gen_highpart (outermode, exp); } return simplify_gen_subreg (outermode, exp, innermode, subreg_highpart_offset (outermode, innermode)); } -/* Return offset in bytes to get OUTERMODE low part - of the value in mode INNERMODE stored in memory in target format. */ +/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */ unsigned int subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode) @@ -1274,8 +1301,7 @@ subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode unsigned int offset = 0; int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); - if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) - abort (); + gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode)); if (difference > 0) { @@ -1293,7 +1319,7 @@ subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode If X is not a SUBREG, always return 1 (it is its own low part!). */ int -subreg_lowpart_p (rtx x) +subreg_lowpart_p (const_rtx x) { if (GET_CODE (x) != SUBREG) return 1; @@ -1335,8 +1361,7 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine if (mode == VOIDmode) mode = GET_MODE (op); - if (mode == VOIDmode) - abort (); + gcc_assert (mode != VOIDmode); /* If OP is narrower than a word, fail. */ if (mode != BLKmode @@ -1351,27 +1376,28 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine /* Form a new MEM at the requested address. */ if (MEM_P (op)) { - rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD); + rtx new_rtx = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD); if (! validate_address) - return new; + return new_rtx; else if (reload_completed) { - if (! strict_memory_address_p (word_mode, XEXP (new, 0))) + if (! strict_memory_address_p (word_mode, XEXP (new_rtx, 0))) return 0; } else - return replace_equiv_address (new, XEXP (new, 0)); + return replace_equiv_address (new_rtx, XEXP (new_rtx, 0)); } /* Rest can be handled by simplify_subreg. */ return simplify_gen_subreg (word_mode, op, mode, (offset * UNITS_PER_WORD)); } -/* Similar to `operand_subword', but never return 0. If we can't extract - the required subword, put OP into a register and try again. If that fails, - abort. We always validate the address in this case. +/* Similar to `operand_subword', but never return 0. If we can't + extract the required subword, put OP into a register and try again. + The second attempt must succeed. We always validate the address in + this case. MODE is the mode of OP, in case it is CONST_INT. */ @@ -1394,44 +1420,11 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode) } result = operand_subword (op, offset, 1, mode); - if (result == 0) - abort (); + gcc_assert (result); return result; } -/* Given a compare instruction, swap the operands. - A test instruction is changed into a compare of 0 against the operand. */ - -void -reverse_comparison (rtx insn) -{ - rtx body = PATTERN (insn); - rtx comp; - - if (GET_CODE (body) == SET) - comp = SET_SRC (body); - else - comp = SET_SRC (XVECEXP (body, 0, 0)); - - if (GET_CODE (comp) == COMPARE) - { - rtx op0 = XEXP (comp, 0); - rtx op1 = XEXP (comp, 1); - XEXP (comp, 0) = op1; - XEXP (comp, 1) = op0; - } - else - { - rtx new = gen_rtx_COMPARE (VOIDmode, - CONST0_RTX (GET_MODE (comp)), comp); - if (GET_CODE (body) == SET) - SET_SRC (body) = new; - else - SET_SRC (XVECEXP (body, 0, 0)) = new; - } -} - /* Within a MEM_EXPR, we care about either (1) a component ref of a decl, or (2) a component ref of something variable. Represent the later with a NULL expression. */ @@ -1447,8 +1440,7 @@ component_ref_for_mem_expr (tree ref) { /* Now remove any conversions: they don't change what the underlying object is. Likewise for SAVE_EXPR. */ - while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR - || TREE_CODE (inner) == NON_LVALUE_EXPR + while (CONVERT_EXPR_P (inner) || TREE_CODE (inner) == VIEW_CONVERT_EXPR || TREE_CODE (inner) == SAVE_EXPR) inner = TREE_OPERAND (inner, 0); @@ -1457,7 +1449,10 @@ component_ref_for_mem_expr (tree ref) inner = NULL_TREE; } - if (inner == TREE_OPERAND (ref, 0)) + if (inner == TREE_OPERAND (ref, 0) + /* Don't leak SSA-names in the third operand. */ + && (!TREE_OPERAND (ref, 2) + || TREE_CODE (TREE_OPERAND (ref, 2)) != SSA_NAME)) return ref; else return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, @@ -1468,7 +1463,7 @@ component_ref_for_mem_expr (tree ref) and 0 otherwise. */ int -mem_expr_equal_p (tree expr1, tree expr2) +mem_expr_equal_p (const_tree expr1, const_tree expr2) { if (expr1 == expr2) return 1; @@ -1486,31 +1481,115 @@ mem_expr_equal_p (tree expr1, tree expr2) && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */ TREE_OPERAND (expr2, 1)); - if (TREE_CODE (expr1) == INDIRECT_REF) + if (INDIRECT_REF_P (expr1)) return mem_expr_equal_p (TREE_OPERAND (expr1, 0), TREE_OPERAND (expr2, 0)); - - /* Decls with different pointers can't be equal. */ - if (DECL_P (expr1)) - return 0; - abort(); /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already + /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already have been resolved here. */ + gcc_assert (DECL_P (expr1)); + + /* Decls with different pointers can't be equal. */ + return 0; } -/* Given REF, a MEM, and T, either the type of X or the expression - corresponding to REF, set the memory attributes. OBJECTP is nonzero - if we are making a new object of this type. BITPOS is nonzero if - there is an offset outstanding on T that will be applied later. */ +/* Return OFFSET if XEXP (MEM, 0) - OFFSET is known to be ALIGN + bits aligned for 0 <= OFFSET < ALIGN / BITS_PER_UNIT, or + -1 if not known. */ -void -set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, - HOST_WIDE_INT bitpos) -{ - HOST_WIDE_INT alias = MEM_ALIAS_SET (ref); - tree expr = MEM_EXPR (ref); - rtx offset = MEM_OFFSET (ref); - rtx size = MEM_SIZE (ref); +int +get_mem_align_offset (rtx mem, unsigned int align) +{ + tree expr; + unsigned HOST_WIDE_INT offset; + + /* This function can't use + if (!MEM_EXPR (mem) || !MEM_OFFSET (mem) + || !CONST_INT_P (MEM_OFFSET (mem)) + || (get_object_alignment (MEM_EXPR (mem), MEM_ALIGN (mem), align) + < align)) + return -1; + else + return (- INTVAL (MEM_OFFSET (mem))) & (align / BITS_PER_UNIT - 1); + for two reasons: + - COMPONENT_REFs in MEM_EXPR can have NULL first operand, + for . get_inner_reference doesn't handle it and + even if it did, the alignment in that case needs to be determined + from DECL_FIELD_CONTEXT's TYPE_ALIGN. + - it would do suboptimal job for COMPONENT_REFs, even if MEM_EXPR + isn't sufficiently aligned, the object it is in might be. */ + gcc_assert (MEM_P (mem)); + expr = MEM_EXPR (mem); + if (expr == NULL_TREE + || MEM_OFFSET (mem) == NULL_RTX + || !CONST_INT_P (MEM_OFFSET (mem))) + return -1; + + offset = INTVAL (MEM_OFFSET (mem)); + if (DECL_P (expr)) + { + if (DECL_ALIGN (expr) < align) + return -1; + } + else if (INDIRECT_REF_P (expr)) + { + if (TYPE_ALIGN (TREE_TYPE (expr)) < (unsigned int) align) + return -1; + } + else if (TREE_CODE (expr) == COMPONENT_REF) + { + while (1) + { + tree inner = TREE_OPERAND (expr, 0); + tree field = TREE_OPERAND (expr, 1); + tree byte_offset = component_ref_field_offset (expr); + tree bit_offset = DECL_FIELD_BIT_OFFSET (field); + + if (!byte_offset + || !host_integerp (byte_offset, 1) + || !host_integerp (bit_offset, 1)) + return -1; + + offset += tree_low_cst (byte_offset, 1); + offset += tree_low_cst (bit_offset, 1) / BITS_PER_UNIT; + + if (inner == NULL_TREE) + { + if (TYPE_ALIGN (DECL_FIELD_CONTEXT (field)) + < (unsigned int) align) + return -1; + break; + } + else if (DECL_P (inner)) + { + if (DECL_ALIGN (inner) < align) + return -1; + break; + } + else if (TREE_CODE (inner) != COMPONENT_REF) + return -1; + expr = inner; + } + } + else + return -1; + + return offset & ((align / BITS_PER_UNIT) - 1); +} + +/* Given REF (a MEM) and T, either the type of X or the expression + corresponding to REF, set the memory attributes. OBJECTP is nonzero + if we are making a new object of this type. BITPOS is nonzero if + there is an offset outstanding on T that will be applied later. */ + +void +set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, + HOST_WIDE_INT bitpos) +{ + alias_set_type alias = MEM_ALIAS_SET (ref); + tree expr = MEM_EXPR (ref); + rtx offset = MEM_OFFSET (ref); + rtx size = MEM_SIZE (ref); unsigned int align = MEM_ALIGN (ref); HOST_WIDE_INT apply_bitpos = 0; tree type; @@ -1529,31 +1608,39 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, wrong answer, as it assumes that DECL_RTL already has the right alias info. Callers should not set DECL_RTL until after the call to set_mem_attributes. */ - if (DECL_P (t) && ref == DECL_RTL_IF_SET (t)) - abort (); + gcc_assert (!DECL_P (t) || ref != DECL_RTL_IF_SET (t)); /* Get the alias set from the expression or type (perhaps using a front-end routine) and use it. */ alias = get_alias_set (t); MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type); - MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); - RTX_UNCHANGING_P (ref) - |= ((lang_hooks.honor_readonly - && (TYPE_READONLY (type) || (t != type && TREE_READONLY (t)))) - || (! TYPE_P (t) && TREE_CONSTANT (t))); + MEM_IN_STRUCT_P (ref) + = AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE; MEM_POINTER (ref) = POINTER_TYPE_P (type); - MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (t); /* If we are making an object of this type, or if this is a DECL, we know that it is a scalar if the type is not an aggregate. */ - if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type)) + if ((objectp || DECL_P (t)) + && ! AGGREGATE_TYPE_P (type) + && TREE_CODE (type) != COMPLEX_TYPE) MEM_SCALAR_P (ref) = 1; /* We can set the alignment from the type if we are making an object, this is an INDIRECT_REF, or if TYPE_ALIGN_OK. */ - if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type)) + if (objectp || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ALIGN_INDIRECT_REF + || TYPE_ALIGN_OK (type)) align = MAX (align, TYPE_ALIGN (type)); + else + if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF) + { + if (integer_zerop (TREE_OPERAND (t, 1))) + /* We don't know anything about the alignment. */ + align = BITS_PER_UNIT; + else + align = tree_low_cst (TREE_OPERAND (t, 1), 1); + } /* If the size is known, we can set that. */ if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1)) @@ -1563,21 +1650,52 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, the expression. */ if (! TYPE_P (t)) { - maybe_set_unchanging (ref, t); + tree base; + bool align_computed = false; + if (TREE_THIS_VOLATILE (t)) MEM_VOLATILE_P (ref) = 1; /* Now remove any conversions: they don't change what the underlying object is. Likewise for SAVE_EXPR. */ - while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR - || TREE_CODE (t) == NON_LVALUE_EXPR + while (CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR || TREE_CODE (t) == SAVE_EXPR) t = TREE_OPERAND (t, 0); - /* If this expression can't be addressed (e.g., it contains a reference - to a non-addressable field), show we don't change its alias set. */ - if (! can_address_p (t)) + /* We may look through structure-like accesses for the purposes of + examining TREE_THIS_NOTRAP, but not array-like accesses. */ + base = t; + while (TREE_CODE (base) == COMPONENT_REF + || TREE_CODE (base) == REALPART_EXPR + || TREE_CODE (base) == IMAGPART_EXPR + || TREE_CODE (base) == BIT_FIELD_REF) + base = TREE_OPERAND (base, 0); + + if (DECL_P (base)) + { + if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS)) + MEM_NOTRAP_P (ref) = !DECL_WEAK (base); + else + MEM_NOTRAP_P (ref) = 1; + } + else + MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (base); + + base = get_base_address (base); + if (base && DECL_P (base) + && TREE_READONLY (base) + && (TREE_STATIC (base) || DECL_EXTERNAL (base))) + { + tree base_type = TREE_TYPE (base); + gcc_assert (!(base_type && TYPE_NEEDS_CONSTRUCTING (base_type)) + || DECL_ARTIFICIAL (base)); + MEM_READONLY_P (ref) = 1; + } + + /* If this expression uses it's parent's alias set, mark it such + that we won't change it. */ + if (component_uses_parent_alias_set (t)) MEM_KEEP_ALIAS_SET_P (ref) = 1; /* If this is a decl, set the attributes of the MEM from it. */ @@ -1590,19 +1708,21 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, && host_integerp (DECL_SIZE_UNIT (t), 1) ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0); align = DECL_ALIGN (t); + align_computed = true; } /* If this is a constant, we know the alignment. */ - else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c') + else if (CONSTANT_CLASS_P (t)) { align = TYPE_ALIGN (type); #ifdef CONSTANT_ALIGNMENT align = CONSTANT_ALIGNMENT (t, align); #endif + align_computed = true; } /* If this is a field reference and not a bit-field, record it. */ - /* ??? There is some information that can be gleened from bit-fields, + /* ??? There is some information that can be gleaned from bit-fields, such as the word offset in the structure that might be modified. But skip it for now. */ else if (TREE_CODE (t) == COMPONENT_REF @@ -1634,12 +1754,13 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, index, then convert to sizetype and multiply by the size of the array element. */ if (! integer_zerop (low_bound)) - index = fold (build2 (MINUS_EXPR, TREE_TYPE (index), - index, low_bound)); + index = fold_build2 (MINUS_EXPR, TREE_TYPE (index), + index, low_bound); off_tree = size_binop (PLUS_EXPR, - size_binop (MULT_EXPR, convert (sizetype, - index), + size_binop (MULT_EXPR, + fold_convert (sizetype, + index), unit_size), off_tree); t2 = TREE_OPERAND (t2, 0); @@ -1657,6 +1778,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, align = DECL_ALIGN (t2); if (aoff && (unsigned HOST_WIDE_INT) aoff < align) align = aoff; + align_computed = true; offset = GEN_INT (ioff); apply_bitpos = bitpos; } @@ -1673,7 +1795,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, the size we got from the type? */ } else if (flag_argument_noalias > 1 - && TREE_CODE (t2) == INDIRECT_REF + && (INDIRECT_REF_P (t2)) && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL) { expr = t2; @@ -1684,12 +1806,19 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* If this is a Fortran indirect argument reference, record the parameter decl. */ else if (flag_argument_noalias > 1 - && TREE_CODE (t) == INDIRECT_REF + && (INDIRECT_REF_P (t)) && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL) { expr = t; offset = NULL; } + + if (!align_computed && !INDIRECT_REF_P (t)) + { + unsigned int obj_align + = get_object_alignment (t, align, BIGGEST_ALIGNMENT); + align = MAX (align, obj_align); + } } /* If we modified OFFSET based on T, then subtract the outstanding @@ -1702,6 +1831,14 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, size = plus_constant (size, apply_bitpos / BITS_PER_UNIT); } + if (TREE_CODE (t) == ALIGN_INDIRECT_REF) + { + /* Force EXPR and OFFSET to NULL, since we don't know exactly what + we're overlapping. */ + offset = NULL; + expr = NULL; + } + /* Now set the attributes we computed above. */ MEM_ATTRS (ref) = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); @@ -1724,26 +1861,14 @@ set_mem_attributes (rtx ref, tree t, int objectp) set_mem_attributes_minus_bitpos (ref, t, objectp, 0); } -/* Set the decl for MEM to DECL. */ - -void -set_mem_attrs_from_reg (rtx mem, rtx reg) -{ - MEM_ATTRS (mem) - = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg), - GEN_INT (REG_OFFSET (reg)), - MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); -} - /* Set the alias set of MEM to SET. */ void -set_mem_alias_set (rtx mem, HOST_WIDE_INT set) +set_mem_alias_set (rtx mem, alias_set_type set) { #ifdef ENABLE_CHECKING /* If the new and old alias sets don't conflict, something is wrong. */ - if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))) - abort (); + gcc_assert (alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))); #endif MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), @@ -1800,10 +1925,9 @@ set_mem_size (rtx mem, rtx size) static rtx change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { - rtx new; + rtx new_rtx; - if (!MEM_P (memref)) - abort (); + gcc_assert (MEM_P (memref)); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) @@ -1815,10 +1939,7 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) if (validate) { if (reload_in_progress || reload_completed) - { - if (! memory_address_p (mode, addr)) - abort (); - } + gcc_assert (memory_address_p (mode, addr)); else addr = memory_address (mode, addr); } @@ -1826,9 +1947,9 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref)) return memref; - new = gen_rtx_MEM (mode, addr); - MEM_COPY_ATTRIBUTES (new, memref); - return new; + new_rtx = gen_rtx_MEM (mode, addr); + MEM_COPY_ATTRIBUTES (new_rtx, memref); + return new_rtx; } /* Like change_address_1 with VALIDATE nonzero, but we are not saying in what @@ -1837,31 +1958,31 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) rtx change_address (rtx memref, enum machine_mode mode, rtx addr) { - rtx new = change_address_1 (memref, mode, addr, 1), size; - enum machine_mode mmode = GET_MODE (new); + rtx new_rtx = change_address_1 (memref, mode, addr, 1), size; + enum machine_mode mmode = GET_MODE (new_rtx); unsigned int align; size = mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)); align = mmode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mmode); /* If there are no changes, just return the original memory reference. */ - if (new == memref) + if (new_rtx == memref) { if (MEM_ATTRS (memref) == 0 || (MEM_EXPR (memref) == NULL && MEM_OFFSET (memref) == NULL && MEM_SIZE (memref) == size && MEM_ALIGN (memref) == align)) - return new; + return new_rtx; - new = gen_rtx_MEM (mmode, XEXP (memref, 0)); - MEM_COPY_ATTRIBUTES (new, memref); + new_rtx = gen_rtx_MEM (mmode, XEXP (memref, 0)); + MEM_COPY_ATTRIBUTES (new_rtx, memref); } - MEM_ATTRS (new) + MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); - return new; + return new_rtx; } /* Return a memory reference like MEMREF, but with its mode changed @@ -1875,10 +1996,11 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, int validate, int adjust) { rtx addr = XEXP (memref, 0); - rtx new; + rtx new_rtx; rtx memoffset = MEM_OFFSET (memref); rtx size = 0; unsigned int memalign = MEM_ALIGN (memref); + int pbits; /* If there are no changes, just return the original memory reference. */ if (mode == GET_MODE (memref) && !offset @@ -1890,6 +2012,16 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, (plus (plus reg reg) const_int) -- so do this always. */ addr = copy_rtx (addr); + /* Convert a possibly large offset to a signed value within the + range of the target address space. */ + pbits = GET_MODE_BITSIZE (Pmode); + if (HOST_BITS_PER_WIDE_INT > pbits) + { + int shift = HOST_BITS_PER_WIDE_INT - pbits; + offset = (((HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) offset << shift)) + >> shift); + } + if (adjust) { /* If MEMREF is a LO_SUM and the offset is within the alignment of the @@ -1904,7 +2036,12 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, addr = plus_constant (addr, offset); } - new = change_address_1 (memref, mode, addr, validate); + new_rtx = change_address_1 (memref, mode, addr, validate); + + /* If the address is a REG, change_address_1 rightfully returns memref, + but this would destroy memref's MEM_ATTRS. */ + if (new_rtx == memref && offset != 0) + new_rtx = copy_rtx (new_rtx); /* Compute the new values of the memory attributes due to this adjustment. We add the offsets and update the alignment. */ @@ -1920,22 +2057,22 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, (unsigned HOST_WIDE_INT) (offset & -offset) * BITS_PER_UNIT); /* We can compute the size in a number of ways. */ - if (GET_MODE (new) != BLKmode) - size = GEN_INT (GET_MODE_SIZE (GET_MODE (new))); + if (GET_MODE (new_rtx) != BLKmode) + size = GEN_INT (GET_MODE_SIZE (GET_MODE (new_rtx))); else if (MEM_SIZE (memref)) size = plus_constant (MEM_SIZE (memref), -offset); - MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), - memoffset, size, memalign, GET_MODE (new)); + MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), + memoffset, size, memalign, GET_MODE (new_rtx)); /* At some point, we should validate that this offset is within the object, if all the appropriate values are known. */ - return new; + return new_rtx; } /* Return a memory reference like MEMREF, but with its mode changed to MODE and its address changed to ADDR, which is assumed to be - MEMREF offseted by OFFSET bytes. If VALIDATE is + MEMREF offset by OFFSET bytes. If VALIDATE is nonzero, the memory address is forced to be valid. */ rtx @@ -1953,9 +2090,9 @@ adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr, rtx offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) { - rtx new, addr = XEXP (memref, 0); + rtx new_rtx, addr = XEXP (memref, 0); - new = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); /* At this point we don't know _why_ the address is invalid. It could have secondary memory references, multiplies or anything. @@ -1964,28 +2101,28 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) being able to recognize the magic around pic_offset_table_rtx. This stuff is fragile, and is yet another example of why it is bad to expose PIC machinery too early. */ - if (! memory_address_p (GET_MODE (memref), new) + if (! memory_address_p (GET_MODE (memref), new_rtx) && GET_CODE (addr) == PLUS && XEXP (addr, 0) == pic_offset_table_rtx) { addr = force_reg (GET_MODE (addr), addr); - new = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); } - update_temp_slot_address (XEXP (memref, 0), new); - new = change_address_1 (memref, VOIDmode, new, 1); + update_temp_slot_address (XEXP (memref, 0), new_rtx); + new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1); /* If there are no changes, just return the original memory reference. */ - if (new == memref) - return new; + if (new_rtx == memref) + return new_rtx; /* Update the alignment to reflect the offset. Reset the offset, which we don't know. */ - MEM_ATTRS (new) + MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0, MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT), - GET_MODE (new)); - return new; + GET_MODE (new_rtx)); + return new_rtx; } /* Return a memory reference like MEMREF, but with its address changed to @@ -2018,14 +2155,14 @@ replace_equiv_address_nv (rtx memref, rtx addr) rtx widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) { - rtx new = adjust_address_1 (memref, mode, offset, 1, 1); - tree expr = MEM_EXPR (new); - rtx memoffset = MEM_OFFSET (new); + rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1); + tree expr = MEM_EXPR (new_rtx); + rtx memoffset = MEM_OFFSET (new_rtx); unsigned int size = GET_MODE_SIZE (mode); /* If there are no changes, just return the original memory reference. */ - if (new == memref) - return new; + if (new_rtx == memref) + return new_rtx; /* If we don't know what offset we were at within the expression, then we can't know if we've overstepped the bounds. */ @@ -2087,10 +2224,70 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) /* The widened memory may alias other stuff, so zap the alias set. */ /* ??? Maybe use get_alias_set on any remaining expression. */ - MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size), - MEM_ALIGN (new), mode); + MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size), + MEM_ALIGN (new_rtx), mode); + + return new_rtx; +} + +/* A fake decl that is used as the MEM_EXPR of spill slots. */ +static GTY(()) tree spill_slot_decl; + +tree +get_spill_slot_decl (bool force_build_p) +{ + tree d = spill_slot_decl; + rtx rd; + + if (d || !force_build_p) + return d; + + d = build_decl (DECL_SOURCE_LOCATION (current_function_decl), + VAR_DECL, get_identifier ("%sfp"), void_type_node); + DECL_ARTIFICIAL (d) = 1; + DECL_IGNORED_P (d) = 1; + TREE_USED (d) = 1; + TREE_THIS_NOTRAP (d) = 1; + spill_slot_decl = d; + + rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx); + MEM_NOTRAP_P (rd) = 1; + MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx, + NULL_RTX, 0, BLKmode); + SET_DECL_RTL (d, rd); + + return d; +} + +/* Given MEM, a result from assign_stack_local, fill in the memory + attributes as appropriate for a register allocator spill slot. + These slots are not aliasable by other memory. We arrange for + them all to use a single MEM_EXPR, so that the aliasing code can + work properly in the case of shared spill slots. */ + +void +set_mem_attrs_for_spill (rtx mem) +{ + alias_set_type alias; + rtx addr, offset; + tree expr; + + expr = get_spill_slot_decl (true); + alias = MEM_ALIAS_SET (DECL_RTL (expr)); + + /* We expect the incoming memory to be of the form: + (mem:MODE (plus (reg sfp) (const_int offset))) + with perhaps the plus missing for offset = 0. */ + addr = XEXP (mem, 0); + offset = const0_rtx; + if (GET_CODE (addr) == PLUS + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + offset = XEXP (addr, 1); - return new; + MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset, + MEM_SIZE (mem), MEM_ALIGN (mem), + GET_MODE (mem)); + MEM_NOTRAP_P (mem) = 1; } /* Return a newly created CODE_LABEL rtx with a unique label number. */ @@ -2122,41 +2319,13 @@ set_new_first_and_last_insn (rtx first, rtx last) cur_insn_uid++; } - -/* Set the last label number found in the current function. - This is used when belatedly compiling an inline function. */ - -void -set_new_last_label_num (int last) -{ - base_label_num = label_num; - last_label_num = last; -} - -/* Restore all variables describing the current status from the structure *P. - This is used after a nested function. */ - -void -restore_emit_status (struct function *p ATTRIBUTE_UNUSED) -{ - last_label_num = 0; -} /* Go through all the RTL insn bodies and copy any invalid shared structure. This routine should only be called once. */ static void -unshare_all_rtl_1 (tree fndecl, rtx insn) +unshare_all_rtl_1 (rtx insn) { - tree decl; - - /* Make sure that virtual parameters are not shared. */ - for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) - SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl))); - - /* Make sure that virtual stack slots are not shared. */ - unshare_all_decls (DECL_INITIAL (fndecl)); - /* Unshare just about everything else. */ unshare_all_rtl_in_chain (insn); @@ -2185,27 +2354,47 @@ unshare_all_rtl_again (rtx insn) { reset_used_flags (PATTERN (p)); reset_used_flags (REG_NOTES (p)); - reset_used_flags (LOG_LINKS (p)); } /* Make sure that virtual stack slots are not shared. */ - reset_used_decls (DECL_INITIAL (cfun->decl)); + set_used_decls (DECL_INITIAL (cfun->decl)); /* Make sure that virtual parameters are not shared. */ for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = TREE_CHAIN (decl)) - reset_used_flags (DECL_RTL (decl)); + set_used_flags (DECL_RTL (decl)); reset_used_flags (stack_slot_list); - unshare_all_rtl_1 (cfun->decl, insn); + unshare_all_rtl_1 (insn); } -void +unsigned int unshare_all_rtl (void) { - unshare_all_rtl_1 (current_function_decl, get_insns ()); + unshare_all_rtl_1 (get_insns ()); + return 0; } +struct rtl_opt_pass pass_unshare_all_rtl = +{ + { + RTL_PASS, + "unshare", /* name */ + NULL, /* gate */ + unshare_all_rtl, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + } +}; + + /* Check that ORIG is not marked when it should not be and mark ORIG as in use, Recursively does the same for subexpressions. */ @@ -2229,6 +2418,7 @@ verify_rtx_sharing (rtx orig, rtx insn) case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -2244,11 +2434,7 @@ verify_rtx_sharing (rtx orig, rtx insn) break; case CONST: - /* CONST can be shared if it contains a SYMBOL_REF. If it contains - a LABEL_REF, it isn't sharable. */ - if (GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + if (shared_const_p (orig)) return; break; @@ -2266,15 +2452,18 @@ verify_rtx_sharing (rtx orig, rtx insn) /* This rtx may not be shared. If it has already been seen, replace it with a copy of itself. */ - +#ifdef ENABLE_CHECKING if (RTX_FLAG (x, used)) { - error ("Invalid rtl sharing found in the insn"); + error ("invalid rtl sharing found in the insn"); debug_rtx (insn); - error ("Shared rtx"); + error ("shared rtx"); debug_rtx (x); - abort (); + internal_error ("internal consistency failure"); } +#endif + gcc_assert (!RTX_FLAG (x, used)); + RTX_FLAG (x, used) = 1; /* Now scan the subexpressions recursively. */ @@ -2297,9 +2486,11 @@ verify_rtx_sharing (rtx orig, rtx insn) for (j = 0; j < len; j++) { - /* We allow sharing of ASM_OPERANDS inside single instruction. */ + /* We allow sharing of ASM_OPERANDS inside single + instruction. */ if (j && GET_CODE (XVECEXP (x, i, j)) == SET - && GET_CODE (SET_SRC (XVECEXP (x, i, j))) == ASM_OPERANDS) + && (GET_CODE (SET_SRC (XVECEXP (x, i, j))) + == ASM_OPERANDS)) verify_rtx_sharing (SET_DEST (XVECEXP (x, i, j)), insn); else verify_rtx_sharing (XVECEXP (x, i, j), insn); @@ -2324,7 +2515,19 @@ verify_rtl_sharing (void) { reset_used_flags (PATTERN (p)); reset_used_flags (REG_NOTES (p)); - reset_used_flags (LOG_LINKS (p)); + if (GET_CODE (PATTERN (p)) == SEQUENCE) + { + int i; + rtx q, sequence = PATTERN (p); + + for (i = 0; i < XVECLEN (sequence, 0); i++) + { + q = XVECEXP (sequence, 0, i); + gcc_assert (INSN_P (q)); + reset_used_flags (PATTERN (q)); + reset_used_flags (REG_NOTES (q)); + } + } } for (p = get_insns (); p; p = NEXT_INSN (p)) @@ -2332,7 +2535,6 @@ verify_rtl_sharing (void) { verify_rtx_sharing (PATTERN (p), p); verify_rtx_sharing (REG_NOTES (p), p); - verify_rtx_sharing (LOG_LINKS (p), p); } } @@ -2347,141 +2549,32 @@ unshare_all_rtl_in_chain (rtx insn) { PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn)); - LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn)); } } -/* Go through all virtual stack slots of a function and copy any - shared structure. */ -static void -unshare_all_decls (tree blk) -{ - tree t; - - /* Copy shared decls. */ - for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t)) - if (DECL_RTL_SET_P (t)) - SET_DECL_RTL (t, copy_rtx_if_shared (DECL_RTL (t))); +/* Go through all virtual stack slots of a function and mark them as + shared. We never replace the DECL_RTLs themselves with a copy, + but expressions mentioned into a DECL_RTL cannot be shared with + expressions in the instruction stream. - /* Now process sub-blocks. */ - for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t)) - unshare_all_decls (t); -} + Note that reload may convert pseudo registers into memories in-place. + Pseudo registers are always shared, but MEMs never are. Thus if we + reset the used flags on MEMs in the instruction stream, we must set + them again on MEMs that appear in DECL_RTLs. */ -/* Go through all virtual stack slots of a function and mark them as - not shared. */ static void -reset_used_decls (tree blk) +set_used_decls (tree blk) { tree t; /* Mark decls. */ for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t)) if (DECL_RTL_SET_P (t)) - reset_used_flags (DECL_RTL (t)); + set_used_flags (DECL_RTL (t)); /* Now process sub-blocks. */ - for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t)) - reset_used_decls (t); -} - -/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is - placed in the result directly, rather than being copied. MAY_SHARE is - either a MEM of an EXPR_LIST of MEMs. */ - -rtx -copy_most_rtx (rtx orig, rtx may_share) -{ - rtx copy; - int i, j; - RTX_CODE code; - const char *format_ptr; - - if (orig == may_share - || (GET_CODE (may_share) == EXPR_LIST - && in_expr_list_p (may_share, orig))) - return orig; - - code = GET_CODE (orig); - - switch (code) - { - case REG: - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - return orig; - default: - break; - } - - copy = rtx_alloc (code); - PUT_MODE (copy, GET_MODE (orig)); - RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct); - RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil); - RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging); - RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related); - RTX_FLAG (copy, return_val) = RTX_FLAG (orig, return_val); - - format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); - - for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) - { - switch (*format_ptr++) - { - case 'e': - XEXP (copy, i) = XEXP (orig, i); - if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share) - XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share); - break; - - case 'u': - XEXP (copy, i) = XEXP (orig, i); - break; - - case 'E': - case 'V': - XVEC (copy, i) = XVEC (orig, i); - if (XVEC (orig, i) != NULL) - { - XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); - for (j = 0; j < XVECLEN (copy, i); j++) - XVECEXP (copy, i, j) - = copy_most_rtx (XVECEXP (orig, i, j), may_share); - } - break; - - case 'w': - XWINT (copy, i) = XWINT (orig, i); - break; - - case 'n': - case 'i': - XINT (copy, i) = XINT (orig, i); - break; - - case 't': - XTREE (copy, i) = XTREE (orig, i); - break; - - case 's': - case 'S': - XSTR (copy, i) = XSTR (orig, i); - break; - - case '0': - X0ANY (copy, i) = X0ANY (orig, i); - break; - - default: - abort (); - } - } - return copy; + for (t = BLOCK_SUBBLOCKS (blk); t; t = BLOCK_CHAIN (t)) + set_used_decls (t); } /* Mark ORIG as in use, and return a copy of it if it was already in use. @@ -2525,6 +2618,7 @@ repeat: case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -2540,11 +2634,7 @@ repeat: break; case CONST: - /* CONST can be shared if it contains a SYMBOL_REF. If it contains - a LABEL_REF, it isn't sharable. */ - if (GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + if (shared_const_p (x)) return; break; @@ -2565,11 +2655,7 @@ repeat: if (RTX_FLAG (x, used)) { - rtx copy; - - copy = rtx_alloc (code); - memcpy (copy, x, RTX_SIZE (code)); - x = copy; + x = shallow_copy_rtx (x); copied = 1; } RTX_FLAG (x, used) = 1; @@ -2650,6 +2736,7 @@ repeat: case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case CODE_LABEL: @@ -2719,6 +2806,7 @@ set_used_flags (rtx x) case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case CODE_LABEL: @@ -2810,8 +2898,7 @@ get_insns (void) void set_first_insn (rtx insn) { - if (PREV_INSN (insn) != 0) - abort (); + gcc_assert (!PREV_INSN (insn)); first_insn = insn; } @@ -2828,8 +2915,7 @@ get_last_insn (void) void set_last_insn (rtx insn) { - if (NEXT_INSN (insn) != 0) - abort (); + gcc_assert (!NEXT_INSN (insn)); last_insn = insn; } @@ -2855,11 +2941,19 @@ get_first_nonnote_insn (void) { rtx insn = first_insn; - while (insn) + if (insn) { - insn = next_insn (insn); - if (insn == 0 || !NOTE_P (insn)) - break; + if (NOTE_P (insn)) + for (insn = next_insn (insn); + insn && NOTE_P (insn); + insn = next_insn (insn)) + continue; + else + { + if (NONJUMP_INSN_P (insn) + && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, 0); + } } return insn; @@ -2873,11 +2967,20 @@ get_last_nonnote_insn (void) { rtx insn = last_insn; - while (insn) + if (insn) { - insn = previous_insn (insn); - if (insn == 0 || !NOTE_P (insn)) - break; + if (NOTE_P (insn)) + for (insn = previous_insn (insn); + insn && NOTE_P (insn); + insn = previous_insn (insn)) + continue; + else + { + if (NONJUMP_INSN_P (insn) + && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, + XVECLEN (PATTERN (insn), 0) - 1); + } } return insn; @@ -2890,33 +2993,6 @@ get_max_uid (void) { return cur_insn_uid; } - -/* Renumber instructions so that no instruction UIDs are wasted. */ - -void -renumber_insns (FILE *stream) -{ - rtx insn; - - /* If we're not supposed to renumber instructions, don't. */ - if (!flag_renumber_insns) - return; - - /* If there aren't that many instructions, then it's not really - worth renumbering them. */ - if (flag_renumber_insns == 1 && get_max_uid () < 25000) - return; - - cur_insn_uid = 1; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (stream) - fprintf (stream, "Renumbering insn %d to %d\n", - INSN_UID (insn), cur_insn_uid); - INSN_UID (insn) = cur_insn_uid++; - } -} /* Return the next insn. If it is a SEQUENCE, return the first insn of the sequence. */ @@ -3039,7 +3115,7 @@ last_call_insn (void) same as next_real_insn. */ int -active_insn_p (rtx insn) +active_insn_p (const_rtx insn) { return (CALL_P (insn) || JUMP_P (insn) || (NONJUMP_INSN_P (insn) @@ -3135,9 +3211,8 @@ link_cc0_insns (rtx insn) if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE) user = XVECEXP (PATTERN (user), 0, 0); - REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, - REG_NOTES (user)); - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn)); + add_reg_note (user, REG_CC_SETTER, insn); + add_reg_note (insn, REG_CC_USER, user); } /* Return the next insn that uses CC0 after INSN, which is assumed to @@ -3179,13 +3254,43 @@ prev_cc0_setter (rtx insn) return XEXP (note, 0); insn = prev_nonnote_insn (insn); - if (! sets_cc0_p (PATTERN (insn))) - abort (); + gcc_assert (sets_cc0_p (PATTERN (insn))); return insn; } #endif +#ifdef AUTO_INC_DEC +/* Find a RTX_AUTOINC class rtx which matches DATA. */ + +static int +find_auto_inc (rtx *xp, void *data) +{ + rtx x = *xp; + rtx reg = (rtx) data; + + if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC) + return 0; + + switch (GET_CODE (x)) + { + case PRE_DEC: + case PRE_INC: + case POST_DEC: + case POST_INC: + case PRE_MODIFY: + case POST_MODIFY: + if (rtx_equal_p (reg, XEXP (x, 0))) + return 1; + break; + + default: + gcc_unreachable (); + } + return -1; +} +#endif + /* Increment the label uses for all labels present in rtx. */ static void @@ -3226,12 +3331,15 @@ try_split (rtx pat, rtx trial, int last) rtx before = PREV_INSN (trial); rtx after = NEXT_INSN (trial); int has_barrier = 0; - rtx tem; - rtx note, seq; + rtx note, seq, tem; int probability; rtx insn_last, insn; int njumps = 0; + /* We're not good at redistributing frame information. */ + if (RTX_FRAME_RELATED_P (trial)) + return trial; + if (any_condjump_p (trial) && (note = find_reg_note (trial, REG_BR_PROB, 0))) split_branch_probability = INTVAL (XEXP (note, 0)); @@ -3265,6 +3373,10 @@ try_split (rtx pat, rtx trial, int last) insn_last = NEXT_INSN (insn_last); } + /* We will be adding the new sequence to the function. The splitters + may have introduced invalid RTL sharing, so unshare the sequence now. */ + unshare_all_rtl_in_chain (seq); + /* Mark labels. */ for (insn = insn_last; insn ; insn = PREV_INSN (insn)) { @@ -3280,12 +3392,8 @@ try_split (rtx pat, rtx trial, int last) one jump is created, otherwise the machine description is responsible for this step using split_branch_probability variable. */ - if (njumps != 1) - abort (); - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_BR_PROB, - GEN_INT (probability), - REG_NOTES (insn)); + gcc_assert (njumps == 1); + add_reg_note (insn, REG_BR_PROB, GEN_INT (probability)); } } } @@ -3311,47 +3419,43 @@ try_split (rtx pat, rtx trial, int last) switch (REG_NOTE_KIND (note)) { case REG_EH_REGION: - insn = insn_last; - while (insn != NULL_RTX) + for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn)) { if (CALL_P (insn) - || (flag_non_call_exceptions + || (flag_non_call_exceptions && INSN_P (insn) && may_trap_p (PATTERN (insn)))) - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_EH_REGION, - XEXP (note, 0), - REG_NOTES (insn)); - insn = PREV_INSN (insn); + add_reg_note (insn, REG_EH_REGION, XEXP (note, 0)); } break; case REG_NORETURN: case REG_SETJMP: - case REG_ALWAYS_RETURN: - insn = insn_last; - while (insn != NULL_RTX) + for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn)) { if (CALL_P (insn)) - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), - XEXP (note, 0), - REG_NOTES (insn)); - insn = PREV_INSN (insn); + add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0)); } break; case REG_NON_LOCAL_GOTO: - insn = insn_last; - while (insn != NULL_RTX) + for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn)) { if (JUMP_P (insn)) - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), - XEXP (note, 0), - REG_NOTES (insn)); - insn = PREV_INSN (insn); + add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0)); + } + break; + +#ifdef AUTO_INC_DEC + case REG_INC: + for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn)) + { + rtx reg = XEXP (note, 0); + if (!FIND_REG_INC_NOTE (insn, reg) + && for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0) + add_reg_note (insn, REG_INC, reg); } break; +#endif default: break; @@ -3360,11 +3464,12 @@ try_split (rtx pat, rtx trial, int last) /* If there are LABELS inside the split insns increment the usage count so we don't delete the label. */ - if (NONJUMP_INSN_P (trial)) + if (INSN_P (trial)) { insn = insn_last; while (insn != NULL_RTX) { + /* JUMP_P insns have already been "marked" above. */ if (NONJUMP_INSN_P (insn)) mark_label_nuses (PATTERN (insn)); @@ -3407,9 +3512,8 @@ make_insn_raw (rtx pattern) INSN_UID (insn) = cur_insn_uid++; PATTERN (insn) = pattern; INSN_CODE (insn) = -1; - LOG_LINKS (insn) = NULL; REG_NOTES (insn) = NULL; - INSN_LOCATOR (insn) = 0; + INSN_LOCATOR (insn) = curr_insn_locator (); BLOCK_FOR_INSN (insn) = NULL; #ifdef ENABLE_RTL_CHECKING @@ -3419,7 +3523,7 @@ make_insn_raw (rtx pattern) || (GET_CODE (insn) == SET && SET_DEST (insn) == pc_rtx))) { - warning ("ICE: emit_insn used where emit_jump_insn needed:\n"); + warning (0, "ICE: emit_insn used where emit_jump_insn needed:\n"); debug_rtx (insn); } #endif @@ -3429,7 +3533,7 @@ make_insn_raw (rtx pattern) /* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */ -static rtx +rtx make_jump_insn_raw (rtx pattern) { rtx insn; @@ -3439,10 +3543,9 @@ make_jump_insn_raw (rtx pattern) PATTERN (insn) = pattern; INSN_CODE (insn) = -1; - LOG_LINKS (insn) = NULL; REG_NOTES (insn) = NULL; JUMP_LABEL (insn) = NULL; - INSN_LOCATOR (insn) = 0; + INSN_LOCATOR (insn) = curr_insn_locator (); BLOCK_FOR_INSN (insn) = NULL; return insn; @@ -3460,10 +3563,9 @@ make_call_insn_raw (rtx pattern) PATTERN (insn) = pattern; INSN_CODE (insn) = -1; - LOG_LINKS (insn) = NULL; REG_NOTES (insn) = NULL; CALL_INSN_FUNCTION_USAGE (insn) = NULL; - INSN_LOCATOR (insn) = 0; + INSN_LOCATOR (insn) = curr_insn_locator (); BLOCK_FOR_INSN (insn) = NULL; return insn; @@ -3493,13 +3595,11 @@ add_insn (rtx insn) SEQUENCE. */ void -add_insn_after (rtx insn, rtx after) +add_insn_after (rtx insn, rtx after, basic_block bb) { rtx next = NEXT_INSN (after); - basic_block bb; - if (optimize && INSN_DELETED_P (after)) - abort (); + gcc_assert (!optimize || !INSN_DELETED_P (after)); NEXT_INSN (insn) = next; PREV_INSN (insn) = after; @@ -3523,8 +3623,7 @@ add_insn_after (rtx insn, rtx after) break; } - if (stack == 0) - abort (); + gcc_assert (stack); } if (!BARRIER_P (after) @@ -3533,14 +3632,13 @@ add_insn_after (rtx insn, rtx after) { set_block_for_insn (insn, bb); if (INSN_P (insn)) - bb->flags |= BB_DIRTY; + df_insn_rescan (insn); /* Should not happen as first in the BB is always either NOTE or LABEL. */ if (BB_END (bb) == after /* Avoid clobbering of structure when creating new BB. */ && !BARRIER_P (insn) - && (!NOTE_P (insn) - || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) + && !NOTE_INSN_BASIC_BLOCK_P (insn)) BB_END (bb) = insn; } @@ -3553,18 +3651,17 @@ add_insn_after (rtx insn, rtx after) } /* Add INSN into the doubly-linked list before insn BEFORE. This and - the previous should be the only functions called to insert an insn once - delay slots have been filled since only they know how to update a - SEQUENCE. */ + the previous should be the only functions called to insert an insn + once delay slots have been filled since only they know how to + update a SEQUENCE. If BB is NULL, an attempt is made to infer the + bb from before. */ void -add_insn_before (rtx insn, rtx before) +add_insn_before (rtx insn, rtx before, basic_block bb) { rtx prev = PREV_INSN (before); - basic_block bb; - if (optimize && INSN_DELETED_P (before)) - abort (); + gcc_assert (!optimize || !INSN_DELETED_P (before)); PREV_INSN (insn) = prev; NEXT_INSN (insn) = before; @@ -3591,25 +3688,25 @@ add_insn_before (rtx insn, rtx before) break; } - if (stack == 0) - abort (); + gcc_assert (stack); } - if (!BARRIER_P (before) - && !BARRIER_P (insn) - && (bb = BLOCK_FOR_INSN (before))) + if (!bb + && !BARRIER_P (before) + && !BARRIER_P (insn)) + bb = BLOCK_FOR_INSN (before); + + if (bb) { set_block_for_insn (insn, bb); if (INSN_P (insn)) - bb->flags |= BB_DIRTY; - /* Should not happen as first in the BB is always - either NOTE or LABEl. */ - if (BB_HEAD (bb) == insn - /* Avoid clobbering of structure when creating new BB. */ - && !BARRIER_P (insn) - && (!NOTE_P (insn) - || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) - abort (); + df_insn_rescan (insn); + /* Should not happen as first in the BB is always either NOTE or + LABEL. */ + gcc_assert (BB_HEAD (bb) != insn + /* Avoid clobbering of structure when creating new BB. */ + || BARRIER_P (insn) + || NOTE_INSN_BASIC_BLOCK_P (insn)); } PREV_INSN (before) = insn; @@ -3617,6 +3714,18 @@ add_insn_before (rtx insn, rtx before) PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn; } + +/* Replace insn with an deleted instruction note. */ + +void +set_insn_deleted (rtx insn) +{ + df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn)); + PUT_CODE (insn, NOTE); + NOTE_KIND (insn) = NOTE_INSN_DELETED; +} + + /* Remove an insn from its doubly-linked list. This function knows how to handle sequences. */ void @@ -3626,6 +3735,9 @@ remove_insn (rtx insn) rtx prev = PREV_INSN (insn); basic_block bb; + /* Later in the code, the block will be marked dirty. */ + df_insn_delete (NULL, INSN_UID (insn)); + if (prev) { NEXT_INSN (prev) = next; @@ -3648,8 +3760,7 @@ remove_insn (rtx insn) break; } - if (stack == 0) - abort (); + gcc_assert (stack); } if (next) @@ -3671,20 +3782,18 @@ remove_insn (rtx insn) break; } - if (stack == 0) - abort (); + gcc_assert (stack); } if (!BARRIER_P (insn) && (bb = BLOCK_FOR_INSN (insn))) { if (INSN_P (insn)) - bb->flags |= BB_DIRTY; + df_set_bb_dirty (bb); if (BB_HEAD (bb) == insn) { /* Never ever delete the basic block note without deleting whole basic block. */ - if (NOTE_P (insn)) - abort (); + gcc_assert (!NOTE_P (insn)); BB_HEAD (bb) = next; } if (BB_END (bb) == insn) @@ -3697,8 +3806,7 @@ remove_insn (rtx insn) void add_function_usage_to (rtx call_insn, rtx call_fusage) { - if (! call_insn || !CALL_P (call_insn)) - abort (); + gcc_assert (call_insn && CALL_P (call_insn)); /* Put the register usage information on the CALL. If there is already some usage information, put ours at the end. */ @@ -3776,14 +3884,14 @@ reorder_insns (rtx from, rtx to, rtx after) && (bb = BLOCK_FOR_INSN (after))) { rtx x; - bb->flags |= BB_DIRTY; + df_set_bb_dirty (bb); if (!BARRIER_P (from) && (bb2 = BLOCK_FOR_INSN (from))) { if (BB_END (bb2) == to) BB_END (bb2) = prev; - bb2->flags |= BB_DIRTY; + df_set_bb_dirty (bb2); } if (BB_END (bb) == after) @@ -3791,137 +3899,10 @@ reorder_insns (rtx from, rtx to, rtx after) for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x)) if (!BARRIER_P (x)) - set_block_for_insn (x, bb); + df_insn_change_bb (x, bb); } } -/* Return the line note insn preceding INSN. */ - -static rtx -find_line_note (rtx insn) -{ - if (no_line_numbers) - return 0; - - for (; insn; insn = PREV_INSN (insn)) - if (NOTE_P (insn) - && NOTE_LINE_NUMBER (insn) >= 0) - break; - - return insn; -} - -/* Remove unnecessary notes from the instruction stream. */ - -void -remove_unnecessary_notes (void) -{ - rtx block_stack = NULL_RTX; - rtx eh_stack = NULL_RTX; - rtx insn; - rtx next; - rtx tmp; - - /* We must not remove the first instruction in the function because - the compiler depends on the first instruction being a note. */ - for (insn = NEXT_INSN (get_insns ()); insn; insn = next) - { - /* Remember what's next. */ - next = NEXT_INSN (insn); - - /* We're only interested in notes. */ - if (!NOTE_P (insn)) - continue; - - switch (NOTE_LINE_NUMBER (insn)) - { - case NOTE_INSN_DELETED: - remove_insn (insn); - break; - - case NOTE_INSN_EH_REGION_BEG: - eh_stack = alloc_INSN_LIST (insn, eh_stack); - break; - - case NOTE_INSN_EH_REGION_END: - /* Too many end notes. */ - if (eh_stack == NULL_RTX) - abort (); - /* Mismatched nesting. */ - if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn)) - abort (); - tmp = eh_stack; - eh_stack = XEXP (eh_stack, 1); - free_INSN_LIST_node (tmp); - break; - - case NOTE_INSN_BLOCK_BEG: - /* By now, all notes indicating lexical blocks should have - NOTE_BLOCK filled in. */ - if (NOTE_BLOCK (insn) == NULL_TREE) - abort (); - block_stack = alloc_INSN_LIST (insn, block_stack); - break; - - case NOTE_INSN_BLOCK_END: - /* Too many end notes. */ - if (block_stack == NULL_RTX) - abort (); - /* Mismatched nesting. */ - if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn)) - abort (); - tmp = block_stack; - block_stack = XEXP (block_stack, 1); - free_INSN_LIST_node (tmp); - - /* Scan back to see if there are any non-note instructions - between INSN and the beginning of this block. If not, - then there is no PC range in the generated code that will - actually be in this block, so there's no point in - remembering the existence of the block. */ - for (tmp = PREV_INSN (insn); tmp; tmp = PREV_INSN (tmp)) - { - /* This block contains a real instruction. Note that we - don't include labels; if the only thing in the block - is a label, then there are still no PC values that - lie within the block. */ - if (INSN_P (tmp)) - break; - - /* We're only interested in NOTEs. */ - if (!NOTE_P (tmp)) - continue; - - if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG) - { - /* We just verified that this BLOCK matches us with - the block_stack check above. Never delete the - BLOCK for the outermost scope of the function; we - can refer to names from that scope even if the - block notes are messed up. */ - if (! is_body_block (NOTE_BLOCK (insn)) - && (*debug_hooks->ignore_block) (NOTE_BLOCK (insn))) - { - remove_insn (tmp); - remove_insn (insn); - } - break; - } - else if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_END) - /* There's a nested block. We need to leave the - current block in place since otherwise the debugger - wouldn't be able to show symbols from our block in - the nested block. */ - break; - } - } - } - - /* Too many begin notes. */ - if (block_stack || eh_stack) - abort (); -} - /* Emit insn(s) of given code and pattern at a specified place within the doubly-linked list. @@ -3951,15 +3932,12 @@ remove_unnecessary_notes (void) /* Make X be output before the instruction BEFORE. */ rtx -emit_insn_before (rtx x, rtx before) +emit_insn_before_noloc (rtx x, rtx before, basic_block bb) { rtx last = before; rtx insn; -#ifdef ENABLE_RTL_CHECKING - if (before == NULL_RTX) - abort (); -#endif + gcc_assert (before); if (x == NULL_RTX) return last; @@ -3976,7 +3954,7 @@ emit_insn_before (rtx x, rtx before) while (insn) { rtx next = NEXT_INSN (insn); - add_insn_before (insn, before); + add_insn_before (insn, before, bb); last = insn; insn = next; } @@ -3984,13 +3962,13 @@ emit_insn_before (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_insn_raw (x); - add_insn_before (last, before); + add_insn_before (last, before, bb); break; } @@ -4001,14 +3979,11 @@ emit_insn_before (rtx x, rtx before) and output it before the instruction BEFORE. */ rtx -emit_jump_insn_before (rtx x, rtx before) +emit_jump_insn_before_noloc (rtx x, rtx before) { rtx insn, last = NULL_RTX; -#ifdef ENABLE_RTL_CHECKING - if (before == NULL_RTX) - abort (); -#endif + gcc_assert (before); switch (GET_CODE (x)) { @@ -4022,7 +3997,7 @@ emit_jump_insn_before (rtx x, rtx before) while (insn) { rtx next = NEXT_INSN (insn); - add_insn_before (insn, before); + add_insn_before (insn, before, NULL); last = insn; insn = next; } @@ -4030,13 +4005,13 @@ emit_jump_insn_before (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_jump_insn_raw (x); - add_insn_before (last, before); + add_insn_before (last, before, NULL); break; } @@ -4047,14 +4022,11 @@ emit_jump_insn_before (rtx x, rtx before) and output it before the instruction BEFORE. */ rtx -emit_call_insn_before (rtx x, rtx before) +emit_call_insn_before_noloc (rtx x, rtx before) { rtx last = NULL_RTX, insn; -#ifdef ENABLE_RTL_CHECKING - if (before == NULL_RTX) - abort (); -#endif + gcc_assert (before); switch (GET_CODE (x)) { @@ -4068,7 +4040,7 @@ emit_call_insn_before (rtx x, rtx before) while (insn) { rtx next = NEXT_INSN (insn); - add_insn_before (insn, before); + add_insn_before (insn, before, NULL); last = insn; insn = next; } @@ -4076,13 +4048,13 @@ emit_call_insn_before (rtx x, rtx before) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_call_insn_raw (x); - add_insn_before (last, before); + add_insn_before (last, before, NULL); break; } @@ -4099,7 +4071,7 @@ emit_barrier_before (rtx before) INSN_UID (insn) = cur_insn_uid++; - add_insn_before (insn, before); + add_insn_before (insn, before, NULL); return insn; } @@ -4113,7 +4085,7 @@ emit_label_before (rtx label, rtx before) if (INSN_UID (label) == 0) { INSN_UID (label) = cur_insn_uid++; - add_insn_before (label, before); + add_insn_before (label, before, NULL); } return label; @@ -4122,41 +4094,43 @@ emit_label_before (rtx label, rtx before) /* Emit a note of subtype SUBTYPE before the insn BEFORE. */ rtx -emit_note_before (int subtype, rtx before) +emit_note_before (enum insn_note subtype, rtx before) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; -#ifndef USE_MAPPED_LOCATION - NOTE_SOURCE_FILE (note) = 0; -#endif - NOTE_LINE_NUMBER (note) = subtype; + NOTE_KIND (note) = subtype; BLOCK_FOR_INSN (note) = NULL; + memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note))); - add_insn_before (note, before); + add_insn_before (note, before, NULL); return note; } /* Helper for emit_insn_after, handles lists of instructions efficiently. */ -static rtx emit_insn_after_1 (rtx, rtx); - static rtx -emit_insn_after_1 (rtx first, rtx after) +emit_insn_after_1 (rtx first, rtx after, basic_block bb) { rtx last; rtx after_after; - basic_block bb; + if (!bb && !BARRIER_P (after)) + bb = BLOCK_FOR_INSN (after); - if (!BARRIER_P (after) - && (bb = BLOCK_FOR_INSN (after))) + if (bb) { - bb->flags |= BB_DIRTY; + df_set_bb_dirty (bb); for (last = first; NEXT_INSN (last); last = NEXT_INSN (last)) if (!BARRIER_P (last)) - set_block_for_insn (last, bb); + { + set_block_for_insn (last, bb); + df_insn_rescan (last); + } if (!BARRIER_P (last)) - set_block_for_insn (last, bb); + { + set_block_for_insn (last, bb); + df_insn_rescan (last); + } if (BB_END (bb) == after) BB_END (bb) = last; } @@ -4174,20 +4148,19 @@ emit_insn_after_1 (rtx first, rtx after) if (after == last_insn) last_insn = last; + return last; } -/* Make X be output after the insn AFTER. */ +/* Make X be output after the insn AFTER and set the BB of insn. If + BB is NULL, an attempt is made to infer the BB from AFTER. */ rtx -emit_insn_after (rtx x, rtx after) +emit_insn_after_noloc (rtx x, rtx after, basic_block bb) { rtx last = after; -#ifdef ENABLE_RTL_CHECKING - if (after == NULL_RTX) - abort (); -#endif + gcc_assert (after); if (x == NULL_RTX) return last; @@ -4200,53 +4173,34 @@ emit_insn_after (rtx x, rtx after) case CODE_LABEL: case BARRIER: case NOTE: - last = emit_insn_after_1 (x, after); + last = emit_insn_after_1 (x, after, bb); break; #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_insn_raw (x); - add_insn_after (last, after); + add_insn_after (last, after, bb); break; } return last; } -/* Similar to emit_insn_after, except that line notes are to be inserted so - as to act as if this insn were at FROM. */ - -void -emit_insn_after_with_line_notes (rtx x, rtx after, rtx from) -{ - rtx from_line = find_line_note (from); - rtx after_line = find_line_note (after); - rtx insn = emit_insn_after (x, after); - - if (from_line) - emit_note_copy_after (from_line, after); - - if (after_line) - emit_note_copy_after (after_line, insn); -} /* Make an insn of code JUMP_INSN with body X and output it after the insn AFTER. */ rtx -emit_jump_insn_after (rtx x, rtx after) +emit_jump_insn_after_noloc (rtx x, rtx after) { rtx last; -#ifdef ENABLE_RTL_CHECKING - if (after == NULL_RTX) - abort (); -#endif + gcc_assert (after); switch (GET_CODE (x)) { @@ -4256,18 +4210,18 @@ emit_jump_insn_after (rtx x, rtx after) case CODE_LABEL: case BARRIER: case NOTE: - last = emit_insn_after_1 (x, after); + last = emit_insn_after_1 (x, after, NULL); break; #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_jump_insn_raw (x); - add_insn_after (last, after); + add_insn_after (last, after, NULL); break; } @@ -4278,14 +4232,11 @@ emit_jump_insn_after (rtx x, rtx after) and output it after the instruction AFTER. */ rtx -emit_call_insn_after (rtx x, rtx after) +emit_call_insn_after_noloc (rtx x, rtx after) { rtx last; -#ifdef ENABLE_RTL_CHECKING - if (after == NULL_RTX) - abort (); -#endif + gcc_assert (after); switch (GET_CODE (x)) { @@ -4295,18 +4246,18 @@ emit_call_insn_after (rtx x, rtx after) case CODE_LABEL: case BARRIER: case NOTE: - last = emit_insn_after_1 (x, after); + last = emit_insn_after_1 (x, after, NULL); break; #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif default: last = make_call_insn_raw (x); - add_insn_after (last, after); + add_insn_after (last, after, NULL); break; } @@ -4323,7 +4274,7 @@ emit_barrier_after (rtx after) INSN_UID (insn) = cur_insn_uid++; - add_insn_after (insn, after); + add_insn_after (insn, after, NULL); return insn; } @@ -4338,7 +4289,7 @@ emit_label_after (rtx label, rtx after) if (INSN_UID (label) == 0) { INSN_UID (label) = cur_insn_uid++; - add_insn_after (label, after); + add_insn_after (label, after, NULL); } return label; @@ -4347,54 +4298,30 @@ emit_label_after (rtx label, rtx after) /* Emit a note of subtype SUBTYPE after the insn AFTER. */ rtx -emit_note_after (int subtype, rtx after) +emit_note_after (enum insn_note subtype, rtx after) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; -#ifndef USE_MAPPED_LOCATION - NOTE_SOURCE_FILE (note) = 0; -#endif - NOTE_LINE_NUMBER (note) = subtype; - BLOCK_FOR_INSN (note) = NULL; - add_insn_after (note, after); - return note; -} - -/* Emit a copy of note ORIG after the insn AFTER. */ - -rtx -emit_note_copy_after (rtx orig, rtx after) -{ - rtx note; - - if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers) - { - cur_insn_uid++; - return 0; - } - - note = rtx_alloc (NOTE); - INSN_UID (note) = cur_insn_uid++; - NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig); - NOTE_DATA (note) = NOTE_DATA (orig); + NOTE_KIND (note) = subtype; BLOCK_FOR_INSN (note) = NULL; - add_insn_after (note, after); + memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note))); + add_insn_after (note, after, NULL); return note; } -/* Like emit_insn_after, but set INSN_LOCATOR according to SCOPE. */ +/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */ rtx emit_insn_after_setloc (rtx pattern, rtx after, int loc) { - rtx last = emit_insn_after (pattern, after); + rtx last = emit_insn_after_noloc (pattern, after, NULL); - if (pattern == NULL_RTX) + if (pattern == NULL_RTX || !loc) return last; after = NEXT_INSN (after); while (1) { - if (active_insn_p (after)) + if (active_insn_p (after) && !INSN_LOCATOR (after)) INSN_LOCATOR (after) = loc; if (after == last) break; @@ -4403,19 +4330,29 @@ emit_insn_after_setloc (rtx pattern, rtx after, int loc) return last; } -/* Like emit_jump_insn_after, but set INSN_LOCATOR according to SCOPE. */ +/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */ +rtx +emit_insn_after (rtx pattern, rtx after) +{ + if (INSN_P (after)) + return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + else + return emit_insn_after_noloc (pattern, after, NULL); +} + +/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */ rtx emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc) { - rtx last = emit_jump_insn_after (pattern, after); + rtx last = emit_jump_insn_after_noloc (pattern, after); - if (pattern == NULL_RTX) + if (pattern == NULL_RTX || !loc) return last; after = NEXT_INSN (after); while (1) { - if (active_insn_p (after)) + if (active_insn_p (after) && !INSN_LOCATOR (after)) INSN_LOCATOR (after) = loc; if (after == last) break; @@ -4424,19 +4361,29 @@ emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc) return last; } -/* Like emit_call_insn_after, but set INSN_LOCATOR according to SCOPE. */ +/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */ +rtx +emit_jump_insn_after (rtx pattern, rtx after) +{ + if (INSN_P (after)) + return emit_jump_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + else + return emit_jump_insn_after_noloc (pattern, after); +} + +/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */ rtx emit_call_insn_after_setloc (rtx pattern, rtx after, int loc) { - rtx last = emit_call_insn_after (pattern, after); + rtx last = emit_call_insn_after_noloc (pattern, after); - if (pattern == NULL_RTX) + if (pattern == NULL_RTX || !loc) return last; after = NEXT_INSN (after); while (1) { - if (active_insn_p (after)) + if (active_insn_p (after) && !INSN_LOCATOR (after)) INSN_LOCATOR (after) = loc; if (after == last) break; @@ -4445,12 +4392,57 @@ emit_call_insn_after_setloc (rtx pattern, rtx after, int loc) return last; } -/* Like emit_insn_before, but set INSN_LOCATOR according to SCOPE. */ +/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */ +rtx +emit_call_insn_after (rtx pattern, rtx after) +{ + if (INSN_P (after)) + return emit_call_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + else + return emit_call_insn_after_noloc (pattern, after); +} + +/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to SCOPE. */ rtx emit_insn_before_setloc (rtx pattern, rtx before, int loc) { rtx first = PREV_INSN (before); - rtx last = emit_insn_before (pattern, before); + rtx last = emit_insn_before_noloc (pattern, before, NULL); + + if (pattern == NULL_RTX || !loc) + return last; + + if (!first) + first = get_insns (); + else + first = NEXT_INSN (first); + while (1) + { + if (active_insn_p (first) && !INSN_LOCATOR (first)) + INSN_LOCATOR (first) = loc; + if (first == last) + break; + first = NEXT_INSN (first); + } + return last; +} + +/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to BEFORE. */ +rtx +emit_insn_before (rtx pattern, rtx before) +{ + if (INSN_P (before)) + return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + else + return emit_insn_before_noloc (pattern, before, NULL); +} + +/* like emit_insn_before_noloc, but set insn_locator according to scope. */ +rtx +emit_jump_insn_before_setloc (rtx pattern, rtx before, int loc) +{ + rtx first = PREV_INSN (before); + rtx last = emit_jump_insn_before_noloc (pattern, before); if (pattern == NULL_RTX) return last; @@ -4458,7 +4450,7 @@ emit_insn_before_setloc (rtx pattern, rtx before, int loc) first = NEXT_INSN (first); while (1) { - if (active_insn_p (first)) + if (active_insn_p (first) && !INSN_LOCATOR (first)) INSN_LOCATOR (first) = loc; if (first == last) break; @@ -4466,6 +4458,49 @@ emit_insn_before_setloc (rtx pattern, rtx before, int loc) } return last; } + +/* Like emit_jump_insn_before_noloc, but set INSN_LOCATOR according to BEFORE. */ +rtx +emit_jump_insn_before (rtx pattern, rtx before) +{ + if (INSN_P (before)) + return emit_jump_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + else + return emit_jump_insn_before_noloc (pattern, before); +} + +/* like emit_insn_before_noloc, but set insn_locator according to scope. */ +rtx +emit_call_insn_before_setloc (rtx pattern, rtx before, int loc) +{ + rtx first = PREV_INSN (before); + rtx last = emit_call_insn_before_noloc (pattern, before); + + if (pattern == NULL_RTX) + return last; + + first = NEXT_INSN (first); + while (1) + { + if (active_insn_p (first) && !INSN_LOCATOR (first)) + INSN_LOCATOR (first) = loc; + if (first == last) + break; + first = NEXT_INSN (first); + } + return last; +} + +/* like emit_call_insn_before_noloc, + but set insn_locator according to before. */ +rtx +emit_call_insn_before (rtx pattern, rtx before) +{ + if (INSN_P (before)) + return emit_call_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + else + return emit_call_insn_before_noloc (pattern, before); +} /* Take X and emit it at the end of the doubly-linked INSN list. @@ -4501,7 +4536,7 @@ emit_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif @@ -4542,7 +4577,7 @@ emit_jump_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif @@ -4576,7 +4611,7 @@ emit_call_insn (rtx x) #ifdef ENABLE_RTL_CHECKING case SEQUENCE: - abort (); + gcc_unreachable (); break; #endif @@ -4617,44 +4652,6 @@ emit_barrier (void) return barrier; } -/* Make line numbering NOTE insn for LOCATION add it to the end - of the doubly-linked list, but only if line-numbers are desired for - debugging info and it doesn't match the previous one. */ - -rtx -emit_line_note (location_t location) -{ - rtx note; - - set_file_and_line_for_stmt (location); - -#ifdef USE_MAPPED_LOCATION - if (location == last_location) - return NULL_RTX; -#else - if (location.file && last_location.file - && !strcmp (location.file, last_location.file) - && location.line == last_location.line) - return NULL_RTX; -#endif - last_location = location; - - if (no_line_numbers) - { - cur_insn_uid++; - return NULL_RTX; - } - -#ifdef USE_MAPPED_LOCATION - note = emit_note ((int) location); -#else - note = emit_note (location.line); - NOTE_SOURCE_FILE (note) = location.file; -#endif - - return note; -} - /* Emit a copy of note ORIG. */ rtx @@ -4662,17 +4659,11 @@ emit_note_copy (rtx orig) { rtx note; - if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers) - { - cur_insn_uid++; - return NULL_RTX; - } - note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; NOTE_DATA (note) = NOTE_DATA (orig); - NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig); + NOTE_KIND (note) = NOTE_KIND (orig); BLOCK_FOR_INSN (note) = NULL; add_insn (note); @@ -4683,30 +4674,82 @@ emit_note_copy (rtx orig) and add it to the end of the doubly-linked list. */ rtx -emit_note (int note_no) +emit_note (enum insn_note kind) { rtx note; note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; - NOTE_LINE_NUMBER (note) = note_no; + NOTE_KIND (note) = kind; memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note))); BLOCK_FOR_INSN (note) = NULL; add_insn (note); return note; } +/* Emit a clobber of lvalue X. */ + +rtx +emit_clobber (rtx x) +{ + /* CONCATs should not appear in the insn stream. */ + if (GET_CODE (x) == CONCAT) + { + emit_clobber (XEXP (x, 0)); + return emit_clobber (XEXP (x, 1)); + } + return emit_insn (gen_rtx_CLOBBER (VOIDmode, x)); +} + +/* Return a sequence of insns to clobber lvalue X. */ + +rtx +gen_clobber (rtx x) +{ + rtx seq; + + start_sequence (); + emit_clobber (x); + seq = get_insns (); + end_sequence (); + return seq; +} + +/* Emit a use of rvalue X. */ + +rtx +emit_use (rtx x) +{ + /* CONCATs should not appear in the insn stream. */ + if (GET_CODE (x) == CONCAT) + { + emit_use (XEXP (x, 0)); + return emit_use (XEXP (x, 1)); + } + return emit_insn (gen_rtx_USE (VOIDmode, x)); +} + +/* Return a sequence of insns to use rvalue X. */ + +rtx +gen_use (rtx x) +{ + rtx seq; + + start_sequence (); + emit_use (x); + seq = get_insns (); + end_sequence (); + return seq; +} + /* Cause next statement to emit a line note even if the line number has not changed. */ void force_next_line_note (void) { -#ifdef USE_MAPPED_LOCATION last_location = -1; -#else - last_location.line = -1; -#endif } /* Place a note of KIND on insn INSN with DATUM as the datum. If a @@ -4727,8 +4770,7 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum) means the insn only has one * useful * set). */ if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn)) { - if (note) - abort (); + gcc_assert (!note); return NULL_RTX; } @@ -4736,26 +4778,43 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum) It serves no useful purpose and breaks eliminate_regs. */ if (GET_CODE (datum) == ASM_OPERANDS) return NULL_RTX; + + if (note) + { + XEXP (note, 0) = datum; + df_notes_rescan (insn); + return note; + } break; default: + if (note) + { + XEXP (note, 0) = datum; + return note; + } break; } - if (note) + add_reg_note (insn, kind, datum); + + switch (kind) { - XEXP (note, 0) = datum; - return note; + case REG_EQUAL: + case REG_EQUIV: + df_notes_rescan (insn); + break; + default: + break; } - REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn)); return REG_NOTES (insn); } /* Return an indication of which type of insn should have X as a body. The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */ -enum rtx_code +static enum rtx_code classify_insn (rtx x) { if (LABEL_P (x)) @@ -4797,21 +4856,24 @@ emit (rtx x) { enum rtx_code code = classify_insn (x); - if (code == CODE_LABEL) - return emit_label (x); - else if (code == INSN) - return emit_insn (x); - else if (code == JUMP_INSN) + switch (code) { - rtx insn = emit_jump_insn (x); - if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN) - return emit_barrier (); - return insn; + case CODE_LABEL: + return emit_label (x); + case INSN: + return emit_insn (x); + case JUMP_INSN: + { + rtx insn = emit_jump_insn (x); + if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN) + return emit_barrier (); + return insn; + } + case CALL_INSN: + return emit_call_insn (x); + default: + gcc_unreachable (); } - else if (code == CALL_INSN) - return emit_call_insn (x); - else - abort (); } /* Space for free sequence stack entries. */ @@ -4835,7 +4897,7 @@ start_sequence (void) free_sequence_stack = tem->next; } else - tem = ggc_alloc (sizeof (struct sequence_stack)); + tem = GGC_NEW (struct sequence_stack); tem->next = seq_stack; tem->first = first_insn; @@ -4864,17 +4926,16 @@ push_to_sequence (rtx first) last_insn = last; } -/* Set up the insn chain from a chain stort in FIRST to LAST. */ +/* Like push_to_sequence, but take the last insn as an argument to avoid + looping through the list. */ void -push_to_full_sequence (rtx first, rtx last) +push_to_sequence2 (rtx first, rtx last) { start_sequence (); + first_insn = first; last_insn = last; - /* We really should have the end of the insn chain here. */ - if (last && NEXT_INSN (last)) - abort (); } /* Set up the outer-level insn chain @@ -4948,15 +5009,14 @@ in_sequence_p (void) /* Put the various virtual registers into REGNO_REG_RTX. */ -void -init_virtual_regs (struct emit_status *es) +static void +init_virtual_regs (void) { - rtx *ptr = es->x_regno_reg_rtx; - ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx; - ptr[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx; - ptr[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx; - ptr[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx; - ptr[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx; + regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx; + regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx; + regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx; + regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx; + regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx; } @@ -4995,6 +5055,9 @@ copy_insn_1 (rtx orig) RTX_CODE code; const char *format_ptr; + if (orig == NULL) + return NULL; + code = GET_CODE (orig); switch (code) @@ -5002,6 +5065,7 @@ copy_insn_1 (rtx orig) case REG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case CODE_LABEL: @@ -5020,11 +5084,7 @@ copy_insn_1 (rtx orig) break; case CONST: - /* CONST can be shared if it contains a SYMBOL_REF. If it contains - a LABEL_REF, it isn't sharable. */ - if (GET_CODE (XEXP (orig, 0)) == PLUS - && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF - && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT) + if (shared_const_p (orig)) return orig; break; @@ -5037,13 +5097,11 @@ copy_insn_1 (rtx orig) break; } - copy = rtx_alloc (code); - - /* Copy the various flags, and other information. We assume that - all fields need copying, and then clear the fields that should + /* Copy the various flags, fields, and other information. We assume + that all fields need copying, and then clear the fields that should not be copied. That is the sensible default behavior, and forces us to explicitly document why we are *not* copying a flag. */ - memcpy (copy, orig, RTX_HDR_SIZE); + copy = shallow_copy_rtx (orig); /* We do not copy the USED flag, which is used as a mark bit during walks over the RTL. */ @@ -5060,49 +5118,45 @@ copy_insn_1 (rtx orig) format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) - { - copy->u.fld[i] = orig->u.fld[i]; - switch (*format_ptr++) - { - case 'e': - if (XEXP (orig, i) != NULL) - XEXP (copy, i) = copy_insn_1 (XEXP (orig, i)); - break; + switch (*format_ptr++) + { + case 'e': + if (XEXP (orig, i) != NULL) + XEXP (copy, i) = copy_insn_1 (XEXP (orig, i)); + break; - case 'E': - case 'V': - if (XVEC (orig, i) == orig_asm_constraints_vector) - XVEC (copy, i) = copy_asm_constraints_vector; - else if (XVEC (orig, i) == orig_asm_operands_vector) - XVEC (copy, i) = copy_asm_operands_vector; - else if (XVEC (orig, i) != NULL) - { - XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); - for (j = 0; j < XVECLEN (copy, i); j++) - XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j)); - } - break; + case 'E': + case 'V': + if (XVEC (orig, i) == orig_asm_constraints_vector) + XVEC (copy, i) = copy_asm_constraints_vector; + else if (XVEC (orig, i) == orig_asm_operands_vector) + XVEC (copy, i) = copy_asm_operands_vector; + else if (XVEC (orig, i) != NULL) + { + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); + for (j = 0; j < XVECLEN (copy, i); j++) + XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j)); + } + break; - case 't': - case 'w': - case 'i': - case 's': - case 'S': - case 'u': - case '0': - /* These are left unchanged. */ - break; + case 't': + case 'w': + case 'i': + case 's': + case 'S': + case 'u': + case '0': + /* These are left unchanged. */ + break; - default: - abort (); - } - } + default: + gcc_unreachable (); + } if (code == SCRATCH) { i = copy_insn_n_scratches++; - if (i >= MAX_RECOG_OPERANDS) - abort (); + gcc_assert (i < MAX_RECOG_OPERANDS); copy_insn_scratch_in[i] = orig; copy_insn_scratch_out[i] = copy; } @@ -5139,28 +5193,23 @@ copy_insn (rtx insn) void init_emit (void) { - struct function *f = cfun; - - f->emit = ggc_alloc (sizeof (struct emit_status)); first_insn = NULL; last_insn = NULL; cur_insn_uid = 1; reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; last_location = UNKNOWN_LOCATION; first_label_num = label_num; - last_label_num = 0; seq_stack = NULL; /* Init the tables that describe all the pseudo regs. */ - f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101; + crtl->emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101; - f->emit->regno_pointer_align - = ggc_alloc_cleared (f->emit->regno_pointer_align_length - * sizeof (unsigned char)); + crtl->emit.regno_pointer_align + = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length); regno_reg_rtx - = ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx)); + = GGC_NEWVEC (rtx, crtl->emit.regno_pointer_align_length); /* Put copies of all the hard registers into regno_reg_rtx. */ memcpy (regno_reg_rtx, @@ -5168,7 +5217,7 @@ init_emit (void) FIRST_PSEUDO_REGISTER * sizeof (rtx)); /* Put copies of all the virtual register rtx into regno_reg_rtx. */ - init_virtual_regs (f->emit); + init_virtual_regs (); /* Indicate that the virtual registers and stack locations are all pointers. */ @@ -5201,10 +5250,10 @@ init_emit (void) #endif } -/* Generate the constant 0. */ +/* Generate a vector constant for mode MODE and constant value CONSTANT. */ static rtx -gen_const_vector_0 (enum machine_mode mode) +gen_const_vector (enum machine_mode mode, int constant) { rtx tem; rtvec v; @@ -5214,31 +5263,116 @@ gen_const_vector_0 (enum machine_mode mode) units = GET_MODE_NUNITS (mode); inner = GET_MODE_INNER (mode); + gcc_assert (!DECIMAL_FLOAT_MODE_P (inner)); + v = rtvec_alloc (units); - /* We need to call this function after we to set CONST0_RTX first. */ - if (!CONST0_RTX (inner)) - abort (); + /* We need to call this function after we set the scalar const_tiny_rtx + entries. */ + gcc_assert (const_tiny_rtx[constant][(int) inner]); for (i = 0; i < units; ++i) - RTVEC_ELT (v, i) = CONST0_RTX (inner); + RTVEC_ELT (v, i) = const_tiny_rtx[constant][(int) inner]; tem = gen_rtx_raw_CONST_VECTOR (mode, v); return tem; } /* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when - all elements are zero. */ + all elements are zero, and the one vector when all elements are one. */ rtx gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v) { - rtx inner_zero = CONST0_RTX (GET_MODE_INNER (mode)); + enum machine_mode inner = GET_MODE_INNER (mode); + int nunits = GET_MODE_NUNITS (mode); + rtx x; int i; - for (i = GET_MODE_NUNITS (mode) - 1; i >= 0; i--) - if (RTVEC_ELT (v, i) != inner_zero) - return gen_rtx_raw_CONST_VECTOR (mode, v); - return CONST0_RTX (mode); + /* Check to see if all of the elements have the same value. */ + x = RTVEC_ELT (v, nunits - 1); + for (i = nunits - 2; i >= 0; i--) + if (RTVEC_ELT (v, i) != x) + break; + + /* If the values are all the same, check to see if we can use one of the + standard constant vectors. */ + if (i == -1) + { + if (x == CONST0_RTX (inner)) + return CONST0_RTX (mode); + else if (x == CONST1_RTX (inner)) + return CONST1_RTX (mode); + } + + return gen_rtx_raw_CONST_VECTOR (mode, v); +} + +/* Initialise global register information required by all functions. */ + +void +init_emit_regs (void) +{ + int i; + + /* Reset register attributes */ + htab_empty (reg_attrs_htab); + + /* We need reg_raw_mode, so initialize the modes now. */ + init_reg_modes_target (); + + /* Assign register numbers to the globally defined register rtx. */ + pc_rtx = gen_rtx_PC (VOIDmode); + cc0_rtx = gen_rtx_CC0 (VOIDmode); + stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM); + frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM); + hard_frame_pointer_rtx = gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM); + arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM); + virtual_incoming_args_rtx = + gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM); + virtual_stack_vars_rtx = + gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM); + virtual_stack_dynamic_rtx = + gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM); + virtual_outgoing_args_rtx = + gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM); + virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM); + + /* Initialize RTL for commonly used hard registers. These are + copied into regno_reg_rtx as we begin to compile each function. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i); + +#ifdef RETURN_ADDRESS_POINTER_REGNUM + return_address_pointer_rtx + = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM); +#endif + +#ifdef STATIC_CHAIN_REGNUM + static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); + +#ifdef STATIC_CHAIN_INCOMING_REGNUM + if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM) + static_chain_incoming_rtx + = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM); + else +#endif + static_chain_incoming_rtx = static_chain_rtx; +#endif + +#ifdef STATIC_CHAIN + static_chain_rtx = STATIC_CHAIN; + +#ifdef STATIC_CHAIN_INCOMING + static_chain_incoming_rtx = STATIC_CHAIN_INCOMING; +#else + static_chain_incoming_rtx = static_chain_rtx; +#endif +#endif + + if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) + pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); + else + pic_offset_table_rtx = NULL_RTX; } /* Create some permanent unique rtl objects shared between all functions. @@ -5251,17 +5385,17 @@ init_emit_once (int line_numbers) enum machine_mode mode; enum machine_mode double_mode; - /* We need reg_raw_mode, so initialize the modes now. */ - init_reg_modes_once (); - - /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash - tables. */ + /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute + hash tables. */ const_int_htab = htab_create_ggc (37, const_int_htab_hash, const_int_htab_eq, NULL); const_double_htab = htab_create_ggc (37, const_double_htab_hash, const_double_htab_eq, NULL); + const_fixed_htab = htab_create_ggc (37, const_fixed_htab_hash, + const_fixed_htab_eq, NULL); + mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash, mem_attrs_htab_eq, NULL); reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash, @@ -5275,7 +5409,8 @@ init_emit_once (int line_numbers) word_mode = VOIDmode; double_mode = VOIDmode; - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT @@ -5287,7 +5422,8 @@ init_emit_once (int line_numbers) word_mode = mode; } - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE @@ -5297,34 +5433,6 @@ init_emit_once (int line_numbers) ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0); - /* Assign register numbers to the globally defined register rtx. - This must be done at runtime because the register number field - is in a union and some compilers can't initialize unions. */ - - pc_rtx = gen_rtx_PC (VOIDmode); - cc0_rtx = gen_rtx_CC0 (VOIDmode); - stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM); - frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM); - if (hard_frame_pointer_rtx == 0) - hard_frame_pointer_rtx = gen_raw_REG (Pmode, - HARD_FRAME_POINTER_REGNUM); - if (arg_pointer_rtx == 0) - arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM); - virtual_incoming_args_rtx = - gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM); - virtual_stack_vars_rtx = - gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM); - virtual_stack_dynamic_rtx = - gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM); - virtual_outgoing_args_rtx = - gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM); - virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM); - - /* Initialize RTL for commonly used hard registers. These are - copied into regno_reg_rtx as we begin to compile each function. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i); - #ifdef INIT_EXPANDERS /* This is to initialize {init|mark|free}_machine_status before the first call to push_function_context_to. This is needed by the Chill front @@ -5350,36 +5458,34 @@ init_emit_once (int line_numbers) REAL_VALUE_FROM_INT (dconst0, 0, 0, double_mode); REAL_VALUE_FROM_INT (dconst1, 1, 0, double_mode); REAL_VALUE_FROM_INT (dconst2, 2, 0, double_mode); - REAL_VALUE_FROM_INT (dconst3, 3, 0, double_mode); - REAL_VALUE_FROM_INT (dconst10, 10, 0, double_mode); - REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode); - REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode); + + dconstm1 = dconst1; + dconstm1.sign = 1; dconsthalf = dconst1; SET_REAL_EXP (&dconsthalf, REAL_EXP (&dconsthalf) - 1); - real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3); - - /* Initialize mathematical constants for constant folding builtins. - These constants need to be given to at least 160 bits precision. */ - real_from_string (&dconstpi, - "3.1415926535897932384626433832795028841971693993751058209749445923078"); - real_from_string (&dconste, - "2.7182818284590452353602874713526624977572470936999595749669676277241"); - for (i = 0; i < (int) ARRAY_SIZE (const_tiny_rtx); i++) { - REAL_VALUE_TYPE *r = + const REAL_VALUE_TYPE *const r = (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + const_tiny_rtx[i][(int) mode] = + CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_DECIMAL_FLOAT); + mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) const_tiny_rtx[i][(int) mode] = CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) const_tiny_rtx[i][(int) mode] = GEN_INT (i); @@ -5389,53 +5495,143 @@ init_emit_once (int line_numbers) const_tiny_rtx[i][(int) mode] = GEN_INT (i); } + for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)]; + const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner); + } + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)]; + const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner); + } + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode); + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); + } for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode); + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); + } - for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i) - if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC) - const_tiny_rtx[0][i] = const0_rtx; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + FCONST0(mode).data.high = 0; + FCONST0(mode).data.low = 0; + FCONST0(mode).mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST0 (mode), mode); + } - const_tiny_rtx[0][(int) BImode] = const0_rtx; - if (STORE_FLAG_VALUE == 1) - const_tiny_rtx[1][(int) BImode] = const1_rtx; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_UFRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + FCONST0(mode).data.high = 0; + FCONST0(mode).data.low = 0; + FCONST0(mode).mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST0 (mode), mode); + } -#ifdef RETURN_ADDRESS_POINTER_REGNUM - return_address_pointer_rtx - = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM); -#endif + for (mode = GET_CLASS_NARROWEST_MODE (MODE_ACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + FCONST0(mode).data.high = 0; + FCONST0(mode).data.low = 0; + FCONST0(mode).mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST0 (mode), mode); + + /* We store the value 1. */ + FCONST1(mode).data.high = 0; + FCONST1(mode).data.low = 0; + FCONST1(mode).mode = mode; + lshift_double (1, 0, GET_MODE_FBIT (mode), + 2 * HOST_BITS_PER_WIDE_INT, + &FCONST1(mode).data.low, + &FCONST1(mode).data.high, + SIGNED_FIXED_POINT_MODE_P (mode)); + const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST1 (mode), mode); + } -#ifdef STATIC_CHAIN_REGNUM - static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); + for (mode = GET_CLASS_NARROWEST_MODE (MODE_UACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + FCONST0(mode).data.high = 0; + FCONST0(mode).data.low = 0; + FCONST0(mode).mode = mode; + const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST0 (mode), mode); + + /* We store the value 1. */ + FCONST1(mode).data.high = 0; + FCONST1(mode).data.low = 0; + FCONST1(mode).mode = mode; + lshift_double (1, 0, GET_MODE_FBIT (mode), + 2 * HOST_BITS_PER_WIDE_INT, + &FCONST1(mode).data.low, + &FCONST1(mode).data.high, + SIGNED_FIXED_POINT_MODE_P (mode)); + const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE ( + FCONST1 (mode), mode); + } -#ifdef STATIC_CHAIN_INCOMING_REGNUM - if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM) - static_chain_incoming_rtx - = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM); - else -#endif - static_chain_incoming_rtx = static_chain_rtx; -#endif + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + } -#ifdef STATIC_CHAIN - static_chain_rtx = STATIC_CHAIN; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UFRACT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + } -#ifdef STATIC_CHAIN_INCOMING - static_chain_incoming_rtx = STATIC_CHAIN_INCOMING; -#else - static_chain_incoming_rtx = static_chain_rtx; -#endif -#endif + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_ACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); + } - if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) - pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UACCUM); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); + const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); + } + + for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i) + if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC) + const_tiny_rtx[0][i] = const0_rtx; + + const_tiny_rtx[0][(int) BImode] = const0_rtx; + if (STORE_FLAG_VALUE == 1) + const_tiny_rtx[1][(int) BImode] = const1_rtx; } /* Produce exact duplicate of insn INSN after AFTER. @@ -5444,65 +5640,59 @@ init_emit_once (int line_numbers) rtx emit_copy_of_insn_after (rtx insn, rtx after) { - rtx new; - rtx note1, note2, link; + rtx new_rtx, link; switch (GET_CODE (insn)) { case INSN: - new = emit_insn_after (copy_insn (PATTERN (insn)), after); + new_rtx = emit_insn_after (copy_insn (PATTERN (insn)), after); break; case JUMP_INSN: - new = emit_jump_insn_after (copy_insn (PATTERN (insn)), after); + new_rtx = emit_jump_insn_after (copy_insn (PATTERN (insn)), after); break; case CALL_INSN: - new = emit_call_insn_after (copy_insn (PATTERN (insn)), after); + new_rtx = emit_call_insn_after (copy_insn (PATTERN (insn)), after); if (CALL_INSN_FUNCTION_USAGE (insn)) - CALL_INSN_FUNCTION_USAGE (new) + CALL_INSN_FUNCTION_USAGE (new_rtx) = copy_insn (CALL_INSN_FUNCTION_USAGE (insn)); - SIBLING_CALL_P (new) = SIBLING_CALL_P (insn); - CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn); + SIBLING_CALL_P (new_rtx) = SIBLING_CALL_P (insn); + RTL_CONST_CALL_P (new_rtx) = RTL_CONST_CALL_P (insn); + RTL_PURE_CALL_P (new_rtx) = RTL_PURE_CALL_P (insn); + RTL_LOOPING_CONST_OR_PURE_CALL_P (new_rtx) + = RTL_LOOPING_CONST_OR_PURE_CALL_P (insn); break; default: - abort (); + gcc_unreachable (); } /* Update LABEL_NUSES. */ - mark_jump_label (PATTERN (new), new, 0); + mark_jump_label (PATTERN (new_rtx), new_rtx, 0); - INSN_LOCATOR (new) = INSN_LOCATOR (insn); + INSN_LOCATOR (new_rtx) = INSN_LOCATOR (insn); - /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will - make them. */ + /* If the old insn is frame related, then so is the new one. This is + primarily needed for IA-64 unwind info which marks epilogue insns, + which may be duplicated by the basic block reordering code. */ + RTX_FRAME_RELATED_P (new_rtx) = RTX_FRAME_RELATED_P (insn); + + /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label + will make them. REG_LABEL_TARGETs are created there too, but are + supposed to be sticky, so we copy them. */ for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) != REG_LABEL) + if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND) { if (GET_CODE (link) == EXPR_LIST) - REG_NOTES (new) - = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link), - XEXP (link, 0), - REG_NOTES (new))); + add_reg_note (new_rtx, REG_NOTE_KIND (link), + copy_insn_1 (XEXP (link, 0))); else - REG_NOTES (new) - = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link), - XEXP (link, 0), - REG_NOTES (new))); + add_reg_note (new_rtx, REG_NOTE_KIND (link), XEXP (link, 0)); } - /* Fix the libcall sequences. */ - if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL) - { - rtx p = new; - while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL) - p = PREV_INSN (p); - XEXP (note1, 0) = p; - XEXP (note2, 0) = new; - } - INSN_CODE (new) = INSN_CODE (insn); - return new; + INSN_CODE (new_rtx) = INSN_CODE (insn); + return new_rtx; } static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];