]>
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 | 185 | (define_insn "movqi_topbyte" |
28987d8b | 186 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=r") |
8a896995 | 187 | (subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))] |
c32ab325 DD |
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" |
28987d8b | 193 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
8a896995 | 194 | (match_operand:QI 1 "msp430_general_operand" "riYsYx,rmi"))] |
f6a83b4a DD |
195 | "" |
196 | "@ | |
197 | MOV.B\t%1, %0 | |
8682b1a5 | 198 | MOVX.B\t%1, %0" |
f6a83b4a DD |
199 | ) |
200 | ||
201 | (define_insn "movhi" | |
28987d8b | 202 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=r,rYsYx,rm") |
8a896995 | 203 | (match_operand:HI 1 "msp430_general_operand" "N,riYsYx,rmi"))] |
f6a83b4a DD |
204 | "" |
205 | "@ | |
3f02735b | 206 | MOV.B\t%1, %0 |
f6a83b4a | 207 | MOV.W\t%1, %0 |
8682b1a5 | 208 | MOVX.W\t%1, %0" |
f6a83b4a DD |
209 | ) |
210 | ||
211 | (define_expand "movsi" | |
28987d8b | 212 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
40ada30a | 213 | (match_operand:SI 1 "general_operand"))] |
f6a83b4a DD |
214 | "" |
215 | "" | |
216 | ) | |
d7edde11 | 217 | |
14ae1d88 | 218 | (define_insn_and_split "movsi_s" |
28987d8b | 219 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
14ae1d88 DD |
220 | (subreg:SI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] |
221 | "" | |
222 | "" | |
223 | "reload_completed" | |
28987d8b | 224 | [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand") |
14ae1d88 | 225 | (match_operand:HI 4 "general_operand")) |
28987d8b | 226 | (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") |
14ae1d88 DD |
227 | (match_operand:HI 5 "general_operand"))] |
228 | "msp430_split_movsi (operands);" | |
229 | ) | |
230 | ||
f6a83b4a | 231 | (define_insn_and_split "movsi_x" |
28987d8b | 232 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
233 | (match_operand:SI 1 "general_operand" "rmi"))] |
234 | "" | |
235 | "#" | |
236 | "reload_completed" | |
28987d8b | 237 | [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand") |
f6a83b4a | 238 | (match_operand:HI 4 "general_operand")) |
28987d8b | 239 | (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
240 | (match_operand:HI 5 "general_operand"))] |
241 | "msp430_split_movsi (operands);" | |
242 | ) | |
243 | ||
8682b1a5 | 244 | ;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them. |
f6a83b4a | 245 | (define_insn "movpsi" |
28987d8b | 246 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,r,Ya,rm") |
8a896995 | 247 | (match_operand:PSI 1 "msp430_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" | |
28987d8b JL |
282 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,rm") |
283 | (plus:PSI (match_operand:PSI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 284 | (match_operand:PSI 2 "msp430_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" | |
28987d8b JL |
292 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
293 | (plus:QI (match_operand:QI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 294 | (match_operand:QI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
295 | "" |
296 | "@ | |
297 | ADD.B\t%2, %0 | |
8682b1a5 | 298 | ADDX.B\t%2, %0" |
f6a83b4a DD |
299 | ) |
300 | ||
301 | (define_insn "addhi3" | |
28987d8b JL |
302 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
303 | (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 304 | (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
305 | "" |
306 | "@ | |
307 | ADD.W\t%2, %0 | |
8682b1a5 | 308 | ADDX.W\t%2, %0" |
f6a83b4a DD |
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 | "" | |
8682b1a5 | 320 | "ADD%X2.W\t%L2, %L0 { ADDC%X2.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" | |
28987d8b JL |
324 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=&rYsYx,rm") |
325 | (plus:SI (match_operand:SI 1 "general_operand" "%0,0") | |
8682b1a5 | 326 | (match_operand:SI 2 "general_operand" "rYsYxi,mi")))] |
f6a83b4a DD |
327 | "" |
328 | "@ | |
329 | ADD\t%L2, %L0 { ADDC\t%H2, %H0 | |
8682b1a5 | 330 | ADDX\t%L2, %L0 { ADDCX\t%H2, %H0" |
f6a83b4a DD |
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 | ||
28987d8b JL |
360 | ; match_operand 3 is likely to be the same as op2 most of the time - except |
361 | ; when op2 is a post_inc and we have stripped the post_inc from match_operand 3 | |
362 | ||
f6a83b4a | 363 | (define_insn "addhi3_cy" |
28987d8b JL |
364 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
365 | (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 366 | (match_operand:HI 2 "msp430_nonimmediate_operand" "rYsYxi,rm"))) |
f6a83b4a DD |
367 | (set (reg:BI CARRY) |
368 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
28987d8b | 369 | (zero_extend:SI (match_operand:HI 3 "msp430_nonimmediate_operand" "rYsYxi,rm"))) |
f6a83b4a DD |
370 | (const_int 16)))) |
371 | ] | |
372 | "" | |
373 | "@ | |
40ada30a | 374 | ADD\t%2, %1 ; cy |
8682b1a5 | 375 | ADDX\t%2, %1 ; cy" |
f6a83b4a DD |
376 | ) |
377 | ||
378 | (define_insn "addhi3_cy_i" | |
28987d8b JL |
379 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=r,rm") |
380 | (plus:HI (match_operand:HI 1 "general_operand" "%0,0") | |
d4f283a1 | 381 | (match_operand:HI 2 "immediate_operand" "i,i"))) |
f6a83b4a DD |
382 | (set (reg:BI CARRY) |
383 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
384 | (match_operand 3 "immediate_operand" "i,i")) | |
385 | (const_int 16)))) | |
386 | ] | |
387 | "" | |
388 | "@ | |
40ada30a NC |
389 | ADD\t%2, %1 ; cy |
390 | ADD%X0\t%2, %1 ; cy" | |
f6a83b4a DD |
391 | ) |
392 | ||
393 | ; Version of addhi that adds the carry, for SImode adds. | |
394 | (define_insn "addchi4_cy" | |
28987d8b JL |
395 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
396 | (plus:HI (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 397 | (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi")) |
f6a83b4a DD |
398 | (zero_extend:HI (reg:BI CARRY)))) |
399 | ] | |
400 | "" | |
401 | "@ | |
40ada30a | 402 | ADDC\t%2, %1 |
8682b1a5 | 403 | ADDCX\t%2, %1" |
f6a83b4a DD |
404 | ) |
405 | ||
406 | ; Split an SImode add into two HImode adds, keeping track of the carry | |
407 | ; so that gcc knows when it can and can't optimize away the two | |
408 | ; halves. | |
28987d8b JL |
409 | ; We use the ugly predicate "msp430_nonsubregnonpostinc_or_imm_operand" to |
410 | ; enforce the position of a post_inc into op2 if present | |
f6a83b4a | 411 | (define_split |
28987d8b JL |
412 | [(set (match_operand:SI 0 "msp430_nonsubreg_dst_operand") |
413 | (plus:SI (match_operand:SI 1 "msp430_nonsubregnonpostinc_or_imm_operand") | |
9c5f6203 | 414 | (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand"))) |
f6a83b4a DD |
415 | ] |
416 | "" | |
28987d8b | 417 | [(parallel [(set (match_operand:HI 3 "msp430_general_dst_nonv_operand" "=&rm") |
f6a83b4a DD |
418 | (plus:HI (match_dup 4) |
419 | (match_dup 5))) | |
420 | (set (reg:BI CARRY) | |
421 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4)) | |
422 | (match_dup 9)) | |
423 | (const_int 16)))) | |
424 | ]) | |
28987d8b | 425 | (set (match_operand:HI 6 "msp430_general_dst_nonv_operand" "=&rm") |
f6a83b4a DD |
426 | (plus:HI (plus:HI (match_dup 7) |
427 | (match_dup 8)) | |
428 | (zero_extend:HI (reg:BI CARRY)))) | |
429 | ] | |
430 | " | |
53f45082 JL |
431 | if (msp430_split_addsi (operands)) |
432 | FAIL; | |
433 | " | |
f6a83b4a DD |
434 | ) |
435 | ||
436 | ||
437 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
438 | (define_insn "subpsi3" | |
28987d8b JL |
439 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r, rm, &?r, ?&r") |
440 | (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i") | |
441 | (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r")))] | |
f6a83b4a DD |
442 | "" |
443 | "@ | |
444 | SUBA\t%2, %0 | |
445 | SUBX.A\t%2, %0 | |
446 | MOVX.A\t%1, %0 { SUBX.A\t%2, %0 | |
447 | MOVX.A\t%1, %0 { SUBA\t%2, %0" | |
448 | ) | |
449 | ||
450 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
451 | (define_insn "subqi3" | |
28987d8b | 452 | [(set (match_operand:QI 0 "msp430_general_dst_nonv_operand" "=rYsYx, rm, &?r, ?&r") |
f6a83b4a | 453 | (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i") |
8682b1a5 | 454 | (match_operand:QI 2 "general_operand" " riYsYx, rmi, rmi, r")))] |
f6a83b4a DD |
455 | "" |
456 | "@ | |
457 | SUB.B\t%2, %0 | |
8682b1a5 JL |
458 | SUBX.B\t%2, %0 |
459 | MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0 | |
f6a83b4a DD |
460 | MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" |
461 | ) | |
462 | ||
463 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
464 | (define_insn "subhi3" | |
28987d8b | 465 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rYsYx, rm, &?r, ?&r") |
f6a83b4a | 466 | (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i") |
8682b1a5 | 467 | (match_operand:HI 2 "general_operand" " riYsYx, rmi, rmi, r")))] |
f6a83b4a DD |
468 | "" |
469 | "@ | |
470 | SUB.W\t%2, %0 | |
8682b1a5 JL |
471 | SUBX.W\t%2, %0 |
472 | MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0 | |
f6a83b4a DD |
473 | MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" |
474 | ) | |
475 | ||
476 | (define_insn "subsi3" | |
28987d8b JL |
477 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=&rYsYx,m") |
478 | (minus:SI (match_operand:SI 1 "general_operand" "0,0") | |
8682b1a5 | 479 | (match_operand:SI 2 "general_operand" "riYsYx,mi")))] |
f6a83b4a | 480 | "" |
8682b1a5 JL |
481 | "@ |
482 | SUB\t%L2, %L0 { SUBC\t%H2, %H0 | |
483 | SUBX\t%L2, %L0 { SUBCX\t%H2, %H0" | |
f6a83b4a DD |
484 | ) |
485 | ||
486 | (define_insn "*bic<mode>_cg" | |
28987d8b | 487 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYs,m") |
8a896995 | 488 | (and:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0") |
f6a83b4a DD |
489 | (match_operand 2 "msp430_inv_constgen_operator" "n,n")))] |
490 | "" | |
491 | "@ | |
51ac3042 NC |
492 | BIC%x0%b0\t#%I2, %0 |
493 | BIC%X0%b0\t#%I2, %0" | |
f6a83b4a DD |
494 | ) |
495 | ||
496 | (define_insn "bic<mode>3" | |
28987d8b | 497 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
8a896995 | 498 | (and:QHI (not:QHI (match_operand:QHI 1 "msp430_general_operand" "rYsYx,rmn")) |
28987d8b | 499 | (match_operand:QHI 2 "msp430_general_operand" "0,0")))] |
f6a83b4a DD |
500 | "" |
501 | "@ | |
51ac3042 | 502 | BIC%x0%b0\t%1, %0 |
8682b1a5 | 503 | BICX%b0\t%1, %0" |
f6a83b4a DD |
504 | ) |
505 | ||
506 | (define_insn "and<mode>3" | |
28987d8b JL |
507 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=r,rYsYx,rm") |
508 | (and:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0,0") | |
8a896995 | 509 | (match_operand:QHI 2 "msp430_general_operand" "N,riYsYx,rmi")))] |
f6a83b4a DD |
510 | "" |
511 | "@ | |
3f02735b | 512 | AND%x0.B\t%2, %0 |
51ac3042 | 513 | AND%x0%b0\t%2, %0 |
8682b1a5 | 514 | ANDX%b0\t%2, %0" |
f6a83b4a DD |
515 | ) |
516 | ||
517 | (define_insn "ior<mode>3" | |
28987d8b JL |
518 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
519 | (ior:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 520 | (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
521 | "" |
522 | "@ | |
51ac3042 | 523 | BIS%x0%b0\t%2, %0 |
8682b1a5 | 524 | BISX%b0\t%2, %0" |
f6a83b4a DD |
525 | ) |
526 | ||
527 | (define_insn "xor<mode>3" | |
28987d8b JL |
528 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
529 | (xor:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 530 | (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
531 | "" |
532 | "@ | |
51ac3042 | 533 | XOR%x0%b0\t%2, %0 |
8682b1a5 | 534 | XORX%b0\t%2, %0" |
f6a83b4a DD |
535 | ) |
536 | ||
537 | ;; Macro : XOR #~0, %0 | |
538 | (define_insn "one_cmpl<mode>2" | |
28987d8b JL |
539 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYs,m") |
540 | (not:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0")))] | |
f6a83b4a DD |
541 | "" |
542 | "@ | |
51ac3042 NC |
543 | INV%x0%b0\t%0 |
544 | INV%X0%b0\t%0" | |
f6a83b4a DD |
545 | ) |
546 | ||
547 | (define_insn "extendqihi2" | |
28987d8b JL |
548 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,m") |
549 | (sign_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,0")))] | |
f6a83b4a DD |
550 | "" |
551 | "@ | |
552 | SXT%X0\t%0 | |
553 | SXT%X0\t%0" | |
554 | ) | |
555 | ||
556 | (define_insn "zero_extendqihi2" | |
28987d8b JL |
557 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,r,r,m") |
558 | (zero_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,rYs,m,0")))] | |
f6a83b4a DD |
559 | "" |
560 | "@ | |
561 | AND\t#0xff, %0 | |
3f02735b | 562 | MOV.B\t%1, %0 |
8682b1a5 | 563 | MOV%X1.B\t%1, %0 |
f6a83b4a DD |
564 | AND%X0\t#0xff, %0" |
565 | ) | |
566 | ||
582b4055 JL |
567 | (define_insn "zero_extendqisi2" |
568 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") | |
569 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] | |
570 | "" | |
571 | "MOV%X1.B\t%1,%L0 { CLR\t%H0" | |
f6a83b4a | 572 | ) |
d7edde11 | 573 | |
f6a83b4a | 574 | (define_insn "zero_extendhipsi2" |
28987d8b JL |
575 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,m") |
576 | (zero_extend:PSI (match_operand:HI 1 "msp430_general_operand" "rm,r")))] | |
f6a83b4a | 577 | "" |
85bd3c01 NC |
578 | "@ |
579 | MOVX\t%1, %0 | |
580 | MOVX.A\t%1, %0" | |
f6a83b4a | 581 | ) |
cac52161 | 582 | |
f6a83b4a | 583 | (define_insn "zero_extendhisi2" |
28987d8b JL |
584 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm,r") |
585 | (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")))] | |
525213a5 | 586 | "" |
bdafd679 | 587 | "@ |
8682b1a5 | 588 | MOV%X0.W\t#0,%H0 |
bdafd679 | 589 | MOV.W\t%1,%L0 { MOV.W\t#0,%H0" |
f6a83b4a DD |
590 | ) |
591 | ||
592 | (define_insn "zero_extendhisipsi2" | |
28987d8b JL |
593 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r,r") |
594 | (subreg:PSI (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")) 0))] | |
c32ab325 | 595 | "msp430x" |
f6a83b4a DD |
596 | "@ |
597 | AND.W\t#-1,%0 | |
598 | MOV.W\t%1,%0" | |
599 | ) | |
600 | ||
f6a83b4a DD |
601 | ; Nasty - we are sign-extending a 20-bit PSI value in one register into |
602 | ; two adjacent 16-bit registers to make an SI value. There is no MSP430X | |
603 | ; instruction that will do this, so we push the 20-bit value onto the stack | |
604 | ; and then pop it off as two 16-bit values. | |
605 | ; | |
606 | ; FIXME: The MSP430X documentation does not specify if zero-extension or | |
607 | ; sign-extension happens when the 20-bit value is pushed onto the stack. | |
608 | ; It is probably zero-extension, but if not this pattern will not work | |
609 | ; when the PSI value is negative.. | |
610 | ; | |
611 | ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... | |
8f0e7f6f NC |
612 | ; |
613 | ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused | |
614 | ; about extending a single PSI mode register into a pair of SImode registers | |
615 | ; with the same starting register. It thinks that the upper register of | |
616 | ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c | |
617 | ; at -O2 to see this. | |
f6a83b4a DD |
618 | |
619 | (define_insn "zero_extendpsisi2" | |
8f0e7f6f | 620 | [(set (match_operand:SI 0 "register_operand" "+r") |
f6a83b4a DD |
621 | (zero_extend:SI (match_operand:PSI 1 "register_operand" "r")))] |
622 | "" | |
623 | "* | |
624 | if (REGNO (operands[1]) == SP_REGNO) | |
625 | /* If the source register is the stack pointer, the value | |
626 | stored in the stack slot will be the value *after* the | |
627 | stack pointer has been decremented. So allow for that | |
628 | here. */ | |
d4f283a1 | 629 | 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 | 630 | else |
d4f283a1 | 631 | 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 |
632 | " |
633 | ) | |
634 | ||
582b4055 JL |
635 | |
636 | ;; Eliminate extraneous zero-extends mysteriously created by gcc. | |
637 | (define_peephole2 | |
638 | [(set (match_operand:HI 0 "register_operand") | |
639 | (zero_extend:HI (match_operand:QI 1 "general_operand"))) | |
640 | (set (match_operand:HI 2 "register_operand") | |
641 | (zero_extend:HI (match_operand:QI 3 "register_operand")))] | |
642 | "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])" | |
643 | [(set (match_dup 0) | |
644 | (zero_extend:HI (match_dup 1)))] | |
645 | ) | |
646 | ||
647 | (define_insn "truncpsihi2" | |
648 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") | |
649 | (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] | |
650 | "" | |
651 | "MOVX\t%1, %0" | |
652 | ) | |
653 | ||
654 | (define_insn "extendhisi2" | |
655 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") | |
656 | (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] | |
657 | "" | |
658 | { return msp430x_extendhisi (operands); } | |
659 | ) | |
660 | ||
661 | (define_insn "extendhipsi2" | |
662 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") | |
663 | (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))] | |
664 | "msp430x" | |
665 | "RLAM.A #4, %0 { RRAM.A #4, %0" | |
666 | ) | |
667 | ||
668 | ;; Look for cases where integer/pointer conversions are suboptimal due | |
669 | ;; to missing patterns, despite us not having opcodes for these | |
670 | ;; patterns. Doing these manually allows for alternate optimization | |
671 | ;; paths. | |
672 | ||
673 | (define_insn "extend_and_shift1_hipsi2" | |
674 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
675 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
676 | (const_int 1)))] | |
677 | "msp430x" | |
678 | "RLAM.A #4, %0 { RRAM.A #3, %0" | |
679 | ) | |
680 | ||
681 | (define_insn "extend_and_shift2_hipsi2" | |
682 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
683 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
684 | (const_int 2)))] | |
685 | "msp430x" | |
686 | "RLAM.A #4, %0 { RRAM.A #2, %0" | |
687 | ) | |
688 | ||
40ada30a NC |
689 | ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). |
690 | ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends | |
691 | ;; it, we use a different method here. | |
692 | ||
693 | (define_insn "extendpsisi2" | |
694 | [(set (match_operand:SI 0 "register_operand" "=r") | |
695 | (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))] | |
c32ab325 | 696 | "msp430x" |
40ada30a NC |
697 | "* |
698 | /* The intention here is that we copy the bottom 16-bits of | |
699 | %1 into %L0 (zeroing the top four bits). Then we copy the | |
700 | entire 20-bits of %1 into %H0 and then arithmetically shift | |
701 | it right by 16 bits, to get the top four bits of the pointer | |
702 | sign-extended in %H0. */ | |
703 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
d4f283a1 | 704 | 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 | 705 | else |
d4f283a1 | 706 | 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 |
707 | " |
708 | ) | |
709 | ||
710 | ; See the movsipsi2 pattern above for another way that GCC performs this | |
711 | ; conversion. | |
712 | (define_insn "truncsipsi2" | |
713 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
714 | (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] | |
715 | "" | |
d4f283a1 | 716 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" |
f6a83b4a DD |
717 | ) |
718 | ||
719 | ;;------------------------------------------------------------ | |
720 | ;; Shift Functions | |
721 | ||
722 | ;; Note: We do not use the RPT ... SHIFT instruction sequence | |
723 | ;; when the repeat count is in a register, because even though RPT | |
724 | ;; accepts counts in registers, it does not work if the count is | |
725 | ;; zero, and the actual count in the register has to be one less | |
726 | ;; than the required number of iterations. We could encode a | |
727 | ;; seqeunce like this: | |
728 | ;; | |
729 | ;; bit #0xf, Rn | |
730 | ;; bz 1f | |
731 | ;; dec Rn | |
732 | ;; rpt Rn | |
733 | ;; <shift> Rm | |
734 | ;; inc Rn | |
735 | ;; 1: | |
736 | ;; | |
737 | ;; But is longer than calling a helper function, and we are mostly | |
738 | ;; concerned with code size. FIXME: Maybe enable a sequence like | |
739 | ;; this at -O3 and above ? | |
740 | ;; | |
741 | ;; Note - we ignore shift counts of less than one or more than 15. | |
742 | ;; This is permitted by the ISO C99 standard as such shifts result | |
9c582551 | 743 | ;; in "undefined" behavior. [6.5.7 (3)] |
f6a83b4a DD |
744 | |
745 | ;; signed A << C | |
746 | ||
747 | (define_expand "ashlhi3" | |
28987d8b | 748 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
749 | (ashift:HI (match_operand:HI 1 "general_operand") |
750 | (match_operand:HI 2 "general_operand")))] | |
751 | "" | |
752 | { | |
e445e4b4 JL |
753 | if ((GET_CODE (operands[1]) == SUBREG |
754 | && REG_P (XEXP (operands[1], 0))) | |
755 | || MEM_P (operands[1])) | |
3f02735b | 756 | operands[1] = force_reg (HImode, operands[1]); |
f6a83b4a DD |
757 | if (msp430x |
758 | && REG_P (operands[0]) | |
759 | && REG_P (operands[1]) | |
760 | && CONST_INT_P (operands[2])) | |
761 | emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
762 | else if (CONST_INT_P (operands[2]) |
763 | && INTVAL (operands[2]) == 1) | |
764 | emit_insn (gen_slli_1 (operands[0], operands[1])); | |
f6a83b4a | 765 | else |
ec573765 JL |
766 | /* The const variants of mspabi shifts have larger code size than the |
767 | generic version, so use the generic version if optimizing for | |
768 | size. */ | |
769 | msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size); | |
f6a83b4a DD |
770 | DONE; |
771 | } | |
772 | ) | |
773 | ||
774 | (define_insn "slli_1" | |
28987d8b | 775 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
776 | (ashift:HI (match_operand:HI 1 "general_operand" "0") |
777 | (const_int 1)))] | |
778 | "" | |
8682b1a5 | 779 | "RLA%X0.W\t%0" ;; Note - this is a macro for ADD |
f6a83b4a DD |
780 | ) |
781 | ||
782 | (define_insn "430x_shift_left" | |
783 | [(set (match_operand:HI 0 "register_operand" "=r") | |
784 | (ashift:HI (match_operand:HI 1 "register_operand" "0") | |
785 | (match_operand 2 "immediate_operand" "n")))] | |
786 | "msp430x" | |
787 | "* | |
788 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) | |
789 | return \"rpt\t%2 { rlax.w\t%0\"; | |
790 | return \"# nop left shift\"; | |
791 | " | |
792 | ) | |
793 | ||
794 | (define_insn "slll_1" | |
28987d8b | 795 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
796 | (ashift:SI (match_operand:SI 1 "general_operand" "0") |
797 | (const_int 1)))] | |
798 | "" | |
8682b1a5 | 799 | "RLA%X0.W\t%L0 { RLC%X0.W\t%H0" |
f6a83b4a DD |
800 | ) |
801 | ||
802 | (define_insn "slll_2" | |
28987d8b | 803 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
804 | (ashift:SI (match_operand:SI 1 "general_operand" "0") |
805 | (const_int 2)))] | |
806 | "" | |
8682b1a5 | 807 | "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0" |
f6a83b4a DD |
808 | ) |
809 | ||
810 | (define_expand "ashlsi3" | |
28987d8b | 811 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
812 | (ashift:SI (match_operand:SI 1 "general_operand") |
813 | (match_operand:SI 2 "general_operand")))] | |
814 | "" | |
ec573765 | 815 | "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size); |
f6a83b4a DD |
816 | DONE;" |
817 | ) | |
818 | ||
0fcc78f7 | 819 | (define_expand "ashldi3" |
28987d8b | 820 | [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") |
0fcc78f7 JL |
821 | (ashift:DI (match_operand:DI 1 "general_operand") |
822 | (match_operand:DI 2 "general_operand")))] | |
823 | "" | |
824 | { | |
825 | /* No const_variant for 64-bit shifts. */ | |
826 | msp430_expand_helper (operands, \"__mspabi_sllll\", false); | |
827 | DONE; | |
828 | } | |
829 | ) | |
830 | ||
f6a83b4a DD |
831 | ;;---------- |
832 | ||
833 | ;; signed A >> C | |
834 | ||
835 | (define_expand "ashrhi3" | |
28987d8b | 836 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
837 | (ashiftrt:HI (match_operand:HI 1 "general_operand") |
838 | (match_operand:HI 2 "general_operand")))] | |
839 | "" | |
840 | { | |
e445e4b4 JL |
841 | if ((GET_CODE (operands[1]) == SUBREG |
842 | && REG_P (XEXP (operands[1], 0))) | |
843 | || MEM_P (operands[1])) | |
3f02735b | 844 | operands[1] = force_reg (HImode, operands[1]); |
f6a83b4a DD |
845 | if (msp430x |
846 | && REG_P (operands[0]) | |
847 | && REG_P (operands[1]) | |
848 | && CONST_INT_P (operands[2])) | |
849 | emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
850 | else if (CONST_INT_P (operands[2]) |
851 | && INTVAL (operands[2]) == 1) | |
852 | emit_insn (gen_srai_1 (operands[0], operands[1])); | |
f6a83b4a | 853 | else |
ec573765 | 854 | msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size); |
f6a83b4a DD |
855 | DONE; |
856 | } | |
857 | ) | |
858 | ||
859 | (define_insn "srai_1" | |
28987d8b | 860 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") |
8a896995 | 861 | (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0") |
f6a83b4a DD |
862 | (const_int 1)))] |
863 | "" | |
8682b1a5 | 864 | "RRA%X0.W\t%0" |
f6a83b4a DD |
865 | ) |
866 | ||
867 | (define_insn "430x_arithmetic_shift_right" | |
868 | [(set (match_operand:HI 0 "register_operand" "=r") | |
869 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
870 | (match_operand 2 "immediate_operand" "n")))] | |
871 | "msp430x" | |
872 | "* | |
873 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) | |
874 | return \"rpt\t%2 { rrax.w\t%0\"; | |
875 | return \"# nop arith right shift\"; | |
876 | " | |
877 | ) | |
878 | ||
879 | (define_insn "srap_1" | |
880 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
881 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
882 | (const_int 1)))] | |
883 | "msp430x" | |
884 | "RRAM.A #1,%0" | |
885 | ) | |
886 | ||
887 | (define_insn "srap_2" | |
888 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
889 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
890 | (const_int 2)))] | |
891 | "msp430x" | |
892 | "RRAM.A #2,%0" | |
893 | ) | |
894 | ||
895 | (define_insn "sral_1" | |
28987d8b | 896 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
897 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") |
898 | (const_int 1)))] | |
899 | "" | |
8682b1a5 | 900 | "RRA%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
901 | ) |
902 | ||
903 | (define_insn "sral_2" | |
28987d8b | 904 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
905 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") |
906 | (const_int 2)))] | |
907 | "" | |
8682b1a5 | 908 | "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
909 | ) |
910 | ||
911 | (define_expand "ashrsi3" | |
28987d8b | 912 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
913 | (ashiftrt:SI (match_operand:SI 1 "general_operand") |
914 | (match_operand:SI 2 "general_operand")))] | |
915 | "" | |
ec573765 | 916 | "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size); |
f6a83b4a DD |
917 | DONE;" |
918 | ) | |
919 | ||
0fcc78f7 | 920 | (define_expand "ashrdi3" |
28987d8b | 921 | [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") |
0fcc78f7 JL |
922 | (ashift:DI (match_operand:DI 1 "general_operand") |
923 | (match_operand:DI 2 "general_operand")))] | |
924 | "" | |
925 | { | |
926 | /* No const_variant for 64-bit shifts. */ | |
927 | msp430_expand_helper (operands, \"__mspabi_srall\", false); | |
928 | DONE; | |
929 | } | |
930 | ) | |
931 | ||
f6a83b4a DD |
932 | ;;---------- |
933 | ||
934 | ;; unsigned A >> C | |
935 | ||
936 | (define_expand "lshrhi3" | |
28987d8b | 937 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
938 | (lshiftrt:HI (match_operand:HI 1 "general_operand") |
939 | (match_operand:HI 2 "general_operand")))] | |
940 | "" | |
941 | { | |
e445e4b4 JL |
942 | if ((GET_CODE (operands[1]) == SUBREG |
943 | && REG_P (XEXP (operands[1], 0))) | |
944 | || MEM_P (operands[1])) | |
3f02735b | 945 | operands[1] = force_reg (HImode, operands[1]); |
f6a83b4a DD |
946 | if (msp430x |
947 | && REG_P (operands[0]) | |
948 | && REG_P (operands[1]) | |
949 | && CONST_INT_P (operands[2])) | |
950 | emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
951 | else if (CONST_INT_P (operands[2]) |
952 | && INTVAL (operands[2]) == 1) | |
953 | emit_insn (gen_srli_1 (operands[0], operands[1])); | |
f6a83b4a | 954 | else |
ec573765 | 955 | msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size); |
f6a83b4a DD |
956 | DONE; |
957 | } | |
958 | ) | |
959 | ||
960 | (define_insn "srli_1" | |
28987d8b | 961 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
962 | (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") |
963 | (const_int 1)))] | |
964 | "" | |
8682b1a5 | 965 | "CLRC { RRC%X0.W\t%0" |
f6a83b4a DD |
966 | ) |
967 | ||
968 | (define_insn "430x_logical_shift_right" | |
969 | [(set (match_operand:HI 0 "register_operand" "=r") | |
970 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
971 | (match_operand 2 "immediate_operand" "n")))] | |
972 | "msp430x" | |
973 | { | |
974 | return msp430x_logical_shift_right (operands[2]); | |
975 | } | |
976 | ) | |
977 | ||
978 | (define_insn "srlp_1" | |
979 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
980 | (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
981 | (const_int 1)))] | |
982 | "" | |
983 | "RRUM.A #1,%0" | |
984 | ) | |
985 | ||
986 | (define_insn "srll_1" | |
28987d8b | 987 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
988 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") |
989 | (const_int 1)))] | |
990 | "" | |
8682b1a5 | 991 | "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
992 | ) |
993 | ||
994 | (define_insn "srll_2x" | |
28987d8b | 995 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") |
f6a83b4a DD |
996 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") |
997 | (const_int 2)))] | |
998 | "msp430x" | |
999 | "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0" | |
1000 | ) | |
1001 | ||
1002 | (define_expand "lshrsi3" | |
28987d8b | 1003 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1004 | (lshiftrt:SI (match_operand:SI 1 "general_operand") |
1005 | (match_operand:SI 2 "general_operand")))] | |
1006 | "" | |
ec573765 | 1007 | "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size); |
f6a83b4a DD |
1008 | DONE;" |
1009 | ) | |
1010 | ||
0fcc78f7 | 1011 | (define_expand "lshrdi3" |
28987d8b | 1012 | [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") |
0fcc78f7 JL |
1013 | (ashift:DI (match_operand:DI 1 "general_operand") |
1014 | (match_operand:DI 2 "general_operand")))] | |
1015 | "" | |
1016 | { | |
1017 | /* No const_variant for 64-bit shifts. */ | |
1018 | msp430_expand_helper (operands, \"__mspabi_srlll\", false); | |
1019 | DONE; | |
1020 | } | |
1021 | ) | |
1022 | ||
f6a83b4a DD |
1023 | ;;------------------------------------------------------------ |
1024 | ;; Function Entry/Exit | |
1025 | ||
1026 | (define_expand "prologue" | |
1027 | [(const_int 0)] | |
1028 | "" | |
1029 | "msp430_expand_prologue (); DONE;" | |
1030 | ) | |
1031 | ||
1032 | (define_expand "epilogue" | |
1033 | [(const_int 0)] | |
1034 | "" | |
1035 | "msp430_expand_epilogue (0); DONE;" | |
1036 | ) | |
1037 | ||
f6a83b4a DD |
1038 | (define_insn "epilogue_helper" |
1039 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)] | |
1040 | "" | |
fb28dac0 | 1041 | "BR%Q0\t#__mspabi_func_epilog_%J0" |
f6a83b4a DD |
1042 | ) |
1043 | ||
f6a83b4a DD |
1044 | (define_insn "prologue_start_marker" |
1045 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] | |
1046 | "" | |
1047 | "; start of prologue" | |
1048 | ) | |
1049 | ||
1050 | (define_insn "prologue_end_marker" | |
1051 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] | |
1052 | "" | |
1053 | "; end of prologue" | |
1054 | ) | |
1055 | ||
1056 | (define_insn "epilogue_start_marker" | |
1057 | [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] | |
1058 | "" | |
1059 | "; start of epilogue" | |
1060 | ) | |
1061 | ||
4f50b9ff DD |
1062 | ;; This makes the linker add a call to exit() after the call to main() |
1063 | ;; in crt0 | |
1064 | (define_insn "msp430_refsym_need_exit" | |
1065 | [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] | |
1066 | "" | |
1067 | ".refsym\t__crt0_call_exit" | |
1068 | ) | |
1069 | ||
f6a83b4a DD |
1070 | ;;------------------------------------------------------------ |
1071 | ;; Jumps | |
1072 | ||
1073 | (define_expand "call" | |
1074 | [(call:HI (match_operand 0 "") | |
40ada30a | 1075 | (match_operand 1 ""))] |
f6a83b4a DD |
1076 | "" |
1077 | "" | |
1078 | ) | |
1079 | ||
1080 | (define_insn "call_internal" | |
fb28dac0 | 1081 | [(call (mem:HI (match_operand 0 "general_operand" "rYci")) |
f6a83b4a DD |
1082 | (match_operand 1 ""))] |
1083 | "" | |
51ac3042 | 1084 | "CALL%Q0\t%0" |
f6a83b4a DD |
1085 | ) |
1086 | ||
1087 | (define_expand "call_value" | |
1088 | [(set (match_operand 0 "register_operand") | |
1089 | (call:HI (match_operand 1 "general_operand") | |
1090 | (match_operand 2 "")))] | |
1091 | "" | |
1092 | "" | |
1093 | ) | |
1094 | ||
1095 | (define_insn "call_value_internal" | |
1096 | [(set (match_operand 0 "register_operand" "=r") | |
fb28dac0 | 1097 | (call (mem:HI (match_operand 1 "general_operand" "rYci")) |
f6a83b4a DD |
1098 | (match_operand 2 "")))] |
1099 | "" | |
51ac3042 | 1100 | "CALL%Q0\t%1" |
f6a83b4a DD |
1101 | ) |
1102 | ||
8a896995 | 1103 | (define_insn "msp430_return" |
f6a83b4a DD |
1104 | [(return)] |
1105 | "" | |
cad055a4 | 1106 | { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } |
f6a83b4a DD |
1107 | ) |
1108 | ||
1109 | ;; This pattern is NOT, as expected, a return pattern. It's called | |
1110 | ;; before reload and must only store its operands, and emit a | |
1111 | ;; placeholder where the epilog needs to be. AFTER reload, the | |
1112 | ;; placeholder should get expanded into a regular-type epilogue that | |
1113 | ;; also does the EH return. | |
1114 | (define_expand "eh_return" | |
40ada30a | 1115 | [(match_operand:HI 0 "")] |
f6a83b4a DD |
1116 | "" |
1117 | "msp430_expand_eh_return (operands[0]); | |
1118 | emit_jump_insn (gen_msp430_eh_epilogue ()); | |
1119 | emit_barrier (); | |
1120 | DONE;" | |
1121 | ) | |
1122 | ||
1123 | ;; This is the actual EH epilogue. We emit it in the pattern above, | |
1124 | ;; before reload, and convert it to a real epilogue after reload. | |
1125 | (define_insn_and_split "msp430_eh_epilogue" | |
1126 | [(eh_return)] | |
1127 | "" | |
1128 | "#" | |
1129 | "reload_completed" | |
1130 | [(const_int 0)] | |
1131 | "msp430_expand_epilogue (1); DONE;" | |
1132 | ) | |
1133 | ||
1134 | (define_insn "jump" | |
1135 | [(set (pc) | |
1136 | (label_ref (match_operand 0 "" "")))] | |
1137 | "" | |
51ac3042 | 1138 | "BR%Q0\t#%l0" |
f6a83b4a DD |
1139 | ) |
1140 | ||
1141 | ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs | |
1142 | ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c). | |
1143 | (define_insn "indirect_jump" | |
1144 | [(set (pc) | |
1145 | (match_operand 0 "nonimmediate_operand" "rYl"))] | |
1146 | "" | |
51ac3042 | 1147 | "BR%Q0\t%0" |
f6a83b4a DD |
1148 | ) |
1149 | ||
1150 | ;;------------------------------------------------------------ | |
1151 | ;; Various Conditionals | |
1152 | ||
1153 | (define_expand "cbranch<mode>4" | |
1154 | [(parallel [(set (pc) (if_then_else | |
1155 | (match_operator 0 "" | |
1156 | [(match_operand:QHI 1 "nonimmediate_operand") | |
1157 | (match_operand:QHI 2 "general_operand")]) | |
1158 | (label_ref (match_operand 3 "" "")) | |
1159 | (pc))) | |
1160 | (clobber (reg:BI CARRY))] | |
1161 | )] | |
1162 | "" | |
1163 | "msp430_fixup_compare_operands (<MODE>mode, operands);" | |
1164 | ) | |
1165 | ||
1166 | (define_insn "cbranchpsi4_real" | |
1167 | [(set (pc) (if_then_else | |
1168 | (match_operator 0 "msp430_cmp_operator" | |
1169 | [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm") | |
1170 | (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) | |
1171 | (label_ref (match_operand 3 "" "")) | |
1172 | (pc))) | |
1173 | (clobber (reg:BI CARRY)) | |
1174 | ] | |
1175 | "" | |
1176 | "@ | |
51ac3042 | 1177 | CMP%Q0\t%2, %1 { J%0\t%l3 |
f6a83b4a DD |
1178 | CMPX.A\t%2, %1 { J%0\t%l3 |
1179 | CMPX.A\t%2, %1 { J%0\t%l3" | |
1180 | ) | |
1181 | ||
1182 | (define_insn "cbranchqi4_real" | |
1183 | [(set (pc) (if_then_else | |
1184 | (match_operator 0 "msp430_cmp_operator" | |
8682b1a5 JL |
1185 | [(match_operand:QI 1 "nonimmediate_operand" "rYsYx,rm") |
1186 | (match_operand:QI 2 "general_operand" "rYsYxi,rmi")]) | |
f6a83b4a DD |
1187 | (label_ref (match_operand 3 "" "")) |
1188 | (pc))) | |
1189 | (clobber (reg:BI CARRY)) | |
1190 | ] | |
1191 | "" | |
1192 | "@ | |
1193 | CMP.B\t%2, %1 { J%0\t%l3 | |
8682b1a5 | 1194 | CMPX.B\t%2, %1 { J%0\t%l3" |
f6a83b4a DD |
1195 | ) |
1196 | ||
1197 | (define_insn "cbranchhi4_real" | |
1198 | [(set (pc) (if_then_else | |
1199 | (match_operator 0 "msp430_cmp_operator" | |
8682b1a5 JL |
1200 | [(match_operand:HI 1 "nonimmediate_operand" "rYsYx,rm") |
1201 | (match_operand:HI 2 "general_operand" "rYsYxi,rmi")]) | |
f6a83b4a DD |
1202 | (label_ref (match_operand 3 "" "")) |
1203 | (pc))) | |
1204 | (clobber (reg:BI CARRY)) | |
1205 | ] | |
1206 | "" | |
d7edde11 NC |
1207 | "* |
1208 | /* This is nasty. If we are splitting code between low and high memory | |
1209 | then we do not want the linker to increase the size of sections by | |
1210 | relaxing out of range jump instructions. (Since relaxation occurs | |
1211 | after section placement). So we have to generate pessimal branches | |
1212 | here. But we only want to do this when really necessary. | |
1213 | ||
1214 | FIXME: Do we need code in the other cbranch patterns ? */ | |
1215 | if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6) | |
1216 | { | |
1217 | return which_alternative == 0 ? | |
1218 | \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" : | |
8682b1a5 | 1219 | \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\"; |
d7edde11 NC |
1220 | } |
1221 | ||
1222 | return which_alternative == 0 ? | |
1223 | \"CMP.W\t%2, %1 { J%0\t%l3\" : | |
8682b1a5 | 1224 | \"CMPX.W\t%2, %1 { J%0\t%l3\"; |
d7edde11 NC |
1225 | " |
1226 | [(set (attr "length") | |
1227 | (if_then_else | |
1228 | (and (ge (minus (match_dup 3) (pc)) (const_int -510)) | |
1229 | (le (minus (match_dup 3) (pc)) (const_int 510))) | |
1230 | (const_int 6) | |
1231 | (const_int 10)) | |
1232 | )] | |
f6a83b4a DD |
1233 | ) |
1234 | ||
1235 | (define_insn "cbranchpsi4_reversed" | |
1236 | [(set (pc) (if_then_else | |
1237 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1238 | [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi") | |
1239 | (match_operand:PSI 2 "general_operand" "r,rYs,rm")]) | |
1240 | (label_ref (match_operand 3 "" "")) | |
1241 | (pc))) | |
1242 | (clobber (reg:BI CARRY)) | |
1243 | ] | |
1244 | "" | |
1245 | "@ | |
51ac3042 | 1246 | CMP%Q0\t%1, %2 { J%R0\t%l3 |
f6a83b4a DD |
1247 | CMPX.A\t%1, %2 { J%R0\t%l3 |
1248 | CMPX.A\t%1, %2 { J%R0\t%l3" | |
1249 | ) | |
1250 | ||
1251 | (define_insn "cbranchqi4_reversed" | |
1252 | [(set (pc) (if_then_else | |
1253 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 JL |
1254 | [(match_operand:QI 1 "general_operand" "rYsYxi,rmi") |
1255 | (match_operand:QI 2 "general_operand" "rYsYx,rm")]) | |
f6a83b4a DD |
1256 | (label_ref (match_operand 3 "" "")) |
1257 | (pc))) | |
1258 | (clobber (reg:BI CARRY)) | |
1259 | ] | |
1260 | "" | |
1261 | "@ | |
1262 | CMP.B\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1263 | CMPX.B\t%1, %2 { J%R0\t%l3" |
f6a83b4a DD |
1264 | ) |
1265 | ||
1266 | (define_insn "cbranchhi4_reversed" | |
1267 | [(set (pc) (if_then_else | |
1268 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 JL |
1269 | [(match_operand:HI 1 "general_operand" "rYsYxi,rmi") |
1270 | (match_operand:HI 2 "general_operand" "rYsYx,rm")]) | |
f6a83b4a DD |
1271 | (label_ref (match_operand 3 "" "")) |
1272 | (pc))) | |
1273 | (clobber (reg:BI CARRY)) | |
1274 | ] | |
1275 | "" | |
1276 | "@ | |
1277 | CMP.W\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1278 | CMPX.W\t%1, %2 { J%R0\t%l3" |
f6a83b4a DD |
1279 | ) |
1280 | ||
f6a83b4a DD |
1281 | (define_insn "*bitbranch<mode>4" |
1282 | [(set (pc) (if_then_else | |
28987d8b | 1283 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1284 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1285 | (const_int 0)) |
1286 | (label_ref (match_operand 2 "" "")) | |
1287 | (pc))) | |
1288 | (clobber (reg:BI CARRY)) | |
1289 | ] | |
1290 | "" | |
1291 | "@ | |
51ac3042 | 1292 | BIT%x0%b0\t%1, %0 { JNE\t%l2 |
8682b1a5 | 1293 | BITX%b0\t%1, %0 { JNE\t%l2" |
f6a83b4a DD |
1294 | ) |
1295 | ||
1296 | (define_insn "*bitbranch<mode>4" | |
1297 | [(set (pc) (if_then_else | |
28987d8b | 1298 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1299 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1300 | (const_int 0)) |
1301 | (label_ref (match_operand 2 "" "")) | |
1302 | (pc))) | |
1303 | (clobber (reg:BI CARRY)) | |
1304 | ] | |
1305 | "" | |
8682b1a5 JL |
1306 | "@ |
1307 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1308 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
f6a83b4a DD |
1309 | ) |
1310 | ||
1311 | (define_insn "*bitbranch<mode>4" | |
1312 | [(set (pc) (if_then_else | |
28987d8b | 1313 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1314 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1315 | (const_int 0)) |
1316 | (pc) | |
1317 | (label_ref (match_operand 2 "" "")))) | |
1318 | (clobber (reg:BI CARRY)) | |
1319 | ] | |
1320 | "" | |
8682b1a5 JL |
1321 | "@ |
1322 | BIT%x0%b0\t%1, %0 { JNE\t%l2 | |
1323 | BITX%b0\t%1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1324 | ) |
1325 | ||
1326 | (define_insn "*bitbranch<mode>4" | |
1327 | [(set (pc) (if_then_else | |
28987d8b | 1328 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1329 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1330 | (const_int 0)) |
1331 | (pc) | |
1332 | (label_ref (match_operand 2 "" "")))) | |
1333 | (clobber (reg:BI CARRY)) | |
1334 | ] | |
1335 | "" | |
8682b1a5 JL |
1336 | "@ |
1337 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1338 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
f6a83b4a DD |
1339 | ) |
1340 | ||
1341 | ;;------------------------------------------------------------ | |
cad055a4 | 1342 | ;; zero-extract versions of the above |
f6a83b4a DD |
1343 | |
1344 | (define_insn "*bitbranch<mode>4_z" | |
1345 | [(set (pc) (if_then_else | |
28987d8b | 1346 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm") |
f6a83b4a DD |
1347 | (const_int 1) |
1348 | (match_operand 1 "msp430_bitpos" "i,i")) | |
1349 | (const_int 0)) | |
1350 | (label_ref (match_operand 2 "" "")) | |
1351 | (pc))) | |
1352 | (clobber (reg:BI CARRY)) | |
1353 | ] | |
1354 | "" | |
1355 | "@ | |
51ac3042 NC |
1356 | BIT%x0%b0\t%p1, %0 { JNE\t%l2 |
1357 | BIT%X0%b0\t%p1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1358 | ) |
1359 | ||
1360 | (define_insn "*bitbranch<mode>4_z" | |
1361 | [(set (pc) (if_then_else | |
28987d8b | 1362 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1363 | (const_int 1) |
1364 | (match_operand 1 "msp430_bitpos" "i")) | |
1365 | (const_int 0)) | |
1366 | (label_ref (match_operand 2 "" "")) | |
1367 | (pc))) | |
1368 | (clobber (reg:BI CARRY)) | |
1369 | ] | |
1370 | "" | |
8682b1a5 | 1371 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1372 | ) |
1373 | ||
1374 | (define_insn "*bitbranch<mode>4_z" | |
1375 | [(set (pc) (if_then_else | |
28987d8b | 1376 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1377 | (const_int 1) |
1378 | (match_operand 1 "msp430_bitpos" "i")) | |
1379 | (const_int 0)) | |
1380 | (pc) | |
1381 | (label_ref (match_operand 2 "" "")))) | |
1382 | (clobber (reg:BI CARRY)) | |
1383 | ] | |
1384 | "" | |
51ac3042 | 1385 | "BIT%X0%b0\t%p1, %0 { JNE\t%l2" |
f6a83b4a DD |
1386 | ) |
1387 | ||
1388 | (define_insn "*bitbranch<mode>4_z" | |
1389 | [(set (pc) (if_then_else | |
28987d8b | 1390 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1391 | (const_int 1) |
1392 | (match_operand 1 "msp430_bitpos" "i")) | |
1393 | (const_int 0)) | |
1394 | (pc) | |
1395 | (label_ref (match_operand 2 "" "")))) | |
1396 | (clobber (reg:BI CARRY)) | |
1397 | ] | |
1398 | "" | |
51ac3042 | 1399 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1400 | ) |
1401 | ||
1402 | ;;------------------------------------------------------------ | |
1403 | ;; Misc | |
1404 | ||
1405 | (define_insn "nop" | |
1406 | [(const_int 0)] | |
1407 | "1" | |
1408 | "NOP" | |
1409 | ) | |
a005b5be | 1410 | |
cad055a4 NC |
1411 | (define_insn "disable_interrupts" |
1412 | [(unspec_volatile [(const_int 0)] UNS_DINT)] | |
1413 | "" | |
a005b5be | 1414 | "DINT \; NOP" |
cad055a4 NC |
1415 | ) |
1416 | ||
1417 | (define_insn "enable_interrupts" | |
1418 | [(unspec_volatile [(const_int 0)] UNS_EINT)] | |
1419 | "" | |
1420 | "EINT" | |
1421 | ) | |
1422 | ||
1423 | (define_insn "push_intr_state" | |
1424 | [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] | |
1425 | "" | |
1426 | "PUSH\tSR" | |
1427 | ) | |
1428 | ||
1429 | (define_insn "pop_intr_state" | |
1430 | [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] | |
1431 | "" | |
1432 | "POP\tSR" | |
1433 | ) | |
1434 | ||
1435 | ;; Clear bits in the copy of the status register that is currently | |
1436 | ;; saved on the stack at the top of the interrupt handler. | |
1437 | (define_insn "bic_SR" | |
1438 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] | |
1439 | "" | |
1440 | "BIC.W\t%0, %O0(SP)" | |
1441 | ) | |
1442 | ||
1443 | ;; Set bits in the copy of the status register that is currently | |
1444 | ;; saved on the stack at the top of the interrupt handler. | |
1445 | (define_insn "bis_SR" | |
1446 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] | |
1447 | "" | |
1448 | "BIS.W\t%0, %O0(SP)" | |
1449 | ) | |
40ada30a NC |
1450 | |
1451 | ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) | |
1452 | ;; very late on in the compilation and not splitting it into separate | |
1453 | ;; instructions, so we provide a pattern to support it here. | |
1454 | (define_insn "andneghi3" | |
1455 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1456 | (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r")) | |
1457 | (match_operand 2 "immediate_operand" "n")))] | |
1458 | "" | |
1459 | "* | |
1460 | if (REGNO (operands[0]) != REGNO (operands[1])) | |
9c5f6203 | 1461 | return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a | 1462 | else |
9c5f6203 | 1463 | return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a NC |
1464 | " |
1465 | ) | |
c6f709ec | 1466 | |
5f35dde5 DD |
1467 | (define_insn "delay_cycles_start" |
1468 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1469 | UNS_DELAY_START)] | |
1470 | "" | |
1471 | "; Begin %J0 cycle delay" | |
1472 | ) | |
1473 | ||
1474 | (define_insn "delay_cycles_end" | |
1475 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1476 | UNS_DELAY_END)] | |
1477 | "" | |
1478 | "; End %J0 cycle delay" | |
1479 | ) | |
1480 | ||
1481 | (define_insn "delay_cycles_32" | |
1482 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1483 | (match_operand 1 "immediate_operand" "i") | |
1484 | ] UNS_DELAY_32)] | |
1485 | "" | |
1486 | "PUSH r13 | |
1487 | PUSH r14 | |
1488 | MOV.W %A0, r13 | |
1489 | MOV.W %B0, r14 | |
1490 | 1: SUB.W #1, r13 | |
1491 | SUBC.W #0, r14 | |
1492 | JNE 1b | |
1493 | TST.W r13 | |
1494 | JNE 1b | |
1495 | POP r14 | |
1496 | POP r13" | |
1497 | ) | |
1498 | ||
1499 | (define_insn "delay_cycles_32x" | |
1500 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1501 | (match_operand 1 "immediate_operand" "i") | |
1502 | ] UNS_DELAY_32X)] | |
1503 | "" | |
47f138d1 | 1504 | "PUSHM.A #2,r14 |
5f35dde5 DD |
1505 | MOV.W %A0, r13 |
1506 | MOV.W %B0, r14 | |
1507 | 1: SUB.W #1, r13 | |
1508 | SUBC.W #0, r14 | |
1509 | JNE 1b | |
1510 | TST.W r13 | |
1511 | JNE 1b | |
47f138d1 | 1512 | POPM.A #2,r14" |
5f35dde5 DD |
1513 | ) |
1514 | ||
1515 | (define_insn "delay_cycles_16" | |
1516 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1517 | (match_operand 1 "immediate_operand" "i") | |
1518 | ] UNS_DELAY_16)] | |
1519 | "" | |
1520 | "PUSH r13 | |
1521 | MOV.W %0, r13 | |
1522 | 1: SUB.W #1, r13 | |
1523 | JNE 1b | |
1524 | POP r13" | |
1525 | ) | |
1526 | ||
1527 | (define_insn "delay_cycles_16x" | |
1528 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1529 | (match_operand 1 "immediate_operand" "i") | |
1530 | ] UNS_DELAY_16X)] | |
1531 | "" | |
1532 | "PUSHM.A #1,r13 | |
1533 | MOV.W %0, r13 | |
1534 | 1: SUB.W #1, r13 | |
1535 | JNE 1b | |
1536 | POPM.A #1,r13" | |
1537 | ) | |
1538 | ||
1539 | (define_insn "delay_cycles_2" | |
1540 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] | |
1541 | "" | |
1542 | "JMP .+2" | |
1543 | ) | |
1544 | ||
1545 | (define_insn "delay_cycles_1" | |
1546 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] | |
1547 | "" | |
1548 | "NOP" | |
1549 | ) | |
1550 | ||
c6f709ec NC |
1551 | (define_insn "mulhisi3" |
1552 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1553 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1554 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
b07447ba | 1555 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1556 | "* |
f7961364 | 1557 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1558 | 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 | 1559 | else |
ba3cf9f1 | 1560 | 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 |
1561 | " |
1562 | ) | |
1563 | ||
1564 | (define_insn "umulhisi3" | |
1565 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1566 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1567 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
b07447ba | 1568 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1569 | "* |
f7961364 | 1570 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1571 | 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 | 1572 | else |
ba3cf9f1 | 1573 | 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 |
1574 | " |
1575 | ) | |
1576 | ||
1577 | (define_insn "mulsidi3" | |
1578 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1579 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1580 | (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
b07447ba | 1581 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1582 | "* |
f7961364 | 1583 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1584 | 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 | 1585 | else |
ba3cf9f1 | 1586 | 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 |
1587 | " |
1588 | ) | |
1589 | ||
1590 | (define_insn "umulsidi3" | |
1591 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1592 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1593 | (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
b07447ba | 1594 | "optimize > 2 && msp430_hwmult_type != MSP430_HWMULT_NONE" |
c6f709ec | 1595 | "* |
f7961364 | 1596 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1597 | 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 | 1598 | else |
ba3cf9f1 | 1599 | 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 |
1600 | " |
1601 | ) |