Message ID | 20210613132738.615611-1-abidh@codesourcery.com |
---|---|
State | New |
Headers | show |
Series | dwarf: Multi-register CFI address support. | expand |
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)); >
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)); >> > >
Ping. On 24/08/2021 16:55, Hafiz Abid Qadeer wrote: > 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)); >>> >> >> > >
On Sun, Jun 13, 2021 at 02:27:38PM +0100, Hafiz Abid Qadeer wrote: > *** 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 I guess as a temporary solution until DWARF6 comes with something more compact for cases like that it can be fine, but is there a DWARF issue filed for it? Is AMDGCN a DWARF2_ADDR_SIZE == 8 target? > +/* 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. */ If this is only used for span > 1, wouldn't it be better to make it unsigned int reg; unsigned short span; unsigned short span_width; and keep span_width 0 for the span == 1 cases and only set span_width to ....to_constant () if span > 1 is needed? If at least for now the only target that needs this is AMDGCN and the only target that has NUM_POLY_INT_COEFFS != 1 is aarch64 (maybe eventually riscv?), then I don't see why we should represent it in poly_uint16... Of course we can change it later if a target which needs both NUM_POLY_INT_COEFFS > 1 and span > 1 registers with non-constant span_width, we can change it, but doing it just in case seems unnecessary complication... Jakub
On 09/11/2021 15:59, Jakub Jelinek wrote: > On Sun, Jun 13, 2021 at 02:27:38PM +0100, Hafiz Abid Qadeer wrote: >> *** 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 > > I guess as a temporary solution until DWARF6 comes with something more > compact for cases like that it can be fine, but is there a DWARF issue > filed for it? I have filed an issue today describing the problem. Although I am not sure what is the best way to handle it as there is not much encoding space left in CFA defining instructions. > Is AMDGCN a DWARF2_ADDR_SIZE == 8 target? Yes > >> +/* 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. */ > > If this is only used for span > 1, wouldn't it be better to > make it > unsigned int reg; > unsigned short span; > unsigned short span_width; > and keep span_width 0 for the span == 1 cases and only set span_width > to ....to_constant () if span > 1 is needed? If at least for now > the only target that needs this is AMDGCN and the only target that has > NUM_POLY_INT_COEFFS != 1 is aarch64 (maybe eventually riscv?), then I don't > see why we should represent it in poly_uint16... > Of course we can change it later if a target which needs both > NUM_POLY_INT_COEFFS > 1 and span > 1 registers with non-constant span_width, > we can change it, but doing it just in case seems unnecessary > complication... Done in the attached patch. Is it ok? Thanks,
On Thu, Nov 11, 2021 at 06:12:50PM +0000, Hafiz Abid Qadeer wrote: > * 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*, 2 spaces instead of 1 before Support above. > + cfa->reg.set_by_dwreg ((op == DW_OP_bregx) > + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0)); Formatting. All those 3 () inner pairs are unnecessary, and it would be nicer to use a temporary, like: unsigned regno = (op == DW_OP_bregx ? ptr->dw_loc_oprnd1.v.val_int : op - DW_OP_breg0); cfa->reg.set_by_dwreg (regno); > + unsigned int regno = (op == DW_OP_bregx) > + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0); With the ()s similarly, and also ? should be below op. > + gcc_assert (regno == (cfa->reg.reg - 1)); Again, the inner () pair is unnecessary. > + cfa->reg.span_width = (cfa->offset.to_constant () / 8); And here the outer () pair. > + > +#if CHECKING_P Please use if (CHECKING_P) instead of #if. > + /* 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; > @@ -3135,7 +3267,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)); If at all possible, avoid function name on one line and ( with first argument on another one. In the above case it can be easily avoided by dw_frame_pointer_regnum = dwf_cfa_reg (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM)); > +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)); Bad formatting, (DW_OP_breg0 should be below (enum > + > + /* deal with the remaining registers in the span. */ Capital letter on Deal > + for (int i = (reg.span - 2); i >= 0; i--) Please remove the redundant inner () pair. > --- a/gcc/dwarf2out.h > +++ b/gcc/dwarf2out.h > @@ -119,6 +119,38 @@ 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 short span; > + unsigned short 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 The normal C++ way would be (const cfa_reg &other), wouldn't it? Or otherwise the const keyword doesn't make much sense. > + { > + return (reg == other.reg && span == other.span > + && (span_width == other.span_width > + || (span == 1 > + && (span_width == 0 || other.span_width == 0)))); > + } > + bool operator!= (const cfa_reg other) const Likewise. Please add an empty line above operator!= > + { > + return !(*this == other); > + } > +}; > + Otherwise LGTM. Jakub
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));