From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id C12273858410 for ; Thu, 11 Nov 2021 18:12:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C12273858410 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=mentor.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: EddFAen+naadrA6acuCKtNYy0xFFKDJs9Czppgk4X1T+n6BnDWLOgd6mcGtlawe50tbbIRSv6b zqH3GJyPabK3sJfRqAbyjtV+cRRyuUVFzBUx67pkWd/ZKjuIYU//0tHEDB6LDHJUgTQtF+9rbt mvLeVLYu3TXQ9e36JoTPPJX9aB1oY0TnKAo3mQGKI3au8J+1u6SHpsr3ClfWMLp0pNc90djjWj iyKFf9xvI4AVr0cCwZx2OKYlLdApl5hIBTSy2J3H+xBgauAhi7RZ01+V0z7bZYGSxmkTiEZfRj myQDV0H5I7vzFQDjxVxnNSdS X-IronPort-AV: E=Sophos;i="5.87,226,1631606400"; d="scan'208,223";a="68381671" Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa2.mentor.iphmx.com with ESMTP; 11 Nov 2021 10:12:55 -0800 IronPort-SDR: sE/mGEtunfxOKGsjC6ZYN6uojZoOlLFiuVLGYQyXUCfD/h+vnTV9E5fZmb7ZmFR+yQ5sERashs rSClBN75KIjiNOlJStIcg90tAcC5RLqUD3Q9XvJcxw6lXUJdaO2moem8/7DNExvq0dhJ/GYLtW B7mg8gndSPiqnbSjy+TMBVG1KdEaqDTCqQJyBlDFkPRmKYF+urG9ggx8txQeTV/UqCQSNaNByM 9xpt/k/58TsVZmmMFDjYt9G8pw9WCnpCzN0KRvpuWT/ARJOm0mzuT5DelrdHHd4A2FCqV/zZNy pMo= Subject: Re: [PATCH] dwarf: Multi-register CFI address support. To: Jakub Jelinek , Hafiz Abid Qadeer , Jason Merrill CC: , References: <20210613132738.615611-1-abidh@codesourcery.com> <20211109155914.GW2710@tucnak> From: Hafiz Abid Qadeer Message-ID: <12350943-7112-7080-d69e-81c23136b968@mentor.com> Date: Thu, 11 Nov 2021 18:12:50 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0 MIME-Version: 1.0 In-Reply-To: <20211109155914.GW2710@tucnak> Content-Type: multipart/mixed; boundary="------------AC459F103E32F966C38C808E" Content-Language: en-US X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-02.mgc.mentorg.com (139.181.222.2) To SVR-IES-MBX-03.mgc.mentorg.com (139.181.222.3) X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, NICE_REPLY_A, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Nov 2021 18:13:01 -0000 --------------AC459F103E32F966C38C808E Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit 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, -- Hafiz Abid Qadeer Mentor, a Siemens Business --------------AC459F103E32F966C38C808E Content-Type: text/x-patch; charset="UTF-8"; name="0001-dwarf-Multi-register-CFI-address-support.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0001-dwarf-Multi-register-CFI-address-support.patch" >From dd25eccd2458c6b6d38a922d9b2c9107c4c0ba2d Mon Sep 17 00:00:00 2001 From: Hafiz Abid Qadeer Date: Thu, 11 Nov 2021 13:43:04 +0000 Subject: [PATCH] dwarf: Multi-register CFI address support. 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. --- gcc/dwarf2cfi.c | 261 ++++++++++++++++++++++++++++++++++++------------ gcc/dwarf2out.c | 54 +++++++++- gcc/dwarf2out.h | 35 ++++++- 3 files changed, 280 insertions(+), 70 deletions(-) diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index df9b625f5bc..eea9959379e 100644 --- a/gcc/dwarf2cfi.c +++ b/gcc/dwarf2cfi.c @@ -229,8 +229,8 @@ static vec 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 (); - 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: + */ + + 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 " instruction, indicating the CFA register has changed to 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,44 @@ 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 = 0; + + 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))). + to_constant (); + +#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 +1209,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 +1219,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 +1293,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 +1310,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 +1321,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 +1343,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 +1367,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 +1384,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 +1396,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 +1408,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 +1794,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 +1804,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 +1825,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 +1849,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 +1883,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 +1896,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 +1911,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 +1926,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 +1935,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 +1978,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 +2065,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 +2090,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 +2107,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 +2125,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 +2142,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 +2169,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 +3081,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 +3144,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 +3193,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 +3207,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 +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)); /* The first time we're called, compute the incoming frame state. */ if (cie_cfi_vec == NULL) @@ -3515,7 +3648,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 fb0e3381e5b..44efefdbacd 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2780,6 +2780,43 @@ 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 * 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. */ @@ -2791,9 +2828,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); @@ -2801,7 +2845,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; } @@ -2819,7 +2863,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)); @@ -20875,7 +20919,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 312a9909784..00d53a58b54 100644 --- 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 + { + 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 + { + 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 +160,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 +317,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); -- 2.25.1 --------------AC459F103E32F966C38C808E--