X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Femit-rtl.c;h=e0acc0c276605680bac77968985b3874821b0d41;hb=3327418041ec57f6db06ba8ec7ea88616c2d7728;hp=22c7979a7736140b17576a74396c790b511c701f;hpb=a1ddb869e0e3d5284a4065fe19e0390f16303611;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 22c7979a773..e0acc0c2766 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1,6 +1,7 @@ /* Emit RTL for the GCC expander. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -58,6 +59,8 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "tree-pass.h" #include "df.h" +#include "params.h" +#include "target.h" /* Commonly used modes. */ @@ -71,7 +74,7 @@ enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ struct rtl_data x_rtl; /* Indexed by pseudo register number, gives the rtx for that pseudo. - Allocated in parallel with regno_pointer_align. + 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. */ @@ -82,10 +85,6 @@ rtx * regno_reg_rtx; static GTY(()) int label_num = 1; -/* Nonzero means do not generate NOTEs for source line numbers. */ - -static int no_line_numbers; - /* Commonly used rtx's, so that we only need space for one copy. These are initialized once for the entire compilation. All of these are unique; no other rtx-object will be equal to any @@ -135,8 +134,6 @@ FIXED_VALUE_TYPE fconst1[MAX_FCONST1]; In an inline procedure, the stack and frame pointer rtxs may not be used for anything else. */ -rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */ -rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */ /* This is used to implement __builtin_return_address for some machines. @@ -175,6 +172,7 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) #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 cur_debug_insn_uid (crtl->emit.x_cur_debug_insn_uid) #define last_location (crtl->emit.x_last_location) #define first_label_num (crtl->emit.x_first_label_num) @@ -193,11 +191,10 @@ 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 (alias_set_type, tree, rtx, rtx, unsigned int, - enum machine_mode); + addr_space_t, 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 (enum machine_mode, int); static void copy_rtx_if_shared_1 (rtx *orig); @@ -293,6 +290,7 @@ mem_attrs_htab_hash (const void *x) const mem_attrs *const p = (const mem_attrs *) x; return (p->alias ^ (p->align * 1000) + ^ (p->addrspace * 4000) ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) ^ (size_t) iterative_hash_expr (p->expr, 0)); @@ -310,6 +308,7 @@ mem_attrs_htab_eq (const void *x, const void *y) return (p->alias == q->alias && p->offset == q->offset && p->size == q->size && p->align == q->align + && p->addrspace == q->addrspace && (p->expr == q->expr || (p->expr != NULL_TREE && q->expr != NULL_TREE && operand_equal_p (p->expr, q->expr, 0)))); @@ -321,7 +320,7 @@ mem_attrs_htab_eq (const void *x, const void *y) static mem_attrs * get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, - unsigned int align, enum machine_mode mode) + unsigned int align, addr_space_t addrspace, enum machine_mode mode) { mem_attrs attrs; void **slot; @@ -329,7 +328,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, /* If everything is the default, we can just return zero. This must match what the corresponding MEM_* macros return when the field is not present. */ - if (alias == 0 && expr == 0 && offset == 0 + if (alias == 0 && expr == 0 && offset == 0 && addrspace == 0 && (size == 0 || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size))) && (STRICT_ALIGNMENT && mode != BLKmode @@ -341,6 +340,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, attrs.offset = offset; attrs.size = size; attrs.align = align; + attrs.addrspace = addrspace; slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT); if (*slot == 0) @@ -518,6 +518,36 @@ const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode) return lookup_const_fixed (fixed); } +/* Constructs double_int from rtx CST. */ + +double_int +rtx_to_double_int (const_rtx cst) +{ + double_int r; + + if (CONST_INT_P (cst)) + r = shwi_to_double_int (INTVAL (cst)); + else if (CONST_DOUBLE_P (cst) && GET_MODE (cst) == VOIDmode) + { + r.low = CONST_DOUBLE_LOW (cst); + r.high = CONST_DOUBLE_HIGH (cst); + } + else + gcc_unreachable (); + + return r; +} + + +/* Return a CONST_DOUBLE or CONST_INT for a value specified as + a double_int. */ + +rtx +immed_double_int_const (double_int i, enum machine_mode mode) +{ + return immed_double_const (i.low, i.high, mode); +} + /* 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 @@ -536,7 +566,7 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode) 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 + 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) @@ -793,35 +823,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 = XALLOCAVEC (rtx, n); + 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 @@ -830,10 +854,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++; @@ -864,9 +889,22 @@ rtx gen_reg_rtx (enum machine_mode mode) { rtx val; + unsigned int align = GET_MODE_ALIGNMENT (mode); 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) + { + unsigned int min_align = MINIMUM_ALIGNMENT (NULL, mode, align); + if (crtl->stack_alignment_estimated < min_align) + crtl->stack_alignment_estimated = min_align; + } + if (generating_concat_p && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)) @@ -890,12 +928,12 @@ gen_reg_rtx (enum machine_mode mode) if (reg_rtx_no == crtl->emit.regno_pointer_align_length) { int old_size = crtl->emit.regno_pointer_align_length; - char *new; + char *tmp; rtx *new1; - new = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2); - memset (new + old_size, 0, old_size); - crtl->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_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2); memset (new1 + old_size, 0, old_size * sizeof (rtx)); @@ -913,9 +951,9 @@ gen_reg_rtx (enum machine_mode mode) to the REG_OFFSET. */ static void -update_reg_offset (rtx new, rtx reg, int offset) +update_reg_offset (rtx new_rtx, rtx reg, int offset) { - REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg), + REG_ATTRS (new_rtx) = get_reg_attrs (REG_EXPR (reg), REG_OFFSET (reg) + offset); } @@ -926,10 +964,10 @@ rtx gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset) { - rtx new = gen_rtx_REG (mode, regno); + rtx new_rtx = gen_rtx_REG (mode, regno); - update_reg_offset (new, reg, offset); - return new; + update_reg_offset (new_rtx, reg, offset); + return new_rtx; } /* Generate a new pseudo-register with the same attributes as REG, but @@ -938,10 +976,10 @@ gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, rtx gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset) { - rtx new = gen_reg_rtx (mode); + rtx new_rtx = gen_reg_rtx (mode); - update_reg_offset (new, 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 @@ -971,11 +1009,11 @@ set_reg_attrs_from_value (rtx reg, rtx x) 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) + if (MEM_OFFSET (x) && CONST_INT_P (MEM_OFFSET (x))) REG_ATTRS (reg) = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset); if (MEM_POINTER (x)) - mark_reg_pointer (reg, MEM_ALIGN (x)); + mark_reg_pointer (reg, 0); } else if (REG_P (x)) { @@ -1024,7 +1062,7 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) /* Set the REG_ATTRS for registers in value X, given that X represents decl T. */ -static void +void set_reg_attrs_for_decl_rtl (tree t, rtx x) { if (GET_CODE (x) == SUBREG) @@ -1177,12 +1215,12 @@ 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 + if (CONST_INT_P (x) && 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); gcc_assert (innermode != VOIDmode && innermode != BLKmode); @@ -1222,7 +1260,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x) } else if (GET_CODE (x) == SUBREG || REG_P (x) || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR - || GET_CODE (x) == CONST_DOUBLE || GET_CODE (x) == CONST_INT) + || GET_CODE (x) == CONST_DOUBLE || CONST_INT_P (x)) return simplify_gen_subreg (mode, x, innermode, offset); /* Otherwise, we can't do this. */ @@ -1243,7 +1281,7 @@ gen_highpart (enum machine_mode mode, rtx 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. */ @@ -1252,7 +1290,7 @@ gen_highpart (enum machine_mode mode, rtx x) result = validize_mem (result); gcc_assert (result); } - + return result; } @@ -1372,18 +1410,20 @@ 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_addr_space_p (word_mode, + XEXP (new_rtx, 0), + MEM_ADDR_SPACE (op))) 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. */ @@ -1421,37 +1461,6 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode) return result; } -/* 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. */ - -static tree -component_ref_for_mem_expr (tree ref) -{ - tree inner = TREE_OPERAND (ref, 0); - - if (TREE_CODE (inner) == COMPONENT_REF) - inner = component_ref_for_mem_expr (inner); - else - { - /* Now remove any conversions: they don't change what the underlying - object is. Likewise for SAVE_EXPR. */ - while (CONVERT_EXPR_P (inner) - || TREE_CODE (inner) == VIEW_CONVERT_EXPR - || TREE_CODE (inner) == SAVE_EXPR) - inner = TREE_OPERAND (inner, 0); - - if (! DECL_P (inner)) - inner = NULL_TREE; - } - - if (inner == TREE_OPERAND (ref, 0)) - return ref; - else - return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, - TREE_OPERAND (ref, 1), NULL_TREE); -} - /* Returns 1 if both MEM_EXPR can be considered equal and 0 otherwise. */ @@ -1467,26 +1476,94 @@ mem_expr_equal_p (const_tree expr1, const_tree expr2) if (TREE_CODE (expr1) != TREE_CODE (expr2)) return 0; - if (TREE_CODE (expr1) == COMPONENT_REF) - return - mem_expr_equal_p (TREE_OPERAND (expr1, 0), - TREE_OPERAND (expr2, 0)) - && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */ - TREE_OPERAND (expr2, 1)); - - if (INDIRECT_REF_P (expr1)) - return mem_expr_equal_p (TREE_OPERAND (expr1, 0), - TREE_OPERAND (expr2, 0)); + return operand_equal_p (expr1, expr2, 0); +} - /* 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; +/* 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. */ + +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 +/* 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. */ @@ -1537,11 +1614,11 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* 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 - || TREE_CODE (t) == ALIGN_INDIRECT_REF + if (objectp || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ALIGN_INDIRECT_REF || TYPE_ALIGN_OK (type)) align = MAX (align, TYPE_ALIGN (type)); - else + else if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF) { if (integer_zerop (TREE_OPERAND (t, 1))) @@ -1560,6 +1637,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, if (! TYPE_P (t)) { tree base; + bool align_computed = false; if (TREE_THIS_VOLATILE (t)) MEM_VOLATILE_P (ref) = 1; @@ -1616,6 +1694,7 @@ 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. */ @@ -1625,6 +1704,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, #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. */ @@ -1634,7 +1714,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, else if (TREE_CODE (t) == COMPONENT_REF && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1))) { - expr = component_ref_for_mem_expr (t); + expr = t; offset = const0_rtx; apply_bitpos = bitpos; /* ??? Any reason the field size would be different than @@ -1684,13 +1764,15 @@ 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; } } else if (TREE_CODE (t2) == COMPONENT_REF) { - expr = component_ref_for_mem_expr (t2); + expr = t2; + offset = NULL; if (host_integerp (off_tree, 1)) { offset = GEN_INT (tree_low_cst (off_tree, 1)); @@ -1699,23 +1781,31 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* ??? Any reason the field size would be different than the size we got from the type? */ } - else if (flag_argument_noalias > 1 - && (INDIRECT_REF_P (t2)) - && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL) + + /* If this is an indirect reference, record it. */ + else if (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == MISALIGNED_INDIRECT_REF) { - expr = t2; - offset = NULL; + expr = t; + offset = const0_rtx; + apply_bitpos = bitpos; } } - /* If this is a Fortran indirect argument reference, record the - parameter decl. */ - else if (flag_argument_noalias > 1 - && (INDIRECT_REF_P (t)) - && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL) + /* If this is an indirect reference, record it. */ + else if (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == MISALIGNED_INDIRECT_REF) { expr = t; - offset = NULL; + offset = const0_rtx; + apply_bitpos = bitpos; + } + + if (!align_computed && !INDIRECT_REF_P (t)) + { + unsigned int obj_align + = get_object_alignment (t, align, BIGGEST_ALIGNMENT); + align = MAX (align, obj_align); } } @@ -1739,7 +1829,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* Now set the attributes we computed above. */ MEM_ATTRS (ref) - = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); + = get_mem_attrs (alias, expr, offset, size, align, + TYPE_ADDR_SPACE (type), GET_MODE (ref)); /* If this is already known to be a scalar or aggregate, we are done. */ if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref)) @@ -1759,17 +1850,6 @@ set_mem_attributes (rtx ref, tree t, int objectp) set_mem_attributes_minus_bitpos (ref, t, objectp, 0); } -/* Set MEM to the decl that REG refers to. */ - -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 @@ -1782,7 +1862,17 @@ set_mem_alias_set (rtx mem, alias_set_type set) MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); +} + +/* Set the address space of MEM to ADDRSPACE (target-defined). */ + +void +set_mem_addr_space (rtx mem, addr_space_t addrspace) +{ + MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), + MEM_OFFSET (mem), MEM_SIZE (mem), + MEM_ALIGN (mem), addrspace, GET_MODE (mem)); } /* Set the alignment of MEM to ALIGN bits. */ @@ -1792,7 +1882,7 @@ set_mem_align (rtx mem, unsigned int align) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), align, - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the expr for MEM to EXPR. */ @@ -1802,7 +1892,8 @@ set_mem_expr (rtx mem, tree expr) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem), - MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); + MEM_SIZE (mem), MEM_ALIGN (mem), + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the offset of MEM to OFFSET. */ @@ -1812,7 +1903,7 @@ set_mem_offset (rtx mem, rtx offset) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the size of MEM to SIZE. */ @@ -1822,7 +1913,7 @@ set_mem_size (rtx mem, rtx size) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), size, MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Return a memory reference like MEMREF, but with its mode changed to MODE @@ -1834,31 +1925,33 @@ set_mem_size (rtx mem, rtx size) static rtx change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { - rtx new; + addr_space_t as; + rtx new_rtx; gcc_assert (MEM_P (memref)); + as = MEM_ADDR_SPACE (memref); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) addr = XEXP (memref, 0); if (mode == GET_MODE (memref) && addr == XEXP (memref, 0) - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; if (validate) { if (reload_in_progress || reload_completed) - gcc_assert (memory_address_p (mode, addr)); + gcc_assert (memory_address_addr_space_p (mode, addr, as)); else - addr = memory_address (mode, addr); + addr = memory_address_addr_space (mode, addr, as); } 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 @@ -1867,31 +1960,32 @@ 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) - = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); + MEM_ATTRS (new_rtx) + = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, + MEM_ADDR_SPACE (memref), mmode); - return new; + return new_rtx; } /* Return a memory reference like MEMREF, but with its mode changed @@ -1905,14 +1999,17 @@ 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); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); + int pbits; /* If there are no changes, just return the original memory reference. */ if (mode == GET_MODE (memref) && !offset - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; /* ??? Prefer to create garbage instead of creating shared rtl. @@ -1920,6 +2017,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 (address_mode); + 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 @@ -1928,13 +2035,18 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, && offset >= 0 && (unsigned HOST_WIDE_INT) offset < GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT) - addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0), + addr = gen_rtx_LO_SUM (address_mode, XEXP (addr, 0), plus_constant (XEXP (addr, 1), offset)); else 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. */ @@ -1950,17 +2062,18 @@ 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, as, + 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 @@ -1983,9 +2096,11 @@ 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); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); - new = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); /* At this point we don't know _why_ the address is invalid. It could have secondary memory references, multiplies or anything. @@ -1994,28 +2109,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_addr_space_p (GET_MODE (memref), new_rtx, as) && 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, address_mode, 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; + as, GET_MODE (new_rtx)); + return new_rtx; } /* Return a memory reference like MEMREF, but with its address changed to @@ -2048,14 +2163,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. */ @@ -2117,10 +2232,71 @@ 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), + MEM_ADDR_SPACE (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, ADDR_SPACE_GENERIC, 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. */ - return new; +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 + && CONST_INT_P (XEXP (addr, 1))) + offset = XEXP (addr, 1); + + MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset, + MEM_SIZE (mem), MEM_ALIGN (mem), + ADDR_SPACE_GENERIC, GET_MODE (mem)); + MEM_NOTRAP_P (mem) = 1; } /* Return a newly created CODE_LABEL rtx with a unique label number. */ @@ -2147,8 +2323,31 @@ set_new_first_and_last_insn (rtx first, rtx last) last_insn = last; cur_insn_uid = 0; - for (insn = first; insn; insn = NEXT_INSN (insn)) - cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn)); + if (MIN_NONDEBUG_INSN_UID || MAY_HAVE_DEBUG_INSNS) + { + int debug_count = 0; + + cur_insn_uid = MIN_NONDEBUG_INSN_UID - 1; + cur_debug_insn_uid = 0; + + for (insn = first; insn; insn = NEXT_INSN (insn)) + if (INSN_UID (insn) < MIN_NONDEBUG_INSN_UID) + cur_debug_insn_uid = MAX (cur_debug_insn_uid, INSN_UID (insn)); + else + { + cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn)); + if (DEBUG_INSN_P (insn)) + debug_count++; + } + + if (debug_count) + cur_debug_insn_uid = MIN_NONDEBUG_INSN_UID + debug_count; + else + cur_debug_insn_uid++; + } + else + for (insn = first; insn; insn = NEXT_INSN (insn)) + cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn)); cur_insn_uid++; } @@ -2218,7 +2417,7 @@ struct rtl_opt_pass pass_unshare_all_rtl = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -2249,6 +2448,8 @@ verify_rtx_sharing (rtx orig, rtx insn) switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2296,7 +2497,7 @@ verify_rtx_sharing (rtx orig, rtx insn) } #endif gcc_assert (!RTX_FLAG (x, used)); - + RTX_FLAG (x, used) = 1; /* Now scan the subexpressions recursively. */ @@ -2449,6 +2650,8 @@ repeat: switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2471,6 +2674,7 @@ repeat: return; break; + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -2501,7 +2705,7 @@ repeat: format_ptr = GET_RTX_FORMAT (code); length = GET_RTX_LENGTH (code); last_ptr = NULL; - + for (i = 0; i < length; i++) { switch (*format_ptr++) @@ -2517,12 +2721,12 @@ repeat: { int j; int len = XVECLEN (x, i); - + /* Copy the vector iff I copied the rtx and the length is nonzero. */ if (copied && len > 0) XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem); - + /* Call recursively on all inside the vector. */ for (j = 0; j < len; j++) { @@ -2567,6 +2771,8 @@ repeat: switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2577,6 +2783,7 @@ repeat: case CC0: return; + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -2594,7 +2801,7 @@ repeat: format_ptr = GET_RTX_FORMAT (code); length = GET_RTX_LENGTH (code); - + for (i = 0; i < length; i++) { switch (*format_ptr++) @@ -2637,6 +2844,8 @@ set_used_flags (rtx x) switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2647,6 +2856,7 @@ set_used_flags (rtx x) case CC0: return; + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -2826,6 +3036,27 @@ get_max_uid (void) { return cur_insn_uid; } + +/* Return the number of actual (non-debug) insns emitted in this + function. */ + +int +get_max_insn_count (void) +{ + int n = cur_insn_uid; + + /* The table size must be stable across -g, to avoid codegen + differences due to debug insns, and not be affected by + -fmin-insn-uid, to avoid excessive table size and to simplify + debugging of -fcompare-debug failures. */ + if (cur_debug_insn_uid > MIN_NONDEBUG_INSN_UID) + n -= cur_debug_insn_uid; + else + n -= MIN_NONDEBUG_INSN_UID; + + return n; +} + /* Return the next insn. If it is a SEQUENCE, return the first insn of the sequence. */ @@ -2877,6 +3108,25 @@ next_nonnote_insn (rtx insn) return insn; } +/* Return the next insn after INSN that is not a NOTE, but stop the + search before we enter another basic block. This routine does not + look inside SEQUENCEs. */ + +rtx +next_nonnote_insn_bb (rtx insn) +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 || !NOTE_P (insn)) + break; + if (NOTE_INSN_BASIC_BLOCK_P (insn)) + return NULL_RTX; + } + + return insn; +} + /* Return the previous insn before INSN that is not a NOTE. This routine does not look inside SEQUENCEs. */ @@ -2893,6 +3143,57 @@ prev_nonnote_insn (rtx insn) return insn; } +/* Return the previous insn before INSN that is not a NOTE, but stop + the search before we enter another basic block. This routine does + not look inside SEQUENCEs. */ + +rtx +prev_nonnote_insn_bb (rtx insn) +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 || !NOTE_P (insn)) + break; + if (NOTE_INSN_BASIC_BLOCK_P (insn)) + return NULL_RTX; + } + + return insn; +} + +/* Return the next insn after INSN that is not a DEBUG_INSN. This + routine does not look inside SEQUENCEs. */ + +rtx +next_nondebug_insn (rtx insn) +{ + while (insn) + { + insn = NEXT_INSN (insn); + if (insn == 0 || !DEBUG_INSN_P (insn)) + break; + } + + return insn; +} + +/* Return the previous insn before INSN that is not a DEBUG_INSN. + This routine does not look inside SEQUENCEs. */ + +rtx +prev_nondebug_insn (rtx insn) +{ + while (insn) + { + insn = PREV_INSN (insn); + if (insn == 0 || !DEBUG_INSN_P (insn)) + break; + } + + return insn; +} + /* Return the next INSN, CALL_INSN or JUMP_INSN after INSN; or 0, if there is none. This routine does not look inside SEQUENCEs. */ @@ -2944,8 +3245,8 @@ last_call_insn (void) } /* Find the next insn after INSN that really does something. This routine - does not look inside SEQUENCEs. Until reload has completed, this is the - same as next_real_insn. */ + does not look inside SEQUENCEs. After reload this also skips over + standalone USE and CLOBBER insn. */ int active_insn_p (const_rtx insn) @@ -2971,8 +3272,8 @@ next_active_insn (rtx insn) } /* Find the last insn before INSN that really does something. This routine - does not look inside SEQUENCEs. Until reload has completed, this is the - same as prev_real_insn. */ + does not look inside SEQUENCEs. After reload this also skips over + standalone USE and CLOBBER insn. */ rtx prev_active_insn (rtx insn) @@ -3169,6 +3470,10 @@ try_split (rtx pat, rtx trial, int last) 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)); @@ -3239,6 +3544,10 @@ try_split (rtx pat, rtx trial, int last) p = &XEXP (*p, 1); *p = CALL_INSN_FUNCTION_USAGE (trial); SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial); + + /* Update the debug information for the CALL_INSN. */ + if (flag_enable_icf_debug) + (*debug_hooks->copy_call_info) (trial, insn); } } @@ -3248,13 +3557,7 @@ try_split (rtx pat, rtx trial, int last) switch (REG_NOTE_KIND (note)) { case REG_EH_REGION: - for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn)) - { - if (CALL_P (insn) - || (flag_non_call_exceptions && INSN_P (insn) - && may_trap_p (PATTERN (insn)))) - add_reg_note (insn, REG_EH_REGION, XEXP (note, 0)); - } + copy_reg_eh_region_note_backward (note, insn_last, NULL); break; case REG_NORETURN: @@ -3360,6 +3663,27 @@ make_insn_raw (rtx pattern) return insn; } +/* Like `make_insn_raw' but make a DEBUG_INSN instead of an insn. */ + +rtx +make_debug_insn_raw (rtx pattern) +{ + rtx insn; + + insn = rtx_alloc (DEBUG_INSN); + INSN_UID (insn) = cur_debug_insn_uid++; + if (cur_debug_insn_uid > MIN_NONDEBUG_INSN_UID) + INSN_UID (insn) = cur_insn_uid++; + + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + REG_NOTES (insn) = NULL; + INSN_LOCATOR (insn) = curr_insn_locator (); + BLOCK_FOR_INSN (insn) = NULL; + + return insn; +} + /* Like `make_insn_raw' but make a JUMP_INSN instead of an insn. */ rtx @@ -3520,7 +3844,7 @@ add_insn_before (rtx insn, rtx before, basic_block bb) gcc_assert (stack); } - if (!bb + if (!bb && !BARRIER_P (before) && !BARRIER_P (insn)) bb = BLOCK_FOR_INSN (before); @@ -3546,7 +3870,8 @@ add_insn_before (rtx insn, rtx before, basic_block bb) /* Replace insn with an deleted instruction note. */ -void set_insn_deleted (rtx insn) +void +set_insn_deleted (rtx insn) { df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn)); PUT_CODE (insn, NOTE); @@ -3772,6 +4097,7 @@ emit_insn_before_noloc (rtx x, rtx before, basic_block bb) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -3815,6 +4141,7 @@ emit_jump_insn_before_noloc (rtx x, rtx before) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -3858,6 +4185,7 @@ emit_call_insn_before_noloc (rtx x, rtx before) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -3889,6 +4217,50 @@ emit_call_insn_before_noloc (rtx x, rtx before) return last; } +/* Make an instruction with body X and code DEBUG_INSN + and output it before the instruction BEFORE. */ + +rtx +emit_debug_insn_before_noloc (rtx x, rtx before) +{ + rtx last = NULL_RTX, insn; + + gcc_assert (before); + + switch (GET_CODE (x)) + { + case DEBUG_INSN: + case INSN: + case JUMP_INSN: + case CALL_INSN: + case CODE_LABEL: + case BARRIER: + case NOTE: + insn = x; + while (insn) + { + rtx next = NEXT_INSN (insn); + add_insn_before (insn, before, NULL); + last = insn; + insn = next; + } + break; + +#ifdef ENABLE_RTL_CHECKING + case SEQUENCE: + gcc_unreachable (); + break; +#endif + + default: + last = make_debug_insn_raw (x); + add_insn_before (last, before, NULL); + break; + } + + return last; +} + /* Make an insn of code BARRIER and output it before the insn BEFORE. */ @@ -3976,6 +4348,7 @@ emit_insn_after_1 (rtx first, rtx after, basic_block bb) if (after == last_insn) last_insn = last; + return last; } @@ -3994,6 +4367,7 @@ emit_insn_after_noloc (rtx x, rtx after, basic_block bb) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4031,6 +4405,7 @@ emit_jump_insn_after_noloc (rtx x, rtx after) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4067,6 +4442,7 @@ emit_call_insn_after_noloc (rtx x, rtx after) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4091,6 +4467,43 @@ emit_call_insn_after_noloc (rtx x, rtx after) return last; } +/* Make an instruction with body X and code CALL_INSN + and output it after the instruction AFTER. */ + +rtx +emit_debug_insn_after_noloc (rtx x, rtx after) +{ + rtx last; + + gcc_assert (after); + + switch (GET_CODE (x)) + { + case DEBUG_INSN: + case INSN: + case JUMP_INSN: + case CALL_INSN: + case CODE_LABEL: + case BARRIER: + case NOTE: + last = emit_insn_after_1 (x, after, NULL); + break; + +#ifdef ENABLE_RTL_CHECKING + case SEQUENCE: + gcc_unreachable (); + break; +#endif + + default: + last = make_debug_insn_raw (x); + add_insn_after (last, after, NULL); + break; + } + + return last; +} + /* Make an insn of code BARRIER and output it after the insn AFTER. */ @@ -4161,8 +4574,13 @@ emit_insn_after_setloc (rtx pattern, rtx after, int loc) rtx emit_insn_after (rtx pattern, rtx after) { - if (INSN_P (after)) - return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + rtx prev = after; + + while (DEBUG_INSN_P (prev)) + prev = PREV_INSN (prev); + + if (INSN_P (prev)) + return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (prev)); else return emit_insn_after_noloc (pattern, after, NULL); } @@ -4192,8 +4610,13 @@ emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc) rtx emit_jump_insn_after (rtx pattern, rtx after) { - if (INSN_P (after)) - return emit_jump_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + rtx prev = after; + + while (DEBUG_INSN_P (prev)) + prev = PREV_INSN (prev); + + if (INSN_P (prev)) + return emit_jump_insn_after_setloc (pattern, after, INSN_LOCATOR (prev)); else return emit_jump_insn_after_noloc (pattern, after); } @@ -4223,12 +4646,48 @@ emit_call_insn_after_setloc (rtx pattern, rtx after, int loc) rtx emit_call_insn_after (rtx pattern, rtx after) { - if (INSN_P (after)) - return emit_call_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + rtx prev = after; + + while (DEBUG_INSN_P (prev)) + prev = PREV_INSN (prev); + + if (INSN_P (prev)) + return emit_call_insn_after_setloc (pattern, after, INSN_LOCATOR (prev)); else return emit_call_insn_after_noloc (pattern, after); } +/* Like emit_debug_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */ +rtx +emit_debug_insn_after_setloc (rtx pattern, rtx after, int loc) +{ + rtx last = emit_debug_insn_after_noloc (pattern, after); + + if (pattern == NULL_RTX || !loc) + return last; + + after = NEXT_INSN (after); + while (1) + { + if (active_insn_p (after) && !INSN_LOCATOR (after)) + INSN_LOCATOR (after) = loc; + if (after == last) + break; + after = NEXT_INSN (after); + } + return last; +} + +/* Like emit_debug_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */ +rtx +emit_debug_insn_after (rtx pattern, rtx after) +{ + if (INSN_P (after)) + return emit_debug_insn_after_setloc (pattern, after, INSN_LOCATOR (after)); + else + return emit_debug_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) @@ -4258,8 +4717,13 @@ emit_insn_before_setloc (rtx pattern, rtx before, int loc) rtx emit_insn_before (rtx pattern, rtx before) { - if (INSN_P (before)) - return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + rtx next = before; + + while (DEBUG_INSN_P (next)) + next = PREV_INSN (next); + + if (INSN_P (next)) + return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (next)); else return emit_insn_before_noloc (pattern, before, NULL); } @@ -4290,8 +4754,13 @@ emit_jump_insn_before_setloc (rtx pattern, rtx before, int loc) rtx emit_jump_insn_before (rtx pattern, rtx before) { - if (INSN_P (before)) - return emit_jump_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + rtx next = before; + + while (DEBUG_INSN_P (next)) + next = PREV_INSN (next); + + if (INSN_P (next)) + return emit_jump_insn_before_setloc (pattern, before, INSN_LOCATOR (next)); else return emit_jump_insn_before_noloc (pattern, before); } @@ -4323,11 +4792,49 @@ emit_call_insn_before_setloc (rtx pattern, rtx before, int loc) rtx emit_call_insn_before (rtx pattern, rtx before) { - if (INSN_P (before)) - return emit_call_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + rtx next = before; + + while (DEBUG_INSN_P (next)) + next = PREV_INSN (next); + + if (INSN_P (next)) + return emit_call_insn_before_setloc (pattern, before, INSN_LOCATOR (next)); else return emit_call_insn_before_noloc (pattern, before); } + +/* like emit_insn_before_noloc, but set insn_locator according to scope. */ +rtx +emit_debug_insn_before_setloc (rtx pattern, rtx before, int loc) +{ + rtx first = PREV_INSN (before); + rtx last = emit_debug_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_debug_insn_before_noloc, + but set insn_locator according to before. */ +rtx +emit_debug_insn_before (rtx pattern, rtx before) +{ + if (INSN_P (before)) + return emit_debug_insn_before_setloc (pattern, before, INSN_LOCATOR (before)); + else + return emit_debug_insn_before_noloc (pattern, before); +} /* Take X and emit it at the end of the doubly-linked INSN list. @@ -4345,6 +4852,7 @@ emit_insn (rtx x) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4376,6 +4884,52 @@ emit_insn (rtx x) return last; } +/* Make an insn of code DEBUG_INSN with pattern X + and add it to the end of the doubly-linked list. */ + +rtx +emit_debug_insn (rtx x) +{ + rtx last = last_insn; + rtx insn; + + if (x == NULL_RTX) + return last; + + switch (GET_CODE (x)) + { + case DEBUG_INSN: + case INSN: + case JUMP_INSN: + case CALL_INSN: + case CODE_LABEL: + case BARRIER: + case NOTE: + insn = x; + while (insn) + { + rtx next = NEXT_INSN (insn); + add_insn (insn); + last = insn; + insn = next; + } + break; + +#ifdef ENABLE_RTL_CHECKING + case SEQUENCE: + gcc_unreachable (); + break; +#endif + + default: + last = make_debug_insn_raw (x); + add_insn (last); + break; + } + + return last; +} + /* Make an insn of code JUMP_INSN with pattern X and add it to the end of the doubly-linked list. */ @@ -4386,6 +4940,7 @@ emit_jump_insn (rtx x) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4427,6 +4982,7 @@ emit_call_insn (rtx x) switch (GET_CODE (x)) { + case DEBUG_INSN: case INSN: case JUMP_INSN: case CALL_INSN: @@ -4485,15 +5041,15 @@ rtx emit_note_copy (rtx orig) { rtx note; - + note = rtx_alloc (NOTE); - + INSN_UID (note) = cur_insn_uid++; NOTE_DATA (note) = NOTE_DATA (orig); NOTE_KIND (note) = NOTE_KIND (orig); BLOCK_FOR_INSN (note) = NULL; add_insn (note); - + return note; } @@ -4698,6 +5254,8 @@ emit (rtx x) } case CALL_INSN: return emit_call_insn (x); + case DEBUG_INSN: + return emit_debug_insn (x); default: gcc_unreachable (); } @@ -4882,6 +5440,9 @@ copy_insn_1 (rtx orig) RTX_CODE code; const char *format_ptr; + if (orig == NULL) + return NULL; + code = GET_CODE (orig); switch (code) @@ -5019,7 +5580,11 @@ init_emit (void) { first_insn = NULL; last_insn = NULL; - cur_insn_uid = 1; + if (MIN_NONDEBUG_INSN_UID) + cur_insn_uid = MIN_NONDEBUG_INSN_UID; + else + cur_insn_uid = 1; + cur_debug_insn_uid = 1; reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; last_location = UNKNOWN_LOCATION; first_label_num = label_num; @@ -5171,39 +5736,16 @@ init_emit_regs (void) = 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. - LINE_NUMBERS is nonzero if line numbers are to be generated. */ +/* Create some permanent unique rtl objects shared between all functions. */ void -init_emit_once (int line_numbers) +init_emit_once (void) { int i; enum machine_mode mode; @@ -5225,8 +5767,6 @@ init_emit_once (int line_numbers) reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash, reg_attrs_htab_eq, NULL); - no_line_numbers = ! line_numbers; - /* Compute the word and byte modes. */ byte_mode = VOIDmode; @@ -5464,27 +6004,31 @@ init_emit_once (int line_numbers) rtx emit_copy_of_insn_after (rtx insn, rtx after) { - rtx new, 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 DEBUG_INSN: + new_rtx = emit_debug_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); - RTL_CONST_CALL_P (new) = RTL_CONST_CALL_P (insn); - RTL_PURE_CALL_P (new) = RTL_PURE_CALL_P (insn); - RTL_LOOPING_CONST_OR_PURE_CALL_P (new) + 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; @@ -5493,14 +6037,14 @@ emit_copy_of_insn_after (rtx insn, rtx after) } /* 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); /* 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_FRAME_RELATED_P (insn); + 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 @@ -5509,14 +6053,14 @@ emit_copy_of_insn_after (rtx insn, rtx after) if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND) { if (GET_CODE (link) == EXPR_LIST) - add_reg_note (new, REG_NOTE_KIND (link), + add_reg_note (new_rtx, REG_NOTE_KIND (link), copy_insn_1 (XEXP (link, 0))); else - add_reg_note (new, REG_NOTE_KIND (link), XEXP (link, 0)); + add_reg_note (new_rtx, REG_NOTE_KIND (link), XEXP (link, 0)); } - 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];