2008-06-10 Xuepeng Guo * dwarf2out.c (dw_fde_struct): Add drap_regnum, stack_realignment, stack_realign, uses_drap, drap_reg_saved and calls_eh_return. (reg_save_with_expression): New. (add_cfi): If stack is realigned, call reg_save_with_expression to represent the location of stored vars. (dwarf2out_frame_debug_expr): Add rules 16-19 to handle stack realign. (output_cfa_loc): Handle DW_CFA_expression. (based_loc_descr): Update assert for stack realign. diff -up ../../gcc/gcc/dwarf2out.c gcc/gcc --- ../../gcc/gcc/dwarf2out.c 2008-06-06 15:10:06.000000000 -0700 +++ gcc/gcc/dwarf2out.c 2008-06-10 10:16:19.000000000 -0700 @@ -239,9 +239,22 @@ typedef struct dw_fde_struct GTY(()) bool dw_fde_switched_sections; dw_cfi_ref dw_fde_cfi; unsigned funcdef_number; + /* If using Dynamic Realign Argument Pointer, show which register + is used. */ + int drap_regnum; + HOST_WIDE_INT stack_realignment; unsigned all_throwers_are_sibcalls : 1; unsigned nothrow : 1; unsigned uses_eh_lsda : 1; + /* Whether we did stack realign in this call frame. */ + unsigned stack_realign : 1; + /* Whether stack realign uses Dynamic Realign Argument Pointer. */ + unsigned uses_drap : 1; + /* Whether we saved the register used by Dynamic Realign Argument + Pointer. */ + unsigned drap_reg_saved : 1; + /* Whether called __builtin_eh_return. */ + unsigned calls_eh_return : 1; } dw_fde_node; @@ -389,6 +402,7 @@ static void get_cfa_from_loc_descr (dw_c static struct dw_loc_descr_struct *build_cfa_loc (dw_cfa_location *, HOST_WIDE_INT); static void def_cfa_1 (const char *, dw_cfa_location *); +static void reg_save_with_expression (dw_cfi_ref); /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START @@ -621,11 +635,21 @@ static inline void add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi) { dw_cfi_ref *p; + dw_fde_ref fde = current_fde (); /* Find the end of the chain. */ for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) ; + /* If stack is realigned, accessing the stored register via + CFA+offset will be invalid. Here we will use a series of + expressions in dwarf2 to simulate the stack realign and + represent the location of the stored register. */ + if (fde + && (fde->stack_realign || fde->uses_drap) + && cfi->dw_cfi_opc == DW_CFA_offset) + reg_save_with_expression (cfi); + *p = cfi; } @@ -1444,6 +1468,11 @@ static dw_cfa_location cfa_temp; Rules 10-14: Save a register to the stack. Define offset as the difference of the original location and cfa_store's location (or cfa_temp's location if cfa_temp is used). + + Rules 16-19: If AND operation happens on sp in prologue, we assume + stack is realigned. We will use a group of DW_OP_XXX + expressions to represent the location of the stored + register instead of CFA+offset. The Rules @@ -1538,13 +1567,40 @@ static dw_cfa_location cfa_temp; Rule 15: (set {unspec, unspec_volatile}) - effects: target-dependent */ + effects: target-dependent + + Rule 16: + (set sp (and: sp )) + constraints: cfa_store.reg == sp + effects: current_fde.stack_realign = 1 + cfa_store.offset = 0 + + if cfa_store.offset >= UNITS_PER_WORD + effects: current_fde.drap_reg_saved = 1 + + Rule 17: + (set (mem ({pre_inc, pre_dec} sp)) (mem (plus (cfa.reg) (const_int)))) + effects: cfa_store.offset += -/+ mode_size(mem) + + Rule 18: + (set (mem({pre_inc, pre_dec} sp)) fp) + constraints: current_fde.stack_realign == 1 + effects: current_fde.stack_realign = 0 + current_fde.uses_drap = 1 + current_fde.drap_regnum = cfa.reg + + Rule 19: + (set fp sp) + constraints: current_fde.uses_drap == 1 + effects: cfa.reg = fp + cfa.offset = cfa_store.offset */ static void dwarf2out_frame_debug_expr (rtx expr, const char *label) { rtx src, dest, span; HOST_WIDE_INT offset; + dw_fde_ref fde; /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of the PARALLEL independently. The first element is always processed if @@ -1595,6 +1651,8 @@ dwarf2out_frame_debug_expr (rtx expr, co src = rsi; } + fde = current_fde (); + switch (GET_CODE (dest)) { case REG: @@ -1616,7 +1674,24 @@ dwarf2out_frame_debug_expr (rtx expr, co cfa_temp.reg = cfa.reg; cfa_temp.offset = cfa.offset; } - else + else if (fde + && fde->uses_drap + && REGNO (src) == STACK_POINTER_REGNUM + && REGNO (dest) == HARD_FRAME_POINTER_REGNUM) + { + /* Rule 19 */ + /* Each time when setting FP to SP under the condition of + that the stack is realigned and the realignment used + Dynamic Realign Argument Pointer and the register used + is the current cfa's register. We update cfa's register + to FP. */ + gcc_assert (DWARF_FRAME_REGNUM (cfa.reg) == fde->drap_regnum); + cfa.reg = REGNO (dest); + cfa.offset = cfa_store.offset; + cfa_temp.reg = cfa.reg; + cfa_temp.offset = cfa.offset; + } + else { /* Saving a register in a register. */ gcc_assert (!fixed_regs [REGNO (dest)] @@ -1756,6 +1831,25 @@ dwarf2out_frame_debug_expr (rtx expr, co targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1)); return; + /* Rule 16 */ + case AND: + /* If this AND operation happens on stack pointer in prologue, + we assume the stack is realigned and we extract the + alignment. */ + if (fde && XEXP (src, 0) == stack_pointer_rtx) + { + gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0))); + fde->stack_realign = 1; + fde->stack_realignment = INTVAL (XEXP (src, 1)); + /* If we didn't push anything to stack before stack is + realigned, we assume the register used by Dynamic + Realign Argument Pointer isn't saved. */ + if (cfa_store.offset > UNITS_PER_WORD) + fde->drap_reg_saved = 1; + cfa_store.offset = 0; + } + return; + default: gcc_unreachable (); } @@ -1764,7 +1858,6 @@ dwarf2out_frame_debug_expr (rtx expr, co break; case MEM: - gcc_assert (REG_P (src)); /* Saving a register to the stack. Make sure dest is relative to the CFA register. */ @@ -1795,8 +1888,23 @@ dwarf2out_frame_debug_expr (rtx expr, co if (GET_CODE (XEXP (dest, 0)) == PRE_INC) offset = -offset; - gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM + gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0)) + == STACK_POINTER_REGNUM) && cfa_store.reg == STACK_POINTER_REGNUM); + + if (fde + && fde->stack_realign + && REGNO (src) == HARD_FRAME_POINTER_REGNUM) + { + /* Rule 18 */ + /* If we push FP after stack is realigned, we assume this + realignment used Dynamic Realign Argument Pointer. We + will record the register used by Dynamic Realign + Argument Pointer. */ + fde->stack_realign = 0; + fde->uses_drap = 1; + fde->drap_regnum = DWARF_FRAME_REGNUM (cfa.reg); + } cfa_store.offset += offset; if (cfa.reg == STACK_POINTER_REGNUM) @@ -1891,6 +1999,12 @@ dwarf2out_frame_debug_expr (rtx expr, co break; } } + /* Rule 17 */ + /* If the source operand of this MEM operation is not a + register, basically the source is return address. Here + we only care how much stack grew and we don't save it. */ + if (!REG_P (src)) + break; def_cfa_1 (label, &cfa); { @@ -2668,6 +2782,7 @@ dwarf2out_begin_prologue (unsigned int l fde->nothrow = TREE_NOTHROW (current_function_decl); fde->uses_eh_lsda = crtl->uses_eh_lsda; fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls; + fde->calls_eh_return = crtl->calls_eh_return; args_size = old_args_size = 0; @@ -3558,6 +3673,9 @@ output_cfa_loc (dw_cfi_ref cfi) dw_loc_descr_ref loc; unsigned long size; + if (cfi->dw_cfi_opc == DW_CFA_expression) + dw2_asm_output_data (1, cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL); + /* Output the size of the block. */ loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; size = size_of_locs (loc); @@ -9034,8 +9152,12 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset += INTVAL (XEXP (elim, 1)); elim = XEXP (elim, 0); } - gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx - : stack_pointer_rtx)); + gcc_assert ((SUPPORTS_STACK_ALIGNMENT + && (elim == hard_frame_pointer_rtx + || elim == stack_pointer_rtx)) + || elim == (frame_pointer_needed + ? hard_frame_pointer_rtx + : stack_pointer_rtx)); offset += frame_pointer_fb_offset; return new_loc_descr (DW_OP_fbreg, offset, 0); @@ -11088,9 +11210,10 @@ compute_frame_pointer_to_fb_displacement offset += INTVAL (XEXP (elim, 1)); elim = XEXP (elim, 0); } - gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx - : stack_pointer_rtx)); + gcc_assert (SUPPORTS_STACK_ALIGNMENT + || elim == (frame_pointer_needed ? hard_frame_pointer_rtx + : stack_pointer_rtx)); frame_pointer_fb_offset = -offset; } @@ -15368,6 +15491,78 @@ dwarf2out_finish (const char *filename) if (debug_str_hash) htab_traverse (debug_str_hash, output_indirect_string, NULL); } + +/* In this function we use a series of DW_OP_?? expression which simulates + how stack is realigned to represent the location of the stored register.*/ +static void +reg_save_with_expression (dw_cfi_ref cfi) +{ + struct dw_loc_descr_struct *head, *tmp; + HOST_WIDE_INT alignment; + dw_fde_ref fde = current_fde (); + HOST_WIDE_INT offset = cfi->dw_cfi_oprnd2.dw_cfi_offset * UNITS_PER_WORD; + int reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + unsigned int dwarf_sp = (unsigned)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM); + + gcc_assert (fde != NULL); + + alignment = fde->stack_realignment; + + if (fde->stack_realign) + { + head = tmp = new_loc_descr (DW_OP_const4s, 2 * UNITS_PER_WORD, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_minus, 0, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_const4s, alignment, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_and, 0, 0); + + /* If stack grows upward, the offset will be a negative. */ + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_const4s, offset, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_minus, 0, 0); + + cfi->dw_cfi_opc = DW_CFA_expression; + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg; + cfi->dw_cfi_oprnd1.dw_cfi_loc = head; + } + + /* We need to restore register used by Dynamic Realign Argument + Pointer through dereference. */ + if (fde->uses_drap && reg == fde->drap_regnum) + { + + dw_cfi_ref cfi2 = new_cfi(); + + cfi->dw_cfi_opc = DW_CFA_expression; + head = tmp = new_loc_descr (DW_OP_const4s, offset, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_minus, 0, 0); + if (fde->drap_reg_saved) + { + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_deref, 0, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_const4s, + 2 * UNITS_PER_WORD, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_minus, 0, 0); + } + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg; + cfi->dw_cfi_oprnd1.dw_cfi_loc = head; + + /* We also need to properly restore the caller's stack pointer. + But if callee calls __builtin_eh_return, the calculation of + offset from exception handling function (typically is + _Unwind_RaiseException) to target function during unwinding + will conflict with this mechanism. It will simply set offset + to zero. So here if functions call __builtin_eh_return, + there will be no unwind information for restoring the stack + pointer. */ + if (!fde->calls_eh_return) + { + head = tmp = new_loc_descr (DW_OP_const4s, offset, 0); + tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_minus, 0, 0); + cfi2->dw_cfi_opc = DW_CFA_expression; + cfi2->dw_cfi_oprnd2.dw_cfi_reg_num = dwarf_sp; + cfi2->dw_cfi_oprnd1.dw_cfi_loc = head; + cfi->dw_cfi_next = cfi2; + } + } +} #else /* This should never be used, but its address is needed for comparisons. */