diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e590fffa0b21578ad4fedf16d9ed27743e724a04..59654738319b49b67e790b4e66c3aee09cc7e086 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2005-11-02 Ulrich Weigand <uweigand@de.ibm.com> + + PR target/24615 + * config/s390/s390-protos.h (s390_decompose_shift_count): Declare. + * config/s390/s390.c (s390_decompose_shift_count): New function. + (s390_extra_constraint_str) ['Y']: Use s390_decompose_shift_count. + (print_shift_count_operand): Use s390_decompose_shift_count. + * config/s390/predicates.md ("setmem_operand", "shift_count_operand"): + Use s390_decompose_shift_count. Do not accept any non-base hard regs. + 2005-11-02 Ulrich Weigand <uweigand@de.ibm.com> PR target/24600 diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index 9f8f8237075956f9fe2c5ea970d18871b58b1ac5..a921d1f344688727e2e1f31bbc1b5c6d674748d1 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -80,35 +80,17 @@ (define_predicate "setmem_operand" (match_code "reg, subreg, plus, const_int") { - HOST_WIDE_INT offset = 0; + HOST_WIDE_INT offset; + rtx base; - /* The padding byte operand of the mvcle instruction is always truncated - to the 8 least significant bits. */ - if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT - && (INTVAL (XEXP (op, 1)) & 255) == 255) - op = XEXP (op, 0); - - /* We can have an integer constant, an address register, - or a sum of the two. Note that reload already checks - that any register present is an address register, so - we just check for any register here. */ - if (GET_CODE (op) == CONST_INT) - { - offset = INTVAL (op); - op = NULL_RTX; - } - if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) - { - offset = INTVAL (XEXP (op, 1)); - op = XEXP (op, 0); - } - while (op && GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (op && GET_CODE (op) != REG) + /* Extract base register and offset. Use 8 significant bits. */ + if (!s390_decompose_shift_count (op, &base, &offset, 8)) return false; - if (op && REGNO (op) < FIRST_PSEUDO_REGISTER - && !GENERAL_REGNO_P (REGNO (op))) + /* Don't allow any non-base hard registers. Doing so without + confusing reload and/or regrename would be tricky, and doesn't + buy us much anyway. */ + if (base && REGNO (base) < FIRST_PSEUDO_REGISTER && !ADDR_REG_P (base)) return false; /* Unfortunately we have to reject constants that are invalid @@ -124,35 +106,17 @@ (define_predicate "shift_count_operand" (match_code "reg, subreg, plus, const_int, and") { - HOST_WIDE_INT offset = 0; + HOST_WIDE_INT offset; + rtx base; - /* Shift count operands are always truncated to the 6 least significant bits. - So we can accept pointless ANDs here. */ - if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT - && (INTVAL (XEXP (op, 1)) & 63) == 63) - op = XEXP (op, 0); - - /* We can have an integer constant, an address register, - or a sum of the two. Note that reload already checks - that any register present is an address register, so - we just check for any register here. */ - if (GET_CODE (op) == CONST_INT) - { - offset = INTVAL (op); - op = NULL_RTX; - } - if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) - { - offset = INTVAL (XEXP (op, 1)); - op = XEXP (op, 0); - } - while (op && GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (op && GET_CODE (op) != REG) + /* Extract base register and offset. Use 6 significant bits. */ + if (!s390_decompose_shift_count (op, &base, &offset, 6)) return false; - if (op && REGNO (op) < FIRST_PSEUDO_REGISTER - && !GENERAL_REGNO_P (REGNO (op))) + /* Don't allow any non-base hard registers. Doing so without + confusing reload and/or regrename would be tricky, and doesn't + buy us much anyway. */ + if (base && REGNO (base) < FIRST_PSEUDO_REGISTER && !ADDR_REG_P (base)) return false; /* Unfortunately we have to reject constants that are invalid diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 3ae43ea209eab01e2b23e13bc3279c25438312f6..42eecdbfcf64fcc89911fcd7b1f12ea53a556032 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -97,6 +97,7 @@ extern rtx s390_load_got (void); extern rtx s390_get_thread_pointer (void); extern void s390_emit_tpf_eh_return (rtx); extern bool s390_legitimate_address_without_index_p (rtx); +extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *, int); extern int s390_branch_condition_mask (rtx); #endif /* RTX_CODE */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 009c17828d89d71bcd0ecefc680392380028163d..03e5a0ee83baf8d2ac8009f478496c0a3cf39cdc 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -1721,6 +1721,58 @@ s390_decompose_address (rtx addr, struct s390_address *out) return true; } +/* Decompose a RTL expression OP for a shift count into its components, + and return the base register in BASE and the offset in OFFSET. + + If BITS is non-zero, the expression is used in a context where only + that number to low-order bits is significant. We then allow OP to + contain and outer AND that does not affect significant bits. If BITS + is zero, we allow OP to contain any outer AND with a constant. + + Return true if OP is a valid shift count, false if not. */ + +bool +s390_decompose_shift_count (rtx op, rtx *base, HOST_WIDE_INT *offset, int bits) +{ + HOST_WIDE_INT off = 0; + + /* Drop outer ANDs. */ + if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT) + { + HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << bits) - 1; + if ((INTVAL (XEXP (op, 1)) & mask) != mask) + return false; + + op = XEXP (op, 0); + } + + /* We can have an integer constant, an address register, + or a sum of the two. */ + if (GET_CODE (op) == CONST_INT) + { + off = INTVAL (op); + op = NULL_RTX; + } + if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) + { + off = INTVAL (XEXP (op, 1)); + op = XEXP (op, 0); + } + while (op && GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (op && GET_CODE (op) != REG) + return false; + + if (offset) + *offset = off; + if (base) + *base = op; + + return true; +} + + /* Return true if CODE is a valid address without index. */ bool @@ -1851,7 +1903,11 @@ s390_extra_constraint_str (rtx op, int c, const char * str) break; case 'Y': - return shift_count_operand (op, VOIDmode); + /* Simply check for the basic form of a shift count. Reload will + take care of making sure we have a proper base register. */ + if (!s390_decompose_shift_count (op, NULL, NULL, 0)) + return 0; + break; default: return 0; @@ -3978,46 +4034,25 @@ s390_delegitimize_address (rtx orig_x) static void print_shift_count_operand (FILE *file, rtx op) { - HOST_WIDE_INT offset = 0; - - /* Shift count operands are always truncated to the 6 least significant bits and - the setmem padding byte to the least 8 significant bits. Hence we can drop - pointless ANDs. */ - if (GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT) - { - if ((INTVAL (XEXP (op, 1)) & 63) != 63) - gcc_unreachable (); - - op = XEXP (op, 0); - } + HOST_WIDE_INT offset; + rtx base; - /* We can have an integer constant, an address register, - or a sum of the two. */ - if (GET_CODE (op) == CONST_INT) - { - offset = INTVAL (op); - op = NULL_RTX; - } - if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) - { - offset = INTVAL (XEXP (op, 1)); - op = XEXP (op, 0); - } - while (op && GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); + /* Extract base register and offset. */ + if (!s390_decompose_shift_count (op, &base, &offset, 0)) + gcc_unreachable (); /* Sanity check. */ - if (op) + if (base) { - gcc_assert (GET_CODE (op) == REG); - gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER); - gcc_assert (REGNO_REG_CLASS (REGNO (op)) == ADDR_REGS); + gcc_assert (GET_CODE (base) == REG); + gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); + gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS); } /* Offsets are constricted to twelve bits. */ fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1)); - if (op) - fprintf (file, "(%s)", reg_names[REGNO (op)]); + if (base) + fprintf (file, "(%s)", reg_names[REGNO (base)]); } /* See 'get_some_local_dynamic_name'. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b0e73c3b9c7812c21739c0b56ce99963f11d2bfd..5fee48f1bc1cdbc4f557d16a9829880027cb2488 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-11-02 Ulrich Weigand <uweigand@de.ibm.com> + + PR target/24615 + * gcc.dg/pr24615.c: New test. + 2005-11-02 Ulrich Weigand <uweigand@de.ibm.com> PR target/24600 diff --git a/gcc/testsuite/gcc.dg/pr24615.c b/gcc/testsuite/gcc.dg/pr24615.c new file mode 100644 index 0000000000000000000000000000000000000000..9699d8e6ded1d8d5eda3062e52492279833f0803 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr24615.c @@ -0,0 +1,27 @@ + +/* { dg-do compile } */ +/* { dg-options "-Os -fPIC" } */ + +void *memset (void *, int, __SIZE_TYPE__); +void *memcpy (void *, const void *, __SIZE_TYPE__); + +char *alloc (int); + +char * +test (int type, int size, char *data, int len) +{ + char *block = alloc (size); + char *bp = block; + + *bp++ = type; + switch (type) + { + case 0: + case 1: + memset (bp, type == 0 ? 0x00 : 0xff, size); + memcpy (bp, data, len); + } + + return block; +} +