From patchwork Fri Jun 3 13:33:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Meissner X-Patchwork-Id: 629833 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rLlRt5lWLz9t6k for ; Fri, 3 Jun 2016 23:34:01 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=ROVdpolF; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=xgEAxZ/0EOwiPftYCyjAEgcg0Sli/h4sQgL74ggVZWJ93CkTgVFWz F8554W0wgBT7rUaIYtftafSVcKdBZte8gt09eJ/W+znhkHVMlaNkjjzjnvJLSn/Z tyMpDrgu6NjQ5mIOYmpYJXaLNqiw9nV30sjV+b0EUagDzC6T/5/Mtk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=rV5zZoMXd6GNRV75cOUS2tmgkMw=; b=ROVdpolFqvUQIU20fDyy fR+OthBEp6Z1zQTIJV7iWBfvldP8Y+3tEc6LGot8hOaYEdIyk/X16ww0gCeKP3kv F/0ANlMBIFJCq/lM6csIPOfpaYe5v3CtH1JBOtjfci+v0z0Mg+HTgd6UpDAkzxiH BA4bkSw14wc8ffeZ8VCzZGE= Received: (qmail 47528 invoked by alias); 3 Jun 2016 13:33:54 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 47514 invoked by uid 89); 3 Jun 2016 13:33:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.5 required=5.0 tests=AWL, BAYES_20, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 spammy=978, 2506r, 8994797, 2506R X-HELO: e31.co.us.ibm.com Received: from e31.co.us.ibm.com (HELO e31.co.us.ibm.com) (32.97.110.149) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Fri, 03 Jun 2016 13:33:49 +0000 Received: from localhost by e31.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 3 Jun 2016 07:33:47 -0600 Received: from d03dlp03.boulder.ibm.com (9.17.202.179) by e31.co.us.ibm.com (192.168.1.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 3 Jun 2016 07:33:45 -0600 X-IBM-Helo: d03dlp03.boulder.ibm.com X-IBM-MailFrom: meissner@ibm-tiger.the-meissners.org X-IBM-RcptTo: gcc-patches@gcc.gnu.org; dje.gcc@gmail.com; segher@kernel.crashing.org Received: from b03cxnp07028.gho.boulder.ibm.com (b03cxnp07028.gho.boulder.ibm.com [9.17.130.15]) by d03dlp03.boulder.ibm.com (Postfix) with ESMTP id D65AE19D8042; Fri, 3 Jun 2016 07:33:25 -0600 (MDT) Received: from b03ledav005.gho.boulder.ibm.com (b03ledav005.gho.boulder.ibm.com [9.17.130.236]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u53DXjB345613072; Fri, 3 Jun 2016 06:33:45 -0700 Received: from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0F55EBE039; Fri, 3 Jun 2016 07:33:45 -0600 (MDT) Received: from ibm-tiger.the-meissners.org (unknown [9.32.77.111]) by b03ledav005.gho.boulder.ibm.com (Postfix) with ESMTP id CF20ABE038; Fri, 3 Jun 2016 07:33:44 -0600 (MDT) Received: by ibm-tiger.the-meissners.org (Postfix, from userid 500) id 1102B4426C; Fri, 3 Jun 2016 09:33:35 -0400 (EDT) Date: Fri, 3 Jun 2016 09:33:35 -0400 From: Michael Meissner To: gcc-patches@gcc.gnu.org, Segher Boessenkool , Bill Schmidt , David Edelsohn Subject: [PATCH] Backport PowerPC complex __float128 compiler support to GCC 6.x Message-ID: <20160603133335.GA28522@ibm-tiger.the-meissners.org> Mail-Followup-To: Michael Meissner , gcc-patches@gcc.gnu.org, Segher Boessenkool , Bill Schmidt , David Edelsohn MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16060313-8236-0000-0000-000031DF3F0C X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused X-IsSubscribed: yes These patches were installed on the trunk on May 2nd, with a fix from Alan Modra on May 11th. Unless I here objections in the next few days, I will commit these changes to the GCC 6.x branch. These changes will allow people to use complex __float128 types (via an attribute) on the PowerPC. Note, we will need patches to libgcc to fully enable complex __float128 support on the PowerPC. These patches enable the compiler support, so that the libgcc changes can be coded. In addition to bootstrapping and regtesting on the PowerPC (little endian power8), I also bootstrapped and regested the changes on x86_64 running RHEL 6.2. There were no regressions in either case. [gcc] 2016-06-02 Michael Meissner Back port from trunk 2016-05-11 Alan Modra * config/rs6000/rs6000.c (is_complex_IBM_long_double, abi_v4_pass_in_fpr): New functions. (rs6000_function_arg_boundary): Exclude complex IBM long double from 64-bit alignment when ABI_V4. (rs6000_function_arg, rs6000_function_arg_advance_1, rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr. Back port from trunk 2016-05-02 Michael Meissner * machmode.h (mode_complex): Add support to give the complex mode for a given mode. (GET_MODE_COMPLEX_MODE): Likewise. * stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode stored by build_complex_type and gfc_build_complex_type instead of trying to figure out the appropriate mode based on the size. Raise an assertion error, if the type was not set. * genmodes.c (struct mode_data): Add field for the complex type of the given type. (blank_mode): Likewise. (make_complex_modes): Remember the complex mode created in the base type. (emit_mode_complex): Write out the mode_complex array to map a type mode to the complex version. (emit_insn_modes_c): Likewise. * tree.c (build_complex_type): Set the complex type to use before calling layout_type. * config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add support for __float128 complex datatypes. (rs6000_hard_regno_mode_ok): Likewise. (rs6000_setup_reg_addr_masks): Likewise. (rs6000_complex_function_value): Likewise. * config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise. __float128 and __ibm128 complex. (FLOAT128_IBM_P): Likewise. (ALTIVEC_ARG_MAX_RETURN): Likewise. * doc/extend.texi (Additional Floating Types): Document that -mfloat128 must be used to enable __float128. Document complex __float128 and __ibm128 support. [gcc/fortran] 2016-06-02 Michael Meissner Back port from trunk 2016-05-02 Michael Meissner * trans-types.c (gfc_build_complex_type): [gcc/testsuite] 2016-06-02 Michael Meissner Back port from trunk 2016-05-02 Michael Meissner * gcc.target/powerpc/float128-complex-1.c: New tests for complex __float128. * gcc.target/powerpc/float128-complex-2.c: Likewise. Index: gcc/machmode.h =================================================================== --- gcc/machmode.h (revision 237045) +++ gcc/machmode.h (working copy) @@ -269,6 +269,10 @@ extern const unsigned char mode_wider[NU extern const unsigned char mode_2xwider[NUM_MACHINE_MODES]; #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE]) +/* Get the complex mode from the component mode. */ +extern const unsigned char mode_complex[NUM_MACHINE_MODES]; +#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE]) + /* Return the mode for data of a given size SIZE and mode class CLASS. If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE. The value is BLKmode if no other mode is found. */ Index: gcc/stor-layout.c =================================================================== --- gcc/stor-layout.c (revision 237045) +++ gcc/stor-layout.c (working copy) @@ -2146,11 +2146,13 @@ layout_type (tree type) case COMPLEX_TYPE: TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type)); - SET_TYPE_MODE (type, - mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)), - (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE - ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT), - 0)); + + /* build_complex_type and fortran's gfc_build_complex_type have set the + expected mode to allow having multiple complex types for multiple + floating point types that have the same size such as the PowerPC with + __ibm128 and __float128. */ + gcc_assert (TYPE_MODE (type) != VOIDmode); + TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type))); TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type))); break; Index: gcc/genmodes.c =================================================================== --- gcc/genmodes.c (revision 237045) +++ gcc/genmodes.c (working copy) @@ -66,6 +66,7 @@ struct mode_data this mode as a component. */ struct mode_data *next_cont; /* Next mode in that list. */ + struct mode_data *complex; /* complex type with mode as component. */ const char *file; /* file and line of definition, */ unsigned int line; /* for error reporting */ unsigned int counter; /* Rank ordering of modes */ @@ -83,7 +84,7 @@ static struct mode_data *void_mode; static const struct mode_data blank_mode = { 0, "", MAX_MODE_CLASS, -1U, -1U, -1U, -1U, - 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, "", 0, 0, 0, 0, false, 0 }; @@ -472,6 +473,7 @@ make_complex_modes (enum mode_class cl, c = new_mode (cclass, buf, file, line); c->component = m; + m->complex = c; } } @@ -1381,6 +1383,22 @@ emit_mode_wider (void) } static void +emit_mode_complex (void) +{ + int c; + struct mode_data *m; + + print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES"); + + for_all_modes (c, m) + tagged_printf ("%smode", + m->complex ? m->complex->name : void_mode->name, + m->name); + + print_closer (); +} + +static void emit_mode_mask (void) { int c; @@ -1745,6 +1763,7 @@ emit_insn_modes_c (void) emit_mode_size (); emit_mode_nunits (); emit_mode_wider (); + emit_mode_complex (); emit_mode_mask (); emit_mode_inner (); emit_mode_unit_size (); Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 237045) +++ gcc/tree.c (working copy) @@ -8675,6 +8675,7 @@ build_complex_type (tree component_type) t = make_node (COMPLEX_TYPE); TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type); + SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type))); /* If we already have such a type, use the old one. */ hstate.add_object (TYPE_HASH (component_type)); Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 237045) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -1882,7 +1882,7 @@ rs6000_hard_regno_nregs_internal (int re 128-bit floating point that can go in vector registers, which has VSX memory addressing. */ if (FP_REGNO_P (regno)) - reg_size = (VECTOR_MEM_VSX_P (mode) + reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode) ? UNITS_PER_VSX_WORD : UNITS_PER_FP_WORD); @@ -1914,6 +1914,9 @@ rs6000_hard_regno_mode_ok (int regno, ma { int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1; + if (COMPLEX_MODE_P (mode)) + mode = GET_MODE_INNER (mode); + /* PTImode can only go in GPRs. Quad word memory operations require even/odd register combinations, and use PTImode where we need to deal with quad word memory operations. Don't allow quad words in the argument or frame @@ -2716,8 +2719,17 @@ rs6000_setup_reg_addr_masks (void) for (m = 0; m < NUM_MACHINE_MODES; ++m) { - machine_mode m2 = (machine_mode)m; - unsigned short msize = GET_MODE_SIZE (m2); + machine_mode m2 = (machine_mode) m; + bool complex_p = false; + size_t msize; + + if (COMPLEX_MODE_P (m2)) + { + complex_p = true; + m2 = GET_MODE_INNER (m2); + } + + msize = GET_MODE_SIZE (m2); /* SDmode is special in that we want to access it only via REG+REG addressing on power7 and above, since we want to use the LFIWZX and @@ -2739,7 +2751,7 @@ rs6000_setup_reg_addr_masks (void) /* Indicate if the mode takes more than 1 physical register. If it takes a single register, indicate it can do REG+REG addressing. */ - if (nregs > 1 || m == BLKmode) + if (nregs > 1 || m == BLKmode || complex_p) addr_mask |= RELOAD_REG_MULTIPLE; else addr_mask |= RELOAD_REG_INDEXED; @@ -2755,7 +2767,7 @@ rs6000_setup_reg_addr_masks (void) && msize <= 8 && !VECTOR_MODE_P (m2) && !FLOAT128_VECTOR_P (m2) - && !COMPLEX_MODE_P (m2) + && !complex_p && (m2 != DFmode || !TARGET_UPPER_REGS_DF) && (m2 != SFmode || !TARGET_UPPER_REGS_SF) && !(TARGET_E500_DOUBLE && msize == 8)) @@ -10266,6 +10278,35 @@ rs6000_must_pass_in_stack (machine_mode return must_pass_in_stack_var_size_or_pad (mode, type); } +static inline bool +is_complex_IBM_long_double (machine_mode mode) +{ + return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode); +} + +/* Whether ABI_V4 passes MODE args to a function in floating point + registers. */ + +static bool +abi_v4_pass_in_fpr (machine_mode mode) +{ + if (!TARGET_FPRS || !TARGET_HARD_FLOAT) + return false; + if (TARGET_SINGLE_FLOAT && mode == SFmode) + return true; + if (TARGET_DOUBLE_FLOAT && mode == DFmode) + return true; + /* ABI_V4 passes complex IBM long double in 8 gprs. + Stupid, but we can't change the ABI now. */ + if (is_complex_IBM_long_double (mode)) + return false; + if (FLOAT128_2REG_P (mode)) + return true; + if (DECIMAL_FLOAT_MODE_P (mode)) + return true; + return false; +} + /* If defined, a C expression which determines whether, and in which direction, to pad out an argument with extra space. The value should be of type `enum direction': either `upward' to pad above @@ -10350,6 +10391,7 @@ rs6000_function_arg_boundary (machine_mo && (GET_MODE_SIZE (mode) == 8 || (TARGET_HARD_FLOAT && TARGET_FPRS + && !is_complex_IBM_long_double (mode) && FLOAT128_2REG_P (mode)))) return 64; else if (FLOAT128_VECTOR_P (mode)) @@ -10729,11 +10771,7 @@ rs6000_function_arg_advance_1 (CUMULATIV } else if (DEFAULT_ABI == ABI_V4) { - if (TARGET_HARD_FLOAT && TARGET_FPRS - && ((TARGET_SINGLE_FLOAT && mode == SFmode) - || (TARGET_DOUBLE_FLOAT && mode == DFmode) - || FLOAT128_2REG_P (mode) - || DECIMAL_FLOAT_MODE_P (mode))) + if (abi_v4_pass_in_fpr (mode)) { /* _Decimal128 must use an even/odd register pair. This assumes that the register number is odd when fregno is odd. */ @@ -11390,11 +11428,7 @@ rs6000_function_arg (cumulative_args_t c else if (abi == ABI_V4) { - if (TARGET_HARD_FLOAT && TARGET_FPRS - && ((TARGET_SINGLE_FLOAT && mode == SFmode) - || (TARGET_DOUBLE_FLOAT && mode == DFmode) - || FLOAT128_2REG_P (mode) - || DECIMAL_FLOAT_MODE_P (mode))) + if (abi_v4_pass_in_fpr (mode)) { /* _Decimal128 must use an even/odd register pair. This assumes that the register number is odd when fregno is odd. */ @@ -12315,19 +12349,15 @@ rs6000_gimplify_va_arg (tree valist, tre rsize = (size + 3) / 4; align = 1; - if (TARGET_HARD_FLOAT && TARGET_FPRS - && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode) - || (TARGET_DOUBLE_FLOAT - && (TYPE_MODE (type) == DFmode - || FLOAT128_2REG_P (TYPE_MODE (type)) - || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))))) + machine_mode mode = TYPE_MODE (type); + if (abi_v4_pass_in_fpr (mode)) { /* FP args go in FP registers, if present. */ reg = fpr; n_reg = (size + 7) / 8; sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4; sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4); - if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode) + if (mode != SFmode && mode != SDmode) align = 8; } else @@ -12347,7 +12377,7 @@ rs6000_gimplify_va_arg (tree valist, tre addr = create_tmp_var (ptr_type_node, "addr"); /* AltiVec vectors never go in registers when -mabi=altivec. */ - if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))) + if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode)) align = 16; else { @@ -12368,7 +12398,7 @@ rs6000_gimplify_va_arg (tree valist, tre } /* _Decimal128 is passed in even/odd fpr pairs; the stored reg number is 0 for f1, so we want to make it odd. */ - else if (reg == fpr && TYPE_MODE (type) == TDmode) + else if (reg == fpr && mode == TDmode) { t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg), build_int_cst (TREE_TYPE (reg), 1)); @@ -12395,7 +12425,7 @@ rs6000_gimplify_va_arg (tree valist, tre FP register for 32-bit binaries. */ if (TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FPRS - && TYPE_MODE (type) == SDmode) + && mode == SDmode) t = fold_build_pointer_plus_hwi (t, size); gimplify_assign (addr, t, pre_p); @@ -18464,25 +18494,33 @@ rs6000_secondary_reload_memory (rtx addr addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & ~RELOAD_REG_AND_M16); - else + /* If the register allocator hasn't made up its mind yet on the register + class to use, settle on defaults to use. */ + else if (rclass == NO_REGS) { - if (TARGET_DEBUG_ADDR) - fprintf (stderr, - "rs6000_secondary_reload_memory: mode = %s, class = %s, " - "class is not GPR, FPR, VMX\n", - GET_MODE_NAME (mode), reg_class_names[rclass]); + addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY] + & ~RELOAD_REG_AND_M16); - return -1; + if ((addr_mask & RELOAD_REG_MULTIPLE) != 0) + addr_mask &= ~(RELOAD_REG_INDEXED + | RELOAD_REG_PRE_INCDEC + | RELOAD_REG_PRE_MODIFY); } + else + addr_mask = 0; + /* If the register isn't valid in this register class, just return now. */ if ((addr_mask & RELOAD_REG_VALID) == 0) { if (TARGET_DEBUG_ADDR) - fprintf (stderr, - "rs6000_secondary_reload_memory: mode = %s, class = %s, " - "not valid in class\n", - GET_MODE_NAME (mode), reg_class_names[rclass]); + { + fprintf (stderr, + "rs6000_secondary_reload_memory: mode = %s, class = %s, " + "not valid in class\n", + GET_MODE_NAME (mode), reg_class_names[rclass]); + debug_rtx (addr); + } return -1; } @@ -19143,6 +19181,9 @@ rs6000_secondary_reload (bool in_p, fprintf (stderr, ", reload func = %s, extra cost = %d", insn_data[sri->icode].name, sri->extra_cost); + else if (sri->extra_cost > 0) + fprintf (stderr, ", extra cost = %d", sri->extra_cost); + fputs ("\n", stderr); debug_rtx (x); } @@ -19553,6 +19594,16 @@ rs6000_preferred_reload_class (rtx x, en machine_mode mode = GET_MODE (x); bool is_constant = CONSTANT_P (x); + /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred + reload class for it. */ + if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS) + && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0) + return NO_REGS; + + if ((rclass == FLOAT_REGS || rclass == VSX_REGS) + && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0) + return NO_REGS; + /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS. Do not allow the reloading of address expressions using PLUS into floating point registers. */ @@ -19603,6 +19654,25 @@ rs6000_preferred_reload_class (rtx x, en return NO_REGS; } + /* If we haven't picked a register class, and the type is a vector or + floating point type, prefer to use the VSX, FPR, or Altivec register + classes. */ + if (rclass == NO_REGS) + { + if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode)) + return VSX_REGS; + + if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode)) + return ALTIVEC_REGS; + + if (DECIMAL_FLOAT_MODE_P (mode)) + return TARGET_DFP ? FLOAT_REGS : NO_REGS; + + if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode) + && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0) + return FLOAT_REGS; + } + if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS) return GENERAL_REGS; @@ -34549,8 +34619,14 @@ rs6000_complex_function_value (machine_m machine_mode inner = GET_MODE_INNER (mode); unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode); - if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) + if (TARGET_FLOAT128 + && (mode == KCmode + || (mode == TCmode && TARGET_IEEEQUAD))) + regno = ALTIVEC_ARG_RETURN; + + else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) regno = FP_ARG_RETURN; + else { regno = GP_ARG_RETURN; Index: gcc/config/rs6000/rs6000.h =================================================================== --- gcc/config/rs6000/rs6000.h (revision 237045) +++ gcc/config/rs6000/rs6000.h (working copy) @@ -418,12 +418,12 @@ extern const char *host_detect_local_cpu Similarly IFmode is the IBM long double format even if the default is IEEE 128-bit. */ #define FLOAT128_IEEE_P(MODE) \ - (((MODE) == TFmode && TARGET_IEEEQUAD) \ - || ((MODE) == KFmode)) + ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \ + || ((MODE) == KFmode) || ((MODE) == KCmode)) #define FLOAT128_IBM_P(MODE) \ - (((MODE) == TFmode && !TARGET_IEEEQUAD) \ - || ((MODE) == IFmode)) + ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \ + || ((MODE) == IFmode) || ((MODE) == ICmode)) /* Helper macros to say whether a 128-bit floating point type can go in a single vector register, or whether it needs paired scalar values. */ @@ -1789,7 +1789,9 @@ extern enum reg_class rs6000_constraints #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2) #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN \ : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1)) -#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \ +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 \ + ? (ALTIVEC_ARG_RETURN \ + + (TARGET_FLOAT128 ? 1 : 0)) \ : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1)) /* Flags for the call/call_value rtl operations set up by function_arg */ Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 237045) +++ gcc/doc/extend.texi (working copy) @@ -962,8 +962,13 @@ complex @code{__float128} type. When th would use the following syntax to declare @code{_Complex128} to be a complex @code{__float128} type: +On the PowerPC Linux VSX targets, you can declare complex types using +the corresponding internal complex type, @code{KCmode} for +@code{__float128} type and @code{ICmode} for @code{__ibm128} type: + @smallexample -typedef _Complex float __attribute__((mode(KC))) _Complex128; +typedef _Complex float __attribute__((mode(KC))) _Complex_float128; +typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128; @end smallexample Not all targets support additional floating-point types. Index: gcc/fortran/trans-types.c =================================================================== --- gcc/fortran/trans-types.c (revision 237045) +++ gcc/fortran/trans-types.c (working copy) @@ -828,6 +828,7 @@ gfc_build_complex_type (tree scalar_type new_type = make_node (COMPLEX_TYPE); TREE_TYPE (new_type) = scalar_type; + SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type))); layout_type (new_type); return new_type; } Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c (revision 0) @@ -0,0 +1,157 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-require-effective-target powerpc_float128_sw_ok } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */ +/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */ + +#ifndef NO_FLOAT +typedef _Complex float float_complex; +extern float_complex cfloat1 (void); +extern float_complex cfloat2 (void); + +#define FLOAT_ARG(NAME, OP) ARG_OP(float, float_complex, NAME, OP) +#define FLOAT_PTR(NAME, OP) PTR_OP(float, float_complex, NAME, OP) +#define FLOAT_CALL() CALL_OP(float, float_complex, cfloat1, cfloat2) + +#else +#define FLOAT_ARG(NAME, OP) +#define FLOAT_PTR(NAME, OP) +#define FLOAT_CALL() +#endif + +#ifndef NO_DOUBLE +typedef _Complex double double_complex; +extern double_complex cdouble1 (void); +extern double_complex cdouble2 (void); + +#define DOUBLE_ARG(NAME, OP) ARG_OP(double, double_complex, NAME, OP) +#define DOUBLE_PTR(NAME, OP) PTR_OP(double, double_complex, NAME, OP) +#define DOUBLE_CALL() CALL_OP(double, double_complex, cdouble1, cdouble2) + +#else +#define DOUBLE_ARG(NAME, OP) +#define DOUBLE_PTR(NAME, OP) +#define DOUBLE_CALL() +#endif + +#ifndef NO_FLOAT128 +#ifdef __VSX__ +typedef _Complex float __attribute__((mode(KC))) float128_complex; +#else +typedef _Complex float __attribute__((mode(TC))) float128_complex; +#endif + +extern float128_complex cfloat128_1 (void); +extern float128_complex cfloat128_2 (void); + +#define FLOAT128_ARG(NAME, OP) ARG_OP(float128, float128_complex, NAME, OP) +#define FLOAT128_PTR(NAME, OP) PTR_OP(float128, float128_complex, NAME, OP) +#define FLOAT128_CALL() CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2) + +#else +#define FLOAT128_ARG(NAME, OP) +#define FLOAT128_PTR(NAME, OP) +#define FLOAT128_CALL() +#endif + +#ifndef NO_LDOUBLE +typedef _Complex long double ldouble_complex; +extern ldouble_complex cldouble1 (void); +extern ldouble_complex cldouble2 (void); + +#define LDOUBLE_ARG(NAME, OP) ARG_OP(ldouble, ldouble_complex, NAME, OP) +#define LDOUBLE_PTR(NAME, OP) PTR_OP(ldouble, ldouble_complex, NAME, OP) +#define LDOUBLE_CALL() CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2) + +#else +#define LDOUBLE_ARG(NAME, OP) +#define LDOUBLE_PTR(NAME, OP) +#define LDOUBLE_CALL() +#endif + + +#define ARG_OP(SUFFIX, TYPE, NAME, OP) \ +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b) \ +{ \ + return a OP b; \ +} + +#define PTR_OP(SUFFIX, TYPE, NAME, OP) \ +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b) \ +{ \ + *p = *a OP *b; \ +} + +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2) \ +TYPE call_ ## SUFFIX (void) \ +{ \ + TYPE value1 = FUNC1 (); \ + TYPE value2 = FUNC2 (); \ + return value1 + value2; \ +} + +#ifndef NO_ARG +#ifndef NO_ADD +FLOAT_ARG (add, +) +DOUBLE_ARG (add, +) +FLOAT128_ARG (add, +) +LDOUBLE_ARG (add, +) +#endif + +#ifndef NO_SUB +FLOAT_ARG (sub, -) +DOUBLE_ARG (sub, -) +FLOAT128_ARG (sub, -) +LDOUBLE_ARG (sub, -) +#endif + +#ifndef NO_MUL +FLOAT_ARG (mul, *) +DOUBLE_ARG (mul, *) +FLOAT128_ARG (mul, *) +LDOUBLE_ARG (mul, *) +#endif + +#ifndef NO_DIV +FLOAT_ARG (div, /) +DOUBLE_ARG (div, /) +FLOAT128_ARG (div, /) +LDOUBLE_ARG (div, /) +#endif +#endif + +#ifndef NO_PTR +#ifndef NO_ADD +FLOAT_PTR (add, +) +DOUBLE_PTR (add, +) +FLOAT128_PTR (add, +) +LDOUBLE_PTR (add, +) +#endif + +#ifndef NO_SUB +FLOAT_PTR (sub, -) +DOUBLE_PTR (sub, -) +FLOAT128_PTR (sub, -) +LDOUBLE_PTR (sub, -) +#endif + +#ifndef NO_MUL +FLOAT_PTR (mul, *) +DOUBLE_PTR (mul, *) +FLOAT128_PTR (mul, *) +LDOUBLE_PTR (mul, *) +#endif + +#ifndef NO_DIV +FLOAT_PTR (div, /) +DOUBLE_PTR (div, /) +FLOAT128_PTR (div, /) +LDOUBLE_PTR (div, /) +#endif +#endif + +#ifndef NO_CALL +FLOAT_CALL () +DOUBLE_CALL () +FLOAT128_CALL () +LDOUBLE_CALL () +#endif Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c (revision 0) @@ -0,0 +1,160 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-require-effective-target powerpc_float128_hw_ok } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */ +/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */ + +#ifndef NO_FLOAT +typedef _Complex float float_complex; +extern float_complex cfloat1 (void); +extern float_complex cfloat2 (void); + +#define FLOAT_ARG(NAME, OP) ARG_OP(float, float_complex, NAME, OP) +#define FLOAT_PTR(NAME, OP) PTR_OP(float, float_complex, NAME, OP) +#define FLOAT_CALL() CALL_OP(float, float_complex, cfloat1, cfloat2) + +#else +#define FLOAT_ARG(NAME, OP) +#define FLOAT_PTR(NAME, OP) +#define FLOAT_CALL() +#endif + +#ifndef NO_DOUBLE +typedef _Complex double double_complex; +extern double_complex cdouble1 (void); +extern double_complex cdouble2 (void); + +#define DOUBLE_ARG(NAME, OP) ARG_OP(double, double_complex, NAME, OP) +#define DOUBLE_PTR(NAME, OP) PTR_OP(double, double_complex, NAME, OP) +#define DOUBLE_CALL() CALL_OP(double, double_complex, cdouble1, cdouble2) + +#else +#define DOUBLE_ARG(NAME, OP) +#define DOUBLE_PTR(NAME, OP) +#define DOUBLE_CALL() +#endif + +#ifndef NO_FLOAT128 +#ifdef __VSX__ +typedef _Complex float __attribute__((mode(KC))) float128_complex; +#else +typedef _Complex float __attribute__((mode(TC))) float128_complex; +#endif + +extern float128_complex cfloat128_1 (void); +extern float128_complex cfloat128_2 (void); + +#define FLOAT128_ARG(NAME, OP) ARG_OP(float128, float128_complex, NAME, OP) +#define FLOAT128_PTR(NAME, OP) PTR_OP(float128, float128_complex, NAME, OP) +#define FLOAT128_CALL() CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2) + +#else +#define FLOAT128_ARG(NAME, OP) +#define FLOAT128_PTR(NAME, OP) +#define FLOAT128_CALL() +#endif + +#ifndef NO_LDOUBLE +typedef _Complex long double ldouble_complex; +extern ldouble_complex cldouble1 (void); +extern ldouble_complex cldouble2 (void); + +#define LDOUBLE_ARG(NAME, OP) ARG_OP(ldouble, ldouble_complex, NAME, OP) +#define LDOUBLE_PTR(NAME, OP) PTR_OP(ldouble, ldouble_complex, NAME, OP) +#define LDOUBLE_CALL() CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2) + +#else +#define LDOUBLE_ARG(NAME, OP) +#define LDOUBLE_PTR(NAME, OP) +#define LDOUBLE_CALL() +#endif + + +#define ARG_OP(SUFFIX, TYPE, NAME, OP) \ +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b) \ +{ \ + return a OP b; \ +} + +#define PTR_OP(SUFFIX, TYPE, NAME, OP) \ +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b) \ +{ \ + *p = *a OP *b; \ +} + +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2) \ +TYPE call_ ## SUFFIX (void) \ +{ \ + TYPE value1 = FUNC1 (); \ + TYPE value2 = FUNC2 (); \ + return value1 + value2; \ +} + +#ifndef NO_ARG +#ifndef NO_ADD +FLOAT_ARG (add, +) +DOUBLE_ARG (add, +) +FLOAT128_ARG (add, +) +LDOUBLE_ARG (add, +) +#endif + +#ifndef NO_SUB +FLOAT_ARG (sub, -) +DOUBLE_ARG (sub, -) +FLOAT128_ARG (sub, -) +LDOUBLE_ARG (sub, -) +#endif + +#ifndef NO_MUL +FLOAT_ARG (mul, *) +DOUBLE_ARG (mul, *) +FLOAT128_ARG (mul, *) +LDOUBLE_ARG (mul, *) +#endif + +#ifndef NO_DIV +FLOAT_ARG (div, /) +DOUBLE_ARG (div, /) +FLOAT128_ARG (div, /) +LDOUBLE_ARG (div, /) +#endif +#endif + +#ifndef NO_PTR +#ifndef NO_ADD +FLOAT_PTR (add, +) +DOUBLE_PTR (add, +) +FLOAT128_PTR (add, +) +LDOUBLE_PTR (add, +) +#endif + +#ifndef NO_SUB +FLOAT_PTR (sub, -) +DOUBLE_PTR (sub, -) +FLOAT128_PTR (sub, -) +LDOUBLE_PTR (sub, -) +#endif + +#ifndef NO_MUL +FLOAT_PTR (mul, *) +DOUBLE_PTR (mul, *) +FLOAT128_PTR (mul, *) +LDOUBLE_PTR (mul, *) +#endif + +#ifndef NO_DIV +FLOAT_PTR (div, /) +DOUBLE_PTR (div, /) +FLOAT128_PTR (div, /) +LDOUBLE_PTR (div, /) +#endif +#endif + +#ifndef NO_CALL +FLOAT_CALL () +DOUBLE_CALL () +FLOAT128_CALL () +LDOUBLE_CALL () +#endif + +/* { dg-final { scan-assembler "xsaddqp" } } */ +/* { dg-final { scan-assembler "xssubqp" } } */