diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8378a7f504e..9b8cf8a3cf6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2005-08-12 Andreas Krebbel + + * config/s390/predicates.md (setmem_operand): New predicate. + (shift_count_operand): Accept ANDs with special constants as + operand. + * config/s390/s390.c (print_shift_count_operand): Skip ANDs + with special constants. + * config/s390/s390.md ("setmem_long", "*setmem_long"): Replaced + shift_count_operand with setmem_operand. + 2005-08-12 Andreas Krebbel * config/s390/s390.c (s390_extract_part, s390_single_part): diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index fb8a9a40085..05ef8c87a15 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -75,13 +75,59 @@ (and (match_test "mode == Pmode") (match_test "!legitimate_la_operand_p (op)")))) -;; Return true if OP is a valid shift count operand. +;; Return true if OP is a valid operand for setmem. -(define_predicate "shift_count_operand" +(define_predicate "setmem_operand" (match_code "reg, subreg, plus, const_int") { HOST_WIDE_INT offset = 0; + /* 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) + return false; + + /* Unfortunately we have to reject constants that are invalid + for an address, or else reload will get confused. */ + if (!DISP_IN_RANGE (offset)) + return false; + + return true; +}) + +;; Return true if OP is a valid shift count operand. + +(define_predicate "shift_count_operand" + (match_code "reg, subreg, plus, const_int, and") +{ + HOST_WIDE_INT offset = 0; + + /* 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 diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 551ffedbc80..277006f6473 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -3758,6 +3758,17 @@ 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); + } + /* We can have an integer constant, an address register, or a sum of the two. */ if (GET_CODE (op) == CONST_INT) diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index ee87cf6938b..c09df126c03 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -2062,7 +2062,7 @@ [(parallel [(clobber (match_dup 1)) (set (match_operand:BLK 0 "memory_operand" "") - (match_operand 2 "shift_count_operand" "")) + (match_operand 2 "setmem_operand" "")) (use (match_operand 1 "general_operand" "")) (use (match_dup 3)) (clobber (reg:CC CC_REGNUM))])] @@ -2088,7 +2088,7 @@ (define_insn "*setmem_long" [(clobber (match_operand: 0 "register_operand" "=d")) (set (mem:BLK (subreg:P (match_operand: 3 "register_operand" "0") 0)) - (match_operand 2 "shift_count_operand" "Y")) + (match_operand 2 "setmem_operand" "Y")) (use (match_dup 3)) (use (match_operand: 1 "register_operand" "d")) (clobber (reg:CC CC_REGNUM))]