Commit 201312c2 by Richard Henderson Committed by Richard Henderson

Makefile.in (insn-preds.o): Depend on TREE_H.

        * Makefile.in (insn-preds.o): Depend on TREE_H.
        * genpreds.c (write_insn_preds_c): Include tree.h.
        * config/alpha/alpha.c (reg_or_0_operand, reg_or_6bit_operand,
        reg_or_8bit_operand, cint8_operand, add_operand, sext_add_operand,
        const48_operand, and_operand, or_operand, mode_width_operand,
        mode_mask_operand, mul8_operand, const0_operand,
        hard_fp_register_operand, hard_int_register_operand,
        reg_or_cint_operand, some_operand, some_ni_operand, input_operand,
        samegp_function_operand, direct_call_operand, small_symbolic_operand,
        global_symbolic_operand, call_operand, symbolic_operand,
        dtp16_symbolic_operand, dtp32_symbolic_operand,
        gotdtp_symbolic_operand, tp16_symbolic_operand, tp32_symbolic_operand,
        gottp_symbolic_operand, alpha_comparison_operator,
        alpha_zero_comparison_operator, alpha_swapped_comparison_operator,
        signed_comparison_operator, alpha_fp_comparison_operator,
        divmod_operator, fix_operator, aligned_memory_operand,
        unaligned_memory_operand, reg_or_unaligned_mem_operand,
        any_memory_operand, reg_not_elim_operand, normal_memory_operand,
        reg_no_subreg_operand, addition_operation): Move to predicates.md.
        (reg_or_const_int_operand): Remove.  Replace all users with
        reg_or_cint_operand.
        (tls_symbolic_operand_1): Export.  Don't check mode or for CONST.
        (resolve_reload_operand): Split out of aligned_memory_operand.
        * config/alpha/alpha-protos.h: Update for exports.
        * config/alpha/alpha.h (PREDICATE_CODES): Remove.
        * config/alpha/alpha.md: Include predicates.md.
        * config/alpha/predicates.md: New file.

