Commit 26ca7d1b by Michael Meissner Committed by Michael Meissner

Add initial support for prefixed/PC-relative addressing.

2019-09-30  Michael Meissner  <meissner@linux.ibm.com>

	* 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.
	(prefixed_load_p): New declaration.
	(prefixed_store_p): New declaration.
	(prefixed_paddi_p): New declaration.
	(rs6000_asm_output_opcode): New declaration.
	(rs6000_final_prescan_insn): Move declaration and update calling
	signature.
	(address_is_prefixed): New helper inline function.
	* config/rs6000/rs6000.c(print_operand_address): Check for either
	PC-relative local symbols or PC-relative external symbols.
	(rs6000_emit_move): Support loading PC-relative addresses.
	(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.
	(reg_to_non_prefixed): New function to identify what the
	non-prefixed memory instruction format is for a register.
	(prefixed_load_p): New function to identify prefixed loads.
	(prefixed_store_p): New function to identify prefixed stores.
	(prefixed_paddi_p): New function to identify prefixed load
	immediates.
	(next_insn_prefixed_p): New static state variable.
	(rs6000_final_prescan_insn): New function to determine if an insn
	uses a prefixed instruction.
	(rs6000_asm_output_opcode): New function to emit 'p' in front of a
	prefixed instruction.
	* config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook.
	(ASM_OUTPUT_OPCODE): New target hook.
	* config/rs6000/rs6000.md (prefixed): New insn attribute for
	prefixed instructions.
	(prefixed_length): New insn attribute for the size of prefixed
	instructions.
	(non_prefixed_length): New insn attribute for the size of
	non-prefixed instructions.
	(pcrel_local_addr): New insn to load up a local PC-relative
	address.
	(pcrel_extern_addr): New insn to load up an external PC-relative
	address.
	(mov<mode>_64bit_dm): Split the alternatives for loading 0.0 to a
	GPR and loading a 128-bit floating point type to a GPR.

From-SVN: r276300
parent 61362d9d
2019-09-30 Michael Meissner <meissner@linux.ibm.com>
* 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.
(prefixed_load_p): New declaration.
(prefixed_store_p): New declaration.
(prefixed_paddi_p): New declaration.
(rs6000_asm_output_opcode): New declaration.
(rs6000_final_prescan_insn): Move declaration and update calling
signature.
(address_is_prefixed): New helper inline function.
* config/rs6000/rs6000.c(print_operand_address): Check for either
PC-relative local symbols or PC-relative external symbols.
(rs6000_emit_move): Support loading PC-relative addresses.
(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.
(reg_to_non_prefixed): New function to identify what the
non-prefixed memory instruction format is for a register.
(prefixed_load_p): New function to identify prefixed loads.
(prefixed_store_p): New function to identify prefixed stores.
(prefixed_paddi_p): New function to identify prefixed load
immediates.
(next_insn_prefixed_p): New static state variable.
(rs6000_final_prescan_insn): New function to determine if an insn
uses a prefixed instruction.
(rs6000_asm_output_opcode): New function to emit 'p' in front of a
prefixed instruction.
* config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook.
(ASM_OUTPUT_OPCODE): New target hook.
* config/rs6000/rs6000.md (prefixed): New insn attribute for
prefixed instructions.
(prefixed_length): New insn attribute for the size of prefixed
instructions.
(non_prefixed_length): New insn attribute for the size of
non-prefixed instructions.
(pcrel_local_addr): New insn to load up a local PC-relative
address.
(pcrel_extern_addr): New insn to load up an external PC-relative
address.
(mov<mode>_64bit_dm): Split the alternatives for loading 0.0 to a
GPR and loading a 128-bit floating point type to a GPR.
2019-09-30 Richard Biener <rguenther@suse.de> 2019-09-30 Richard Biener <rguenther@suse.de>
* gimple.c (gimple_get_lhs): For PHIs return the result. * gimple.c (gimple_get_lhs): For PHIs return the result.
......
...@@ -1625,82 +1625,7 @@ ...@@ -1625,82 +1625,7 @@
return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL; 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 ;; Match the first insn (addis) in fusing the combination of addis and loads to
;; GPR registers on power8. ;; GPR registers on power8.
(define_predicate "fusion_gpr_addis" (define_predicate "fusion_gpr_addis"
...@@ -1857,3 +1782,28 @@ ...@@ -1857,3 +1782,28 @@
return 0; return 0;
}) })
;; Return true if the operand is a PC-relative address of 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 a PC-relative 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"
(ior (match_operand 0 "pcrel_local_address")
(match_operand 0 "pcrel_external_address")))
...@@ -154,7 +154,66 @@ extern align_flags rs6000_loop_align (rtx); ...@@ -154,7 +154,66 @@ extern align_flags rs6000_loop_align (rtx);
extern void rs6000_split_logical (rtx [], enum rtx_code, bool, bool, bool); extern void rs6000_split_logical (rtx [], enum rtx_code, bool, bool, bool);
extern bool rs6000_pcrel_p (struct function *); extern bool rs6000_pcrel_p (struct function *);
extern bool rs6000_fndecl_pcrel_p (const_tree); 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 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, /* Reg + 16-bit numeric offset. */
INSN_FORM_DS, /* Reg + offset, bottom 2 bits must be 0. */
INSN_FORM_DQ, /* Reg + offset, bottom 4 bits must be 0. */
INSN_FORM_X, /* Base register + index register. */
INSN_FORM_UPDATE, /* Address updates base register. */
INSN_FORM_LO_SUM, /* Reg + offset using symbol. */
INSN_FORM_PREFIXED_NUMERIC, /* Reg + 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_form {
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_form);
extern bool prefixed_load_p (rtx_insn *);
extern bool prefixed_store_p (rtx_insn *);
extern bool prefixed_paddi_p (rtx_insn *);
extern void rs6000_asm_output_opcode (FILE *);
extern void rs6000_final_prescan_insn (rtx_insn *, rtx [], int);
/* Return true if the address can be used for a prefixed load, store, or add
immediate instructions that cannot be used with a non-prefixed instruction.
For example, using a numeric offset that is not valid for the non-prefixed
instruction or a PC-relative reference to a local symbol would return true,
but an address with an offset of 64 would not return true.
References to external PC-relative symbols aren't allowed, because GCC has
to load the address into a register and then issue a separate load or
store. */
static inline bool
address_is_prefixed (rtx addr,
machine_mode mode,
enum non_prefixed_form non_prefixed)
{
enum insn_form iform = address_to_insn_form (addr, mode, non_prefixed);
return (iform == INSN_FORM_PREFIXED_NUMERIC
|| iform == INSN_FORM_PCREL_LOCAL);
}
#endif /* RTX_CODE */ #endif /* RTX_CODE */
#ifdef TREE_CODE #ifdef TREE_CODE
...@@ -234,8 +293,6 @@ extern void rs6000_d_target_versions (void); ...@@ -234,8 +293,6 @@ extern void rs6000_d_target_versions (void);
const char * rs6000_xcoff_strip_dollar (const char *); const char * rs6000_xcoff_strip_dollar (const char *);
#endif #endif
void rs6000_final_prescan_insn (rtx_insn *, rtx *operand, int num_operands);
extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES]; extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES];
extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER]; extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER];
......
...@@ -2547,3 +2547,24 @@ typedef struct GTY(()) machine_function ...@@ -2547,3 +2547,24 @@ typedef struct GTY(()) machine_function
IN_RANGE ((VALUE), \ IN_RANGE ((VALUE), \
-(HOST_WIDE_INT_1 << 33), \ -(HOST_WIDE_INT_1 << 33), \
(HOST_WIDE_INT_1 << 33) - 1 - (EXTRA)) (HOST_WIDE_INT_1 << 33) - 1 - (EXTRA))
/* Define this if some processing needs to be done before outputting the
assembler code. On the PowerPC, we remember if the current insn is a normal
prefixed insn where we need to emit a 'p' before the insn. */
#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS) \
do \
{ \
if (TARGET_PREFIXED_ADDR) \
rs6000_final_prescan_insn (INSN, OPERANDS, NOPERANDS); \
} \
while (0)
/* Do anything special before emitting an opcode. We use it to emit a 'p' for
prefixed insns that is set in FINAL_PRESCAN_INSN. */
#define ASM_OUTPUT_OPCODE(STREAM, OPCODE) \
do \
{ \
if (TARGET_PREFIXED_ADDR) \
rs6000_asm_output_opcode (STREAM); \
} \
while (0)
...@@ -256,8 +256,49 @@ ...@@ -256,8 +256,49 @@
;; Is copying of this instruction disallowed? ;; Is copying of this instruction disallowed?
(define_attr "cannot_copy" "no,yes" (const_string "no")) (define_attr "cannot_copy" "no,yes" (const_string "no"))
;; Length of the instruction (in bytes).
(define_attr "length" "" (const_int 4)) ;; Whether an insn is a prefixed insn, and an initial 'p' should be printed
;; before the instruction. A prefixed instruction has a prefix instruction
;; word that extends the immediate value of the instructions from 12-16 bits to
;; 34 bits. The macro ASM_OUTPUT_OPCODE emits a leading 'p' for prefixed
;; insns. The default "length" attribute will also be adjusted by default to
;; be 12 bytes.
(define_attr "prefixed" "no,yes"
(cond [(ior (match_test "!TARGET_PREFIXED_ADDR")
(match_test "!NONJUMP_INSN_P (insn)"))
(const_string "no")
(eq_attr "type" "load,fpload,vecload")
(if_then_else (match_test "prefixed_load_p (insn)")
(const_string "yes")
(const_string "no"))
(eq_attr "type" "store,fpstore,vecstore")
(if_then_else (match_test "prefixed_store_p (insn)")
(const_string "yes")
(const_string "no"))
(eq_attr "type" "integer,add")
(if_then_else (match_test "prefixed_paddi_p (insn)")
(const_string "yes")
(const_string "no"))]
(const_string "no")))
;; Length in bytes of instructions that use prefixed addressing and length in
;; bytes of instructions that does not use prefixed addressing. This allows
;; both lengths to be defined as constants, and the length attribute can pick
;; the size as appropriate.
(define_attr "prefixed_length" "" (const_int 12))
(define_attr "non_prefixed_length" "" (const_int 4))
;; Length of the instruction (in bytes). Prefixed insns are 8 bytes, but the
;; assembler might issue need to issue a NOP so that the prefixed instruction
;; does not cross a cache boundary, which makes them possibly 12 bytes.
(define_attr "length" ""
(if_then_else (eq_attr "prefixed" "yes")
(attr "prefixed_length")
(attr "non_prefixed_length")))
;; Processor type -- this attribute must exactly match the processor_type ;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in rs6000-opts.h. ;; enumeration in rs6000-opts.h.
...@@ -7713,9 +7754,18 @@ ...@@ -7713,9 +7754,18 @@
;; not swapped like they are for TImode or TFmode. Subregs therefore are ;; not swapped like they are for TImode or TFmode. Subregs therefore are
;; problematical. Don't allow direct move for this case. ;; problematical. Don't allow direct move for this case.
;; FPR load FPR store FPR move FPR zero GPR load
;; GPR zero GPR store GPR move MFVSRD MTVSRD
(define_insn_and_split "*mov<mode>_64bit_dm" (define_insn_and_split "*mov<mode>_64bit_dm"
[(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r,r,d") [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand"
(match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,<zero_fp>,r,<zero_fp>Y,r,d,r"))] "=m, d, d, d, Y,
r, r, r, r, d")
(match_operand:FMOVE128_FPR 1 "input_operand"
"d, m, d, <zero_fp>, r,
<zero_fp>, Y, r, d, r"))]
"TARGET_HARD_FLOAT && TARGET_POWERPC64 && FLOAT128_2REG_P (<MODE>mode) "TARGET_HARD_FLOAT && TARGET_POWERPC64 && FLOAT128_2REG_P (<MODE>mode)
&& (<MODE>mode != TDmode || WORDS_BIG_ENDIAN) && (<MODE>mode != TDmode || WORDS_BIG_ENDIAN)
&& (gpc_reg_operand (operands[0], <MODE>mode) && (gpc_reg_operand (operands[0], <MODE>mode)
...@@ -7724,8 +7774,8 @@ ...@@ -7724,8 +7774,8 @@
"&& reload_completed" "&& reload_completed"
[(pc)] [(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; } { rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "8,8,8,8,12,12,8,8,8") [(set_attr "length" "8")
(set_attr "isa" "*,*,*,*,*,*,*,p8v,p8v")]) (set_attr "isa" "*,*,*,*,*,*,*,*,p8v,p8v")])
(define_insn_and_split "*movtd_64bit_nodm" (define_insn_and_split "*movtd_64bit_nodm"
[(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r") [(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
...@@ -9874,6 +9924,28 @@ ...@@ -9874,6 +9924,28 @@
operands[6] = gen_rtx_PARALLEL (VOIDmode, p); operands[6] = gen_rtx_PARALLEL (VOIDmode, p);
}) })
;; Load up a PC-relative address. Print_operand_address will append a @pcrel
;; to the symbol or label.
(define_insn "*pcrel_local_addr"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(match_operand:DI 1 "pcrel_local_address"))]
"TARGET_PCREL"
"la %0,%a1"
[(set_attr "prefixed" "yes")])
;; Load up a PC-relative address to an external symbol. If the symbol and the
;; program are both defined in the main program, the linker will optimize this
;; to a PADDI. Otherwise, it will create a GOT address that is relocated by
;; the dynamic linker and loaded up. Print_operand_address will append a
;; @got@pcrel to the symbol.
(define_insn "*pcrel_extern_addr"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(match_operand:DI 1 "pcrel_external_address"))]
"TARGET_PCREL"
"ld %0,%a1"
[(set_attr "prefixed" "yes")
(set_attr "type" "load")])
;; TOC register handling. ;; TOC register handling.
;; Code to initialize the TOC register... ;; Code to initialize the TOC register...
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment