Hi Guys, I am checking in the attached patch to fix some regressions in the RX port with regard to alignment and addressing modes. With this patch applied I have 18 fewer failures in the GCC testsuite.
Cheers Nick gcc/ChangeLog 2011-03-16 Nick Clifton <ni...@redhat.com> * config/rx/rx.h (JUMP_ALIGN): Define. (JUMP_ALIGN_MAX_SKIP, LABEL_ALIGN_AFTER_BARRIER, LOOP_ALIGN, (LABEL_ALIGN, LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP, (LOOP_ALIGN_MAX_SKIP, LABEL_ALIGN_MAX_SKIP): Define. * config/rx/rx-protos.h (rx_align_for_label): Prototype. (rx_max_skip_for_label): Prototype. * config/rx/rx.md (abssi3): Use CC_ZSmode. (andis3): Fix timings. (peephole): Add peephole to combine zero- and sign- extending loads with arithmetic instructions. (bset): Fix timing. (bclr): Fix timing. * config/rx/rx.c (rx_is_legitimate_address): Add checks for QImode and HImode reg+int address. (rx_print_operand): Add support for %R. Fix generation of .B and .W addressing modes. (rx_align_for_label): New function. (rx_max_skip_for_label): New function.
Index: gcc/config/rx/rx.h =================================================================== --- gcc/config/rx/rx.h (revision 171032) +++ gcc/config/rx/rx.h (working copy) @@ -663,3 +663,28 @@ #define SELECT_CC_MODE(OP,X,Y) rx_select_cc_mode ((OP), (X), (Y)) +#define JUMP_ALIGN(x) rx_align_for_label (x) +#define JUMP_ALIGN_MAX_SKIP rx_max_skip_for_label (label) +#define LABEL_ALIGN_AFTER_BARRIER(x) rx_align_for_label (x) +#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP rx_max_skip_for_label (label) +#define LOOP_ALIGN(x) rx_align_for_label (x) +#define LOOP_ALIGN_MAX_SKIP rx_max_skip_for_label (label) +#define LABEL_ALIGN(x) rx_align_for_label (x) +#define LABEL_ALIGN_MAX_SKIP rx_max_skip_for_label (NULL_RTX) + +#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM, LOG, MAX_SKIP) \ + do \ + { \ + if ((LOG) == 0 || (MAX_SKIP) == 0) \ + break; \ + if (TARGET_AS100_SYNTAX) \ + { \ + if ((LOG) >= 2) \ + fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \ + else \ + fprintf (STREAM, "\t.ALIGN 2\n"); \ + } \ + else \ + fprintf (STREAM, "\t.balign %d,3,%d\n", 1 << (LOG), (MAX_SKIP)); \ + } \ + while (0) Index: gcc/config/rx/rx-protos.h =================================================================== --- gcc/config/rx/rx-protos.h (revision 171032) +++ gcc/config/rx/rx-protos.h (working copy) @@ -31,6 +31,7 @@ extern void rx_set_optimization_options (void); #ifdef RTX_CODE +extern int rx_align_for_label (rtx); extern bool rx_compare_redundant (rtx); extern void rx_emit_stack_popm (rtx *, bool); extern void rx_emit_stack_pushm (rtx *); @@ -41,6 +42,7 @@ 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 int rx_max_skip_for_label (rtx); 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); Index: gcc/config/rx/rx.md =================================================================== --- gcc/config/rx/rx.md (revision 171032) +++ gcc/config/rx/rx.md (working copy) @@ -798,7 +798,10 @@ (set (reg CC_REG) (compare (abs:SI (match_dup 1)) (const_int 0)))] - "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)" + ;; Note - although the ABS instruction does set the O bit in the processor + ;; status word, it does not do so in a way that is comparable with the CMP + ;; instruction. Hence we use CC_ZSmode rather than CC_ZSOmode. + "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" "@ abs\t%0 abs\t%1, %0" @@ -1005,7 +1008,7 @@ 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 "timings" "11,11,11,11,11,11,11,11,33") (set_attr "length" "2,2,3,4,5,6,2,5,5")] ) @@ -1027,7 +1030,7 @@ 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 "timings" "11,11,11,11,11,11,11,11,33") (set_attr "length" "2,2,3,4,5,6,2,5,5")] ) @@ -1543,6 +1546,139 @@ (set_attr "length" "3,4,5,6,7,6")] ) +;; A set of peepholes to catch extending loads followed by arithmetic operations. +;; We use iterators where possible to reduce the amount of typing and hence the +;; possibilities for typos. + +(define_code_iterator extend_types [(zero_extend "") (sign_extend "")]) +(define_code_attr letter [(zero_extend "R") (sign_extend "Q")]) + +(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")]) +(define_code_iterator memex_noncomm [(div "") (udiv "") (minus "")]) +(define_code_iterator memex_nocc [(smax "") (smin "") (mult "")]) + +(define_code_attr op [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")]) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (parallel [(set (match_operand:SI 2 "register_operand") + (memex_commutative:SI (match_dup 0) + (match_dup 2))) + (clobber (reg:CC CC_REG))])] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(parallel [(set:SI (match_dup 2) + (memex_commutative:SI (match_dup 2) + (extend_types:SI (match_dup 1)))) + (clobber (reg:CC CC_REG))])] +) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (parallel [(set (match_operand:SI 2 "register_operand") + (memex_commutative:SI (match_dup 2) + (match_dup 0))) + (clobber (reg:CC CC_REG))])] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(parallel [(set:SI (match_dup 2) + (memex_commutative:SI (match_dup 2) + (extend_types:SI (match_dup 1)))) + (clobber (reg:CC CC_REG))])] +) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (parallel [(set (match_operand:SI 2 "register_operand") + (memex_noncomm:SI (match_dup 2) + (match_dup 0))) + (clobber (reg:CC CC_REG))])] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(parallel [(set:SI (match_dup 2) + (memex_noncomm:SI (match_dup 2) + (extend_types:SI (match_dup 1)))) + (clobber (reg:CC CC_REG))])] +) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (set (match_operand:SI 2 "register_operand") + (memex_nocc:SI (match_dup 0) + (match_dup 2)))] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(set:SI (match_dup 2) + (memex_nocc:SI (match_dup 2) + (extend_types:SI (match_dup 1))))] +) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (set (match_operand:SI 2 "register_operand") + (memex_nocc:SI (match_dup 2) + (match_dup 0)))] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(set:SI (match_dup 2) + (memex_nocc:SI (match_dup 2) + (extend_types:SI (match_dup 1))))] +) + +(define_insn "*<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>" + [(set (match_operand:SI 0 "register_operand" "=r") + (memex_commutative:SI (match_operand:SI 1 "register_operand" "%0") + (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q")))) + (clobber (reg:CC CC_REG))] + "" + "<memex_commutative:op>\t%<extend_types:letter>2, %0" + [(set_attr "timings" "33") + (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns +) ;; rather than using iterators we could specify exact sizes. + +(define_insn "*<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>" + [(set (match_operand:SI 0 "register_operand" "=r") + (memex_noncomm:SI (match_operand:SI 1 "register_operand" "0") + (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q")))) + (clobber (reg:CC CC_REG))] + "" + "<memex_noncomm:op>\t%<extend_types:letter>2, %0" + [(set_attr "timings" "33") + (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns +) ;; rather than using iterators we could specify exact sizes. + +(define_insn "*<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>" + [(set (match_operand:SI 0 "register_operand" "=r") + (memex_nocc:SI (match_operand:SI 1 "register_operand" "%0") + (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))] + "" + "<memex_nocc:op>\t%<extend_types:letter>2, %0" + [(set_attr "timings" "33") + (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns +) ;; rather than using iterators we could specify exact sizes. + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) + (set (reg:CC CC_REG) + (compare:CC (match_operand:SI 2 "register_operand") + (match_dup 0)))] + "peep2_regno_dead_p (2, REGNO (operands[0]))" + [(set (reg:CC CC_REG) + (compare:CC (match_dup 2) + (extend_types:SI (match_dup 1))))] +) + +(define_insn "*comparesi3_<extend_types:code><small_int_modes:mode>" + [(set (reg:CC CC_REG) + (compare:CC (match_operand:SI 0 "register_operand" "=r") + (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))] + "" + "cmp\t%<extend_types:letter>1, %0" + [(set_attr "timings" "33") + (set_attr "length" "5")] ;; Worst case sceanario. FIXME: If we defined separate patterns +) ;; rather than using iterators we could specify exact sizes. + ;; Floating Point Instructions (define_insn "addsf3" @@ -1641,7 +1777,7 @@ "" "bset\t%1, %0.B" [(set_attr "length" "3") - (set_attr "timings" "34")] + (set_attr "timings" "33")] ) (define_insn "*bitinvert" @@ -1687,7 +1823,7 @@ "" "bclr\t%1, %0.B" [(set_attr "length" "3") - (set_attr "timings" "34")] + (set_attr "timings" "33")] ) (define_insn "*insv_imm" Index: gcc/config/rx/rx.c =================================================================== --- gcc/config/rx/rx.c (revision 171032) +++ gcc/config/rx/rx.c (working copy) @@ -80,7 +80,9 @@ /* Register Indirect. */ return true; - if (GET_MODE_SIZE (mode) == 4 + if ((GET_MODE_SIZE (mode) == 4 + || GET_MODE_SIZE (mode) == 2 + || GET_MODE_SIZE (mode) == 1) && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)) /* Pre-decrement Register Indirect or Post-increment Register Indirect. */ @@ -182,8 +184,11 @@ base = XEXP (mem, 0); index = XEXP (mem, 1); - return RX_REG_P (base) && CONST_INT_P (index); + if (! RX_REG_P (base) || ! CONST_INT_P (index)) + return false; + return IN_RANGE (INTVAL (index), 0, (0x10000 * GET_MODE_SIZE (mode)) - 1); + case SYMBOL_REF: /* Can happen when small data is being supported. Assume that it will be resolved into GP+INT. */ @@ -447,11 +452,14 @@ %L Print low part of a DImode register, integer or address. %N Print the negation of the immediate value. %Q If the operand is a MEM, then correctly generate - register indirect or register relative addressing. */ + register indirect or register relative addressing. + %R Like %Q but for zero-extending loads. */ void rx_print_operand (FILE * file, rtx op, int letter) { + bool unsigned_load = false; + switch (letter) { case 'A': @@ -615,10 +623,15 @@ rx_print_integer (file, - INTVAL (op)); break; + case 'R': + gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4); + unsigned_load = true; + /* Fall through. */ case 'Q': if (MEM_P (op)) { HOST_WIDE_INT offset; + rtx mem = op; op = XEXP (op, 0); @@ -653,22 +666,24 @@ rx_print_operand (file, op, 0); fprintf (file, "]."); - switch (GET_MODE_SIZE (GET_MODE (op))) + switch (GET_MODE_SIZE (GET_MODE (mem))) { case 1: - gcc_assert (offset < 65535 * 1); - fprintf (file, "B"); + gcc_assert (offset <= 65535 * 1); + fprintf (file, unsigned_load ? "UB" : "B"); break; case 2: gcc_assert (offset % 2 == 0); - gcc_assert (offset < 65535 * 2); - fprintf (file, "W"); + gcc_assert (offset <= 65535 * 2); + fprintf (file, unsigned_load ? "UW" : "W"); break; - default: + case 4: gcc_assert (offset % 4 == 0); - gcc_assert (offset < 65535 * 4); + gcc_assert (offset <= 65535 * 4); fprintf (file, "L"); break; + default: + gcc_unreachable (); } break; } @@ -2656,6 +2671,36 @@ return true; } +int +rx_align_for_label (rtx lab ATTRIBUTE_UNUSED) +{ + return optimize_size ? 1 : 3; +} + +int +rx_max_skip_for_label (rtx lab) +{ + int opsize; + rtx op; + + if (lab == NULL_RTX) + return 0; + op = lab; + do + { + op = next_nonnote_insn (op); + } + while (op && (LABEL_P (op) + || (INSN_P (op) && GET_CODE (PATTERN (op)) == USE))); + if (!op) + return 0; + + opsize = get_attr_length (op); + if (opsize >= 0 && opsize < 8) + return opsize - 1; + return 0; +} + #undef TARGET_FUNCTION_VALUE #define TARGET_FUNCTION_VALUE rx_function_value