From-SVN: r85953
parent 73389fa4
2004-08-13 Richard Henderson <rth@redhat.com>
* Makefile.in (insn-preds.o): Depend on TREE_H.
* genpreds.c (write_insn_preds_c): Include tree.h.
* config/alpha/alpha.c (reg_or_0_operand, reg_or_6bit_operand,
reg_or_8bit_operand, cint8_operand, add_operand, sext_add_operand,
const48_operand, and_operand, or_operand, mode_width_operand,
mode_mask_operand, mul8_operand, const0_operand,
hard_fp_register_operand, hard_int_register_operand,
reg_or_cint_operand, some_operand, some_ni_operand, input_operand,
samegp_function_operand, direct_call_operand, small_symbolic_operand,
global_symbolic_operand, call_operand, symbolic_operand,
dtp16_symbolic_operand, dtp32_symbolic_operand,
gotdtp_symbolic_operand, tp16_symbolic_operand, tp32_symbolic_operand,
gottp_symbolic_operand, alpha_comparison_operator,
alpha_zero_comparison_operator, alpha_swapped_comparison_operator,
signed_comparison_operator, alpha_fp_comparison_operator,
divmod_operator, fix_operator, aligned_memory_operand,
unaligned_memory_operand, reg_or_unaligned_mem_operand,
any_memory_operand, reg_not_elim_operand, normal_memory_operand,
reg_no_subreg_operand, addition_operation): Move to predicates.md.
(reg_or_const_int_operand): Remove. Replace all users with
reg_or_cint_operand.
(tls_symbolic_operand_1): Export. Don't check mode or for CONST.
(resolve_reload_operand): Split out of aligned_memory_operand.
* config/alpha/alpha-protos.h: Update for exports.
* config/alpha/alpha.h (PREDICATE_CODES): Remove.
* config/alpha/alpha.md: Include predicates.md.
* config/alpha/predicates.md: New file.
2004-08-13 Richard Sandiford <rsandifo@redhat.com> 2004-08-13 Richard Sandiford <rsandifo@redhat.com>
* genattrtab.c (insn_ent): Replace insn_code, insn_index and lineno * genattrtab.c (insn_ent): Replace insn_code, insn_index and lineno
......
...@@ -2350,8 +2350,8 @@ s-preds: $(md_file) genpreds$(build_exeext) ...@@ -2350,8 +2350,8 @@ s-preds: $(md_file) genpreds$(build_exeext)
$(STAMP) s-preds $(STAMP) s-preds
insn-preds.o : insn-preds.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ insn-preds.o : insn-preds.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) insn-config.h $(RECOG_H) real.h output.h $(FLAGS_H) function.h \ $(RTL_H) $(TREE_H) insn-config.h $(RECOG_H) real.h output.h $(FLAGS_H) \
hard-reg-set.h $(RESOURCE_H) $(TM_P_H) toplev.h reload.h function.h hard-reg-set.h $(RESOURCE_H) $(TM_P_H) toplev.h reload.h
GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
$(CPP_ID_DATA_H) $(host_xm_file_list) \ $(CPP_ID_DATA_H) $(host_xm_file_list) \
......
...@@ -121,3 +121,7 @@ extern char * unicosmk_data_section (void); ...@@ -121,3 +121,7 @@ extern char * unicosmk_data_section (void);
extern void unicosmk_output_common (FILE *, const char *, int, int); extern void unicosmk_output_common (FILE *, const char *, int, int);
extern int unicosmk_initial_elimination_offset (int, int); extern int unicosmk_initial_elimination_offset (int, int);
#endif #endif
extern int some_small_symbolic_operand (rtx, enum machine_mode);
extern int tls_symbolic_operand_1 (rtx, int, int);
extern rtx resolve_reload_operand (rtx);
...@@ -519,527 +519,12 @@ zap_mask (HOST_WIDE_INT value) ...@@ -519,527 +519,12 @@ zap_mask (HOST_WIDE_INT value)
return 1; return 1;
} }
/* Returns 1 if OP is either the constant zero or a register. If a /* Return true if OP is valid for a particular TLS relocation.
register, it must be in the proper mode unless MODE is VOIDmode. */ We are already guaranteed that OP is a CONST. */
int int
reg_or_0_operand (rtx op, enum machine_mode mode) tls_symbolic_operand_1 (rtx op, int size, int unspec)
{ {
return op == CONST0_RTX (mode) || register_operand (op, mode);
}
/* Return 1 if OP is a constant in the range of 0-63 (for a shift) or
any register. */
int
reg_or_6bit_operand (rtx op, enum machine_mode mode)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 64)
|| register_operand (op, mode));
}
/* Return 1 if OP is an 8-bit constant or any register. */
int
reg_or_8bit_operand (rtx op, enum machine_mode mode)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
|| register_operand (op, mode));
}
/* Return 1 if OP is a constant or any register. */
int
reg_or_const_int_operand (rtx op, enum machine_mode mode)
{
return GET_CODE (op) == CONST_INT || register_operand (op, mode);
}
/* Return 1 if OP is an 8-bit constant. */
int
cint8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100));
}
/* Return 1 if the operand is a valid second operand to an add insn. */
int
add_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
/* Constraints I, J, O and P are covered by K. */
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
return register_operand (op, mode);
}
/* Return 1 if the operand is a valid second operand to a sign-extending
add insn. */
int
sext_add_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
return reg_not_elim_operand (op, mode);
}
/* Return 1 if OP is the constant 4 or 8. */
int
const48_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 4 || INTVAL (op) == 8));
}
/* Return 1 if OP is a valid first operand to an AND insn. */
int
and_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
return (zap_mask (CONST_DOUBLE_LOW (op))
&& zap_mask (CONST_DOUBLE_HIGH (op)));
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
|| zap_mask (INTVAL (op)));
return register_operand (op, mode);
}
/* Return 1 if OP is a valid first operand to an IOR or XOR insn. */
int
or_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100);
return register_operand (op, mode);
}
/* Return 1 if OP is a constant that is the width, in bits, of an integral
mode smaller than DImode. */
int
mode_width_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 8 || INTVAL (op) == 16
|| INTVAL (op) == 32 || INTVAL (op) == 64));
}
/* Return 1 if OP is a constant that is the width of an integral machine mode
smaller than an integer. */
int
mode_mask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op);
if (value == 0xff)
return 1;
if (value == 0xffff)
return 1;
if (value == 0xffffffff)
return 1;
if (value == -1)
return 1;
}
else if (HOST_BITS_PER_WIDE_INT == 32 && GET_CODE (op) == CONST_DOUBLE)
{
if (CONST_DOUBLE_LOW (op) == 0xffffffff && CONST_DOUBLE_HIGH (op) == 0)
return 1;
}
return 0;
}
/* Return 1 if OP is a multiple of 8 less than 64. */
int
mul8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 64
&& (INTVAL (op) & 7) == 0);
}
/* Return 1 if OP is the zero constant for MODE. */
int
const0_operand (rtx op, enum machine_mode mode)
{
return op == CONST0_RTX (mode);
}
/* Return 1 if OP is a hard floating-point register. */
int
hard_fp_register_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS;
}
/* Return 1 if OP is a hard general register. */
int
hard_int_register_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS;
}
/* Return 1 if OP is a register or a constant integer. */
int
reg_or_cint_operand (rtx op, enum machine_mode mode)
{
return (GET_CODE (op) == CONST_INT
|| register_operand (op, mode));
}
/* Return 1 if OP is something that can be reloaded into a register;
if it is a MEM, it need not be valid. */
int
some_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
switch (GET_CODE (op))
{
case REG:
case MEM:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case LABEL_REF:
case SYMBOL_REF:
case CONST:
case HIGH:
return 1;
case SUBREG:
return some_operand (SUBREG_REG (op), VOIDmode);
default:
break;
}
return 0;
}
/* Likewise, but don't accept constants. */
int
some_ni_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return (GET_CODE (op) == REG || GET_CODE (op) == MEM);
}
/* Return 1 if OP is a valid operand for the source of a move insn. */
int
input_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode)
return 0;
switch (GET_CODE (op))
{
case LABEL_REF:
case SYMBOL_REF:
case CONST:
if (TARGET_EXPLICIT_RELOCS)
{
/* We don't split symbolic operands into something unintelligable
until after reload, but we do not wish non-small, non-global
symbolic operands to be reconstructed from their high/lo_sum
form. */
return (small_symbolic_operand (op, mode)
|| global_symbolic_operand (op, mode)
|| gotdtp_symbolic_operand (op, mode)
|| gottp_symbolic_operand (op, mode));
}
/* This handles both the Windows/NT and OSF cases. */
return mode == ptr_mode || mode == DImode;
case HIGH:
return (TARGET_EXPLICIT_RELOCS
&& local_symbolic_operand (XEXP (op, 0), mode));
case REG:
return 1;
case SUBREG:
if (register_operand (op, mode))
return 1;
/* ... fall through ... */
case MEM:
return ((TARGET_BWX || (mode != HImode && mode != QImode))
&& general_operand (op, mode));
case CONST_DOUBLE:
case CONST_VECTOR:
return op == CONST0_RTX (mode);
case CONST_INT:
return mode == QImode || mode == HImode || add_operand (op, mode);
default:
break;
}
return 0;
}
/* Return 1 if OP is a SYMBOL_REF for a function known to be in this
file, and in the same section as the current function. */
int
samegp_function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != SYMBOL_REF)
return false;
/* Easy test for recursion. */
if (op == XEXP (DECL_RTL (current_function_decl), 0))
return true;
/* Functions that are not local can be overridden, and thus may
not share the same gp. */
if (! SYMBOL_REF_LOCAL_P (op))
return false;
/* If -msmall-data is in effect, assume that there is only one GP
for the module, and so any local symbol has this property. We
need explicit relocations to be able to enforce this for symbols
not defined in this unit of translation, however. */
if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
return true;
/* Functions that are not external are defined in this UoT,
and thus must share the same gp. */
return ! SYMBOL_REF_EXTERNAL_P (op);
}
/* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr. */
int
direct_call_operand (rtx op, enum machine_mode mode)
{
tree op_decl, cfun_sec, op_sec;
/* Must share the same GP. */
if (!samegp_function_operand (op, mode))
return false;
/* If profiling is implemented via linker tricks, we can't jump
to the nogp alternate entry point. Note that current_function_profile
would not be correct, since that doesn't indicate if the target
function uses profiling. */
/* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
but is approximately correct for the OSF ABIs. Don't know
what to do for VMS, NT, or UMK. */
if (!TARGET_PROFILING_NEEDS_GP && profile_flag)
return false;
/* Must be a function. In some cases folks create thunks in static
data structures and then make calls to them. If we allow the
direct call, we'll get an error from the linker about !samegp reloc
against a symbol without a .prologue directive. */
if (!SYMBOL_REF_FUNCTION_P (op))
return false;
/* Must be "near" so that the branch is assumed to reach. With
-msmall-text, this is assumed true of all local symbols. Since
we've already checked samegp, locality is already assured. */
if (TARGET_SMALL_TEXT)
return true;
/* Otherwise, a decl is "near" if it is defined in the same section. */
if (flag_function_sections)
return false;
op_decl = SYMBOL_REF_DECL (op);
if (DECL_ONE_ONLY (current_function_decl)
|| (op_decl && DECL_ONE_ONLY (op_decl)))
return false;
cfun_sec = DECL_SECTION_NAME (current_function_decl);
op_sec = op_decl ? DECL_SECTION_NAME (op_decl) : NULL;
return ((!cfun_sec && !op_sec)
|| (cfun_sec && op_sec
&& strcmp (TREE_STRING_POINTER (cfun_sec),
TREE_STRING_POINTER (op_sec)) == 0));
}
/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
a (non-tls) variable known to be defined in this file. */
int
local_symbolic_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == LABEL_REF)
return 1;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
}
/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
known to be defined in this file in the small data area. */
int
small_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (! TARGET_SMALL_DATA)
return 0;
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
/* ??? There's no encode_section_info equivalent for the rtl
constant pool, so SYMBOL_FLAG_SMALL never gets set. */
if (CONSTANT_POOL_ADDRESS_P (op))
return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value;
return (SYMBOL_REF_LOCAL_P (op)
&& SYMBOL_REF_SMALL_P (op)
&& SYMBOL_REF_TLS_MODEL (op) == 0);
}
/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
not known (or known not) to be defined in this file. */
int
global_symbolic_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
return !SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
}
/* Return 1 if OP is a valid operand for the MEM of a CALL insn. */
int
call_operand (rtx op, enum machine_mode mode)
{
if (mode != Pmode)
return 0;
if (GET_CODE (op) == REG)
{
if (TARGET_ABI_OSF)
{
/* Disallow virtual registers to cope with pathological test cases
such as compile/930117-1.c in which the virtual reg decomposes
to the frame pointer. Which is a hard reg that is not $27. */
return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER);
}
else
return 1;
}
if (TARGET_ABI_UNICOSMK)
return 0;
if (GET_CODE (op) == SYMBOL_REF)
return 1;
return 0;
}
/* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
possibly with an offset. */
int
symbolic_operand (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
return 1;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op,0)) == PLUS
&& GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT)
return 1;
return 0;
}
/* Return true if OP is valid for a particular TLS relocation. */
static int
tls_symbolic_operand_1 (rtx op, enum machine_mode mode, int size, int unspec)
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) != CONST)
return 0;
op = XEXP (op, 0); op = XEXP (op, 0);
if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec) if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec)
...@@ -1073,203 +558,12 @@ tls_symbolic_operand_1 (rtx op, enum machine_mode mode, int size, int unspec) ...@@ -1073,203 +558,12 @@ tls_symbolic_operand_1 (rtx op, enum machine_mode mode, int size, int unspec)
} }
} }
/* Return true if OP is valid for 16-bit DTP relative relocations. */ /* Used by aligned_memory_operand and unaligned_memory_operand to
resolve what reload is going to do with OP if it's a register. */
int
dtp16_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_DTPREL);
}
/* Return true if OP is valid for 32-bit DTP relative relocations. */
int
dtp32_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_DTPREL);
}
/* Return true if OP is valid for 64-bit DTP relative relocations. */
int
gotdtp_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_DTPREL);
}
/* Return true if OP is valid for 16-bit TP relative relocations. */
int
tp16_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_TPREL);
}
/* Return true if OP is valid for 32-bit TP relative relocations. */
int
tp32_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_TPREL);
}
/* Return true if OP is valid for 64-bit TP relative relocations. */
int
gottp_symbolic_operand (rtx op, enum machine_mode mode)
{
return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_TPREL);
}
/* Return 1 if OP is a valid Alpha comparison operator. Here we know which
comparisons are valid in which insn. */
int
alpha_comparison_operator (rtx op, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == LE || code == LT
|| code == LEU || code == LTU);
}
/* Return 1 if OP is a valid Alpha comparison operator against zero.
Here we know which comparisons are valid in which insn. */
int
alpha_zero_comparison_operator (rtx op, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == NE || code == LE || code == LT
|| code == LEU || code == LTU);
}
/* Return 1 if OP is a valid Alpha swapped comparison operator. */
int
alpha_swapped_comparison_operator (rtx op, enum machine_mode mode)
{
enum rtx_code code;
if ((mode != GET_MODE (op) && mode != VOIDmode)
|| !COMPARISON_P (op))
return 0;
code = swap_condition (GET_CODE (op));
return (code == EQ || code == LE || code == LT
|| code == LEU || code == LTU);
}
/* Return 1 if OP is a signed comparison operation. */
int
signed_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == NE
|| code == LE || code == LT
|| code == GE || code == GT);
}
/* Return 1 if OP is a valid Alpha floating point comparison operator.
Here we know which comparisons are valid in which insn. */
int
alpha_fp_comparison_operator (rtx op, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == LE || code == LT || code == UNORDERED);
}
/* Return 1 if this is a divide or modulus operator. */
int
divmod_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (op);
return (code == DIV || code == MOD || code == UDIV || code == UMOD);
}
/* Return 1 if this is a float->int conversion operator. */
int
fix_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (op);
return (code == FIX || code == UNSIGNED_FIX);
}
/* Return 1 if this memory address is a known aligned register plus
a constant. It must be a valid address. This means that we can do
this as an aligned reference plus some offset.
Take into account what reload will do. */
int
aligned_memory_operand (rtx op, enum machine_mode mode)
{
rtx base;
if (reload_in_progress)
{
rtx tmp = op;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
{
op = reg_equiv_memory_loc[REGNO (tmp)];
if (op == 0)
return 0;
}
}
if (GET_CODE (op) != MEM)
return 0;
if (MEM_ALIGN (op) >= 32)
return 1;
op = XEXP (op, 0);
/* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
sorts of constructs. Dig for the real base register. */
if (reload_in_progress
&& GET_CODE (op) == PLUS
&& GET_CODE (XEXP (op, 0)) == PLUS)
base = XEXP (XEXP (op, 0), 0);
else
{
if (! memory_address_p (mode, op))
return 0;
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) >= 32);
}
/* Similar, but return 1 if OP is a MEM which is not alignable. */
int rtx
unaligned_memory_operand (rtx op, enum machine_mode mode) resolve_reload_operand (rtx op)
{ {
rtx base;
if (reload_in_progress) if (reload_in_progress)
{ {
rtx tmp = op; rtx tmp = op;
...@@ -1283,128 +577,7 @@ unaligned_memory_operand (rtx op, enum machine_mode mode) ...@@ -1283,128 +577,7 @@ unaligned_memory_operand (rtx op, enum machine_mode mode)
return 0; return 0;
} }
} }
return op;
if (GET_CODE (op) != MEM)
return 0;
if (MEM_ALIGN (op) >= 32)
return 0;
op = XEXP (op, 0);
/* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
sorts of constructs. Dig for the real base register. */
if (reload_in_progress
&& GET_CODE (op) == PLUS
&& GET_CODE (XEXP (op, 0)) == PLUS)
base = XEXP (XEXP (op, 0), 0);
else
{
if (! memory_address_p (mode, op))
return 0;
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) < 32);
}
/* Return 1 if OP is either a register or an unaligned memory location. */
int
reg_or_unaligned_mem_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || unaligned_memory_operand (op, mode);
}
/* Return 1 if OP is any memory location. During reload a pseudo matches. */
int
any_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == MEM
|| (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
|| (reload_in_progress && GET_CODE (op) == REG
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)
|| (reload_in_progress && GET_CODE (op) == SUBREG
&& GET_CODE (SUBREG_REG (op)) == REG
&& REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));
}
/* Returns 1 if OP is not an eliminable register.
This exists to cure a pathological abort in the s8addq (et al) patterns,
long foo () { long t; bar(); return (long) &t * 26107; }
which run afoul of a hack in reload to cure a (presumably) similar
problem with lea-type instructions on other targets. But there is
one of us and many of them, so work around the problem by selectively
preventing combine from making the optimization. */
int
reg_not_elim_operand (rtx op, enum machine_mode mode)
{
rtx inner = op;
if (GET_CODE (op) == SUBREG)
inner = SUBREG_REG (op);
if (inner == frame_pointer_rtx || inner == arg_pointer_rtx)
return 0;
return register_operand (op, mode);
}
/* Return 1 is OP is a memory location that is not a reference (using
an AND) to an unaligned location. Take into account what reload
will do. */
int
normal_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (reload_in_progress)
{
rtx tmp = op;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
{
op = reg_equiv_memory_loc[REGNO (tmp)];
/* This may not have been assigned an equivalent address if it will
be eliminated. In that case, it doesn't matter what we do. */
if (op == 0)
return 1;
}
}
return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) != AND;
}
/* Accept a register, but not a subreg of any kind. This allows us to
avoid pathological cases in reload wrt data movement common in
int->fp conversion. */
int
reg_no_subreg_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != REG)
return 0;
return register_operand (op, mode);
}
/* Recognize an addition operation that includes a constant. Used to
convince reload to canonize (plus (plus reg c1) c2) during register
elimination. */
int
addition_operation (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
if (GET_CODE (op) == PLUS
&& register_operand (XEXP (op, 0), mode)
&& GET_CODE (XEXP (op, 1)) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K'))
return 1;
return 0;
} }
/* Implements CONST_OK_FOR_LETTER_P. Return true if the value matches /* Implements CONST_OK_FOR_LETTER_P. Return true if the value matches
...@@ -1984,6 +1157,10 @@ alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) ...@@ -1984,6 +1157,10 @@ alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
small symbolic operand until after reload. At which point we need small symbolic operand until after reload. At which point we need
to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref)) to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref))
so that sched2 has the proper dependency information. */ so that sched2 has the proper dependency information. */
/*
{"some_small_symbolic_operand", {SET, PARALLEL, PREFETCH, UNSPEC, \
UNSPEC_VOLATILE}},
*/
static int static int
some_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED) some_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
......
...@@ -1609,68 +1609,11 @@ do { \ ...@@ -1609,68 +1609,11 @@ do { \
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ #define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
((CODE) == '/' || (CODE) == ',' || (CODE) == '-' || (CODE) == '~' \ ((CODE) == '/' || (CODE) == ',' || (CODE) == '-' || (CODE) == '~' \
|| (CODE) == '#' || (CODE) == '*' || (CODE) == '&' || (CODE) == '+') || (CODE) == '#' || (CODE) == '*' || (CODE) == '&' || (CODE) == '+')
/* Print a memory address as an operand to reference that memory location. */ /* Print a memory address as an operand to reference that memory location. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
print_operand_address((FILE), (ADDR)) print_operand_address((FILE), (ADDR))
/* Define the codes that are matched by predicates in alpha.c. */
#define PREDICATE_CODES \
{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, \
CONST_VECTOR}}, \
{"reg_or_6bit_operand", {SUBREG, REG, CONST_INT}}, \
{"reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \
{"reg_or_const_int_operand", {SUBREG, REG, CONST_INT}}, \
{"cint8_operand", {CONST_INT}}, \
{"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, \
{"add_operand", {SUBREG, REG, CONST_INT}}, \
{"sext_add_operand", {SUBREG, REG, CONST_INT}}, \
{"const48_operand", {CONST_INT}}, \
{"and_operand", {SUBREG, REG, CONST_INT}}, \
{"or_operand", {SUBREG, REG, CONST_INT}}, \
{"mode_mask_operand", {CONST_INT}}, \
{"mul8_operand", {CONST_INT}}, \
{"mode_width_operand", {CONST_INT}}, \
{"alpha_comparison_operator", {EQ, LE, LT, LEU, LTU}}, \
{"alpha_zero_comparison_operator", {EQ, NE, LE, LT, LEU, LTU}}, \
{"alpha_swapped_comparison_operator", {EQ, GE, GT, GEU, GTU}}, \
{"signed_comparison_operator", {EQ, NE, LE, LT, GE, GT}}, \
{"alpha_fp_comparison_operator", {EQ, LE, LT, UNORDERED}}, \
{"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
{"fix_operator", {FIX, UNSIGNED_FIX}}, \
{"const0_operand", {CONST_INT, CONST_DOUBLE, CONST_VECTOR}}, \
{"samegp_function_operand", {SYMBOL_REF}}, \
{"direct_call_operand", {SYMBOL_REF}}, \
{"local_symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \
{"small_symbolic_operand", {SYMBOL_REF, CONST}}, \
{"global_symbolic_operand", {SYMBOL_REF, CONST}}, \
{"dtp16_symbolic_operand", {CONST}}, \
{"dtp32_symbolic_operand", {CONST}}, \
{"gotdtp_symbolic_operand", {CONST}}, \
{"tp16_symbolic_operand", {CONST}}, \
{"tp32_symbolic_operand", {CONST}}, \
{"gottp_symbolic_operand", {CONST}}, \
{"call_operand", {REG, SYMBOL_REF}}, \
{"input_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
CONST_VECTOR, SYMBOL_REF, CONST, LABEL_REF, HIGH}},\
{"some_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
CONST_VECTOR, SYMBOL_REF, CONST, LABEL_REF, HIGH}}, \
{"some_ni_operand", {SUBREG, REG, MEM}}, \
{"aligned_memory_operand", {MEM}}, \
{"unaligned_memory_operand", {MEM}}, \
{"reg_or_unaligned_mem_operand", {SUBREG, REG, MEM}}, \
{"any_memory_operand", {MEM}}, \
{"normal_memory_operand", {MEM}}, \
{"hard_fp_register_operand", {SUBREG, REG}}, \
{"hard_int_register_operand", {SUBREG, REG}}, \
{"reg_not_elim_operand", {SUBREG, REG}}, \
{"reg_no_subreg_operand", {REG}}, \
{"addition_operation", {PLUS}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"some_small_symbolic_operand", {SET, PARALLEL, PREFETCH, UNSPEC, \
UNSPEC_VOLATILE}},
/* Implement `va_start' for varargs and stdarg. */ /* Implement `va_start' for varargs and stdarg. */
#define EXPAND_BUILTIN_VA_START(valist, nextarg) \ #define EXPAND_BUILTIN_VA_START(valist, nextarg) \
......
...@@ -168,6 +168,12 @@ ...@@ -168,6 +168,12 @@
(include "ev4.md") (include "ev4.md")
(include "ev5.md") (include "ev5.md")
(include "ev6.md") (include "ev6.md")
;; Include predicate definitions
(include "predicates.md")
;; First define the arithmetic insns. Note that the 32-bit forms also ;; First define the arithmetic insns. Note that the 32-bit forms also
;; sign-extend. ;; sign-extend.
...@@ -7378,9 +7384,9 @@ ...@@ -7378,9 +7384,9 @@
(define_expand "builtin_zap" (define_expand "builtin_zap"
[(set (match_operand:DI 0 "register_operand" "") [(set (match_operand:DI 0 "register_operand" "")
(and:DI (unspec:DI (and:DI (unspec:DI
[(match_operand:DI 2 "reg_or_const_int_operand" "")] [(match_operand:DI 2 "reg_or_cint_operand" "")]
UNSPEC_ZAP) UNSPEC_ZAP)
(match_operand:DI 1 "reg_or_const_int_operand" "")))] (match_operand:DI 1 "reg_or_cint_operand" "")))]
"" ""
{ {
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
...@@ -7410,9 +7416,9 @@ ...@@ -7410,9 +7416,9 @@
(define_insn "*builtin_zap_1" (define_insn "*builtin_zap_1"
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r") [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
(and:DI (unspec:DI (and:DI (unspec:DI
[(match_operand:QI 2 "reg_or_const_int_operand" "n,n,r,r")] [(match_operand:QI 2 "reg_or_cint_operand" "n,n,r,r")]
UNSPEC_ZAP) UNSPEC_ZAP)
(match_operand:DI 1 "reg_or_const_int_operand" "n,r,J,r")))] (match_operand:DI 1 "reg_or_cint_operand" "n,r,J,r")))]
"" ""
"@ "@
# #
...@@ -7471,9 +7477,9 @@ ...@@ -7471,9 +7477,9 @@
(define_expand "builtin_zapnot" (define_expand "builtin_zapnot"
[(set (match_operand:DI 0 "register_operand" "") [(set (match_operand:DI 0 "register_operand" "")
(and:DI (unspec:DI (and:DI (unspec:DI
[(not:QI (match_operand:DI 2 "reg_or_const_int_operand" ""))] [(not:QI (match_operand:DI 2 "reg_or_cint_operand" ""))]
UNSPEC_ZAP) UNSPEC_ZAP)
(match_operand:DI 1 "reg_or_const_int_operand" "")))] (match_operand:DI 1 "reg_or_cint_operand" "")))]
"" ""
{ {
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
......
;; Predicate definitions for DEC Alpha.
;; Copyright (C) 2004 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;; Return 1 if OP is the zero constant for MODE.
(define_predicate "const0_operand"
(and (match_code "const_int,const_double,const_vector")
(match_test "op == CONST0_RTX (mode)")))
;; Returns true if OP is either the constant zero or a register.
(define_predicate "reg_or_0_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "const0_operand")))
;; Return 1 if OP is a constant in the range of 0-63 (for a shift) or
;; any register.
(define_predicate "reg_or_6bit_operand"
(if_then_else (match_code "const_int")
(match_test "INTVAL (op) >= 0 && INTVAL (op) < 64")
(match_operand 0 "register_operand")))
;; Return 1 if OP is an 8-bit constant.
(define_predicate "cint8_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) >= 0 && INTVAL (op) < 256")))
;; Return 1 if OP is an 8-bit constant or any register.
(define_predicate "reg_or_8bit_operand"
(if_then_else (match_code "const_int")
(match_test "INTVAL (op) >= 0 && INTVAL (op) < 256")
(match_operand 0 "register_operand")))
;; Return 1 if OP is a constant or any register.
(define_predicate "reg_or_cint_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "const_int_operand")))
;; Return 1 if the operand is a valid second operand to an add insn.
(define_predicate "add_operand"
(if_then_else (match_code "const_int")
(match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')")
(match_operand 0 "register_operand")))
;; Return 1 if the operand is a valid second operand to a
;; sign-extending add insn.
(define_predicate "sext_add_operand"
(if_then_else (match_code "const_int")
(match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')")
(match_operand 0 "register_operand")))
;; Return 1 if OP is the constant 4 or 8.
(define_predicate "const48_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) == 4 || INTVAL (op) == 8")))
;; Return 1 if OP is a valid first operand to an AND insn.
(define_predicate "and_operand"
(if_then_else (match_code "const_int")
(match_test "(unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
|| zap_mask (INTVAL (op))")
(if_then_else (match_code "const_double")
(match_test "zap_mask (CONST_DOUBLE_LOW (op))
&& zap_mask (CONST_DOUBLE_HIGH (op))")
(match_operand 0 "register_operand"))))
;; Return 1 if OP is a valid first operand to an IOR or XOR insn.
(define_predicate "or_operand"
(if_then_else (match_code "const_int")
(match_test "(unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100")
(match_operand 0 "register_operand")))
;; Return 1 if OP is a constant that is the width, in bits, of an integral
;; mode not larger than DImode.
(define_predicate "mode_width_operand"
(match_code "const_int")
{
HOST_WIDE_INT i = INTVAL (op);
return i == 8 || i == 16 || i == 32 || i == 64;
})
;; Return 1 if OP is a constant that is a mask of ones of width of an
;; integral machine mode not larger than DImode.
(define_predicate "mode_mask_operand"
(match_code "const_int,const_double")
{
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op);
if (value == 0xff)
return 1;
if (value == 0xffff)
return 1;
if (value == 0xffffffff)
return 1;
if (value == -1)
return 1;
}
else if (HOST_BITS_PER_WIDE_INT == 32 && GET_CODE (op) == CONST_DOUBLE)
{
if (CONST_DOUBLE_LOW (op) == 0xffffffff && CONST_DOUBLE_HIGH (op) == 0)
return 1;
}
return 0;
})
;; Return 1 if OP is a multiple of 8 less than 64.
(define_predicate "mul8_operand"
(match_code "const_int")
{
unsigned HOST_WIDE_INT i = INTVAL (op);
return i < 64 && i % 8 == 0;
})
;; Return 1 if OP is a hard floating-point register.
(define_predicate "hard_fp_register_operand"
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS;
})
;; Return 1 if OP is a hard general register.
(define_predicate "hard_int_register_operand"
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS;
})
;; Return 1 if OP is something that can be reloaded into a register;
;; if it is a MEM, it need not be valid.
(define_predicate "some_operand"
(ior (match_code "reg,mem,const_int,const_double,const_vector,
label_ref,symbol_ref,const,high")
(and (match_code "subreg")
(match_test "some_operand (SUBREG_REG (op), VOIDmode)"))))
;; Likewise, but don't accept constants.
(define_predicate "some_ni_operand"
(ior (match_code "reg,mem")
(and (match_code "subreg")
(match_test "some_ni_operand (SUBREG_REG (op), VOIDmode)"))))
;; Return 1 if OP is a valid operand for the source of a move insn.
(define_predicate "input_operand"
(match_code "label_ref,symbol_ref,const,high,reg,subreg,mem,
const_double,const_vector,const_int")
{
switch (GET_CODE (op))
{
case LABEL_REF:
case SYMBOL_REF:
case CONST:
if (TARGET_EXPLICIT_RELOCS)
{
/* We don't split symbolic operands into something unintelligable
until after reload, but we do not wish non-small, non-global
symbolic operands to be reconstructed from their high/lo_sum
form. */
return (small_symbolic_operand (op, mode)
|| global_symbolic_operand (op, mode)
|| gotdtp_symbolic_operand (op, mode)
|| gottp_symbolic_operand (op, mode));
}
/* This handles both the Windows/NT and OSF cases. */
return mode == ptr_mode || mode == DImode;
case HIGH:
return (TARGET_EXPLICIT_RELOCS
&& local_symbolic_operand (XEXP (op, 0), mode));
case REG:
return 1;
case SUBREG:
if (register_operand (op, mode))
return 1;
/* ... fall through ... */
case MEM:
return ((TARGET_BWX || (mode != HImode && mode != QImode))
&& general_operand (op, mode));
case CONST_DOUBLE:
case CONST_VECTOR:
return op == CONST0_RTX (mode);
case CONST_INT:
return mode == QImode || mode == HImode || add_operand (op, mode);
default:
abort ();
}
return 0;
})
;; Return 1 if OP is a SYMBOL_REF for a function known to be in this
;; file, and in the same section as the current function.
(define_predicate "samegp_function_operand"
(match_code "symbol_ref")
{
/* Easy test for recursion. */
if (op == XEXP (DECL_RTL (current_function_decl), 0))
return true;
/* Functions that are not local can be overridden, and thus may
not share the same gp. */
if (! SYMBOL_REF_LOCAL_P (op))
return false;
/* If -msmall-data is in effect, assume that there is only one GP
for the module, and so any local symbol has this property. We
need explicit relocations to be able to enforce this for symbols
not defined in this unit of translation, however. */
if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
return true;
/* Functions that are not external are defined in this UoT,
and thus must share the same gp. */
return ! SYMBOL_REF_EXTERNAL_P (op);
})
;; Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr.
(define_predicate "direct_call_operand"
(match_operand 0 "samegp_function_operand")
{
tree op_decl, cfun_sec, op_sec;
/* If profiling is implemented via linker tricks, we can't jump
to the nogp alternate entry point. Note that current_function_profile
would not be correct, since that doesn't indicate if the target
function uses profiling. */
/* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
but is approximately correct for the OSF ABIs. Don't know
what to do for VMS, NT, or UMK. */
if (!TARGET_PROFILING_NEEDS_GP && profile_flag)
return false;
/* Must be a function. In some cases folks create thunks in static
data structures and then make calls to them. If we allow the
direct call, we'll get an error from the linker about !samegp reloc
against a symbol without a .prologue directive. */
if (!SYMBOL_REF_FUNCTION_P (op))
return false;
/* Must be "near" so that the branch is assumed to reach. With
-msmall-text, this is assumed true of all local symbols. Since
we've already checked samegp, locality is already assured. */
if (TARGET_SMALL_TEXT)
return true;
/* Otherwise, a decl is "near" if it is defined in the same section. */
if (flag_function_sections)
return false;
op_decl = SYMBOL_REF_DECL (op);
if (DECL_ONE_ONLY (current_function_decl)
|| (op_decl && DECL_ONE_ONLY (op_decl)))
return false;
cfun_sec = DECL_SECTION_NAME (current_function_decl);
op_sec = op_decl ? DECL_SECTION_NAME (op_decl) : NULL;
return ((!cfun_sec && !op_sec)
|| (cfun_sec && op_sec
&& strcmp (TREE_STRING_POINTER (cfun_sec),
TREE_STRING_POINTER (op_sec)) == 0));
})
;; Return 1 if OP is a valid operand for the MEM of a CALL insn.
;;
;; For TARGET_ABI_OSF, we want to restrict to R27 or a pseudo.
;; For TARGET_ABI_UNICOSMK, we want to restrict to registers.
(define_predicate "call_operand"
(if_then_else (match_code "reg")
(match_test "!TARGET_ABI_OSF
|| REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER")
(and (match_test "!TARGET_ABI_UNICOSMK")
(match_code "symbol_ref"))))
;; Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
;; a (non-tls) variable known to be defined in this file.
(define_predicate "local_symbolic_operand"
(match_code "label_ref,const,symbol_ref")
{
if (GET_CODE (op) == LABEL_REF)
return 1;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
})
;; Return true if OP is a SYMBOL_REF or CONST referencing a variable
;; known to be defined in this file in the small data area.
(define_predicate "small_symbolic_operand"
(match_code "const,symbol_ref")
{
if (! TARGET_SMALL_DATA)
return 0;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
/* ??? There's no encode_section_info equivalent for the rtl
constant pool, so SYMBOL_FLAG_SMALL never gets set. */
if (CONSTANT_POOL_ADDRESS_P (op))
return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value;
return (SYMBOL_REF_LOCAL_P (op)
&& SYMBOL_REF_SMALL_P (op)
&& SYMBOL_REF_TLS_MODEL (op) == 0);
})
;; Return true if OP is a SYMBOL_REF or CONST referencing a variable
;; not known (or known not) to be defined in this file.
(define_predicate "global_symbolic_operand"
(match_code "const,symbol_ref")
{
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
op = XEXP (XEXP (op, 0), 0);
if (GET_CODE (op) != SYMBOL_REF)
return 0;
return !SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
})
;; Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
;; possibly with an offset.
(define_predicate "symbolic_operand"
(ior (match_code "symbol_ref,label_ref")
(and (match_code "const")
(match_test "GET_CODE (XEXP (op,0)) == PLUS
&& GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT"))))
;; Return true if OP is valid for 16-bit DTP relative relocations.
(define_predicate "dtp16_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 16, UNSPEC_DTPREL)")))
;; Return true if OP is valid for 32-bit DTP relative relocations.
(define_predicate "dtp32_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 32, UNSPEC_DTPREL)")))
;; Return true if OP is valid for 64-bit DTP relative relocations.
(define_predicate "gotdtp_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 64, UNSPEC_DTPREL)")))
;; Return true if OP is valid for 16-bit TP relative relocations.
(define_predicate "tp16_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 16, UNSPEC_TPREL)")))
;; Return true if OP is valid for 32-bit TP relative relocations.
(define_predicate "tp32_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 32, UNSPEC_TPREL)")))
;; Return true if OP is valid for 64-bit TP relative relocations.
(define_predicate "gottp_symbolic_operand"
(and (match_code "const")
(match_test "tls_symbolic_operand_1 (op, 64, UNSPEC_TPREL)")))
;; Return 1 if this memory address is a known aligned register plus
;; a constant. It must be a valid address. This means that we can do
;; this as an aligned reference plus some offset.
;;
;; Take into account what reload will do. Oh god this is awful.
;; The horrible comma-operator construct below is to prevent genrecog
;; from thinking that this predicate accepts REG and SUBREG. We don't
;; use recog during reload, so pretending these codes are accepted
;; pessimizes things a tad.
(define_predicate "aligned_memory_operand"
(ior (match_test "op = resolve_reload_operand (op), 0")
(match_code "mem"))
{
rtx base;
if (MEM_ALIGN (op) >= 32)
return 1;
op = XEXP (op, 0);
/* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
sorts of constructs. Dig for the real base register. */
if (reload_in_progress
&& GET_CODE (op) == PLUS
&& GET_CODE (XEXP (op, 0)) == PLUS)
base = XEXP (XEXP (op, 0), 0);
else
{
if (! memory_address_p (mode, op))
return 0;
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) >= 32);
})
;; Similar, but return 1 if OP is a MEM which is not alignable.
(define_predicate "unaligned_memory_operand"
(ior (match_test "op = resolve_reload_operand (op), 0")
(match_code "mem"))
{
rtx base;
if (MEM_ALIGN (op) >= 32)
return 0;
op = XEXP (op, 0);
/* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
sorts of constructs. Dig for the real base register. */
if (reload_in_progress
&& GET_CODE (op) == PLUS
&& GET_CODE (XEXP (op, 0)) == PLUS)
base = XEXP (XEXP (op, 0), 0);
else
{
if (! memory_address_p (mode, op))
return 0;
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) < 32);
})
;; Return 1 if OP is any memory location. During reload a pseudo matches.
(define_predicate "any_memory_operand"
(ior (match_code "mem,reg")
(and (match_code "subreg")
(match_test "GET_CODE (SUBREG_REG (op)) == REG"))))
;; Return 1 if OP is either a register or an unaligned memory location.
(define_predicate "reg_or_unaligned_mem_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "unaligned_memory_operand")))
;; Return 1 is OP is a memory location that is not a reference
;; (using an AND) to an unaligned location. Take into account
;; what reload will do.
(define_predicate "normal_memory_operand"
(ior (match_test "op = resolve_reload_operand (op), 0")
(and (match_code "mem")
(match_test "GET_CODE (XEXP (op, 0)) != AND"))))
;; Returns 1 if OP is not an eliminable register.
;;
;; This exists to cure a pathological abort in the s8addq (et al) patterns,
;;
;; long foo () { long t; bar(); return (long) &t * 26107; }
;;
;; which run afoul of a hack in reload to cure a (presumably) similar
;; problem with lea-type instructions on other targets. But there is
;; one of us and many of them, so work around the problem by selectively
;; preventing combine from making the optimization.
(define_predicate "reg_not_elim_operand"
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return op != frame_pointer_rtx && op != arg_pointer_rtx;
})
;; Accept a register, but not a subreg of any kind. This allows us to
;; avoid pathological cases in reload wrt data movement common in
;; int->fp conversion. */
(define_predicate "reg_no_subreg_operand"
(and (match_code "reg")
(match_operand 0 "register_operand")))
;; Return 1 if OP is a valid Alpha comparison operator for "cmp" style
;; instructions.
(define_predicate "alpha_comparison_operator"
(match_code "eq,le,lt,leu,ltu"))
;; Similarly, but with swapped operands.
(define_predicate "alpha_swapped_comparison_operator"
(match_code "eq,ge,gt,gtu,gtu"))
;; Return 1 if OP is a valid Alpha comparison operator against zero
;; for "bcc" style instructions.
(define_predicate "alpha_zero_comparison_operator"
(match_code "eq,ne,le,lt,leu,ltu"))
;; Return 1 if OP is a signed comparison operation.
(define_predicate "signed_comparison_operator"
(match_code "eq,ne,le,lt,ge,gt"))
;; Return 1 if OP is a valid Alpha floating point comparison operator.
(define_predicate "alpha_fp_comparison_operator"
(match_code "eq,le,lt,unordered"))
;; Return 1 if this is a divide or modulus operator.
(define_predicate "divmod_operator"
(match_code "div,mod,udiv,umod"))
;; Return 1 if this is a float->int conversion operator.
(define_predicate "fix_operator"
(match_code "fix,unsigned_fix"))
;; Recognize an addition operation that includes a constant. Used to
;; convince reload to canonize (plus (plus reg c1) c2) during register
;; elimination.
(define_predicate "addition_operation"
(and (match_code "plus")
(match_test "register_operand (XEXP (op, 0), mode)
&& GET_CODE (XEXP (op, 1)) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K')")))
...@@ -417,6 +417,7 @@ write_insn_preds_c (void) ...@@ -417,6 +417,7 @@ write_insn_preds_c (void)
#include \"coretypes.h\"\n\ #include \"coretypes.h\"\n\
#include \"tm.h\"\n\ #include \"tm.h\"\n\
#include \"rtl.h\"\n\ #include \"rtl.h\"\n\
#include \"tree.h\"\n\
#include \"tm_p.h\"\n\ #include \"tm_p.h\"\n\
#include \"function.h\"\n\ #include \"function.h\"\n\
#include \"insn-config.h\"\n\ #include \"insn-config.h\"\n\
......
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