diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-18 11:20:51 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-18 11:20:51 +0000 |
commit | 10c77d2b4d6c2244dd7fba02f80733c03c6c4b20 (patch) | |
tree | 3fabbd2d1f832606564c35679ccae185098d100c /gcc/config/alpha | |
parent | 7ec3178a3fc06b6bb7acccfc457f3cccdb5cb670 (diff) | |
download | gcc-10c77d2b4d6c2244dd7fba02f80733c03c6c4b20.tar.gz |
* config/alpha/alpha.c (alpha_split_tfmode_pair): Rename into
alpha_split_tmode_pair. Add 'mode' and 'fixup_overlap' arguments.
Test against the appropriate null constant for the mode.
If 'fixup_overlap' is true, swap the operands if they overlap.
(alpha_split_tfmode_frobsign): Adjust call to alpha_split_tfmode_pair.
* config/alpha/alpha-protos.h (alpha_split_tfmode_pair): Rename into
alpha_split_tmode_pair and adjust for above change.
* config/alpha/alpha.md (movtf_internal): Adjust call to
alpha_split_tfmode_pair and rely on it to swap the operands.
(movti_internal): New insn and post-reload splitter.
(movti): New expander.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109882 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/alpha')
-rw-r--r-- | gcc/config/alpha/alpha-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.c | 27 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.md | 82 |
3 files changed, 96 insertions, 15 deletions
diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 00fc52530b0..f099b4d15e7 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -64,7 +64,7 @@ extern bool alpha_expand_mov_nobwx (enum machine_mode, rtx *); extern void alpha_expand_movmisalign (enum machine_mode, rtx *); extern void alpha_emit_floatuns (rtx[]); extern rtx alpha_emit_conditional_move (rtx, enum machine_mode); -extern void alpha_split_tfmode_pair (rtx[]); +extern void alpha_split_tmode_pair (rtx[], enum machine_mode, bool); extern void alpha_split_tfmode_frobsign (rtx[], rtx (*)(rtx, rtx, rtx)); extern void alpha_expand_unaligned_load (rtx, rtx, HOST_WIDE_INT, HOST_WIDE_INT, int); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 244aa271204..c684a4cb1e2 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -3198,12 +3198,17 @@ alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[]) operands[1])); } -/* Split a TFmode OP[1] into DImode OP[2,3] and likewise for - OP[0] into OP[0,1]. Naturally, output operand ordering is - little-endian. */ - +/* Split a TImode or TFmode move from OP[1] to OP[0] into a pair of + DImode moves from OP[2,3] to OP[0,1]. If FIXUP_OVERLAP is true, + guarantee that the sequence + set (OP[0] OP[2]) + set (OP[1] OP[3]) + is valid. Naturally, output operand ordering is little-endian. + This is used by *movtf_internal and *movti_internal. */ + void -alpha_split_tfmode_pair (rtx operands[4]) +alpha_split_tmode_pair (rtx operands[4], enum machine_mode mode, + bool fixup_overlap) { switch (GET_CODE (operands[1])) { @@ -3217,8 +3222,9 @@ alpha_split_tfmode_pair (rtx operands[4]) operands[2] = adjust_address (operands[1], DImode, 0); break; + case CONST_INT: case CONST_DOUBLE: - gcc_assert (operands[1] == CONST0_RTX (TFmode)); + gcc_assert (operands[1] == CONST0_RTX (mode)); operands[2] = operands[3] = const0_rtx; break; @@ -3241,6 +3247,13 @@ alpha_split_tfmode_pair (rtx operands[4]) default: gcc_unreachable (); } + + if (fixup_overlap && reg_overlap_mentioned_p (operands[0], operands[3])) + { + rtx tmp; + tmp = operands[0], operands[0] = operands[1], operands[1] = tmp; + tmp = operands[2], operands[2] = operands[3], operands[3] = tmp; + } } /* Implement negtf2 or abstf2. Op0 is destination, op1 is source, @@ -3254,7 +3267,7 @@ alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx)) rtx scratch; int move; - alpha_split_tfmode_pair (operands); + alpha_split_tmode_pair (operands, TFmode, false); /* Detect three flavors of operand overlap. */ move = 1; diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index d9f9e09e808..2838499fa86 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -5176,13 +5176,7 @@ [(set (match_dup 0) (match_dup 2)) (set (match_dup 1) (match_dup 3))] { - alpha_split_tfmode_pair (operands); - if (reg_overlap_mentioned_p (operands[0], operands[3])) - { - rtx tmp; - tmp = operands[0], operands[0] = operands[1], operands[1] = tmp; - tmp = operands[2], operands[2] = operands[3], operands[3] = tmp; - } + alpha_split_tmode_pair (operands, TFmode, true); }) (define_expand "movsf" @@ -5668,6 +5662,80 @@ FAIL; }) +;; We need to prevent reload from splitting TImode moves, because it +;; might decide to overwrite a pointer with the value it points to. +;; In that case we have to do the loads in the appropriate order so +;; that the pointer is not destroyed too early. + +(define_insn_and_split "*movti_internal" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") + (match_operand:TI 1 "input_operand" "roJ,rJ"))] + "(register_operand (operands[0], TImode) + /* Prevent rematerialization of constants. */ + && ! CONSTANT_P (operands[1])) + || reg_or_0_operand (operands[1], TImode)" + "#" + "reload_completed" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 1) (match_dup 3))] +{ + alpha_split_tmode_pair (operands, TImode, true); +}) + +(define_expand "movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "" +{ + if (GET_CODE (operands[0]) == MEM + && ! reg_or_0_operand (operands[1], TImode)) + operands[1] = force_reg (TImode, operands[1]); + + if (operands[1] == const0_rtx) + ; + /* We must put 64-bit constants in memory. We could keep the + 32-bit constants in TImode and rely on the splitter, but + this doesn't seem to be worth the pain. */ + else if (GET_CODE (operands[1]) == CONST_INT + || GET_CODE (operands[1]) == CONST_DOUBLE) + { + rtx in[2], out[2], target; + + gcc_assert (!no_new_pseudos); + + split_double (operands[1], &in[0], &in[1]); + + if (in[0] == const0_rtx) + out[0] = const0_rtx; + else + { + out[0] = gen_reg_rtx (DImode); + emit_insn (gen_movdi (out[0], in[0])); + } + + if (in[1] == const0_rtx) + out[1] = const0_rtx; + else + { + out[1] = gen_reg_rtx (DImode); + emit_insn (gen_movdi (out[1], in[1])); + } + + if (GET_CODE (operands[0]) != REG) + target = gen_reg_rtx (TImode); + else + target = operands[0]; + + emit_insn (gen_movdi (gen_rtx_SUBREG (DImode, target, 0), out[0])); + emit_insn (gen_movdi (gen_rtx_SUBREG (DImode, target, 8), out[1])); + + if (target != operands[0]) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], target)); + + DONE; + } +}) + ;; These are the partial-word cases. ;; ;; First we have the code to load an aligned word. Operand 0 is the register |