]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-doubleword.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-doubleword.md
1 ;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
2 ;; Copyright (C) 2012-2016 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.
11 ;;
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.
16 ;;
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/>.
20
21
22 ;; -------------------------------------------------------------
23 ;; Move DImode/DFmode instructions.
24 ;; -------------------------------------------------------------
25
26
27 (define_expand "movdi"
28 [(set (match_operand:DI 0 "general_operand" "")
29 (match_operand:DI 1 "general_operand" ""))]
30 ""
31 {
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]);
35 })
36
37 (define_expand "movdf"
38 [(set (match_operand:DF 0 "general_operand" "")
39 (match_operand:DF 1 "general_operand" ""))]
40 ""
41 {
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]);
45 })
46
47
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 ""
52 {
53 rtx addr;
54 rtx otherops[5];
55
56 switch (which_alternative)
57 {
58 case 0:
59 return "movd44\t%0, %1";
60
61 case 1:
62 /* reg <- const_int, we ask gcc to split instruction. */
63 return "#";
64
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);
70
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;
74
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);
85
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 }
98
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 }
118
119 /* We have already used output_asm_insn() by ourself,
120 so return an empty string. */
121 return "";
122
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);
128
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;
132
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);
143
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 }
156
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 }
176
177 /* We have already used output_asm_insn() by ourself,
178 so return an empty string. */
179 return "";
180
181 default:
182 gcc_unreachable ();
183 }
184 }
185 [(set_attr "type" "move,move,move,move")
186 (set_attr "length" " 4, 16, 8, 8")])
187
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))]
194 {
195 /* Construct lowpart rtx. */
196 operands[2] = gen_lowpart (SImode, operands[0]);
197 operands[3] = gen_lowpart (SImode, operands[1]);
198
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]);
206
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;
212 })
213
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))]
223 {
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]);
228
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];
234
235 operands[0] = operands[2];
236 operands[1] = operands[3];
237 operands[2] = tmp0;
238 operands[3] = tmp1;
239 }
240 })
241
242 ;; -------------------------------------------------------------
243 ;; Boolean DImode instructions.
244 ;; -------------------------------------------------------------
245
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.
250
251 ;; -------------------------------------------------------------