]>
Commit | Line | Data |
---|---|---|
9304f876 | 1 | ;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler |
7adcbafe | 2 | ;; Copyright (C) 2012-2022 Free Software Foundation, Inc. |
9304f876 CJW |
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>" | |
e2286268 MC |
49 | [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, r, Da, m, f, Q, f, *r, *f") |
50 | (match_operand:DIDF 1 "general_operand" " r, i, Da, m, r, r, Q, f, f, *f, *r"))] | |
b4350271 KC |
51 | "register_operand(operands[0], <MODE>mode) |
52 | || register_operand(operands[1], <MODE>mode)" | |
9304f876 | 53 | { |
9304f876 CJW |
54 | switch (which_alternative) |
55 | { | |
56 | case 0: | |
57 | return "movd44\t%0, %1"; | |
9304f876 CJW |
58 | case 1: |
59 | /* reg <- const_int, we ask gcc to split instruction. */ | |
60 | return "#"; | |
9304f876 | 61 | case 2: |
e2286268 MC |
62 | /* The memory format is (mem (reg)), |
63 | we can generate 'lmw.bi' instruction. */ | |
64 | return nds32_output_double (operands, true); | |
9304f876 | 65 | case 3: |
e2286268 MC |
66 | /* We haven't 64-bit load instruction, |
67 | we split this pattern to two SImode pattern. */ | |
68 | return "#"; | |
69 | case 4: | |
70 | /* The memory format is (mem (reg)), | |
71 | we can generate 'smw.bi' instruction. */ | |
72 | return nds32_output_double (operands, false); | |
73 | case 5: | |
74 | /* We haven't 64-bit store instruction, | |
75 | we split this pattern to two SImode pattern. */ | |
76 | return "#"; | |
77 | case 6: | |
78 | return nds32_output_float_load (operands); | |
79 | case 7: | |
80 | return nds32_output_float_store (operands); | |
81 | case 8: | |
82 | return "fcpysd\t%0, %1, %1"; | |
83 | case 9: | |
84 | return "fmfdr\t%0, %1"; | |
85 | case 10: | |
86 | return "fmtdr\t%1, %0"; | |
9304f876 CJW |
87 | default: |
88 | gcc_unreachable (); | |
89 | } | |
90 | } | |
e2286268 MC |
91 | [(set_attr "type" "alu,alu,load,load,store,store,fload,fstore,fcpy,fmfdr,fmtdr") |
92 | (set_attr_alternative "length" | |
93 | [ | |
94 | ;; Alternative 0 | |
95 | (if_then_else (match_test "!TARGET_16_BIT") | |
96 | (const_int 4) | |
97 | (const_int 2)) | |
98 | ;; Alternative 1 | |
99 | (const_int 16) | |
100 | ;; Alternative 2 | |
101 | (const_int 4) | |
102 | ;; Alternative 3 | |
103 | (const_int 8) | |
104 | ;; Alternative 4 | |
105 | (const_int 4) | |
106 | ;; Alternative 5 | |
107 | (const_int 8) | |
108 | ;; Alternative 6 | |
109 | (const_int 4) | |
110 | ;; Alternative 7 | |
111 | (const_int 4) | |
112 | ;; Alternative 8 | |
113 | (const_int 4) | |
114 | ;; Alternative 9 | |
115 | (const_int 4) | |
116 | ;; Alternative 10 | |
117 | (const_int 4) | |
118 | ]) | |
119 | (set_attr "feature" " v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu")]) | |
9304f876 | 120 | |
ed4230b2 CJW |
121 | ;; Split move_di pattern when the hard register is odd. |
122 | (define_split | |
123 | [(set (match_operand:DIDF 0 "register_operand" "") | |
124 | (match_operand:DIDF 1 "register_operand" ""))] | |
125 | "(NDS32_IS_GPR_REGNUM (REGNO (operands[0])) | |
126 | && ((REGNO (operands[0]) & 0x1) == 1)) | |
127 | || (NDS32_IS_GPR_REGNUM (REGNO (operands[1])) | |
128 | && ((REGNO (operands[1]) & 0x1) == 1))" | |
129 | [(set (match_dup 2) (match_dup 3)) | |
130 | (set (match_dup 4) (match_dup 5))] | |
131 | { | |
132 | operands[2] = gen_lowpart (SImode, operands[0]); | |
133 | operands[4] = gen_highpart (SImode, operands[0]); | |
134 | operands[3] = gen_lowpart (SImode, operands[1]); | |
135 | operands[5] = gen_highpart (SImode, operands[1]); | |
136 | } | |
137 | ) | |
138 | ||
9304f876 CJW |
139 | (define_split |
140 | [(set (match_operand:DIDF 0 "register_operand" "") | |
141 | (match_operand:DIDF 1 "const_double_operand" ""))] | |
b26fa4f9 | 142 | "flag_pic || reload_completed" |
9304f876 CJW |
143 | [(set (match_dup 2) (match_dup 3)) |
144 | (set (match_dup 4) (match_dup 5))] | |
145 | { | |
146 | /* Construct lowpart rtx. */ | |
147 | operands[2] = gen_lowpart (SImode, operands[0]); | |
148 | operands[3] = gen_lowpart (SImode, operands[1]); | |
149 | ||
150 | /* Construct highpart rtx. */ | |
151 | /* Note that operands[1] can be VOIDmode constant, | |
152 | so we need to use gen_highpart_mode(). | |
e53b6e56 | 153 | Refer to gcc/emit-rtl.cc for more information. */ |
9304f876 CJW |
154 | operands[4] = gen_highpart (SImode, operands[0]); |
155 | operands[5] = gen_highpart_mode (SImode, | |
156 | GET_MODE (operands[0]), operands[1]); | |
157 | ||
158 | /* Actually we would like to create move behavior by ourself. | |
159 | So that movsi expander could have chance to split large constant. */ | |
160 | emit_move_insn (operands[2], operands[3]); | |
e2286268 MC |
161 | |
162 | unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode); | |
163 | if ((UINTVAL (operands[3]) & mask) == (UINTVAL (operands[5]) & mask)) | |
164 | emit_move_insn (operands[4], operands[2]); | |
165 | else | |
166 | emit_move_insn (operands[4], operands[5]); | |
9304f876 CJW |
167 | DONE; |
168 | }) | |
169 | ||
170 | ;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA. | |
171 | ;; We only need to split it under V2 ISA or none-16-bit code generation. | |
172 | (define_split | |
173 | [(set (match_operand:DIDF 0 "register_operand" "") | |
174 | (match_operand:DIDF 1 "register_operand" ""))] | |
175 | "reload_completed | |
e2286268 MC |
176 | && (TARGET_ISA_V2 || !TARGET_16_BIT) |
177 | && NDS32_IS_GPR_REGNUM (REGNO (operands[0])) | |
178 | && NDS32_IS_GPR_REGNUM (REGNO (operands[1]))" | |
9304f876 CJW |
179 | [(set (match_dup 0) (match_dup 1)) |
180 | (set (match_dup 2) (match_dup 3))] | |
181 | { | |
182 | operands[2] = gen_highpart (SImode, operands[0]); | |
183 | operands[3] = gen_highpart (SImode, operands[1]); | |
184 | operands[0] = gen_lowpart (SImode, operands[0]); | |
185 | operands[1] = gen_lowpart (SImode, operands[1]); | |
186 | ||
187 | /* Handle a partial overlap. */ | |
188 | if (rtx_equal_p (operands[0], operands[3])) | |
189 | { | |
190 | rtx tmp0 = operands[0]; | |
191 | rtx tmp1 = operands[1]; | |
192 | ||
193 | operands[0] = operands[2]; | |
194 | operands[1] = operands[3]; | |
195 | operands[2] = tmp0; | |
196 | operands[3] = tmp1; | |
197 | } | |
198 | }) | |
199 | ||
e2286268 MC |
200 | (define_split |
201 | [(set (match_operand:DIDF 0 "nds32_general_register_operand" "") | |
202 | (match_operand:DIDF 1 "memory_operand" ""))] | |
203 | "reload_completed | |
204 | && nds32_split_double_word_load_store_p (operands, true)" | |
205 | [(set (match_dup 2) (match_dup 3)) | |
206 | (set (match_dup 4) (match_dup 5))] | |
207 | { | |
208 | nds32_spilt_doubleword (operands, true); | |
209 | }) | |
210 | ||
211 | (define_split | |
212 | [(set (match_operand:DIDF 0 "memory_operand" "") | |
213 | (match_operand:DIDF 1 "nds32_general_register_operand" ""))] | |
214 | "reload_completed | |
215 | && nds32_split_double_word_load_store_p (operands, false)" | |
216 | [(set (match_dup 2) (match_dup 3)) | |
217 | (set (match_dup 4) (match_dup 5))] | |
218 | { | |
219 | nds32_spilt_doubleword (operands, false); | |
220 | }) | |
221 | ||
9304f876 CJW |
222 | ;; ------------------------------------------------------------- |
223 | ;; Boolean DImode instructions. | |
224 | ;; ------------------------------------------------------------- | |
225 | ||
226 | ;; Nowadays, the generic code is supposed to split the DImode | |
227 | ;; boolean operations and have good code generation. | |
228 | ;; Unless we find out some bad cases, there is no need to | |
229 | ;; define DImode boolean operations by ourself. | |
230 | ||
231 | ;; ------------------------------------------------------------- |