]>
Commit | Line | Data |
---|---|---|
f6a83b4a | 1 | ;; Machine Description for TI MSP43* processors |
a5544970 | 2 | ;; Copyright (C) 2013-2019 Free Software Foundation, Inc. |
f6a83b4a DD |
3 | ;; Contributed by Red Hat. |
4 | ||
5 | ;; This file is part of GCC. | |
6 | ||
7 | ;; GCC is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 3, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GCC is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public 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 | \f | |
21 | ||
22 | (define_constants | |
23 | [ | |
24 | (PC_REGNO 0) | |
25 | (SP_REGNO 1) | |
26 | (CARRY 2) | |
27 | ]) | |
28 | ||
29 | (define_c_enum "unspec" | |
30 | [ | |
31 | UNS_PROLOGUE_START_MARKER | |
32 | UNS_PROLOGUE_END_MARKER | |
33 | UNS_EPILOGUE_START_MARKER | |
34 | UNS_EPILOGUE_HELPER | |
35 | ||
36 | UNS_PUSHM | |
37 | UNS_POPM | |
38 | ||
39 | UNS_GROW_AND_SWAP | |
40 | UNS_SWAP_AND_SHRINK | |
cad055a4 NC |
41 | |
42 | UNS_DINT | |
43 | UNS_EINT | |
44 | UNS_PUSH_INTR | |
45 | UNS_POP_INTR | |
46 | UNS_BIC_SR | |
47 | UNS_BIS_SR | |
4f50b9ff DD |
48 | |
49 | UNS_REFSYM_NEED_EXIT | |
5f35dde5 DD |
50 | |
51 | UNS_DELAY_32 | |
52 | UNS_DELAY_32X | |
53 | UNS_DELAY_16 | |
54 | UNS_DELAY_16X | |
55 | UNS_DELAY_2 | |
56 | UNS_DELAY_1 | |
57 | UNS_DELAY_START | |
58 | UNS_DELAY_END | |
f6a83b4a | 59 | ]) |
c6f709ec | 60 | |
d7edde11 NC |
61 | ;; This is an approximation. |
62 | (define_attr "length" "" (const_int 4)) | |
63 | ||
f6a83b4a DD |
64 | (include "predicates.md") |
65 | (include "constraints.md") | |
66 | ||
67 | (define_mode_iterator QHI [QI HI PSI]) | |
68 | ||
69 | ;; There are two basic "family" tests we do here: | |
70 | ;; | |
71 | ;; msp430x - true if 430X instructions are available. | |
72 | ;; TARGET_LARGE - true if pointers are 20-bits | |
73 | ;; | |
74 | ;; Note that there are three supported cases, since the base 430 | |
75 | ;; doesn't have 20-bit pointers: | |
76 | ;; | |
77 | ;; 1. MSP430 cpu, small model | |
78 | ;; 2. MSP430X cpu, small model. | |
79 | ;; 3. MSP430X cpu, large model. | |
80 | ||
81 | ;;------------------------------------------------------------ | |
82 | ;; Moves | |
83 | ||
84 | ;; Push/Pop must be before the generic move patterns | |
85 | ||
86 | (define_insn "push" | |
87 | [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO))) | |
88 | (match_operand:HI 0 "register_operand" "r"))] | |
89 | "" | |
90 | "PUSH\t%0" | |
91 | ) | |
92 | ||
93 | (define_insn "pusha" | |
94 | [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO))) | |
95 | (match_operand:PSI 0 "register_operand" "r"))] | |
96 | "TARGET_LARGE" | |
97 | "PUSHX.A\t%0" | |
98 | ) | |
99 | ||
100 | (define_insn "pushm" | |
101 | [(unspec_volatile [(match_operand 0 "register_operand" "r") | |
cad055a4 | 102 | (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)] |
f6a83b4a | 103 | "" |
51ac3042 | 104 | "PUSHM%b0\t%1, %0" |
f6a83b4a DD |
105 | ) |
106 | ||
107 | (define_insn "pop" | |
108 | [(set (match_operand:HI 0 "register_operand" "=r") | |
109 | (mem:HI (post_inc:HI (reg:HI SP_REGNO))))] | |
110 | "" | |
111 | "POP\t%0" | |
112 | ) | |
113 | ||
114 | (define_insn "popa" | |
115 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
116 | (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))] | |
117 | "TARGET_LARGE" | |
118 | "POPX.A\t%0" | |
119 | ) | |
120 | ||
121 | ;; This is nasty. Operand0 is bogus. It is only there so that we can get a | |
51ac3042 | 122 | ;; mode for the %b0 to work. We should use operand1 for this, but that does |
f6a83b4a DD |
123 | ;; not have a mode. |
124 | ;; | |
125 | ;; Operand1 is actually a register, but we cannot accept (REG...) because the | |
126 | ;; cprop_hardreg pass can and will renumber registers even inside | |
127 | ;; unspec_volatiles. So we take an integer register number parameter and | |
d4f283a1 | 128 | ;; fudge it to be a register name when we generate the assembler. |
f6a83b4a DD |
129 | ;; |
130 | ;; The pushm pattern does not have this problem because of all of the | |
131 | ;; frame info cruft attached to it, so cprop_hardreg leaves it alone. | |
132 | (define_insn "popm" | |
133 | [(unspec_volatile [(match_operand 0 "register_operand" "r") | |
134 | (match_operand 1 "immediate_operand" "i") | |
135 | (match_operand 2 "immediate_operand" "i")] UNS_POPM)] | |
136 | "" | |
d4f283a1 | 137 | "POPM%b0\t%2, r%J1" |
f6a83b4a DD |
138 | ) |
139 | ||
140 | ;; The next two patterns are here to support a "feature" of how GCC implements | |
141 | ;; varargs. When a function uses varargs and the *second* to last named | |
142 | ;; argument is split between argument registers and the stack, gcc expects the | |
143 | ;; callee to allocate space on the stack that can contain the register-based | |
144 | ;; part of the argument. This space *has* to be just before the remaining | |
145 | ;; arguments (ie the ones that are fully on the stack). | |
146 | ;; | |
147 | ;; The problem is that the MSP430 CALL instruction pushes the return address | |
148 | ;; onto the stack in the exact place where the callee wants to allocate | |
149 | ;; this extra space. So we need a sequence of instructions that can allocate | |
150 | ;; the extra space and then move the return address down the stack, so that | |
151 | ;; the extra space is now adjacent to the remaining arguments. | |
152 | ;; | |
153 | ;; This could be constructed through regular insns, but they might be split up | |
154 | ;; by a misguided optimization, so an unspec volatile is used instead. | |
155 | ||
156 | (define_insn "grow_and_swap" | |
157 | [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP)] | |
158 | "" | |
c6f709ec NC |
159 | "* |
160 | if (TARGET_LARGE) | |
161 | return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\"; | |
162 | return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\"; | |
163 | " | |
164 | ) | |
f6a83b4a DD |
165 | |
166 | (define_insn "swap_and_shrink" | |
167 | [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK)] | |
168 | "" | |
c6f709ec NC |
169 | "* return TARGET_LARGE |
170 | ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\" | |
171 | : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\"; | |
172 | ") | |
f6a83b4a DD |
173 | |
174 | ; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a | |
175 | ; zero_extend anyway. Catch it here. | |
176 | (define_insn "movqihi" | |
177 | [(set (match_operand:HI 0 "register_operand" "=r,r") | |
178 | (zero_extend:HI (match_operand:QI 1 "memory_operand" "Ys,m")))] | |
179 | "" | |
180 | "@ | |
181 | MOV.B\t%1, %0 | |
182 | MOV%X1.B\t%1, %0" | |
183 | ) | |
184 | ||
c32ab325 DD |
185 | (define_insn "movqi_topbyte" |
186 | [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r") | |
187 | (subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))] | |
188 | "msp430x" | |
189 | "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0" | |
190 | ) | |
191 | ||
f6a83b4a | 192 | (define_insn "movqi" |
a3b50977 DD |
193 | [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm") |
194 | (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))] | |
f6a83b4a DD |
195 | "" |
196 | "@ | |
197 | MOV.B\t%1, %0 | |
198 | MOV%X0.B\t%1, %0" | |
199 | ) | |
200 | ||
201 | (define_insn "movhi" | |
3f02735b DD |
202 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rYs,rm") |
203 | (match_operand:HI 1 "msp_general_operand" "N,riYs,rmi"))] | |
f6a83b4a DD |
204 | "" |
205 | "@ | |
3f02735b | 206 | MOV.B\t%1, %0 |
f6a83b4a DD |
207 | MOV.W\t%1, %0 |
208 | MOV%X0.W\t%1, %0" | |
209 | ) | |
210 | ||
211 | (define_expand "movsi" | |
40ada30a NC |
212 | [(set (match_operand:SI 0 "nonimmediate_operand") |
213 | (match_operand:SI 1 "general_operand"))] | |
f6a83b4a DD |
214 | "" |
215 | "" | |
216 | ) | |
d7edde11 | 217 | |
14ae1d88 DD |
218 | (define_insn_and_split "movsi_s" |
219 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
220 | (subreg:SI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] | |
221 | "" | |
222 | "" | |
223 | "reload_completed" | |
224 | [(set (match_operand:HI 2 "nonimmediate_operand") | |
225 | (match_operand:HI 4 "general_operand")) | |
226 | (set (match_operand:HI 3 "nonimmediate_operand") | |
227 | (match_operand:HI 5 "general_operand"))] | |
228 | "msp430_split_movsi (operands);" | |
229 | ) | |
230 | ||
f6a83b4a DD |
231 | (define_insn_and_split "movsi_x" |
232 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
233 | (match_operand:SI 1 "general_operand" "rmi"))] | |
234 | "" | |
235 | "#" | |
236 | "reload_completed" | |
237 | [(set (match_operand:HI 2 "nonimmediate_operand") | |
238 | (match_operand:HI 4 "general_operand")) | |
239 | (set (match_operand:HI 3 "nonimmediate_operand") | |
240 | (match_operand:HI 5 "general_operand"))] | |
241 | "msp430_split_movsi (operands);" | |
242 | ) | |
243 | ||
244 | ;; Some MOVX.A cases can be done with MOVA, this is only a few of them. | |
245 | (define_insn "movpsi" | |
3f02735b DD |
246 | [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,r,r,Ya,rm") |
247 | (match_operand:PSI 1 "msp_general_operand" "N,O,riYa,r,rmi"))] | |
f6a83b4a DD |
248 | "" |
249 | "@ | |
3f02735b DD |
250 | MOV.B\t%1, %0 |
251 | MOV.W\t%1, %0 | |
c32ab325 DD |
252 | MOVA\t%1, %0 |
253 | MOVA\t%1, %0 | |
254 | MOVX.A\t%1, %0") | |
f6a83b4a DD |
255 | |
256 | ; This pattern is identical to the truncsipsi2 pattern except | |
257 | ; that it uses a SUBREG instead of a TRUNC. It is needed in | |
258 | ; order to prevent reload from converting (set:SI (SUBREG:PSI (SI))) | |
259 | ; into (SET:PSI (PSI)). | |
260 | ; | |
261 | ; Note: using POPM.A #1 is two bytes smaller than using POPX.A.... | |
262 | ||
263 | (define_insn "movsipsi2" | |
264 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
265 | (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] | |
c32ab325 | 266 | "msp430x" |
d4f283a1 | 267 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0" |
f6a83b4a DD |
268 | ) |
269 | ||
e56989ff NC |
270 | ;; Produced when converting a pointer to an integer via a union, eg gcc.dg/pr47201.c. |
271 | (define_insn "*movpsihi2_lo" | |
272 | [(set (match_operand:HI 0 "register_operand" "=r") | |
273 | (subreg:HI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] | |
274 | "msp430x" | |
275 | "MOVA\t%1, %0" | |
276 | ) | |
277 | ||
f6a83b4a DD |
278 | ;;------------------------------------------------------------ |
279 | ;; Math | |
280 | ||
281 | (define_insn "addpsi3" | |
a3b50977 DD |
282 | [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,rm") |
283 | (plus:PSI (match_operand:PSI 1 "msp_nonimmediate_operand" "%0,0") | |
284 | (match_operand:PSI 2 "msp_general_operand" "rLs,rmi")))] | |
f6a83b4a DD |
285 | "" |
286 | "@ | |
287 | ADDA\t%2, %0 | |
288 | ADDX.A\t%2, %0" | |
289 | ) | |
290 | ||
291 | (define_insn "addqi3" | |
a3b50977 DD |
292 | [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm") |
293 | (plus:QI (match_operand:QI 1 "msp_nonimmediate_operand" "%0,0") | |
294 | (match_operand:QI 2 "msp_general_operand" "riYs,rmi")))] | |
f6a83b4a DD |
295 | "" |
296 | "@ | |
297 | ADD.B\t%2, %0 | |
298 | ADD%X0.B\t%2, %0" | |
299 | ) | |
300 | ||
301 | (define_insn "addhi3" | |
a3b50977 DD |
302 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm") |
303 | (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") | |
304 | (match_operand:HI 2 "msp_general_operand" "riYs,rmi")))] | |
f6a83b4a DD |
305 | "" |
306 | "@ | |
307 | ADD.W\t%2, %0 | |
308 | ADD%X0.W\t%2, %0" | |
309 | ) | |
310 | ||
311 | ; This pattern is needed in order to avoid reload problems. | |
312 | ; It takes an SI pair of registers, adds a value to them, and | |
313 | ; then converts them into a single PSI register. | |
314 | ||
315 | (define_insn "addsipsi3" | |
316 | [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0) | |
317 | (plus:SI (match_operand:SI 1 "register_operand" "0") | |
318 | (match_operand 2 "general_operand" "rmi")))] | |
319 | "" | |
d4f283a1 | 320 | "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0" |
f6a83b4a DD |
321 | ) |
322 | ||
323 | (define_insn "addsi3" | |
324 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm") | |
325 | (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") | |
326 | (match_operand:SI 2 "general_operand" "r,mi")))] | |
327 | "" | |
328 | "@ | |
329 | ADD\t%L2, %L0 { ADDC\t%H2, %H0 | |
330 | ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0" | |
331 | ) | |
332 | ||
333 | ; Version of addhi that exposes the carry operations, for SImode adds. | |
334 | ; | |
335 | ; NOTE - we are playing a dangerous game with GCC here. We have these two | |
336 | ; add patterns and the splitter that follows because our tests have shown | |
337 | ; that this results in a significant reduction in code size - because GCC is | |
338 | ; able to discard any unused part of the addition. We have to annotate the | |
339 | ; patterns with the set and use of the carry flag because otherwise GCC will | |
340 | ; discard parts of the addition when they are actually needed. But we have | |
341 | ; not annotated all the other patterns that set the CARRY flag as doing so | |
342 | ; results in an overall increase in code size[1]. Instead we just *hope* | |
343 | ; that GCC will not move a carry-setting instruction in between the first | |
344 | ; and second adds. | |
345 | ; | |
346 | ; So far our experiments have shown that GCC is likely to move MOV and CMP | |
347 | ; instructions in between the two adds, but not other instructions. MOV is | |
348 | ; safe, CMP is not. So we have annotated the CMP patterns and left the | |
349 | ; subtract, shift and other add patterns alone. At the moment this is | |
350 | ; working, but with future changes to the generic parts of GCC that might | |
351 | ; change. | |
352 | ; | |
353 | ; [1] It is not clear exactly why the code size increases. The cause appears | |
354 | ; to be that reload is more prevelent to spilling a variable onto the stack | |
355 | ; but why it does this is unknown. Possibly the additional CLOBBERs necessary | |
356 | ; to correctly annotate the other patterns makes reload think that there is | |
357 | ; increased register pressure. Or possibly reload does not handle ADD patterns | |
358 | ; that are not single_set() very well. | |
359 | ||
360 | (define_insn "addhi3_cy" | |
51ac3042 | 361 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm") |
a3b50977 | 362 | (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") |
d4f283a1 | 363 | (match_operand:HI 2 "msp_nonimmediate_operand" "r,rm"))) |
f6a83b4a DD |
364 | (set (reg:BI CARRY) |
365 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
366 | (zero_extend:SI (match_dup 2))) | |
367 | (const_int 16)))) | |
368 | ] | |
369 | "" | |
370 | "@ | |
40ada30a NC |
371 | ADD\t%2, %1 ; cy |
372 | ADD%X0\t%2, %1 ; cy" | |
f6a83b4a DD |
373 | ) |
374 | ||
375 | (define_insn "addhi3_cy_i" | |
d4f283a1 | 376 | [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") |
f6a83b4a | 377 | (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") |
d4f283a1 | 378 | (match_operand:HI 2 "immediate_operand" "i,i"))) |
f6a83b4a DD |
379 | (set (reg:BI CARRY) |
380 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
381 | (match_operand 3 "immediate_operand" "i,i")) | |
382 | (const_int 16)))) | |
383 | ] | |
384 | "" | |
385 | "@ | |
40ada30a NC |
386 | ADD\t%2, %1 ; cy |
387 | ADD%X0\t%2, %1 ; cy" | |
f6a83b4a DD |
388 | ) |
389 | ||
390 | ; Version of addhi that adds the carry, for SImode adds. | |
391 | (define_insn "addchi4_cy" | |
51ac3042 | 392 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm") |
a3b50977 | 393 | (plus:HI (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") |
d4f283a1 | 394 | (match_operand:HI 2 "msp_general_operand" "ri,rmi")) |
f6a83b4a DD |
395 | (zero_extend:HI (reg:BI CARRY)))) |
396 | ] | |
397 | "" | |
398 | "@ | |
40ada30a NC |
399 | ADDC\t%2, %1 |
400 | ADDC%X0\t%2, %1" | |
f6a83b4a DD |
401 | ) |
402 | ||
403 | ; Split an SImode add into two HImode adds, keeping track of the carry | |
404 | ; so that gcc knows when it can and can't optimize away the two | |
405 | ; halves. | |
406 | (define_split | |
51ac3042 | 407 | [(set (match_operand:SI 0 "msp430_nonsubreg_operand") |
9c5f6203 DD |
408 | (plus:SI (match_operand:SI 1 "msp430_nonsubreg_operand") |
409 | (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand"))) | |
f6a83b4a DD |
410 | ] |
411 | "" | |
412 | [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm") | |
413 | (plus:HI (match_dup 4) | |
414 | (match_dup 5))) | |
415 | (set (reg:BI CARRY) | |
416 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4)) | |
417 | (match_dup 9)) | |
418 | (const_int 16)))) | |
419 | ]) | |
420 | (set (match_operand:HI 6 "nonimmediate_operand" "=&rm") | |
421 | (plus:HI (plus:HI (match_dup 7) | |
422 | (match_dup 8)) | |
423 | (zero_extend:HI (reg:BI CARRY)))) | |
424 | ] | |
425 | " | |
426 | operands[3] = msp430_subreg (HImode, operands[0], SImode, 0); | |
427 | operands[4] = msp430_subreg (HImode, operands[1], SImode, 0); | |
428 | operands[5] = msp430_subreg (HImode, operands[2], SImode, 0); | |
429 | operands[6] = msp430_subreg (HImode, operands[0], SImode, 2); | |
430 | operands[7] = msp430_subreg (HImode, operands[1], SImode, 2); | |
431 | operands[8] = msp430_subreg (HImode, operands[2], SImode, 2); | |
5704db33 NC |
432 | |
433 | /* BZ 64160: Do not use this splitter when the dest partially overlaps the source. */ | |
434 | if (reg_overlap_mentioned_p (operands[3], operands[7]) | |
435 | || reg_overlap_mentioned_p (operands[3], operands[8])) | |
436 | FAIL; | |
437 | ||
f6a83b4a | 438 | if (GET_CODE (operands[5]) == CONST_INT) |
5704db33 | 439 | operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff); |
f6a83b4a | 440 | else |
5704db33 | 441 | operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]); |
f6a83b4a DD |
442 | " |
443 | ) | |
444 | ||
445 | ||
446 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
447 | (define_insn "subpsi3" | |
448 | [(set (match_operand:PSI 0 "nonimmediate_operand" "=r, rm, &?r, ?&r") | |
449 | (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i") | |
450 | (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r")))] | |
451 | "" | |
452 | "@ | |
453 | SUBA\t%2, %0 | |
454 | SUBX.A\t%2, %0 | |
455 | MOVX.A\t%1, %0 { SUBX.A\t%2, %0 | |
456 | MOVX.A\t%1, %0 { SUBA\t%2, %0" | |
457 | ) | |
458 | ||
459 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
460 | (define_insn "subqi3" | |
461 | [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") | |
462 | (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i") | |
463 | (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r")))] | |
464 | "" | |
465 | "@ | |
466 | SUB.B\t%2, %0 | |
467 | SUB%X0.B\t%2, %0 | |
468 | MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0 | |
469 | MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" | |
470 | ) | |
471 | ||
472 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
473 | (define_insn "subhi3" | |
474 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") | |
475 | (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i") | |
476 | (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r")))] | |
477 | "" | |
478 | "@ | |
479 | SUB.W\t%2, %0 | |
480 | SUB%X0.W\t%2, %0 | |
481 | MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0 | |
482 | MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" | |
483 | ) | |
484 | ||
485 | (define_insn "subsi3" | |
486 | [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm") | |
487 | (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0") | |
488 | (match_operand:SI 2 "general_operand" "rmi")))] | |
489 | "" | |
490 | "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0" | |
491 | ) | |
492 | ||
493 | (define_insn "*bic<mode>_cg" | |
494 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m") | |
495 | (and:QHI (match_operand:QHI 1 "msp_general_operand" "0,0") | |
496 | (match_operand 2 "msp430_inv_constgen_operator" "n,n")))] | |
497 | "" | |
498 | "@ | |
51ac3042 NC |
499 | BIC%x0%b0\t#%I2, %0 |
500 | BIC%X0%b0\t#%I2, %0" | |
f6a83b4a DD |
501 | ) |
502 | ||
503 | (define_insn "bic<mode>3" | |
504 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") | |
505 | (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn")) | |
506 | (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))] | |
507 | "" | |
508 | "@ | |
51ac3042 NC |
509 | BIC%x0%b0\t%1, %0 |
510 | BIC%X0%b0\t%1, %0" | |
f6a83b4a DD |
511 | ) |
512 | ||
513 | (define_insn "and<mode>3" | |
3f02735b DD |
514 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=r,rYs,rm") |
515 | (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0,0") | |
516 | (match_operand:QHI 2 "msp_general_operand" "N,riYs,rmi")))] | |
f6a83b4a DD |
517 | "" |
518 | "@ | |
3f02735b | 519 | AND%x0.B\t%2, %0 |
51ac3042 NC |
520 | AND%x0%b0\t%2, %0 |
521 | AND%X0%b0\t%2, %0" | |
f6a83b4a DD |
522 | ) |
523 | ||
524 | (define_insn "ior<mode>3" | |
51ac3042 | 525 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") |
f6a83b4a DD |
526 | (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") |
527 | (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))] | |
528 | "" | |
529 | "@ | |
51ac3042 NC |
530 | BIS%x0%b0\t%2, %0 |
531 | BIS%X0%b0\t%2, %0" | |
f6a83b4a DD |
532 | ) |
533 | ||
534 | (define_insn "xor<mode>3" | |
51ac3042 | 535 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") |
a3b50977 DD |
536 | (xor:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") |
537 | (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))] | |
f6a83b4a DD |
538 | "" |
539 | "@ | |
51ac3042 NC |
540 | XOR%x0%b0\t%2, %0 |
541 | XOR%X0%b0\t%2, %0" | |
f6a83b4a DD |
542 | ) |
543 | ||
544 | ;; Macro : XOR #~0, %0 | |
545 | (define_insn "one_cmpl<mode>2" | |
51ac3042 | 546 | [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m") |
a3b50977 | 547 | (not:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "0,0")))] |
f6a83b4a DD |
548 | "" |
549 | "@ | |
51ac3042 NC |
550 | INV%x0%b0\t%0 |
551 | INV%X0%b0\t%0" | |
f6a83b4a DD |
552 | ) |
553 | ||
554 | (define_insn "extendqihi2" | |
51ac3042 | 555 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m") |
a3b50977 | 556 | (sign_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))] |
f6a83b4a DD |
557 | "" |
558 | "@ | |
559 | SXT%X0\t%0 | |
560 | SXT%X0\t%0" | |
561 | ) | |
562 | ||
563 | (define_insn "zero_extendqihi2" | |
3f02735b DD |
564 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,r,r,m") |
565 | (zero_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,rYs,m,0")))] | |
f6a83b4a DD |
566 | "" |
567 | "@ | |
568 | AND\t#0xff, %0 | |
3f02735b DD |
569 | MOV.B\t%1, %0 |
570 | MOV%X0.B\t%1, %0 | |
f6a83b4a DD |
571 | AND%X0\t#0xff, %0" |
572 | ) | |
573 | ||
574 | ;; Eliminate extraneous zero-extends mysteriously created by gcc. | |
575 | (define_peephole2 | |
576 | [(set (match_operand:HI 0 "register_operand") | |
577 | (zero_extend:HI (match_operand:QI 1 "general_operand"))) | |
578 | (set (match_operand:HI 2 "register_operand") | |
579 | (zero_extend:HI (match_operand:QI 3 "register_operand")))] | |
580 | "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])" | |
581 | [(set (match_dup 0) | |
582 | (zero_extend:HI (match_dup 1)))] | |
583 | ) | |
d7edde11 | 584 | |
f6a83b4a | 585 | (define_insn "zero_extendhipsi2" |
d4f283a1 | 586 | [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,m") |
a3b50977 | 587 | (zero_extend:PSI (match_operand:HI 1 "msp_nonimmediate_operand" "rm,r")))] |
f6a83b4a | 588 | "" |
85bd3c01 NC |
589 | "@ |
590 | MOVX\t%1, %0 | |
591 | MOVX.A\t%1, %0" | |
f6a83b4a DD |
592 | ) |
593 | ||
594 | (define_insn "truncpsihi2" | |
a3b50977 | 595 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm") |
f6a83b4a DD |
596 | (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] |
597 | "" | |
598 | "MOVX\t%1, %0" | |
599 | ) | |
600 | ||
601 | (define_insn "extendhisi2" | |
602 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r") | |
603 | (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] | |
604 | "" | |
605 | { return msp430x_extendhisi (operands); } | |
606 | ) | |
607 | ||
608 | (define_insn "extendhipsi2" | |
609 | [(set (match_operand:PSI 0 "nonimmediate_operand" "=r") | |
610 | (subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))] | |
c32ab325 | 611 | "msp430x" |
862edcd1 | 612 | "RLAM.A #4, %0 { RRAM.A #4, %0" |
f6a83b4a DD |
613 | ) |
614 | ||
615 | ;; Look for cases where integer/pointer conversions are suboptimal due | |
616 | ;; to missing patterns, despite us not having opcodes for these | |
617 | ;; patterns. Doing these manually allows for alternate optimization | |
618 | ;; paths. | |
3f02735b DD |
619 | |
620 | (define_insn "zero_extendqisi2" | |
621 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r") | |
525213a5 JL |
622 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] |
623 | "" | |
3f02735b DD |
624 | "MOV.B\t%1,%L0 { CLR\t%H0" |
625 | ) | |
626 | ||
f6a83b4a | 627 | (define_insn "zero_extendhisi2" |
bdafd679 NC |
628 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") |
629 | (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")))] | |
525213a5 | 630 | "" |
bdafd679 NC |
631 | "@ |
632 | MOV.W\t#0,%H0 | |
633 | MOV.W\t%1,%L0 { MOV.W\t#0,%H0" | |
f6a83b4a DD |
634 | ) |
635 | ||
636 | (define_insn "zero_extendhisipsi2" | |
637 | [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r") | |
638 | (subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))] | |
c32ab325 | 639 | "msp430x" |
f6a83b4a DD |
640 | "@ |
641 | AND.W\t#-1,%0 | |
642 | MOV.W\t%1,%0" | |
643 | ) | |
644 | ||
645 | (define_insn "extend_and_shift1_hipsi2" | |
646 | [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) | |
647 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) | |
648 | (const_int 1)))] | |
c32ab325 | 649 | "msp430x" |
862edcd1 | 650 | "RLAM.A #4, %0 { RRAM.A #3, %0" |
f6a83b4a DD |
651 | ) |
652 | ||
653 | (define_insn "extend_and_shift2_hipsi2" | |
654 | [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) | |
655 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) | |
656 | (const_int 2)))] | |
c32ab325 | 657 | "msp430x" |
862edcd1 | 658 | "RLAM.A #4, %0 { RRAM.A #2, %0" |
f6a83b4a DD |
659 | ) |
660 | ||
661 | ; Nasty - we are sign-extending a 20-bit PSI value in one register into | |
662 | ; two adjacent 16-bit registers to make an SI value. There is no MSP430X | |
663 | ; instruction that will do this, so we push the 20-bit value onto the stack | |
664 | ; and then pop it off as two 16-bit values. | |
665 | ; | |
666 | ; FIXME: The MSP430X documentation does not specify if zero-extension or | |
667 | ; sign-extension happens when the 20-bit value is pushed onto the stack. | |
668 | ; It is probably zero-extension, but if not this pattern will not work | |
669 | ; when the PSI value is negative.. | |
670 | ; | |
671 | ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... | |
8f0e7f6f NC |
672 | ; |
673 | ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused | |
674 | ; about extending a single PSI mode register into a pair of SImode registers | |
675 | ; with the same starting register. It thinks that the upper register of | |
676 | ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c | |
677 | ; at -O2 to see this. | |
f6a83b4a DD |
678 | |
679 | (define_insn "zero_extendpsisi2" | |
8f0e7f6f | 680 | [(set (match_operand:SI 0 "register_operand" "+r") |
f6a83b4a DD |
681 | (zero_extend:SI (match_operand:PSI 1 "register_operand" "r")))] |
682 | "" | |
683 | "* | |
684 | if (REGNO (operands[1]) == SP_REGNO) | |
685 | /* If the source register is the stack pointer, the value | |
686 | stored in the stack slot will be the value *after* the | |
687 | stack pointer has been decremented. So allow for that | |
688 | here. */ | |
d4f283a1 | 689 | return \"PUSHM.A\t#1, %1 { ADDX.W\t#4, @r1 { POPX.W\t%L0 { POPX.W\t%H0 ; get stack pointer into %L0:%H0\"; |
40ada30a | 690 | else |
d4f283a1 | 691 | return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\"; |
40ada30a NC |
692 | " |
693 | ) | |
694 | ||
695 | ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). | |
696 | ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends | |
697 | ;; it, we use a different method here. | |
698 | ||
699 | (define_insn "extendpsisi2" | |
700 | [(set (match_operand:SI 0 "register_operand" "=r") | |
701 | (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))] | |
c32ab325 | 702 | "msp430x" |
40ada30a NC |
703 | "* |
704 | /* The intention here is that we copy the bottom 16-bits of | |
705 | %1 into %L0 (zeroing the top four bits). Then we copy the | |
706 | entire 20-bits of %1 into %H0 and then arithmetically shift | |
707 | it right by 16 bits, to get the top four bits of the pointer | |
708 | sign-extended in %H0. */ | |
709 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
d4f283a1 | 710 | return \"MOVX.A\t%1, %H0 { MOV.W\t%1, %L0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\"; |
f6a83b4a | 711 | else |
d4f283a1 | 712 | return \"MOV.W\t%1, %L0 { MOVX.A\t%1, %H0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\"; |
f6a83b4a DD |
713 | " |
714 | ) | |
715 | ||
716 | ; See the movsipsi2 pattern above for another way that GCC performs this | |
717 | ; conversion. | |
718 | (define_insn "truncsipsi2" | |
719 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
720 | (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] | |
721 | "" | |
d4f283a1 | 722 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" |
f6a83b4a DD |
723 | ) |
724 | ||
725 | ;;------------------------------------------------------------ | |
726 | ;; Shift Functions | |
727 | ||
728 | ;; Note: We do not use the RPT ... SHIFT instruction sequence | |
729 | ;; when the repeat count is in a register, because even though RPT | |
730 | ;; accepts counts in registers, it does not work if the count is | |
731 | ;; zero, and the actual count in the register has to be one less | |
732 | ;; than the required number of iterations. We could encode a | |
733 | ;; seqeunce like this: | |
734 | ;; | |
735 | ;; bit #0xf, Rn | |
736 | ;; bz 1f | |
737 | ;; dec Rn | |
738 | ;; rpt Rn | |
739 | ;; <shift> Rm | |
740 | ;; inc Rn | |
741 | ;; 1: | |
742 | ;; | |
743 | ;; But is longer than calling a helper function, and we are mostly | |
744 | ;; concerned with code size. FIXME: Maybe enable a sequence like | |
745 | ;; this at -O3 and above ? | |
746 | ;; | |
747 | ;; Note - we ignore shift counts of less than one or more than 15. | |
748 | ;; This is permitted by the ISO C99 standard as such shifts result | |
9c582551 | 749 | ;; in "undefined" behavior. [6.5.7 (3)] |
f6a83b4a DD |
750 | |
751 | ;; signed A << C | |
752 | ||
753 | (define_expand "ashlhi3" | |
754 | [(set (match_operand:HI 0 "nonimmediate_operand") | |
755 | (ashift:HI (match_operand:HI 1 "general_operand") | |
756 | (match_operand:HI 2 "general_operand")))] | |
757 | "" | |
758 | { | |
3f02735b DD |
759 | if (GET_CODE (operands[1]) == SUBREG |
760 | && REG_P (XEXP (operands[1], 0))) | |
761 | operands[1] = force_reg (HImode, operands[1]); | |
f6a83b4a DD |
762 | if (msp430x |
763 | && REG_P (operands[0]) | |
764 | && REG_P (operands[1]) | |
765 | && CONST_INT_P (operands[2])) | |
766 | emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
767 | else if (CONST_INT_P (operands[2]) |
768 | && INTVAL (operands[2]) == 1) | |
769 | emit_insn (gen_slli_1 (operands[0], operands[1])); | |
f6a83b4a DD |
770 | else |
771 | msp430_expand_helper (operands, \"__mspabi_slli\", true); | |
772 | DONE; | |
773 | } | |
774 | ) | |
775 | ||
776 | (define_insn "slli_1" | |
777 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") | |
778 | (ashift:HI (match_operand:HI 1 "general_operand" "0") | |
779 | (const_int 1)))] | |
780 | "" | |
781 | "RLA.W\t%0" ;; Note - this is a macro for ADD | |
782 | ) | |
783 | ||
784 | (define_insn "430x_shift_left" | |
785 | [(set (match_operand:HI 0 "register_operand" "=r") | |
786 | (ashift:HI (match_operand:HI 1 "register_operand" "0") | |
787 | (match_operand 2 "immediate_operand" "n")))] | |
788 | "msp430x" | |
789 | "* | |
790 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) | |
791 | return \"rpt\t%2 { rlax.w\t%0\"; | |
792 | return \"# nop left shift\"; | |
793 | " | |
794 | ) | |
795 | ||
796 | (define_insn "slll_1" | |
797 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
798 | (ashift:SI (match_operand:SI 1 "general_operand" "0") | |
799 | (const_int 1)))] | |
800 | "" | |
801 | "RLA.W\t%L0 { RLC.W\t%H0" | |
802 | ) | |
803 | ||
804 | (define_insn "slll_2" | |
805 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
806 | (ashift:SI (match_operand:SI 1 "general_operand" "0") | |
807 | (const_int 2)))] | |
808 | "" | |
809 | "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0" | |
810 | ) | |
811 | ||
812 | (define_expand "ashlsi3" | |
813 | [(set (match_operand:SI 0 "nonimmediate_operand") | |
814 | (ashift:SI (match_operand:SI 1 "general_operand") | |
815 | (match_operand:SI 2 "general_operand")))] | |
816 | "" | |
817 | "msp430_expand_helper (operands, \"__mspabi_slll\", true); | |
818 | DONE;" | |
819 | ) | |
820 | ||
821 | ;;---------- | |
822 | ||
823 | ;; signed A >> C | |
824 | ||
825 | (define_expand "ashrhi3" | |
826 | [(set (match_operand:HI 0 "nonimmediate_operand") | |
827 | (ashiftrt:HI (match_operand:HI 1 "general_operand") | |
828 | (match_operand:HI 2 "general_operand")))] | |
829 | "" | |
830 | { | |
3f02735b DD |
831 | if (GET_CODE (operands[1]) == SUBREG |
832 | && REG_P (XEXP (operands[1], 0))) | |
833 | operands[1] = force_reg (HImode, operands[1]); | |
f6a83b4a DD |
834 | if (msp430x |
835 | && REG_P (operands[0]) | |
836 | && REG_P (operands[1]) | |
837 | && CONST_INT_P (operands[2])) | |
838 | emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
839 | else if (CONST_INT_P (operands[2]) |
840 | && INTVAL (operands[2]) == 1) | |
841 | emit_insn (gen_srai_1 (operands[0], operands[1])); | |
f6a83b4a DD |
842 | else |
843 | msp430_expand_helper (operands, \"__mspabi_srai\", true); | |
844 | DONE; | |
845 | } | |
846 | ) | |
847 | ||
848 | (define_insn "srai_1" | |
a3b50977 DD |
849 | [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm") |
850 | (ashiftrt:HI (match_operand:HI 1 "msp_general_operand" "0") | |
f6a83b4a DD |
851 | (const_int 1)))] |
852 | "" | |
853 | "RRA.W\t%0" | |
854 | ) | |
855 | ||
856 | (define_insn "430x_arithmetic_shift_right" | |
857 | [(set (match_operand:HI 0 "register_operand" "=r") | |
858 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
859 | (match_operand 2 "immediate_operand" "n")))] | |
860 | "msp430x" | |
861 | "* | |
862 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) | |
863 | return \"rpt\t%2 { rrax.w\t%0\"; | |
864 | return \"# nop arith right shift\"; | |
865 | " | |
866 | ) | |
867 | ||
868 | (define_insn "srap_1" | |
869 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
870 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
871 | (const_int 1)))] | |
872 | "msp430x" | |
873 | "RRAM.A #1,%0" | |
874 | ) | |
875 | ||
876 | (define_insn "srap_2" | |
877 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
878 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
879 | (const_int 2)))] | |
880 | "msp430x" | |
881 | "RRAM.A #2,%0" | |
882 | ) | |
883 | ||
884 | (define_insn "sral_1" | |
885 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
886 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
887 | (const_int 1)))] | |
888 | "" | |
889 | "RRA.W\t%H0 { RRC.W\t%L0" | |
890 | ) | |
891 | ||
892 | (define_insn "sral_2" | |
893 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
894 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
895 | (const_int 2)))] | |
896 | "" | |
897 | "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0" | |
898 | ) | |
899 | ||
900 | (define_expand "ashrsi3" | |
901 | [(set (match_operand:SI 0 "nonimmediate_operand") | |
902 | (ashiftrt:SI (match_operand:SI 1 "general_operand") | |
903 | (match_operand:SI 2 "general_operand")))] | |
904 | "" | |
905 | "msp430_expand_helper (operands, \"__mspabi_sral\", true); | |
906 | DONE;" | |
907 | ) | |
908 | ||
909 | ;;---------- | |
910 | ||
911 | ;; unsigned A >> C | |
912 | ||
913 | (define_expand "lshrhi3" | |
914 | [(set (match_operand:HI 0 "nonimmediate_operand") | |
915 | (lshiftrt:HI (match_operand:HI 1 "general_operand") | |
916 | (match_operand:HI 2 "general_operand")))] | |
917 | "" | |
918 | { | |
3f02735b DD |
919 | if (GET_CODE (operands[1]) == SUBREG |
920 | && REG_P (XEXP (operands[1], 0))) | |
921 | operands[1] = force_reg (HImode, operands[1]); | |
f6a83b4a DD |
922 | if (msp430x |
923 | && REG_P (operands[0]) | |
924 | && REG_P (operands[1]) | |
925 | && CONST_INT_P (operands[2])) | |
926 | emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
927 | else if (CONST_INT_P (operands[2]) |
928 | && INTVAL (operands[2]) == 1) | |
929 | emit_insn (gen_srli_1 (operands[0], operands[1])); | |
f6a83b4a DD |
930 | else |
931 | msp430_expand_helper (operands, \"__mspabi_srli\", true); | |
932 | DONE; | |
933 | } | |
934 | ) | |
935 | ||
936 | (define_insn "srli_1" | |
937 | [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") | |
938 | (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") | |
939 | (const_int 1)))] | |
940 | "" | |
941 | "CLRC { RRC.W\t%0" | |
942 | ) | |
943 | ||
944 | (define_insn "430x_logical_shift_right" | |
945 | [(set (match_operand:HI 0 "register_operand" "=r") | |
946 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
947 | (match_operand 2 "immediate_operand" "n")))] | |
948 | "msp430x" | |
949 | { | |
950 | return msp430x_logical_shift_right (operands[2]); | |
951 | } | |
952 | ) | |
953 | ||
954 | (define_insn "srlp_1" | |
955 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
956 | (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
957 | (const_int 1)))] | |
958 | "" | |
959 | "RRUM.A #1,%0" | |
960 | ) | |
961 | ||
962 | (define_insn "srll_1" | |
963 | [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") | |
964 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
965 | (const_int 1)))] | |
966 | "" | |
967 | "CLRC { RRC.W\t%H0 { RRC.W\t%L0" | |
968 | ) | |
969 | ||
970 | (define_insn "srll_2x" | |
971 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r") | |
972 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
973 | (const_int 2)))] | |
974 | "msp430x" | |
975 | "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0" | |
976 | ) | |
977 | ||
978 | (define_expand "lshrsi3" | |
979 | [(set (match_operand:SI 0 "nonimmediate_operand") | |
980 | (lshiftrt:SI (match_operand:SI 1 "general_operand") | |
981 | (match_operand:SI 2 "general_operand")))] | |
982 | "" | |
983 | "msp430_expand_helper (operands, \"__mspabi_srll\", true); | |
984 | DONE;" | |
985 | ) | |
986 | ||
987 | ;;------------------------------------------------------------ | |
988 | ;; Function Entry/Exit | |
989 | ||
990 | (define_expand "prologue" | |
991 | [(const_int 0)] | |
992 | "" | |
993 | "msp430_expand_prologue (); DONE;" | |
994 | ) | |
995 | ||
996 | (define_expand "epilogue" | |
997 | [(const_int 0)] | |
998 | "" | |
999 | "msp430_expand_epilogue (0); DONE;" | |
1000 | ) | |
1001 | ||
f6a83b4a DD |
1002 | (define_insn "epilogue_helper" |
1003 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)] | |
1004 | "" | |
fb28dac0 | 1005 | "BR%Q0\t#__mspabi_func_epilog_%J0" |
f6a83b4a DD |
1006 | ) |
1007 | ||
f6a83b4a DD |
1008 | (define_insn "prologue_start_marker" |
1009 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] | |
1010 | "" | |
1011 | "; start of prologue" | |
1012 | ) | |
1013 | ||
1014 | (define_insn "prologue_end_marker" | |
1015 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] | |
1016 | "" | |
1017 | "; end of prologue" | |
1018 | ) | |
1019 | ||
1020 | (define_insn "epilogue_start_marker" | |
1021 | [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] | |
1022 | "" | |
1023 | "; start of epilogue" | |
1024 | ) | |
1025 | ||
4f50b9ff DD |
1026 | ;; This makes the linker add a call to exit() after the call to main() |
1027 | ;; in crt0 | |
1028 | (define_insn "msp430_refsym_need_exit" | |
1029 | [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] | |
1030 | "" | |
1031 | ".refsym\t__crt0_call_exit" | |
1032 | ) | |
1033 | ||
f6a83b4a DD |
1034 | ;;------------------------------------------------------------ |
1035 | ;; Jumps | |
1036 | ||
1037 | (define_expand "call" | |
1038 | [(call:HI (match_operand 0 "") | |
40ada30a | 1039 | (match_operand 1 ""))] |
f6a83b4a DD |
1040 | "" |
1041 | "" | |
1042 | ) | |
1043 | ||
1044 | (define_insn "call_internal" | |
fb28dac0 | 1045 | [(call (mem:HI (match_operand 0 "general_operand" "rYci")) |
f6a83b4a DD |
1046 | (match_operand 1 ""))] |
1047 | "" | |
51ac3042 | 1048 | "CALL%Q0\t%0" |
f6a83b4a DD |
1049 | ) |
1050 | ||
1051 | (define_expand "call_value" | |
1052 | [(set (match_operand 0 "register_operand") | |
1053 | (call:HI (match_operand 1 "general_operand") | |
1054 | (match_operand 2 "")))] | |
1055 | "" | |
1056 | "" | |
1057 | ) | |
1058 | ||
1059 | (define_insn "call_value_internal" | |
1060 | [(set (match_operand 0 "register_operand" "=r") | |
fb28dac0 | 1061 | (call (mem:HI (match_operand 1 "general_operand" "rYci")) |
f6a83b4a DD |
1062 | (match_operand 2 "")))] |
1063 | "" | |
51ac3042 | 1064 | "CALL%Q0\t%1" |
f6a83b4a DD |
1065 | ) |
1066 | ||
1067 | (define_insn "msp_return" | |
1068 | [(return)] | |
1069 | "" | |
cad055a4 | 1070 | { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } |
f6a83b4a DD |
1071 | ) |
1072 | ||
1073 | ;; This pattern is NOT, as expected, a return pattern. It's called | |
1074 | ;; before reload and must only store its operands, and emit a | |
1075 | ;; placeholder where the epilog needs to be. AFTER reload, the | |
1076 | ;; placeholder should get expanded into a regular-type epilogue that | |
1077 | ;; also does the EH return. | |
1078 | (define_expand "eh_return" | |
40ada30a | 1079 | [(match_operand:HI 0 "")] |
f6a83b4a DD |
1080 | "" |
1081 | "msp430_expand_eh_return (operands[0]); | |
1082 | emit_jump_insn (gen_msp430_eh_epilogue ()); | |
1083 | emit_barrier (); | |
1084 | DONE;" | |
1085 | ) | |
1086 | ||
1087 | ;; This is the actual EH epilogue. We emit it in the pattern above, | |
1088 | ;; before reload, and convert it to a real epilogue after reload. | |
1089 | (define_insn_and_split "msp430_eh_epilogue" | |
1090 | [(eh_return)] | |
1091 | "" | |
1092 | "#" | |
1093 | "reload_completed" | |
1094 | [(const_int 0)] | |
1095 | "msp430_expand_epilogue (1); DONE;" | |
1096 | ) | |
1097 | ||
1098 | (define_insn "jump" | |
1099 | [(set (pc) | |
1100 | (label_ref (match_operand 0 "" "")))] | |
1101 | "" | |
51ac3042 | 1102 | "BR%Q0\t#%l0" |
f6a83b4a DD |
1103 | ) |
1104 | ||
1105 | ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs | |
1106 | ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c). | |
1107 | (define_insn "indirect_jump" | |
1108 | [(set (pc) | |
1109 | (match_operand 0 "nonimmediate_operand" "rYl"))] | |
1110 | "" | |
51ac3042 | 1111 | "BR%Q0\t%0" |
f6a83b4a DD |
1112 | ) |
1113 | ||
1114 | ;;------------------------------------------------------------ | |
1115 | ;; Various Conditionals | |
1116 | ||
1117 | (define_expand "cbranch<mode>4" | |
1118 | [(parallel [(set (pc) (if_then_else | |
1119 | (match_operator 0 "" | |
1120 | [(match_operand:QHI 1 "nonimmediate_operand") | |
1121 | (match_operand:QHI 2 "general_operand")]) | |
1122 | (label_ref (match_operand 3 "" "")) | |
1123 | (pc))) | |
1124 | (clobber (reg:BI CARRY))] | |
1125 | )] | |
1126 | "" | |
1127 | "msp430_fixup_compare_operands (<MODE>mode, operands);" | |
1128 | ) | |
1129 | ||
1130 | (define_insn "cbranchpsi4_real" | |
1131 | [(set (pc) (if_then_else | |
1132 | (match_operator 0 "msp430_cmp_operator" | |
1133 | [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm") | |
1134 | (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) | |
1135 | (label_ref (match_operand 3 "" "")) | |
1136 | (pc))) | |
1137 | (clobber (reg:BI CARRY)) | |
1138 | ] | |
1139 | "" | |
1140 | "@ | |
51ac3042 | 1141 | CMP%Q0\t%2, %1 { J%0\t%l3 |
f6a83b4a DD |
1142 | CMPX.A\t%2, %1 { J%0\t%l3 |
1143 | CMPX.A\t%2, %1 { J%0\t%l3" | |
1144 | ) | |
1145 | ||
1146 | (define_insn "cbranchqi4_real" | |
1147 | [(set (pc) (if_then_else | |
1148 | (match_operator 0 "msp430_cmp_operator" | |
1149 | [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm") | |
1150 | (match_operand:QI 2 "general_operand" "rYsi,rmi")]) | |
1151 | (label_ref (match_operand 3 "" "")) | |
1152 | (pc))) | |
1153 | (clobber (reg:BI CARRY)) | |
1154 | ] | |
1155 | "" | |
1156 | "@ | |
1157 | CMP.B\t%2, %1 { J%0\t%l3 | |
1158 | CMP%X0.B\t%2, %1 { J%0\t%l3" | |
1159 | ) | |
1160 | ||
1161 | (define_insn "cbranchhi4_real" | |
1162 | [(set (pc) (if_then_else | |
1163 | (match_operator 0 "msp430_cmp_operator" | |
1164 | [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm") | |
1165 | (match_operand:HI 2 "general_operand" "rYsi,rmi")]) | |
1166 | (label_ref (match_operand 3 "" "")) | |
1167 | (pc))) | |
1168 | (clobber (reg:BI CARRY)) | |
1169 | ] | |
1170 | "" | |
d7edde11 NC |
1171 | "* |
1172 | /* This is nasty. If we are splitting code between low and high memory | |
1173 | then we do not want the linker to increase the size of sections by | |
1174 | relaxing out of range jump instructions. (Since relaxation occurs | |
1175 | after section placement). So we have to generate pessimal branches | |
1176 | here. But we only want to do this when really necessary. | |
1177 | ||
1178 | FIXME: Do we need code in the other cbranch patterns ? */ | |
1179 | if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6) | |
1180 | { | |
1181 | return which_alternative == 0 ? | |
1182 | \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" : | |
1183 | \"CMP%X0.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\"; | |
1184 | } | |
1185 | ||
1186 | return which_alternative == 0 ? | |
1187 | \"CMP.W\t%2, %1 { J%0\t%l3\" : | |
1188 | \"CMP%X0.W\t%2, %1 { J%0\t%l3\"; | |
1189 | " | |
1190 | [(set (attr "length") | |
1191 | (if_then_else | |
1192 | (and (ge (minus (match_dup 3) (pc)) (const_int -510)) | |
1193 | (le (minus (match_dup 3) (pc)) (const_int 510))) | |
1194 | (const_int 6) | |
1195 | (const_int 10)) | |
1196 | )] | |
f6a83b4a DD |
1197 | ) |
1198 | ||
1199 | (define_insn "cbranchpsi4_reversed" | |
1200 | [(set (pc) (if_then_else | |
1201 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1202 | [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi") | |
1203 | (match_operand:PSI 2 "general_operand" "r,rYs,rm")]) | |
1204 | (label_ref (match_operand 3 "" "")) | |
1205 | (pc))) | |
1206 | (clobber (reg:BI CARRY)) | |
1207 | ] | |
1208 | "" | |
1209 | "@ | |
51ac3042 | 1210 | CMP%Q0\t%1, %2 { J%R0\t%l3 |
f6a83b4a DD |
1211 | CMPX.A\t%1, %2 { J%R0\t%l3 |
1212 | CMPX.A\t%1, %2 { J%R0\t%l3" | |
1213 | ) | |
1214 | ||
1215 | (define_insn "cbranchqi4_reversed" | |
1216 | [(set (pc) (if_then_else | |
1217 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1218 | [(match_operand:QI 1 "general_operand" "rYsi,rmi") | |
1219 | (match_operand:QI 2 "general_operand" "rYs,rm")]) | |
1220 | (label_ref (match_operand 3 "" "")) | |
1221 | (pc))) | |
1222 | (clobber (reg:BI CARRY)) | |
1223 | ] | |
1224 | "" | |
1225 | "@ | |
1226 | CMP.B\t%1, %2 { J%R0\t%l3 | |
1227 | CMP%X0.B\t%1, %2 { J%R0\t%l3" | |
1228 | ) | |
1229 | ||
1230 | (define_insn "cbranchhi4_reversed" | |
1231 | [(set (pc) (if_then_else | |
1232 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1233 | [(match_operand:HI 1 "general_operand" "rYsi,rmi") | |
1234 | (match_operand:HI 2 "general_operand" "rYs,rm")]) | |
1235 | (label_ref (match_operand 3 "" "")) | |
1236 | (pc))) | |
1237 | (clobber (reg:BI CARRY)) | |
1238 | ] | |
1239 | "" | |
1240 | "@ | |
1241 | CMP.W\t%1, %2 { J%R0\t%l3 | |
1242 | CMP%X0.W\t%1, %2 { J%R0\t%l3" | |
1243 | ) | |
1244 | ||
f6a83b4a DD |
1245 | (define_insn "*bitbranch<mode>4" |
1246 | [(set (pc) (if_then_else | |
1247 | (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm") | |
1248 | (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi")) | |
1249 | (const_int 0)) | |
1250 | (label_ref (match_operand 2 "" "")) | |
1251 | (pc))) | |
1252 | (clobber (reg:BI CARRY)) | |
1253 | ] | |
1254 | "" | |
1255 | "@ | |
51ac3042 NC |
1256 | BIT%x0%b0\t%1, %0 { JNE\t%l2 |
1257 | BIT%X0%b0\t%1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1258 | ) |
1259 | ||
1260 | (define_insn "*bitbranch<mode>4" | |
1261 | [(set (pc) (if_then_else | |
1262 | (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1263 | (match_operand:QHI 1 "msp_general_operand" "rmi")) | |
1264 | (const_int 0)) | |
1265 | (label_ref (match_operand 2 "" "")) | |
1266 | (pc))) | |
1267 | (clobber (reg:BI CARRY)) | |
1268 | ] | |
1269 | "" | |
c32ab325 | 1270 | "BIT%x0%b0\t%1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1271 | ) |
1272 | ||
1273 | (define_insn "*bitbranch<mode>4" | |
1274 | [(set (pc) (if_then_else | |
1275 | (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1276 | (match_operand:QHI 1 "msp_general_operand" "rmi")) | |
1277 | (const_int 0)) | |
1278 | (pc) | |
1279 | (label_ref (match_operand 2 "" "")))) | |
1280 | (clobber (reg:BI CARRY)) | |
1281 | ] | |
1282 | "" | |
51ac3042 | 1283 | "BIT%X0%b0\t%1, %0 { JNE\t%l2" |
f6a83b4a DD |
1284 | ) |
1285 | ||
1286 | (define_insn "*bitbranch<mode>4" | |
1287 | [(set (pc) (if_then_else | |
1288 | (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1289 | (match_operand:QHI 1 "msp_general_operand" "rmi")) | |
1290 | (const_int 0)) | |
1291 | (pc) | |
1292 | (label_ref (match_operand 2 "" "")))) | |
1293 | (clobber (reg:BI CARRY)) | |
1294 | ] | |
1295 | "" | |
51ac3042 | 1296 | "BIT%X0%b0\t%1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1297 | ) |
1298 | ||
1299 | ;;------------------------------------------------------------ | |
cad055a4 | 1300 | ;; zero-extract versions of the above |
f6a83b4a DD |
1301 | |
1302 | (define_insn "*bitbranch<mode>4_z" | |
1303 | [(set (pc) (if_then_else | |
1304 | (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm") | |
1305 | (const_int 1) | |
1306 | (match_operand 1 "msp430_bitpos" "i,i")) | |
1307 | (const_int 0)) | |
1308 | (label_ref (match_operand 2 "" "")) | |
1309 | (pc))) | |
1310 | (clobber (reg:BI CARRY)) | |
1311 | ] | |
1312 | "" | |
1313 | "@ | |
51ac3042 NC |
1314 | BIT%x0%b0\t%p1, %0 { JNE\t%l2 |
1315 | BIT%X0%b0\t%p1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1316 | ) |
1317 | ||
1318 | (define_insn "*bitbranch<mode>4_z" | |
1319 | [(set (pc) (if_then_else | |
1320 | (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1321 | (const_int 1) | |
1322 | (match_operand 1 "msp430_bitpos" "i")) | |
1323 | (const_int 0)) | |
1324 | (label_ref (match_operand 2 "" "")) | |
1325 | (pc))) | |
1326 | (clobber (reg:BI CARRY)) | |
1327 | ] | |
1328 | "" | |
51ac3042 | 1329 | "BIT%x0%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1330 | ) |
1331 | ||
1332 | (define_insn "*bitbranch<mode>4_z" | |
1333 | [(set (pc) (if_then_else | |
1334 | (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1335 | (const_int 1) | |
1336 | (match_operand 1 "msp430_bitpos" "i")) | |
1337 | (const_int 0)) | |
1338 | (pc) | |
1339 | (label_ref (match_operand 2 "" "")))) | |
1340 | (clobber (reg:BI CARRY)) | |
1341 | ] | |
1342 | "" | |
51ac3042 | 1343 | "BIT%X0%b0\t%p1, %0 { JNE\t%l2" |
f6a83b4a DD |
1344 | ) |
1345 | ||
1346 | (define_insn "*bitbranch<mode>4_z" | |
1347 | [(set (pc) (if_then_else | |
1348 | (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") | |
1349 | (const_int 1) | |
1350 | (match_operand 1 "msp430_bitpos" "i")) | |
1351 | (const_int 0)) | |
1352 | (pc) | |
1353 | (label_ref (match_operand 2 "" "")))) | |
1354 | (clobber (reg:BI CARRY)) | |
1355 | ] | |
1356 | "" | |
51ac3042 | 1357 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1358 | ) |
1359 | ||
1360 | ;;------------------------------------------------------------ | |
1361 | ;; Misc | |
1362 | ||
1363 | (define_insn "nop" | |
1364 | [(const_int 0)] | |
1365 | "1" | |
1366 | "NOP" | |
1367 | ) | |
a005b5be | 1368 | |
cad055a4 NC |
1369 | (define_insn "disable_interrupts" |
1370 | [(unspec_volatile [(const_int 0)] UNS_DINT)] | |
1371 | "" | |
a005b5be | 1372 | "DINT \; NOP" |
cad055a4 NC |
1373 | ) |
1374 | ||
1375 | (define_insn "enable_interrupts" | |
1376 | [(unspec_volatile [(const_int 0)] UNS_EINT)] | |
1377 | "" | |
1378 | "EINT" | |
1379 | ) | |
1380 | ||
1381 | (define_insn "push_intr_state" | |
1382 | [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] | |
1383 | "" | |
1384 | "PUSH\tSR" | |
1385 | ) | |
1386 | ||
1387 | (define_insn "pop_intr_state" | |
1388 | [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] | |
1389 | "" | |
1390 | "POP\tSR" | |
1391 | ) | |
1392 | ||
1393 | ;; Clear bits in the copy of the status register that is currently | |
1394 | ;; saved on the stack at the top of the interrupt handler. | |
1395 | (define_insn "bic_SR" | |
1396 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] | |
1397 | "" | |
1398 | "BIC.W\t%0, %O0(SP)" | |
1399 | ) | |
1400 | ||
1401 | ;; Set bits in the copy of the status register that is currently | |
1402 | ;; saved on the stack at the top of the interrupt handler. | |
1403 | (define_insn "bis_SR" | |
1404 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] | |
1405 | "" | |
1406 | "BIS.W\t%0, %O0(SP)" | |
1407 | ) | |
40ada30a NC |
1408 | |
1409 | ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) | |
1410 | ;; very late on in the compilation and not splitting it into separate | |
1411 | ;; instructions, so we provide a pattern to support it here. | |
1412 | (define_insn "andneghi3" | |
1413 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1414 | (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r")) | |
1415 | (match_operand 2 "immediate_operand" "n")))] | |
1416 | "" | |
1417 | "* | |
1418 | if (REGNO (operands[0]) != REGNO (operands[1])) | |
9c5f6203 | 1419 | return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a | 1420 | else |
9c5f6203 | 1421 | return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a NC |
1422 | " |
1423 | ) | |
c6f709ec | 1424 | |
5f35dde5 DD |
1425 | (define_insn "delay_cycles_start" |
1426 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1427 | UNS_DELAY_START)] | |
1428 | "" | |
1429 | "; Begin %J0 cycle delay" | |
1430 | ) | |
1431 | ||
1432 | (define_insn "delay_cycles_end" | |
1433 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1434 | UNS_DELAY_END)] | |
1435 | "" | |
1436 | "; End %J0 cycle delay" | |
1437 | ) | |
1438 | ||
1439 | (define_insn "delay_cycles_32" | |
1440 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1441 | (match_operand 1 "immediate_operand" "i") | |
1442 | ] UNS_DELAY_32)] | |
1443 | "" | |
1444 | "PUSH r13 | |
1445 | PUSH r14 | |
1446 | MOV.W %A0, r13 | |
1447 | MOV.W %B0, r14 | |
1448 | 1: SUB.W #1, r13 | |
1449 | SUBC.W #0, r14 | |
1450 | JNE 1b | |
1451 | TST.W r13 | |
1452 | JNE 1b | |
1453 | POP r14 | |
1454 | POP r13" | |
1455 | ) | |
1456 | ||
1457 | (define_insn "delay_cycles_32x" | |
1458 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1459 | (match_operand 1 "immediate_operand" "i") | |
1460 | ] UNS_DELAY_32X)] | |
1461 | "" | |
47f138d1 | 1462 | "PUSHM.A #2,r14 |
5f35dde5 DD |
1463 | MOV.W %A0, r13 |
1464 | MOV.W %B0, r14 | |
1465 | 1: SUB.W #1, r13 | |
1466 | SUBC.W #0, r14 | |
1467 | JNE 1b | |
1468 | TST.W r13 | |
1469 | JNE 1b | |
47f138d1 | 1470 | POPM.A #2,r14" |
5f35dde5 DD |
1471 | ) |
1472 | ||
1473 | (define_insn "delay_cycles_16" | |
1474 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1475 | (match_operand 1 "immediate_operand" "i") | |
1476 | ] UNS_DELAY_16)] | |
1477 | "" | |
1478 | "PUSH r13 | |
1479 | MOV.W %0, r13 | |
1480 | 1: SUB.W #1, r13 | |
1481 | JNE 1b | |
1482 | POP r13" | |
1483 | ) | |
1484 | ||
1485 | (define_insn "delay_cycles_16x" | |
1486 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1487 | (match_operand 1 "immediate_operand" "i") | |
1488 | ] UNS_DELAY_16X)] | |
1489 | "" | |
1490 | "PUSHM.A #1,r13 | |
1491 | MOV.W %0, r13 | |
1492 | 1: SUB.W #1, r13 | |
1493 | JNE 1b | |
1494 | POPM.A #1,r13" | |
1495 | ) | |
1496 | ||
1497 | (define_insn "delay_cycles_2" | |
1498 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] | |
1499 | "" | |
1500 | "JMP .+2" | |
1501 | ) | |
1502 | ||
1503 | (define_insn "delay_cycles_1" | |
1504 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] | |
1505 | "" | |
1506 | "NOP" | |
1507 | ) | |
1508 | ||
c6f709ec NC |
1509 | (define_insn "mulhisi3" |
1510 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1511 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1512 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
b07447ba | 1513 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1514 | "* |
f7961364 | 1515 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1516 | return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C2 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\"; |
c6f709ec | 1517 | else |
ba3cf9f1 | 1518 | return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; |
c6f709ec NC |
1519 | " |
1520 | ) | |
1521 | ||
1522 | (define_insn "umulhisi3" | |
1523 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1524 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1525 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
b07447ba | 1526 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1527 | "* |
f7961364 | 1528 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1529 | return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C0 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\"; |
c6f709ec | 1530 | else |
ba3cf9f1 | 1531 | return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; |
c6f709ec NC |
1532 | " |
1533 | ) | |
1534 | ||
1535 | (define_insn "mulsidi3" | |
1536 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1537 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1538 | (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
b07447ba | 1539 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1540 | "* |
f7961364 | 1541 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1542 | return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D4 { MOV.W %H1, &0x04D6 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\"; |
c6f709ec | 1543 | else |
ba3cf9f1 | 1544 | return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; |
c6f709ec NC |
1545 | " |
1546 | ) | |
1547 | ||
1548 | (define_insn "umulsidi3" | |
1549 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1550 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1551 | (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
b07447ba | 1552 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1553 | "* |
f7961364 | 1554 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1555 | return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D0 { MOV.W %H1, &0x04D2 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\"; |
c6f709ec | 1556 | else |
ba3cf9f1 | 1557 | return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0140 { MOV.W %H1, &0x0142 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; |
c6f709ec NC |
1558 | " |
1559 | ) |