2002-08-21 Richard Henderson * config/i386/i386-protos.h (i386_output_dwarf_dtprel): Add prototype. * config/i386/i386.c (i386_output_dwarf_dtprel): New. * config/i386/i386.h (ASM_OUTPUT_DWARF_DTPREL): Define. * dwarf2.h (DW_OP_GNU_push_tls_address): Add. (DW_OP_lo_user): Define to 0xe0. * dwarf2out.c (INTERNAL_DW_OP_tls_addr): Define. (dwarf_stack_op_name, sizeof_loc_descr): Handle a few more OPs. (output_loc_operands): Handle INTERNAL_DW_OP_tls_addr. (loc_descriptor_from_tree): Handle DECL_THREAD_LOCAL variables. (add_AT_location_description): Pass descr instead of rtl. (add_location_or_const_value_attribute, add_bound_info, gen_subprogram_die): Adjust its callers. (rtl_for_decl_location): Avoid constant pool references. --- gcc/config/i386/i386-protos.h 20 Aug 2002 17:20:36 -0000 1.1.1.1 +++ gcc/config/i386/i386-protos.h 20 Aug 2002 22:35:02 -0000 @@ -113,6 +113,7 @@ extern const char *output_fix_trunc PARA extern const char *output_fp_compare PARAMS ((rtx, rtx*, int, int)); extern void i386_dwarf_output_addr_const PARAMS ((FILE*, rtx)); +extern void i386_output_dwarf_dtprel PARAMS ((FILE*, int, rtx)); extern rtx i386_simplify_dwarf_addr PARAMS ((rtx)); extern void ix86_expand_clear PARAMS ((rtx)); --- gcc/config/i386/i386.c 20 Aug 2002 17:20:36 -0000 1.1.1.1 +++ gcc/config/i386/i386.c 20 Aug 2002 22:35:02 -0000 @@ -5921,6 +5921,33 @@ i386_dwarf_output_addr_const (file, x) fputc ('\n', file); } +/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL. + We need to emit DTP-relative relocations. */ + +void +i386_output_dwarf_dtprel (file, size, x) + FILE *file; + int size; + rtx x; +{ + switch (size) + { + case 4: + fputs (ASM_LONG, file); + break; + case 8: +#ifdef ASM_QUAD + fputs (ASM_QUAD, file); + break; +#endif + default: + abort (); + } + + output_addr_const (file, x); + fputs ("@DTPOFF", file); +} + /* In the name of slightly smaller debug output, and to cater to general assembler losage, recognize PIC+GOTOFF and turn it back into a direct symbol reference. */ --- gcc/config/i386/i386.h 20 Aug 2002 17:20:36 -0000 1.1.1.1 +++ gcc/config/i386/i386.h 20 Aug 2002 22:35:02 -0000 @@ -2899,6 +2899,13 @@ extern int const svr4_dbx_register_map[F #define ASM_SIMPLIFY_DWARF_ADDR(X) \ i386_simplify_dwarf_addr (X) +/* Emit a dtp-relative reference to a TLS variable. */ + +#ifdef HAVE_AS_TLS +#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \ + i386_output_dwarf_dtprel (FILE, SIZE, X) +#endif + /* Switch to init or fini section via SECTION_OP, emit a call to FUNC, and switch back. For x86 we do this only to save a few bytes that would otherwise be unused in the text section. */ --- gcc/dwarf2.h 20 Aug 2002 17:20:19 -0000 1.1.1.1 +++ gcc/dwarf2.h 20 Aug 2002 22:35:02 -0000 @@ -399,10 +399,12 @@ enum dwarf_location_atom DW_OP_push_object_address = 0x97, DW_OP_call2 = 0x98, DW_OP_call4 = 0x99, - DW_OP_calli = 0x9a + DW_OP_call_ref = 0x9a, + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0 }; -#define DW_OP_lo_user 0x80 /* Implementation-defined range start. */ +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ #define DW_OP_hi_user 0xff /* Implementation-defined range end. */ /* Type encodings. */ --- gcc/dwarf2out.c 20 Aug 2002 17:20:19 -0000 1.1.1.1 +++ gcc/dwarf2out.c 20 Aug 2002 22:40:42 -0000 @@ -2169,6 +2169,11 @@ dwarf2out_frame_finish () /* And now, the subset of the debugging information support code necessary for emitting location expressions. */ +/* We need some way to distinguish DW_OP_addr with a direct symbol + relocation from DW_OP_addr with a dtp-relative symbol relocation. */ +#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr) + + typedef struct dw_val_struct *dw_val_ref; typedef struct die_struct *dw_die_ref; typedef struct dw_loc_descr_struct *dw_loc_descr_ref; @@ -2294,6 +2299,7 @@ dwarf_stack_op_name (op) switch (op) { case DW_OP_addr: + case INTERNAL_DW_OP_tls_addr: return "DW_OP_addr"; case DW_OP_deref: return "DW_OP_deref"; @@ -2583,6 +2589,16 @@ dwarf_stack_op_name (op) return "DW_OP_xderef_size"; case DW_OP_nop: return "DW_OP_nop"; + case DW_OP_push_object_address: + return "DW_OP_push_object_address"; + case DW_OP_call2: + return "DW_OP_call2"; + case DW_OP_call4: + return "DW_OP_call4"; + case DW_OP_call_ref: + return "DW_OP_call_ref"; + case DW_OP_GNU_push_tls_address: + return "DW_OP_GNU_push_tls_address"; default: return "OP_"; } @@ -2640,6 +2656,7 @@ size_of_loc_descr (loc) switch (loc->dw_loc_opc) { case DW_OP_addr: + case INTERNAL_DW_OP_tls_addr: size += DWARF2_ADDR_SIZE; break; case DW_OP_const1u: @@ -2725,6 +2742,15 @@ size_of_loc_descr (loc) case DW_OP_xderef_size: size += 1; break; + case DW_OP_call2: + size += 2; + break; + case DW_OP_call4: + size += 4; + break; + case DW_OP_call_ref: + size += DWARF2_ADDR_SIZE; + break; default: break; } @@ -2874,6 +2900,17 @@ output_loc_operands (loc) case DW_OP_xderef_size: dw2_asm_output_data (1, val1->v.val_int, NULL); break; + + case INTERNAL_DW_OP_tls_addr: +#ifdef ASM_OUTPUT_DWARF_DTPREL + ASM_OUTPUT_DWARF_DTPREL (asm_out_file, DWARF2_ADDR_SIZE, + val1->v.val_addr); + fputc ('\n', asm_out_file); +#else + abort (); +#endif + break; + default: /* Other codes have no operands. */ break; @@ -3598,7 +3635,8 @@ static unsigned int simple_field_decl_al static unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree)); static HOST_WIDE_INT field_byte_offset PARAMS ((tree)); static void add_AT_location_description PARAMS ((dw_die_ref, - enum dwarf_attribute, rtx)); + enum dwarf_attribute, + dw_loc_descr_ref)); static void add_data_member_location_attribute PARAMS ((dw_die_ref, tree)); static void add_const_value_attribute PARAMS ((dw_die_ref, rtx)); static rtx rtl_for_decl_location PARAMS ((tree)); @@ -8031,6 +8069,41 @@ loc_descriptor_from_tree (loc, addressp) : 0); case VAR_DECL: + if (DECL_THREAD_LOCAL (loc)) + { + rtx rtl; + +#ifndef ASM_OUTPUT_DWARF_DTPREL + /* If this is not defined, we have no way to emit the data. */ + return 0; +#endif + /* The way DW_OP_GNU_push_tls_address is specified, we can only + look up addresses of objects in the current module. */ + if (DECL_P (loc) && TREE_PUBLIC (loc) && !MODULE_LOCAL_P (loc)) + return 0; + + rtl = rtl_for_decl_location (loc); + if (rtl == NULL_RTX) + return 0; + + if (GET_CODE (rtl) != MEM) + return 0; + rtl = XEXP (rtl, 0); + if (! CONSTANT_P (rtl)) + return 0; + + ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0); + ret->dw_loc_oprnd1.val_class = dw_val_class_addr; + ret->dw_loc_oprnd1.v.val_addr = rtl; + + ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); + add_loc_descr (&ret, ret1); + + indirect_p = 1; + break; + } + /* FALLTHRU */ + case PARM_DECL: { rtx rtl = rtl_for_decl_location (loc); @@ -8531,14 +8604,12 @@ field_byte_offset (decl) whole parameters. Note that the location attributes for struct fields are generated by the routine `data_member_location_attribute' below. */ -static void -add_AT_location_description (die, attr_kind, rtl) +static inline void +add_AT_location_description (die, attr_kind, descr) dw_die_ref die; enum dwarf_attribute attr_kind; - rtx rtl; + dw_loc_descr_ref descr; { - dw_loc_descr_ref descr = loc_descriptor (rtl); - if (descr != 0) add_AT_loc (die, attr_kind, descr); } @@ -8963,6 +9034,13 @@ rtl_for_decl_location (decl) if (rtl) rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl); #endif + + /* If we don't look past the constant pool, we risk emitting a + reference to a constant pool entry that isn't referenced from + code, and thus is not emitted. */ + if (rtl) + rtl = avoid_constant_pool_reference (rtl); + return rtl; } @@ -8983,6 +9061,7 @@ add_location_or_const_value_attribute (d tree decl; { rtx rtl; + dw_loc_descr_ref descr; if (TREE_CODE (decl) == ERROR_MARK) return; @@ -8993,16 +9072,11 @@ add_location_or_const_value_attribute (d if (rtl == NULL_RTX) return; - /* If we don't look past the constant pool, we risk emitting a - reference to a constant pool entry that isn't referenced from - code, and thus is not emitted. */ - rtl = avoid_constant_pool_reference (rtl); - switch (GET_CODE (rtl)) { case ADDRESSOF: - /* The address of a variable that was optimized away; don't emit - anything. */ + /* The address of a variable that was optimized away; + don't emit anything. */ break; case CONST_INT: @@ -9017,12 +9091,24 @@ add_location_or_const_value_attribute (d break; case MEM: - case REG: - case SUBREG: - case CONCAT: - add_AT_location_description (die, DW_AT_location, rtl); + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) + { + /* Need loc_descriptor_from_tree since that's where we know + how to handle TLS variables. Want the object's address + since the top-level DW_AT_location assumes such. See + the confusion in loc_descriptor for reference. */ + descr = loc_descriptor_from_tree (decl, 1); + } + else + { + case REG: + case SUBREG: + case CONCAT: + descr = loc_descriptor (rtl); + } + add_AT_location_description (die, DW_AT_location, descr); break; - + default: abort (); } @@ -9154,7 +9240,8 @@ add_bound_info (subrange_die, bound_attr add_AT_flag (decl_die, DW_AT_artificial, 1); add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); - add_AT_location_description (decl_die, DW_AT_location, loc); + add_AT_location_description (decl_die, DW_AT_location, + loc_descriptor (loc)); add_AT_die_ref (subrange_die, bound_attr, decl_die); } @@ -10359,7 +10446,7 @@ gen_subprogram_die (decl, context_die) is not part of the state saved/restored for inline functions. */ if (current_function_needs_context) add_AT_location_description (subr_die, DW_AT_static_link, - lookup_static_chain (decl)); + loc_descriptor (lookup_static_chain (decl))); #endif }