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
This commit is contained in:
Michael Meissner 2019-09-30 13:49:13 +00:00 committed by Michael Meissner
parent 61362d9d18
commit 26ca7d1b24
6 changed files with 631 additions and 153 deletions

View File

@ -1,3 +1,56 @@
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>
* gimple.c (gimple_get_lhs): For PHIs return the result.

View File

@ -1625,82 +1625,7 @@
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,28 @@
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")))

View File

@ -154,7 +154,66 @@ 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_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 */
#ifdef TREE_CODE
@ -234,8 +293,6 @@ extern void rs6000_d_target_versions (void);
const char * rs6000_xcoff_strip_dollar (const char *);
#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_hard_regno_nregs[][FIRST_PSEUDO_REGISTER];

View File

@ -9640,6 +9640,14 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode)
return;
}
/* Use the default pattern for loading up PC-relative addresses. */
if (TARGET_PCREL && mode == Pmode
&& pcrel_local_or_external_address (operands[1], Pmode))
{
emit_insn (gen_rtx_SET (operands[0], operands[1]));
return;
}
if (DEFAULT_ABI == ABI_V4
&& mode == Pmode && mode == SImode
&& flag_pic == 1 && got_operand (operands[1], mode))
@ -13082,8 +13090,8 @@ 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))
/* Is it a PC-relative address? */
else if (TARGET_PCREL && pcrel_local_or_external_address (x, VOIDmode))
{
HOST_WIDE_INT offset;
@ -13103,7 +13111,10 @@ print_operand_address (FILE *file, rtx x)
if (offset)
fprintf (file, "%+" PRId64, offset);
fputs ("@pcrel", file);
if (SYMBOL_REF_P (x) && !SYMBOL_REF_LOCAL_P (x))
fprintf (file, "@got");
fprintf (file, "@pcrel");
}
else if (SYMBOL_REF_P (x) || GET_CODE (x) == CONST
|| GET_CODE (x) == LABEL_REF)
@ -13588,71 +13599,6 @@ rs6000_pltseq_template (rtx *operands, int which)
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
@ -24617,6 +24563,385 @@ 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_FORMAT) is, return the instruction format
for the address. */
enum insn_form
address_to_insn_form (rtx addr,
machine_mode mode,
enum non_prefixed_form non_prefixed_format)
{
/* Single register is easy. */
if (REG_P (addr) || SUBREG_P (addr))
return INSN_FORM_BASE_REG;
/* If the non prefixed instruction format doesn't support offset addressing,
make sure only indexed addressing is allowed.
We special case SDmode so that the register allocator does not try to move
SDmode through GPR registers, but instead uses the 32-bit integer load and
store instructions for the floating point registers. */
if (non_prefixed_format == NON_PREFIXED_X || (mode == SDmode && TARGET_DFP))
{
if (GET_CODE (addr) != PLUS)
return INSN_FORM_BAD;
rtx op0 = XEXP (addr, 0);
rtx 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) && !SYMBOL_REF_LOCAL_P (addr))
return INSN_FORM_PCREL_EXTERNAL;
if (SYMBOL_REF_P (addr) || LABEL_REF_P (addr))
return INSN_FORM_PCREL_LOCAL;
}
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
/* Recognize LO_SUM addresses used with TOC and 32-bit addressing. */
if (GET_CODE (addr) == LO_SUM)
return INSN_FORM_LO_SUM;
/* Everything below must be an offset address of some form. */
if (GET_CODE (addr) != PLUS)
return INSN_FORM_BAD;
rtx op0 = XEXP (addr, 0);
rtx op1 = XEXP (addr, 1);
/* Check for indexed addresses. */
if (REG_P (op1) || SUBREG_P (op1))
{
if (REG_P (op0) || SUBREG_P (op0))
return INSN_FORM_X;
return INSN_FORM_BAD;
}
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) && !SYMBOL_REF_LOCAL_P (op0))
return INSN_FORM_PCREL_EXTERNAL;
if (SYMBOL_REF_P (op0) || LABEL_REF_P (op0))
return INSN_FORM_PCREL_LOCAL;
}
/* If it isn't PC-relative, the address must use a base register. */
if (!REG_P (op0) && !SUBREG_P (op0))
return INSN_FORM_BAD;
/* Large offsets must be prefixed. */
if (!SIGNED_16BIT_OFFSET_P (offset))
{
if (TARGET_PREFIXED_ADDR)
return INSN_FORM_PREFIXED_NUMERIC;
return INSN_FORM_BAD;
}
/* We have a 16-bit offset, see what default instruction format to use. */
if (non_prefixed_format == NON_PREFIXED_DEFAULT)
{
unsigned size = GET_MODE_SIZE (mode);
/* On 64-bit systems, assume 64-bit integers need to use DS form
addresses (for LD/STD). VSX vectors need to use DQ form addresses
(for LXV and STXV). TImode is problematical in that its normal usage
is expected to be GPRs where it wants a DS instruction format, but if
it goes into the vector registers, it wants a DQ instruction
format. */
if (TARGET_POWERPC64 && size >= 8 && GET_MODE_CLASS (mode) == MODE_INT)
non_prefixed_format = NON_PREFIXED_DS;
else if (TARGET_VSX && size >= 16
&& (VECTOR_MODE_P (mode) || FLOAT128_VECTOR_P (mode)))
non_prefixed_format = NON_PREFIXED_DQ;
else
non_prefixed_format = NON_PREFIXED_D;
}
/* Classify the D/DS/DQ-form addresses. */
switch (non_prefixed_format)
{
/* 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;
}
/* Helper function to take a REG and a MODE and turn it into the non-prefixed
instruction format (D/DS/DQ) used for offset memory. */
static enum non_prefixed_form
reg_to_non_prefixed (rtx reg, machine_mode mode)
{
/* If it isn't a register, use the defaults. */
if (!REG_P (reg) && !SUBREG_P (reg))
return NON_PREFIXED_DEFAULT;
unsigned int r = reg_or_subregno (reg);
/* If we have a pseudo, use the default instruction format. */
if (!HARD_REGISTER_NUM_P (r))
return NON_PREFIXED_DEFAULT;
unsigned size = GET_MODE_SIZE (mode);
/* FPR registers use D-mode for scalars, and DQ-mode for vectors, IEEE
128-bit floating point, and 128-bit integers. */
if (FP_REGNO_P (r))
{
if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode))
return NON_PREFIXED_D;
else if (size < 8)
return NON_PREFIXED_X;
else if (TARGET_VSX && size >= 16
&& (VECTOR_MODE_P (mode)
|| FLOAT128_VECTOR_P (mode)
|| mode == TImode || mode == CTImode))
return NON_PREFIXED_DQ;
else
return NON_PREFIXED_DEFAULT;
}
/* Altivec registers use DS-mode for scalars, and DQ-mode for vectors, IEEE
128-bit floating point, and 128-bit integers. */
else if (ALTIVEC_REGNO_P (r))
{
if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode))
return NON_PREFIXED_DS;
else if (size < 8)
return NON_PREFIXED_X;
else if (TARGET_VSX && size >= 16
&& (VECTOR_MODE_P (mode)
|| FLOAT128_VECTOR_P (mode)
|| mode == TImode || mode == CTImode))
return NON_PREFIXED_DQ;
else
return NON_PREFIXED_DEFAULT;
}
/* GPR registers use DS-mode for 64-bit items on 64-bit systems, and D-mode
otherwise. Assume that any other register, such as LR, CRs, etc. will go
through the GPR registers for memory operations. */
else if (TARGET_POWERPC64 && size >= 8)
return NON_PREFIXED_DS;
return NON_PREFIXED_D;
}
/* Whether a load instruction is a prefixed instruction. This is called from
the prefixed attribute processing. */
bool
prefixed_load_p (rtx_insn *insn)
{
/* Validate the insn to make sure it is a normal load insn. */
extract_insn_cached (insn);
if (recog_data.n_operands < 2)
return false;
rtx reg = recog_data.operand[0];
rtx mem = recog_data.operand[1];
if (!REG_P (reg) && !SUBREG_P (reg))
return false;
if (!MEM_P (mem))
return false;
/* Prefixed load instructions do not support update or indexed forms. */
if (get_attr_indexed (insn) == INDEXED_YES
|| get_attr_update (insn) == UPDATE_YES)
return false;
/* LWA uses the DS format instead of the D format that LWZ uses. */
enum non_prefixed_form non_prefixed;
machine_mode reg_mode = GET_MODE (reg);
machine_mode mem_mode = GET_MODE (mem);
if (mem_mode == SImode && reg_mode == DImode
&& get_attr_sign_extend (insn) == SIGN_EXTEND_YES)
non_prefixed = NON_PREFIXED_DS;
else
non_prefixed = reg_to_non_prefixed (reg, mem_mode);
return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed);
}
/* Whether a store instruction is a prefixed instruction. This is called from
the prefixed attribute processing. */
bool
prefixed_store_p (rtx_insn *insn)
{
/* Validate the insn to make sure it is a normal store insn. */
extract_insn_cached (insn);
if (recog_data.n_operands < 2)
return false;
rtx mem = recog_data.operand[0];
rtx reg = recog_data.operand[1];
if (!REG_P (reg) && !SUBREG_P (reg))
return false;
if (!MEM_P (mem))
return false;
/* Prefixed store instructions do not support update or indexed forms. */
if (get_attr_indexed (insn) == INDEXED_YES
|| get_attr_update (insn) == UPDATE_YES)
return false;
machine_mode mem_mode = GET_MODE (mem);
enum non_prefixed_form non_prefixed = reg_to_non_prefixed (reg, mem_mode);
return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed);
}
/* Whether a load immediate or add instruction is a prefixed instruction. This
is called from the prefixed attribute processing. */
bool
prefixed_paddi_p (rtx_insn *insn)
{
rtx set = single_set (insn);
if (!set)
return false;
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
if (!REG_P (dest) && !SUBREG_P (dest))
return false;
/* Is this a load immediate that can't be done with a simple ADDI or
ADDIS? */
if (CONST_INT_P (src))
return (satisfies_constraint_eI (src)
&& !satisfies_constraint_I (src)
&& !satisfies_constraint_L (src));
/* Is this a PADDI instruction that can't be done with a simple ADDI or
ADDIS? */
if (GET_CODE (src) == PLUS)
{
rtx op1 = XEXP (src, 1);
return (CONST_INT_P (op1)
&& satisfies_constraint_eI (op1)
&& !satisfies_constraint_I (op1)
&& !satisfies_constraint_L (op1));
}
/* If not, is it a load of a PC-relative address? */
if (!TARGET_PCREL || GET_MODE (dest) != Pmode)
return false;
if (!SYMBOL_REF_P (src) && !LABEL_REF_P (src) && GET_CODE (src) != CONST)
return false;
enum insn_form iform = address_to_insn_form (src, Pmode,
NON_PREFIXED_DEFAULT);
return (iform == INSN_FORM_PCREL_EXTERNAL || iform == INSN_FORM_PCREL_LOCAL);
}
/* Whether the next instruction needs a 'p' prefix issued before the
instruction is printed out. */
static bool next_insn_prefixed_p;
/* Define FINAL_PRESCAN_INSN if some processing needs to be done before
outputting the assembler code. On the PowerPC, we remember if the current
insn is a prefixed insn where we need to emit a 'p' before the insn.
In addition, if the insn is part of a PC-relative reference to an external
label optimization, this is recorded also. */
void
rs6000_final_prescan_insn (rtx_insn *insn, rtx [], int)
{
next_insn_prefixed_p = (get_attr_prefixed (insn) != PREFIXED_NO);
return;
}
/* Define ASM_OUTPUT_OPCODE to do anything special before emitting an opcode.
We use it to emit a 'p' for prefixed insns that is set in
FINAL_PRESCAN_INSN. */
void
rs6000_asm_output_opcode (FILE *stream)
{
if (next_insn_prefixed_p)
fprintf (stream, "p");
return;
}
#ifdef HAVE_GAS_HIDDEN
# define USE_HIDDEN_LINKONCE 1
#else

View File

@ -2547,3 +2547,24 @@ typedef struct GTY(()) machine_function
IN_RANGE ((VALUE), \
-(HOST_WIDE_INT_1 << 33), \
(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)

View File

@ -256,8 +256,49 @@
;; Is copying of this instruction disallowed?
(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
;; enumeration in rs6000-opts.h.
@ -7713,9 +7754,18 @@
;; not swapped like they are for TImode or TFmode. Subregs therefore are
;; 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"
[(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r,r,d")
(match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,<zero_fp>,r,<zero_fp>Y,r,d,r"))]
[(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand"
"=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)
&& (<MODE>mode != TDmode || WORDS_BIG_ENDIAN)
&& (gpc_reg_operand (operands[0], <MODE>mode)
@ -7724,8 +7774,8 @@
"&& reload_completed"
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "8,8,8,8,12,12,8,8,8")
(set_attr "isa" "*,*,*,*,*,*,*,p8v,p8v")])
[(set_attr "length" "8")
(set_attr "isa" "*,*,*,*,*,*,*,*,p8v,p8v")])
(define_insn_and_split "*movtd_64bit_nodm"
[(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
@ -9874,6 +9924,28 @@
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.
;; Code to initialize the TOC register...