From 0cf856b72826d6c8888a5570716596242bf2085c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 25 Jul 2009 01:30:39 +0200 Subject: [PATCH] re PR rtl-optimization/34999 (Incorrect FDE entries with hot/cold code section splitting (partition_hot_cold_basic_blocks)) PR rtl-optimization/34999 * dwarf2out.c (struct dw_fde_struct): Add dw_fde_switch_cfi and dw_fde_switched_cold_to_hot fields. (output_cfi_p): New function. (output_call_frame_info): If fde->dw_fde_switched_sections, output 2 FDEs instead of one with corrupted header. (dwarf2out_do_cfi_startproc): New function. (dwarf2out_begin_prologue): Use it. Initialize fde->dw_fde_switch_cfi and fde->dw_fde_switched_cold_to_hot. (dwarf2out_switch_text_section): Compute fde->dw_fde_switched_cold_to_hot. Switch to new text section here. If dwarf2out_do_cfi_asm, emit .cfi_endproc before it and call dwarf2out_do_cfi_startproc plus emit again currently active CFI insns. Otherwise, compute fde->dw_fde_switch_cfi. From-SVN: r150069 --- gcc/ChangeLog | 17 ++ gcc/dwarf2out.c | 413 ++++++++++++++++++++++++++++++------------------ 2 files changed, 279 insertions(+), 151 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0647513b03f..948f2fa6fda 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2009-07-25 Jakub Jelinek + + PR rtl-optimization/34999 + * dwarf2out.c (struct dw_fde_struct): Add dw_fde_switch_cfi + and dw_fde_switched_cold_to_hot fields. + (output_cfi_p): New function. + (output_call_frame_info): If fde->dw_fde_switched_sections, + output 2 FDEs instead of one with corrupted header. + (dwarf2out_do_cfi_startproc): New function. + (dwarf2out_begin_prologue): Use it. Initialize fde->dw_fde_switch_cfi + and fde->dw_fde_switched_cold_to_hot. + (dwarf2out_switch_text_section): Compute + fde->dw_fde_switched_cold_to_hot. Switch to new text section here. + If dwarf2out_do_cfi_asm, emit .cfi_endproc before it and call + dwarf2out_do_cfi_startproc plus emit again currently active CFI insns. + Otherwise, compute fde->dw_fde_switch_cfi. + 2009-07-24 Cary Coutant * tree-cfg.c (assign_discriminator): Add explicit parentheses. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 2c5d0562562..c6211620446 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -268,8 +268,8 @@ typedef struct GTY(()) dw_fde_struct { const char *dw_fde_hot_section_end_label; const char *dw_fde_unlikely_section_label; const char *dw_fde_unlikely_section_end_label; - bool dw_fde_switched_sections; dw_cfi_ref dw_fde_cfi; + dw_cfi_ref dw_fde_switch_cfi; /* Last CFI before switching sections. */ unsigned funcdef_number; HOST_WIDE_INT stack_realignment; /* Dynamic realign argument pointer register. */ @@ -288,6 +288,10 @@ typedef struct GTY(()) dw_fde_struct { /* True iff dw_fde_unlikely_section_label is in text_section or cold_text_section. */ unsigned cold_in_std_section : 1; + /* True iff switched sections. */ + unsigned dw_fde_switched_sections : 1; + /* True iff switching from cold to hot section. */ + unsigned dw_fde_switched_cold_to_hot : 1; } dw_fde_node; @@ -3210,6 +3214,57 @@ output_cfi_directive (dw_cfi_ref cfi) } } +/* Return true if *CFIP should be output after switching sections. */ + +static bool +output_cfi_p (dw_cfi_ref *cfip, dw_cfi_ref *cfi_args_sizep) +{ + dw_cfi_ref cfi = *cfip, cfi2; + + switch (cfi->dw_cfi_opc) + { + case DW_CFA_advance_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + case DW_CFA_MIPS_advance_loc8: + case DW_CFA_set_loc: + /* All advances should be ignored. */ + return false; + case DW_CFA_remember_state: + /* Skip everything between .cfi_remember_state and + .cfi_restore_state. */ + for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next) + if (cfi2->dw_cfi_opc == DW_CFA_restore_state) + break; + else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size) + *cfi_args_sizep = cfi2; + else + gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state); + if (cfi2 == NULL) + return true; + *cfip = cfi2; + return false; + case DW_CFA_def_cfa_offset: + case DW_CFA_def_cfa_offset_sf: + /* Only keep the last of these if they are consecutive. */ + for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next) + if (cfi2->dw_cfi_opc == cfi->dw_cfi_opc) + *cfip = cfi2; + else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size) + *cfi_args_sizep = cfi2; + else + break; + return true; + case DW_CFA_GNU_args_size: + /* One DW_CFA_GNU_args_size, the last one, is enough. */ + *cfi_args_sizep = cfi; + return false; + default: + return true; + } +} + /* Output the call frame information used to record information that relates to calculating the frame pointer, and records the location of saved registers. */ @@ -3217,7 +3272,7 @@ output_cfi_directive (dw_cfi_ref cfi) static void output_call_frame_info (int for_eh) { - unsigned int i; + unsigned int i, j; dw_fde_ref fde; dw_cfi_ref cfi; char l1[20], l2[20], section_start_label[20]; @@ -3423,8 +3478,9 @@ output_call_frame_info (int for_eh) ASM_OUTPUT_LABEL (asm_out_file, l2); /* Loop through all of the FDE's. */ - for (i = 0; i < fde_table_in_use; i++) + for (i = 0, j = 0; i < fde_table_in_use; i++) { + unsigned int k; fde = &fde_table[i]; /* Don't emit EH unwind info for leaf functions that don't need it. */ @@ -3434,139 +3490,154 @@ output_call_frame_info (int for_eh) && !fde->uses_eh_lsda) continue; - targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh, /* empty */ 0); - targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2); - ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2); - ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2); - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh) - dw2_asm_output_data (4, 0xffffffff, - "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1, - "FDE Length"); - ASM_OUTPUT_LABEL (asm_out_file, l1); - - if (for_eh) - dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset"); - else - dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label, - debug_frame_section, "FDE CIE offset"); - - if (for_eh) + for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++) { - if (fde->dw_fde_switched_sections) + const char *begin, *end; + + targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh, + /* empty */ 0); + targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, + for_eh + j); + ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j); + ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j); + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh) + dw2_asm_output_data (4, 0xffffffff, "Initial length escape value" + " indicating 64-bit DWARF extension"); + dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1, + "FDE Length"); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + if (for_eh) + dw2_asm_output_delta (4, l1, section_start_label, + "FDE CIE offset"); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label, + debug_frame_section, "FDE CIE offset"); + + if (!fde->dw_fde_switched_sections) { - rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode, - fde->dw_fde_unlikely_section_label); - rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode, - fde->dw_fde_hot_section_label); - SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL; - SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL; - dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3, false, - "FDE initial location"); - dw2_asm_output_delta (size_of_encoded_value (fde_encoding), - fde->dw_fde_hot_section_end_label, - fde->dw_fde_hot_section_label, - "FDE address range"); - dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2, false, - "FDE initial location"); - dw2_asm_output_delta (size_of_encoded_value (fde_encoding), - fde->dw_fde_unlikely_section_end_label, - fde->dw_fde_unlikely_section_label, - "FDE address range"); + begin = fde->dw_fde_begin; + end = fde->dw_fde_end; + } + else if (k ^ fde->dw_fde_switched_cold_to_hot) + { + begin = fde->dw_fde_unlikely_section_label; + end = fde->dw_fde_unlikely_section_end_label; } else { - rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin); + begin = fde->dw_fde_hot_section_label; + end = fde->dw_fde_hot_section_end_label; + } + + if (for_eh) + { + rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin); SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL; dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false, "FDE initial location"); dw2_asm_output_delta (size_of_encoded_value (fde_encoding), - fde->dw_fde_end, fde->dw_fde_begin, - "FDE address range"); - } - } - else - { - if (fde->dw_fde_switched_sections) - { - dw2_asm_output_addr (DWARF2_ADDR_SIZE, - fde->dw_fde_hot_section_label, - "FDE initial location"); - dw2_asm_output_delta (DWARF2_ADDR_SIZE, - fde->dw_fde_hot_section_end_label, - fde->dw_fde_hot_section_label, - "FDE address range"); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, - fde->dw_fde_unlikely_section_label, - "FDE initial location"); - dw2_asm_output_delta (DWARF2_ADDR_SIZE, - fde->dw_fde_unlikely_section_end_label, - fde->dw_fde_unlikely_section_label, - "FDE address range"); + end, begin, "FDE address range"); } else { - dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin, + dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location"); - dw2_asm_output_delta (DWARF2_ADDR_SIZE, - fde->dw_fde_end, fde->dw_fde_begin, + dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range"); } - } - if (augmentation[0]) - { - if (any_lsda_needed) + if (augmentation[0]) { - int size = size_of_encoded_value (lsda_encoding); - - if (lsda_encoding == DW_EH_PE_aligned) + if (any_lsda_needed) { - int offset = ( 4 /* Length */ - + 4 /* CIE offset */ - + 2 * size_of_encoded_value (fde_encoding) - + 1 /* Augmentation size */ ); - int pad = -offset & (PTR_SIZE - 1); - - size += pad; - gcc_assert (size_of_uleb128 (size) == 1); - } + int size = size_of_encoded_value (lsda_encoding); - dw2_asm_output_data_uleb128 (size, "Augmentation size"); + if (lsda_encoding == DW_EH_PE_aligned) + { + int offset = ( 4 /* Length */ + + 4 /* CIE offset */ + + 2 * size_of_encoded_value (fde_encoding) + + 1 /* Augmentation size */ ); + int pad = -offset & (PTR_SIZE - 1); + + size += pad; + gcc_assert (size_of_uleb128 (size) == 1); + } - if (fde->uses_eh_lsda) - { - ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA", - fde->funcdef_number); - dw2_asm_output_encoded_addr_rtx ( - lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1), - false, "Language Specific Data Area"); + dw2_asm_output_data_uleb128 (size, "Augmentation size"); + + if (fde->uses_eh_lsda) + { + ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA", + fde->funcdef_number); + dw2_asm_output_encoded_addr_rtx (lsda_encoding, + gen_rtx_SYMBOL_REF (Pmode, l1), + false, + "Language Specific Data Area"); + } + else + { + if (lsda_encoding == DW_EH_PE_aligned) + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); + dw2_asm_output_data ( + size_of_encoded_value (lsda_encoding), 0, + "Language Specific Data Area (none)"); + } } else + dw2_asm_output_data_uleb128 (0, "Augmentation size"); + } + + /* Loop through the Call Frame Instructions associated with + this FDE. */ + fde->dw_fde_current_label = begin; + if (!fde->dw_fde_switched_sections) + for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, fde, for_eh); + else if (k == 0) + { + if (fde->dw_fde_switch_cfi) + for (cfi = fde->dw_fde_cfi; cfi != NULL; + cfi = cfi->dw_cfi_next) + { + output_cfi (cfi, fde, for_eh); + if (cfi == fde->dw_fde_switch_cfi) + break; + } + } + else + { + dw_cfi_ref cfi_next = fde->dw_fde_cfi; + + if (fde->dw_fde_switch_cfi) { - if (lsda_encoding == DW_EH_PE_aligned) - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); - dw2_asm_output_data - (size_of_encoded_value (lsda_encoding), 0, - "Language Specific Data Area (none)"); + dw_cfi_ref cfi_args_size = NULL; + cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next; + fde->dw_fde_switch_cfi->dw_cfi_next = NULL; + for (cfi = fde->dw_fde_cfi; cfi != NULL; + cfi = cfi->dw_cfi_next) + if (output_cfi_p (&cfi, &cfi_args_size)) + output_cfi (cfi, fde, for_eh); + if (cfi_args_size + && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) + output_cfi (cfi_args_size, fde, for_eh); + fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next; } + for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next) + output_cfi (cfi, fde, for_eh); } - else - dw2_asm_output_data_uleb128 (0, "Augmentation size"); - } - /* Loop through the Call Frame Instructions associated with - this FDE. */ - fde->dw_fde_current_label = fde->dw_fde_begin; - for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + /* Pad the FDE out to an address sized boundary. */ + ASM_OUTPUT_ALIGN (asm_out_file, + floor_log2 ((for_eh + ? PTR_SIZE : DWARF2_ADDR_SIZE))); + ASM_OUTPUT_LABEL (asm_out_file, l2); - /* Pad the FDE out to an address sized boundary. */ - ASM_OUTPUT_ALIGN (asm_out_file, - floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE))); - ASM_OUTPUT_LABEL (asm_out_file, l2); + j += 2; + } } if (for_eh && targetm.terminate_dw2_eh_frame_info) @@ -3582,6 +3653,52 @@ output_call_frame_info (int for_eh) app_disable (); } +/* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed. */ + +static void +dwarf2out_do_cfi_startproc (void) +{ + int enc; + rtx ref; + + fprintf (asm_out_file, "\t.cfi_startproc\n"); + + if (eh_personality_libfunc) + { + enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); + ref = eh_personality_libfunc; + + /* ??? The GAS support isn't entirely consistent. We have to + handle indirect support ourselves, but PC-relative is done + in the assembler. Further, the assembler can't handle any + of the weirder relocation types. */ + if (enc & DW_EH_PE_indirect) + ref = dw2_force_const_mem (ref, true); + + fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc); + output_addr_const (asm_out_file, ref); + fputc ('\n', asm_out_file); + } + + if (crtl->uses_eh_lsda) + { + char lab[20]; + + enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0); + ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA", + current_function_funcdef_no); + ref = gen_rtx_SYMBOL_REF (Pmode, lab); + SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL; + + if (enc & DW_EH_PE_indirect) + ref = dw2_force_const_mem (ref, true); + + fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc); + output_addr_const (asm_out_file, ref); + fputc ('\n', asm_out_file); + } +} + /* Output a marker (i.e. a label) for the beginning of a function, before the prologue. */ @@ -3644,9 +3761,11 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, fde->dw_fde_hot_section_end_label = NULL; fde->dw_fde_unlikely_section_label = NULL; fde->dw_fde_unlikely_section_end_label = NULL; - fde->dw_fde_switched_sections = false; + fde->dw_fde_switched_sections = 0; + fde->dw_fde_switched_cold_to_hot = 0; fde->dw_fde_end = NULL; fde->dw_fde_cfi = NULL; + fde->dw_fde_switch_cfi = NULL; fde->funcdef_number = current_function_funcdef_no; fde->nothrow = crtl->nothrow; fde->uses_eh_lsda = crtl->uses_eh_lsda; @@ -3685,47 +3804,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, #endif if (dwarf2out_do_cfi_asm ()) - { - int enc; - rtx ref; - - fprintf (asm_out_file, "\t.cfi_startproc\n"); - - if (eh_personality_libfunc) - { - enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); - ref = eh_personality_libfunc; - - /* ??? The GAS support isn't entirely consistent. We have to - handle indirect support ourselves, but PC-relative is done - in the assembler. Further, the assembler can't handle any - of the weirder relocation types. */ - if (enc & DW_EH_PE_indirect) - ref = dw2_force_const_mem (ref, true); - - fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc); - output_addr_const (asm_out_file, ref); - fputc ('\n', asm_out_file); - } - - if (crtl->uses_eh_lsda) - { - char lab[20]; - - enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0); - ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA", - current_function_funcdef_no); - ref = gen_rtx_SYMBOL_REF (Pmode, lab); - SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL; - - if (enc & DW_EH_PE_indirect) - ref = dw2_force_const_mem (ref, true); - - fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc); - output_addr_const (asm_out_file, ref); - fputc ('\n', asm_out_file); - } - } + dwarf2out_do_cfi_startproc (); } /* Output a marker (i.e. a label) for the absolute end of the generated code @@ -3807,9 +3886,11 @@ dwarf2out_switch_text_section (void) { dw_fde_ref fde = current_fde (); - gcc_assert (cfun && fde); + gcc_assert (cfun && fde && !fde->dw_fde_switched_sections); + + fde->dw_fde_switched_sections = 1; + fde->dw_fde_switched_cold_to_hot = !in_cold_section_p; - fde->dw_fde_switched_sections = true; fde->dw_fde_hot_section_label = crtl->subsections.hot_section_label; fde->dw_fde_hot_section_end_label = crtl->subsections.hot_section_end_label; fde->dw_fde_unlikely_section_label = crtl->subsections.cold_section_label; @@ -3823,6 +3904,36 @@ dwarf2out_switch_text_section (void) /* There is no need to mark used sections when not debugging. */ if (cold_text_section != NULL) dwarf2out_note_section_used (); + + if (dwarf2out_do_cfi_asm ()) + fprintf (asm_out_file, "\t.cfi_endproc\n"); + + /* Now do the real section switch. */ + switch_to_section (current_function_section ()); + + if (dwarf2out_do_cfi_asm ()) + { + dw_cfi_ref cfi, cfi_args_size = NULL; + + dwarf2out_do_cfi_startproc (); + /* As this is a different FDE, insert all current CFI instructions + again. */ + for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + if (output_cfi_p (&cfi, &cfi_args_size)) + output_cfi_directive (cfi); + if (cfi_args_size && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) + output_cfi_directive (cfi_args_size); + } + else + { + dw_cfi_ref cfi = fde->dw_fde_cfi; + + cfi = fde->dw_fde_cfi; + if (cfi) + while (cfi->dw_cfi_next != NULL) + cfi = cfi->dw_cfi_next; + fde->dw_fde_switch_cfi = cfi; + } } #endif -- 2.30.2