Ping. On 22/07/2021 11:58, Hafiz Abid Qadeer wrote: > Ping. > > On 13/06/2021 14:27, Hafiz Abid Qadeer wrote: >> Add support for architectures such as AMD GCN, in which the pointer size is >> larger than the register size. This allows the CFI information to include >> multi-register locations for the stack pointer, frame pointer, and return >> address. >> >> This patch was originally posted by Andrew Stubbs in >> https://gcc.gnu.org/pipermail/gcc-patches/2020-August/552873.html >> >> It has now been re-worked according to the review comments. It does not use >> DW_OP_piece or DW_OP_LLVM_piece_end. Instead it uses >> DW_OP_bregx/DW_OP_shl/DW_OP_bregx/DW_OP_plus to build the CFA from multiple >> consecutive registers. Here is how .debug_frame looks before and after this >> patch: >> >> $ cat factorial.c >> int factorial(int n) { >> if (n == 0) return 1; >> return n * factorial (n - 1); >> } >> >> $ amdgcn-amdhsa-gcc -g factorial.c -O0 -c -o fac.o >> $ llvm-dwarfdump -debug-frame fac.o >> >> *** without this patch (edited for brevity)*** >> >> 00000000 00000014 ffffffff CIE >> >> DW_CFA_def_cfa: reg48 +0 >> DW_CFA_register: reg16 reg50 >> >> 00000018 0000002c 00000000 FDE cie=00000000 pc=00000000...000001ac >> DW_CFA_advance_loc4: 96 >> DW_CFA_offset: reg46 0 >> DW_CFA_offset: reg47 4 >> DW_CFA_offset: reg50 8 >> DW_CFA_offset: reg51 12 >> DW_CFA_offset: reg16 8 >> DW_CFA_advance_loc4: 4 >> DW_CFA_def_cfa_sf: reg46 -16 >> >> *** with this patch (edited for brevity)*** >> >> 00000000 00000024 ffffffff CIE >> >> DW_CFA_def_cfa_expression: DW_OP_bregx SGPR49+0, DW_OP_const1u 0x20, >> DW_OP_shl, DW_OP_bregx SGPR48+0, DW_OP_plus >> DW_CFA_expression: reg16 DW_OP_bregx SGPR51+0, DW_OP_const1u 0x20, >> DW_OP_shl, DW_OP_bregx SGPR50+0, DW_OP_plus >> >> 00000028 0000003c 00000000 FDE cie=00000000 pc=00000000...000001ac >> DW_CFA_advance_loc4: 96 >> DW_CFA_offset: reg46 0 >> DW_CFA_offset: reg47 4 >> DW_CFA_offset: reg50 8 >> DW_CFA_offset: reg51 12 >> DW_CFA_offset: reg16 8 >> DW_CFA_advance_loc4: 4 >> DW_CFA_def_cfa_expression: DW_OP_bregx SGPR47+0, DW_OP_const1u 0x20, >> DW_OP_shl, DW_OP_bregx SGPR46+0, DW_OP_plus, DW_OP_lit16, DW_OP_minus >> >> gcc/ChangeLog: >> >> * dwarf2cfi.c (dw_stack_pointer_regnum): Change type to struct cfa_reg. >> (dw_frame_pointer_regnum): Likewise. >> (new_cfi_row): Use set_by_dwreg. >> (get_cfa_from_loc_descr): Use set_by_dwreg. Support register spans. >> handle DW_OP_bregx with DW_OP_breg{0-31}. Support DW_OP_lit*, >> DW_OP_const*, DW_OP_minus, DW_OP_shl and DW_OP_plus. >> (lookup_cfa_1): Use set_by_dwreg. >> (def_cfa_0): Update for cfa_reg and support register spans. >> (reg_save): Change sreg parameter to struct cfa_reg. Support register >> spans. >> (dwf_cfa_reg): New function. >> (dwarf2out_flush_queued_reg_saves): Use dwf_cfa_reg instead of >> dwf_regno. >> (dwarf2out_frame_debug_def_cfa): Likewise. >> (dwarf2out_frame_debug_adjust_cfa): Likewise. >> (dwarf2out_frame_debug_cfa_offset): Likewise. Update reg_save usage. >> (dwarf2out_frame_debug_cfa_register): Likewise. >> (dwarf2out_frame_debug_expr): Likewise. >> (create_pseudo_cfg): Use set_by_dwreg. >> (initial_return_save): Use set_by_dwreg and dwf_cfa_reg, >> (create_cie_data): Use dwf_cfa_reg. >> (execute_dwarf2_frame): Use dwf_cfa_reg. >> (dump_cfi_row): Use set_by_dwreg. >> * dwarf2out.c (build_span_loc, build_breg_loc): New function. >> (build_cfa_loc): Support register spans. >> (build_cfa_aligned_loc): Update cfa_reg usage. >> (convert_cfa_to_fb_loc_list): Use set_by_dwreg. >> * dwarf2out.h (struct cfa_reg): New type. >> (struct dw_cfa_location): Use struct cfa_reg. >> (build_span_loc): New prototype. >> * gengtype.c (main): Accept poly_uint16_pod type. >> --- >> gcc/dwarf2cfi.c | 260 ++++++++++++++++++++++++++++++++++++------------ >> gcc/dwarf2out.c | 55 +++++++++- >> gcc/dwarf2out.h | 37 ++++++- >> gcc/gengtype.c | 1 + >> 4 files changed, 283 insertions(+), 70 deletions(-) >> >> diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c >> index c27ac1960b0..5aacdcd094a 100644 >> --- a/gcc/dwarf2cfi.c >> +++ b/gcc/dwarf2cfi.c >> @@ -229,8 +229,8 @@ static vec<queued_reg_save> queued_reg_saves; >> static bool any_cfis_emitted; >> >> /* Short-hand for commonly used register numbers. */ >> -static unsigned dw_stack_pointer_regnum; >> -static unsigned dw_frame_pointer_regnum; >> +static struct cfa_reg dw_stack_pointer_regnum; >> +static struct cfa_reg dw_frame_pointer_regnum; >> >> /* Hook used by __throw. */ >> >> @@ -430,7 +430,7 @@ new_cfi_row (void) >> { >> dw_cfi_row *row = ggc_cleared_alloc<dw_cfi_row> (); >> >> - row->cfa.reg = INVALID_REGNUM; >> + row->cfa.reg.set_by_dwreg (INVALID_REGNUM); >> >> return row; >> } >> @@ -538,7 +538,7 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct >> dw_loc_descr_node *loc) >> cfa->offset = 0; >> cfa->base_offset = 0; >> cfa->indirect = 0; >> - cfa->reg = -1; >> + cfa->reg.set_by_dwreg (INVALID_REGNUM); >> >> for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next) >> { >> @@ -578,10 +578,10 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct >> dw_loc_descr_node *loc) >> case DW_OP_reg29: >> case DW_OP_reg30: >> case DW_OP_reg31: >> - cfa->reg = op - DW_OP_reg0; >> + cfa->reg.set_by_dwreg (op - DW_OP_reg0); >> break; >> case DW_OP_regx: >> - cfa->reg = ptr->dw_loc_oprnd1.v.val_int; >> + cfa->reg.set_by_dwreg (ptr->dw_loc_oprnd1.v.val_int); >> break; >> case DW_OP_breg0: >> case DW_OP_breg1: >> @@ -615,16 +615,92 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct >> dw_loc_descr_node *loc) >> case DW_OP_breg29: >> case DW_OP_breg30: >> case DW_OP_breg31: >> - cfa->reg = op - DW_OP_breg0; >> - cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int; >> - break; >> case DW_OP_bregx: >> - cfa->reg = ptr->dw_loc_oprnd1.v.val_int; >> - cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int; >> + if (cfa->reg.reg == INVALID_REGNUM) >> + { >> + cfa->reg.set_by_dwreg ((op == DW_OP_bregx) >> + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0)); >> + cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int; >> + } >> + else >> + { >> + /* Handle case when span can cover multiple registers. We >> + only support the simple case of consecutive registers >> + all with the same size. DWARF that we are dealing with >> + will look something like: >> + <DW_OP_bregx: (r49) 0; DW_OP_const1u: 32; DW_OP_shl; >> + DW_OP_bregx: (r48) 0; DW_OP_plus> */ >> + >> + unsigned int regno = (op == DW_OP_bregx) >> + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0); >> + gcc_assert (regno == (cfa->reg.reg - 1)); >> + cfa->reg.span++; >> + /* From all the consecutive registers used, we want to set >> + cfa->reg.reg to lower number register. */ >> + cfa->reg.reg = regno; >> + /* The offset was the shift value. Use it to get the >> + span_width and then set it to 0. */ >> + cfa->reg.span_width = (cfa->offset.to_constant () / 8); >> + cfa->offset = 0; >> + } >> break; >> case DW_OP_deref: >> cfa->indirect = 1; >> break; >> + case DW_OP_shl: >> + break; >> + case DW_OP_lit0: >> + case DW_OP_lit1: >> + case DW_OP_lit2: >> + case DW_OP_lit3: >> + case DW_OP_lit4: >> + case DW_OP_lit5: >> + case DW_OP_lit6: >> + case DW_OP_lit7: >> + case DW_OP_lit8: >> + case DW_OP_lit9: >> + case DW_OP_lit10: >> + case DW_OP_lit11: >> + case DW_OP_lit12: >> + case DW_OP_lit13: >> + case DW_OP_lit14: >> + case DW_OP_lit15: >> + case DW_OP_lit16: >> + case DW_OP_lit17: >> + case DW_OP_lit18: >> + case DW_OP_lit19: >> + case DW_OP_lit20: >> + case DW_OP_lit21: >> + case DW_OP_lit22: >> + case DW_OP_lit23: >> + case DW_OP_lit24: >> + case DW_OP_lit25: >> + case DW_OP_lit26: >> + case DW_OP_lit27: >> + case DW_OP_lit28: >> + case DW_OP_lit29: >> + case DW_OP_lit30: >> + case DW_OP_lit31: >> + gcc_assert (known_eq (cfa->offset, 0)); >> + cfa->offset = op - DW_OP_lit0; >> + break; >> + case DW_OP_const1u: >> + case DW_OP_const1s: >> + case DW_OP_const2u: >> + case DW_OP_const2s: >> + case DW_OP_const4s: >> + case DW_OP_const8s: >> + case DW_OP_constu: >> + case DW_OP_consts: >> + gcc_assert (known_eq (cfa->offset, 0)); >> + cfa->offset = ptr->dw_loc_oprnd1.v.val_int; >> + break; >> + case DW_OP_minus: >> + cfa->offset = -cfa->offset; >> + break; >> + case DW_OP_plus: >> + /* The offset is already in place. */ >> + break; >> case DW_OP_plus_uconst: >> cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned; >> break; >> @@ -648,11 +724,11 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, >> dw_cfa_location *remember) >> loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset; >> break; >> case DW_CFA_def_cfa_register: >> - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; >> + loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); >> break; >> case DW_CFA_def_cfa: >> case DW_CFA_def_cfa_sf: >> - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; >> + loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); >> loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset; >> break; >> case DW_CFA_def_cfa_expression: >> @@ -798,6 +874,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location >> *new_cfa) >> >> HOST_WIDE_INT const_offset; >> if (new_cfa->reg == old_cfa->reg >> + && new_cfa->reg.span == 1 >> && !new_cfa->indirect >> && !old_cfa->indirect >> && new_cfa->offset.is_constant (&const_offset)) >> @@ -814,7 +891,8 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location >> *new_cfa) >> } >> else if (new_cfa->offset.is_constant () >> && known_eq (new_cfa->offset, old_cfa->offset) >> - && old_cfa->reg != INVALID_REGNUM >> + && old_cfa->reg.reg != INVALID_REGNUM >> + && new_cfa->reg.span == 1 >> && !new_cfa->indirect >> && !old_cfa->indirect) >> { >> @@ -824,10 +902,11 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location >> *new_cfa) >> been set as a register plus offset rather than a general >> DW_CFA_def_cfa_expression. */ >> cfi->dw_cfi_opc = DW_CFA_def_cfa_register; >> - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg; >> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg; >> } >> else if (new_cfa->indirect == 0 >> - && new_cfa->offset.is_constant (&const_offset)) >> + && new_cfa->offset.is_constant (&const_offset) >> + && new_cfa->reg.span == 1) >> { >> /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction, >> indicating the CFA register has changed to <register> with >> @@ -838,7 +917,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location >> *new_cfa) >> cfi->dw_cfi_opc = DW_CFA_def_cfa_sf; >> else >> cfi->dw_cfi_opc = DW_CFA_def_cfa; >> - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg; >> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg; >> cfi->dw_cfi_oprnd2.dw_cfi_offset = const_offset; >> } >> else >> @@ -885,18 +964,18 @@ def_cfa_1 (dw_cfa_location *new_cfa) >> } >> >> /* Add the CFI for saving a register. REG is the CFA column number. >> - If SREG is -1, the register is saved at OFFSET from the CFA; >> + If SREG is INVALID_REGISTER, the register is saved at OFFSET from the >> CFA; >> otherwise it is saved in SREG. */ >> >> static void >> -reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset) >> +reg_save (unsigned int reg, struct cfa_reg sreg, poly_int64 offset) >> { >> dw_fde_ref fde = cfun ? cfun->fde : NULL; >> dw_cfi_ref cfi = new_cfi (); >> >> cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; >> >> - if (sreg == INVALID_REGNUM) >> + if (sreg.reg == INVALID_REGNUM) >> { >> HOST_WIDE_INT const_offset; >> /* When stack is aligned, store REG using DW_CFA_expression with FP. >> */ >> @@ -926,7 +1005,7 @@ reg_save (unsigned int reg, unsigned int sreg, >> poly_int64 offset) >> = build_cfa_loc (&cur_row->cfa, offset); >> } >> } >> - else if (sreg == reg) >> + else if (sreg.reg == reg) >> { >> /* While we could emit something like DW_CFA_same_value or >> DW_CFA_restore, we never expect to see something like that >> @@ -934,10 +1013,16 @@ reg_save (unsigned int reg, unsigned int sreg, >> poly_int64 offset) >> can always bypass this by using REG_CFA_RESTORE directly. */ >> gcc_unreachable (); >> } >> + else if (sreg.span > 1) >> + { >> + cfi->dw_cfi_opc = DW_CFA_expression; >> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; >> + cfi->dw_cfi_oprnd2.dw_cfi_loc = build_span_loc (sreg); >> + } >> else >> { >> cfi->dw_cfi_opc = DW_CFA_register; >> - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; >> + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg.reg; >> } >> >> add_cfi (cfi); >> @@ -1018,6 +1103,43 @@ dwf_regno (const_rtx reg) >> return DWARF_FRAME_REGNUM (REGNO (reg)); >> } >> >> +/* Like dwf_regno, but when the value can span multiple registers. */ >> + >> +static struct cfa_reg >> +dwf_cfa_reg (rtx reg) >> +{ >> + struct cfa_reg result; >> + >> + gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER); >> + >> + result.reg = dwf_regno (reg); >> + result.span = 1; >> + result.span_width = GET_MODE_SIZE (GET_MODE (reg)); >> + >> + rtx span = targetm.dwarf_register_span (reg); >> + if (span) >> + { >> + /* We only support the simple case of consecutive registers all with >> the >> + same size. */ >> + result.span = XVECLEN (span, 0); >> + result.span_width = GET_MODE_SIZE (GET_MODE (XVECEXP (span, 0, 0))); >> + >> +#if CHECKING_P >> + /* Ensure that the above assumption is accurate. */ >> + for (unsigned int i = 0; i < result.span; i++) >> + { >> + gcc_assert (known_eq (GET_MODE_SIZE (GET_MODE (XVECEXP (span, >> + 0, i))), >> + result.span_width)); >> + gcc_assert (REG_P (XVECEXP (span, 0, i))); >> + gcc_assert (dwf_regno (XVECEXP (span, 0, i)) == result.reg + i); >> + } >> +#endif >> + } >> + >> + return result; >> +} >> + >> /* Compare X and Y for equivalence. The inputs may be REGs or PC_RTX. */ >> >> static bool >> @@ -1086,7 +1208,8 @@ dwarf2out_flush_queued_reg_saves (void) >> >> FOR_EACH_VEC_ELT (queued_reg_saves, i, q) >> { >> - unsigned int reg, sreg; >> + unsigned int reg; >> + struct cfa_reg sreg; >> >> record_reg_saved_in_reg (q->saved_reg, q->reg); >> >> @@ -1095,9 +1218,9 @@ dwarf2out_flush_queued_reg_saves (void) >> else >> reg = dwf_regno (q->reg); >> if (q->saved_reg) >> - sreg = dwf_regno (q->saved_reg); >> + sreg = dwf_cfa_reg (q->saved_reg); >> else >> - sreg = INVALID_REGNUM; >> + sreg.set_by_dwreg (INVALID_REGNUM); >> reg_save (reg, sreg, q->cfa_offset); >> } >> >> @@ -1169,7 +1292,7 @@ dwarf2out_frame_debug_def_cfa (rtx pat) >> /* ??? If this fails, we could be calling into the _loc functions to >> define a full expression. So far no port does that. */ >> gcc_assert (REG_P (pat)); >> - cur_cfa->reg = dwf_regno (pat); >> + cur_cfa->reg = dwf_cfa_reg (pat); >> } >> >> /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */ >> @@ -1186,7 +1309,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat) >> switch (GET_CODE (src)) >> { >> case PLUS: >> - gcc_assert (dwf_regno (XEXP (src, 0)) == cur_cfa->reg); >> + gcc_assert (dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg); >> cur_cfa->offset -= rtx_to_poly_int64 (XEXP (src, 1)); >> break; >> >> @@ -1197,7 +1320,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat) >> gcc_unreachable (); >> } >> >> - cur_cfa->reg = dwf_regno (dest); >> + cur_cfa->reg = dwf_cfa_reg (dest); >> gcc_assert (cur_cfa->indirect == 0); >> } >> >> @@ -1219,11 +1342,11 @@ dwarf2out_frame_debug_cfa_offset (rtx set) >> switch (GET_CODE (addr)) >> { >> case REG: >> - gcc_assert (dwf_regno (addr) == cur_cfa->reg); >> + gcc_assert (dwf_cfa_reg (addr) == cur_cfa->reg); >> offset = -cur_cfa->offset; >> break; >> case PLUS: >> - gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_cfa->reg); >> + gcc_assert (dwf_cfa_reg (XEXP (addr, 0)) == cur_cfa->reg); >> offset = rtx_to_poly_int64 (XEXP (addr, 1)) - cur_cfa->offset; >> break; >> default: >> @@ -1243,8 +1366,10 @@ dwarf2out_frame_debug_cfa_offset (rtx set) >> >> /* ??? We'd like to use queue_reg_save, but we need to come up with >> a different flushing heuristic for epilogues. */ >> + struct cfa_reg invalid; >> + invalid.set_by_dwreg (INVALID_REGNUM); >> if (!span) >> - reg_save (sregno, INVALID_REGNUM, offset); >> + reg_save (sregno, invalid, offset); >> else >> { >> /* We have a PARALLEL describing where the contents of SRC live. >> @@ -1258,7 +1383,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set) >> { >> rtx elem = XVECEXP (span, 0, par_index); >> sregno = dwf_regno (src); >> - reg_save (sregno, INVALID_REGNUM, span_offset); >> + reg_save (sregno, invalid, span_offset); >> span_offset += GET_MODE_SIZE (GET_MODE (elem)); >> } >> } >> @@ -1270,7 +1395,8 @@ static void >> dwarf2out_frame_debug_cfa_register (rtx set) >> { >> rtx src, dest; >> - unsigned sregno, dregno; >> + unsigned sregno; >> + struct cfa_reg dregno; >> >> src = XEXP (set, 1); >> dest = XEXP (set, 0); >> @@ -1281,7 +1407,7 @@ dwarf2out_frame_debug_cfa_register (rtx set) >> else >> sregno = dwf_regno (src); >> >> - dregno = dwf_regno (dest); >> + dregno = dwf_cfa_reg (dest); >> >> /* ??? We'd like to use queue_reg_save, but we need to come up with >> a different flushing heuristic for epilogues. */ >> @@ -1667,7 +1793,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> { >> /* Setting FP from SP. */ >> case REG: >> - if (cur_cfa->reg == dwf_regno (src)) >> + if (cur_cfa->reg == dwf_cfa_reg (src)) >> { >> /* Rule 1 */ >> /* Update the CFA rule wrt SP or FP. Make sure src is >> @@ -1677,7 +1803,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> ARM copies SP to a temporary register, and from there to >> FP. So we just rely on the backends to only set >> RTX_FRAME_RELATED_P on appropriate insns. */ >> - cur_cfa->reg = dwf_regno (dest); >> + cur_cfa->reg = dwf_cfa_reg (dest); >> cur_trace->cfa_temp.reg = cur_cfa->reg; >> cur_trace->cfa_temp.offset = cur_cfa->offset; >> } >> @@ -1698,7 +1824,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> { >> gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM >> && fde->drap_reg != INVALID_REGNUM >> - && cur_cfa->reg != dwf_regno (src) >> + && cur_cfa->reg != dwf_cfa_reg (src) >> && fde->rule18); >> fde->rule18 = 0; >> /* The save of hard frame pointer has been deferred >> @@ -1722,7 +1848,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> /* Adjusting SP. */ >> if (REG_P (XEXP (src, 1))) >> { >> - gcc_assert (dwf_regno (XEXP (src, 1)) >> + gcc_assert (dwf_cfa_reg (XEXP (src, 1)) >> == cur_trace->cfa_temp.reg); >> offset = cur_trace->cfa_temp.offset; >> } >> @@ -1756,7 +1882,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> gcc_assert (frame_pointer_needed); >> >> gcc_assert (REG_P (XEXP (src, 0)) >> - && dwf_regno (XEXP (src, 0)) == cur_cfa->reg); >> + && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg); >> offset = rtx_to_poly_int64 (XEXP (src, 1)); >> if (GET_CODE (src) != MINUS) >> offset = -offset; >> @@ -1769,14 +1895,14 @@ dwarf2out_frame_debug_expr (rtx expr) >> >> /* Rule 4 */ >> if (REG_P (XEXP (src, 0)) >> - && dwf_regno (XEXP (src, 0)) == cur_cfa->reg >> + && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg >> && poly_int_rtx_p (XEXP (src, 1), &offset)) >> { >> /* Setting a temporary CFA register that will be copied >> into the FP later on. */ >> offset = -offset; >> cur_cfa->offset += offset; >> - cur_cfa->reg = dwf_regno (dest); >> + cur_cfa->reg = dwf_cfa_reg (dest); >> /* Or used to save regs to the stack. */ >> cur_trace->cfa_temp.reg = cur_cfa->reg; >> cur_trace->cfa_temp.offset = cur_cfa->offset; >> @@ -1784,13 +1910,13 @@ dwarf2out_frame_debug_expr (rtx expr) >> >> /* Rule 5 */ >> else if (REG_P (XEXP (src, 0)) >> - && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg >> + && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg >> && XEXP (src, 1) == stack_pointer_rtx) >> { >> /* Setting a scratch register that we will use instead >> of SP for saving registers to the stack. */ >> gcc_assert (cur_cfa->reg == dw_stack_pointer_regnum); >> - cur_trace->cfa_store.reg = dwf_regno (dest); >> + cur_trace->cfa_store.reg = dwf_cfa_reg (dest); >> cur_trace->cfa_store.offset >> = cur_cfa->offset - cur_trace->cfa_temp.offset; >> } >> @@ -1799,7 +1925,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> else if (GET_CODE (src) == LO_SUM >> && poly_int_rtx_p (XEXP (src, 1), >> &cur_trace->cfa_temp.offset)) >> - cur_trace->cfa_temp.reg = dwf_regno (dest); >> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest); >> else >> gcc_unreachable (); >> } >> @@ -1808,17 +1934,17 @@ dwarf2out_frame_debug_expr (rtx expr) >> /* Rule 6 */ >> case CONST_INT: >> case CONST_POLY_INT: >> - cur_trace->cfa_temp.reg = dwf_regno (dest); >> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest); >> cur_trace->cfa_temp.offset = rtx_to_poly_int64 (src); >> break; >> >> /* Rule 7 */ >> case IOR: >> gcc_assert (REG_P (XEXP (src, 0)) >> - && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg >> + && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg >> && CONST_INT_P (XEXP (src, 1))); >> >> - cur_trace->cfa_temp.reg = dwf_regno (dest); >> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest); >> if (!can_ior_p (cur_trace->cfa_temp.offset, INTVAL (XEXP (src, 1)), >> &cur_trace->cfa_temp.offset)) >> /* The target shouldn't generate this kind of CFI note if we >> @@ -1851,14 +1977,17 @@ dwarf2out_frame_debug_expr (rtx expr) >> dwarf2out_flush_queued_reg_saves (); >> >> gcc_assert (cur_trace->cfa_store.reg >> - == dwf_regno (XEXP (src, 0))); >> + == dwf_cfa_reg (XEXP (src, 0))); >> fde->stack_realign = 1; >> fde->stack_realignment = INTVAL (XEXP (src, 1)); >> cur_trace->cfa_store.offset = 0; >> >> if (cur_cfa->reg != dw_stack_pointer_regnum >> && cur_cfa->reg != dw_frame_pointer_regnum) >> - fde->drap_reg = cur_cfa->reg; >> + { >> + gcc_assert (cur_cfa->reg.span == 1); >> + fde->drap_reg = cur_cfa->reg.reg; >> + } >> } >> return; >> >> @@ -1935,14 +2064,14 @@ dwarf2out_frame_debug_expr (rtx expr) >> case MINUS: >> case LO_SUM: >> { >> - unsigned int regno; >> + struct cfa_reg regno; >> >> gcc_assert (REG_P (XEXP (XEXP (dest, 0), 0))); >> offset = rtx_to_poly_int64 (XEXP (XEXP (dest, 0), 1)); >> if (GET_CODE (XEXP (dest, 0)) == MINUS) >> offset = -offset; >> >> - regno = dwf_regno (XEXP (XEXP (dest, 0), 0)); >> + regno = dwf_cfa_reg (XEXP (XEXP (dest, 0), 0)); >> >> if (cur_cfa->reg == regno) >> offset -= cur_cfa->offset; >> @@ -1960,7 +2089,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> /* Without an offset. */ >> case REG: >> { >> - unsigned int regno = dwf_regno (XEXP (dest, 0)); >> + struct cfa_reg regno = dwf_cfa_reg (XEXP (dest, 0)); >> >> if (cur_cfa->reg == regno) >> offset = -cur_cfa->offset; >> @@ -1977,7 +2106,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> /* Rule 14 */ >> case POST_INC: >> gcc_assert (cur_trace->cfa_temp.reg >> - == dwf_regno (XEXP (XEXP (dest, 0), 0))); >> + == dwf_cfa_reg (XEXP (XEXP (dest, 0), 0))); >> offset = -cur_trace->cfa_temp.offset; >> cur_trace->cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest)); >> break; >> @@ -1995,7 +2124,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> if (REG_P (src) >> && REGNO (src) != STACK_POINTER_REGNUM >> && REGNO (src) != HARD_FRAME_POINTER_REGNUM >> - && dwf_regno (src) == cur_cfa->reg) >> + && dwf_cfa_reg (src) == cur_cfa->reg) >> { >> /* We're storing the current CFA reg into the stack. */ >> >> @@ -2012,7 +2141,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> && cur_cfa->indirect == 0 >> && cur_cfa->reg != dw_frame_pointer_regnum) >> { >> - gcc_assert (fde->drap_reg == cur_cfa->reg); >> + gcc_assert (fde->drap_reg == cur_cfa->reg.reg); >> >> cur_cfa->indirect = 1; >> cur_cfa->reg = dw_frame_pointer_regnum; >> @@ -2039,7 +2168,7 @@ dwarf2out_frame_debug_expr (rtx expr) >> x = XEXP (x, 0); >> gcc_assert (REG_P (x)); >> >> - cur_cfa->reg = dwf_regno (x); >> + cur_cfa->reg = dwf_cfa_reg (x); >> cur_cfa->base_offset = offset; >> cur_cfa->indirect = 1; >> break; >> @@ -2951,7 +3080,7 @@ create_pseudo_cfg (void) >> ti.head = get_insns (); >> ti.beg_row = cie_cfi_row; >> ti.cfa_store = cie_cfi_row->cfa; >> - ti.cfa_temp.reg = INVALID_REGNUM; >> + ti.cfa_temp.reg.set_by_dwreg (INVALID_REGNUM); >> trace_info.quick_push (ti); >> >> if (cie_return_save) >> @@ -3014,14 +3143,15 @@ create_pseudo_cfg (void) >> static void >> initial_return_save (rtx rtl) >> { >> - unsigned int reg = INVALID_REGNUM; >> + struct cfa_reg reg; >> + reg.set_by_dwreg (INVALID_REGNUM); >> poly_int64 offset = 0; >> >> switch (GET_CODE (rtl)) >> { >> case REG: >> /* RA is in a register. */ >> - reg = dwf_regno (rtl); >> + reg = dwf_cfa_reg (rtl); >> break; >> >> case MEM: >> @@ -3062,9 +3192,9 @@ initial_return_save (rtx rtl) >> gcc_unreachable (); >> } >> >> - if (reg != DWARF_FRAME_RETURN_COLUMN) >> + if (reg.reg != DWARF_FRAME_RETURN_COLUMN) >> { >> - if (reg != INVALID_REGNUM) >> + if (reg.reg != INVALID_REGNUM) >> record_reg_saved_in_reg (rtl, pc_rtx); >> reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - >> cur_row->cfa.offset); >> } >> @@ -3076,7 +3206,8 @@ create_cie_data (void) >> dw_cfa_location loc; >> dw_trace_info cie_trace; >> >> - dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM); >> + dw_stack_pointer_regnum = dwf_cfa_reg (gen_rtx_REG (Pmode, >> + STACK_POINTER_REGNUM)); >> >> memset (&cie_trace, 0, sizeof (cie_trace)); >> cur_trace = &cie_trace; >> @@ -3135,7 +3266,8 @@ static unsigned int >> execute_dwarf2_frame (void) >> { >> /* Different HARD_FRAME_POINTER_REGNUM might coexist in the same file. */ >> - dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM); >> + dw_frame_pointer_regnum = dwf_cfa_reg (gen_rtx_REG >> + (Pmode, HARD_FRAME_POINTER_REGNUM)); >> >> /* The first time we're called, compute the incoming frame state. */ >> if (cie_cfi_vec == NULL) >> @@ -3515,7 +3647,7 @@ dump_cfi_row (FILE *f, dw_cfi_row *row) >> { >> dw_cfa_location dummy; >> memset (&dummy, 0, sizeof (dummy)); >> - dummy.reg = INVALID_REGNUM; >> + dummy.reg.set_by_dwreg (INVALID_REGNUM); >> cfi = def_cfa_0 (&dummy, &row->cfa); >> } >> output_cfi_directive (f, cfi); >> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c >> index 88eb3f9c455..a0b41df6da0 100644 >> --- a/gcc/dwarf2out.c >> +++ b/gcc/dwarf2out.c >> @@ -2785,6 +2785,44 @@ output_loc_sequence_raw (dw_loc_descr_ref loc) >> } >> } >> >> +static void >> +build_breg_loc (struct dw_loc_descr_node **head, unsigned int regno) >> +{ >> + if (regno <= 31) >> + add_loc_descr (head, new_loc_descr ((enum dwarf_location_atom) >> + (DW_OP_breg0 + regno), 0, 0)); >> + else >> + add_loc_descr (head, new_loc_descr (DW_OP_bregx, regno, 0)); >> +} >> + >> +/* Build a dwarf location for a cfa_reg spanning multiple >> + consecutive registers. */ >> + >> +struct dw_loc_descr_node * >> +build_span_loc (struct cfa_reg reg) >> +{ >> + struct dw_loc_descr_node *head = NULL; >> + >> + gcc_assert (known_gt (reg.span_width, 0)); >> + gcc_assert (reg.span > 1); >> + >> + /* Start from the highest number register as it goes in the upper bits. >> */ >> + unsigned int regno = reg.reg + reg.span - 1; >> + build_breg_loc (&head, regno); >> + >> + /* deal with the remaining registers in the span. */ >> + for (int i = (reg.span - 2); i >= 0; i--) >> + { >> + add_loc_descr (&head, int_loc_descriptor >> + (reg.span_width.to_constant () * 8)); >> + add_loc_descr (&head, new_loc_descr (DW_OP_shl, 0, 0)); >> + regno--; >> + build_breg_loc (&head, regno); >> + add_loc_descr (&head, new_loc_descr (DW_OP_plus, 0, 0)); >> + } >> + return head; >> +} >> + >> /* This function builds a dwarf location descriptor sequence from a >> dw_cfa_location, adding the given OFFSET to the result of the >> expression. */ >> @@ -2796,9 +2834,16 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 >> offset) >> >> offset += cfa->offset; >> >> - if (cfa->indirect) >> + if (cfa->reg.span > 1) >> + { >> + head = build_span_loc (cfa->reg); >> + >> + if (maybe_ne (offset, 0)) >> + loc_descr_plus_const (&head, offset); >> + } >> + else if (cfa->indirect) >> { >> - head = new_reg_loc_descr (cfa->reg, cfa->base_offset); >> + head = new_reg_loc_descr (cfa->reg.reg, cfa->base_offset); >> head->dw_loc_oprnd1.val_class = dw_val_class_const; >> head->dw_loc_oprnd1.val_entry = NULL; >> tmp = new_loc_descr (DW_OP_deref, 0, 0); >> @@ -2806,7 +2851,7 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset) >> loc_descr_plus_const (&head, offset); >> } >> else >> - head = new_reg_loc_descr (cfa->reg, offset); >> + head = new_reg_loc_descr (cfa->reg.reg, offset); >> >> return head; >> } >> @@ -2824,7 +2869,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa, >> = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM); >> >> /* When CFA is defined as FP+OFFSET, emulate stack alignment. */ >> - if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0) >> + if (cfa->reg.reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0) >> { >> head = new_reg_loc_descr (dwarf_fp, 0); >> add_loc_descr (&head, int_loc_descriptor (alignment)); >> @@ -20865,7 +20910,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) >> list = NULL; >> >> memset (&next_cfa, 0, sizeof (next_cfa)); >> - next_cfa.reg = INVALID_REGNUM; >> + next_cfa.reg.set_by_dwreg (INVALID_REGNUM); >> remember = next_cfa; >> >> start_label = fde->dw_fde_begin; >> diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h >> index 54b6343704c..38b52c8e1c2 100644 >> --- a/gcc/dwarf2out.h >> +++ b/gcc/dwarf2out.h >> @@ -119,6 +119,40 @@ struct GTY(()) dw_fde_node { >> }; >> >> >> +/* This represents a register, in DWARF_FRAME_REGNUM space, for use in CFA >> + definitions and expressions. >> + Most architectures only need a single register number, but some (amdgcn) >> + have pointers that span multiple registers. DWARF permits arbitrary >> + register sets but existing use-cases only require contiguous register >> + sets, as represented here. */ >> +struct GTY(()) cfa_reg { >> + unsigned int reg; >> + unsigned int span; >> + poly_uint16_pod span_width; /* A.K.A. register mode size. */ >> + >> + cfa_reg& set_by_dwreg (unsigned int r) >> + { >> + reg = r; >> + span = 1; >> + span_width = 0; /* Unknown size (permitted when span == 1). */ >> + return *this; >> + } >> + >> + bool operator== (const cfa_reg other) const >> + { >> + return (reg == other.reg >> + && span == other.span >> + && (known_eq (span_width, other.span_width) >> + || (span == 1 >> + && (known_eq (span_width, 0) >> + || known_eq (other.span_width, 0))))); >> + } >> + bool operator!= (const cfa_reg other) const >> + { >> + return !(*this == other); >> + } >> +}; >> + >> /* This is how we define the location of the CFA. We use to handle it >> as REG + OFFSET all the time, but now it can be more complex. >> It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + >> CFA_OFFSET. >> @@ -128,7 +162,7 @@ struct GTY(()) dw_cfa_location { >> poly_int64_pod offset; >> poly_int64_pod base_offset; >> /* REG is in DWARF_FRAME_REGNUM space, *not* normal REGNO space. */ >> - unsigned int reg; >> + struct cfa_reg reg; >> BOOL_BITFIELD indirect : 1; /* 1 if CFA is accessed via a dereference. >> */ >> BOOL_BITFIELD in_use : 1; /* 1 if a saved cfa is stored here. */ >> }; >> @@ -285,6 +319,7 @@ extern struct dw_loc_descr_node *build_cfa_loc >> (dw_cfa_location *, poly_int64); >> extern struct dw_loc_descr_node *build_cfa_aligned_loc >> (dw_cfa_location *, poly_int64, HOST_WIDE_INT); >> +extern struct dw_loc_descr_node *build_span_loc (struct cfa_reg); >> extern struct dw_loc_descr_node *mem_loc_descriptor >> (rtx, machine_mode mode, machine_mode mem_mode, >> enum var_init_status); >> diff --git a/gcc/gengtype.c b/gcc/gengtype.c >> index b94e2f126ec..45e9f856470 100644 >> --- a/gcc/gengtype.c >> +++ b/gcc/gengtype.c >> @@ -5195,6 +5195,7 @@ main (int argc, char **argv) >> POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos)); >> POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos)); >> POS_HERE (do_scalar_typedef ("double_int", &pos)); >> + POS_HERE (do_scalar_typedef ("poly_uint16_pod", &pos)); >> POS_HERE (do_scalar_typedef ("poly_int64_pod", &pos)); >> POS_HERE (do_scalar_typedef ("offset_int", &pos)); >> POS_HERE (do_scalar_typedef ("widest_int", &pos)); >> > >
-- Hafiz Abid Qadeer Mentor, a Siemens Business