From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5596 invoked by alias); 18 Sep 2019 23:49:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 5521 invoked by uid 89); 18 Sep 2019 23:49:27 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.8 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.1 spammy=rs6000, Bottom, rs6000c, rs6000.c X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Sep 2019 23:49:24 +0000 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x8INbTJZ144919; Wed, 18 Sep 2019 19:49:22 -0400 Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 2v3vds3fwg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Sep 2019 19:49:22 -0400 Received: from m0098416.ppops.net (m0098416.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.27/8.16.0.27) with SMTP id x8INc8Lq147009; Wed, 18 Sep 2019 19:49:22 -0400 Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0b-001b2d01.pphosted.com with ESMTP id 2v3vds3fw8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Sep 2019 19:49:22 -0400 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id x8INZxax020267; Wed, 18 Sep 2019 23:49:21 GMT Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by ppma02wdc.us.ibm.com with ESMTP id 2v3vbtrsje-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Sep 2019 23:49:21 +0000 Received: from b03ledav006.gho.boulder.ibm.com (b03ledav006.gho.boulder.ibm.com [9.17.130.237]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x8INnKSH50659786 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 18 Sep 2019 23:49:20 GMT Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C6E1CC605A; Wed, 18 Sep 2019 23:49:20 +0000 (GMT) Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 34674C6059; Wed, 18 Sep 2019 23:49:20 +0000 (GMT) Received: from ibm-toto.the-meissners.org (unknown [9.32.77.177]) by b03ledav006.gho.boulder.ibm.com (Postfix) with ESMTPS; Wed, 18 Sep 2019 23:49:20 +0000 (GMT) Date: Wed, 18 Sep 2019 23:49:00 -0000 From: Michael Meissner To: Michael Meissner , gcc-patches@gcc.gnu.org, segher@kernel.crashing.org, dje.gcc@gmail.com Subject: [PATCH] V4, patch #1: Rework prefixed/pc-relative lookup Message-ID: <20190918234918.GA28484@ibm-toto.the-meissners.org> Mail-Followup-To: Michael Meissner , gcc-patches@gcc.gnu.org, segher@kernel.crashing.org, dje.gcc@gmail.com References: <20190918234214.GA27521@ibm-toto.the-meissners.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20190918234214.GA27521@ibm-toto.the-meissners.org> User-Agent: Mutt/1.5.21 (2010-09-15) X-SW-Source: 2019-09/txt/msg01126.txt.bz2 This patch reworks the prefixed and pc-relative memory matching functions. As I said in the intro message, I do not re-use the address mask bits in reg_addr, but instead, I have a separate function that takes an address and decodes it into the various different flavors (single register address, D-form 16-bit address, X-form indexed address, numeric 34-bit offset, local pc-relative address, etc.). The caller then decides whether the address matches what they are looking for. I have two enumerations that I added to this series: 1) insn_form: This is the address format (D, DS, DQ, X, etc.); 2) non_prefixed: This is a limited enum that just describes the format of the non-prefixed instruction to decide if an address needs to be prefixed or not. Originally, I was trying to re-use the same insn_form enumeration for both the output and the input to say what the traditional instruction uses, but I ultimately separated them to make it clearer. This is an infrastructure patch. It needs the second patch to enable basic pc-relative support. I have done a bootstrap build with all of the patches applied, and there were no regressions in the test suite. After posting these patches, I will start a job to build each set of patches in turn just to make sure there are no extra warnings. Can I commit this patch to the trunk? 2019-09-18 Michael Meissner * config/rs6000/predicates.md (pcrel_address): Delete predicate. (pcrel_local_address): Replace pcrel_address predicate, use the new function address_to_insn_form. (pcrel_external_address): Replace with new implementation using address_to_insn_form.. (prefixed_mem_operand): Delete predicate which is now unused. (pcrel_external_mem_operand): Delete predicate which is now unused. * config/rs6000/rs6000-protos.h (enum insn_form): New enumeration. (enum non_prefixed): New enumeration. (address_to_insn_form): New declaration. * config/rs6000/rs6000.c (print_operand_address): Check for either pc-relative local symbols or pc-relative external symbols. (mode_supports_prefixed_address_p): Delete, no longer used. (rs6000_prefixed_address_mode_p): Delete, no longer used. (address_to_insn_form): New function to decode an address format. Index: gcc/config/rs6000/predicates.md =================================================================== --- gcc/config/rs6000/predicates.md (revision 275903) +++ gcc/config/rs6000/predicates.md (working copy) @@ -1625,82 +1625,7 @@ (define_predicate "small_toc_ref" return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL; }) -;; Return true if the operand is a pc-relative address. -(define_predicate "pcrel_address" - (match_code "label_ref,symbol_ref,const") -{ - if (!rs6000_pcrel_p (cfun)) - return false; - - if (GET_CODE (op) == CONST) - op = XEXP (op, 0); - - /* Validate offset. */ - if (GET_CODE (op) == PLUS) - { - rtx op0 = XEXP (op, 0); - rtx op1 = XEXP (op, 1); - - if (!CONST_INT_P (op1) || !SIGNED_34BIT_OFFSET_P (INTVAL (op1))) - return false; - - op = op0; - } - - if (LABEL_REF_P (op)) - return true; - - return (SYMBOL_REF_P (op) && SYMBOL_REF_LOCAL_P (op)); -}) - -;; Return true if the operand is an external symbol whose address can be loaded -;; into a register using: -;; PLD reg,label@pcrel@got -;; -;; The linker will either optimize this to either a PADDI if the label is -;; defined locally in another module or a PLD of the address if the label is -;; defined in another module. - -(define_predicate "pcrel_external_address" - (match_code "symbol_ref,const") -{ - if (!rs6000_pcrel_p (cfun)) - return false; - - if (GET_CODE (op) == CONST) - op = XEXP (op, 0); - - /* Validate offset. */ - if (GET_CODE (op) == PLUS) - { - rtx op0 = XEXP (op, 0); - rtx op1 = XEXP (op, 1); - - if (!CONST_INT_P (op1) || !SIGNED_34BIT_OFFSET_P (INTVAL (op1))) - return false; - - op = op0; - } - - return (SYMBOL_REF_P (op) && !SYMBOL_REF_LOCAL_P (op)); -}) - -;; Return 1 if op is a prefixed memory operand. -(define_predicate "prefixed_mem_operand" - (match_code "mem") -{ - return rs6000_prefixed_address_mode_p (XEXP (op, 0), GET_MODE (op)); -}) - -;; Return 1 if op is a memory operand to an external variable when we -;; support pc-relative addressing and the PCREL_OPT relocation to -;; optimize references to it. -(define_predicate "pcrel_external_mem_operand" - (match_code "mem") -{ - return pcrel_external_address (XEXP (op, 0), Pmode); -}) - + ;; Match the first insn (addis) in fusing the combination of addis and loads to ;; GPR registers on power8. (define_predicate "fusion_gpr_addis" @@ -1857,3 +1782,31 @@ (define_predicate "fusion_addis_mem_comb return 0; }) + + +;; Return true if the operand is a pc-relative address to a local symbol or a +;; label that can be used directly in a memory operation. +(define_predicate "pcrel_local_address" + (match_code "label_ref,symbol_ref,const") +{ + enum insn_form iform = address_to_insn_form (op, mode, NON_PREFIXED_DEFAULT); + return iform == INSN_FORM_PCREL_LOCAL; +}) + +;; Return true if the operand is an external symbol whose address can be loaded +;; into a register. +(define_predicate "pcrel_external_address" + (match_code "symbol_ref,const") +{ + enum insn_form iform = address_to_insn_form (op, mode, NON_PREFIXED_DEFAULT); + return iform == INSN_FORM_PCREL_EXTERNAL; +}) + +;; Return true if the address is pc-relative and the symbol is either local or +;; external. +(define_predicate "pcrel_local_or_external_address" + (match_code "label_ref,symbol_ref,const") +{ + enum insn_form iform = address_to_insn_form (op, mode, NON_PREFIXED_DEFAULT); + return (iform == INSN_FORM_PCREL_EXTERNAL || iform == INSN_FORM_PCREL_LOCAL); +}) Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 275903) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -154,7 +154,41 @@ extern align_flags rs6000_loop_align (rt extern void rs6000_split_logical (rtx [], enum rtx_code, bool, bool, bool); extern bool rs6000_pcrel_p (struct function *); extern bool rs6000_fndecl_pcrel_p (const_tree); -extern bool rs6000_prefixed_address_mode_p (rtx, machine_mode); + +/* Different PowerPC instruction formats that are used by GCC. There are + various other instruction formats used by the PowerPC hardware, but the + these formats are not currently used by GCC. */ + +enum insn_form { + INSN_FORM_BAD, /* Bad instruction format. */ + INSN_FORM_BASE_REG, /* Base register only. */ + INSN_FORM_D, /* Base register + 16-bit numeric offset. */ + INSN_FORM_DS, /* Base register + 14-bit offset + 00. */ + INSN_FORM_DQ, /* Base register + 12-bit offset + 0000. */ + INSN_FORM_X, /* Base register + index register. */ + INSN_FORM_UPDATE, /* Address udpates base register. */ + INSN_FORM_LO_SUM, /* Special offset instruction. */ + INSN_FORM_PREFIXED_NUMERIC, /* Base register + 34 bit numeric offset. */ + INSN_FORM_PCREL_LOCAL, /* Pc-relative local symbol. */ + INSN_FORM_PCREL_EXTERNAL /* Pc-relative external symbol. */ +}; + +/* Instruction format for the non-prefixed version of a load or store. This is + used to determine if a 16-bit offset is valid to be used with a non-prefixed + (traditional) instruction or if the bottom bits of the offset cannot be used + with a DS or DQ instruction format, and GCC has to use a prefixed + instruction for the load or store. */ + +enum non_prefixed { + NON_PREFIXED_DEFAULT, /* Use the default. */ + NON_PREFIXED_D, /* All 16-bits are valid. */ + NON_PREFIXED_DS, /* Bottom 2 bits must be 0. */ + NON_PREFIXED_DQ, /* Bottom 4 bits must be 0. */ + NON_PREFIXED_X /* No offset memory form exists. */ +}; + +extern enum insn_form address_to_insn_form (rtx, machine_mode, + enum non_prefixed); #endif /* RTX_CODE */ #ifdef TREE_CODE Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 275903) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -13079,7 +13079,7 @@ print_operand_address (FILE *file, rtx x fprintf (file, "0(%s)", reg_names[ REGNO (x) ]); /* Is it a pc-relative address? */ - else if (pcrel_address (x, Pmode)) + else if (TARGET_PCREL && pcrel_local_or_external_address (x, VOIDmode)) { HOST_WIDE_INT offset; @@ -13099,6 +13099,9 @@ print_operand_address (FILE *file, rtx x if (offset) fprintf (file, "%+" PRId64, offset); + if (SYMBOL_REF_P (x) && !SYMBOL_REF_LOCAL_P (x)) + fputs ("@got", file); + fputs ("@pcrel", file); } else if (SYMBOL_REF_P (x) || GET_CODE (x) == CONST @@ -13584,71 +13587,6 @@ rs6000_pltseq_template (rtx *operands, i return str; } #endif - -/* Helper function to return whether a MODE can do prefixed loads/stores. - VOIDmode is used when we are loading the pc-relative address into a base - register, but we are not using it as part of a memory operation. As modes - add support for prefixed memory, they will be added here. */ - -static bool -mode_supports_prefixed_address_p (machine_mode mode) -{ - return mode == VOIDmode; -} - -/* Function to return true if ADDR is a valid prefixed memory address that uses - mode MODE. */ - -bool -rs6000_prefixed_address_mode_p (rtx addr, machine_mode mode) -{ - if (!TARGET_PREFIXED_ADDR || !mode_supports_prefixed_address_p (mode)) - return false; - - /* Check for PC-relative addresses. */ - if (pcrel_address (addr, Pmode)) - return true; - - /* Check for prefixed memory addresses that have a large numeric offset, - or an offset that can't be used for a DS/DQ-form memory operation. */ - if (GET_CODE (addr) == PLUS) - { - rtx op0 = XEXP (addr, 0); - rtx op1 = XEXP (addr, 1); - - if (!base_reg_operand (op0, Pmode) || !CONST_INT_P (op1)) - return false; - - HOST_WIDE_INT value = INTVAL (op1); - if (!SIGNED_34BIT_OFFSET_P (value)) - return false; - - /* Offset larger than 16-bits? */ - if (!SIGNED_16BIT_OFFSET_P (value)) - return true; - - /* DQ instruction (bottom 4 bits must be 0) for vectors. */ - HOST_WIDE_INT mask; - if (GET_MODE_SIZE (mode) >= 16) - mask = 15; - - /* DS instruction (bottom 2 bits must be 0). For 32-bit integers, we - need to use DS instructions if we are sign-extending the value with - LWA. For 32-bit floating point, we need DS instructions to load and - store values to the traditional Altivec registers. */ - else if (GET_MODE_SIZE (mode) >= 4) - mask = 3; - - /* QImode/HImode has no restrictions. */ - else - return true; - - /* Return true if we must use a prefixed instruction. */ - return (value & mask) != 0; - } - - return false; -} #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO /* Emit an assembler directive to set symbol visibility for DECL to @@ -24627,6 +24565,158 @@ rs6000_pcrel_p (struct function *fn) return rs6000_fndecl_pcrel_p (fn->decl); } + +/* Given an address (ADDR), a mode (MODE), and what the format of the + non-prefixed address (NON_PREFIXED_INSN) is, return the instruction format + for the address. */ + +enum insn_form +address_to_insn_form (rtx addr, + machine_mode mode, + enum non_prefixed non_prefixed_insn) +{ + rtx op0, op1; + + /* Single register is easy. */ + if (REG_P (addr) || SUBREG_P (addr)) + return INSN_FORM_BASE_REG; + + /* If we don't support offset addressing, make sure only indexed addressing + is allowed. We special case SDmode so that the register allocator does + try to move SDmode through GPR registers, but instead uses the 32-bit + integer read/write instructions for the floating point registers. */ + if (non_prefixed_insn == NON_PREFIXED_X || mode == SDmode) + { + if (GET_CODE (addr) != PLUS) + return INSN_FORM_BAD; + + op0 = XEXP (addr, 0); + op1 = XEXP (addr, 1); + if (!REG_P (op0) && !SUBREG_P (op0)) + return INSN_FORM_BAD; + + if (!REG_P (op1) && !SUBREG_P (op1)) + return INSN_FORM_BAD; + + return INSN_FORM_X; + } + + /* Deal with update forms. */ + if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC) + return INSN_FORM_UPDATE; + + /* Handle pc-relative symbols and labels. Check for both local and external + symbols. Assume labels are always local. */ + if (TARGET_PCREL) + { + if (SYMBOL_REF_P (addr)) + return (SYMBOL_REF_LOCAL_P (addr) + ? INSN_FORM_PCREL_LOCAL + : INSN_FORM_PCREL_EXTERNAL); + + if (LABEL_REF_P (addr)) + return INSN_FORM_PCREL_LOCAL; + } + + /* Check whether this is an offsettable address. Deal with LO_SUM addresses + used with TOC and 32-bit addressing and with indexed addresses. */ + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + if (GET_CODE (addr) != PLUS) + return GET_CODE (addr) == LO_SUM ? INSN_FORM_LO_SUM : INSN_FORM_BAD; + + op0 = XEXP (addr, 0); + op1 = XEXP (addr, 1); + + if (REG_P (op1) || SUBREG_P (op1)) + return INSN_FORM_X; + + if (!CONST_INT_P (op1)) + return INSN_FORM_BAD; + + HOST_WIDE_INT offset = INTVAL (op1); + if (!SIGNED_34BIT_OFFSET_P (offset)) + return INSN_FORM_BAD; + + /* Check for local and external pc-relative addresses. Labels are always + local. */ + if (TARGET_PCREL) + { + if (SYMBOL_REF_P (op0)) + return (SYMBOL_REF_LOCAL_P (op0) + ? INSN_FORM_PCREL_LOCAL + : INSN_FORM_PCREL_EXTERNAL); + + if (LABEL_REF_P (op0)) + return INSN_FORM_PCREL_LOCAL; + } + + /* If it isn't pc-relative, check for 16-bit D/DS/DQ-form. */ + if (!REG_P (op0) && !SUBREG_P (op0)) + return INSN_FORM_BAD; + + /* Large offsets must be prefixed. */ + if (!SIGNED_16BIT_OFFSET_P (offset)) + return (TARGET_PREFIXED_ADDR + ? INSN_FORM_PREFIXED_NUMERIC + : INSN_FORM_BAD); + + /* 16-bit offset, see what default instruction format to use. */ + if (non_prefixed_insn == NON_PREFIXED_DEFAULT) + { + unsigned size = GET_MODE_SIZE (mode); + + /* On 64-bit systems, assume 64-bit integers need to use DS form + addresses. VSX vectors need to use DQ form addresses. */ + if (TARGET_POWERPC64 && size >= 8 && GET_MODE_CLASS (mode) == MODE_INT) + non_prefixed_insn = NON_PREFIXED_DS; + + else if (TARGET_VSX && size >= 16 + && ALTIVEC_OR_VSX_VECTOR_MODE (mode)) + non_prefixed_insn = NON_PREFIXED_DQ; + + else + non_prefixed_insn = NON_PREFIXED_D; + } + + /* Classify the D/DS/DQ-form addresses. */ + switch (non_prefixed_insn) + { + /* Instruction format D, all 16 bits are valid. */ + case NON_PREFIXED_D: + return INSN_FORM_D; + + /* Instruction format DS, bottom 2 bits must be 0. */ + case NON_PREFIXED_DS: + if ((offset & 3) == 0) + return INSN_FORM_DS; + + else if (TARGET_PREFIXED_ADDR) + return INSN_FORM_PREFIXED_NUMERIC; + + else + return INSN_FORM_BAD; + + /* Instruction format DQ, bottom 4 bits must be 0. */ + case NON_PREFIXED_DQ: + if ((offset & 15) == 0) + return INSN_FORM_DQ; + + else if (TARGET_PREFIXED_ADDR) + return INSN_FORM_PREFIXED_NUMERIC; + + else + return INSN_FORM_BAD; + + default: + break; + } + + return INSN_FORM_BAD; +} + + #ifdef HAVE_GAS_HIDDEN # define USE_HIDDEN_LINKONCE 1 #else -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meissner@linux.ibm.com, phone: +1 (978) 899-4797