diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2012-09-13 23:00:23 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2012-09-13 23:00:23 +0000 |
commit | 03c432bd847bf0088ce4b323f30c29feb6597f0e (patch) | |
tree | 47b10f77dfce449ecb804ff4d663b85eb222ddab /gcc/config/sparc/sparc.md | |
parent | 12308bc61de47a985b260889194156021da3cc2e (diff) | |
download | gcc-03c432bd847bf0088ce4b323f30c29feb6597f0e.tar.gz |
predicates.md (input_operand): Do not consider TImode constants as 1-instruction integer constants.
* config/sparc/predicates.md (input_operand): Do not consider TImode
constants as 1-instruction integer constants.
Use register_or_zero_operand instead of register_operand and tidy up.
* config/sparc/sparc.md (movti): New expander.
(movti_insn_sp64): New instruction.
(movti_insn_sp64_hq): Likewise.
(TImode splitters): New splitters.
* config/sparc/sparc.c (sparc_expand_move) <TImode>: New case.
(sparc_legitimate_address_p): Return 0 for REG+REG in TImode.
* config/sparc/sparc-protos.h (arith_double_4096_operand): Delete.
(arith_4096_operand): Likewise.
(zero_operand): Likewise.
(fp_zero_operand): Likewise.
(reg_or_0_operand): Likewise.
From-SVN: r191283
Diffstat (limited to 'gcc/config/sparc/sparc.md')
-rw-r--r-- | gcc/config/sparc/sparc.md | 160 |
1 files changed, 159 insertions, 1 deletions
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 8f19efab45d..3e854616a0a 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -2034,6 +2034,164 @@ DONE; }) +(define_expand "movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "TARGET_ARCH64" +{ + if (sparc_expand_move (TImode, operands)) + DONE; +}) + +;; 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 "*movti_insn_sp64" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r , o,?*e,?o,b") + (match_operand:TI 1 "input_operand" "roJ,rJ, eo, e,J"))] + "TARGET_ARCH64 + && ! TARGET_HARD_QUAD + && (register_operand (operands[0], TImode) + || register_or_zero_operand (operands[1], TImode))" + "#" + [(set_attr "length" "2,2,2,2,2") + (set_attr "cpu_feature" "*,*,fpu,fpu,vis")]) + +(define_insn "*movti_insn_sp64_hq" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r , o,?*e,?*e,?m,b") + (match_operand:TI 1 "input_operand" "roJ,rJ, e, m, e,J"))] + "TARGET_ARCH64 + && TARGET_HARD_QUAD + && (register_operand (operands[0], TImode) + || register_or_zero_operand (operands[1], TImode))" + "@ + # + # + fmovq\t%1, %0 + ldq\t%1, %0 + stq\t%1, %0 + #" + [(set_attr "type" "*,*,fpmove,fpload,fpstore,*") + (set_attr "length" "2,2,*,*,*,2")]) + +;; Now all the splits to handle multi-insn TI mode moves. +(define_split + [(set (match_operand:TI 0 "register_operand" "") + (match_operand:TI 1 "register_operand" ""))] + "reload_completed + && ((TARGET_FPU + && ! TARGET_HARD_QUAD) + || (! fp_register_operand (operands[0], TImode) + && ! fp_register_operand (operands[1], TImode)))" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + dest1 = gen_highpart (DImode, set_dest); + dest2 = gen_lowpart (DImode, set_dest); + src1 = gen_highpart (DImode, set_src); + src2 = gen_lowpart (DImode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (reg_overlap_mentioned_p (dest1, src2)) + { + emit_insn (gen_movdi (dest2, src2)); + emit_insn (gen_movdi (dest1, src1)); + } + else + { + emit_insn (gen_movdi (dest1, src1)); + emit_insn (gen_movdi (dest2, src2)); + } + DONE; +}) + +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "const_zero_operand" ""))] + "reload_completed" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx dest1, dest2; + + switch (GET_CODE (set_dest)) + { + case REG: + dest1 = gen_highpart (DImode, set_dest); + dest2 = gen_lowpart (DImode, set_dest); + break; + case MEM: + dest1 = adjust_address (set_dest, DImode, 0); + dest2 = adjust_address (set_dest, DImode, 8); + break; + default: + gcc_unreachable (); + } + + emit_insn (gen_movdi (dest1, const0_rtx)); + emit_insn (gen_movdi (dest2, const0_rtx)); + DONE; +}) + +(define_split + [(set (match_operand:TI 0 "register_operand" "") + (match_operand:TI 1 "memory_operand" ""))] + "reload_completed + && offsettable_memref_p (operands[1]) + && (! TARGET_HARD_QUAD + || ! fp_register_operand (operands[0], TImode))" + [(clobber (const_int 0))] +{ + rtx word0 = adjust_address (operands[1], DImode, 0); + rtx word1 = adjust_address (operands[1], DImode, 8); + rtx set_dest, dest1, dest2; + + set_dest = operands[0]; + + dest1 = gen_highpart (DImode, set_dest); + dest2 = gen_lowpart (DImode, set_dest); + + /* Now output, ordering such that we don't clobber any registers + mentioned in the address. */ + if (reg_overlap_mentioned_p (dest1, word1)) + + { + emit_insn (gen_movdi (dest2, word1)); + emit_insn (gen_movdi (dest1, word0)); + } + else + { + emit_insn (gen_movdi (dest1, word0)); + emit_insn (gen_movdi (dest2, word1)); + } + DONE; +}) + +(define_split + [(set (match_operand:TI 0 "memory_operand" "") + (match_operand:TI 1 "register_operand" ""))] + "reload_completed + && offsettable_memref_p (operands[0]) + && (! TARGET_HARD_QUAD + || ! fp_register_operand (operands[1], TImode))" + [(clobber (const_int 0))] +{ + rtx set_src = operands[1]; + + emit_insn (gen_movdi (adjust_address (operands[0], DImode, 0), + gen_highpart (DImode, set_src))); + emit_insn (gen_movdi (adjust_address (operands[0], DImode, 8), + gen_lowpart (DImode, set_src))); + DONE; +}) + ;; Floating point move instructions @@ -2477,7 +2635,7 @@ dest2 = adjust_address (set_dest, DFmode, 8); break; default: - gcc_unreachable (); + gcc_unreachable (); } emit_insn (gen_movdf (dest1, CONST0_RTX (DFmode))); |