From: Nick Clifton Date: Wed, 2 Feb 2011 14:31:55 +0000 (+0000) Subject: Import these patches from the mainline: X-Git-Tag: releases/gcc-4.5.3~252 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=446e8260591494d635d585227aba1373c26d9e77;p=thirdparty%2Fgcc.git Import these patches from the mainline: 2011-01-31 Nick Clifton * config/rx/rx.c (rx_get_stack_layout): Only save call clobbered registers inside interrupt handlers if the handler is not a leaf function. 2011-01-25 Nick Clifton * config/rx/rx.h (LIBCALL_VALUE): Do not promote complex types. * config/rx/rx.c (rx_function_value): Likewise. (rx_promote_function_mode): Likewise. (gen_safe_add): Place an outsized immediate value inside an UNSPEC in order to make it legitimate. * config/rx/rx.md (adddi3_internal): If the second operand is a MEM make sure that the first operand is the same as the result register. (addsi3_unspec): Delete. (subdi3): Do not accept immediate operands. (subdi3_internal): Likewise. 2011-01-24 Richard Henderson * config/rx/predicates.md (rx_fp_comparison_operator): Don't accept compound unordered comparisons. * config/rx/rx.c (rx_split_fp_compare): Remove. * config/rx/rx-protos.h: Update. * config/rx/rx.md (gcc_conds, rx_conds): Remove. (cbranchsf4): Don't call rx_split_fp_compare. (*cbranchsf4): Use rx_split_cbranch. (*cmpsf): Don't accept "i" constraint. (*conditional_branch): Only valid after reload. (cstoresf4): Merge expander with insn. Don't call rx_split_fp_compare. 2011-01-22 Nick Clifton * config/rx/rx.md (cstoresf4): Pass comparison operator to rx_split_fp_compare. 2011-01-22 Nick Clifton * config/rx/rx.md (UNSPEC_CONST): New. (deallocate_and_return): Wrap the amount popped off the stack in an UNSPEC_CONST in order to stop it being rejected by -mmax-constant-size. (pop_and_return): Add a "(return)" rtx. (call): Drop the immediate operand. (call_internal): Likewise. (call_value): Likewise. (call_value_internal): Likewise. (sibcall_internal): Likewise. (sibcall_value_internal): Likewise. (sibcall): Likewise. Generate an explicit call using sibcall_internal. (sibcall_value): Likewise. (mov<>): FAIL if a constant operand is not legitimate. (addsi3_unpsec): New pattern. * config/rx/rx.c (rx_print_operand_address): Handle UNPSEC CONSTs. (ok_for_max_constant): New function. (gen_safe_add): New function. (rx_expand_prologue): Use gen_safe_add. (rx_expand_epilogue): Likewise. (rx_is_legitimate_constant): Use ok_for_max_constant. Handle UNSPEC CONSTs. 2011-01-17 Richard Henderson * config/rx/predicates.md (rx_constshift_operand): Use match_test. (rx_restricted_mem_operand): New. (rx_shift_operand): Use register_operand. (rx_source_operand, rx_compare_operand): Likewise. * config/rx/rx.md (addsi3_flags): New expander. (adddi3): Rewrite as expander. (adc_internal, *adc_flags, adddi3_internal): New patterns. (subsi3_flags): New expander. (subdi3): Rewrite as expander. (sbb_internal, *sbb_flags, subdi3_internal): New patterns. * config/rx/rx.c (RX_BUILTIN_SAT): Remove. (rx_init_builtins): Remove sat builtin. (rx_expand_builtin): Likewise. * config/rx/rx.md (ssaddsi3): New. (*sat): Rename from sat. Represent the CC_REG input. * config/rx/predicates.md (rshift_operator): New. * config/rx/rx.c (rx_expand_insv): Remove. * config/rx/rx-protos.h: Update. * config/rx/rx.md (*bitset): Rename from bitset. Swap the ashift operand to the canonical position. (*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly. (*bitclr, *bitclr_in_memory): Similarly. (*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New. (insv): Retain the zero_extract in the expansion. * config/rx/rx.md (bswapsi2): Use = not + for output reload. (bswaphi2, bitinvert, revw): Likewise. * config/rx/rx.c (gen_rx_store_vector): Use VOIDmode for gen_rtx_SET. (gen_rx_rtsd_vector, gen_rx_popm_vector): Likewise. * config/rx/rx.md (pop_and_return): Use VOIDmode for SET. (stack_push, stack_pushm, stack_pop, stack_popm): Likewise. (bitset, bitset_in_memory): Likewise. (bitinvert, bitinvert_in_memory): Likewise. (bitclr, bitclr_in_memory): Likewise. (insv, sync_lock_test_and_setsi, movstr, rx_movstr): Likewise. (rx_strend, rx_cmpstrn): Likewise. (rx_setmem): Likewise. Make the source BLKmode to match the dest. (bitop peep2 patterns): Remove. * config/rx/rx.c (rx_match_ccmode): New. * config/rx/rx-protos.h: Update. * config/rx/rx.md (abssi2): Clobber, don't set flags. (addsi3, adddi3, andsi3, negsi2, one_cmplsi2, iorsi3): Likewise. (rotlsi3, rotrsi3, ashrsi3, lshrsi3, ashlsi3): Likewise. (subsi3, subdi3, xorsi3, addsf3, divsf3, mulsf3, subsf3): Likewise. (fix_truncsfsi2, floatsisf2): Likewise. (*abssi2_flags, *addsi3_flags, *andsi3_flags, *negsi2_flags): New. (*one_cmplsi2_flags, *iorsi3_flags, *rotlsi3_flags): New. (*rotrsi3_flags, *ashrsi3_flags, *lshrsi3_flags, *ashlsi3_flags): New. (*subsi3_flags, *xorsi3_flags): New. * config/rx/rx.md (cstoresf4, *cstoresf4): New patterns. * config/rx/rx.c (rx_print_operand): Remove workaround for unsplit comparison operations. * config/rx/rx.md (movsicc): Split after reload. (*movsicc): Merge *movsieq and *movsine via match_operator. (*stcc): New pattern. * config/rx/rx.c (rx_float_compare_mode): Remove. * config/rx/rx.h (rx_float_compare_mode): Remove. * config/rx/rx.md (cstoresi4): Split after reload. (*sccc): New pattern. * config/rx/predicates.md (label_ref_operand): New. (rx_z_comparison_operator): New. (rx_zs_comparison_operator): New. (rx_fp_comparison_operator): New. * config/rx/rx.c (rx_print_operand) [B]: Examine comparison modes. Validate that the flags are set properly for the comparison. (rx_gen_cond_branch_template): Remove. (rx_cc_modes_compatible): Remove. (mode_from_flags): New. (flags_from_code): Rename from flags_needed_for_conditional. (rx_cc_modes_compatible): Re-write in terms of flags_from_mode. (rx_select_cc_mode): Likewise. (rx_split_fp_compare): New. (rx_split_cbranch): New. * config/rx/rx.md (most_cond, zs_cond): Remove iterators. (*cbranchsi4): Use match_operator and rx_split_cbranch. (*cbranchsf4): Similarly. (*cbranchsi4_tst): Rename from *tstbranchsi4_. Use match_operator and rx_split_cbranch. (*cbranchsi4_tst_ext): Combine *tstbranchsi4m_eq and tstbranchsi4m_ne. Use match_operator and rx_split_cbranch. (*cmpsi): Rename from cmpsi. (*tstsi): Rename from tstsi. (*cmpsf): Rename from cmpsf; use CC_Fmode. (*conditional_branch): Rename from conditional_branch. (*reveresed_conditional_branch): Remove. (b): Remove expander. * config/rx/rx-protos.h: Update. * config/rx/rx.c (rx_compare_redundant): Remove. * config/rx/rx.md (cmpsi): Don't use it. * config/rx/rx-protos.h: Update. * config/rx/rx-modes.def (CC_F): New mode. * config/rx/rx.c (rx_select_cc_mode): New. * config/rx/rx.h (SELECT_CC_MODE): Use it. * config/rx/rx-protos.h: Update. From-SVN: r169526 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 27c16ea23b5c..0a67267d10de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,181 @@ +2011-02-02 Nick Clifton + + Import these patches from the mainline: + 2011-01-31 Nick Clifton + + * config/rx/rx.c (rx_get_stack_layout): Only save call clobbered + registers inside interrupt handlers if the handler is not a leaf + function. + + 2011-01-25 Nick Clifton + + * config/rx/rx.h (LIBCALL_VALUE): Do not promote complex types. + * config/rx/rx.c (rx_function_value): Likewise. + (rx_promote_function_mode): Likewise. + (gen_safe_add): Place an outsized immediate value inside an UNSPEC + in order to make it legitimate. + * config/rx/rx.md (adddi3_internal): If the second operand is a + MEM make sure that the first operand is the same as the result + register. + (addsi3_unspec): Delete. + (subdi3): Do not accept immediate operands. + (subdi3_internal): Likewise. + + 2011-01-24 Richard Henderson + + * config/rx/predicates.md (rx_fp_comparison_operator): Don't accept + compound unordered comparisons. + * config/rx/rx.c (rx_split_fp_compare): Remove. + * config/rx/rx-protos.h: Update. + * config/rx/rx.md (gcc_conds, rx_conds): Remove. + (cbranchsf4): Don't call rx_split_fp_compare. + (*cbranchsf4): Use rx_split_cbranch. + (*cmpsf): Don't accept "i" constraint. + (*conditional_branch): Only valid after reload. + (cstoresf4): Merge expander with insn. Don't call + rx_split_fp_compare. + + 2011-01-22 Nick Clifton + + * config/rx/rx.md (cstoresf4): Pass comparison operator to + rx_split_fp_compare. + + 2011-01-22 Nick Clifton + + * config/rx/rx.md (UNSPEC_CONST): New. + (deallocate_and_return): Wrap the amount popped off the stack in + an UNSPEC_CONST in order to stop it being rejected by + -mmax-constant-size. + (pop_and_return): Add a "(return)" rtx. + (call): Drop the immediate operand. + (call_internal): Likewise. + (call_value): Likewise. + (call_value_internal): Likewise. + (sibcall_internal): Likewise. + (sibcall_value_internal): Likewise. + (sibcall): Likewise. Generate an explicit call using + sibcall_internal. + (sibcall_value): Likewise. + (mov<>): FAIL if a constant operand is not legitimate. + (addsi3_unpsec): New pattern. + + * config/rx/rx.c (rx_print_operand_address): Handle UNPSEC + CONSTs. + (ok_for_max_constant): New function. + (gen_safe_add): New function. + (rx_expand_prologue): Use gen_safe_add. + (rx_expand_epilogue): Likewise. + (rx_is_legitimate_constant): Use ok_for_max_constant. Handle + UNSPEC CONSTs. + + 2011-01-17 Richard Henderson + + * config/rx/predicates.md (rx_constshift_operand): Use match_test. + (rx_restricted_mem_operand): New. + (rx_shift_operand): Use register_operand. + (rx_source_operand, rx_compare_operand): Likewise. + * config/rx/rx.md (addsi3_flags): New expander. + (adddi3): Rewrite as expander. + (adc_internal, *adc_flags, adddi3_internal): New patterns. + (subsi3_flags): New expander. + (subdi3): Rewrite as expander. + (sbb_internal, *sbb_flags, subdi3_internal): New patterns. + + * config/rx/rx.c (RX_BUILTIN_SAT): Remove. + (rx_init_builtins): Remove sat builtin. + (rx_expand_builtin): Likewise. + * config/rx/rx.md (ssaddsi3): New. + (*sat): Rename from sat. Represent the CC_REG input. + + * config/rx/predicates.md (rshift_operator): New. + * config/rx/rx.c (rx_expand_insv): Remove. + * config/rx/rx-protos.h: Update. + * config/rx/rx.md (*bitset): Rename from bitset. Swap the ashift + operand to the canonical position. + (*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly. + (*bitclr, *bitclr_in_memory): Similarly. + (*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New. + (insv): Retain the zero_extract in the expansion. + + * config/rx/rx.md (bswapsi2): Use = not + for output reload. + (bswaphi2, bitinvert, revw): Likewise. + + * config/rx/rx.c (gen_rx_store_vector): Use VOIDmode for gen_rtx_SET. + (gen_rx_rtsd_vector, gen_rx_popm_vector): Likewise. + * config/rx/rx.md (pop_and_return): Use VOIDmode for SET. + (stack_push, stack_pushm, stack_pop, stack_popm): Likewise. + (bitset, bitset_in_memory): Likewise. + (bitinvert, bitinvert_in_memory): Likewise. + (bitclr, bitclr_in_memory): Likewise. + (insv, sync_lock_test_and_setsi, movstr, rx_movstr): Likewise. + (rx_strend, rx_cmpstrn): Likewise. + (rx_setmem): Likewise. Make the source BLKmode to match the dest. + (bitop peep2 patterns): Remove. + + * config/rx/rx.c (rx_match_ccmode): New. + * config/rx/rx-protos.h: Update. + * config/rx/rx.md (abssi2): Clobber, don't set flags. + (addsi3, adddi3, andsi3, negsi2, one_cmplsi2, iorsi3): Likewise. + (rotlsi3, rotrsi3, ashrsi3, lshrsi3, ashlsi3): Likewise. + (subsi3, subdi3, xorsi3, addsf3, divsf3, mulsf3, subsf3): Likewise. + (fix_truncsfsi2, floatsisf2): Likewise. + (*abssi2_flags, *addsi3_flags, *andsi3_flags, *negsi2_flags): New. + (*one_cmplsi2_flags, *iorsi3_flags, *rotlsi3_flags): New. + (*rotrsi3_flags, *ashrsi3_flags, *lshrsi3_flags, *ashlsi3_flags): New. + (*subsi3_flags, *xorsi3_flags): New. + + * config/rx/rx.md (cstoresf4, *cstoresf4): New patterns. + + * config/rx/rx.c (rx_print_operand): Remove workaround for + unsplit comparison operations. + + * config/rx/rx.md (movsicc): Split after reload. + (*movsicc): Merge *movsieq and *movsine via match_operator. + (*stcc): New pattern. + + * config/rx/rx.c (rx_float_compare_mode): Remove. + * config/rx/rx.h (rx_float_compare_mode): Remove. + * config/rx/rx.md (cstoresi4): Split after reload. + (*sccc): New pattern. + + * config/rx/predicates.md (label_ref_operand): New. + (rx_z_comparison_operator): New. + (rx_zs_comparison_operator): New. + (rx_fp_comparison_operator): New. + * config/rx/rx.c (rx_print_operand) [B]: Examine comparison modes. + Validate that the flags are set properly for the comparison. + (rx_gen_cond_branch_template): Remove. + (rx_cc_modes_compatible): Remove. + (mode_from_flags): New. + (flags_from_code): Rename from flags_needed_for_conditional. + (rx_cc_modes_compatible): Re-write in terms of flags_from_mode. + (rx_select_cc_mode): Likewise. + (rx_split_fp_compare): New. + (rx_split_cbranch): New. + * config/rx/rx.md (most_cond, zs_cond): Remove iterators. + (*cbranchsi4): Use match_operator and rx_split_cbranch. + (*cbranchsf4): Similarly. + (*cbranchsi4_tst): Rename from *tstbranchsi4_. Use + match_operator and rx_split_cbranch. + (*cbranchsi4_tst_ext): Combine *tstbranchsi4m_eq and + tstbranchsi4m_ne. Use match_operator and rx_split_cbranch. + (*cmpsi): Rename from cmpsi. + (*tstsi): Rename from tstsi. + (*cmpsf): Rename from cmpsf; use CC_Fmode. + (*conditional_branch): Rename from conditional_branch. + (*reveresed_conditional_branch): Remove. + (b): Remove expander. + * config/rx/rx-protos.h: Update. + + * config/rx/rx.c (rx_compare_redundant): Remove. + * config/rx/rx.md (cmpsi): Don't use it. + * config/rx/rx-protos.h: Update. + + * config/rx/rx-modes.def (CC_F): New mode. + * config/rx/rx.c (rx_select_cc_mode): New. + * config/rx/rx.h (SELECT_CC_MODE): Use it. + * config/rx/rx-protos.h: Update. + 2011-02-01 Richard Guenther PR tree-optimization/47541 @@ -21,14 +199,14 @@ 2011-01-30 Gerald Pfeifer * doc/install.texi: Update copyright years. - + 2011-01-30 Gerald Pfeifer * doc/install.texi (Binaries): Remove outdated reference for Motorola 68HC11/68HC12 downloads. 2011-01-30 Gerald Pfeifer - + * doc/extend.texi (Thread-Local): Adjust reference to Ulrich Drepper's paper. diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md index d8def87d6e8b..5b33c1c52b37 100644 --- a/gcc/config/rx/predicates.md +++ b/gcc/config/rx/predicates.md @@ -1,5 +1,5 @@ ;; Predicate definitions for Renesas RX. -;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; ;; This file is part of GCC. @@ -37,19 +37,19 @@ ;; Only small integers or a value in a register are permitted. (define_predicate "rx_shift_operand" - (match_code "const_int,reg") - { - if (CONST_INT_P (op)) - return IN_RANGE (INTVAL (op), 0, 31); - return true; - } + (ior (match_operand 0 "register_operand") + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 31)"))) ) (define_predicate "rx_constshift_operand" - (match_code "const_int") - { - return IN_RANGE (INTVAL (op), 0, 31); - } + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 31)")) +) + +(define_predicate "rx_restricted_mem_operand" + (and (match_code "mem") + (match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)")) ) ;; Check that the operand is suitable as the source operand @@ -57,20 +57,9 @@ ;; and a restricted subset of memory addresses are allowed. (define_predicate "rx_source_operand" - (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") - { - if (CONSTANT_P (op)) - return rx_is_legitimate_constant (op); - - if (! MEM_P (op)) - return true; - - /* Do not allow size conversions whilst accessing memory. */ - if (GET_MODE (op) != mode) - return false; - - return rx_is_restricted_memory_address (XEXP (op, 0), mode); - } + (ior (match_operand 0 "register_operand") + (match_operand 0 "immediate_operand") + (match_operand 0 "rx_restricted_mem_operand")) ) ;; Check that the operand is suitable as the source operand @@ -79,16 +68,8 @@ ;; CONST_INTs are not. (define_predicate "rx_compare_operand" - (match_code "subreg,reg,mem") - { - if (GET_CODE (op) == SUBREG) - return REG_P (XEXP (op, 0)); - - if (! MEM_P (op)) - return true; - - return rx_is_restricted_memory_address (XEXP (op, 0), mode); - } + (ior (match_operand 0 "register_operand") + (match_operand 0 "rx_restricted_mem_operand")) ) ;; Return true if OP is a store multiple operation. This looks like: @@ -293,3 +274,24 @@ element = XVECEXP (op, 0, count - 1); return GET_CODE (element) == RETURN; }) + +(define_predicate "label_ref_operand" + (match_code "label_ref") +) + +(define_predicate "rx_z_comparison_operator" + (match_code "eq,ne") +) + +(define_predicate "rx_zs_comparison_operator" + (match_code "eq,ne") +) + +;; GT and LE omitted due to operand swap required. +(define_predicate "rx_fp_comparison_operator" + (match_code "eq,ne,lt,ge,ordered,unordered") +) + +(define_predicate "rshift_operator" + (match_code "ashiftrt,lshiftrt") +) diff --git a/gcc/config/rx/rx-modes.def b/gcc/config/rx/rx-modes.def index 781d93366c6f..31e3225c6774 100644 --- a/gcc/config/rx/rx-modes.def +++ b/gcc/config/rx/rx-modes.def @@ -1,5 +1,6 @@ -/* Definitions of target machine for GNU compiler, for RX. - Copyright (C) 2010 by Nick Clifton (nickc@redhat.com). +/* Definitions of target specific machine modes for the RX. + Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Contributed by Red Hat. This file is part of GCC. @@ -20,3 +21,5 @@ CC_MODE (CC_ZS); CC_MODE (CC_ZSO); CC_MODE (CC_ZSC); + +CC_MODE (CC_F); /* fcmp */ diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h index 2ebf1d8f3253..2d291c1ad958 100644 --- a/gcc/config/rx/rx-protos.h +++ b/gcc/config/rx/rx-protos.h @@ -1,5 +1,5 @@ /* Exported function prototypes from the Renesas RX backend. - Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -35,15 +35,17 @@ extern bool rx_compare_redundant (rtx); extern void rx_emit_stack_popm (rtx *, bool); extern void rx_emit_stack_pushm (rtx *); extern void rx_expand_epilogue (bool); -extern bool rx_expand_insv (rtx *); extern const char * rx_gen_cond_branch_template (rtx, bool); extern char * rx_gen_move_template (rtx *, bool); extern bool rx_is_legitimate_constant (rtx); extern bool rx_is_mode_dependent_addr (rtx); extern bool rx_is_restricted_memory_address (rtx, Mmode); +extern bool rx_match_ccmode (rtx, Mmode); extern void rx_notice_update_cc (rtx body, rtx insn); extern void rx_print_operand (FILE *, rtx, int); extern void rx_print_operand_address (FILE *, rtx); +extern Mmode rx_select_cc_mode (enum rtx_code, rtx, rtx); +extern void rx_split_cbranch (Mmode, enum rtx_code, rtx, rtx, rtx); #endif #ifdef TREE_CODE diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 77e3fcfc4785..d1d17f9c6565 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -1,5 +1,5 @@ /* Subroutines used for code generation on Renesas RX processors. - Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -51,6 +51,12 @@ #include "target-def.h" #include "langhooks.h" +#define CC_FLAG_S (1 << 0) +#define CC_FLAG_Z (1 << 1) +#define CC_FLAG_O (1 << 2) +#define CC_FLAG_C (1 << 3) +#define CC_FLAG_FP (1 << 4) /* Fake, to differentiate CC_Fmode. */ + enum rx_cpu_types rx_cpu_type = RX600; /* Return true if OP is a reference to an object in a small data area. */ @@ -312,9 +318,18 @@ rx_print_operand_address (FILE * file, rtx addr) break; } + case CONST: + if (GET_CODE (XEXP (addr, 0)) == UNSPEC) + { + addr = XEXP (addr, 0); + gcc_assert (XINT (addr, 1) == UNSPEC_CONST); + + addr = XVECEXP (addr, 0, 0); + gcc_assert (CONST_INT_P (addr)); + } + /* Fall through. */ case LABEL_REF: case SYMBOL_REF: - case CONST: fprintf (file, "#"); default: output_addr_const (file, addr); @@ -351,8 +366,75 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned) return true; } +/* Convert a CC_MODE to the set of flags that it represents. */ + +static unsigned int +flags_from_mode (enum machine_mode mode) +{ + switch (mode) + { + case CC_ZSmode: + return CC_FLAG_S | CC_FLAG_Z; + case CC_ZSOmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; + case CC_ZSCmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C; + case CCmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C; + case CC_Fmode: + return CC_FLAG_FP; + default: + gcc_unreachable (); + } +} + +/* Convert a set of flags to a CC_MODE that can implement it. */ + +static enum machine_mode +mode_from_flags (unsigned int f) +{ + if (f & CC_FLAG_FP) + return CC_Fmode; + if (f & CC_FLAG_O) + { + if (f & CC_FLAG_C) + return CCmode; + else + return CC_ZSOmode; + } + else if (f & CC_FLAG_C) + return CC_ZSCmode; + else + return CC_ZSmode; +} + +/* Convert an RTX_CODE to the set of flags needed to implement it. + This assumes an integer comparison. */ -int rx_float_compare_mode; +static unsigned int +flags_from_code (enum rtx_code code) +{ + switch (code) + { + case LT: + case GE: + return CC_FLAG_S | CC_FLAG_O; + case GT: + case LE: + return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z; + case GEU: + case LTU: + return CC_FLAG_C; + case GTU: + case LEU: + return CC_FLAG_C | CC_FLAG_Z; + case EQ: + case NE: + return CC_FLAG_Z; + default: + gcc_unreachable (); + } +} /* Handles the insertion of a single operand into the assembler output. The % directives supported are: @@ -393,21 +475,48 @@ rx_print_operand (FILE * file, rtx op, int letter) break; case 'B': - switch (GET_CODE (op)) - { - case LT: fprintf (file, "lt"); break; - case GE: fprintf (file, "ge"); break; - case GT: fprintf (file, "gt"); break; - case LE: fprintf (file, "le"); break; - case GEU: fprintf (file, "geu"); break; - case LTU: fprintf (file, "ltu"); break; - case GTU: fprintf (file, "gtu"); break; - case LEU: fprintf (file, "leu"); break; - case EQ: fprintf (file, "eq"); break; - case NE: fprintf (file, "ne"); break; - default: debug_rtx (op); gcc_unreachable (); - } - break; + { + enum rtx_code code = GET_CODE (op); + enum machine_mode mode = GET_MODE (XEXP (op, 0)); + const char * ret; + + if (mode == CC_Fmode) + { + /* C flag is undefined, and O flag carries unordered. None of the + branch combinations that include O use it helpfully. */ + switch (code) + { + case ORDERED: ret = "no"; break; + case UNORDERED: ret = "o"; break; + case LT: ret = "n"; break; + case GE: ret = "pz"; break; + case EQ: ret = "eq"; break; + case NE: ret = "ne"; break; + default: gcc_unreachable (); + } + } + else + { + switch (code) + { + case LT: ret = "lt"; break; + case GE: ret = "ge"; break; + case GT: ret = "gt"; break; + case LE: ret = "le"; break; + case GEU: ret = "geu"; break; + case LTU: ret = "ltu"; break; + case GTU: ret = "gtu"; break; + case LEU: ret = "leu"; break; + case EQ: ret = "eq"; break; + case NE: ret = "ne"; break; + default: gcc_unreachable (); + } + gcc_assert ((flags_from_code (code) + & ~flags_from_mode (mode)) == 0); + } + fputs (ret, file); + break; + } case 'C': gcc_assert (CONST_INT_P (op)); @@ -698,51 +807,6 @@ rx_gen_move_template (rtx * operands, bool is_movu) extension, src_template, dst_template); return out_template; } - -/* Returns an assembler template for a conditional branch instruction. */ - -const char * -rx_gen_cond_branch_template (rtx condition, bool reversed) -{ - enum rtx_code code = GET_CODE (condition); - - if (reversed) - { - if (rx_float_compare_mode) - code = reverse_condition_maybe_unordered (code); - else - code = reverse_condition (code); - } - - /* We do not worry about encoding the branch length here as GAS knows - how to choose the smallest version, and how to expand a branch that - is to a destination that is out of range. */ - - switch (code) - { - case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:"; - case LTGT: return "bo\t1f\n\tbne\t%0\n1:"; - case UNLT: return "bo\t1f\n\tbn\t%0\n1:"; - case UNGE: return "bo\t1f\n\tbpz\t%0\n1:"; - case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:"; - case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:"; - case UNORDERED: return "bo\t%0"; - case ORDERED: return "bno\t%0"; - - case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0"; - case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0"; - case GT: return "bgt\t%0"; - case LE: return "ble\t%0"; - case GEU: return "bgeu\t%0"; - case LTU: return "bltu\t%0"; - case GTU: return "bgtu\t%0"; - case LEU: return "bleu\t%0"; - case EQ: return "beq\t%0"; - case NE: return "bne\t%0"; - default: - gcc_unreachable (); - } -} /* Return VALUE rounded up to the next ALIGNMENT boundary. */ @@ -825,7 +889,9 @@ rx_function_value (const_tree ret_type, /* RX ABI specifies that small integer types are promoted to int when returned by a function. */ - if (GET_MODE_SIZE (mode) > 0 && GET_MODE_SIZE (mode) < 4) + if (GET_MODE_SIZE (mode) > 0 + && GET_MODE_SIZE (mode) < 4 + && ! COMPLEX_MODE_P (mode)) return gen_rtx_REG (SImode, FUNC_RETURN_REGNUM); return gen_rtx_REG (mode, FUNC_RETURN_REGNUM); @@ -843,6 +909,7 @@ rx_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, { if (for_return != 1 || GET_MODE_SIZE (mode) >= 4 + || COMPLEX_MODE_P (mode) || GET_MODE_SIZE (mode) < 1) return mode; @@ -1083,7 +1150,13 @@ rx_get_stack_layout (unsigned int * lowest, for (save_mask = high = low = 0, reg = 1; reg < CC_REGNUM; reg++) { - if (df_regs_ever_live_p (reg) + if ((df_regs_ever_live_p (reg) + /* Always save all call clobbered registers inside non-leaf + interrupt handlers, even if they are not live - they may + be used in (non-interrupt aware) routines called from this one. */ + || (call_used_regs[reg] + && is_interrupt_func (NULL_TREE) + && ! current_function_is_leaf)) && (! call_used_regs[reg] /* Even call clobbered registered must be pushed inside interrupt handlers. */ @@ -1238,6 +1311,59 @@ mark_frame_related (rtx insn) } } +static bool +ok_for_max_constant (HOST_WIDE_INT val) +{ + if (rx_max_constant_size == 0 || rx_max_constant_size == 4) + /* If there is no constraint on the size of constants + used as operands, then any value is legitimate. */ + return true; + + /* rx_max_constant_size specifies the maximum number + of bytes that can be used to hold a signed value. */ + return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)), + ( 1 << (rx_max_constant_size * 8))); +} + +/* Generate an ADD of SRC plus VAL into DEST. + Handles the case where VAL is too big for max_constant_value. + Sets FRAME_RELATED_P on the insn if IS_FRAME_RELATED is true. */ + +static void +gen_safe_add (rtx dest, rtx src, rtx val, bool is_frame_related) +{ + rtx insn; + + if (val == NULL_RTX || INTVAL (val) == 0) + { + gcc_assert (dest != src); + + insn = emit_move_insn (dest, src); + } + else if (ok_for_max_constant (INTVAL (val))) + insn = emit_insn (gen_addsi3 (dest, src, val)); + else + { + /* Wrap VAL in an UNSPEC so that rx_is_legitimate_constant + will not reject it. */ + val = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_CONST)); + insn = emit_insn (gen_addsi3 (dest, src, val)); + + if (is_frame_related) + /* We have to provide our own frame related note here + as the dwarf2out code cannot be expected to grok + our unspec. */ + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (SImode, dest, + gen_rtx_PLUS (SImode, src, val))); + return; + } + + if (is_frame_related) + RTX_FRAME_RELATED_P (insn) = 1; + return; +} + void rx_expand_prologue (void) { @@ -1323,23 +1449,12 @@ rx_expand_prologue (void) emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD), gen_rx_store_vector (acc_low, acc_high))); } - - frame_size += 2 * UNITS_PER_WORD; } /* If needed, set up the frame pointer. */ if (frame_pointer_needed) - { - if (frame_size) - insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, - GEN_INT (- (HOST_WIDE_INT) frame_size))); - else - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - - RTX_FRAME_RELATED_P (insn) = 1; - } - - insn = NULL_RTX; + gen_safe_add (frame_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size), true); /* Allocate space for the outgoing args. If the stack frame has not already been set up then handle this as well. */ @@ -1348,29 +1463,26 @@ rx_expand_prologue (void) if (frame_size) { if (frame_pointer_needed) - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx, - GEN_INT (- (HOST_WIDE_INT) - stack_size))); + gen_safe_add (stack_pointer_rtx, frame_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) stack_size), true); else - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (- (HOST_WIDE_INT) - (frame_size + stack_size)))); + gen_safe_add (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) (frame_size + stack_size)), + true); } else - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (- (HOST_WIDE_INT) stack_size))); + gen_safe_add (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) stack_size), true); } else if (frame_size) { if (! frame_pointer_needed) - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (- (HOST_WIDE_INT) frame_size))); + gen_safe_add (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size), true); else - insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + gen_safe_add (stack_pointer_rtx, frame_pointer_rtx, NULL_RTX, + true); } - - if (insn != NULL_RTX) - RTX_FRAME_RELATED_P (insn) = 1; } static void @@ -1548,8 +1660,8 @@ rx_expand_epilogue (bool is_sibcall) { /* Cannot use the special instructions - deconstruct by hand. */ if (total_size) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (total_size))); + gen_safe_add (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size), false); if (MUST_SAVE_ACC_REGISTER) { @@ -1640,8 +1752,8 @@ rx_expand_epilogue (bool is_sibcall) return; } - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (total_size))); + gen_safe_add (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size), false); } if (low) @@ -1918,7 +2030,7 @@ rx_expand_builtin_mvtipl (rtx arg) if (rx_cpu_type == RX610) return NULL_RTX; - if (! CONST_INT_P (arg) || ! IN_RANGE (arg, 0, (1 << 4) - 1)) + if (! CONST_INT_P (arg) || ! IN_RANGE (INTVAL (arg), 0, (1 << 4) - 1)) return NULL_RTX; emit_insn (gen_mvtipl (arg)); @@ -1987,6 +2099,31 @@ rx_expand_builtin_round (rtx arg, rtx target) return target; } +static int +valid_psw_flag (rtx op, const char *which) +{ + static int mvtc_inform_done = 0; + + if (GET_CODE (op) == CONST_INT) + switch (INTVAL (op)) + { + case 0: case 'c': case 'C': + case 1: case 'z': case 'Z': + case 2: case 's': case 'S': + case 3: case 'o': case 'O': + case 8: case 'i': case 'I': + case 9: case 'u': case 'U': + return 1; + } + + error ("__builtin_rx_%s takes 'C', 'Z', 'S', 'O', 'I', or 'U'", which); + if (!mvtc_inform_done) + error ("use __builtin_rx_mvtc (0, ... ) to write arbitrary values to PSW"); + mvtc_inform_done = 1; + + return 0; +} + static rtx rx_expand_builtin (tree exp, rtx target, @@ -2002,10 +2139,14 @@ rx_expand_builtin (tree exp, switch (fcode) { case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX; - case RX_BUILTIN_CLRPSW: return rx_expand_void_builtin_1_arg - (op, gen_clrpsw, false); - case RX_BUILTIN_SETPSW: return rx_expand_void_builtin_1_arg - (op, gen_setpsw, false); + case RX_BUILTIN_CLRPSW: + if (! valid_psw_flag (op, "clrpsw")) + return NULL_RTX; + return rx_expand_void_builtin_1_arg (op, gen_clrpsw, false); + if (! valid_psw_flag (op, "setpsw")) + return NULL_RTX; + return rx_expand_void_builtin_1_arg (op, gen_setpsw, false); + case RX_BUILTIN_SETPSW: case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg (op, gen_int, false); case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi); @@ -2211,7 +2352,6 @@ rx_set_optimization_options (void) error ("Changing the FPU insns/math optimizations pairing is not supported"); } } - static bool rx_allocate_stack_slots_for_args (void) @@ -2258,50 +2398,10 @@ rx_file_start (void) static bool rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) { - return TRUE; + /* The packed attribute overrides the MS behaviour. */ + return ! TYPE_PACKED (record_type); } -/* Try to generate code for the "isnv" pattern which inserts bits - into a word. - operands[0] => Location to be altered. - operands[1] => Number of bits to change. - operands[2] => Starting bit. - operands[3] => Value to insert. - Returns TRUE if successful, FALSE otherwise. */ - -bool -rx_expand_insv (rtx * operands) -{ - if (INTVAL (operands[1]) != 1 - || ! CONST_INT_P (operands[3])) - return false; - - if (MEM_P (operands[0]) - && INTVAL (operands[2]) > 7) - return false; - - switch (INTVAL (operands[3])) - { - case 0: - if (MEM_P (operands[0])) - emit_insn (gen_bitclr_in_memory (operands[0], operands[0], - operands[2])); - else - emit_insn (gen_bitclr (operands[0], operands[0], operands[2])); - break; - case 1: - case -1: - if (MEM_P (operands[0])) - emit_insn (gen_bitset_in_memory (operands[0], operands[0], - operands[2])); - else - emit_insn (gen_bitset (operands[0], operands[0], operands[2])); - break; - default: - return false; - } - return true; -} /* Returns true if X a legitimate constant for an immediate operand on the RX. X is already known to satisfy CONSTANT_P. */ @@ -2309,8 +2409,6 @@ rx_expand_insv (rtx * operands) bool rx_is_legitimate_constant (rtx x) { - HOST_WIDE_INT val; - switch (GET_CODE (x)) { case CONST: @@ -2333,7 +2431,9 @@ rx_is_legitimate_constant (rtx x) case SYMBOL_REF: return true; - /* One day we may have to handle UNSPEC constants here. */ + case UNSPEC: + return XINT (x, 1) == UNSPEC_CONST; + default: /* FIXME: Can this ever happen ? */ abort (); @@ -2353,17 +2453,7 @@ rx_is_legitimate_constant (rtx x) break; } - if (rx_max_constant_size == 0 || rx_max_constant_size == 4) - /* If there is no constraint on the size of constants - used as operands, then any value is legitimate. */ - return true; - - val = INTVAL (x); - - /* rx_max_constant_size specifies the maximum number - of bytes that can be used to hold a signed value. */ - return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)), - ( 1 << (rx_max_constant_size * 8))); + return ok_for_max_constant (INTVAL (x)); } static int @@ -2487,211 +2577,83 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) } } +/* Return a CC_MODE of which both M1 and M2 are subsets. */ + static enum machine_mode rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) { - if (m1 == CCmode) - return m2; - if (m2 == CCmode) - return m1; + unsigned f; + + /* Early out for identical modes. */ if (m1 == m2) return m1; - if (m1 == CC_ZSmode) - return m1; - if (m2 == CC_ZSmode) - return m2; - return VOIDmode; + + /* There's no valid combination for FP vs non-FP. */ + f = flags_from_mode (m1) | flags_from_mode (m2); + if (f & CC_FLAG_FP) + return VOIDmode; + + /* Otherwise, see what mode can implement all the flags. */ + return mode_from_flags (f); } -#define CC_FLAG_S (1 << 0) -#define CC_FLAG_Z (1 << 1) -#define CC_FLAG_O (1 << 2) -#define CC_FLAG_C (1 << 3) +/* Return the minimal CC mode needed to implement (CMP_CODE X Y). */ -static unsigned int -flags_needed_for_conditional (rtx conditional) +enum machine_mode +rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y ATTRIBUTE_UNUSED) { - switch (GET_CODE (conditional)) - { - case LE: - case GT: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; - - case LEU: - case GTU: return CC_FLAG_Z | CC_FLAG_C; + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + return CC_Fmode; - case LT: - case GE: return CC_FLAG_S | CC_FLAG_O; + return mode_from_flags (flags_from_code (cmp_code)); +} - case LTU: - case GEU: return CC_FLAG_C; +/* Split the conditional branch. Emit (COMPARE C1 C2) into CC_REG with + CC_MODE, and use that in branches based on that compare. */ - case EQ: - case NE: return CC_FLAG_Z; +void +rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1, + rtx c1, rtx c2, rtx label) +{ + rtx flags, x; - default: gcc_unreachable (); - } -} + flags = gen_rtx_REG (cc_mode, CC_REG); + x = gen_rtx_COMPARE (cc_mode, c1, c2); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); -static unsigned int -flags_from_mode (enum machine_mode mode) -{ - switch (mode) - { - case CCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C; - case CC_ZSmode: return CC_FLAG_S | CC_FLAG_Z; - case CC_ZSOmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; - case CC_ZSCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C; - default: gcc_unreachable (); - } + x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); } -/* Returns true if a compare insn is redundant because it - would only set flags that are already set correctly. */ +/* A helper function for matching parallels that set the flags. */ bool -rx_compare_redundant (rtx cmp) -{ - unsigned int flags_needed; - unsigned int flags_set; - rtx next; - rtx prev; - rtx source; - rtx dest; - static rtx cc_reg = NULL_RTX; - - if (cc_reg == NULL_RTX) - cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); - - /* We can only eliminate compares against 0. */ - if (GET_CODE (XEXP (SET_SRC (PATTERN (cmp)), 1)) != CONST_INT - || INTVAL (XEXP (SET_SRC (PATTERN (cmp)), 1)) != 0) - return false; - - /* Locate the branch insn that follows the - compare and which tests the bits in the PSW. */ - next = cmp; - do - { - /* If we have found an insn that sets or clobbers the CC - register and it was not the IF_THEN_ELSE insn that we - are looking for, then the comparison is redundant. */ - if (next != cmp && reg_mentioned_p (cc_reg, PATTERN (next))) - return true; - - next = next_nonnote_insn (next); - - /* If we run out of insns without finding the - user then the comparison is unnecessary. */ - if (next == NULL_RTX) - return true; - - /* If we have found another comparison - insn then the first one is redundant. */ - if (INSN_P (next) - && GET_CODE (PATTERN (next)) == SET - && REG_P (SET_DEST (PATTERN (next))) - && REGNO (SET_DEST (PATTERN (next))) == CC_REGNUM) - return true; +rx_match_ccmode (rtx insn, enum machine_mode cc_mode) +{ + rtx op1, flags; + enum machine_mode flags_mode; - /* If we have found another arithmetic/logic insn that - sets the PSW flags then the comparison is redundant. */ - if (INSN_P (next) - && GET_CODE (PATTERN (next)) == PARALLEL - && GET_CODE (XVECEXP (PATTERN (next), 0, 1)) == SET - && REG_P (SET_DEST (XVECEXP (PATTERN (next), 0, 1))) - && REGNO (SET_DEST (XVECEXP (PATTERN (next), 0, 1))) == CC_REGNUM) - return true; + gcc_assert (XVECLEN (PATTERN (insn), 0) == 2); - /* If we have found an unconditional branch then the - PSW flags might be carried along with the jump, so - the comparison is necessary. */ - if (INSN_P (next) && JUMP_P (next)) - { - if (GET_CODE (PATTERN (next)) != SET) - /* If the jump does not involve setting the PC - then it is a return of some kind, and we know - that the comparison is not used. */ - return true; + op1 = XVECEXP (PATTERN (insn), 0, 1); + gcc_assert (GET_CODE (SET_SRC (op1)) == COMPARE); - if (GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE) - return false; - } - } - while (! INSN_P (next) - || DEBUG_INSN_P (next) - || GET_CODE (PATTERN (next)) != SET - || GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE); - - flags_needed = flags_needed_for_conditional (XEXP (SET_SRC (PATTERN (next)), 0)); - - /* Now look to see if there was a previous - instruction which set the PSW bits. */ - source = XEXP (SET_SRC (PATTERN (cmp)), 0); - prev = cmp; - do - { - /* If this insn uses/sets/clobbers the CC register - and it is not the insn that we are looking for - below, then we must need the comparison. */ - if (prev != cmp && reg_mentioned_p (cc_reg, PATTERN (prev))) - return false; - - prev = prev_nonnote_insn (prev); + flags = SET_DEST (op1); + flags_mode = GET_MODE (flags); - if (prev == NULL_RTX) - return false; - - /* If we encounter an insn which changes the contents of - the register which is the source of the comparison then - we will definitely need the comparison. */ - if (INSN_P (prev) - && GET_CODE (PATTERN (prev)) == SET - && rtx_equal_p (SET_DEST (PATTERN (prev)), source)) - { - /* Unless this instruction is a simple register move - instruction. In which case we can continue our - scan backwards, but now using the *source* of this - set instruction. */ - if (REG_P (SET_SRC (PATTERN (prev)))) - source = SET_SRC (PATTERN (prev)); - /* We can also survive a sign-extension if the test is - for EQ/NE. Note the same does not apply to zero- - extension as this can turn a non-zero bit-pattern - into zero. */ - else if (flags_needed == CC_FLAG_Z - && GET_CODE (SET_SRC (PATTERN (prev))) == SIGN_EXTEND) - source = XEXP (SET_SRC (PATTERN (prev)), 0); - else - return false; - } + if (GET_MODE (SET_SRC (op1)) != flags_mode) + return false; + if (GET_MODE_CLASS (flags_mode) != MODE_CC) + return false; - /* A label means a possible branch into the - code here, so we have to stop scanning. */ - if (LABEL_P (prev)) - return false; - } - while (! INSN_P (prev) - || DEBUG_INSN_P (prev) - || GET_CODE (PATTERN (prev)) != PARALLEL - || GET_CODE (XVECEXP (PATTERN (prev), 0, 1)) != SET - || ! REG_P (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))) - || REGNO (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))) != CC_REGNUM); - - flags_set = flags_from_mode (GET_MODE (SET_DEST (XVECEXP (PATTERN (prev), 0, 1)))); - - dest = SET_DEST (XVECEXP (PATTERN (prev), 0, 0)); - /* The destination of the previous arithmetic/logic instruction - must match the source in the comparison operation. For registers - we ignore the mode as there may have been a sign-extension involved. */ - if (! rtx_equal_p (source, dest)) - { - if (REG_P (source) && REG_P (dest) && REGNO (dest) == REGNO (source)) - ; - else - return false; - } + /* Ensure that the mode of FLAGS is compatible with CC_MODE. */ + if (flags_from_mode (flags_mode) & ~flags_from_mode (cc_mode)) + return false; - return ((flags_set & flags_needed) == flags_needed); + return true; } #undef TARGET_FUNCTION_VALUE diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h index fae30a0a028d..85e911916cf3 100644 --- a/gcc/config/rx/rx.h +++ b/gcc/config/rx/rx.h @@ -1,5 +1,5 @@ /* GCC backend definitions for the Renesas RX processor. - Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -25,7 +25,10 @@ builtin_define ("__RX__"); \ builtin_assert ("cpu=RX"); \ if (rx_cpu_type == RX610) \ - builtin_assert ("machine=RX610"); \ + { \ + builtin_define ("__RX610__"); \ + builtin_assert ("machine=RX610"); \ + } \ else \ builtin_assert ("machine=RX600"); \ \ @@ -144,6 +147,10 @@ extern enum rx_cpu_types rx_cpu_type; #define SIZE_TYPE "long unsigned int" #undef PTRDIFF_TYPE #define PTRDIFF_TYPE "long int" +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD #define POINTERS_EXTEND_UNSIGNED 1 #define FUNCTION_MODE QImode #define CASE_VECTOR_MODE Pmode @@ -260,6 +267,7 @@ enum reg_class #define LIBCALL_VALUE(MODE) \ gen_rtx_REG (((GET_MODE_CLASS (MODE) != MODE_INT \ + || COMPLEX_MODE_P (MODE) \ || GET_MODE_SIZE (MODE) >= 4) \ ? (MODE) \ : SImode), \ @@ -354,7 +362,7 @@ typedef unsigned int CUMULATIVE_ARGS; { \ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc" \ - }; + } #define ADDITIONAL_REGISTER_NAMES \ { \ @@ -616,8 +624,6 @@ typedef unsigned int CUMULATIVE_ARGS; #define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ rx_print_operand_address (FILE, ADDR) -extern int rx_float_compare_mode; - /* This is a version of REG_P that also returns TRUE for SUBREGs. */ #define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG) @@ -655,12 +661,5 @@ extern int rx_float_compare_mode; #define REGISTER_MOVE_COST(MODE, FROM, TO) 2 #define MEMORY_MOVE_COST(MODE, REGCLASS, IN) (2 + memory_move_secondary_cost (MODE, REGCLASS, IN)) -#define SELECT_CC_MODE(OP,X,Y) \ - (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CC_ZSmode : \ - (GET_CODE (X) == PLUS || GET_CODE (X) == MINUS ? CC_ZSCmode : \ - (GET_CODE (X) == ABS ? CC_ZSOmode : \ - (GET_CODE (X) == AND || GET_CODE (X) == NOT || GET_CODE (X) == IOR \ - || GET_CODE (X) == XOR || GET_CODE (X) == ROTATE \ - || GET_CODE (X) == ROTATERT || GET_CODE (X) == ASHIFTRT \ - || GET_CODE (X) == LSHIFTRT || GET_CODE (X) == ASHIFT ? CC_ZSmode : \ - CCmode)))) +#define SELECT_CC_MODE(OP,X,Y) rx_select_cc_mode ((OP), (X), (Y)) + diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 370f959e16a2..c33fa2f0b772 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -1,5 +1,5 @@ ;; Machine Description for Renesas RX processors -;; Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. +;; Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; This file is part of GCC. @@ -19,14 +19,6 @@ ;; . -;; This code iterator allows all branch instructions to -;; be generated from a single define_expand template. -(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu - unordered ordered ]) - -;; Likewise, but only the ones that use Z or S. -(define_code_iterator zs_cond [eq ne gtu geu ltu leu ]) - ;; This code iterator is used for sign- and zero- extensions. (define_mode_iterator small_int_modes [(HI "") (QI "")]) @@ -38,15 +30,6 @@ [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")]) -;; Used to map RX condition names to GCC -;; condition names for builtin instructions. -(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu - unge unlt uneq ltgt]) -(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt") - (le "le") (gtu "gtu") (geu "geu") (ltu "ltu") - (leu "leu") (unge "pz") (unlt "n") (uneq "o") - (ltgt "no")]) - (define_constants [ (SP_REG 0) @@ -58,6 +41,7 @@ (UNSPEC_RTE 10) (UNSPEC_RTFI 11) (UNSPEC_NAKED 12) + (UNSPEC_CONST 13) (UNSPEC_MOVSTR 20) (UNSPEC_MOVMEM 21) @@ -150,6 +134,8 @@ (define_insn_reservation "throughput_18_latency_18" 1 (eq_attr "timings" "1818") "throughput*18") +;; ---------------------------------------------------------------------------- + ;; Comparisons ;; Note - we do not specify the two instructions necessary to perform @@ -160,254 +146,164 @@ (define_expand "cbranchsi4" [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:SI 1 "register_operand") - (match_operand:SI 2 "rx_source_operand")]) - (label_ref (match_operand 3 "")) - (pc))) - ] - "" + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] "" ) -(define_insn_and_split "*cbranchsi4_" +(define_insn_and_split "*cbranchsi4" [(set (pc) - (if_then_else (most_cond (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (label_ref (match_operand 2 "" "")) - (pc))) - ] + (if_then_else + (match_operator 3 "comparison_operator" + [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "" "#" "reload_completed" [(const_int 0)] - " - /* We contstruct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_cmpsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) +{ + rx_split_cbranch (CCmode, GET_CODE (operands[3]), + operands[0], operands[1], operands[2]); + DONE; +}) -;; ----------------------------------------------------------------------------- -;; These two are the canonical TST/branch insns. However, GCC -;; generates a wide variety of tst-like patterns, we catch those -;; below. -(define_insn_and_split "*tstbranchsi4_" - [(set (pc) - (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (const_int 0)) - (label_ref (match_operand 2 "" "")) - (pc))) - ] - "" - "#" +(define_insn "*cmpsi" + [(set (reg:CC CC_REG) + (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))] "reload_completed" - [(const_int 0)] - " - emit_insn (gen_tstsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " + "cmp\t%Q1, %0" + [(set_attr "timings" "11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,5")] ) -;; Inverse of above -(define_insn_and_split "*tstbranchsi4_" +;; Canonical method for representing TST. +(define_insn_and_split "*cbranchsi4_tst" [(set (pc) - (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (const_int 0)) - (pc) - (label_ref (match_operand 2 "" "")))) - ] + (if_then_else + (match_operator 3 "rx_zs_comparison_operator" + [(and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")) + (const_int 0)]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "" "#" "reload_completed" [(const_int 0)] - " - emit_insn (gen_tstsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (reverse_condition (), CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) +{ + rx_split_cbranch (CC_ZSmode, GET_CODE (operands[3]), + XEXP (operands[3], 0), XEXP (operands[3], 1), + operands[2]); + DONE; +}) ;; Various other ways that GCC codes "var & const" - -(define_insn_and_split "*tstbranchsi4m_eq" +(define_insn_and_split "*cbranchsi4_tst_ext" [(set (pc) - (if_then_else (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r") - (match_operand 1 "rx_constshift_operand" "i") - (match_operand 2 "rx_constshift_operand" "i")) - (const_int 0)) - (label_ref (match_operand 3 "" "")) - (pc))) - ] - "" - "#" - "" - [(set (pc) - (if_then_else (eq (and:SI (match_dup 0) - (match_dup 4)) - (const_int 0)) - (label_ref (match_dup 3)) - (pc))) - ] - "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" -) - -(define_insn_and_split "*tstbranchsi4m_ne" - [(set (pc) - (if_then_else (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r") - (match_operand 1 "rx_constshift_operand" "i") - (match_operand 2 "rx_constshift_operand" "i")) - (const_int 0)) - (label_ref (match_operand 3 "" "")) - (pc))) - ] + (if_then_else + (match_operator 4 "rx_z_comparison_operator" + [(zero_extract:SI + (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_constshift_operand" "") + (match_operand:SI 2 "rx_constshift_operand" "")) + (const_int 0)]) + (match_operand 3 "label_ref_operand" "") + (pc)))] "" "#" - "" - [(set (pc) - (if_then_else (ne (and:SI (match_dup 0) - (match_dup 4)) - (const_int 0)) - (label_ref (match_dup 3)) - (pc))) - ] - "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" + "reload_completed" + [(const_int 0)] +{ + HOST_WIDE_INT mask; + rtx x; + + mask = 1; + mask <<= INTVAL (operands[1]); + mask -= 1; + mask <<= INTVAL (operands[2]); + x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode)); + + rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]), + x, const0_rtx, operands[3]); + DONE; +}) + +(define_insn "*tstsi" + [(set (reg:CC_ZS CC_REG) + (compare:CC_ZS + (and:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "rx_source_operand" "r,i,Q")) + (const_int 0)))] + "reload_completed" + "tst\t%Q1, %0" + [(set_attr "timings" "11,11,33") + (set_attr "length" "3,7,6")] ) -;; ----------------------------------------------------------------------------- - (define_expand "cbranchsf4" [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:SF 1 "register_operand") - (match_operand:SF 2 "rx_source_operand")]) - (label_ref (match_operand 3 "")) - (pc))) - ] + (if_then_else + (match_operator 0 "rx_fp_comparison_operator" + [(match_operand:SF 1 "register_operand") + (match_operand:SF 2 "rx_source_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] "ALLOW_RX_FPU_INSNS" - "" ) -(define_insn_and_split "*cbranchsf4_" +(define_insn_and_split "*cbranchsf4" [(set (pc) - (if_then_else (most_cond (match_operand:SF 0 "register_operand" "r") - (match_operand:SF 1 "rx_source_operand" "rFiQ")) - (label_ref (match_operand 2 "" "")) - (pc))) - ] + (if_then_else + (match_operator 3 "rx_fp_comparison_operator" + [(match_operand:SF 0 "register_operand" "r") + (match_operand:SF 1 "rx_source_operand" "rFQ")]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "ALLOW_RX_FPU_INSNS" "#" "&& reload_completed" [(const_int 0)] - " - /* We contstruct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_cmpsf (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) - -(define_insn "tstsi" - [(set (reg:CC_ZS CC_REG) - (compare:CC_ZS (and:SI (match_operand:SI 0 "register_operand" "r,r,r") - (match_operand:SI 1 "rx_source_operand" "r,i,Q")) - (const_int 0)))] - "" - { - rx_float_compare_mode = false; - return "tst\t%Q1, %0"; - } - [(set_attr "timings" "11,11,33") - (set_attr "length" "3,7,6")] -) - -(define_insn "cmpsi" - [(set (reg:CC CC_REG) - (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") - (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))] - "" - { - rx_float_compare_mode = false; - if (rx_compare_redundant (insn)) - return "; Compare Eliminated: cmp %Q1, %0"; - return "cmp\t%Q1, %0"; - } - [(set_attr "timings" "11,11,11,11,11,11,33") - (set_attr "length" "2,2,3,4,5,6,5")] -) - -;; This pattern is disabled when -fnon-call-exceptions is active because -;; it could generate a floating point exception, which would introduce an -;; edge into the flow graph between this insn and the conditional branch -;; insn to follow, thus breaking the cc0 relationship. Run the g++ test -;; g++.dg/eh/080514-1.C to see this happen. -(define_insn "cmpsf" - [(set (reg:CC_ZSO CC_REG) - (compare:CC_ZSO (match_operand:SF 0 "register_operand" "r,r,r") - (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))] - "ALLOW_RX_FPU_INSNS" - { - rx_float_compare_mode = true; - return "fcmp\t%1, %0"; - } +{ + rx_split_cbranch (CC_Fmode, GET_CODE (operands[3]), + operands[0], operands[1], operands[2]); + DONE; +}) + +(define_insn "*cmpsf" + [(set (reg:CC_F CC_REG) + (compare:CC_F + (match_operand:SF 0 "register_operand" "r,r,r") + (match_operand:SF 1 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS && reload_completed" + "fcmp\t%1, %0" [(set_attr "timings" "11,11,33") (set_attr "length" "3,7,5")] ) ;; Flow Control Instructions: -(define_expand "b" +(define_insn "*conditional_branch" [(set (pc) - (if_then_else (most_cond (reg:CC CC_REG) (const_int 0)) - (label_ref (match_operand 0)) - (pc)))] - "" - "" -) - -(define_insn "conditional_branch" - [(set (pc) - (if_then_else (match_operator 1 "comparison_operator" - [(reg:CC CC_REG) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - { - return rx_gen_cond_branch_template (operands[1], false); - } + (if_then_else + (match_operator 1 "comparison_operator" + [(reg CC_REG) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "reload_completed" + "b%B1\t%0" [(set_attr "length" "8") ;; This length is wrong, but it is ;; too hard to compute statically. (set_attr "timings" "33")] ;; The timing assumes that the branch is taken. ) -(define_insn "*reveresed_conditional_branch" - [(set (pc) - (if_then_else (match_operator 1 "comparison_operator" - [(reg:CC CC_REG) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - { - return rx_gen_cond_branch_template (operands[1], true); - } - [(set_attr "length" "8") ;; This length is wrong, but it is - ;; too hard to compute statically. - (set_attr "timings" "33")] ;; The timing assumes that the branch is taken. -) +;; ---------------------------------------------------------------------------- (define_insn "jump" [(set (pc) @@ -448,10 +344,12 @@ (set_attr "timings" "55")] ) +;; Unspec used so that the constant will not be invalid +;; if -mmax-constant-size has been specified. (define_insn "deallocate_and_return" [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 0 "immediate_operand" "i"))) + (const:SI (unspec:SI [(match_operand 0 "const_int_operand" "n")] UNSPEC_CONST)))) (return)] "" "rtsd\t%0" @@ -461,9 +359,10 @@ (define_insn "pop_and_return" [(match_parallel 1 "rx_rtsd_vector" - [(set:SI (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) - (match_operand:SI 0 "const_int_operand" "n")))])] + [(set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 0 "const_int_operand" "n")))]) + (return)] "reload_completed" { rx_emit_stack_popm (operands, false); @@ -513,14 +412,14 @@ if (! rx_call_operand (dest, Pmode)) dest = force_reg (Pmode, dest); - emit_call_insn (gen_call_internal (dest, operands[1])); + emit_call_insn (gen_call_internal (dest)); DONE; } ) (define_insn "call_internal" [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol")) - (match_operand:SI 1 "general_operand" "g,g")) + (const_int 0)) (clobber (reg:CC CC_REG))] "" "@ @@ -540,7 +439,7 @@ if (! rx_call_operand (dest, Pmode)) dest = force_reg (Pmode, dest); - emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2])); + emit_call_insn (gen_call_value_internal (operands[0], dest)); DONE; } ) @@ -548,7 +447,7 @@ (define_insn "call_value_internal" [(set (match_operand 0 "register_operand" "=r,r") (call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol")) - (match_operand:SI 2 "general_operand" "g,g"))) + (const_int 0))) (clobber (reg:CC CC_REG))] "" "@ @@ -572,12 +471,14 @@ { if (MEM_P (operands[0])) operands[0] = XEXP (operands[0], 0); + emit_call_insn (gen_sibcall_internal (operands[0])); + DONE; } ) (define_insn "sibcall_internal" [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) - (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) (return)] "" "bra\t%A0" @@ -595,13 +496,15 @@ { if (MEM_P (operands[1])) operands[1] = XEXP (operands[1], 0); + emit_call_insn (gen_sibcall_value_internal (operands[0], operands[1])); + DONE; } ) (define_insn "sibcall_value_internal" [(set (match_operand 0 "register_operand" "=r") (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) - (match_operand:SI 2 "general_operand" "g"))) + (const_int 0))) (return)] "" "bra\t%A1" @@ -653,6 +556,9 @@ { if (MEM_P (operand0) && MEM_P (operand1)) operands[1] = copy_to_mode_reg (mode, operand1); + if (CONST_INT_P (operand1) + && ! rx_is_legitimate_constant (operand1)) + FAIL; } ) @@ -688,11 +594,11 @@ ) (define_insn "stack_push" - [(set:SI (reg:SI SP_REG) - (minus:SI (reg:SI SP_REG) - (const_int 4))) - (set:SI (mem:SI (reg:SI SP_REG)) - (match_operand:SI 0 "register_operand" "r"))] + [(set (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (const_int 4))) + (set (mem:SI (reg:SI SP_REG)) + (match_operand:SI 0 "register_operand" "r"))] "" "push.l\t%0" [(set_attr "length" "2")] @@ -700,9 +606,9 @@ (define_insn "stack_pushm" [(match_parallel 1 "rx_store_multiple_vector" - [(set:SI (reg:SI SP_REG) - (minus:SI (reg:SI SP_REG) - (match_operand:SI 0 "const_int_operand" "n")))])] + [(set (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (match_operand:SI 0 "const_int_operand" "n")))])] "reload_completed" { rx_emit_stack_pushm (operands); @@ -713,11 +619,11 @@ ) (define_insn "stack_pop" - [(set:SI (match_operand:SI 0 "register_operand" "=r") - (mem:SI (reg:SI SP_REG))) - (set:SI (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) - (const_int 4)))] + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (reg:SI SP_REG))) + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (const_int 4)))] "" "pop\t%0" [(set_attr "length" "2") @@ -726,9 +632,9 @@ (define_insn "stack_popm" [(match_parallel 1 "rx_load_multiple_vector" - [(set:SI (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) - (match_operand:SI 0 "const_int_operand" "n")))])] + [(set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 0 "const_int_operand" "n")))])] "reload_completed" { rx_emit_stack_popm (operands, true); @@ -738,79 +644,161 @@ (set_attr "timings" "45")] ;; The timing is a guesstimate average timing. ) -;; FIXME: Add memory destination options ? -(define_insn "cstoresi4" - [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") +(define_insn_and_split "cstoresi4" + [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "comparison_operator" - [(match_operand:SI 2 "register_operand" "r,r,r,r,r,r,r") - (match_operand:SI 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")])) - (clobber (reg:CC CC_REG))] ;; Because the cc flags are set based on comparing ops 2 & 3 not the value in op 0. + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "rx_source_operand" "riQ")])) + (clobber (reg:CC CC_REG))] "" - { - rx_float_compare_mode = false; - return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0"; - } - [(set_attr "timings" "22,22,22,22,22,22,44") - (set_attr "length" "5,5,6,7,8,9,8")] + "#" + "reload_completed" + [(const_int 0)] +{ + rtx flags, x; + + flags = gen_rtx_REG (CCmode, CC_REG); + x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx); + x = gen_rtx_SET (VOIDmode, operands[0], x); + emit_insn (x); + DONE; +}) + +(define_insn "*sccc" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operator:SI 1 "comparison_operator" + [(reg CC_REG) (const_int 0)]))] + "reload_completed" + "sc%B1.L\t%0" + [(set_attr "length" "3")] ) +(define_insn_and_split "cstoresf4" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operator:SI 1 "rx_fp_comparison_operator" + [(match_operand:SF 2 "register_operand" "r") + (match_operand:SF 3 "rx_source_operand" "rFQ")]))] + "ALLOW_RX_FPU_INSNS" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx flags, x; + + flags = gen_rtx_REG (CC_Fmode, CC_REG); + x = gen_rtx_COMPARE (CC_Fmode, operands[2], operands[3]); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx); + x = gen_rtx_SET (VOIDmode, operands[0], x); + emit_insn (x); + DONE; +}) + (define_expand "movsicc" [(parallel [(set (match_operand:SI 0 "register_operand") (if_then_else:SI (match_operand:SI 1 "comparison_operator") (match_operand:SI 2 "nonmemory_operand") - (match_operand:SI 3 "immediate_operand"))) - (clobber (reg:CC CC_REG))])] ;; See cstoresi4 + (match_operand:SI 3 "nonmemory_operand"))) + (clobber (reg:CC CC_REG))])] "" - { - if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) - FAIL; - if (! CONST_INT_P (operands[3])) - FAIL; - } +{ + /* ??? Support other conditions via cstore into a temporary? */ + if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) + FAIL; + /* One operand must be a constant. */ + if (!CONSTANT_P (operands[2]) && !CONSTANT_P (operands[3])) + FAIL; +}) + +(define_insn_and_split "*movsicc" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI + (match_operator 5 "rx_z_comparison_operator" + [(match_operand:SI 3 "register_operand" "r,r") + (match_operand:SI 4 "rx_source_operand" "riQ,riQ")]) + (match_operand:SI 1 "nonmemory_operand" "i,ri") + (match_operand:SI 2 "nonmemory_operand" "ri,i"))) + (clobber (reg:CC CC_REG))] + "CONSTANT_P (operands[1]) || CONSTANT_P (operands[2])" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx x, flags, op0, op1, op2; + enum rtx_code cmp_code; + + flags = gen_rtx_REG (CCmode, CC_REG); + x = gen_rtx_COMPARE (CCmode, operands[3], operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, flags, x)); + + cmp_code = GET_CODE (operands[5]); + op0 = operands[0]; + op1 = operands[1]; + op2 = operands[2]; + + /* If OP2 is the constant, reverse the sense of the move. */ + if (!CONSTANT_P (operands[1])) + { + x = op1, op1 = op2, op2 = x; + cmp_code = reverse_condition (cmp_code); + } + + /* If OP2 does not match the output, copy it into place. We have allowed + these alternatives so that the destination can legitimately be one of + the comparison operands without increasing register pressure. */ + if (!rtx_equal_p (op0, op2)) + emit_move_insn (op0, op2); + + x = gen_rtx_fmt_ee (cmp_code, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (SImode, x, op1, op0); + emit_insn (gen_rtx_SET (VOIDmode, op0, x)); + DONE; +}) + +(define_insn "*stcc" + [(set (match_operand:SI 0 "register_operand" "+r,r,r,r") + (if_then_else:SI + (match_operator 2 "rx_z_comparison_operator" + [(reg CC_REG) (const_int 0)]) + (match_operand:SI 1 "immediate_operand" "Sint08,Sint16,Sint24,i") + (match_dup 0)))] + "reload_completed" +{ + if (GET_CODE (operands[2]) == EQ) + return "stz\t%1, %0"; + else + return "stnz\t%1, %0"; +} + [(set_attr "length" "4,5,6,7")] ) -(define_insn "*movsieq" - [(set (match_operand:SI 0 "register_operand" "=r,r,r") - (if_then_else:SI (eq (match_operand:SI 3 "register_operand" "r,r,r") - (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ")) - (match_operand:SI 1 "nonmemory_operand" "0,i,r") - (match_operand:SI 2 "immediate_operand" "i,i,i"))) - (clobber (reg:CC CC_REG))] ;; See cstoresi4 - "" - "@ - cmp\t%Q4, %Q3\n\tstnz\t%2, %0 - cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0 - cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0" - [(set_attr "length" "13,19,15") - (set_attr "timings" "22,33,33")] -) +;; Arithmetic Instructions -(define_insn "*movsine" - [(set (match_operand:SI 0 "register_operand" "=r,r,r") - (if_then_else:SI (ne (match_operand:SI 3 "register_operand" "r,r,r") - (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ")) - (match_operand:SI 1 "nonmemory_operand" "0,i,r") - (match_operand:SI 2 "immediate_operand" "i,i,i"))) - (clobber (reg:CC CC_REG))] ;; See cstoresi4 +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (abs:SI (match_operand:SI 1 "register_operand" "0,r"))) + (clobber (reg:CC CC_REG))] "" "@ - cmp\t%Q4, %Q3\n\tstz\t%2, %0 - cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0 - cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0" - [(set_attr "length" "13,19,15") - (set_attr "timings" "22,33,33")] + abs\t%0 + abs\t%1, %0" + [(set_attr "length" "2,3")] ) -;; Arithmetic Instructions - -(define_insn "abssi2" +(define_insn "*abssi2_flags" [(set (match_operand:SI 0 "register_operand" "=r,r") (abs:SI (match_operand:SI 1 "register_operand" "0,r"))) - (set (reg:CC_ZSO CC_REG) - (compare:CC_ZSO (abs:SI (match_dup 1)) - (const_int 0)))] - "" + (set (reg CC_REG) + (compare (abs:SI (match_dup 1)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)" "@ abs\t%0 abs\t%1, %0" @@ -821,9 +809,7 @@ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0") (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q"))) - (set (reg:CC_ZSC CC_REG) ;; See subsi3 - (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ add\t%2, %0 @@ -844,27 +830,170 @@ (set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")] ) -(define_insn "adddi3" - [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") - (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0") - (match_operand:DI 2 "rx_source_operand" - "r,Sint08,Sint16,Sint24,i,Q"))) - (set (reg:CC_ZSC CC_REG) ;; See subsi3 - (compare:CC_ZSC (plus:DI (match_dup 1) (match_dup 2)) - (const_int 0)))] - "" - "add\t%L2, %L0\n\tadc\t%H2, %H0" - [(set_attr "timings" "22,22,22,22,22,44") - (set_attr "length" "5,7,9,11,13,11")] +(define_insn "*addsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q"))) + (set (reg CC_REG) + (compare (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" + "@ + add\t%2, %0 + add\t%2, %0 + sub\t%N2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%Q2, %0" + [(set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,11,11,33") + (set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")] ) +;; A helper to expand the above with the CC_MODE filled in. +(define_expand "addsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand") + (plus:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand"))) + (set (reg:CC_ZSC CC_REG) + (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))])] +) + +(define_insn "adc_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (plus:SI + (plus:SI + (ltu:SI (reg:CC CC_REG) (const_int 0)) + (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")) + (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) + (clobber (reg:CC CC_REG))] + "reload_completed" + "adc %2,%0" + [(set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) + +(define_insn "*adc_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (plus:SI + (plus:SI + (ltu:SI (reg:CC CC_REG) (const_int 0)) + (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")) + (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) + (set (reg CC_REG) + (compare + (plus:SI + (plus:SI + (ltu:SI (reg:CC CC_REG) (const_int 0)) + (match_dup 1)) + (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" + "adc %2,%0" + [(set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) + +(define_expand "adddi3" + [(set (match_operand:DI 0 "register_operand") + (plus:DI (match_operand:DI 1 "register_operand") + (match_operand:DI 2 "rx_source_operand")))] + "" +{ + rtx op0l, op0h, op1l, op1h, op2l, op2h; + + op0l = gen_lowpart (SImode, operands[0]); + op1l = gen_lowpart (SImode, operands[1]); + op2l = gen_lowpart (SImode, operands[2]); + op0h = gen_highpart (SImode, operands[0]); + op1h = gen_highpart (SImode, operands[1]); + op2h = gen_highpart_mode (SImode, DImode, operands[2]); + + emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h)); + DONE; +}) + +(define_insn_and_split "adddi3_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "rx_source_operand" "riQ"))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI + (plus:SI + (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2)) + (match_operand:SI 4 "register_operand" "%1")) + (match_operand:SI 5 "rx_source_operand" "riQ"))) + (clobber (match_scratch:SI 6 "=&r")) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx op0l = operands[0]; + rtx op0h = operands[1]; + rtx op1l = operands[2]; + rtx op2l = operands[3]; + rtx op1h = operands[4]; + rtx op2h = operands[5]; + rtx scratch = operands[6]; + rtx x; + + if (reg_overlap_mentioned_p (op0l, op1h)) + { + emit_move_insn (scratch, op0l); + op1h = scratch; + if (reg_overlap_mentioned_p (op0l, op2h)) + op2h = scratch; + } + else if (reg_overlap_mentioned_p (op0l, op2h)) + { + emit_move_insn (scratch, op0l); + op2h = scratch; + } + + if (rtx_equal_p (op0l, op1l)) + ; + /* It is preferable that op0l == op1l... */ + else if (rtx_equal_p (op0l, op2l)) + x = op1l, op1l = op2l, op2l = x; + /* ... but it is only a requirement if op2l == MEM. */ + else if (MEM_P (op2l)) + { + /* Let's hope that we still have a scratch register free. */ + gcc_assert (op1h != scratch); + emit_move_insn (scratch, op2l); + op2l = scratch; + } + + emit_insn (gen_addsi3_flags (op0l, op1l, op2l)); + + if (rtx_equal_p (op0h, op1h)) + ; + else if (rtx_equal_p (op0h, op2h)) + x = op1h, op1h = op2h, op2h = x; + else + { + emit_move_insn (op0h, op1h); + op1h = op0h; + } + emit_insn (gen_adc_internal (op0h, op1h, op2h)); + DONE; +}) + (define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (and:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ and\t%2, %0 @@ -880,9 +1009,31 @@ (set_attr "length" "2,2,3,4,5,6,2,5,5")] ) +(define_insn "*andsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) + (set (reg CC_REG) + (compare (and:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%1, %0 + and\t%2, %1, %0 + and\t%Q2, %0" + [(set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,2,5,5")] +) + ;; Byte swap (single 32-bit value). (define_insn "bswapsi2" - [(set (match_operand:SI 0 "register_operand" "+r") + [(set (match_operand:SI 0 "register_operand" "=r") (bswap:SI (match_operand:SI 1 "register_operand" "r")))] "" "revl\t%1, %0" @@ -891,7 +1042,7 @@ ;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits. (define_insn "bswaphi2" - [(set (match_operand:HI 0 "register_operand" "+r") + [(set (match_operand:HI 0 "register_operand" "=r") (bswap:HI (match_operand:HI 1 "register_operand" "r")))] "" "revw\t%1, %0" @@ -999,12 +1150,23 @@ (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (neg:SI (match_operand:SI 1 "register_operand" "0,r"))) - (set (reg:CC CC_REG) - (compare:CC (neg:SI (match_dup 1)) - (const_int 0)))] - ;; The NEG instruction does not comply with -fwrapv semantics. - ;; See gcc.c-torture/execute/pr22493-1.c for an example of this. - "! flag_wrapv" + (clobber (reg:CC CC_REG))] + "" + "@ + neg\t%0 + neg\t%1, %0" + [(set_attr "length" "2,3")] +) + +;; Note that the O and C flags are not set as per a normal compare, +;; and thus are unusable in that context. +(define_insn "*negsi2_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (neg:SI (match_operand:SI 1 "register_operand" "0,r"))) + (set (reg CC_REG) + (compare (neg:SI (match_dup 1)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" "@ neg\t%0 neg\t%1, %0" @@ -1014,9 +1176,7 @@ (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (not:SI (match_operand:SI 1 "register_operand" "0,r"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (not:SI (match_dup 1)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ not\t%0 @@ -1024,13 +1184,24 @@ [(set_attr "length" "2,3")] ) +(define_insn "*one_cmplsi2_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (not:SI (match_operand:SI 1 "register_operand" "0,r"))) + (set (reg CC_REG) + (compare (not:SI (match_dup 1)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + not\t%0 + not\t%1, %0" + [(set_attr "length" "2,3")] +) + (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (ior:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ or\t%2, %0 @@ -1046,37 +1217,77 @@ (set_attr "length" "2,2,3,4,5,6,2,3,5")] ) +(define_insn "*iorsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) + (set (reg CC_REG) + (compare (ior:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%Q2, %0 + or\t%1, %0 + or\t%2, %1, %0 + or\t%Q2, %0" + [(set_attr "timings" "11,11,11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,2,3,5")] +) + (define_insn "rotlsi3" [(set (match_operand:SI 0 "register_operand" "=r") (rotate:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "rx_shift_operand" "rn"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (rotate:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "rotl\t%2, %0" [(set_attr "length" "3")] ) +(define_insn "*rotlsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn"))) + (set (reg CC_REG) + (compare (rotate:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "rotl\t%2, %0" + [(set_attr "length" "3")] +) + (define_insn "rotrsi3" [(set (match_operand:SI 0 "register_operand" "=r") (rotatert:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "rx_shift_operand" "rn"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (rotatert:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "rotr\t%2, %0" [(set_attr "length" "3")] ) +(define_insn "*rotrsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn"))) + (set (reg CC_REG) + (compare (rotatert:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "rotr\t%2, %0" + [(set_attr "length" "3")] +) + (define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r") (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (ashiftrt:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ shar\t%2, %0 @@ -1085,13 +1296,26 @@ [(set_attr "length" "3,2,3")] ) +(define_insn "*ashrsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) + (set (reg CC_REG) + (compare (ashiftrt:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + shar\t%2, %0 + shar\t%2, %0 + shar\t%2, %1, %0" + [(set_attr "length" "3,2,3")] +) + (define_insn "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r") (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (lshiftrt:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ shlr\t%2, %0 @@ -1100,13 +1324,26 @@ [(set_attr "length" "3,2,3")] ) +(define_insn "*lshrsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) + (set (reg CC_REG) + (compare (lshiftrt:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + shlr\t%2, %0 + shlr\t%2, %0 + shlr\t%2, %1, %0" + [(set_attr "length" "3,2,3")] +) + (define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r") (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (ashift:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ shll\t%2, %0 @@ -1115,16 +1352,57 @@ [(set_attr "length" "3,2,3")] ) +(define_insn "*ashlsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) + (set (reg CC_REG) + (compare (ashift:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "@ + shll\t%2, %0 + shll\t%2, %0 + shll\t%2, %1, %0" + [(set_attr "length" "3,2,3")] +) + +;; Saturate to 32-bits +(define_insn_and_split "ssaddsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ss_plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "rx_source_operand" "riQ"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (plus:SI (match_dup 1) (match_dup 2))) + (set (reg:CC_ZSC CC_REG) + (compare:CC_ZSC + (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))]) + (set (match_dup 0) + (unspec:SI [(match_dup 0) (reg:CC CC_REG)] + UNSPEC_BUILTIN_SAT))] + "" +) + +(define_insn "*sat" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "0") + (reg:CC CC_REG)] + UNSPEC_BUILTIN_SAT))] + "reload_completed" + "sat\t%0" + [(set_attr "length" "2")] +) + (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q"))) - (set (reg:CC_ZSC CC_REG) - ;; Note - we do not acknowledge that the SUB instruction sets the Overflow - ;; flag because its interpretation is different from comparing the result - ;; against zero. Compile and run gcc.c-torture/execute/cmpsi-1.c to see this. - (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "@ sub\t%2, %0 @@ -1136,32 +1414,134 @@ (set_attr "length" "2,2,6,3,5")] ) -(define_insn "subdi3" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:DI 2 "rx_source_operand" "r,Q"))) - (set (reg:CC_ZSC CC_REG) ;; See subsi3 - (compare:CC_ZSC (minus:DI (match_dup 1) (match_dup 2)) - (const_int 0)))] - "" - "sub\t%L2, %L0\n\tsbb\t%H2, %H0" - [(set_attr "timings" "22,44") - (set_attr "length" "5,11")] +;; Note that the O flag is set as if (compare op1 op2) not for +;; what is described here, (compare op0 0). +(define_insn "*subsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") + (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q"))) + (set (reg CC_REG) + (compare (minus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" + "@ + sub\t%2, %0 + sub\t%2, %0 + add\t%N2, %0 + sub\t%2, %1, %0 + sub\t%Q2, %0" + [(set_attr "timings" "11,11,11,11,33") + (set_attr "length" "2,2,6,3,5")] ) +;; A helper to expand the above with the CC_MODE filled in. +(define_expand "subsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand") + (minus:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand"))) + (set (reg:CC_ZSC CC_REG) + (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))])] +) + +(define_insn "sbb_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI + (minus:SI + (match_operand:SI 1 "register_operand" " 0,0") + (match_operand:SI 2 "rx_compare_operand" " r,Q")) + (geu:SI (reg:CC CC_REG) (const_int 0)))) + (clobber (reg:CC CC_REG))] + "reload_completed" + "sbb\t%2, %0" + [(set_attr "timings" "11,33") + (set_attr "length" "3,6")] +) + +(define_insn "*sbb_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI + (minus:SI + (match_operand:SI 1 "register_operand" " 0,0") + (match_operand:SI 2 "rx_compare_operand" " r,Q")) + (geu:SI (reg:CC CC_REG) (const_int 0)))) + (set (reg CC_REG) + (compare + (minus:SI + (minus:SI (match_dup 1) (match_dup 2)) + (geu:SI (reg:CC CC_REG) (const_int 0))) + (const_int 0)))] + "reload_completed" + "sbb\t%2, %0" + [(set_attr "timings" "11,33") + (set_attr "length" "3,6")] +) + +(define_expand "subdi3" + [(set (match_operand:DI 0 "register_operand") + (minus:DI (match_operand:DI 1 "register_operand") + (match_operand:DI 2 "rx_compare_operand")))] + "" +{ + rtx op0l, op0h, op1l, op1h, op2l, op2h; + + op0l = gen_lowpart (SImode, operands[0]); + op1l = gen_lowpart (SImode, operands[1]); + op2l = gen_lowpart (SImode, operands[2]); + op0h = gen_highpart (SImode, operands[0]); + op1h = gen_highpart (SImode, operands[1]); + op2h = gen_highpart_mode (SImode, DImode, operands[2]); + + emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h)); + DONE; +}) + +(define_insn_and_split "subdi3_internal" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (minus:SI (match_operand:SI 2 "register_operand" " 0, r") + (match_operand:SI 3 "rx_compare_operand" "rQ, r"))) + (set (match_operand:SI 1 "register_operand" "= r, r") + (minus:SI + (minus:SI + (match_operand:SI 4 "register_operand" " 1, 1") + (match_operand:SI 5 "rx_compare_operand" " rQ,rQ")) + (geu:SI (match_dup 2) (match_dup 3)))) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3])); + emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5])); + DONE; +}) + (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (xor:SI (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "" "xor\t%Q2, %0" [(set_attr "timings" "11,11,11,11,11,33") (set_attr "length" "3,4,5,6,7,6")] ) + +(define_insn "*xorsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q"))) + (set (reg CC_REG) + (compare (xor:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" + "xor\t%Q2, %0" + [(set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) ;; Floating Point Instructions @@ -1169,9 +1549,7 @@ [(set (match_operand:SF 0 "register_operand" "=r,r,r") (plus:SF (match_operand:SF 1 "register_operand" "%0,0,0") (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (plus:SF (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "fadd\t%2, %0" [(set_attr "timings" "44,44,66") @@ -1182,9 +1560,7 @@ [(set (match_operand:SF 0 "register_operand" "=r,r,r") (div:SF (match_operand:SF 1 "register_operand" "0,0,0") (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (div:SF (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "fdiv\t%2, %0" [(set_attr "timings" "1616,1616,1818") @@ -1195,9 +1571,7 @@ [(set (match_operand:SF 0 "register_operand" "=r,r,r") (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0") (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (mult:SF (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "fmul\t%2, %0" [(set_attr "timings" "33,33,55") @@ -1208,9 +1582,7 @@ [(set (match_operand:SF 0 "register_operand" "=r,r,r") (minus:SF (match_operand:SF 1 "register_operand" "0,0,0") (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (minus:SF (match_dup 1) (match_dup 2)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "fsub\t%Q2, %0" [(set_attr "timings" "44,44,66") @@ -1220,9 +1592,7 @@ (define_insn "fix_truncsfsi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (fix:SI (match_dup 1)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "ftoi\t%Q1, %0" [(set_attr "timings" "22,44") @@ -1232,9 +1602,7 @@ (define_insn "floatsisf2" [(set (match_operand:SF 0 "register_operand" "=r,r") (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q"))) - (set (reg:CC_ZS CC_REG) - (compare:CC_ZS (float:SF (match_dup 1)) - (const_int 0)))] + (clobber (reg:CC CC_REG))] "ALLOW_RX_FPU_INSNS" "itof\t%Q1, %0" [(set_attr "timings" "22,44") @@ -1242,217 +1610,216 @@ ) ;; Bit manipulation instructions. -;; Note - there are two versions of each pattern because the memory -;; accessing versions use QImode whilst the register accessing -;; versions use SImode. -;; The peephole are here because the combiner only looks at a maximum -;; of three instructions at a time. - -(define_insn "bitset" - [(set:SI (match_operand:SI 0 "register_operand" "=r") - (ior:SI (match_operand:SI 1 "register_operand" "0") - (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri"))))] - "" - "bset\t%2, %0" + +;; ??? The *_in_memory patterns will not be matched without further help. +;; At one time we had the insv expander generate them, but I suspect that +;; in general we get better performance by exposing the register load to +;; the optimizers. +;; +;; An alternate solution would be to re-organize these patterns such +;; that allow both register and memory operands. This would allow the +;; register allocator to spill and not load the register operand. This +;; would be possible only for operations for which we have a constant +;; bit offset, so that we can adjust the address by ofs/8 and replace +;; the offset in the insn by ofs%8. + +(define_insn "*bitset" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (ashift:SI (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "register_operand" "0")))] + "" + "bset\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitset_in_memory" - [(set:QI (match_operand:QI 0 "memory_operand" "=m") - (ior:QI (match_operand:QI 1 "memory_operand" "0") - (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri"))))] +(define_insn "*bitset_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (ior:QI (ashift:QI (const_int 1) + (match_operand:QI 1 "nonmemory_operand" "ri")) + (match_dup 0)))] "" - "bset\t%2, %0.B" + "bset\t%1, %0.B" [(set_attr "length" "3") (set_attr "timings" "34")] ) -;; (set (reg A) (const_int 1)) -;; (set (reg A) (ashift (reg A) (reg B))) -;; (set (reg C) (ior (reg A) (reg C))) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int 1)) - (set:SI (match_dup 0) - (ashift:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_operand:SI 2 "register_operand" "") - (ior:SI (match_dup 0) - (match_dup 2)))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (ior:SI (match_dup 2) - (ashift:SI (const_int 1) - (match_dup 1))))] -) - -;; (set (reg A) (const_int 1)) -;; (set (reg A) (ashift (reg A) (reg B))) -;; (set (reg A) (ior (reg A) (reg C))) -;; (set (reg C) (reg A) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int 1)) - (set:SI (match_dup 0) - (ashift:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_dup 0) - (ior:SI (match_dup 0) - (match_operand:SI 2 "register_operand" ""))) - (set:SI (match_dup 2) (match_dup 0))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (ior:SI (match_dup 2) - (ashift:SI (const_int 1) - (match_dup 1))))] -) - -(define_insn "bitinvert" - [(set:SI (match_operand:SI 0 "register_operand" "+r") - (xor:SI (match_operand:SI 1 "register_operand" "0") - (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri"))))] +(define_insn "*bitinvert" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (ashift:SI (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "register_operand" "0")))] "" - "bnot\t%2, %0" + "bnot\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitinvert_in_memory" - [(set:QI (match_operand:QI 0 "memory_operand" "+m") - (xor:QI (match_operand:QI 1 "register_operand" "0") - (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri"))))] +(define_insn "*bitinvert_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (xor:QI (ashift:QI (const_int 1) + (match_operand:QI 1 "nonmemory_operand" "ri")) + (match_dup 0)))] "" - "bnot\t%2, %0.B" + "bnot\t%1, %0.B" [(set_attr "length" "5") (set_attr "timings" "33")] ) -;; (set (reg A) (const_int 1)) -;; (set (reg A) (ashift (reg A) (reg B))) -;; (set (reg C) (xor (reg A) (reg C))) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int 1)) - (set:SI (match_dup 0) - (ashift:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_operand:SI 2 "register_operand" "") - (xor:SI (match_dup 0) - (match_dup 2)))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (xor:SI (match_dup 2) - (ashift:SI (const_int 1) - (match_dup 1))))] +(define_insn "*bitclr" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI + (ashift:SI + (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri"))) + (match_operand:SI 2 "register_operand" "0")))] "" -) - -;; (set (reg A) (const_int 1)) -;; (set (reg A) (ashift (reg A) (reg B))) -;; (set (reg A) (xor (reg A) (reg C))) -;; (set (reg C) (reg A)) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int 1)) - (set:SI (match_dup 0) - (ashift:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_dup 0) - (xor:SI (match_dup 0) - (match_operand:SI 2 "register_operand" ""))) - (set:SI (match_dup 2) (match_dup 0))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (xor:SI (match_dup 2) - (ashift:SI (const_int 1) - (match_dup 1))))] - "" -) - -(define_insn "bitclr" - [(set:SI (match_operand:SI 0 "register_operand" "+r") - (and:SI (match_operand:SI 1 "register_operand" "0") - (not:SI (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri")))))] - "" - "bclr\t%2, %0" + "bclr\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitclr_in_memory" - [(set:QI (match_operand:QI 0 "memory_operand" "+m") - (and:QI (match_operand:QI 1 "memory_operand" "0") - (not:QI (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri")))))] +(define_insn "*bitclr_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (and:QI (not:QI + (ashift:QI + (const_int 1) + (match_operand:QI 1 "nonmemory_operand" "ri"))) + (match_dup 0)))] "" - "bclr\t%2, %0.B" + "bclr\t%1, %0.B" [(set_attr "length" "3") (set_attr "timings" "34")] ) -;; (set (reg A) (const_int -2)) -;; (set (reg A) (rotate (reg A) (reg B))) -;; (set (reg C) (and (reg A) (reg C))) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int -2)) - (set:SI (match_dup 0) - (rotate:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_operand:SI 2 "register_operand" "") - (and:SI (match_dup 0) - (match_dup 2)))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (and:SI (match_dup 2) - (not:SI (ashift:SI (const_int 1) - (match_dup 1)))))] +(define_insn "*insv_imm" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "const_int_operand" ""))] + "" +{ + if (INTVAL (operands[2]) & 1) + return "bset\t%1, %0"; + else + return "bclr\t%1, %0"; +} + [(set_attr "length" "3")] ) - -;; (set (reg A) (const_int -2)) -;; (set (reg A) (rotate (reg A) (reg B))) -;; (set (reg A) (and (reg A) (reg C))) -;; (set (reg C) (reg A) -(define_peephole2 - [(set:SI (match_operand:SI 0 "register_operand" "") - (const_int -2)) - (set:SI (match_dup 0) - (rotate:SI (match_dup 0) - (match_operand:SI 1 "register_operand" ""))) - (set:SI (match_dup 0) - (and:SI (match_dup 0) - (match_operand:SI 2 "register_operand" ""))) - (set:SI (match_dup 2) (match_dup 0))] - "dead_or_set_p (insn, operands[0])" - [(set:SI (match_dup 2) - (and:SI (match_dup 2) - (not:SI (ashift:SI (const_int 1) - (match_dup 1)))))] + +(define_insn_and_split "rx_insv_reg" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operand:SI 2 "register_operand" "r")) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (match_dup 3))] +{ + rtx flags, x; + + /* Emit tst #1, op2. */ + flags = gen_rtx_REG (CC_ZSmode, CC_REG); + x = gen_rtx_AND (SImode, operands[2], const1_rtx); + x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + /* Emit bmne. */ + operands[3] = gen_rtx_NE (SImode, flags, const0_rtx); +}) + +(define_insn_and_split "*insv_cond" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "rx_source_operand" "riQ")])) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (match_dup 4))] +{ + rtx flags, x; + + flags = gen_rtx_REG (CCmode, CC_REG); + x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, + flags, const0_rtx); +}) + +(define_insn "*bmcc" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 2 "comparison_operator" + [(reg CC_REG) (const_int 0)]))] + "reload_completed" + "bm%B2\t%1, %0" + [(set_attr "length" "3")] ) -(define_expand "insv" - [(set:SI (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination - (match_operand 1 "immediate_operand") ;; # of bits to set - (match_operand 2 "immediate_operand")) ;; Starting bit - (match_operand 3 "immediate_operand"))] ;; Bits to insert +;; Work around the fact that X=Y<0 is preferentially expanded as a shift. +(define_insn_and_split "*insv_cond_lt" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 3 "rshift_operator" + [(match_operand:SI 2 "register_operand" "r") + (const_int 31)])) + (clobber (reg:CC CC_REG))] "" - { - if (rx_expand_insv (operands)) + "#" + "" + [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (lt:SI (match_dup 2) (const_int 0))) + (clobber (reg:CC CC_REG))])] + "" +) + +(define_expand "insv" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand") ;; Destination + (match_operand:SI 1 "const_int_operand") ;; # of bits to set + (match_operand:SI 2 "nonmemory_operand")) ;; Starting bit + (match_operand:SI 3 "nonmemory_operand"))] ;; Bits to insert + "" +{ + /* We only handle single-bit inserts. */ + if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1) + FAIL; + + /* Either the bit to insert or the position must be constant. */ + if (CONST_INT_P (operands[3])) + operands[3] = GEN_INT (INTVAL (operands[3]) & 1); + else if (CONST_INT_P (operands[2])) + { + emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3])); DONE; + } + else FAIL; - } -) +}) ;; Atomic exchange operation. (define_insn "sync_lock_test_and_setsi" - [(set:SI (match_operand:SI 0 "register_operand" "=r,r") - (match_operand:SI 1 "rx_compare_operand" "=r,Q")) - (set:SI (match_dup 1) - (match_operand:SI 2 "register_operand" "0,0"))] + [(set (match_operand:SI 0 "register_operand" "=r,r") + (match_operand:SI 1 "rx_compare_operand" "=r,Q")) + (set (match_dup 1) + (match_operand:SI 2 "register_operand" "0,0"))] "" "xchg\t%1, %0" [(set_attr "length" "3,6") @@ -1462,9 +1829,9 @@ ;; Block move functions. (define_expand "movstr" - [(set:SI (match_operand:BLK 1 "memory_operand") ;; Dest - (match_operand:BLK 2 "memory_operand")) ;; Source - (use (match_operand:SI 0 "register_operand")) ;; Updated Dest + [(set (match_operand:BLK 1 "memory_operand") ;; Dest + (match_operand:BLK 2 "memory_operand")) ;; Source + (use (match_operand:SI 0 "register_operand")) ;; Updated Dest ] "" { @@ -1487,8 +1854,8 @@ ) (define_insn "rx_movstr" - [(set:SI (mem:BLK (reg:SI 1)) - (mem:BLK (reg:SI 2))) + [(set (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR) (clobber (reg:SI 1)) (clobber (reg:SI 2)) @@ -1500,8 +1867,8 @@ ) (define_insn "rx_strend" - [(set:SI (match_operand:SI 0 "register_operand" "=r") - (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") (reg:SI 3)] UNSPEC_STRLEN)) (clobber (reg:SI 1)) (clobber (reg:SI 2)) @@ -1582,8 +1949,8 @@ ) (define_insn "rx_setmem" - [(set:BLK (mem:BLK (reg:SI 1)) (reg 2)) - (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM) + [(set (mem:BLK (reg:SI 1)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)) (clobber (reg:SI 1)) (clobber (reg:SI 3))] "" @@ -1636,11 +2003,11 @@ ) (define_insn "rx_cmpstrn" - [(set:SI (match_operand:SI 0 "register_operand" "=r") - (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] - UNSPEC_CMPSTRN)) - (use (match_operand:BLK 1 "memory_operand" "m")) - (use (match_operand:BLK 2 "memory_operand" "m")) + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] + UNSPEC_CMPSTRN)) + (use (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:BLK 2 "memory_operand" "m")) (clobber (reg:SI 1)) (clobber (reg:SI 2)) (clobber (reg:SI 3)) @@ -1773,7 +2140,7 @@ ;; Byte swap (two 16-bit values). (define_insn "revw" - [(set (match_operand:SI 0 "register_operand" "+r") + [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_BUILTIN_REVW))] "" @@ -1807,7 +2174,7 @@ ;; Clear Processor Status Word (define_insn "clrpsw" - [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_BUILTIN_CLRPSW) (clobber (reg:CC CC_REG))] "" @@ -1817,7 +2184,7 @@ ;; Set Processor Status Word (define_insn "setpsw" - [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_BUILTIN_SETPSW) (clobber (reg:CC CC_REG))] "" @@ -1828,7 +2195,7 @@ ;; Move from control register (define_insn "mvfc" [(set (match_operand:SI 0 "register_operand" "=r") - (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")] + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_BUILTIN_MVFC))] "" "mvfc\t%C1, %0" @@ -1837,7 +2204,7 @@ ;; Move to control register (define_insn "mvtc" - [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i,i") (match_operand:SI 1 "nonmemory_operand" "r,i")] UNSPEC_BUILTIN_MVTC)] "" @@ -1852,7 +2219,7 @@ ;; Move to interrupt priority level (define_insn "mvtipl" - [(unspec:SI [(match_operand:SI 0 "immediate_operand" "Uint04")] + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "Uint04")] UNSPEC_BUILTIN_MVTIPL)] "" "mvtipl\t%0"