2014-07-12 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / config / nds32 / nds32-doubleword.md
blobe68bfece5e18697c084127dedbd4f5e88040e64c
1 ;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
2 ;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
3 ;; Contributed by Andes Technology Corporation.
4 ;;
5 ;; This file is part of GCC.
6 ;;
7 ;; GCC is free software; you can redistribute it and/or modify it
8 ;; under the terms of the GNU General Public License as published
9 ;; by the Free Software Foundation; either version 3, or (at your
10 ;; option) any later version.
12 ;; GCC is distributed in the hope that it will be useful, but WITHOUT
13 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15 ;; License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3.  If not see
19 ;; <http://www.gnu.org/licenses/>.
22 ;; -------------------------------------------------------------
23 ;; Move DImode/DFmode instructions.
24 ;; -------------------------------------------------------------
27 (define_expand "movdi"
28   [(set (match_operand:DI 0 "general_operand" "")
29         (match_operand:DI 1 "general_operand" ""))]
30   ""
32   /* Need to force register if mem <- !reg.  */
33   if (MEM_P (operands[0]) && !REG_P (operands[1]))
34     operands[1] = force_reg (DImode, operands[1]);
37 (define_expand "movdf"
38   [(set (match_operand:DF 0 "general_operand" "")
39         (match_operand:DF 1 "general_operand" ""))]
40   ""
42   /* Need to force register if mem <- !reg.  */
43   if (MEM_P (operands[0]) && !REG_P (operands[1]))
44     operands[1] = force_reg (DFmode, operands[1]);
48 (define_insn "move_<mode>"
49   [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m")
50         (match_operand:DIDF 1 "general_operand"      " r, i, m, r"))]
51   ""
53   rtx addr;
54   rtx otherops[5];
56   switch (which_alternative)
57     {
58     case 0:
59       return "movd44\t%0, %1";
61     case 1:
62       /* reg <- const_int, we ask gcc to split instruction.  */
63       return "#";
65     case 2:
66       /* Refer to nds32_legitimate_address_p() in nds32.c,
67          we only allow "reg", "symbol_ref", "const", and "reg + const_int"
68          as address rtx for DImode/DFmode memory access.  */
69       addr = XEXP (operands[1], 0);
71       otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
72       otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
73       otherops[2] = addr;
75       if (REG_P (addr))
76         {
77           /* (reg) <- (mem (reg)) */
78           output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops);
79         }
80       else if (GET_CODE (addr) == PLUS)
81         {
82           /* (reg) <- (mem (plus (reg) (const_int))) */
83           rtx op0 = XEXP (addr, 0);
84           rtx op1 = XEXP (addr, 1);
86           if (REG_P (op0))
87             {
88               otherops[2] = op0;
89               otherops[3] = op1;
90               otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
91             }
92           else
93             {
94               otherops[2] = op1;
95               otherops[3] = op0;
96               otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
97             }
99           /* To avoid base overwrite when REGNO(%0) == REGNO(%2).  */
100           if (REGNO (otherops[0]) != REGNO (otherops[2]))
101             {
102               output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops);
103               output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
104             }
105           else
106             {
107               output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
108               output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops);
109             }
110         }
111       else
112         {
113           /* (reg) <- (mem (symbol_ref ...))
114              (reg) <- (mem (const ...)) */
115           output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops);
116           output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops);
117         }
119       /* We have already used output_asm_insn() by ourself,
120          so return an empty string.  */
121       return "";
123     case 3:
124       /* Refer to nds32_legitimate_address_p() in nds32.c,
125          we only allow "reg", "symbol_ref", "const", and "reg + const_int"
126          as address rtx for DImode/DFmode memory access.  */
127       addr = XEXP (operands[0], 0);
129       otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1]));
130       otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
131       otherops[2] = addr;
133       if (REG_P (addr))
134         {
135           /* (mem (reg)) <- (reg) */
136           output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops);
137         }
138       else if (GET_CODE (addr) == PLUS)
139         {
140           /* (mem (plus (reg) (const_int))) <- (reg) */
141           rtx op0 = XEXP (addr, 0);
142           rtx op1 = XEXP (addr, 1);
144           if (REG_P (op0))
145             {
146               otherops[2] = op0;
147               otherops[3] = op1;
148               otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
149             }
150           else
151             {
152               otherops[2] = op1;
153               otherops[3] = op0;
154               otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
155             }
157           /* To avoid base overwrite when REGNO(%0) == REGNO(%2).  */
158           if (REGNO (otherops[0]) != REGNO (otherops[2]))
159             {
160               output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
161               output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
162             }
163           else
164             {
165               output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
166               output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
167             }
168         }
169       else
170         {
171           /* (mem (symbol_ref ...)) <- (reg)
172              (mem (const ...))      <- (reg) */
173           output_asm_insn ("swi.gp\t%0, [ + %2]", otherops);
174           output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops);
175         }
177       /* We have already used output_asm_insn() by ourself,
178          so return an empty string.  */
179       return "";
181     default:
182       gcc_unreachable ();
183     }
185   [(set_attr "type"   "move,move,move,move")
186    (set_attr "length" "   4,  16,   8,   8")])
188 (define_split
189   [(set (match_operand:DIDF 0 "register_operand"     "")
190         (match_operand:DIDF 1 "const_double_operand" ""))]
191   "reload_completed"
192   [(set (match_dup 2) (match_dup 3))
193    (set (match_dup 4) (match_dup 5))]
195   /* Construct lowpart rtx.  */
196   operands[2] = gen_lowpart (SImode, operands[0]);
197   operands[3] = gen_lowpart (SImode, operands[1]);
199   /* Construct highpart rtx.  */
200   /* Note that operands[1] can be VOIDmode constant,
201      so we need to use gen_highpart_mode().
202      Refer to gcc/emit-rtl.c for more information.  */
203   operands[4] = gen_highpart (SImode, operands[0]);
204   operands[5] = gen_highpart_mode (SImode,
205                                    GET_MODE (operands[0]), operands[1]);
207   /* Actually we would like to create move behavior by ourself.
208      So that movsi expander could have chance to split large constant.  */
209   emit_move_insn (operands[2], operands[3]);
210   emit_move_insn (operands[4], operands[5]);
211   DONE;
214 ;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA.
215 ;; We only need to split it under V2 ISA or none-16-bit code generation.
216 (define_split
217   [(set (match_operand:DIDF 0 "register_operand" "")
218         (match_operand:DIDF 1 "register_operand" ""))]
219   "reload_completed
220    && (TARGET_ISA_V2 || !TARGET_16_BIT)"
221   [(set (match_dup 0) (match_dup 1))
222    (set (match_dup 2) (match_dup 3))]
224   operands[2] = gen_highpart (SImode, operands[0]);
225   operands[3] = gen_highpart (SImode, operands[1]);
226   operands[0] = gen_lowpart (SImode, operands[0]);
227   operands[1] = gen_lowpart (SImode, operands[1]);
229   /* Handle a partial overlap.  */
230   if (rtx_equal_p (operands[0], operands[3]))
231     {
232       rtx tmp0 = operands[0];
233       rtx tmp1 = operands[1];
235       operands[0] = operands[2];
236       operands[1] = operands[3];
237       operands[2] = tmp0;
238       operands[3] = tmp1;
239     }
242 ;; -------------------------------------------------------------
243 ;; Boolean DImode instructions.
244 ;; -------------------------------------------------------------
246 ;; Nowadays, the generic code is supposed to split the DImode
247 ;; boolean operations and have good code generation.
248 ;; Unless we find out some bad cases, there is no need to
249 ;; define DImode boolean operations by ourself.
251 ;; -------------------------------------------------------------