From be80a87ee585150cfdd94304848350a2c6d3e0bd Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 30 Apr 2011 12:06:18 +0200 Subject: [PATCH] dwarf2.h (DW_OP_GNU_const_type, [...]): New. * dwarf2.h (DW_OP_GNU_const_type, DW_OP_GNU_regval_type, DW_OP_GNU_deref_type, DW_OP_GNU_convert, DW_OP_GNU_reinterpret): New. * dwarf2out.c (get_address_mode): New inline. (mem_loc_descriptor): Add MEM_MODE parameter, adjust recursive calls, if not dwarf_strict emit DW_OP_GNU_{{const,regval,deref}_type,convert,reinterpret} when desirable. Handle FLOAT_EXTEND, FLOAT_TRUNCATE, FLOAT, UNSIGNED_FLOAT, FIX and UNSIGNED_FIX. Just return NULL for FMA, STRICT_LOW_PART, CONST_VECTOR and CONST_FIXED. (dwarf2out_frame_debug_cfa_expression, reg_loc_descriptor, dw_loc_list_1, cst_pool_loc_descr, loc_list_from_tree): Adjust mem_loc_descriptor callers. (dwarf_stack_op_name, size_of_loc_descr, output_loc_operands, output_loc_operands_raw, hash_loc_operands, compare_loc_operands): Handle DW_OP_GNU_const_type, DW_OP_GNU_regval_type, DW_OP_GNU_deref_type, DW_OP_GNU_convert and DW_OP_GNU_reinterpret. (base_types): New variable. (get_base_type_offset, calc_base_type_die_sizes, base_type_for_mode, mark_base_types, base_type_cmp, move_marked_base_types): New functions. (calc_die_sizes): Assert that die_offset is 0 or equal to next_die_offset. (loc_descriptor): Only handle here lowpart SUBREGs of REG, for others defer to mem_loc_descriptor. Adjust mem_loc_descriptor callers. If not dwarf_strict, call mem_loc_descriptor even for non-MODE_INT modes or MODE_INT modes larger than DWARF2_ADDR_SIZE. (gen_subprogram_die): Don't give up on call site parameters with non-integral or large integral modes. Adjust mem_loc_descriptor callers. (prune_unused_types): Call prune_unused_types_mark on base_types vector entries. (resolve_addr): Call mark_base_types. (dwarf2out_finish): Call move_marked_base_types. From-SVN: r173210 --- gcc/ChangeLog | 32 ++ gcc/dwarf2out.c | 1235 ++++++++++++++++++++++++++++++++++++--------- include/ChangeLog | 5 + include/dwarf2.h | 7 + 4 files changed, 1049 insertions(+), 230 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ee2340471ba2..0655cf644a76 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,37 @@ 2011-04-30 Jakub Jelinek + * dwarf2out.c (get_address_mode): New inline. + (mem_loc_descriptor): Add MEM_MODE parameter, adjust recursive calls, + if not dwarf_strict emit + DW_OP_GNU_{{const,regval,deref}_type,convert,reinterpret} when + desirable. Handle FLOAT_EXTEND, FLOAT_TRUNCATE, FLOAT, + UNSIGNED_FLOAT, FIX and UNSIGNED_FIX. Just return NULL for + FMA, STRICT_LOW_PART, CONST_VECTOR and CONST_FIXED. + (dwarf2out_frame_debug_cfa_expression, reg_loc_descriptor, + dw_loc_list_1, cst_pool_loc_descr, loc_list_from_tree): Adjust + mem_loc_descriptor callers. + (dwarf_stack_op_name, size_of_loc_descr, output_loc_operands, + output_loc_operands_raw, hash_loc_operands, compare_loc_operands): + Handle DW_OP_GNU_const_type, DW_OP_GNU_regval_type, + DW_OP_GNU_deref_type, DW_OP_GNU_convert and DW_OP_GNU_reinterpret. + (base_types): New variable. + (get_base_type_offset, calc_base_type_die_sizes, + base_type_for_mode, mark_base_types, base_type_cmp, + move_marked_base_types): New functions. + (calc_die_sizes): Assert that die_offset is 0 or equal to + next_die_offset. + (loc_descriptor): Only handle here lowpart SUBREGs of REG, for + others defer to mem_loc_descriptor. Adjust mem_loc_descriptor + callers. If not dwarf_strict, call mem_loc_descriptor even for + non-MODE_INT modes or MODE_INT modes larger than DWARF2_ADDR_SIZE. + (gen_subprogram_die): Don't give up on call site parameters + with non-integral or large integral modes. Adjust + mem_loc_descriptor callers. + (prune_unused_types): Call prune_unused_types_mark on base_types + vector entries. + (resolve_addr): Call mark_base_types. + (dwarf2out_finish): Call move_marked_base_types. + PR tree-optimization/48809 * tree-switch-conversion.c (build_arrays): Compute tidx in unsigned type. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index fb1dd9c77826..83653d2984e9 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -482,7 +482,8 @@ static struct dw_loc_descr_struct *build_cfa_aligned_loc (HOST_WIDE_INT, HOST_WIDE_INT); static void def_cfa_1 (const char *, dw_cfa_location *); static struct dw_loc_descr_struct *mem_loc_descriptor - (rtx, enum machine_mode mode, enum var_init_status); + (rtx, enum machine_mode mode, enum machine_mode mem_mode, + enum var_init_status); /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START @@ -2053,6 +2054,17 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label) reg_save (label, sregno, dregno, 0); } +/* Helper function to get mode of MEM's address. */ + +static inline enum machine_mode +get_address_mode (rtx mem) +{ + enum machine_mode mode = GET_MODE (XEXP (mem, 0)); + if (mode != VOIDmode) + return mode; + return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); +} + /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */ static void @@ -2073,8 +2085,8 @@ dwarf2out_frame_debug_cfa_expression (rtx set, const char *label) cfi->dw_cfi_opc = DW_CFA_expression; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (REGNO (src)); cfi->dw_cfi_oprnd2.dw_cfi_loc - = mem_loc_descriptor (XEXP (dest, 0), GET_MODE (dest), - VAR_INIT_STATUS_INITIALIZED); + = mem_loc_descriptor (XEXP (dest, 0), get_address_mode (dest), + GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED); /* ??? We'd like to use queue_reg_save, were the interface different, and, as above, we could manage flushing for epilogues. */ @@ -4785,6 +4797,16 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_GNU_implicit_pointer"; case DW_OP_GNU_entry_value: return "DW_OP_GNU_entry_value"; + case DW_OP_GNU_const_type: + return "DW_OP_GNU_const_type"; + case DW_OP_GNU_regval_type: + return "DW_OP_GNU_regval_type"; + case DW_OP_GNU_deref_type: + return "DW_OP_GNU_deref_type"; + case DW_OP_GNU_convert: + return "DW_OP_GNU_convert"; + case DW_OP_GNU_reinterpret: + return "DW_OP_GNU_reinterpret"; default: return "OP_"; @@ -4892,6 +4914,7 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset) (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE) static unsigned long size_of_locs (dw_loc_descr_ref); +static unsigned long int get_base_type_offset (dw_die_ref); /* Return the size of a location descriptor. */ @@ -5014,6 +5037,50 @@ size_of_loc_descr (dw_loc_descr_ref loc) size += size_of_uleb128 (op_size) + op_size; break; } + case DW_OP_GNU_const_type: + { + unsigned long o + = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die); + size += size_of_uleb128 (o) + 1; + switch (loc->dw_loc_oprnd2.val_class) + { + case dw_val_class_vec: + size += loc->dw_loc_oprnd2.v.val_vec.length + * loc->dw_loc_oprnd2.v.val_vec.elt_size; + break; + case dw_val_class_const: + size += HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT; + break; + case dw_val_class_const_double: + size += 2 * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT; + break; + default: + gcc_unreachable (); + } + break; + } + case DW_OP_GNU_regval_type: + { + unsigned long o + = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die); + size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned) + + size_of_uleb128 (o); + } + break; + case DW_OP_GNU_deref_type: + { + unsigned long o + = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die); + size += 1 + size_of_uleb128 (o); + } + break; + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + { + unsigned long o + = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die); + size += size_of_uleb128 (o); + } default: break; } @@ -5306,6 +5373,96 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) output_loc_sequence (val1->v.val_loc, for_eh_or_skip); break; + case DW_OP_GNU_const_type: + { + unsigned long o = get_base_type_offset (val1->v.val_die_ref.die), l; + gcc_assert (o); + dw2_asm_output_data_uleb128 (o, NULL); + switch (val2->val_class) + { + case dw_val_class_const: + l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; + dw2_asm_output_data (1, l, NULL); + dw2_asm_output_data (l, val2->v.val_int, NULL); + break; + case dw_val_class_vec: + { + unsigned int elt_size = val2->v.val_vec.elt_size; + unsigned int len = val2->v.val_vec.length; + unsigned int i; + unsigned char *p; + + l = len * elt_size; + dw2_asm_output_data (1, l, NULL); + if (elt_size > sizeof (HOST_WIDE_INT)) + { + elt_size /= 2; + len *= 2; + } + for (i = 0, p = val2->v.val_vec.array; + i < len; + i++, p += elt_size) + dw2_asm_output_data (elt_size, extract_int (p, elt_size), + "fp or vector constant word %u", i); + } + break; + case dw_val_class_const_double: + { + unsigned HOST_WIDE_INT first, second; + l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; + + dw2_asm_output_data (1, 2 * l, NULL); + if (WORDS_BIG_ENDIAN) + { + first = val2->v.val_double.high; + second = val2->v.val_double.low; + } + else + { + first = val2->v.val_double.low; + second = val2->v.val_double.high; + } + dw2_asm_output_data (l, first, NULL); + dw2_asm_output_data (l, second, NULL); + } + break; + default: + gcc_unreachable (); + } + } + break; + case DW_OP_GNU_regval_type: + { + unsigned r = val1->v.val_unsigned; + unsigned long o = get_base_type_offset (val2->v.val_die_ref.die); + gcc_assert (o); + if (for_eh_or_skip >= 0) + { + r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip); + gcc_assert (size_of_uleb128 (r) + == size_of_uleb128 (val1->v.val_unsigned)); + } + dw2_asm_output_data_uleb128 (r, NULL); + dw2_asm_output_data_uleb128 (o, NULL); + } + break; + case DW_OP_GNU_deref_type: + { + unsigned long o = get_base_type_offset (val2->v.val_die_ref.die); + gcc_assert (o); + dw2_asm_output_data (1, val1->v.val_int, NULL); + dw2_asm_output_data_uleb128 (o, NULL); + } + break; + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + { + unsigned long o = get_base_type_offset (val1->v.val_die_ref.die); + gcc_assert (o); + dw2_asm_output_data_uleb128 (o, NULL); + } + break; + default: /* Other codes have no operands. */ break; @@ -5483,6 +5640,11 @@ output_loc_operands_raw (dw_loc_descr_ref loc) case DW_OP_GNU_implicit_pointer: case DW_OP_GNU_entry_value: + case DW_OP_GNU_const_type: + case DW_OP_GNU_regval_type: + case DW_OP_GNU_deref_type: + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: gcc_unreachable (); break; @@ -6310,6 +6472,8 @@ static GTY(()) VEC(tree,gc) *generic_type_instances; within the current function. */ static HOST_WIDE_INT frame_pointer_fb_offset; +static VEC (dw_die_ref, heap) *base_types; + /* Forward declarations for functions defined in this file. */ static int is_pseudo_reg (const_rtx); @@ -6442,6 +6606,7 @@ static void output_location_lists (dw_die_ref); static int constant_size (unsigned HOST_WIDE_INT); static unsigned long size_of_die (dw_die_ref); static void calc_die_sizes (dw_die_ref); +static void calc_base_type_die_sizes (void); static void mark_dies (dw_die_ref); static void unmark_dies (dw_die_ref); static void unmark_all_dies (dw_die_ref); @@ -6780,6 +6945,21 @@ get_ref_die_offset_label (char *label, dw_die_ref ref) sprintf (label, "%s+%ld", debug_info_section_label, ref->die_offset); } +/* Return die_offset of a DIE reference to a base type. */ + +static unsigned long int +get_base_type_offset (dw_die_ref ref) +{ + if (ref->die_offset) + return ref->die_offset; + if (comp_unit_die ()->die_abbrev) + { + calc_base_type_die_sizes (); + gcc_assert (ref->die_offset); + } + return ref->die_offset; +} + /* Convert a DIE tag into its string name. */ static const char * @@ -10811,6 +10991,8 @@ calc_die_sizes (dw_die_ref die) { dw_die_ref c; + gcc_assert (die->die_offset == 0 + || (unsigned long int) die->die_offset == next_die_offset); die->die_offset = next_die_offset; next_die_offset += size_of_die (die); @@ -10821,6 +11003,36 @@ calc_die_sizes (dw_die_ref die) next_die_offset += 1; } +/* Size just the base type children at the start of the CU. + This is needed because build_abbrev needs to size locs + and sizing of type based stack ops needs to know die_offset + values for the base types. */ + +static void +calc_base_type_die_sizes (void) +{ + unsigned long die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; + unsigned int i; + dw_die_ref base_type; +#if ENABLE_ASSERT_CHECKING + dw_die_ref prev = comp_unit_die ()->die_child; +#endif + + die_offset += size_of_die (comp_unit_die ()); + for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++) + { +#if ENABLE_ASSERT_CHECKING + gcc_assert (base_type->die_offset == 0 + && prev->die_sib == base_type + && base_type->die_child == NULL + && base_type->die_abbrev); + prev = base_type; +#endif + base_type->die_offset = die_offset; + die_offset += size_of_die (base_type); + } +} + /* Set the marks for a die and its children. We do this so that we know whether or not a reference needs to use FORM_ref_addr; only DIEs in the same CU will be marked. We used to clear out the offset @@ -13168,7 +13380,8 @@ reg_loc_descriptor (rtx rtl, enum var_init_status initialized) if (dwarf_version >= 4 || !dwarf_strict) { - result = mem_loc_descriptor (rtl, VOIDmode, initialized); + result = mem_loc_descriptor (rtl, GET_MODE (rtl), VOIDmode, + initialized); if (result) add_loc_descr (&result, new_loc_descr (DW_OP_stack_value, 0, 0)); @@ -13596,6 +13809,33 @@ const_ok_for_output (rtx rtl) return true; } +/* Return a reference to DW_TAG_base_type corresponding to MODE and UNSIGNEDP + if possible, NULL otherwise. */ + +static dw_die_ref +base_type_for_mode (enum machine_mode mode, bool unsignedp) +{ + dw_die_ref type_die; + tree type = lang_hooks.types.type_for_mode (mode, unsignedp); + + if (type == NULL) + return NULL; + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case REAL_TYPE: + break; + default: + return NULL; + } + type_die = lookup_type_die (type); + if (!type_die) + type_die = modified_type_die (type, false, false, comp_unit_die ()); + if (type_die == NULL || type_die->die_tag != DW_TAG_base_type) + return NULL; + return type_die; +} + /* The following routine converts the RTL for a variable or parameter (resident in memory) into an equivalent Dwarf representation of a mechanism for getting the address of that same variable onto the top of a @@ -13606,22 +13846,25 @@ const_ok_for_output (rtx rtl) equivalent. This routine recursively descends an RTL tree, turning it into Dwarf postfix code as it goes. - MODE is the mode of the memory reference, needed to handle some - autoincrement addressing modes. + MODE is the mode that should be assumed for the rtl if it is VOIDmode. - CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the - location list for RTL. + MEM_MODE is the mode of the memory reference, needed to handle some + autoincrement addressing modes. Return 0 if we can't represent the location. */ static dw_loc_descr_ref mem_loc_descriptor (rtx rtl, enum machine_mode mode, + enum machine_mode mem_mode, enum var_init_status initialized) { dw_loc_descr_ref mem_loc_result = NULL; enum dwarf_location_atom op; dw_loc_descr_ref op0, op1; + if (mode == VOIDmode) + mode = GET_MODE (rtl); + /* Note that for a dynamically sized array, the location we will generate a description of here will be the lowest numbered location which is actually within the array. That's *not* necessarily the same as the @@ -13629,12 +13872,15 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, rtl = targetm.delegitimize_address (rtl); + if (mode != GET_MODE (rtl) && GET_MODE (rtl) != VOIDmode) + return NULL; + switch (GET_CODE (rtl)) { case POST_INC: case POST_DEC: case POST_MODIFY: - return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized); + return mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, initialized); case SUBREG: /* The case of a subreg may arise when we have a local (register) @@ -13644,15 +13890,72 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, contains the given subreg. */ if (!subreg_lowpart_p (rtl)) break; - rtl = SUBREG_REG (rtl); - if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE) + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_CLASS (GET_MODE (SUBREG_REG (rtl))) == MODE_INT + && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE + && GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))) <= DWARF2_ADDR_SIZE) + { + mem_loc_result = mem_loc_descriptor (SUBREG_REG (rtl), + GET_MODE (SUBREG_REG (rtl)), + mem_mode, initialized); + break; + } + if (dwarf_strict) + break; + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl)))) break; - if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT) + if (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl))) + && (GET_MODE_CLASS (mode) != MODE_INT + || GET_MODE_CLASS (GET_MODE (SUBREG_REG (rtl))) != MODE_INT)) break; - mem_loc_result = mem_loc_descriptor (rtl, mode, initialized); + else + { + dw_die_ref type_die; + dw_loc_descr_ref cvt; + + mem_loc_result = mem_loc_descriptor (SUBREG_REG (rtl), + GET_MODE (SUBREG_REG (rtl)), + mode, initialized); + if (mem_loc_result == NULL) + break; + type_die = base_type_for_mode (mode, 0); + if (type_die == NULL) + { + mem_loc_result = NULL; + break; + } + if (GET_MODE_SIZE (mode) + != GET_MODE_SIZE (GET_MODE (SUBREG_REG (rtl)))) + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + else + cvt = new_loc_descr (DW_OP_GNU_reinterpret, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&mem_loc_result, cvt); + } break; case REG: + if (GET_MODE_CLASS (mode) != MODE_INT + || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + { + dw_die_ref type_die; + + if (dwarf_strict) + break; + if (REGNO (rtl) > FIRST_PSEUDO_REGISTER) + break; + type_die = base_type_for_mode (mode, 0); + if (type_die == NULL) + break; + mem_loc_result = new_loc_descr (DW_OP_GNU_regval_type, + dbx_reg_number (rtl), 0); + mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_die_ref; + mem_loc_result->dw_loc_oprnd2.v.val_die_ref.die = type_die; + mem_loc_result->dw_loc_oprnd2.v.val_die_ref.external = 0; + break; + } /* Whenever a register number forms a part of the description of the method for calculating the (dynamic) address of a memory resident object, DWARF rules require the register number be referred to as @@ -13682,11 +13985,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case SIGN_EXTEND: case ZERO_EXTEND: - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); + gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); + op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)), + mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0) break; - else + else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE) { int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))); @@ -13701,37 +14005,75 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, add_loc_descr (&mem_loc_result, int_loc_descriptor (shift)); add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); } + else if (!dwarf_strict) + { + dw_die_ref type_die1, type_die2; + dw_loc_descr_ref cvt; + + type_die1 = base_type_for_mode (GET_MODE (XEXP (rtl, 0)), + GET_CODE (rtl) == ZERO_EXTEND); + if (type_die1 == NULL) + break; + type_die2 = base_type_for_mode (mode, 0); + if (type_die2 == NULL) + break; + mem_loc_result = op0; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die1; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&mem_loc_result, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die2; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&mem_loc_result, cvt); + } break; case MEM: - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), + get_address_mode (rtl), mode, VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result == NULL) mem_loc_result = tls_mem_loc_descriptor (rtl); if (mem_loc_result != 0) { - if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE) + if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE + || GET_MODE_CLASS (mode) != MODE_INT) { - expansion_failed (NULL_TREE, rtl, "DWARF address size mismatch"); - return 0; + dw_die_ref type_die; + dw_loc_descr_ref deref; + + if (dwarf_strict) + return NULL; + type_die = base_type_for_mode (mode, 0); + if (type_die == NULL) + return NULL; + deref = new_loc_descr (DW_OP_GNU_deref_type, + GET_MODE_SIZE (mode), 0); + deref->dw_loc_oprnd2.val_class = dw_val_class_die_ref; + deref->dw_loc_oprnd2.v.val_die_ref.die = type_die; + deref->dw_loc_oprnd2.v.val_die_ref.external = 0; + add_loc_descr (&mem_loc_result, deref); } - else if (GET_MODE_SIZE (GET_MODE (rtl)) == DWARF2_ADDR_SIZE) + else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE) add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); else add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref_size, - GET_MODE_SIZE (GET_MODE (rtl)), 0)); + GET_MODE_SIZE (mode), 0)); } else { rtx new_rtl = avoid_constant_pool_reference (rtl); if (new_rtl != rtl) - return mem_loc_descriptor (new_rtl, mode, initialized); + return mem_loc_descriptor (new_rtl, mode, mem_mode, initialized); } break; case LO_SUM: - return mem_loc_descriptor (XEXP (rtl, 1), mode, initialized); + return mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, initialized); case LABEL_REF: /* Some ports can transform a symbol ref into a label ref, because @@ -13739,6 +14081,9 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, pool. */ case CONST: case SYMBOL_REF: + if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE + || GET_MODE_CLASS (mode) != MODE_INT) + break; if (GET_CODE (rtl) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE) { @@ -13784,23 +14129,32 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case ENTRY_VALUE: if (dwarf_strict) return NULL; - mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0); - mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc; if (REG_P (ENTRY_VALUE_EXP (rtl))) - mem_loc_result->dw_loc_oprnd1.v.val_loc - = one_reg_loc_descriptor (dbx_reg_number (ENTRY_VALUE_EXP (rtl)), - VAR_INIT_STATUS_INITIALIZED); - else if (MEM_P (ENTRY_VALUE_EXP (rtl)) && REG_P (XEXP (ENTRY_VALUE_EXP (rtl), 0))) { - dw_loc_descr_ref ref - = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), GET_MODE (rtl), - VAR_INIT_STATUS_INITIALIZED); - if (ref == NULL || ref->dw_loc_opc == DW_OP_fbreg) + if (GET_MODE_CLASS (mode) != MODE_INT + || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode, + VOIDmode, VAR_INIT_STATUS_INITIALIZED); + else + op0 + = one_reg_loc_descriptor (dbx_reg_number (ENTRY_VALUE_EXP (rtl)), + VAR_INIT_STATUS_INITIALIZED); + } + else if (MEM_P (ENTRY_VALUE_EXP (rtl)) + && REG_P (XEXP (ENTRY_VALUE_EXP (rtl), 0))) + { + op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode, + VOIDmode, VAR_INIT_STATUS_INITIALIZED); + if (op0 && op0->dw_loc_opc == DW_OP_fbreg) return NULL; - mem_loc_result->dw_loc_oprnd1.v.val_loc = ref; } else gcc_unreachable (); + if (op0 == NULL) + return NULL; + mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc; + mem_loc_result->dw_loc_oprnd1.v.val_loc = op0; return mem_loc_result; case PRE_MODIFY: @@ -13813,32 +14167,35 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case PRE_DEC: /* Turn these into a PLUS expression and fall into the PLUS code below. */ - rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0), + rtl = gen_rtx_PLUS (mode, XEXP (rtl, 0), GEN_INT (GET_CODE (rtl) == PRE_INC - ? GET_MODE_UNIT_SIZE (mode) - : -GET_MODE_UNIT_SIZE (mode))); + ? GET_MODE_UNIT_SIZE (mem_mode) + : -GET_MODE_UNIT_SIZE (mem_mode))); /* ... fall through ... */ case PLUS: plus: - if (is_based_loc (rtl)) + if (is_based_loc (rtl) + && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE + && GET_MODE_CLASS (mode) == MODE_INT) mem_loc_result = based_loc_descr (XEXP (rtl, 0), INTVAL (XEXP (rtl, 1)), VAR_INIT_STATUS_INITIALIZED); else { - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result == 0) break; - if (CONST_INT_P (XEXP (rtl, 1))) + if (CONST_INT_P (XEXP (rtl, 1)) + && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE) loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1))); else { dw_loc_descr_ref mem_loc_result2 - = mem_loc_descriptor (XEXP (rtl, 1), mode, + = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result2 == 0) break; @@ -13869,15 +14226,31 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case ASHIFT: op = DW_OP_shl; - goto do_binop; + goto do_shift; case ASHIFTRT: op = DW_OP_shra; - goto do_binop; + goto do_shift; case LSHIFTRT: op = DW_OP_shr; - goto do_binop; + goto do_shift; + + do_shift: + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), + GET_MODE (XEXP (rtl, 1)) == VOIDmode + ? mode : GET_MODE (XEXP (rtl, 1)), mem_mode, + VAR_INIT_STATUS_INITIALIZED); + + if (op0 == 0 || op1 == 0) + break; + + mem_loc_result = op0; + add_loc_descr (&mem_loc_result, op1); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + break; case AND: op = DW_OP_and; @@ -13892,9 +14265,9 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_binop; do_binop: - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0 || op1 == 0) @@ -13906,9 +14279,9 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; case MOD: - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0 || op1 == 0) @@ -13936,7 +14309,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_unop; do_unop: - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0) @@ -13947,7 +14320,75 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_INT: - mem_loc_result = int_loc_descriptor (INTVAL (rtl)); + if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE) + { + mem_loc_result = int_loc_descriptor (INTVAL (rtl)); + break; + } + if (!dwarf_strict + && (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT + || GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT)) + { + dw_die_ref type_die = base_type_for_mode (mode, 0); + if (type_die == NULL) + return NULL; + mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, + INTVAL (rtl)); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die; + mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0; + if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT) + mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_const; + else + { + mem_loc_result->dw_loc_oprnd2.val_class + = dw_val_class_const_double; + mem_loc_result->dw_loc_oprnd2.v.val_double + = shwi_to_double_int (INTVAL (rtl)); + } + } + break; + + case CONST_DOUBLE: + if (!dwarf_strict) + { + dw_die_ref type_die; + + /* Note that a CONST_DOUBLE rtx could represent either an integer + or a floating-point constant. A CONST_DOUBLE is used whenever + the constant requires more than one word in order to be + adequately represented. We output CONST_DOUBLEs as blocks. */ + if (mode == VOIDmode + || (GET_MODE (rtl) == VOIDmode + && GET_MODE_BITSIZE (mode) != 2 * HOST_BITS_PER_WIDE_INT)) + break; + type_die = base_type_for_mode (mode, 0); + if (type_die == NULL) + return NULL; + mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die; + mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0; + if (SCALAR_FLOAT_MODE_P (mode)) + { + unsigned int length = GET_MODE_SIZE (mode); + unsigned char *array + = (unsigned char*) ggc_alloc_atomic (length); + + insert_float (rtl, array); + mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec; + mem_loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4; + mem_loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4; + mem_loc_result->dw_loc_oprnd2.v.val_vec.array = array; + } + else + { + mem_loc_result->dw_loc_oprnd2.val_class + = dw_val_class_const_double; + mem_loc_result->dw_loc_oprnd2.v.val_double + = rtx_to_double_int (rtl); + } + } break; case EQ: @@ -13975,74 +14416,75 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_scompare; do_scompare: - if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE - || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE) - break; - else - { - enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); + { + enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); - if (op_mode == VOIDmode) - op_mode = GET_MODE (XEXP (rtl, 1)); - if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) - break; + if (op_mode == VOIDmode) + op_mode = GET_MODE (XEXP (rtl, 1)); + if (op_mode == VOIDmode) + break; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, - VAR_INIT_STATUS_INITIALIZED); + if (dwarf_strict + && (GET_MODE_CLASS (op_mode) != MODE_INT + || GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)) + break; - if (op0 == 0 || op1 == 0) - break; + op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); - if (op_mode != VOIDmode - && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) - { - int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode); - shift *= BITS_PER_UNIT; - /* For eq/ne, if the operands are known to be zero-extended, - there is no need to do the fancy shifting up. */ - if (op == DW_OP_eq || op == DW_OP_ne) - { - dw_loc_descr_ref last0, last1; - for (last0 = op0; - last0->dw_loc_next != NULL; - last0 = last0->dw_loc_next) - ; - for (last1 = op1; - last1->dw_loc_next != NULL; - last1 = last1->dw_loc_next) - ; - /* deref_size zero extends, and for constants we can check - whether they are zero extended or not. */ - if (((last0->dw_loc_opc == DW_OP_deref_size - && last0->dw_loc_oprnd1.v.val_int - <= GET_MODE_SIZE (op_mode)) - || (CONST_INT_P (XEXP (rtl, 0)) - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0)) - == (INTVAL (XEXP (rtl, 0)) - & GET_MODE_MASK (op_mode)))) - && ((last1->dw_loc_opc == DW_OP_deref_size - && last1->dw_loc_oprnd1.v.val_int - <= GET_MODE_SIZE (op_mode)) - || (CONST_INT_P (XEXP (rtl, 1)) - && (unsigned HOST_WIDE_INT) - INTVAL (XEXP (rtl, 1)) - == (INTVAL (XEXP (rtl, 1)) - & GET_MODE_MASK (op_mode))))) - goto do_compare; - } - add_loc_descr (&op0, int_loc_descriptor (shift)); - add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift); - else - { - add_loc_descr (&op1, int_loc_descriptor (shift)); - add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); - } - } - } + if (op0 == 0 || op1 == 0) + break; + + if (GET_MODE_CLASS (op_mode) == MODE_INT + && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) + { + int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode); + shift *= BITS_PER_UNIT; + /* For eq/ne, if the operands are known to be zero-extended, + there is no need to do the fancy shifting up. */ + if (op == DW_OP_eq || op == DW_OP_ne) + { + dw_loc_descr_ref last0, last1; + for (last0 = op0; + last0->dw_loc_next != NULL; + last0 = last0->dw_loc_next) + ; + for (last1 = op1; + last1->dw_loc_next != NULL; + last1 = last1->dw_loc_next) + ; + /* deref_size zero extends, and for constants we can check + whether they are zero extended or not. */ + if (((last0->dw_loc_opc == DW_OP_deref_size + && last0->dw_loc_oprnd1.v.val_int + <= GET_MODE_SIZE (op_mode)) + || (CONST_INT_P (XEXP (rtl, 0)) + && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0)) + == (INTVAL (XEXP (rtl, 0)) + & GET_MODE_MASK (op_mode)))) + && ((last1->dw_loc_opc == DW_OP_deref_size + && last1->dw_loc_oprnd1.v.val_int + <= GET_MODE_SIZE (op_mode)) + || (CONST_INT_P (XEXP (rtl, 1)) + && (unsigned HOST_WIDE_INT) + INTVAL (XEXP (rtl, 1)) + == (INTVAL (XEXP (rtl, 1)) + & GET_MODE_MASK (op_mode))))) + goto do_compare; + } + add_loc_descr (&op0, int_loc_descriptor (shift)); + add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift); + else + { + add_loc_descr (&op1, int_loc_descriptor (shift)); + add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0)); + } + } + } do_compare: mem_loc_result = op0; @@ -14073,87 +14515,111 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, goto do_ucompare; do_ucompare: - if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE - || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 1))) > DWARF2_ADDR_SIZE) - break; - else - { - enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); + { + enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0)); - if (op_mode == VOIDmode) - op_mode = GET_MODE (XEXP (rtl, 1)); - if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) - break; + if (op_mode == VOIDmode) + op_mode = GET_MODE (XEXP (rtl, 1)); + if (op_mode == VOIDmode) + break; + if (GET_MODE_CLASS (op_mode) != MODE_INT) + break; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, - VAR_INIT_STATUS_INITIALIZED); + if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE) + break; - if (op0 == 0 || op1 == 0) + if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT) break; - if (op_mode != VOIDmode - && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) - { - HOST_WIDE_INT mask = GET_MODE_MASK (op_mode); - dw_loc_descr_ref last0, last1; - for (last0 = op0; - last0->dw_loc_next != NULL; - last0 = last0->dw_loc_next) - ; - for (last1 = op1; - last1->dw_loc_next != NULL; - last1 = last1->dw_loc_next) - ; - if (CONST_INT_P (XEXP (rtl, 0))) - op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask); - /* deref_size zero extends, so no need to mask it again. */ - else if (last0->dw_loc_opc != DW_OP_deref_size - || last0->dw_loc_oprnd1.v.val_int - > GET_MODE_SIZE (op_mode)) - { - add_loc_descr (&op0, int_loc_descriptor (mask)); - add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); - } - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask); - /* deref_size zero extends, so no need to mask it again. */ - else if (last1->dw_loc_opc != DW_OP_deref_size - || last1->dw_loc_oprnd1.v.val_int - > GET_MODE_SIZE (op_mode)) - { - add_loc_descr (&op1, int_loc_descriptor (mask)); - add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0)); - } - } - else - { - HOST_WIDE_INT bias = 1; - bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1); - add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0)); - if (CONST_INT_P (XEXP (rtl, 1))) - op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias - + INTVAL (XEXP (rtl, 1))); - else - add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, - bias, 0)); - } - } + op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); + + if (op0 == 0 || op1 == 0) + break; + + if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE) + { + HOST_WIDE_INT mask = GET_MODE_MASK (op_mode); + dw_loc_descr_ref last0, last1; + for (last0 = op0; + last0->dw_loc_next != NULL; + last0 = last0->dw_loc_next) + ; + for (last1 = op1; + last1->dw_loc_next != NULL; + last1 = last1->dw_loc_next) + ; + if (CONST_INT_P (XEXP (rtl, 0))) + op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask); + /* deref_size zero extends, so no need to mask it again. */ + else if (last0->dw_loc_opc != DW_OP_deref_size + || last0->dw_loc_oprnd1.v.val_int + > GET_MODE_SIZE (op_mode)) + { + add_loc_descr (&op0, int_loc_descriptor (mask)); + add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); + } + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask); + /* deref_size zero extends, so no need to mask it again. */ + else if (last1->dw_loc_opc != DW_OP_deref_size + || last1->dw_loc_oprnd1.v.val_int + > GET_MODE_SIZE (op_mode)) + { + add_loc_descr (&op1, int_loc_descriptor (mask)); + add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0)); + } + } + else if (GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE) + { + HOST_WIDE_INT bias = 1; + bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1); + add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0)); + if (CONST_INT_P (XEXP (rtl, 1))) + op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias + + INTVAL (XEXP (rtl, 1))); + else + add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, + bias, 0)); + } + else + { + dw_die_ref type_die = base_type_for_mode (mode, 1); + dw_loc_descr_ref cvt; + + if (type_die == NULL) + break; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op1, cvt); + } + } goto do_compare; - case SMIN: - case SMAX: case UMIN: case UMAX: - if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT - || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE - || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1))) + if (GET_MODE_CLASS (mode) != MODE_INT) + break; + /* FALLTHRU */ + case SMIN: + case SMAX: + if (dwarf_strict + && (GET_MODE_CLASS (mode) != MODE_INT + || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)) break; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0 || op1 == 0) @@ -14164,26 +14630,44 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0)); if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX) { - if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE) + if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE) { - HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0))); + HOST_WIDE_INT mask = GET_MODE_MASK (mode); add_loc_descr (&op0, int_loc_descriptor (mask)); add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0)); add_loc_descr (&op1, int_loc_descriptor (mask)); add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0)); } - else + else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE) { HOST_WIDE_INT bias = 1; bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1); add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0)); add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0)); } + else + { + dw_die_ref type_die = base_type_for_mode (mode, 1); + dw_loc_descr_ref cvt; + + if (type_die == NULL) + break; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op1, cvt); + } } - else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE) + else if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE) { - int shift = DWARF2_ADDR_SIZE - - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))); + int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode); shift *= BITS_PER_UNIT; add_loc_descr (&op0, int_loc_descriptor (shift)); add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0)); @@ -14217,13 +14701,14 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, && CONST_INT_P (XEXP (rtl, 2)) && ((unsigned) INTVAL (XEXP (rtl, 1)) + (unsigned) INTVAL (XEXP (rtl, 2)) - <= GET_MODE_BITSIZE (GET_MODE (rtl))) - && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE + <= GET_MODE_BITSIZE (mode)) + && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE) { int shift, size; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); + op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)), + mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == 0) break; if (GET_CODE (rtl) == SIGN_EXTRACT) @@ -14255,11 +14740,13 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case IF_THEN_ELSE: { dw_loc_descr_ref op2, bra_node, drop_node; - op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, - VAR_INIT_STATUS_INITIALIZED); - op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + op0 = mem_loc_descriptor (XEXP (rtl, 0), + GET_MODE (XEXP (rtl, 0)) == VOIDmode + ? word_mode : GET_MODE (XEXP (rtl, 0)), + mem_mode, VAR_INIT_STATUS_INITIALIZED); + op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); - op2 = mem_loc_descriptor (XEXP (rtl, 2), mode, + op2 = mem_loc_descriptor (XEXP (rtl, 2), mode, mem_mode, VAR_INIT_STATUS_INITIALIZED); if (op0 == NULL || op1 == NULL || op2 == NULL) break; @@ -14277,6 +14764,70 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, } break; + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case UNSIGNED_FLOAT: + case FIX: + case UNSIGNED_FIX: + if (!dwarf_strict) + { + dw_die_ref type_die; + dw_loc_descr_ref cvt; + + op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)), + mem_mode, VAR_INIT_STATUS_INITIALIZED); + if (op0 == NULL) + break; + if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) == MODE_INT + && (GET_CODE (rtl) == UNSIGNED_FLOAT + || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) + <= DWARF2_ADDR_SIZE)) + { + type_die = base_type_for_mode (GET_MODE (XEXP (rtl, 0)), + GET_CODE (rtl) == UNSIGNED_FLOAT); + if (type_die == NULL) + break; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + } + type_die = base_type_for_mode (mode, GET_CODE (rtl) == UNSIGNED_FIX); + if (type_die == NULL) + break; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + if (GET_MODE_CLASS (mode) == MODE_INT + && (GET_CODE (rtl) == UNSIGNED_FIX + || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)) + { + enum machine_mode outer_mode = mode; + if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE) + { + outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT, + MODE_INT, 0); + if (outer_mode == BLKmode + || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE) + break; + } + type_die = base_type_for_mode (outer_mode, 0); + if (type_die == NULL) + break; + cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr (&op0, cvt); + } + mem_loc_result = op0; + } + break; + case COMPARE: case ROTATE: case ROTATERT: @@ -14308,12 +14859,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case UNLE: case UNLT: case LTGT: - case FLOAT_EXTEND: - case FLOAT_TRUNCATE: - case FLOAT: - case UNSIGNED_FLOAT: - case FIX: - case UNSIGNED_FIX: case FRACT_CONVERT: case UNSIGNED_FRACT_CONVERT: case SAT_FRACT: @@ -14332,6 +14877,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case VEC_DUPLICATE: case UNSPEC: case HIGH: + case FMA: + case STRICT_LOW_PART: + case CONST_VECTOR: + case CONST_FIXED: /* If delegitimize_address couldn't do anything with the UNSPEC, we can't express it in the debug info. This can happen e.g. with some TLS UNSPECs. */ @@ -14469,7 +15018,10 @@ loc_descriptor (rtx rtl, enum machine_mode mode, up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized); + if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl)) + loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized); + else + goto do_default; break; case REG: @@ -14477,8 +15029,8 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case MEM: - loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), - initialized); + loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl), + GET_MODE (rtl), initialized); if (loc_result == NULL) loc_result = tls_mem_loc_descriptor (rtl); if (loc_result == NULL) @@ -14673,13 +15225,15 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; } /* FALLTHRU */ + do_default: default: - if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode - && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE - && (dwarf_version >= 4 || !dwarf_strict)) + if ((GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode + && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE + && dwarf_version >= 4) + || (!dwarf_strict && mode != VOIDmode && mode != BLKmode)) { /* Value expression. */ - loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized); + loc_result = mem_loc_descriptor (rtl, mode, VOIDmode, initialized); if (loc_result) add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); @@ -14754,18 +15308,20 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address, if (MEM_P (varloc)) { rtx addr = XEXP (varloc, 0); - descr = mem_loc_descriptor (addr, mode, initialized); + descr = mem_loc_descriptor (addr, get_address_mode (varloc), + mode, initialized); if (descr) have_address = 1; else { rtx x = avoid_constant_pool_reference (varloc); if (x != varloc) - descr = mem_loc_descriptor (x, mode, initialized); + descr = mem_loc_descriptor (x, mode, VOIDmode, + initialized); } } else - descr = mem_loc_descriptor (varloc, mode, initialized); + descr = mem_loc_descriptor (varloc, mode, VOIDmode, initialized); } else return 0; @@ -15187,7 +15743,6 @@ cst_pool_loc_descr (tree loc) { /* Get an RTL for this, if something has been emitted. */ rtx rtl = lookup_constant_def (loc); - enum machine_mode mode; if (!rtl || !MEM_P (rtl)) { @@ -15205,9 +15760,8 @@ cst_pool_loc_descr (tree loc) "CST value in contant pool but not marked."); return 0; } - mode = GET_MODE (rtl); - rtl = XEXP (rtl, 0); - return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + return mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl), + GET_MODE (rtl), VAR_INIT_STATUS_INITIALIZED); } /* Return dw_loc_list representing address of addr_expr LOC @@ -15452,7 +16006,7 @@ loc_list_from_tree (tree loc, int want_address) } else { - enum machine_mode mode; + enum machine_mode mode, mem_mode; /* Certain constructs can only be represented at top-level. */ if (want_address == 2) @@ -15464,12 +16018,16 @@ loc_list_from_tree (tree loc, int want_address) else { mode = GET_MODE (rtl); + mem_mode = VOIDmode; if (MEM_P (rtl)) { + mem_mode = mode; + mode = get_address_mode (rtl); rtl = XEXP (rtl, 0); have_address = 1; } - ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + ret = mem_loc_descriptor (rtl, mode, mem_mode, + VAR_INIT_STATUS_INITIALIZED); } if (!ret) expansion_failed (loc, rtl, @@ -19513,8 +20071,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (mode == VOIDmode) mode = GET_MODE (XEXP (arg, 0)); } - if (GET_MODE_CLASS (mode) != MODE_INT - || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + if (mode == VOIDmode || mode == BLKmode) continue; if (XEXP (XEXP (arg, 0), 0) == pc_rtx) { @@ -19533,14 +20090,19 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0), VAR_INIT_STATUS_INITIALIZED); else if (MEM_P (XEXP (XEXP (arg, 0), 0))) - reg = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 0), - 0), 0), mode, - VAR_INIT_STATUS_INITIALIZED); + { + rtx mem = XEXP (XEXP (arg, 0), 0); + reg = mem_loc_descriptor (XEXP (mem, 0), + get_address_mode (mem), + GET_MODE (mem), + VAR_INIT_STATUS_INITIALIZED); + } else continue; if (reg == NULL) continue; - val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), VOIDmode, + val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode, + VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (val == NULL) continue; @@ -19552,8 +20114,12 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) add_AT_loc (cdie, DW_AT_GNU_call_site_value, val); if (next_arg != XEXP (arg, 1)) { + mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1)); + if (mode == VOIDmode) + mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0)); val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1), - 0), 1), VOIDmode, + 0), 1), + mode, VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (val != NULL) add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val); @@ -19567,13 +20133,19 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) dw_loc_descr_ref tval = NULL; if (tloc != NULL_RTX) - tval = mem_loc_descriptor (tloc, VOIDmode, + tval = mem_loc_descriptor (tloc, + GET_MODE (tloc) == VOIDmode + ? Pmode : GET_MODE (tloc), + VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (tval) add_AT_loc (die, DW_AT_GNU_call_site_target, tval); else if (tlocc != NULL_RTX) { - tval = mem_loc_descriptor (tlocc, VOIDmode, + tval = mem_loc_descriptor (tlocc, + GET_MODE (tlocc) == VOIDmode + ? Pmode : GET_MODE (tlocc), + VOIDmode, VAR_INIT_STATUS_INITIALIZED); if (tval) add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered, @@ -22838,6 +23410,7 @@ prune_unused_types (void) limbo_die_node *node; comdat_type_node *ctnode; pubname_ref pub; + dw_die_ref base_type; #if ENABLE_ASSERT_CHECKING /* All the marks should already be clear. */ @@ -22865,6 +23438,8 @@ prune_unused_types (void) pubname_table. */ FOR_EACH_VEC_ELT (pubname_entry, pubname_table, i, pub) prune_unused_types_mark (pub->die, 1); + for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++) + prune_unused_types_mark (base_type, 1); /* Get rid of nodes that aren't marked; and update the string counts. */ if (debug_str_hash && debug_str_hash_forced) @@ -22953,6 +23528,117 @@ move_linkage_attr (dw_die_ref die) } } +/* Helper function for resolve_addr, mark DW_TAG_base_type nodes + referenced from typed stack ops and count how often they are used. */ + +static void +mark_base_types (dw_loc_descr_ref loc) +{ + dw_die_ref base_type = NULL; + + for (; loc; loc = loc->dw_loc_next) + { + switch (loc->dw_loc_opc) + { + case DW_OP_GNU_regval_type: + case DW_OP_GNU_deref_type: + base_type = loc->dw_loc_oprnd2.v.val_die_ref.die; + break; + case DW_OP_GNU_const_type: + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + base_type = loc->dw_loc_oprnd1.v.val_die_ref.die; + break; + case DW_OP_GNU_entry_value: + mark_base_types (loc->dw_loc_oprnd1.v.val_loc); + continue; + default: + continue; + } + gcc_assert (base_type->die_parent == comp_unit_die ()); + if (base_type->die_mark) + base_type->die_mark++; + else + { + VEC_safe_push (dw_die_ref, heap, base_types, base_type); + base_type->die_mark = 1; + } + } +} + +/* Comparison function for sorting marked base types. */ + +static int +base_type_cmp (const void *x, const void *y) +{ + dw_die_ref dx = *(const dw_die_ref *) x; + dw_die_ref dy = *(const dw_die_ref *) y; + unsigned int byte_size1, byte_size2; + unsigned int encoding1, encoding2; + if (dx->die_mark > dy->die_mark) + return -1; + if (dx->die_mark < dy->die_mark) + return 1; + byte_size1 = get_AT_unsigned (dx, DW_AT_byte_size); + byte_size2 = get_AT_unsigned (dy, DW_AT_byte_size); + if (byte_size1 < byte_size2) + return 1; + if (byte_size1 > byte_size2) + return -1; + encoding1 = get_AT_unsigned (dx, DW_AT_encoding); + encoding2 = get_AT_unsigned (dy, DW_AT_encoding); + if (encoding1 < encoding2) + return 1; + if (encoding1 > encoding2) + return -1; + return 0; +} + +/* Move base types marked by mark_base_types as early as possible + in the CU, sorted by decreasing usage count both to make the + uleb128 references as small as possible and to make sure they + will have die_offset already computed by calc_die_sizes when + sizes of typed stack loc ops is computed. */ + +static void +move_marked_base_types (void) +{ + unsigned int i; + dw_die_ref base_type, die, c; + + if (VEC_empty (dw_die_ref, base_types)) + return; + + /* Sort by decreasing usage count, they will be added again in that + order later on. */ + VEC_qsort (dw_die_ref, base_types, base_type_cmp); + die = comp_unit_die (); + c = die->die_child; + do + { + dw_die_ref prev = c; + c = c->die_sib; + while (c->die_mark) + { + remove_child_with_prev (c, prev); + /* As base types got marked, there must be at least + one node other than DW_TAG_base_type. */ + gcc_assert (c != c->die_sib); + c = c->die_sib; + } + } + while (c != die->die_child); + gcc_assert (die->die_child); + c = die->die_child; + for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++) + { + base_type->die_mark = 0; + base_type->die_sib = c->die_sib; + c->die_sib = base_type; + c = base_type; + } +} + /* Helper function for resolve_addr, attempt to resolve one CONST_STRING, return non-zero if not successful. Similarly verify that SYMBOL_REFs refer to variables emitted in the current CU. */ @@ -23073,7 +23759,10 @@ resolve_addr (dw_die_ref die) *curr = next; } else - curr = &(*curr)->dw_loc_next; + { + mark_base_types ((*curr)->expr); + curr = &(*curr)->dw_loc_next; + } } if (loc == *start) loc->resolved_addr = 1; @@ -23095,6 +23784,8 @@ resolve_addr (dw_die_ref die) remove_AT (die, a->dw_attr); ix--; } + else + mark_base_types (AT_loc (a)); break; case dw_val_class_addr: if (a->dw_attr == DW_AT_const_value @@ -23262,6 +23953,56 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash) case DW_OP_GNU_entry_value: hash = hash_loc_operands (val1->v.val_loc, hash); break; + case DW_OP_GNU_regval_type: + case DW_OP_GNU_deref_type: + { + unsigned int byte_size + = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_byte_size); + unsigned int encoding + = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_encoding); + hash = iterative_hash_object (val1->v.val_int, hash); + hash = iterative_hash_object (byte_size, hash); + hash = iterative_hash_object (encoding, hash); + } + break; + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + case DW_OP_GNU_const_type: + { + unsigned int byte_size + = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_byte_size); + unsigned int encoding + = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_encoding); + hash = iterative_hash_object (byte_size, hash); + hash = iterative_hash_object (encoding, hash); + if (loc->dw_loc_opc != DW_OP_GNU_const_type) + break; + hash = iterative_hash_object (val2->val_class, hash); + switch (val2->val_class) + { + case dw_val_class_const: + hash = iterative_hash_object (val2->v.val_int, hash); + break; + case dw_val_class_vec: + { + unsigned int elt_size = val2->v.val_vec.elt_size; + unsigned int len = val2->v.val_vec.length; + + hash = iterative_hash_object (elt_size, hash); + hash = iterative_hash_object (len, hash); + hash = iterative_hash (val2->v.val_vec.array, + len * elt_size, hash); + } + break; + case dw_val_class_const_double: + hash = iterative_hash_object (val2->v.val_double.low, hash); + hash = iterative_hash_object (val2->v.val_double.high, hash); + break; + default: + gcc_unreachable (); + } + } + break; default: /* Other codes have no operands. */ @@ -23421,6 +24162,33 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) && valx2->v.val_int == valy2->v.val_int; case DW_OP_GNU_entry_value: return compare_loc_operands (valx1->v.val_loc, valy1->v.val_loc); + case DW_OP_GNU_const_type: + if (valx1->v.val_die_ref.die != valy1->v.val_die_ref.die + || valx2->val_class != valy2->val_class) + return false; + switch (valx2->val_class) + { + case dw_val_class_const: + return valx2->v.val_int == valy2->v.val_int; + case dw_val_class_vec: + return valx2->v.val_vec.elt_size == valy2->v.val_vec.elt_size + && valx2->v.val_vec.length == valy2->v.val_vec.length + && memcmp (valx2->v.val_vec.array, valy2->v.val_vec.array, + valx2->v.val_vec.elt_size + * valx2->v.val_vec.length) == 0; + case dw_val_class_const_double: + return valx2->v.val_double.low == valy2->v.val_double.low + && valx2->v.val_double.high == valy2->v.val_double.high; + default: + gcc_unreachable (); + } + case DW_OP_GNU_regval_type: + case DW_OP_GNU_deref_type: + return valx1->v.val_int == valy1->v.val_int + && valx2->v.val_die_ref.die == valy2->v.val_die_ref.die; + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die; default: /* Other codes have no operands. */ return true; @@ -23602,7 +24370,14 @@ dwarf2out_finish (const char *filename) limbo_die_list = NULL; +#if ENABLE_ASSERT_CHECKING + { + dw_die_ref die = comp_unit_die (), c; + FOR_EACH_CHILD (die, c, gcc_assert (! c->die_mark)); + } +#endif resolve_addr (comp_unit_die ()); + move_marked_base_types (); for (node = deferred_asm_name; node; node = node->next) { diff --git a/include/ChangeLog b/include/ChangeLog index fcabfb8384c0..7ad246e44a70 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2011-04-30 Jakub Jelinek + + * dwarf2.h (DW_OP_GNU_const_type, DW_OP_GNU_regval_type, + DW_OP_GNU_deref_type, DW_OP_GNU_convert, DW_OP_GNU_reinterpret): New. + 2011-04-25 Jan Kratochvil * ansidecl.h (ENUM_BITFIELD): New, from gcc/system.h. diff --git a/include/dwarf2.h b/include/dwarf2.h index 44b4328de5a3..0b008661f964 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -556,6 +556,13 @@ enum dwarf_location_atom /* The GNU entry value extension. See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open . */ DW_OP_GNU_entry_value = 0xf3, + /* The GNU typed stack extension. + See http://www.dwarfstd.org/doc/040408.1.html . */ + DW_OP_GNU_const_type = 0xf4, + DW_OP_GNU_regval_type = 0xf5, + DW_OP_GNU_deref_type = 0xf6, + DW_OP_GNU_convert = 0xf7, + DW_OP_GNU_reinterpret = 0xf9, /* HP extensions. */ DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ DW_OP_HP_is_value = 0xe1, -- 2.43.5