From: Hafiz Abid Qadeer <abid_qadeer@mentor.com>
To: Hafiz Abid Qadeer <abidh@codesourcery.com>, <gcc-patches@gcc.gnu.org>
Cc: <jakub@redhat.com>, <ams@codesourcery.com>
Subject: Re: [PATCH] dwarf: Multi-register CFI address support.
Date: Tue, 2 Nov 2021 15:02:16 +0000 [thread overview]
Message-ID: <02df9cc2-90f9-1955-817b-c006ea1d767c@mentor.com> (raw)
In-Reply-To: <1b031910-abfe-da5c-b0f5-3936a10d0612@mentor.com>
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;
>>> \f
>>> /* Hook used by __throw. */
>>>
>>> @@ -430,7 +430,7 @@ new_cfi_row (void)
>>> {
>>> dw_cfi_row *row = ggc_cleared_alloc<dw_cfi_row> ();
>>>
>>> - row->cfa.reg = INVALID_REGNUM;
>>> + row->cfa.reg.set_by_dwreg (INVALID_REGNUM);
>>>
>>> return row;
>>> }
>>> @@ -538,7 +538,7 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
>>> cfa->offset = 0;
>>> cfa->base_offset = 0;
>>> cfa->indirect = 0;
>>> - cfa->reg = -1;
>>> + cfa->reg.set_by_dwreg (INVALID_REGNUM);
>>>
>>> for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
>>> {
>>> @@ -578,10 +578,10 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
>>> case DW_OP_reg29:
>>> case DW_OP_reg30:
>>> case DW_OP_reg31:
>>> - cfa->reg = op - DW_OP_reg0;
>>> + cfa->reg.set_by_dwreg (op - DW_OP_reg0);
>>> break;
>>> case DW_OP_regx:
>>> - cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
>>> + cfa->reg.set_by_dwreg (ptr->dw_loc_oprnd1.v.val_int);
>>> break;
>>> case DW_OP_breg0:
>>> case DW_OP_breg1:
>>> @@ -615,16 +615,92 @@ get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
>>> case DW_OP_breg29:
>>> case DW_OP_breg30:
>>> case DW_OP_breg31:
>>> - cfa->reg = op - DW_OP_breg0;
>>> - cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
>>> - break;
>>> case DW_OP_bregx:
>>> - cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
>>> - cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
>>> + if (cfa->reg.reg == INVALID_REGNUM)
>>> + {
>>> + cfa->reg.set_by_dwreg ((op == DW_OP_bregx)
>>> + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0));
>>> + cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
>>> + }
>>> + else
>>> + {
>>> + /* Handle case when span can cover multiple registers. We
>>> + only support the simple case of consecutive registers
>>> + all with the same size. DWARF that we are dealing with
>>> + will look something like:
>>> + <DW_OP_bregx: (r49) 0; DW_OP_const1u: 32; DW_OP_shl;
>>> + DW_OP_bregx: (r48) 0; DW_OP_plus> */
>>> +
>>> + unsigned int regno = (op == DW_OP_bregx)
>>> + ? (ptr->dw_loc_oprnd1.v.val_int) : (op - DW_OP_breg0);
>>> + gcc_assert (regno == (cfa->reg.reg - 1));
>>> + cfa->reg.span++;
>>> + /* From all the consecutive registers used, we want to set
>>> + cfa->reg.reg to lower number register. */
>>> + cfa->reg.reg = regno;
>>> + /* The offset was the shift value. Use it to get the
>>> + span_width and then set it to 0. */
>>> + cfa->reg.span_width = (cfa->offset.to_constant () / 8);
>>> + cfa->offset = 0;
>>> + }
>>> break;
>>> case DW_OP_deref:
>>> cfa->indirect = 1;
>>> break;
>>> + case DW_OP_shl:
>>> + break;
>>> + case DW_OP_lit0:
>>> + case DW_OP_lit1:
>>> + case DW_OP_lit2:
>>> + case DW_OP_lit3:
>>> + case DW_OP_lit4:
>>> + case DW_OP_lit5:
>>> + case DW_OP_lit6:
>>> + case DW_OP_lit7:
>>> + case DW_OP_lit8:
>>> + case DW_OP_lit9:
>>> + case DW_OP_lit10:
>>> + case DW_OP_lit11:
>>> + case DW_OP_lit12:
>>> + case DW_OP_lit13:
>>> + case DW_OP_lit14:
>>> + case DW_OP_lit15:
>>> + case DW_OP_lit16:
>>> + case DW_OP_lit17:
>>> + case DW_OP_lit18:
>>> + case DW_OP_lit19:
>>> + case DW_OP_lit20:
>>> + case DW_OP_lit21:
>>> + case DW_OP_lit22:
>>> + case DW_OP_lit23:
>>> + case DW_OP_lit24:
>>> + case DW_OP_lit25:
>>> + case DW_OP_lit26:
>>> + case DW_OP_lit27:
>>> + case DW_OP_lit28:
>>> + case DW_OP_lit29:
>>> + case DW_OP_lit30:
>>> + case DW_OP_lit31:
>>> + gcc_assert (known_eq (cfa->offset, 0));
>>> + cfa->offset = op - DW_OP_lit0;
>>> + break;
>>> + case DW_OP_const1u:
>>> + case DW_OP_const1s:
>>> + case DW_OP_const2u:
>>> + case DW_OP_const2s:
>>> + case DW_OP_const4s:
>>> + case DW_OP_const8s:
>>> + case DW_OP_constu:
>>> + case DW_OP_consts:
>>> + gcc_assert (known_eq (cfa->offset, 0));
>>> + cfa->offset = ptr->dw_loc_oprnd1.v.val_int;
>>> + break;
>>> + case DW_OP_minus:
>>> + cfa->offset = -cfa->offset;
>>> + break;
>>> + case DW_OP_plus:
>>> + /* The offset is already in place. */
>>> + break;
>>> case DW_OP_plus_uconst:
>>> cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
>>> break;
>>> @@ -648,11 +724,11 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
>>> loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
>>> break;
>>> case DW_CFA_def_cfa_register:
>>> - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
>>> + loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
>>> break;
>>> case DW_CFA_def_cfa:
>>> case DW_CFA_def_cfa_sf:
>>> - loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
>>> + loc->reg.set_by_dwreg (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
>>> loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
>>> break;
>>> case DW_CFA_def_cfa_expression:
>>> @@ -798,6 +874,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
>>>
>>> HOST_WIDE_INT const_offset;
>>> if (new_cfa->reg == old_cfa->reg
>>> + && new_cfa->reg.span == 1
>>> && !new_cfa->indirect
>>> && !old_cfa->indirect
>>> && new_cfa->offset.is_constant (&const_offset))
>>> @@ -814,7 +891,8 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
>>> }
>>> else if (new_cfa->offset.is_constant ()
>>> && known_eq (new_cfa->offset, old_cfa->offset)
>>> - && old_cfa->reg != INVALID_REGNUM
>>> + && old_cfa->reg.reg != INVALID_REGNUM
>>> + && new_cfa->reg.span == 1
>>> && !new_cfa->indirect
>>> && !old_cfa->indirect)
>>> {
>>> @@ -824,10 +902,11 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
>>> been set as a register plus offset rather than a general
>>> DW_CFA_def_cfa_expression. */
>>> cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
>>> - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
>>> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg;
>>> }
>>> else if (new_cfa->indirect == 0
>>> - && new_cfa->offset.is_constant (&const_offset))
>>> + && new_cfa->offset.is_constant (&const_offset)
>>> + && new_cfa->reg.span == 1)
>>> {
>>> /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
>>> indicating the CFA register has changed to <register> with
>>> @@ -838,7 +917,7 @@ def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
>>> cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
>>> else
>>> cfi->dw_cfi_opc = DW_CFA_def_cfa;
>>> - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
>>> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg.reg;
>>> cfi->dw_cfi_oprnd2.dw_cfi_offset = const_offset;
>>> }
>>> else
>>> @@ -885,18 +964,18 @@ def_cfa_1 (dw_cfa_location *new_cfa)
>>> }
>>>
>>> /* Add the CFI for saving a register. REG is the CFA column number.
>>> - If SREG is -1, the register is saved at OFFSET from the CFA;
>>> + If SREG is INVALID_REGISTER, the register is saved at OFFSET from the CFA;
>>> otherwise it is saved in SREG. */
>>>
>>> static void
>>> -reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
>>> +reg_save (unsigned int reg, struct cfa_reg sreg, poly_int64 offset)
>>> {
>>> dw_fde_ref fde = cfun ? cfun->fde : NULL;
>>> dw_cfi_ref cfi = new_cfi ();
>>>
>>> cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
>>>
>>> - if (sreg == INVALID_REGNUM)
>>> + if (sreg.reg == INVALID_REGNUM)
>>> {
>>> HOST_WIDE_INT const_offset;
>>> /* When stack is aligned, store REG using DW_CFA_expression with FP. */
>>> @@ -926,7 +1005,7 @@ reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
>>> = build_cfa_loc (&cur_row->cfa, offset);
>>> }
>>> }
>>> - else if (sreg == reg)
>>> + else if (sreg.reg == reg)
>>> {
>>> /* While we could emit something like DW_CFA_same_value or
>>> DW_CFA_restore, we never expect to see something like that
>>> @@ -934,10 +1013,16 @@ reg_save (unsigned int reg, unsigned int sreg, poly_int64 offset)
>>> can always bypass this by using REG_CFA_RESTORE directly. */
>>> gcc_unreachable ();
>>> }
>>> + else if (sreg.span > 1)
>>> + {
>>> + cfi->dw_cfi_opc = DW_CFA_expression;
>>> + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
>>> + cfi->dw_cfi_oprnd2.dw_cfi_loc = build_span_loc (sreg);
>>> + }
>>> else
>>> {
>>> cfi->dw_cfi_opc = DW_CFA_register;
>>> - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
>>> + cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg.reg;
>>> }
>>>
>>> add_cfi (cfi);
>>> @@ -1018,6 +1103,43 @@ dwf_regno (const_rtx reg)
>>> return DWARF_FRAME_REGNUM (REGNO (reg));
>>> }
>>>
>>> +/* Like dwf_regno, but when the value can span multiple registers. */
>>> +
>>> +static struct cfa_reg
>>> +dwf_cfa_reg (rtx reg)
>>> +{
>>> + struct cfa_reg result;
>>> +
>>> + gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER);
>>> +
>>> + result.reg = dwf_regno (reg);
>>> + result.span = 1;
>>> + result.span_width = GET_MODE_SIZE (GET_MODE (reg));
>>> +
>>> + rtx span = targetm.dwarf_register_span (reg);
>>> + if (span)
>>> + {
>>> + /* We only support the simple case of consecutive registers all with the
>>> + same size. */
>>> + result.span = XVECLEN (span, 0);
>>> + result.span_width = GET_MODE_SIZE (GET_MODE (XVECEXP (span, 0, 0)));
>>> +
>>> +#if CHECKING_P
>>> + /* Ensure that the above assumption is accurate. */
>>> + for (unsigned int i = 0; i < result.span; i++)
>>> + {
>>> + gcc_assert (known_eq (GET_MODE_SIZE (GET_MODE (XVECEXP (span,
>>> + 0, i))),
>>> + result.span_width));
>>> + gcc_assert (REG_P (XVECEXP (span, 0, i)));
>>> + gcc_assert (dwf_regno (XVECEXP (span, 0, i)) == result.reg + i);
>>> + }
>>> +#endif
>>> + }
>>> +
>>> + return result;
>>> +}
>>> +
>>> /* Compare X and Y for equivalence. The inputs may be REGs or PC_RTX. */
>>>
>>> static bool
>>> @@ -1086,7 +1208,8 @@ dwarf2out_flush_queued_reg_saves (void)
>>>
>>> FOR_EACH_VEC_ELT (queued_reg_saves, i, q)
>>> {
>>> - unsigned int reg, sreg;
>>> + unsigned int reg;
>>> + struct cfa_reg sreg;
>>>
>>> record_reg_saved_in_reg (q->saved_reg, q->reg);
>>>
>>> @@ -1095,9 +1218,9 @@ dwarf2out_flush_queued_reg_saves (void)
>>> else
>>> reg = dwf_regno (q->reg);
>>> if (q->saved_reg)
>>> - sreg = dwf_regno (q->saved_reg);
>>> + sreg = dwf_cfa_reg (q->saved_reg);
>>> else
>>> - sreg = INVALID_REGNUM;
>>> + sreg.set_by_dwreg (INVALID_REGNUM);
>>> reg_save (reg, sreg, q->cfa_offset);
>>> }
>>>
>>> @@ -1169,7 +1292,7 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
>>> /* ??? If this fails, we could be calling into the _loc functions to
>>> define a full expression. So far no port does that. */
>>> gcc_assert (REG_P (pat));
>>> - cur_cfa->reg = dwf_regno (pat);
>>> + cur_cfa->reg = dwf_cfa_reg (pat);
>>> }
>>>
>>> /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */
>>> @@ -1186,7 +1309,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
>>> switch (GET_CODE (src))
>>> {
>>> case PLUS:
>>> - gcc_assert (dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
>>> + gcc_assert (dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg);
>>> cur_cfa->offset -= rtx_to_poly_int64 (XEXP (src, 1));
>>> break;
>>>
>>> @@ -1197,7 +1320,7 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
>>> gcc_unreachable ();
>>> }
>>>
>>> - cur_cfa->reg = dwf_regno (dest);
>>> + cur_cfa->reg = dwf_cfa_reg (dest);
>>> gcc_assert (cur_cfa->indirect == 0);
>>> }
>>>
>>> @@ -1219,11 +1342,11 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
>>> switch (GET_CODE (addr))
>>> {
>>> case REG:
>>> - gcc_assert (dwf_regno (addr) == cur_cfa->reg);
>>> + gcc_assert (dwf_cfa_reg (addr) == cur_cfa->reg);
>>> offset = -cur_cfa->offset;
>>> break;
>>> case PLUS:
>>> - gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_cfa->reg);
>>> + gcc_assert (dwf_cfa_reg (XEXP (addr, 0)) == cur_cfa->reg);
>>> offset = rtx_to_poly_int64 (XEXP (addr, 1)) - cur_cfa->offset;
>>> break;
>>> default:
>>> @@ -1243,8 +1366,10 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
>>>
>>> /* ??? We'd like to use queue_reg_save, but we need to come up with
>>> a different flushing heuristic for epilogues. */
>>> + struct cfa_reg invalid;
>>> + invalid.set_by_dwreg (INVALID_REGNUM);
>>> if (!span)
>>> - reg_save (sregno, INVALID_REGNUM, offset);
>>> + reg_save (sregno, invalid, offset);
>>> else
>>> {
>>> /* We have a PARALLEL describing where the contents of SRC live.
>>> @@ -1258,7 +1383,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
>>> {
>>> rtx elem = XVECEXP (span, 0, par_index);
>>> sregno = dwf_regno (src);
>>> - reg_save (sregno, INVALID_REGNUM, span_offset);
>>> + reg_save (sregno, invalid, span_offset);
>>> span_offset += GET_MODE_SIZE (GET_MODE (elem));
>>> }
>>> }
>>> @@ -1270,7 +1395,8 @@ static void
>>> dwarf2out_frame_debug_cfa_register (rtx set)
>>> {
>>> rtx src, dest;
>>> - unsigned sregno, dregno;
>>> + unsigned sregno;
>>> + struct cfa_reg dregno;
>>>
>>> src = XEXP (set, 1);
>>> dest = XEXP (set, 0);
>>> @@ -1281,7 +1407,7 @@ dwarf2out_frame_debug_cfa_register (rtx set)
>>> else
>>> sregno = dwf_regno (src);
>>>
>>> - dregno = dwf_regno (dest);
>>> + dregno = dwf_cfa_reg (dest);
>>>
>>> /* ??? We'd like to use queue_reg_save, but we need to come up with
>>> a different flushing heuristic for epilogues. */
>>> @@ -1667,7 +1793,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> {
>>> /* Setting FP from SP. */
>>> case REG:
>>> - if (cur_cfa->reg == dwf_regno (src))
>>> + if (cur_cfa->reg == dwf_cfa_reg (src))
>>> {
>>> /* Rule 1 */
>>> /* Update the CFA rule wrt SP or FP. Make sure src is
>>> @@ -1677,7 +1803,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> ARM copies SP to a temporary register, and from there to
>>> FP. So we just rely on the backends to only set
>>> RTX_FRAME_RELATED_P on appropriate insns. */
>>> - cur_cfa->reg = dwf_regno (dest);
>>> + cur_cfa->reg = dwf_cfa_reg (dest);
>>> cur_trace->cfa_temp.reg = cur_cfa->reg;
>>> cur_trace->cfa_temp.offset = cur_cfa->offset;
>>> }
>>> @@ -1698,7 +1824,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> {
>>> gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM
>>> && fde->drap_reg != INVALID_REGNUM
>>> - && cur_cfa->reg != dwf_regno (src)
>>> + && cur_cfa->reg != dwf_cfa_reg (src)
>>> && fde->rule18);
>>> fde->rule18 = 0;
>>> /* The save of hard frame pointer has been deferred
>>> @@ -1722,7 +1848,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> /* Adjusting SP. */
>>> if (REG_P (XEXP (src, 1)))
>>> {
>>> - gcc_assert (dwf_regno (XEXP (src, 1))
>>> + gcc_assert (dwf_cfa_reg (XEXP (src, 1))
>>> == cur_trace->cfa_temp.reg);
>>> offset = cur_trace->cfa_temp.offset;
>>> }
>>> @@ -1756,7 +1882,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> gcc_assert (frame_pointer_needed);
>>>
>>> gcc_assert (REG_P (XEXP (src, 0))
>>> - && dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
>>> + && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg);
>>> offset = rtx_to_poly_int64 (XEXP (src, 1));
>>> if (GET_CODE (src) != MINUS)
>>> offset = -offset;
>>> @@ -1769,14 +1895,14 @@ dwarf2out_frame_debug_expr (rtx expr)
>>>
>>> /* Rule 4 */
>>> if (REG_P (XEXP (src, 0))
>>> - && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
>>> + && dwf_cfa_reg (XEXP (src, 0)) == cur_cfa->reg
>>> && poly_int_rtx_p (XEXP (src, 1), &offset))
>>> {
>>> /* Setting a temporary CFA register that will be copied
>>> into the FP later on. */
>>> offset = -offset;
>>> cur_cfa->offset += offset;
>>> - cur_cfa->reg = dwf_regno (dest);
>>> + cur_cfa->reg = dwf_cfa_reg (dest);
>>> /* Or used to save regs to the stack. */
>>> cur_trace->cfa_temp.reg = cur_cfa->reg;
>>> cur_trace->cfa_temp.offset = cur_cfa->offset;
>>> @@ -1784,13 +1910,13 @@ dwarf2out_frame_debug_expr (rtx expr)
>>>
>>> /* Rule 5 */
>>> else if (REG_P (XEXP (src, 0))
>>> - && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
>>> + && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg
>>> && XEXP (src, 1) == stack_pointer_rtx)
>>> {
>>> /* Setting a scratch register that we will use instead
>>> of SP for saving registers to the stack. */
>>> gcc_assert (cur_cfa->reg == dw_stack_pointer_regnum);
>>> - cur_trace->cfa_store.reg = dwf_regno (dest);
>>> + cur_trace->cfa_store.reg = dwf_cfa_reg (dest);
>>> cur_trace->cfa_store.offset
>>> = cur_cfa->offset - cur_trace->cfa_temp.offset;
>>> }
>>> @@ -1799,7 +1925,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> else if (GET_CODE (src) == LO_SUM
>>> && poly_int_rtx_p (XEXP (src, 1),
>>> &cur_trace->cfa_temp.offset))
>>> - cur_trace->cfa_temp.reg = dwf_regno (dest);
>>> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
>>> else
>>> gcc_unreachable ();
>>> }
>>> @@ -1808,17 +1934,17 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> /* Rule 6 */
>>> case CONST_INT:
>>> case CONST_POLY_INT:
>>> - cur_trace->cfa_temp.reg = dwf_regno (dest);
>>> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
>>> cur_trace->cfa_temp.offset = rtx_to_poly_int64 (src);
>>> break;
>>>
>>> /* Rule 7 */
>>> case IOR:
>>> gcc_assert (REG_P (XEXP (src, 0))
>>> - && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
>>> + && dwf_cfa_reg (XEXP (src, 0)) == cur_trace->cfa_temp.reg
>>> && CONST_INT_P (XEXP (src, 1)));
>>>
>>> - cur_trace->cfa_temp.reg = dwf_regno (dest);
>>> + cur_trace->cfa_temp.reg = dwf_cfa_reg (dest);
>>> if (!can_ior_p (cur_trace->cfa_temp.offset, INTVAL (XEXP (src, 1)),
>>> &cur_trace->cfa_temp.offset))
>>> /* The target shouldn't generate this kind of CFI note if we
>>> @@ -1851,14 +1977,17 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> dwarf2out_flush_queued_reg_saves ();
>>>
>>> gcc_assert (cur_trace->cfa_store.reg
>>> - == dwf_regno (XEXP (src, 0)));
>>> + == dwf_cfa_reg (XEXP (src, 0)));
>>> fde->stack_realign = 1;
>>> fde->stack_realignment = INTVAL (XEXP (src, 1));
>>> cur_trace->cfa_store.offset = 0;
>>>
>>> if (cur_cfa->reg != dw_stack_pointer_regnum
>>> && cur_cfa->reg != dw_frame_pointer_regnum)
>>> - fde->drap_reg = cur_cfa->reg;
>>> + {
>>> + gcc_assert (cur_cfa->reg.span == 1);
>>> + fde->drap_reg = cur_cfa->reg.reg;
>>> + }
>>> }
>>> return;
>>>
>>> @@ -1935,14 +2064,14 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> case MINUS:
>>> case LO_SUM:
>>> {
>>> - unsigned int regno;
>>> + struct cfa_reg regno;
>>>
>>> gcc_assert (REG_P (XEXP (XEXP (dest, 0), 0)));
>>> offset = rtx_to_poly_int64 (XEXP (XEXP (dest, 0), 1));
>>> if (GET_CODE (XEXP (dest, 0)) == MINUS)
>>> offset = -offset;
>>>
>>> - regno = dwf_regno (XEXP (XEXP (dest, 0), 0));
>>> + regno = dwf_cfa_reg (XEXP (XEXP (dest, 0), 0));
>>>
>>> if (cur_cfa->reg == regno)
>>> offset -= cur_cfa->offset;
>>> @@ -1960,7 +2089,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> /* Without an offset. */
>>> case REG:
>>> {
>>> - unsigned int regno = dwf_regno (XEXP (dest, 0));
>>> + struct cfa_reg regno = dwf_cfa_reg (XEXP (dest, 0));
>>>
>>> if (cur_cfa->reg == regno)
>>> offset = -cur_cfa->offset;
>>> @@ -1977,7 +2106,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> /* Rule 14 */
>>> case POST_INC:
>>> gcc_assert (cur_trace->cfa_temp.reg
>>> - == dwf_regno (XEXP (XEXP (dest, 0), 0)));
>>> + == dwf_cfa_reg (XEXP (XEXP (dest, 0), 0)));
>>> offset = -cur_trace->cfa_temp.offset;
>>> cur_trace->cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
>>> break;
>>> @@ -1995,7 +2124,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> if (REG_P (src)
>>> && REGNO (src) != STACK_POINTER_REGNUM
>>> && REGNO (src) != HARD_FRAME_POINTER_REGNUM
>>> - && dwf_regno (src) == cur_cfa->reg)
>>> + && dwf_cfa_reg (src) == cur_cfa->reg)
>>> {
>>> /* We're storing the current CFA reg into the stack. */
>>>
>>> @@ -2012,7 +2141,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> && cur_cfa->indirect == 0
>>> && cur_cfa->reg != dw_frame_pointer_regnum)
>>> {
>>> - gcc_assert (fde->drap_reg == cur_cfa->reg);
>>> + gcc_assert (fde->drap_reg == cur_cfa->reg.reg);
>>>
>>> cur_cfa->indirect = 1;
>>> cur_cfa->reg = dw_frame_pointer_regnum;
>>> @@ -2039,7 +2168,7 @@ dwarf2out_frame_debug_expr (rtx expr)
>>> x = XEXP (x, 0);
>>> gcc_assert (REG_P (x));
>>>
>>> - cur_cfa->reg = dwf_regno (x);
>>> + cur_cfa->reg = dwf_cfa_reg (x);
>>> cur_cfa->base_offset = offset;
>>> cur_cfa->indirect = 1;
>>> break;
>>> @@ -2951,7 +3080,7 @@ create_pseudo_cfg (void)
>>> ti.head = get_insns ();
>>> ti.beg_row = cie_cfi_row;
>>> ti.cfa_store = cie_cfi_row->cfa;
>>> - ti.cfa_temp.reg = INVALID_REGNUM;
>>> + ti.cfa_temp.reg.set_by_dwreg (INVALID_REGNUM);
>>> trace_info.quick_push (ti);
>>>
>>> if (cie_return_save)
>>> @@ -3014,14 +3143,15 @@ create_pseudo_cfg (void)
>>> static void
>>> initial_return_save (rtx rtl)
>>> {
>>> - unsigned int reg = INVALID_REGNUM;
>>> + struct cfa_reg reg;
>>> + reg.set_by_dwreg (INVALID_REGNUM);
>>> poly_int64 offset = 0;
>>>
>>> switch (GET_CODE (rtl))
>>> {
>>> case REG:
>>> /* RA is in a register. */
>>> - reg = dwf_regno (rtl);
>>> + reg = dwf_cfa_reg (rtl);
>>> break;
>>>
>>> case MEM:
>>> @@ -3062,9 +3192,9 @@ initial_return_save (rtx rtl)
>>> gcc_unreachable ();
>>> }
>>>
>>> - if (reg != DWARF_FRAME_RETURN_COLUMN)
>>> + if (reg.reg != DWARF_FRAME_RETURN_COLUMN)
>>> {
>>> - if (reg != INVALID_REGNUM)
>>> + if (reg.reg != INVALID_REGNUM)
>>> record_reg_saved_in_reg (rtl, pc_rtx);
>>> reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cur_row->cfa.offset);
>>> }
>>> @@ -3076,7 +3206,8 @@ create_cie_data (void)
>>> dw_cfa_location loc;
>>> dw_trace_info cie_trace;
>>>
>>> - dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
>>> + dw_stack_pointer_regnum = dwf_cfa_reg (gen_rtx_REG (Pmode,
>>> + STACK_POINTER_REGNUM));
>>>
>>> memset (&cie_trace, 0, sizeof (cie_trace));
>>> cur_trace = &cie_trace;
>>> @@ -3135,7 +3266,8 @@ static unsigned int
>>> execute_dwarf2_frame (void)
>>> {
>>> /* Different HARD_FRAME_POINTER_REGNUM might coexist in the same file. */
>>> - dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
>>> + dw_frame_pointer_regnum = dwf_cfa_reg (gen_rtx_REG
>>> + (Pmode, HARD_FRAME_POINTER_REGNUM));
>>>
>>> /* The first time we're called, compute the incoming frame state. */
>>> if (cie_cfi_vec == NULL)
>>> @@ -3515,7 +3647,7 @@ dump_cfi_row (FILE *f, dw_cfi_row *row)
>>> {
>>> dw_cfa_location dummy;
>>> memset (&dummy, 0, sizeof (dummy));
>>> - dummy.reg = INVALID_REGNUM;
>>> + dummy.reg.set_by_dwreg (INVALID_REGNUM);
>>> cfi = def_cfa_0 (&dummy, &row->cfa);
>>> }
>>> output_cfi_directive (f, cfi);
>>> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
>>> index 88eb3f9c455..a0b41df6da0 100644
>>> --- a/gcc/dwarf2out.c
>>> +++ b/gcc/dwarf2out.c
>>> @@ -2785,6 +2785,44 @@ output_loc_sequence_raw (dw_loc_descr_ref loc)
>>> }
>>> }
>>>
>>> +static void
>>> +build_breg_loc (struct dw_loc_descr_node **head, unsigned int regno)
>>> +{
>>> + if (regno <= 31)
>>> + add_loc_descr (head, new_loc_descr ((enum dwarf_location_atom)
>>> + (DW_OP_breg0 + regno), 0, 0));
>>> + else
>>> + add_loc_descr (head, new_loc_descr (DW_OP_bregx, regno, 0));
>>> +}
>>> +
>>> +/* Build a dwarf location for a cfa_reg spanning multiple
>>> + consecutive registers. */
>>> +
>>> +struct dw_loc_descr_node *
>>> +build_span_loc (struct cfa_reg reg)
>>> +{
>>> + struct dw_loc_descr_node *head = NULL;
>>> +
>>> + gcc_assert (known_gt (reg.span_width, 0));
>>> + gcc_assert (reg.span > 1);
>>> +
>>> + /* Start from the highest number register as it goes in the upper bits. */
>>> + unsigned int regno = reg.reg + reg.span - 1;
>>> + build_breg_loc (&head, regno);
>>> +
>>> + /* deal with the remaining registers in the span. */
>>> + for (int i = (reg.span - 2); i >= 0; i--)
>>> + {
>>> + add_loc_descr (&head, int_loc_descriptor
>>> + (reg.span_width.to_constant () * 8));
>>> + add_loc_descr (&head, new_loc_descr (DW_OP_shl, 0, 0));
>>> + regno--;
>>> + build_breg_loc (&head, regno);
>>> + add_loc_descr (&head, new_loc_descr (DW_OP_plus, 0, 0));
>>> + }
>>> + return head;
>>> +}
>>> +
>>> /* This function builds a dwarf location descriptor sequence from a
>>> dw_cfa_location, adding the given OFFSET to the result of the
>>> expression. */
>>> @@ -2796,9 +2834,16 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset)
>>>
>>> offset += cfa->offset;
>>>
>>> - if (cfa->indirect)
>>> + if (cfa->reg.span > 1)
>>> + {
>>> + head = build_span_loc (cfa->reg);
>>> +
>>> + if (maybe_ne (offset, 0))
>>> + loc_descr_plus_const (&head, offset);
>>> + }
>>> + else if (cfa->indirect)
>>> {
>>> - head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
>>> + head = new_reg_loc_descr (cfa->reg.reg, cfa->base_offset);
>>> head->dw_loc_oprnd1.val_class = dw_val_class_const;
>>> head->dw_loc_oprnd1.val_entry = NULL;
>>> tmp = new_loc_descr (DW_OP_deref, 0, 0);
>>> @@ -2806,7 +2851,7 @@ build_cfa_loc (dw_cfa_location *cfa, poly_int64 offset)
>>> loc_descr_plus_const (&head, offset);
>>> }
>>> else
>>> - head = new_reg_loc_descr (cfa->reg, offset);
>>> + head = new_reg_loc_descr (cfa->reg.reg, offset);
>>>
>>> return head;
>>> }
>>> @@ -2824,7 +2869,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
>>> = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
>>>
>>> /* When CFA is defined as FP+OFFSET, emulate stack alignment. */
>>> - if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
>>> + if (cfa->reg.reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
>>> {
>>> head = new_reg_loc_descr (dwarf_fp, 0);
>>> add_loc_descr (&head, int_loc_descriptor (alignment));
>>> @@ -20865,7 +20910,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
>>> list = NULL;
>>>
>>> memset (&next_cfa, 0, sizeof (next_cfa));
>>> - next_cfa.reg = INVALID_REGNUM;
>>> + next_cfa.reg.set_by_dwreg (INVALID_REGNUM);
>>> remember = next_cfa;
>>>
>>> start_label = fde->dw_fde_begin;
>>> diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
>>> index 54b6343704c..38b52c8e1c2 100644
>>> --- a/gcc/dwarf2out.h
>>> +++ b/gcc/dwarf2out.h
>>> @@ -119,6 +119,40 @@ struct GTY(()) dw_fde_node {
>>> };
>>>
>>>
>>> +/* This represents a register, in DWARF_FRAME_REGNUM space, for use in CFA
>>> + definitions and expressions.
>>> + Most architectures only need a single register number, but some (amdgcn)
>>> + have pointers that span multiple registers. DWARF permits arbitrary
>>> + register sets but existing use-cases only require contiguous register
>>> + sets, as represented here. */
>>> +struct GTY(()) cfa_reg {
>>> + unsigned int reg;
>>> + unsigned int span;
>>> + poly_uint16_pod span_width; /* A.K.A. register mode size. */
>>> +
>>> + cfa_reg& set_by_dwreg (unsigned int r)
>>> + {
>>> + reg = r;
>>> + span = 1;
>>> + span_width = 0; /* Unknown size (permitted when span == 1). */
>>> + return *this;
>>> + }
>>> +
>>> + bool operator== (const cfa_reg other) const
>>> + {
>>> + return (reg == other.reg
>>> + && span == other.span
>>> + && (known_eq (span_width, other.span_width)
>>> + || (span == 1
>>> + && (known_eq (span_width, 0)
>>> + || known_eq (other.span_width, 0)))));
>>> + }
>>> + bool operator!= (const cfa_reg other) const
>>> + {
>>> + return !(*this == other);
>>> + }
>>> +};
>>> +
>>> /* This is how we define the location of the CFA. We use to handle it
>>> as REG + OFFSET all the time, but now it can be more complex.
>>> It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
>>> @@ -128,7 +162,7 @@ struct GTY(()) dw_cfa_location {
>>> poly_int64_pod offset;
>>> poly_int64_pod base_offset;
>>> /* REG is in DWARF_FRAME_REGNUM space, *not* normal REGNO space. */
>>> - unsigned int reg;
>>> + struct cfa_reg reg;
>>> BOOL_BITFIELD indirect : 1; /* 1 if CFA is accessed via a dereference. */
>>> BOOL_BITFIELD in_use : 1; /* 1 if a saved cfa is stored here. */
>>> };
>>> @@ -285,6 +319,7 @@ extern struct dw_loc_descr_node *build_cfa_loc
>>> (dw_cfa_location *, poly_int64);
>>> extern struct dw_loc_descr_node *build_cfa_aligned_loc
>>> (dw_cfa_location *, poly_int64, HOST_WIDE_INT);
>>> +extern struct dw_loc_descr_node *build_span_loc (struct cfa_reg);
>>> extern struct dw_loc_descr_node *mem_loc_descriptor
>>> (rtx, machine_mode mode, machine_mode mem_mode,
>>> enum var_init_status);
>>> diff --git a/gcc/gengtype.c b/gcc/gengtype.c
>>> index b94e2f126ec..45e9f856470 100644
>>> --- a/gcc/gengtype.c
>>> +++ b/gcc/gengtype.c
>>> @@ -5195,6 +5195,7 @@ main (int argc, char **argv)
>>> POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
>>> POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
>>> POS_HERE (do_scalar_typedef ("double_int", &pos));
>>> + POS_HERE (do_scalar_typedef ("poly_uint16_pod", &pos));
>>> POS_HERE (do_scalar_typedef ("poly_int64_pod", &pos));
>>> POS_HERE (do_scalar_typedef ("offset_int", &pos));
>>> POS_HERE (do_scalar_typedef ("widest_int", &pos));
>>>
>>
>>
>
>
--
Hafiz Abid Qadeer
Mentor, a Siemens Business
next prev parent reply other threads:[~2021-11-02 15:02 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-13 13:27 Hafiz Abid Qadeer
2021-07-22 10:58 ` Hafiz Abid Qadeer
2021-08-24 15:55 ` Hafiz Abid Qadeer
2021-11-02 15:02 ` Hafiz Abid Qadeer [this message]
2021-11-09 15:59 ` Jakub Jelinek
2021-11-11 18:12 ` Hafiz Abid Qadeer
2021-12-01 15:49 ` Jakub Jelinek
-- strict thread matches above, loose matches on Subject: below --
2020-08-28 12:04 Andrew Stubbs
2020-09-02 17:49 ` Tom Tromey
2020-09-02 19:35 ` Andrew Stubbs
2020-09-02 19:55 ` Tom Tromey
2020-09-03 15:29 ` Andrew Stubbs
2020-09-21 13:51 ` Andrew Stubbs
2020-10-05 10:07 ` Andrew Stubbs
2020-10-19 9:36 ` Jakub Jelinek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=02df9cc2-90f9-1955-817b-c006ea1d767c@mentor.com \
--to=abid_qadeer@mentor.com \
--cc=abidh@codesourcery.com \
--cc=ams@codesourcery.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).