From a1842c37af6ab85a81d556861f33c2f38ce8b8f6 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Fri, 31 May 2019 00:38:35 +0000 Subject: [PATCH] predicates.md (pcrel_address): New define_predicate. 2019-05-30 Bill Schmidt Michael Meissner * config/rs6000/predicates.md (pcrel_address): New define_predicate. (prefixed_mem_operand): Likewise. (non_prefixed_mem_operand): Likewise. * config/rs6000/rs6000-protos.h (rs6000_prefixed_address): New prototype. * config/rs6000/rs6000.c (print_operand_address): Handle PC-relative addresses. (mode_supports_prefixed_address_p): New function. (rs6000_prefixed_address): New function. * config/rs6000/rs6000.h (SYMBOL_FLAG_PCREL): New #define. (SYMBOL_REF_PCREL_P): Likewise. Co-Authored-By: Michael Meissner From-SVN: r271798 --- gcc/ChangeLog | 15 ++++++ gcc/config/rs6000/predicates.md | 39 ++++++++++++++ gcc/config/rs6000/rs6000-protos.h | 1 + gcc/config/rs6000/rs6000.c | 89 +++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.h | 7 +++ 5 files changed, 151 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 269d62b7dd4..293744ea091 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2019-05-30 Bill Schmidt + Michael Meissner + + * config/rs6000/predicates.md (pcrel_address): New define_predicate. + (prefixed_mem_operand): Likewise. + (non_prefixed_mem_operand): Likewise. + * config/rs6000/rs6000-protos.h (rs6000_prefixed_address): New + prototype. + * config/rs6000/rs6000.c (print_operand_address): Handle + PC-relative addresses. + (mode_supports_prefixed_address_p): New function. + (rs6000_prefixed_address): New function. + * config/rs6000/rs6000.h (SYMBOL_FLAG_PCREL): New #define. + (SYMBOL_REF_PCREL_P): Likewise. + 2019-05-30 Jakub Jelinek * gimplify.c (enum gimplify_omp_var_data): Add GOVD_CONDTEMP. diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index a578e0f27f7..8ca98299950 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1622,6 +1622,45 @@ 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 (!TARGET_PCREL) + return false; + + /* Discard any CONST's. */ + 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), 0)) + return false; + + op = op0; + } + + return LABEL_REF_P (op) || SYMBOL_REF_PCREL_P (op); +}) + +;; Return 1 if op is a prefixed memory operand +(define_predicate "prefixed_mem_operand" + (match_code "mem") +{ + return rs6000_prefixed_address (XEXP (op, 0), GET_MODE (op)); +}) + +;; Return 1 if op is a memory operand that is not a prefixed memory +;; operand. +(define_predicate "non_prefixed_mem_operand" + (and (match_operand 0 "memory_operand") + (not (match_operand 0 "prefixed_mem_operand")))) + ;; Match the first insn (addis) in fusing the combination of addis and loads to ;; GPR registers on power8. (define_predicate "fusion_gpr_addis" diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 18ece005a96..feb1250fb8b 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -154,6 +154,7 @@ extern align_flags rs6000_loop_align (rtx); 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 (rtx, machine_mode); #endif /* RTX_CODE */ #ifdef TREE_CODE diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index fca8bdfc04c..94795bec1d4 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -21085,6 +21085,30 @@ print_operand_address (FILE *file, rtx x) { if (REG_P (x)) fprintf (file, "0(%s)", reg_names[ REGNO (x) ]); + + /* Is it a pc-relative address? */ + else if (pcrel_address (x, Pmode)) + { + 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, x); + + if (offset) + fprintf (file, "%+" PRId64, offset); + + fputs ("@pcrel", file); + } else if (SYMBOL_REF_P (x) || GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF) { @@ -21569,6 +21593,71 @@ rs6000_pltseq_template (rtx *operands, int which) } #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 (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, 0)) + return false; + + /* Offset larger than 16-bits? */ + if (!SIGNED_16BIT_OFFSET_P (value, 0)) + 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 VISIBILITY_TYPE. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 8119c6621d5..34fa36b6ed9 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2516,3 +2516,10 @@ extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; IN_RANGE (VALUE, \ -(HOST_WIDE_INT_1 << 33), \ (HOST_WIDE_INT_1 << 33) - 1 - (EXTRA)) + +/* Flag to mark SYMBOL_REF objects to say they are local addresses and are used + in pc-relative addresses. */ +#define SYMBOL_FLAG_PCREL SYMBOL_FLAG_MACH_DEP + +#define SYMBOL_REF_PCREL_P(X) \ + (SYMBOL_REF_P (X) && SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_PCREL) -- 2.30.2