This is patch #13 which adds new support for matching insn addresses, particularly prefixed insns. In particular the main feature of this patch is a function called 'addr_validate_p' that given an address, a mask of address types you want to match, and an instruction format enumeration, it will return true if the instruction matches the address. It will optionally return the information broken out into a base address, numeric offset, and a mask of which type of address matches.
At the moment, I only added support for the address formats I need for prefixed addressing. I could imagine that it can be extended for other types of addresses, such as TOC addresses. But I wanted to keep this particular patch focused on what is needed for prefixed addressing. The address types it can match include: 1) An address consisting of a single register; 2) A traditional instruction with a 16/14/12-bit offset; 3) A prefixed instruction with a numeric 34-bit offset; 4) A pc-relative address pointing to a local symbol or label; (or) 5) A pc-relative address to an external symbol. You can OR the address types together, so you could look for an address that is either a 34-bit numeric prefixed instruction or a pc-relative address to a local symbol. I have bootstrapped these changes on a power8 little endian system and there were no regressions in make check. Can I check this in the FSF trunk? This is a series of separate patches to add functionality to the PowerPC backend to support future processors. Here is a high level summary of the patches: * Patches 1-8, have already been applied * Patch 9 has been rewritten in patches 12-13 * Patch 10 is withdrawn for now * Patch 11 adds DS offset mode to rs6000.c's reg_addr * Patch 12 adds a new enumeration for instruction format * Patch 13 adds support for matching prefixed insns * Patch 14 adds pc-relative support to load up addresses * Patch 15 renamed some functions to be smaller * Patch 16 updated a comment and moved a predicate * Patch 17 adds the prefixed RTL attribute & emitting 'p' before prefixed * Patch 18 adds prefixed support for scalar types * Patch 19 uses a separate 'future' cost structure * Patch 20 clones power9.md for initial scheduling on future.md. The following patches have not yet been written, but I expect them to be: * Patch 21 finish prefixed insn support for vectors & 128-bit int/floats * Patch 22 enable pc-relative by default * Patch 23 add pcrel linker optimization * Patch 24 new tests 2019-07-24 Michael Meissner <meiss...@linux.ibm.com> * config/rs6000/predicates.md (lwa_operand): If we have prefixed addresses, allow sign extend SImode to have odd offsets. (pcrel_address): Rewrite to use addr_validate_p. (pcrel_external_address): Rewrite to use addr_validate_p. (pcrel_external_mem_operand): Rewrite to use addr_validate_p. * config/rs6000/rs6000-protos.h (addr_validate_info): New structure for addr_validate_p to return information. (ADDR_VALIDATE_REG_SINGLE): New mask for addr_validate_p. (ADDR_VALIDATE_REG_16BIT): New mask for addr_validate_p. (ADDR_VALIDATE_REG_34BIT): New mask for addr_validate_p. (ADDR_VALIDATE_REG_PCREL_LOCAL): New mask for addr_validate_p. (ADDR_VALIDATE_REG_PCREL_EXT): New mask for addr_validate_p. (addr_validate_p): New declaration. * config/rs6000/rs6000.c (mode_supports_prefixed_address_p): Move higher in the file. (quad_address_p): Add checks to see if we can use prefixed addresses without worrying about DQ alignment constraints. (mem_operand_gpr): Add checks to see if we can use prefixed addresses without worrying about DS alignment constraints. (mem_operand_ds_form): Add checks to see if we can use prefixed addresses without worrying about DS alignment constraints. (print_operand_address): Use addr_validate_p to detect pc-relative addresses, and to crack them into the symbol and offset. (addr_validate_p): New function to validate addresses and optionally return the cracked information. (rs6000_prefixed_address_mode_p): Rewrite to use addr_validate_p. Index: gcc/config/rs6000/predicates.md =================================================================== --- gcc/config/rs6000/predicates.md (revision 273771) +++ gcc/config/rs6000/predicates.md (working copy) @@ -921,6 +921,8 @@ (define_predicate "vsx_scalar_64bit" (define_predicate "lwa_operand" (match_code "reg,subreg,mem") { + const unsigned addr_flags = (ADDR_VALIDATE_REG_34BIT + | ADDR_VALIDATE_PCREL_LOCAL); rtx inner, addr, offset; inner = op; @@ -933,6 +935,13 @@ (define_predicate "lwa_operand" return false; addr = XEXP (inner, 0); + + /* The LWA instruction uses the DS-form format where the bottom two bits of + the offset must be 0. The prefixed PLWA does not have this + restriction. */ + if (TARGET_PREFIXED_ADDR && addr_validate_p (addr, INSN_FORM_DS, addr_flags)) + return true; + if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC || (GET_CODE (addr) == PRE_MODIFY @@ -1630,28 +1639,10 @@ (define_predicate "small_toc_ref" (define_predicate "pcrel_address" (match_code "label_ref,symbol_ref,const") { - if (!rs6000_pcrel_p (cfun)) + if (!TARGET_PCREL) 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 addr_validate_p (op, INSN_FORM_PREFIXED, ADDR_VALIDATE_PCREL_LOCAL); }) ;; Return true if the operand is an external symbol whose address can be loaded @@ -1665,25 +1656,10 @@ (define_predicate "pcrel_address" (define_predicate "pcrel_external_address" (match_code "symbol_ref,const") { - if (!rs6000_pcrel_p (cfun)) + if (!TARGET_PCREL) 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 addr_validate_p (op, INSN_FORM_PREFIXED, ADDR_VALIDATE_PCREL_EXT); }) ;; Return 1 if op is a prefixed memory operand. @@ -1699,7 +1675,11 @@ (define_predicate "prefixed_mem_operand" (define_predicate "pcrel_external_mem_operand" (match_code "mem") { - return pcrel_external_address (XEXP (op, 0), Pmode); + if (!TARGET_PCREL) + return false; + + rtx addr = XEXP (op, 0); + return addr_validate_p (addr, INSN_FORM_PREFIXED, ADDR_VALIDATE_PCREL_EXT); }) ;; Match the first insn (addis) in fusing the combination of addis and loads to Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 273771) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -48,6 +48,25 @@ extern bool legitimate_indexed_address_p extern bool avoiding_indexed_address_p (machine_mode); extern rtx rs6000_force_indexed_or_indirect_mem (rtx x); +/* Information structure optionally returned by addr_validate_p to break out + the base, offset, etc. */ + +typedef struct { + rtx base_addr; /* Register, symbol_ref, or label_ref. */ + HOST_WIDE_INT offset; /* Numeric offset. */ + unsigned flags; /* Flags indicate the address type. */ +} addr_validate_info; + +/* Mask flags for addr_validate_p to say what kind of address offset we are + looking for. */ +static const unsigned ADDR_VALIDATE_REG_SINGLE = 0x01; /* single register. */ +static const unsigned ADDR_VALIDATE_REG_16BIT = 0x02; /* reg + 16 bit. */ +static const unsigned ADDR_VALIDATE_REG_34BIT = 0x04; /* reg + 34 bit. */ +static const unsigned ADDR_VALIDATE_PCREL_LOCAL = 0x08; /* local pcrel sym. */ +static const unsigned ADDR_VALIDATE_PCREL_EXT = 0x10; /* ext. pcrel sym. */ + +extern bool addr_validate_p (rtx, enum INSN_FORM, unsigned, + addr_validate_info * = (addr_validate_info *)0); extern rtx rs6000_got_register (rtx); extern rtx find_addr_reg (rtx); extern rtx gen_easy_altivec_constant (rtx); Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 273777) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -410,6 +410,17 @@ mode_supports_dq_form (machine_mode mode != 0); } +/* 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; +} + /* Given that there exists at least one variable that is set (produced) by OUT_INSN and read (consumed) by IN_INSN, return true iff IN_INSN represents one or more memory store operations and none of @@ -7332,6 +7343,8 @@ direct_move_p (rtx op0, rtx op1) bool quad_address_p (rtx addr, machine_mode mode, bool strict) { + const unsigned addr_flags = (ADDR_VALIDATE_REG_34BIT + | ADDR_VALIDATE_PCREL_LOCAL); rtx op0, op1; if (GET_MODE_SIZE (mode) != 16) @@ -7343,6 +7356,14 @@ quad_address_p (rtx addr, machine_mode m if (VECTOR_MODE_P (mode) && !mode_supports_dq_form (mode)) return false; + /* Is this a valid prefixed address? If the bottom four bits of the offset + are non-zero, we could use a prefixed instruction (which does not have the + DQ-form constraint that the traditional instruction had) instead of + forcing the unaligned offset to a GPR. */ + if (TARGET_PREFIXED_ADDR && mode_supports_prefixed_address_p (mode) + && addr_validate_p (addr, INSN_FORM_DQ, addr_flags)) + return true; + if (GET_CODE (addr) != PLUS) return false; @@ -7433,6 +7454,8 @@ address_offset (rtx op) bool mem_operand_gpr (rtx op, machine_mode mode) { + const unsigned addr_flags = (ADDR_VALIDATE_REG_34BIT + | ADDR_VALIDATE_PCREL_LOCAL); unsigned HOST_WIDE_INT offset; int extra; rtx addr = XEXP (op, 0); @@ -7444,6 +7467,14 @@ mem_operand_gpr (rtx op, machine_mode mo && legitimate_indirect_address_p (XEXP (addr, 0), false)) return true; + /* Allow prefixed instructions if supported. If the bottom two bits of the + offset are non-zero, we could use a prefixed instruction (which does not + have the DS-form constraint that the traditional instruction had) instead + of forcing the unaligned offset to a GPR. */ + if (TARGET_PREFIXED_ADDR && mode_supports_prefixed_address_p (mode) + && addr_validate_p (addr, INSN_FORM_DS, addr_flags)) + return true; + /* Don't allow non-offsettable addresses. See PRs 83969 and 84279. */ if (!rs6000_offsettable_memref_p (op, mode, false)) return false; @@ -7474,10 +7505,20 @@ mem_operand_gpr (rtx op, machine_mode mo bool mem_operand_ds_form (rtx op, machine_mode mode) { + const unsigned addr_flags = (ADDR_VALIDATE_REG_34BIT + | ADDR_VALIDATE_PCREL_LOCAL); unsigned HOST_WIDE_INT offset; int extra; rtx addr = XEXP (op, 0); + /* Allow prefixed instructions if supported. If the bottom two bits of the + offset are non-zero, we could use a prefixed instruction (which does not + have the DS-form constraint that the traditional instruction had) instead + of forcing the unaligned offset to a GPR. */ + if (TARGET_PREFIXED_ADDR && mode_supports_prefixed_address_p (mode) + && addr_validate_p (addr, INSN_FORM_DS, addr_flags)) + return true; + if (!offsettable_address_p (false, mode, addr)) return false; @@ -13174,29 +13215,24 @@ print_operand (FILE *file, rtx x, int co void print_operand_address (FILE *file, rtx x) { + addr_validate_info pcrel_info; + const unsigned pcrel_flags = (ADDR_VALIDATE_PCREL_LOCAL + | ADDR_VALIDATE_PCREL_EXT); + if (REG_P (x)) fprintf (file, "0(%s)", reg_names[ REGNO (x) ]); /* Is it a pc-relative address? */ - else if (pcrel_address (x, Pmode)) + else if (addr_validate_p (x, INSN_FORM_PREFIXED, pcrel_flags, &pcrel_info)) { - HOST_WIDE_INT offset; - - if (GET_CODE (x) == CONST) - x = XEXP (x, 0); - - if (GET_CODE (x) == PLUS) - { - offset = INTVAL (XEXP (x, 1)); - x = XEXP (x, 0); - } - else - offset = 0; + output_addr_const (file, pcrel_info.base_addr); - output_addr_const (file, x); + if (pcrel_info.offset) + fprintf (file, "%+" PRId64, pcrel_info.offset); - if (offset) - fprintf (file, "%+" PRId64, offset); + if (SYMBOL_REF_P (pcrel_info.base_addr) + && !SYMBOL_REF_LOCAL_P (pcrel_info.base_addr)) + fputs ("@got", file); fputs ("@pcrel", file); } @@ -13683,70 +13719,133 @@ rs6000_pltseq_template (rtx *operands, i return str; } #endif + +/* Decode a rs6000 address (ADDR) if it is an offset instruction. Use + INFO_FORM to determine whether it is a normal instruction or a prefixed + instruction, and FLAGS to determine what type of offset instruction is + desired. Return the base address into the rtx pointed to by P_BASE. + Optionally return the information about the address into the structure + pointed to with P_INFO. */ -/* 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) +bool +addr_validate_p (rtx addr, + enum INSN_FORM insn_form, + unsigned flags, + addr_validate_info *p_info) { - return mode == VOIDmode; -} + HOST_WIDE_INT offset = 0; + rtx base_addr = NULL_RTX; + unsigned addr_flags = 0; -/* Function to return true if ADDR is a valid prefixed memory address that uses - mode MODE. */ + if (p_info) + memset ((void *) p_info, '\0', sizeof (addr_validate_info)); -bool -rs6000_prefixed_address_mode_p (rtx addr, machine_mode mode) -{ - if (!TARGET_PREFIXED_ADDR || !mode_supports_prefixed_address_p (mode)) - return false; + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); - /* Check for PC-relative addresses. */ - if (pcrel_address (addr, Pmode)) - return true; + /* Single register. */ + if (REG_P (addr) || SUBREG_P (addr)) + { + addr_flags = ADDR_VALIDATE_REG_SINGLE; + base_addr = addr; + } - /* 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) + /* Register + offset. */ + else if (GET_CODE (addr) == PLUS + && (REG_P (XEXP (addr, 0)) || SUBREG_P (XEXP (addr, 0))) + && CONST_INT_P (XEXP (addr, 1))) { - rtx op0 = XEXP (addr, 0); - rtx op1 = XEXP (addr, 1); + base_addr = XEXP (addr, 0); + offset = INTVAL (XEXP (addr, 1)); + bool prefixed_p; - if (!base_reg_operand (op0, Pmode) || !CONST_INT_P (op1)) + /* Prefixed instructions can only access 34-bits. Fail if the value + is larger than that. */ + if (!SIGNED_34BIT_OFFSET_P (offset)) return false; - HOST_WIDE_INT value = INTVAL (op1); - if (!SIGNED_34BIT_OFFSET_P (value)) - return false; + /* Determine if the offset requires the instruction to be prefixed, + either because it is too large, or because it doesn't meet the + requirements for DS instruction encoding or DQ instruction + encoding. */ + if (!SIGNED_16BIT_OFFSET_P (offset)) + prefixed_p = true; - /* Offset larger than 16-bits? */ - if (!SIGNED_16BIT_OFFSET_P (value)) - return true; + else if (insn_form == INSN_FORM_DS) + prefixed_p = (offset & 3) != 0; - /* 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; + else if (insn_form == INSN_FORM_DQ) + prefixed_p = (offset & 15) != 0; - /* QImode/HImode has no restrictions. */ else - return true; + prefixed_p = false; - /* Return true if we must use a prefixed instruction. */ - return (value & mask) != 0; + addr_flags = (prefixed_p + ? ADDR_VALIDATE_REG_34BIT + : ADDR_VALIDATE_REG_16BIT); } - return false; + else if (!TARGET_PCREL) + return false; + + /* Pc-relative symbols/labels without offsets. */ + else if (SYMBOL_REF_P (addr)) + { + base_addr = addr; + addr_flags = (SYMBOL_REF_LOCAL_P (addr) + ? ADDR_VALIDATE_PCREL_LOCAL + : ADDR_VALIDATE_PCREL_EXT); + } + + else if (LABEL_REF_P (addr)) + { + base_addr = addr; + addr_flags = ADDR_VALIDATE_PCREL_LOCAL; + } + + /* Pc-relative symbols with offsets. */ + else if (GET_CODE (addr) == PLUS + && SYMBOL_REF_P (XEXP (addr, 0)) + && CONST_INT_P (XEXP (addr, 1))) + { + base_addr = XEXP (addr, 0); + offset = INTVAL (XEXP (addr, 1)); + addr_flags = (SYMBOL_REF_LOCAL_P (base_addr) + ? ADDR_VALIDATE_PCREL_LOCAL + : ADDR_VALIDATE_PCREL_EXT); + } + + else + return false; + + /* See if the address type matches what the user wanted. */ + if ((flags & addr_flags) == 0) + return false; + + /* Return information to caller if desired. */ + if (p_info) + { + p_info->base_addr = base_addr; + p_info->offset = offset; + p_info->flags = addr_flags; + } + + return true; +} + +/* 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) +{ + const unsigned addr_flags = (ADDR_VALIDATE_REG_34BIT + | ADDR_VALIDATE_PCREL_LOCAL); + + if (!TARGET_PREFIXED_ADDR || !mode_supports_prefixed_address_p (mode)) + return false; + + return addr_validate_p (addr, reg_addr[mode].default_insn_form, addr_flags); } #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797