diff -ur gcc.orig/config/s390/s390-protos.h gcc/config/s390/s390-protos.h --- gcc.orig/config/s390/s390-protos.h 2004-02-11 19:04:07.000000000 -0500 +++ gcc/config/s390/s390-protos.h 2004-02-11 19:08:21.000000000 -0500 @@ -43,6 +43,7 @@ extern int s390_extract_hi PARAMS ((rtx, enum machine_mode, int)); extern int s390_single_qi PARAMS ((rtx, enum machine_mode, int)); extern int s390_extract_qi PARAMS ((rtx, enum machine_mode, int)); +extern bool s390_split_ok_p PARAMS ((rtx, rtx, enum machine_mode, int)); extern int tls_symbolic_operand PARAMS ((rtx)); extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode)); @@ -61,6 +62,7 @@ extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode)); extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class)); extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx)); +extern enum reg_class s390_secondary_output_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx)); extern int s390_plus_operand PARAMS ((rtx, enum machine_mode)); extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx)); extern void emit_symbolic_move PARAMS ((rtx *)); diff -ur gcc.orig/config/s390/s390.c gcc/config/s390/s390.c --- gcc.orig/config/s390/s390.c 2004-02-11 19:04:07.000000000 -0500 +++ gcc/config/s390/s390.c 2004-02-11 19:08:21.000000000 -0500 @@ -863,6 +863,42 @@ abort (); } +/* Check whether we can (and want to) split a double-word + move in mode MODE from SRC to DST into two single-word + moves, moving the subword FIRST_SUBWORD first. */ + +bool +s390_split_ok_p (dst, src, mode, first_subword) + rtx dst; + rtx src; + enum machine_mode mode; + int first_subword; +{ + /* Floating point registers cannot be split. */ + if (FP_REG_P (src) || FP_REG_P (dst)) + return false; + + /* We don't need to split if operands are directly accessable. */ + if (s_operand (src, mode) || s_operand (dst, mode)) + return false; + + /* Non-offsettable memory references cannot be split. */ + if ((GET_CODE (src) == MEM && !offsettable_memref_p (src)) + || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst))) + return false; + + /* Moving the first subword must not clobber a register + needed to move the second subword. */ + if (register_operand (dst, mode)) + { + rtx subreg = operand_subword (dst, first_subword, 0, mode); + if (reg_overlap_mentioned_p (subreg, src)) + return false; + } + + return true; +} + /* Change optimizations to be performed, depending on the optimization level. @@ -1755,6 +1791,29 @@ return NO_REGS; } +/* Return the register class of a scratch register needed to + store a register of class CLASS in MODE into OUT: + + We need a temporary when storing a double-word to a + non-offsettable memory address. */ + +enum reg_class +s390_secondary_output_reload_class (class, mode, out) + enum reg_class class; + enum machine_mode mode; + rtx out; +{ + if ((TARGET_64BIT ? mode == TImode + : (mode == DImode || mode == DFmode)) + && reg_classes_intersect_p (GENERAL_REGS, class) + && GET_CODE (out) == MEM + && !offsettable_memref_p (out) + && !s_operand (out, VOIDmode)) + return ADDR_REGS; + + return NO_REGS; +} + /* Return true if OP is a PLUS that is not a legitimate operand for the LA instruction. OP is the current operation. diff -ur gcc.orig/config/s390/s390.h gcc/config/s390/s390.h --- gcc.orig/config/s390/s390.h 2004-02-11 19:04:07.000000000 -0500 +++ gcc/config/s390/s390.h 2004-02-11 19:08:21.000000000 -0500 @@ -474,6 +474,11 @@ #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \ s390_secondary_input_reload_class ((CLASS), (MODE), (IN)) +/* We need a secondary reload when storing a double-word + to a non-offsettable memory address. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT) \ + s390_secondary_output_reload_class ((CLASS), (MODE), (OUT)) + /* We need secondary memory to move data between GPRs and FPRs. */ #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \ ((CLASS1) != (CLASS2) && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS)) diff -ur gcc.orig/config/s390/s390.md gcc/config/s390/s390.md --- gcc.orig/config/s390/s390.md 2004-02-11 19:04:08.000000000 -0500 +++ gcc/config/s390/s390.md 2004-02-11 19:08:21.000000000 -0500 @@ -939,7 +939,7 @@ (define_insn "movti" [(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o,Q") - (match_operand:TI 1 "general_operand" "QS,d,dKo,d,Q"))] + (match_operand:TI 1 "general_operand" "QS,d,dKm,d,Q"))] "TARGET_64BIT" "@ lmg\\t%0,%N0,%1 @@ -954,36 +954,29 @@ [(set (match_operand:TI 0 "nonimmediate_operand" "") (match_operand:TI 1 "general_operand" ""))] "TARGET_64BIT && reload_completed - && !s_operand (operands[0], VOIDmode) - && !s_operand (operands[1], VOIDmode) - && (register_operand (operands[0], VOIDmode) - || register_operand (operands[1], VOIDmode)) - && (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode), - operands[1]) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, TImode), - operands[1]))" + && s390_split_ok_p (operands[0], operands[1], TImode, 0)" [(set (match_dup 2) (match_dup 4)) (set (match_dup 3) (match_dup 5))] - " { - if (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode), - operands[1])) - { - operands[2] = operand_subword (operands[0], 0, 0, TImode); - operands[3] = operand_subword (operands[0], 1, 0, TImode); - operands[4] = operand_subword (operands[1], 0, 0, TImode); - operands[5] = operand_subword (operands[1], 1, 0, TImode); - } - else - { - operands[2] = operand_subword (operands[0], 1, 0, TImode); - operands[3] = operand_subword (operands[0], 0, 0, TImode); - operands[4] = operand_subword (operands[1], 1, 0, TImode); - operands[5] = operand_subword (operands[1], 0, 0, TImode); - } -}") + operands[2] = operand_subword (operands[0], 0, 0, TImode); + operands[3] = operand_subword (operands[0], 1, 0, TImode); + operands[4] = operand_subword (operands[1], 0, 0, TImode); + operands[5] = operand_subword (operands[1], 1, 0, TImode); +}) + +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "TARGET_64BIT && reload_completed + && s390_split_ok_p (operands[0], operands[1], TImode, 1)" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] +{ + operands[2] = operand_subword (operands[0], 1, 0, TImode); + operands[3] = operand_subword (operands[0], 0, 0, TImode); + operands[4] = operand_subword (operands[1], 1, 0, TImode); + operands[5] = operand_subword (operands[1], 0, 0, TImode); +}) (define_split [(set (match_operand:TI 0 "register_operand" "") @@ -991,12 +984,23 @@ "TARGET_64BIT && reload_completed && !s_operand (operands[1], VOIDmode)" [(set (match_dup 0) (match_dup 1))] - " { rtx addr = operand_subword (operands[0], 1, 0, TImode); s390_load_address (addr, XEXP (operands[1], 0)); operands[1] = replace_equiv_address (operands[1], addr); -}") +}) + +(define_expand "reload_outti" + [(parallel [(match_operand:TI 0 "memory_operand" "") + (match_operand:TI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "=&a")])] + "TARGET_64BIT" +{ + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); + DONE; +}) ; ; movdi instruction pattern(s). @@ -1091,7 +1095,7 @@ (define_insn "*movdi_31" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!*f,!R,!T,Q") - (match_operand:DI 1 "general_operand" "Q,d,dKo,d,*f,R,T,*f,*f,Q"))] + (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,R,T,*f,*f,Q"))] "!TARGET_64BIT" "@ lm\\t%0,%N0,%1 @@ -1111,53 +1115,54 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "") (match_operand:DI 1 "general_operand" ""))] "!TARGET_64BIT && reload_completed - && !FP_REG_P (operands[0]) - && !FP_REG_P (operands[1]) - && !s_operand (operands[0], VOIDmode) - && !s_operand (operands[1], VOIDmode) - && (register_operand (operands[0], VOIDmode) - || register_operand (operands[1], VOIDmode)) - && (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode), - operands[1]) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DImode), - operands[1]))" + && s390_split_ok_p (operands[0], operands[1], DImode, 0)" [(set (match_dup 2) (match_dup 4)) (set (match_dup 3) (match_dup 5))] - " { - if (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode), - operands[1])) - { - operands[2] = operand_subword (operands[0], 0, 0, DImode); - operands[3] = operand_subword (operands[0], 1, 0, DImode); - operands[4] = operand_subword (operands[1], 0, 0, DImode); - operands[5] = operand_subword (operands[1], 1, 0, DImode); - } - else - { - operands[2] = operand_subword (operands[0], 1, 0, DImode); - operands[3] = operand_subword (operands[0], 0, 0, DImode); - operands[4] = operand_subword (operands[1], 1, 0, DImode); - operands[5] = operand_subword (operands[1], 0, 0, DImode); - } -}") + operands[2] = operand_subword (operands[0], 0, 0, DImode); + operands[3] = operand_subword (operands[0], 1, 0, DImode); + operands[4] = operand_subword (operands[1], 0, 0, DImode); + operands[5] = operand_subword (operands[1], 1, 0, DImode); +}) + +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && s390_split_ok_p (operands[0], operands[1], DImode, 1)" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] +{ + operands[2] = operand_subword (operands[0], 1, 0, DImode); + operands[3] = operand_subword (operands[0], 0, 0, DImode); + operands[4] = operand_subword (operands[1], 1, 0, DImode); + operands[5] = operand_subword (operands[1], 0, 0, DImode); +}) (define_split [(set (match_operand:DI 0 "register_operand" "") (match_operand:DI 1 "memory_operand" ""))] "!TARGET_64BIT && reload_completed && !FP_REG_P (operands[0]) - && !FP_REG_P (operands[1]) && !s_operand (operands[1], VOIDmode)" [(set (match_dup 0) (match_dup 1))] - " { rtx addr = operand_subword (operands[0], 1, 0, DImode); s390_load_address (addr, XEXP (operands[1], 0)); operands[1] = replace_equiv_address (operands[1], addr); -}") +}) + +(define_expand "reload_outdi" + [(parallel [(match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "=&a")])] + "!TARGET_64BIT" +{ + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); + DONE; +}) (define_peephole2 [(set (match_operand:DI 0 "register_operand" "") @@ -1429,7 +1434,7 @@ (define_insn "*movdf_31" [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,Q,d,o,Q") - (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKo,d,Q"))] + (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKm,d,Q"))] "!TARGET_64BIT" "@ ldr\\t%0,%1 @@ -1449,53 +1454,54 @@ [(set (match_operand:DF 0 "nonimmediate_operand" "") (match_operand:DF 1 "general_operand" ""))] "!TARGET_64BIT && reload_completed - && !FP_REG_P (operands[0]) - && !FP_REG_P (operands[1]) - && !s_operand (operands[0], VOIDmode) - && !s_operand (operands[1], VOIDmode) - && (register_operand (operands[0], VOIDmode) - || register_operand (operands[1], VOIDmode)) - && (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode), - operands[1]) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DFmode), - operands[1]))" + && s390_split_ok_p (operands[0], operands[1], DFmode, 0)" [(set (match_dup 2) (match_dup 4)) (set (match_dup 3) (match_dup 5))] - " { - if (!register_operand (operands[0], VOIDmode) - || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode), - operands[1])) - { - operands[2] = operand_subword (operands[0], 0, 0, DFmode); - operands[3] = operand_subword (operands[0], 1, 0, DFmode); - operands[4] = operand_subword (operands[1], 0, 0, DFmode); - operands[5] = operand_subword (operands[1], 1, 0, DFmode); - } - else - { - operands[2] = operand_subword (operands[0], 1, 0, DFmode); - operands[3] = operand_subword (operands[0], 0, 0, DFmode); - operands[4] = operand_subword (operands[1], 1, 0, DFmode); - operands[5] = operand_subword (operands[1], 0, 0, DFmode); - } -}") + operands[2] = operand_subword (operands[0], 0, 0, DFmode); + operands[3] = operand_subword (operands[0], 1, 0, DFmode); + operands[4] = operand_subword (operands[1], 0, 0, DFmode); + operands[5] = operand_subword (operands[1], 1, 0, DFmode); +}) + +(define_split + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && s390_split_ok_p (operands[0], operands[1], DFmode, 1)" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] +{ + operands[2] = operand_subword (operands[0], 1, 0, DFmode); + operands[3] = operand_subword (operands[0], 0, 0, DFmode); + operands[4] = operand_subword (operands[1], 1, 0, DFmode); + operands[5] = operand_subword (operands[1], 0, 0, DFmode); +}) (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "memory_operand" ""))] "!TARGET_64BIT && reload_completed && !FP_REG_P (operands[0]) - && !FP_REG_P (operands[1]) && !s_operand (operands[1], VOIDmode)" [(set (match_dup 0) (match_dup 1))] - " { rtx addr = operand_subword (operands[0], 1, 0, DFmode); s390_load_address (addr, XEXP (operands[1], 0)); operands[1] = replace_equiv_address (operands[1], addr); -}") +}) + +(define_expand "reload_outdf" + [(parallel [(match_operand:DF 0 "memory_operand" "") + (match_operand:DF 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "=&a")])] + "!TARGET_64BIT" +{ + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); + DONE; +}) ; ; movsf instruction pattern(s). diff -ur gcc.orig/testsuite/gcc.dg/20030627-1.c gcc/testsuite/gcc.dg/20030627-1.c --- gcc.orig/testsuite/gcc.dg/20030627-1.c 2004-02-11 19:06:21.000000000 -0500 +++ gcc/testsuite/gcc.dg/20030627-1.c 2004-02-11 19:08:21.000000000 -0500 @@ -0,0 +1,20 @@ +/* This tests whether non-offsettable memory operands are reloaded + correctly in certain corner cases on s390 targets. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu89" } */ + +void test_inout (char *bd, int xd, char *bs, int xs) +{ + *(long long *)(bd + xd + 4093) = *(long long *)(bs + xs + 4093); +} + +void test_in (char *bd, int xd, char *bs, int xs) +{ + *(long long *)(bd + xd) = *(long long *)(bs + xs + 4093); +} + +void test_out (char *bd, int xd, char *bs, int xs) +{ + *(long long *)(bd + xd + 4093) = *(long long *)(bs + xs); +} +