From patchwork Tue Jul 26 16:21:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Sayle X-Patchwork-Id: 56341 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 470733857342 for ; Tue, 26 Jul 2022 16:22:09 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from server.nextmovesoftware.com (server.nextmovesoftware.com [162.254.253.69]) by sourceware.org (Postfix) with ESMTPS id 010063858D28 for ; Tue, 26 Jul 2022 16:21:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 010063858D28 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=nextmovesoftware.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nextmovesoftware.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nextmovesoftware.com; s=default; h=Content-Type:MIME-Version:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=loC4Yjo/JLocYWBR+bP/cmuN5QlzgUg6xWzevX+CgS0=; b=lzVi1smNrA285CZ7dDJjF8Ttpf b59NBSOY+/dIUqmvali4HKx1zdiODbjWZA0CrcXSuQJnlnVfHfTvIpeacaKf06AvZtljCC0YdtHM2 KPiRw7WL+uxE6Zt8F9QaCBWV5g4NsZrGZbSolDIcmZWEG0L7zjqubWemyD5pP2LJp/ziKHFBpo0fg Zfcnm2wgfbDp4A06I0sNCCwRJRiOSz3q4CL2QqOSZvPlggHWZpcKjCKMHIyF3l9Oh47QXVOzhSMOT k5C0oDUUjZnr1XQtiVG01QfFblELSUb7m8DVj9rDQ5wl/3IiU8sB3CzfAlKHQ7sk6k/5TKX5RbIcn 2n6zYSSg==; Received: from host81-156-58-95.range81-156.btcentralplus.com ([81.156.58.95]:52980 helo=Dell) by server.nextmovesoftware.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1oGNJf-0005Wi-2R; Tue, 26 Jul 2022 12:21:51 -0400 From: "Roger Sayle" To: Subject: [PATCH] middle-end: More support for ABIs that pass FP values as wider ints. Date: Tue, 26 Jul 2022 17:21:49 +0100 Message-ID: <00c101d8a10b$cfdc1990$6f944cb0$@nextmovesoftware.com> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 16.0 Thread-Index: AdihCmmiRriAEPh1TdOhQtf0YOvuig== Content-Language: en-gb X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.nextmovesoftware.com X-AntiAbuse: Original Domain - gcc.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - nextmovesoftware.com X-Get-Message-Sender-Via: server.nextmovesoftware.com: authenticated_id: roger@nextmovesoftware.com X-Authenticated-Sender: server.nextmovesoftware.com: roger@nextmovesoftware.com X-Source: X-Source-Args: X-Source-Dir: X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Firstly many thanks again to Jeff Law for reviewing/approving the previous patch to add support for ABIs that pass FP values as wider integer modes. That has allowed significant progress on PR target/104489. As predicted enabling HFmode on nvptx-none automatically enables more testcases in the testsuite and making sure these all PASS has revealed a few missed spots and a deficiency in the middle-end. For example, support for HC mode, where a complex value is encoded as two 16-bit HFmode parts was insufficiently covered in my previous testing. More interesting is that __fixunshfti is required by GCC, and not natively supported by the nvptx backend, requiring softfp support in libgcc, which in turn revealed an interesting asymmetry in libcall handling in optabs.cc. In the expand_fixed_convert function, which is responsible for expanding libcalls for integer to floating point conversion, GCC calls prepare_libcall_arg that (specifically for integer arguments) calls promote_function_mode on the argument, so that the libcall ABI matches the regular target ABI. By comparison, the equivalent expand_fix function, for floating point to integer conversion, doesn't promote its argument. On nvptx, where the assembler is strongly typed, this produces a mismatch as the __fixunshfti function created by libgcc doesn't precisely match the signature assumed by optabs. The solution is to perform the same (or similar) prepare_libcall_arg preparation in both cases. In this patch, the existing (static) prepare_libcall_arg, which assumes an integer argument, is renamed prepare_libcall_int_arg, and a matching prepare_libcall_fp_arg is introduced. This should be safe on other platforms (fingers-crossed) as floating point argument promotion is rare [floats are passed in float registers, doubles are passed in double registers, etc.] This patch has been tested on x86_64-pc-linux-gnu with make bootstrap and make -k check, both with and without --target_board=unix{-m32}, and on nvptx-none with a backend patch that resolves the rest of PR target/104489. Ok for mainline? 2022-07-26 Roger Sayle gcc/ChangeLog PR target/104489 * calls.cc (emit_library_call_value_1): Enable the FP return value of a libcall to be returned as a wider integer, by converting the int result to be converted to the desired floating point mode. (store_one_arg): Allow floating point arguments to be passed on the stack as wider integers using convert_float_to_wider_int. * function.cc (assign_parms_unsplit_complex): Likewise, allow complex floating point modes to be passed as wider integer parts, using convert_wider_int_to_float. * optabs.cc (prepare_libcall_fp_arg): New function. A floating point version of the previous prepare_libcall_arg that calls promote_function_mode on its argument. (expand_fix): Call new prepare_libcall_fp_arg on FIX argument. (prepare_libcall_int_arg): Renamed from prepare_libcall_arg. (expand_fixed_convert): Update call of prepare_libcall_arg to the new name, prepare_libcall_int_arg. Thanks again, Roger diff --git a/gcc/calls.cc b/gcc/calls.cc index 7f3cf5f..50d0495 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -4791,14 +4791,20 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, else { /* Convert to the proper mode if a promotion has been active. */ - if (GET_MODE (valreg) != outmode) + enum machine_mode valmode = GET_MODE (valreg); + if (valmode != outmode) { int unsignedp = TYPE_UNSIGNED (tfom); gcc_assert (promote_function_mode (tfom, outmode, &unsignedp, fndecl ? TREE_TYPE (fndecl) : fntype, 1) - == GET_MODE (valreg)); - valreg = convert_modes (outmode, GET_MODE (valreg), valreg, 0); + == valmode); + if (SCALAR_INT_MODE_P (valmode) + && SCALAR_FLOAT_MODE_P (outmode) + && known_gt (GET_MODE_SIZE (valmode), GET_MODE_SIZE (outmode))) + valreg = convert_wider_int_to_float (outmode, valmode, valreg); + else + valreg = convert_modes (outmode, valmode, valreg, 0); } if (value != 0) @@ -5003,8 +5009,20 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* If we are promoting object (or for any other reason) the mode doesn't agree, convert the mode. */ - if (arg->mode != TYPE_MODE (TREE_TYPE (pval))) - arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)), + machine_mode old_mode = TYPE_MODE (TREE_TYPE (pval)); + + /* Some ABIs require scalar floating point modes to be passed + in a wider scalar integer mode. We need to explicitly + reinterpret to an integer mode of the correct precision + before extending to the desired result. */ + if (SCALAR_INT_MODE_P (arg->mode) + && SCALAR_FLOAT_MODE_P (old_mode) + && known_gt (GET_MODE_SIZE (arg->mode), + GET_MODE_SIZE (old_mode))) + arg->value = convert_float_to_wider_int (arg->mode, old_mode, + arg->value); + else if (arg->mode != old_mode) + arg->value = convert_modes (arg->mode, old_mode, arg->value, arg->unsignedp); if (arg->pass_on_stack) diff --git a/gcc/function.cc b/gcc/function.cc index 31256b5..4deb6b0 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -3584,7 +3584,16 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all, real = DECL_RTL (fnargs[i]); imag = DECL_RTL (fnargs[i + 1]); - if (inner != GET_MODE (real)) + machine_mode orig_mode = GET_MODE (real); + if (SCALAR_FLOAT_MODE_P (inner) + && SCALAR_INT_MODE_P (orig_mode) + && known_lt (GET_MODE_SIZE (inner), + GET_MODE_SIZE (orig_mode))) + { + real = convert_wider_int_to_float (inner, orig_mode, real); + imag = convert_wider_int_to_float (inner, orig_mode, imag); + } + else if (inner != orig_mode) { real = gen_lowpart_SUBREG (inner, real); imag = gen_lowpart_SUBREG (inner, imag); @@ -3618,7 +3627,23 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all, real = DECL_INCOMING_RTL (fnargs[i]); imag = DECL_INCOMING_RTL (fnargs[i + 1]); - if (inner != GET_MODE (real)) + orig_mode = GET_MODE (real); + if (SCALAR_FLOAT_MODE_P (inner) + && SCALAR_INT_MODE_P (orig_mode) + && known_lt (GET_MODE_SIZE (inner), + GET_MODE_SIZE (orig_mode))) + { + push_to_sequence2 (all->first_conversion_insn, + all->last_conversion_insn); + real = force_reg (orig_mode, real); + imag = force_reg (orig_mode, imag); + real = convert_wider_int_to_float (inner, orig_mode, real); + imag = convert_wider_int_to_float (inner, orig_mode, imag); + all->first_conversion_insn = get_insns (); + all->last_conversion_insn = get_last_insn (); + end_sequence (); + } + else if (inner != orig_mode) { real = gen_lowpart_SUBREG (inner, real); imag = gen_lowpart_SUBREG (inner, imag); diff --git a/gcc/optabs.cc b/gcc/optabs.cc index a50dd79..10ccfbc 100644 --- a/gcc/optabs.cc +++ b/gcc/optabs.cc @@ -5539,6 +5539,37 @@ expand_float (rtx to, rtx from, int unsignedp) } } +/* Promote floating point arguments for a libcall if necessary. + There are no tree types defined for libcalls. */ + +static rtx +prepare_libcall_fp_arg (rtx arg) +{ + scalar_float_mode mode; + machine_mode arg_mode; + if (is_a (GET_MODE (arg), &mode)) + { + /* If we need to promote the floating point function argument, do + it here instead of inside emit_library_call_value matching the + use of prepare_libcall_int_arg. */ + + int unsigned_p = 0; + arg_mode = targetm.calls.promote_function_mode (NULL_TREE, mode, + &unsigned_p, + NULL_TREE, 0); + /* Some ABIs require scalar floating point modes to be passed + in a wider scalar integer mode. We need to explicitly + reinterpret to an integer mode of the correct precision + before extending to the desired result. */ + if (SCALAR_INT_MODE_P (arg_mode) + && known_gt (GET_MODE_SIZE (arg_mode), GET_MODE_SIZE (mode))) + return convert_float_to_wider_int (arg_mode, mode, arg); + if (arg_mode != mode) + return convert_to_mode (arg_mode, arg, unsigned_p); + } + return arg; +} + /* Generate code to convert FROM to fixed point and store in TO. FROM must be floating point. */ @@ -5701,15 +5732,19 @@ expand_fix (rtx to, rtx from, int unsignedp) rtx_insn *insns; rtx value; rtx libfunc; + rtx promoted_from; convert_optab tab = unsignedp ? ufix_optab : sfix_optab; libfunc = convert_optab_libfunc (tab, GET_MODE (to), GET_MODE (from)); gcc_assert (libfunc); + promoted_from = prepare_libcall_fp_arg (from); + start_sequence (); value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, - GET_MODE (to), from, GET_MODE (from)); + GET_MODE (to), promoted_from, + GET_MODE (promoted_from)); insns = get_insns (); end_sequence (); @@ -5734,7 +5769,7 @@ expand_fix (rtx to, rtx from, int unsignedp) there are no tree types defined for libcalls. */ static rtx -prepare_libcall_arg (rtx arg, int uintp) +prepare_libcall_int_arg (rtx arg, int uintp) { scalar_int_mode mode; machine_mode arg_mode; @@ -5796,7 +5831,7 @@ expand_fixed_convert (rtx to, rtx from, int uintp, int satp) libfunc = convert_optab_libfunc (tab, to_mode, from_mode); gcc_assert (libfunc); - from = prepare_libcall_arg (from, uintp); + from = prepare_libcall_int_arg (from, uintp); from_mode = GET_MODE (from); start_sequence ();