From patchwork Mon Nov 14 15:26:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Krebbel X-Patchwork-Id: 60604 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1512C38438E2 for ; Mon, 14 Nov 2022 15:27:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1512C38438E2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1668439660; bh=yafJBmYE8qTb5lJPP5ThaYAYKx717WZ6Kc7VAAoeFCM=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Y9mh1ENm+G7gBw7r13GciC6yzor6Vo8pTB8bhDB/0AxYYIbHNEvQZa8akjDJgJWy3 pjg0W2MEHVkG7lwpYiSfMbm4QpyJCrwlIl+aU/ZXhNnTizNJ2pnoUzFiOmQ+Xoa2hQ PuCecJiMP3ch5DsUo3CYEzLybCEAQ1LprN0D2ATk= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 0C2533858404 for ; Mon, 14 Nov 2022 15:27:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0C2533858404 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.5) with ESMTP id 2AEFPteX017364 for ; Mon, 14 Nov 2022 15:27:04 GMT Received: from ppma06fra.de.ibm.com (48.49.7a9f.ip4.static.sl-reverse.com [159.122.73.72]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3kurafr0db-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 14 Nov 2022 15:27:03 +0000 Received: from pps.filterd (ppma06fra.de.ibm.com [127.0.0.1]) by ppma06fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 2AEFLlY0001457 for ; Mon, 14 Nov 2022 15:27:01 GMT Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by ppma06fra.de.ibm.com with ESMTP id 3kt2rj21da-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 14 Nov 2022 15:27:01 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 2AEFQwi766126128 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 14 Nov 2022 15:26:58 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8C2AB11C050 for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 649FB11C04A for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) Received: from li-ecc9ffcc-3485-11b2-a85c-e633c5126265.fritz.box (unknown [9.179.13.145]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 1/2] New reg note REG_CFA_NORESTORE Date: Mon, 14 Nov 2022 16:26:56 +0100 Message-Id: <20221114152657.43632-2-krebbel@linux.ibm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221114152657.43632-1-krebbel@linux.ibm.com> References: <20221114152657.43632-1-krebbel@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: R9CarSX06k2OWL4Cnso3ufnbeN4sKKB8 X-Proofpoint-ORIG-GUID: R9CarSX06k2OWL4Cnso3ufnbeN4sKKB8 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2022-11-14_12,2022-11-11_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 lowpriorityscore=0 mlxlogscore=930 malwarescore=0 suspectscore=0 impostorscore=0 adultscore=0 mlxscore=0 phishscore=0 priorityscore=1501 spamscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2211140107 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andreas Krebbel via Gcc-patches From: Andreas Krebbel Reply-To: Andreas Krebbel Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch introduces a new reg note which can be used to tell the CFI verification in dwarf2cfi that a register is stored without intending to restore from it. This is useful when storing e.g. register contents to the stack and generate CFI for it although the register is not really supposed to be restored. gcc/ChangeLog: * dwarf2cfi.cc (dwarf2out_frame_debug_cfa_restore): Add EMIT_CFI parameter. (dwarf2out_frame_debug): Add case for REG_CFA_NORESTORE. * reg-notes.def (REG_CFA_NOTE): New reg note definition. --- gcc/dwarf2cfi.cc | 15 ++++++++++----- gcc/reg-notes.def | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc index bef3165e691..6686498d7cc 100644 --- a/gcc/dwarf2cfi.cc +++ b/gcc/dwarf2cfi.cc @@ -1496,10 +1496,12 @@ dwarf2out_frame_debug_cfa_val_expression (rtx set) update_row_reg_save (cur_row, dwf_regno (dest), cfi); } -/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */ +/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE + note. When called with EMIT_CFI set to false emitting a CFI + statement is suppressed. */ static void -dwarf2out_frame_debug_cfa_restore (rtx reg) +dwarf2out_frame_debug_cfa_restore (rtx reg, bool emit_cfi = true) { gcc_assert (REG_P (reg)); @@ -1507,7 +1509,8 @@ dwarf2out_frame_debug_cfa_restore (rtx reg) if (!span) { unsigned int regno = dwf_regno (reg); - add_cfi_restore (regno); + if (emit_cfi) + add_cfi_restore (regno); update_row_reg_save (cur_row, regno, NULL); } else @@ -1522,7 +1525,8 @@ dwarf2out_frame_debug_cfa_restore (rtx reg) reg = XVECEXP (span, 0, par_index); gcc_assert (REG_P (reg)); unsigned int regno = dwf_regno (reg); - add_cfi_restore (regno); + if (emit_cfi) + add_cfi_restore (regno); update_row_reg_save (cur_row, regno, NULL); } } @@ -2309,6 +2313,7 @@ dwarf2out_frame_debug (rtx_insn *insn) break; case REG_CFA_RESTORE: + case REG_CFA_NORESTORE: n = XEXP (note, 0); if (n == NULL) { @@ -2317,7 +2322,7 @@ dwarf2out_frame_debug (rtx_insn *insn) n = XVECEXP (n, 0, 0); n = XEXP (n, 0); } - dwarf2out_frame_debug_cfa_restore (n); + dwarf2out_frame_debug_cfa_restore (n, REG_NOTE_KIND (note) == REG_CFA_RESTORE); handled_one = true; break; diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def index 704bc75b0e7..ab08e65eedc 100644 --- a/gcc/reg-notes.def +++ b/gcc/reg-notes.def @@ -157,6 +157,11 @@ REG_CFA_NOTE (CFA_VAL_EXPRESSION) first pattern is the register to be restored. */ REG_CFA_NOTE (CFA_RESTORE) +/* Like CFA_RESTORE but without actually emitting CFI. This can be + used to tell the verification infrastructure that a register is + saved without intending to restore it. */ +REG_CFA_NOTE (CFA_NORESTORE) + /* Attached to insns that are RTX_FRAME_RELATED_P, marks insn that sets vDRAP from DRAP. If vDRAP is a register, vdrap_reg is initalized to the argument, if it is a MEM, it is ignored. */ From patchwork Mon Nov 14 15:26:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Krebbel X-Patchwork-Id: 60603 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F41CF38438E2 for ; Mon, 14 Nov 2022 15:27:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F41CF38438E2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1668439658; bh=XtMh5xOuIA1kSPdK28116Di/dky2A0gUb1d+sVMC+9I=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Y7vD8CcykTL/pB511LZHIXB3hwfZFeGgv48RH8mUH+IyjO0g3DbY6NuztY4i0+EB9 b9ZbRebO93LjkMR8EJ/LktDdQXxhT6XDE7muBz1p+YKKXR0QlzckAwdG2oR+n5D+Je JdXAGrxEUxA248jo27//19VNOkO5TP5uUn8V1Uvs= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id BDBD93858C3A for ; Mon, 14 Nov 2022 15:27:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BDBD93858C3A Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.5) with ESMTP id 2AEFFB9L003518 for ; Mon, 14 Nov 2022 15:27:03 GMT Received: from ppma04fra.de.ibm.com (6a.4a.5195.ip4.static.sl-reverse.com [149.81.74.106]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3kur5f0a2v-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 14 Nov 2022 15:27:03 +0000 Received: from pps.filterd (ppma04fra.de.ibm.com [127.0.0.1]) by ppma04fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 2AEFMC3t024179 for ; Mon, 14 Nov 2022 15:27:01 GMT Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by ppma04fra.de.ibm.com with ESMTP id 3kt349a0pk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 14 Nov 2022 15:27:01 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 2AEFQw2Y66126132 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 14 Nov 2022 15:26:58 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D0ED811C04C for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9EF0011C04A for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) Received: from li-ecc9ffcc-3485-11b2-a85c-e633c5126265.fritz.box (unknown [9.179.13.145]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Mon, 14 Nov 2022 15:26:58 +0000 (GMT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 2/2] IBM zSystems: Save argument registers to the stack -mpreserve-args Date: Mon, 14 Nov 2022 16:26:57 +0100 Message-Id: <20221114152657.43632-3-krebbel@linux.ibm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221114152657.43632-1-krebbel@linux.ibm.com> References: <20221114152657.43632-1-krebbel@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: K-H1HSNwWZVcVNwI72Es_myO-mJcDbYO X-Proofpoint-GUID: K-H1HSNwWZVcVNwI72Es_myO-mJcDbYO X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2022-11-14_12,2022-11-11_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 bulkscore=0 phishscore=0 lowpriorityscore=0 clxscore=1015 suspectscore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2211140107 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andreas Krebbel via Gcc-patches From: Andreas Krebbel Reply-To: Andreas Krebbel Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This adds support for preserving the content of parameter registers to the stack and emit CFI for it. This useful for applications which want to implement their own stack unwinding and need access to function arguments. With the -mpreserve-args option GPRs and FPRs are save to the stack slots which are reserved for stdargs in the register save area. gcc/ChangeLog: * config/s390/s390.cc (s390_restore_gpr_p): New function. (s390_preserve_gpr_arg_in_range_p): New function. (s390_preserve_gpr_arg_p): New function. (s390_preserve_fpr_args_p): New function. (s390_preserve_fpr_arg_p): New function. (s390_register_info_stdarg_fpr): Rename to ... (s390_register_info_arg_fpr): ... this. Add -mpreserve-args handling. (s390_register_info_stdarg_gpr): Rename to ... (s390_register_info_arg_gpr): ... this. Add -mpreserve-args handling. (s390_register_info): Use the renamed functions above. (s390_optimize_register_info): Likewise. (save_fpr): Generate CFI for -mpreserve-args. (save_gprs): Generate CFI for -mpreserve-args. Drop return value. (s390_emit_prologue): Adjust to changed calling convention of save_gprs. (s390_optimize_prologue): Likewise. * config/s390/s390.opt: New option -mpreserve-args gcc/testsuite/ChangeLog: * gcc.target/s390/preserve-args-1.c: New test. * gcc.target/s390/preserve-args-2.c: New test. --- gcc/config/s390/s390.cc | 263 +++++++++++++----- gcc/config/s390/s390.opt | 4 + .../gcc.target/s390/preserve-args-1.c | 17 ++ .../gcc.target/s390/preserve-args-2.c | 19 ++ 4 files changed, 229 insertions(+), 74 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-1.c create mode 100644 gcc/testsuite/gcc.target/s390/preserve-args-2.c diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index f5c75395cf3..5e197b5314b 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -411,6 +411,53 @@ struct s390_address #define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2) #define VEC_ARG_NUM_REG 8 +/* Return TRUE if GPR REGNO is supposed to be restored in the function + epilogue. */ +static inline bool +s390_restore_gpr_p (int regno) +{ + return (cfun_frame_layout.first_restore_gpr != -1 + && regno >= cfun_frame_layout.first_restore_gpr + && regno <= cfun_frame_layout.last_restore_gpr); +} + +/* Return TRUE if any of the registers in range [FIRST, LAST] is saved + because of -mpreserve-args. */ +static inline bool +s390_preserve_gpr_arg_in_range_p (int first, int last) +{ + int num_arg_regs = MIN (crtl->args.info.gprs + cfun->va_list_gpr_size, + GP_ARG_NUM_REG); + return (num_arg_regs + && s390_preserve_args_p + && first <= GPR2_REGNUM + num_arg_regs - 1 + && last >= GPR2_REGNUM); +} + +static inline bool +s390_preserve_gpr_arg_p (int regno) +{ + return s390_preserve_gpr_arg_in_range_p (regno, regno); +} + +/* Return TRUE if FPR arguments need to be saved onto the stack due to -mpreserve-args. */ +static inline bool +s390_preserve_fpr_args_p (void) +{ + return (s390_preserve_args_p + && (crtl->args.info.fprs + cfun->va_list_fpr_size)); +} + +static inline bool +s390_preserve_fpr_arg_p (int regno) +{ + int num_arg_regs = MIN (crtl->args.info.fprs + cfun->va_list_fpr_size, + FP_ARG_NUM_REG); + return (s390_preserve_args_p + && regno <= FPR0_REGNUM + num_arg_regs - 1 + && regno >= FPR0_REGNUM); +} + /* A couple of shortcuts. */ #define CONST_OK_FOR_J(x) \ CONST_OK_FOR_CONSTRAINT_P((x), 'J', "J") @@ -9893,61 +9940,90 @@ s390_register_info_gprtofpr () } /* Set the bits in fpr_bitmap for FPRs which need to be saved due to - stdarg. + stdarg or -mpreserve-args. This is a helper routine for s390_register_info. */ - static void -s390_register_info_stdarg_fpr () +s390_register_info_arg_fpr () { int i; - int min_fpr; - int max_fpr; + int min_stdarg_fpr = INT_MAX, max_stdarg_fpr = -1; + int min_preserve_fpr = INT_MAX, max_preserve_fpr = -1; + int min_fpr, max_fpr; /* Save the FP argument regs for stdarg. f0, f2 for 31 bit and f0-f4 for 64 bit. */ - if (!cfun->stdarg - || !TARGET_HARD_FLOAT - || !cfun->va_list_fpr_size - || crtl->args.info.fprs >= FP_ARG_NUM_REG) - return; + if (cfun->stdarg + && TARGET_HARD_FLOAT + && cfun->va_list_fpr_size + && crtl->args.info.fprs < FP_ARG_NUM_REG) + { + min_stdarg_fpr = crtl->args.info.fprs; + max_stdarg_fpr = min_stdarg_fpr + cfun->va_list_fpr_size - 1; + if (max_stdarg_fpr >= FP_ARG_NUM_REG) + max_stdarg_fpr = FP_ARG_NUM_REG - 1; + + /* FPR argument regs start at f0. */ + min_stdarg_fpr += FPR0_REGNUM; + max_stdarg_fpr += FPR0_REGNUM; + } + + if (s390_preserve_fpr_args_p ()) + { + min_preserve_fpr = FPR0_REGNUM; + max_preserve_fpr = min_preserve_fpr + crtl->args.info.fprs - 1; + } - min_fpr = crtl->args.info.fprs; - max_fpr = min_fpr + cfun->va_list_fpr_size - 1; - if (max_fpr >= FP_ARG_NUM_REG) - max_fpr = FP_ARG_NUM_REG - 1; + min_fpr = MIN (min_stdarg_fpr, min_preserve_fpr); + max_fpr = MAX (max_stdarg_fpr, max_preserve_fpr); - /* FPR argument regs start at f0. */ - min_fpr += FPR0_REGNUM; - max_fpr += FPR0_REGNUM; + if (max_fpr == -1) + return; for (i = min_fpr; i <= max_fpr; i++) cfun_set_fpr_save (i); } + /* Reserve the GPR save slots for GPRs which need to be saved due to - stdarg. + stdarg or -mpreserve-args. This is a helper routine for s390_register_info. */ static void -s390_register_info_stdarg_gpr () +s390_register_info_arg_gpr () { int i; - int min_gpr; - int max_gpr; + int min_stdarg_gpr = INT_MAX, max_stdarg_gpr = -1; + int min_preserve_gpr = INT_MAX, max_preserve_gpr = -1; + int min_gpr, max_gpr; - if (!cfun->stdarg - || !cfun->va_list_gpr_size - || crtl->args.info.gprs >= GP_ARG_NUM_REG) - return; + if (cfun->stdarg + && cfun->va_list_gpr_size + && crtl->args.info.gprs < GP_ARG_NUM_REG) + { + min_stdarg_gpr = crtl->args.info.gprs; + max_stdarg_gpr = min_stdarg_gpr + cfun->va_list_gpr_size - 1; + if (max_stdarg_gpr >= GP_ARG_NUM_REG) + max_stdarg_gpr = GP_ARG_NUM_REG - 1; - min_gpr = crtl->args.info.gprs; - max_gpr = min_gpr + cfun->va_list_gpr_size - 1; - if (max_gpr >= GP_ARG_NUM_REG) - max_gpr = GP_ARG_NUM_REG - 1; + /* GPR argument regs start at r2. */ + min_stdarg_gpr += GPR2_REGNUM; + max_stdarg_gpr += GPR2_REGNUM; + } - /* GPR argument regs start at r2. */ - min_gpr += GPR2_REGNUM; - max_gpr += GPR2_REGNUM; + if (s390_preserve_args_p && crtl->args.info.gprs) + { + min_preserve_gpr = GPR2_REGNUM; + if (crtl->args.info.gprs >= GP_ARG_NUM_REG) + max_preserve_gpr = min_preserve_gpr + GP_ARG_NUM_REG - 1; + else + max_preserve_gpr = min_preserve_gpr + crtl->args.info.gprs - 1; + } + + min_gpr = MIN (min_stdarg_gpr, min_preserve_gpr); + max_gpr = MAX (max_stdarg_gpr, max_preserve_gpr); + + if (max_gpr == -1) + return; /* If r6 was supposed to be saved into an FPR and now needs to go to the stack for vararg we have to adjust the restore range to make @@ -10079,14 +10155,14 @@ s390_register_info () if (clobbered_regs[i]) cfun_gpr_save_slot (i) = SAVE_SLOT_STACK; - s390_register_info_stdarg_fpr (); + s390_register_info_arg_fpr (); s390_register_info_gprtofpr (); s390_register_info_set_ranges (); - /* stdarg functions might need to save GPRs 2 to 6. This might - override the GPR->FPR save decision made by - s390_register_info_gprtofpr for r6 since vararg regs must go to - the stack. */ - s390_register_info_stdarg_gpr (); + + /* Forcing argument registers to be saved on the stack might + override the GPR->FPR save decision for r6 so this must come + last. */ + s390_register_info_arg_gpr (); } /* Return true if REGNO is a global register, but not one @@ -10143,7 +10219,7 @@ s390_optimize_register_info () cfun_gpr_save_slot (i) = SAVE_SLOT_NONE; s390_register_info_set_ranges (); - s390_register_info_stdarg_gpr (); + s390_register_info_arg_gpr (); } /* Fill cfun->machine with info about frame of current function. */ @@ -10866,14 +10942,28 @@ static rtx save_fpr (rtx base, int offset, int regnum) { rtx addr; + rtx insn; + addr = gen_rtx_MEM (DFmode, plus_constant (Pmode, base, offset)); - if (regnum >= 16 && regnum <= (16 + FP_ARG_NUM_REG)) + if (regnum >= FPR0_REGNUM && regnum <= (FPR0_REGNUM + FP_ARG_NUM_REG)) set_mem_alias_set (addr, get_varargs_alias_set ()); else set_mem_alias_set (addr, get_frame_alias_set ()); - return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum)); + insn = emit_move_insn (addr, gen_rtx_REG (DFmode, regnum)); + + if (!call_used_regs[regnum] || s390_preserve_fpr_arg_p (regnum)) + RTX_FRAME_RELATED_P (insn) = 1; + + if (s390_preserve_fpr_arg_p (regnum) && !cfun_fpr_save_p (regnum)) + { + rtx reg = gen_rtx_REG (DFmode, regnum); + add_reg_note (insn, REG_CFA_NORESTORE, reg); + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (addr, reg)); + } + + return insn; } /* Emit insn to restore fpr REGNUM from offset OFFSET relative @@ -10893,10 +10983,11 @@ restore_fpr (rtx base, int offset, int regnum) the register save area located at offset OFFSET relative to register BASE. */ -static rtx -save_gprs (rtx base, int offset, int first, int last) +static void +save_gprs (rtx base, int offset, int first, int last, rtx_insn *before = NULL) { rtx addr, insn, note; + rtx_insn *out_insn; int i; addr = plus_constant (Pmode, base, offset); @@ -10914,7 +11005,15 @@ save_gprs (rtx base, int offset, int first, int last) if (!global_not_special_regno_p (first)) RTX_FRAME_RELATED_P (insn) = 1; - return insn; + + if (s390_preserve_gpr_arg_p (first) && !s390_restore_gpr_p (first)) + { + rtx reg = gen_rtx_REG (Pmode, first); + add_reg_note (insn, REG_CFA_NORESTORE, reg); + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (addr, reg)); + } + + goto emit; } @@ -10943,7 +11042,12 @@ save_gprs (rtx base, int offset, int first, int last) set, even if it does not. Therefore we emit a new pattern without those registers as REG_FRAME_RELATED_EXPR note. */ - if (first >= 6 && !global_not_special_regno_p (first)) + /* In these cases all of the sets are marked as frame related: + 1. call-save GPR saved and restored + 2. argument GPR saved because of -mpreserve-args */ + if ((first >= 6 && !global_not_special_regno_p (first)) + || s390_preserve_gpr_arg_in_range_p (first, last)) + { rtx pat = PATTERN (insn); @@ -10954,6 +11058,24 @@ save_gprs (rtx base, int offset, int first, int last) RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1; RTX_FRAME_RELATED_P (insn) = 1; + + /* For the -mpreserve-args register saves no restore operations + will be emitted. CFI checking would complain about this. We + manually generate the REG_CFA notes here to be able to mark + those operations with REG_CFA_NORESTORE. */ + if (s390_preserve_gpr_arg_in_range_p (first, last)) + { + for (int regno = first; regno <= last; regno++) + { + rtx reg = gen_rtx_REG (Pmode, regno); + rtx reg_addr = plus_constant (Pmode, base, + offset + (regno - first) * UNITS_PER_LONG); + if (!s390_restore_gpr_p (regno)) + add_reg_note (insn, REG_CFA_NORESTORE, reg); + add_reg_note (insn, REG_CFA_OFFSET, + gen_rtx_SET (gen_frame_mem (Pmode, reg_addr), reg)); + } + } } else if (last >= 6) { @@ -10964,7 +11086,7 @@ save_gprs (rtx base, int offset, int first, int last) break; if (start > last) - return insn; + goto emit; addr = plus_constant (Pmode, base, offset + (start - first) * UNITS_PER_LONG); @@ -10982,7 +11104,7 @@ save_gprs (rtx base, int offset, int first, int last) add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); RTX_FRAME_RELATED_P (insn) = 1; - return insn; + goto emit; } note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), @@ -11001,9 +11123,15 @@ save_gprs (rtx base, int offset, int first, int last) RTX_FRAME_RELATED_P (insn) = 1; } - return insn; + emit: + if (before != NULL_RTX) + out_insn = emit_insn_before (insn, before); + else + out_insn = emit_insn (insn); + INSN_ADDRESSES_NEW (out_insn, -1); } + /* Generate insn to restore registers FIRST to LAST from the register save area located at offset OFFSET relative to register BASE. */ @@ -11427,12 +11555,12 @@ s390_emit_prologue (void) /* Save call saved gprs. */ if (cfun_frame_layout.first_save_gpr != -1) { - insn = save_gprs (stack_pointer_rtx, - cfun_frame_layout.gprs_offset + - UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr - - cfun_frame_layout.first_save_gpr_slot), - cfun_frame_layout.first_save_gpr, - cfun_frame_layout.last_save_gpr); + save_gprs (stack_pointer_rtx, + cfun_frame_layout.gprs_offset + + UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr + - cfun_frame_layout.first_save_gpr_slot), + cfun_frame_layout.first_save_gpr, + cfun_frame_layout.last_save_gpr); /* This is not 100% correct. If we have more than one register saved, then LAST_PROBE_OFFSET can move even closer to sp. */ @@ -11440,8 +11568,6 @@ s390_emit_prologue (void) = (cfun_frame_layout.gprs_offset + UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr - cfun_frame_layout.first_save_gpr_slot)); - - emit_insn (insn); } /* Dummy insn to mark literal pool slot. */ @@ -11471,15 +11597,10 @@ s390_emit_prologue (void) { if (cfun_fpr_save_p (i)) { - insn = save_fpr (stack_pointer_rtx, offset, i); + save_fpr (stack_pointer_rtx, offset, i); if (offset < last_probe_offset) last_probe_offset = offset; offset += 8; - - /* If f4 and f6 are call clobbered they are saved due to - stdargs and therefore are not frame related. */ - if (!call_used_regs[i]) - RTX_FRAME_RELATED_P (insn) = 1; } else if (!TARGET_PACKED_STACK || call_used_regs[i]) offset += 8; @@ -11495,11 +11616,10 @@ s390_emit_prologue (void) for (i = FPR15_REGNUM; i >= FPR8_REGNUM && offset >= 0; i--) if (cfun_fpr_save_p (i)) { - insn = save_fpr (stack_pointer_rtx, offset, i); + save_fpr (stack_pointer_rtx, offset, i); if (offset < last_probe_offset) last_probe_offset = offset; - RTX_FRAME_RELATED_P (insn) = 1; offset -= 8; } if (offset >= cfun_frame_layout.f8_offset) @@ -11667,7 +11787,6 @@ s390_emit_prologue (void) insn = save_fpr (temp_reg, offset, i); offset += 8; - RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_FRAME_RELATED_EXPR, gen_rtx_SET (gen_rtx_MEM (DFmode, addr), gen_rtx_REG (DFmode, i))); @@ -14161,15 +14280,11 @@ s390_optimize_prologue (void) continue; if (cfun_frame_layout.first_save_gpr != -1) - { - rtx s_pat = save_gprs (base, - off + (cfun_frame_layout.first_save_gpr - - first) * UNITS_PER_LONG, - cfun_frame_layout.first_save_gpr, - cfun_frame_layout.last_save_gpr); - new_insn = emit_insn_before (s_pat, insn); - INSN_ADDRESSES_NEW (new_insn, -1); - } + save_gprs (base, + off + (cfun_frame_layout.first_save_gpr + - first) * UNITS_PER_LONG, + cfun_frame_layout.first_save_gpr, + cfun_frame_layout.last_save_gpr, insn); remove_insn (insn); continue; diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt index c375b9c5f72..507c1f2d103 100644 --- a/gcc/config/s390/s390.opt +++ b/gcc/config/s390/s390.opt @@ -325,3 +325,7 @@ purposes. munroll-only-small-loops Target Undocumented Var(unroll_only_small_loops) Init(0) Save ; Use conservative small loop unrolling. + +mpreserve-args +Target Var(s390_preserve_args_p) Init(0) +Store all argument registers on the stack. diff --git a/gcc/testsuite/gcc.target/s390/preserve-args-1.c b/gcc/testsuite/gcc.target/s390/preserve-args-1.c new file mode 100644 index 00000000000..24dcf547432 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/preserve-args-1.c @@ -0,0 +1,17 @@ +/* Functional tests for the -mpreserve-args cmdline option. */ + +/* { dg-do compile } */ +/* { dg-options "-O3 -march=z900 -mpreserve-args" } */ + + +int +foo (int a, int b, int c, double d, double e) +{ + return a + c + (int)d + (int)e; +} + +/* { dg-final { scan-assembler "stmg\t%r2,%r4,\[0-9\]*\\(%r15\\)" { target lp64 } } } */ +/* { dg-final { scan-assembler "stm\t%r2,%r4,\[0-9\]*\\(%r15\\)" { target { ! lp64 } } } } */ + +/* { dg-final { scan-assembler "std\t%f0,\[0-9\]*\\(%r15\\)" } } */ +/* { dg-final { scan-assembler "std\t%f2,\[0-9\]*\\(%r15\\)" } } */ diff --git a/gcc/testsuite/gcc.target/s390/preserve-args-2.c b/gcc/testsuite/gcc.target/s390/preserve-args-2.c new file mode 100644 index 00000000000..006aad9c371 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/preserve-args-2.c @@ -0,0 +1,19 @@ +/* This test requires special handling of a GPR which is saved because + of -mpreserve-args but not restored. dwarf2cfi used to ICE for + this in maybe_record_trace_start. The solution was to introduce a + REG_CFA_NORESTORE reg note. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -march=z900 -mpreserve-args" } */ + +void *foo (void *); +void bar (); +int x; +void * +baz (void *y) +{ + if (__builtin_expect (x, 0)) + return foo (y); + bar (); + return foo (y); +}