]>
Commit | Line | Data |
---|---|---|
f6a83b4a | 1 | ;; Machine Description for TI MSP43* processors |
8d9254fc | 2 | ;; Copyright (C) 2013-2020 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 | ||
aa360dd1 JL |
556 | (define_insn "extendqipsi2" |
557 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,m") | |
558 | (sign_extend:PSI (match_operand:QI 1 "msp430_general_operand" "0,0")))] | |
559 | "" | |
560 | "@ | |
561 | SXT\t%0 | |
562 | SXTX.A\t%0" | |
563 | ) | |
564 | ||
a0a9a3fc JL |
565 | ;; ------------------------ |
566 | ;; ZERO EXTEND INSTRUCTIONS | |
567 | ;; Byte-writes to registers clear bits 19:8 | |
568 | ;; * Byte-writes to memory do not affect bits 15:8 | |
569 | ;; Word-writes to registers clear bits 19:16 | |
570 | ;; PSImode writes to memory clear bits 15:4 of the second memory word | |
571 | ;; We define all possible insns since that results in better code than if | |
572 | ;; they are inferred. | |
573 | ;; ------------------------ | |
574 | ||
f6a83b4a | 575 | (define_insn "zero_extendqihi2" |
28987d8b JL |
576 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,r,r,m") |
577 | (zero_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,rYs,m,0")))] | |
f6a83b4a DD |
578 | "" |
579 | "@ | |
580 | AND\t#0xff, %0 | |
3f02735b | 581 | MOV.B\t%1, %0 |
8682b1a5 | 582 | MOV%X1.B\t%1, %0 |
f6a83b4a DD |
583 | AND%X0\t#0xff, %0" |
584 | ) | |
585 | ||
a0a9a3fc JL |
586 | (define_insn "zero_extendqipsi2" |
587 | [(set (match_operand:PSI 0 "register_operand" "=r,r") | |
588 | (zero_extend:PSI (match_operand:QI 1 "general_operand" "rYs,m")))] | |
589 | "msp430x" | |
590 | "@ | |
591 | MOV.B\t%1, %0 | |
592 | MOV%X1.B\t%1, %0" | |
593 | ) | |
594 | ||
582b4055 | 595 | (define_insn "zero_extendqisi2" |
a0a9a3fc JL |
596 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r,r") |
597 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,rm")))] | |
582b4055 | 598 | "" |
a0a9a3fc JL |
599 | "@ |
600 | CLR\t%H0 | |
601 | MOV%X1.B\t%1,%L0 { CLR\t%H0" | |
f6a83b4a | 602 | ) |
d7edde11 | 603 | |
f6a83b4a | 604 | (define_insn "zero_extendhipsi2" |
a0a9a3fc JL |
605 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,m") |
606 | (zero_extend:PSI (match_operand:HI 1 "msp430_general_operand" "rYs,m,r")))] | |
607 | "msp430x" | |
85bd3c01 | 608 | "@ |
a0a9a3fc JL |
609 | MOV.W\t%1, %0 |
610 | MOV%X1\t%1, %0 | |
85bd3c01 | 611 | MOVX.A\t%1, %0" |
f6a83b4a | 612 | ) |
cac52161 | 613 | |
f6a83b4a | 614 | (define_insn "zero_extendhisi2" |
28987d8b JL |
615 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm,r") |
616 | (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")))] | |
525213a5 | 617 | "" |
bdafd679 | 618 | "@ |
8682b1a5 | 619 | MOV%X0.W\t#0,%H0 |
bdafd679 | 620 | MOV.W\t%1,%L0 { MOV.W\t#0,%H0" |
f6a83b4a DD |
621 | ) |
622 | ||
623 | (define_insn "zero_extendhisipsi2" | |
28987d8b JL |
624 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r,r") |
625 | (subreg:PSI (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")) 0))] | |
c32ab325 | 626 | "msp430x" |
f6a83b4a DD |
627 | "@ |
628 | AND.W\t#-1,%0 | |
629 | MOV.W\t%1,%0" | |
630 | ) | |
631 | ||
f6a83b4a DD |
632 | ; Nasty - we are sign-extending a 20-bit PSI value in one register into |
633 | ; two adjacent 16-bit registers to make an SI value. There is no MSP430X | |
634 | ; instruction that will do this, so we push the 20-bit value onto the stack | |
635 | ; and then pop it off as two 16-bit values. | |
636 | ; | |
637 | ; FIXME: The MSP430X documentation does not specify if zero-extension or | |
638 | ; sign-extension happens when the 20-bit value is pushed onto the stack. | |
639 | ; It is probably zero-extension, but if not this pattern will not work | |
640 | ; when the PSI value is negative.. | |
641 | ; | |
642 | ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... | |
8f0e7f6f NC |
643 | ; |
644 | ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused | |
645 | ; about extending a single PSI mode register into a pair of SImode registers | |
646 | ; with the same starting register. It thinks that the upper register of | |
647 | ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c | |
648 | ; at -O2 to see this. | |
f6a83b4a | 649 | |
a0a9a3fc | 650 | ; FIXME we can use MOVA for r->m if m is &abs20 or z16(rdst) |
f6a83b4a | 651 | (define_insn "zero_extendpsisi2" |
a0a9a3fc JL |
652 | [(set (match_operand:SI 0 "register_operand" "+r,m") |
653 | (zero_extend:SI (match_operand:PSI 1 "register_operand" "r,r")))] | |
f6a83b4a | 654 | "" |
a0a9a3fc JL |
655 | "@ |
656 | * if (REGNO (operands[1]) == SP_REGNO) \ | |
657 | /* If the source register is the stack pointer, the value \ | |
658 | stored in the stack slot will be the value *after* the \ | |
659 | stack pointer has been decremented. So allow for that \ | |
660 | here. */ \ | |
661 | 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\"; \ | |
662 | else \ | |
d4f283a1 | 663 | return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\"; |
a0a9a3fc JL |
664 | MOVX.A %1, %0" |
665 | ) | |
666 | ||
667 | ;; Below are unnamed insn patterns to catch pointer manipulation insns | |
668 | ;; generated by combine. | |
669 | ;; We get large code size bloat when a PSImode pointer is stored in | |
670 | ;; memory, so we try to avoid that where possible and keep point manipulation | |
671 | ;; between registers. | |
672 | ; FIXME many of these should be unnnecessary once combine deals with | |
673 | ; (sign_extend (zero_extend)) or (sign_extend (subreg)) BZ 91865. | |
674 | ||
675 | ;; This is just another way of writing movqipsi/zero_extendqipsi | |
676 | (define_insn "" | |
677 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
678 | (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))] | |
679 | "msp430x" | |
680 | "MOV%X1.B\t%1, %0" | |
40ada30a NC |
681 | ) |
682 | ||
a0a9a3fc JL |
683 | (define_insn "" |
684 | [(set (match_operand:PSI 0 "register_operand" "=r,r") | |
685 | (sign_extend:PSI (zero_extend:HI (match_operand:QI 1 "general_operand" "rYs,m"))))] | |
686 | "msp430x" | |
687 | "@ | |
688 | MOV.B\t%1, %0 | |
689 | MOV%X1.B\t%1, %0" | |
690 | ) | |
691 | ||
692 | (define_insn "" | |
693 | [(set (match_operand:SI 0 "register_operand" "=r") | |
694 | (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "rm")) | |
695 | (match_operand:HI 2 "immediate_operand" "M")))] | |
696 | "msp430x" | |
697 | "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" | |
698 | ) | |
699 | ||
700 | ;; We are taking a char and shifting it and putting the result in 2 registers. | |
701 | ;; the high register will always be for 0 shift counts < 8. | |
702 | (define_insn "" | |
703 | [(set (match_operand:SI 0 "register_operand" "=r") | |
704 | (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) | |
705 | (match_operand:HI 2 "immediate_operand" "M")))] | |
706 | "msp430x" | |
707 | "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" | |
708 | ) | |
709 | ||
710 | ;; Same as above but with a NOP sign_extend round the subreg | |
711 | (define_insn "" | |
712 | [(set (match_operand:SI 0 "register_operand" "=r") | |
713 | (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))) | |
714 | (match_operand:HI 2 "immediate_operand" "M")))] | |
715 | "msp430x" | |
716 | "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" | |
717 | ) | |
718 | ||
719 | (define_insn "" | |
720 | [(set (match_operand:SI 0 "register_operand" "=r") | |
721 | (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))] | |
722 | "msp430x" | |
723 | "MOV%X1.B %1, %L0 { CLR %H0" | |
724 | ) | |
725 | ||
726 | (define_insn "" | |
727 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
728 | (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) | |
729 | (match_operand:HI 2 "immediate_operand" "M")))] | |
730 | "msp430x" | |
731 | "MOV%X1.B %1, %0 { RLAM.W %2, %0" | |
732 | ) | |
733 | ;; END msp430 pointer manipulation combine insn patterns | |
582b4055 JL |
734 | |
735 | ;; Eliminate extraneous zero-extends mysteriously created by gcc. | |
736 | (define_peephole2 | |
737 | [(set (match_operand:HI 0 "register_operand") | |
738 | (zero_extend:HI (match_operand:QI 1 "general_operand"))) | |
739 | (set (match_operand:HI 2 "register_operand") | |
740 | (zero_extend:HI (match_operand:QI 3 "register_operand")))] | |
741 | "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])" | |
742 | [(set (match_dup 0) | |
743 | (zero_extend:HI (match_dup 1)))] | |
744 | ) | |
745 | ||
746 | (define_insn "truncpsihi2" | |
747 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") | |
748 | (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] | |
749 | "" | |
750 | "MOVX\t%1, %0" | |
751 | ) | |
752 | ||
753 | (define_insn "extendhisi2" | |
754 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") | |
755 | (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] | |
756 | "" | |
757 | { return msp430x_extendhisi (operands); } | |
758 | ) | |
759 | ||
760 | (define_insn "extendhipsi2" | |
761 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") | |
762 | (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))] | |
763 | "msp430x" | |
764 | "RLAM.A #4, %0 { RRAM.A #4, %0" | |
765 | ) | |
766 | ||
767 | ;; Look for cases where integer/pointer conversions are suboptimal due | |
768 | ;; to missing patterns, despite us not having opcodes for these | |
769 | ;; patterns. Doing these manually allows for alternate optimization | |
770 | ;; paths. | |
771 | ||
772 | (define_insn "extend_and_shift1_hipsi2" | |
773 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
774 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
775 | (const_int 1)))] | |
776 | "msp430x" | |
777 | "RLAM.A #4, %0 { RRAM.A #3, %0" | |
778 | ) | |
779 | ||
780 | (define_insn "extend_and_shift2_hipsi2" | |
781 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
782 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
783 | (const_int 2)))] | |
784 | "msp430x" | |
785 | "RLAM.A #4, %0 { RRAM.A #2, %0" | |
786 | ) | |
787 | ||
40ada30a NC |
788 | ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). |
789 | ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends | |
790 | ;; it, we use a different method here. | |
791 | ||
792 | (define_insn "extendpsisi2" | |
793 | [(set (match_operand:SI 0 "register_operand" "=r") | |
794 | (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))] | |
c32ab325 | 795 | "msp430x" |
40ada30a NC |
796 | "* |
797 | /* The intention here is that we copy the bottom 16-bits of | |
798 | %1 into %L0 (zeroing the top four bits). Then we copy the | |
799 | entire 20-bits of %1 into %H0 and then arithmetically shift | |
800 | it right by 16 bits, to get the top four bits of the pointer | |
801 | sign-extended in %H0. */ | |
802 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
d4f283a1 | 803 | 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 | 804 | else |
d4f283a1 | 805 | 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 |
806 | " |
807 | ) | |
808 | ||
809 | ; See the movsipsi2 pattern above for another way that GCC performs this | |
810 | ; conversion. | |
811 | (define_insn "truncsipsi2" | |
812 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
813 | (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] | |
814 | "" | |
d4f283a1 | 815 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" |
f6a83b4a DD |
816 | ) |
817 | ||
818 | ;;------------------------------------------------------------ | |
819 | ;; Shift Functions | |
820 | ||
821 | ;; Note: We do not use the RPT ... SHIFT instruction sequence | |
822 | ;; when the repeat count is in a register, because even though RPT | |
823 | ;; accepts counts in registers, it does not work if the count is | |
824 | ;; zero, and the actual count in the register has to be one less | |
825 | ;; than the required number of iterations. We could encode a | |
826 | ;; seqeunce like this: | |
827 | ;; | |
828 | ;; bit #0xf, Rn | |
829 | ;; bz 1f | |
830 | ;; dec Rn | |
831 | ;; rpt Rn | |
832 | ;; <shift> Rm | |
833 | ;; inc Rn | |
834 | ;; 1: | |
835 | ;; | |
836 | ;; But is longer than calling a helper function, and we are mostly | |
837 | ;; concerned with code size. FIXME: Maybe enable a sequence like | |
838 | ;; this at -O3 and above ? | |
839 | ;; | |
840 | ;; Note - we ignore shift counts of less than one or more than 15. | |
841 | ;; This is permitted by the ISO C99 standard as such shifts result | |
9c582551 | 842 | ;; in "undefined" behavior. [6.5.7 (3)] |
f6a83b4a DD |
843 | |
844 | ;; signed A << C | |
845 | ||
846 | (define_expand "ashlhi3" | |
28987d8b | 847 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
848 | (ashift:HI (match_operand:HI 1 "general_operand") |
849 | (match_operand:HI 2 "general_operand")))] | |
850 | "" | |
851 | { | |
e445e4b4 JL |
852 | if ((GET_CODE (operands[1]) == SUBREG |
853 | && REG_P (XEXP (operands[1], 0))) | |
854 | || MEM_P (operands[1])) | |
3f02735b | 855 | operands[1] = force_reg (HImode, operands[1]); |
f6a83b4a DD |
856 | if (msp430x |
857 | && REG_P (operands[0]) | |
858 | && REG_P (operands[1]) | |
859 | && CONST_INT_P (operands[2])) | |
860 | emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
861 | else if (CONST_INT_P (operands[2]) |
862 | && INTVAL (operands[2]) == 1) | |
863 | emit_insn (gen_slli_1 (operands[0], operands[1])); | |
f6a83b4a | 864 | else |
ec573765 JL |
865 | /* The const variants of mspabi shifts have larger code size than the |
866 | generic version, so use the generic version if optimizing for | |
867 | size. */ | |
868 | msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size); | |
f6a83b4a DD |
869 | DONE; |
870 | } | |
871 | ) | |
872 | ||
873 | (define_insn "slli_1" | |
28987d8b | 874 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
875 | (ashift:HI (match_operand:HI 1 "general_operand" "0") |
876 | (const_int 1)))] | |
877 | "" | |
8682b1a5 | 878 | "RLA%X0.W\t%0" ;; Note - this is a macro for ADD |
f6a83b4a DD |
879 | ) |
880 | ||
881 | (define_insn "430x_shift_left" | |
882 | [(set (match_operand:HI 0 "register_operand" "=r") | |
883 | (ashift:HI (match_operand:HI 1 "register_operand" "0") | |
884 | (match_operand 2 "immediate_operand" "n")))] | |
885 | "msp430x" | |
886 | "* | |
d8e4dc54 JL |
887 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) |
888 | return \"RLAM.W\t%2, %0\"; | |
889 | else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) | |
890 | return \"RPT\t%2 { RLAX.W\t%0\"; | |
f6a83b4a DD |
891 | return \"# nop left shift\"; |
892 | " | |
893 | ) | |
894 | ||
895 | (define_insn "slll_1" | |
28987d8b | 896 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
897 | (ashift:SI (match_operand:SI 1 "general_operand" "0") |
898 | (const_int 1)))] | |
899 | "" | |
8682b1a5 | 900 | "RLA%X0.W\t%L0 { RLC%X0.W\t%H0" |
f6a83b4a DD |
901 | ) |
902 | ||
903 | (define_insn "slll_2" | |
28987d8b | 904 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
905 | (ashift:SI (match_operand:SI 1 "general_operand" "0") |
906 | (const_int 2)))] | |
907 | "" | |
8682b1a5 | 908 | "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0" |
f6a83b4a DD |
909 | ) |
910 | ||
911 | (define_expand "ashlsi3" | |
28987d8b | 912 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
913 | (ashift:SI (match_operand:SI 1 "general_operand") |
914 | (match_operand:SI 2 "general_operand")))] | |
915 | "" | |
ec573765 | 916 | "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size); |
f6a83b4a DD |
917 | DONE;" |
918 | ) | |
919 | ||
0fcc78f7 | 920 | (define_expand "ashldi3" |
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_sllll\", false); | |
928 | DONE; | |
929 | } | |
930 | ) | |
931 | ||
f6a83b4a DD |
932 | ;;---------- |
933 | ||
934 | ;; signed A >> C | |
935 | ||
936 | (define_expand "ashrhi3" | |
28987d8b | 937 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
938 | (ashiftrt: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_arithmetic_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_srai_1 (operands[0], operands[1])); | |
f6a83b4a | 954 | else |
ec573765 | 955 | msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size); |
f6a83b4a DD |
956 | DONE; |
957 | } | |
958 | ) | |
959 | ||
960 | (define_insn "srai_1" | |
28987d8b | 961 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") |
8a896995 | 962 | (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0") |
f6a83b4a DD |
963 | (const_int 1)))] |
964 | "" | |
8682b1a5 | 965 | "RRA%X0.W\t%0" |
f6a83b4a DD |
966 | ) |
967 | ||
968 | (define_insn "430x_arithmetic_shift_right" | |
969 | [(set (match_operand:HI 0 "register_operand" "=r") | |
970 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
971 | (match_operand 2 "immediate_operand" "n")))] | |
972 | "msp430x" | |
973 | "* | |
d8e4dc54 JL |
974 | if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) |
975 | return \"RRAM.W\t%2, %0\"; | |
976 | else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) | |
977 | return \"RPT\t%2 { RRAX.W\t%0\"; | |
f6a83b4a DD |
978 | return \"# nop arith right shift\"; |
979 | " | |
980 | ) | |
981 | ||
982 | (define_insn "srap_1" | |
983 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
984 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
985 | (const_int 1)))] | |
986 | "msp430x" | |
987 | "RRAM.A #1,%0" | |
988 | ) | |
989 | ||
990 | (define_insn "srap_2" | |
991 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
992 | (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
993 | (const_int 2)))] | |
994 | "msp430x" | |
995 | "RRAM.A #2,%0" | |
996 | ) | |
997 | ||
998 | (define_insn "sral_1" | |
28987d8b | 999 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
1000 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") |
1001 | (const_int 1)))] | |
1002 | "" | |
8682b1a5 | 1003 | "RRA%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
1004 | ) |
1005 | ||
1006 | (define_insn "sral_2" | |
28987d8b | 1007 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
1008 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") |
1009 | (const_int 2)))] | |
1010 | "" | |
8682b1a5 | 1011 | "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
1012 | ) |
1013 | ||
1014 | (define_expand "ashrsi3" | |
28987d8b | 1015 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1016 | (ashiftrt:SI (match_operand:SI 1 "general_operand") |
1017 | (match_operand:SI 2 "general_operand")))] | |
1018 | "" | |
ec573765 | 1019 | "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size); |
f6a83b4a DD |
1020 | DONE;" |
1021 | ) | |
1022 | ||
0fcc78f7 | 1023 | (define_expand "ashrdi3" |
28987d8b | 1024 | [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") |
0fcc78f7 JL |
1025 | (ashift:DI (match_operand:DI 1 "general_operand") |
1026 | (match_operand:DI 2 "general_operand")))] | |
1027 | "" | |
1028 | { | |
1029 | /* No const_variant for 64-bit shifts. */ | |
1030 | msp430_expand_helper (operands, \"__mspabi_srall\", false); | |
1031 | DONE; | |
1032 | } | |
1033 | ) | |
1034 | ||
f6a83b4a DD |
1035 | ;;---------- |
1036 | ||
1037 | ;; unsigned A >> C | |
1038 | ||
1039 | (define_expand "lshrhi3" | |
28987d8b | 1040 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1041 | (lshiftrt:HI (match_operand:HI 1 "general_operand") |
1042 | (match_operand:HI 2 "general_operand")))] | |
1043 | "" | |
1044 | { | |
e445e4b4 JL |
1045 | if ((GET_CODE (operands[1]) == SUBREG |
1046 | && REG_P (XEXP (operands[1], 0))) | |
1047 | || MEM_P (operands[1])) | |
3f02735b | 1048 | operands[1] = force_reg (HImode, operands[1]); |
f6a83b4a DD |
1049 | if (msp430x |
1050 | && REG_P (operands[0]) | |
1051 | && REG_P (operands[1]) | |
1052 | && CONST_INT_P (operands[2])) | |
1053 | emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2])); | |
9c8a71e6 DD |
1054 | else if (CONST_INT_P (operands[2]) |
1055 | && INTVAL (operands[2]) == 1) | |
1056 | emit_insn (gen_srli_1 (operands[0], operands[1])); | |
f6a83b4a | 1057 | else |
ec573765 | 1058 | msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size); |
f6a83b4a DD |
1059 | DONE; |
1060 | } | |
1061 | ) | |
1062 | ||
1063 | (define_insn "srli_1" | |
28987d8b | 1064 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
1065 | (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") |
1066 | (const_int 1)))] | |
1067 | "" | |
8682b1a5 | 1068 | "CLRC { RRC%X0.W\t%0" |
f6a83b4a DD |
1069 | ) |
1070 | ||
1071 | (define_insn "430x_logical_shift_right" | |
1072 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1073 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
1074 | (match_operand 2 "immediate_operand" "n")))] | |
1075 | "msp430x" | |
1076 | { | |
1077 | return msp430x_logical_shift_right (operands[2]); | |
1078 | } | |
1079 | ) | |
1080 | ||
1081 | (define_insn "srlp_1" | |
1082 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
1083 | (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") | |
1084 | (const_int 1)))] | |
1085 | "" | |
1086 | "RRUM.A #1,%0" | |
1087 | ) | |
1088 | ||
1089 | (define_insn "srll_1" | |
28987d8b | 1090 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
1091 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") |
1092 | (const_int 1)))] | |
1093 | "" | |
8682b1a5 | 1094 | "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0" |
f6a83b4a DD |
1095 | ) |
1096 | ||
1097 | (define_insn "srll_2x" | |
28987d8b | 1098 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") |
f6a83b4a DD |
1099 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") |
1100 | (const_int 2)))] | |
1101 | "msp430x" | |
1102 | "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0" | |
1103 | ) | |
1104 | ||
1105 | (define_expand "lshrsi3" | |
28987d8b | 1106 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1107 | (lshiftrt:SI (match_operand:SI 1 "general_operand") |
1108 | (match_operand:SI 2 "general_operand")))] | |
1109 | "" | |
ec573765 | 1110 | "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size); |
f6a83b4a DD |
1111 | DONE;" |
1112 | ) | |
1113 | ||
0fcc78f7 | 1114 | (define_expand "lshrdi3" |
28987d8b | 1115 | [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") |
0fcc78f7 JL |
1116 | (ashift:DI (match_operand:DI 1 "general_operand") |
1117 | (match_operand:DI 2 "general_operand")))] | |
1118 | "" | |
1119 | { | |
1120 | /* No const_variant for 64-bit shifts. */ | |
1121 | msp430_expand_helper (operands, \"__mspabi_srlll\", false); | |
1122 | DONE; | |
1123 | } | |
1124 | ) | |
1125 | ||
f6a83b4a DD |
1126 | ;;------------------------------------------------------------ |
1127 | ;; Function Entry/Exit | |
1128 | ||
1129 | (define_expand "prologue" | |
1130 | [(const_int 0)] | |
1131 | "" | |
1132 | "msp430_expand_prologue (); DONE;" | |
1133 | ) | |
1134 | ||
1135 | (define_expand "epilogue" | |
1136 | [(const_int 0)] | |
1137 | "" | |
1138 | "msp430_expand_epilogue (0); DONE;" | |
1139 | ) | |
1140 | ||
f6a83b4a | 1141 | (define_insn "epilogue_helper" |
07432a80 JL |
1142 | [(set (pc) |
1143 | (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) | |
1144 | (return)] | |
f6a83b4a | 1145 | "" |
fb28dac0 | 1146 | "BR%Q0\t#__mspabi_func_epilog_%J0" |
f6a83b4a DD |
1147 | ) |
1148 | ||
f6a83b4a DD |
1149 | (define_insn "prologue_start_marker" |
1150 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] | |
1151 | "" | |
1152 | "; start of prologue" | |
1153 | ) | |
1154 | ||
1155 | (define_insn "prologue_end_marker" | |
1156 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] | |
1157 | "" | |
1158 | "; end of prologue" | |
1159 | ) | |
1160 | ||
1161 | (define_insn "epilogue_start_marker" | |
1162 | [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] | |
1163 | "" | |
1164 | "; start of epilogue" | |
1165 | ) | |
1166 | ||
4f50b9ff DD |
1167 | ;; This makes the linker add a call to exit() after the call to main() |
1168 | ;; in crt0 | |
1169 | (define_insn "msp430_refsym_need_exit" | |
1170 | [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] | |
1171 | "" | |
1172 | ".refsym\t__crt0_call_exit" | |
1173 | ) | |
1174 | ||
f6a83b4a DD |
1175 | ;;------------------------------------------------------------ |
1176 | ;; Jumps | |
1177 | ||
1178 | (define_expand "call" | |
1179 | [(call:HI (match_operand 0 "") | |
40ada30a | 1180 | (match_operand 1 ""))] |
f6a83b4a DD |
1181 | "" |
1182 | "" | |
1183 | ) | |
1184 | ||
1185 | (define_insn "call_internal" | |
fb28dac0 | 1186 | [(call (mem:HI (match_operand 0 "general_operand" "rYci")) |
f6a83b4a DD |
1187 | (match_operand 1 ""))] |
1188 | "" | |
51ac3042 | 1189 | "CALL%Q0\t%0" |
f6a83b4a DD |
1190 | ) |
1191 | ||
1192 | (define_expand "call_value" | |
1193 | [(set (match_operand 0 "register_operand") | |
1194 | (call:HI (match_operand 1 "general_operand") | |
1195 | (match_operand 2 "")))] | |
1196 | "" | |
1197 | "" | |
1198 | ) | |
1199 | ||
1200 | (define_insn "call_value_internal" | |
1201 | [(set (match_operand 0 "register_operand" "=r") | |
fb28dac0 | 1202 | (call (mem:HI (match_operand 1 "general_operand" "rYci")) |
f6a83b4a DD |
1203 | (match_operand 2 "")))] |
1204 | "" | |
51ac3042 | 1205 | "CALL%Q0\t%1" |
f6a83b4a DD |
1206 | ) |
1207 | ||
8a896995 | 1208 | (define_insn "msp430_return" |
f6a83b4a DD |
1209 | [(return)] |
1210 | "" | |
cad055a4 | 1211 | { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } |
f6a83b4a DD |
1212 | ) |
1213 | ||
1214 | ;; This pattern is NOT, as expected, a return pattern. It's called | |
1215 | ;; before reload and must only store its operands, and emit a | |
1216 | ;; placeholder where the epilog needs to be. AFTER reload, the | |
1217 | ;; placeholder should get expanded into a regular-type epilogue that | |
1218 | ;; also does the EH return. | |
1219 | (define_expand "eh_return" | |
40ada30a | 1220 | [(match_operand:HI 0 "")] |
f6a83b4a DD |
1221 | "" |
1222 | "msp430_expand_eh_return (operands[0]); | |
1223 | emit_jump_insn (gen_msp430_eh_epilogue ()); | |
1224 | emit_barrier (); | |
1225 | DONE;" | |
1226 | ) | |
1227 | ||
1228 | ;; This is the actual EH epilogue. We emit it in the pattern above, | |
1229 | ;; before reload, and convert it to a real epilogue after reload. | |
1230 | (define_insn_and_split "msp430_eh_epilogue" | |
1231 | [(eh_return)] | |
1232 | "" | |
1233 | "#" | |
1234 | "reload_completed" | |
1235 | [(const_int 0)] | |
1236 | "msp430_expand_epilogue (1); DONE;" | |
1237 | ) | |
1238 | ||
1239 | (define_insn "jump" | |
1240 | [(set (pc) | |
1241 | (label_ref (match_operand 0 "" "")))] | |
1242 | "" | |
51ac3042 | 1243 | "BR%Q0\t#%l0" |
f6a83b4a DD |
1244 | ) |
1245 | ||
1246 | ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs | |
1247 | ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c). | |
1248 | (define_insn "indirect_jump" | |
1249 | [(set (pc) | |
1250 | (match_operand 0 "nonimmediate_operand" "rYl"))] | |
1251 | "" | |
51ac3042 | 1252 | "BR%Q0\t%0" |
f6a83b4a DD |
1253 | ) |
1254 | ||
1255 | ;;------------------------------------------------------------ | |
1256 | ;; Various Conditionals | |
1257 | ||
1258 | (define_expand "cbranch<mode>4" | |
1259 | [(parallel [(set (pc) (if_then_else | |
1260 | (match_operator 0 "" | |
6ff8ab6a | 1261 | [(match_operand:QHI 1 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1262 | (match_operand:QHI 2 "general_operand")]) |
1263 | (label_ref (match_operand 3 "" "")) | |
1264 | (pc))) | |
1265 | (clobber (reg:BI CARRY))] | |
1266 | )] | |
1267 | "" | |
1268 | "msp430_fixup_compare_operands (<MODE>mode, operands);" | |
1269 | ) | |
1270 | ||
1271 | (define_insn "cbranchpsi4_real" | |
1272 | [(set (pc) (if_then_else | |
1273 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1274 | [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm") |
f6a83b4a DD |
1275 | (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) |
1276 | (label_ref (match_operand 3 "" "")) | |
1277 | (pc))) | |
1278 | (clobber (reg:BI CARRY)) | |
1279 | ] | |
1280 | "" | |
1281 | "@ | |
51ac3042 | 1282 | CMP%Q0\t%2, %1 { J%0\t%l3 |
f6a83b4a DD |
1283 | CMPX.A\t%2, %1 { J%0\t%l3 |
1284 | CMPX.A\t%2, %1 { J%0\t%l3" | |
1285 | ) | |
1286 | ||
1287 | (define_insn "cbranchqi4_real" | |
1288 | [(set (pc) (if_then_else | |
1289 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1290 | [(match_operand:QI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm") |
8682b1a5 | 1291 | (match_operand:QI 2 "general_operand" "rYsYxi,rmi")]) |
f6a83b4a DD |
1292 | (label_ref (match_operand 3 "" "")) |
1293 | (pc))) | |
1294 | (clobber (reg:BI CARRY)) | |
1295 | ] | |
1296 | "" | |
1297 | "@ | |
1298 | CMP.B\t%2, %1 { J%0\t%l3 | |
8682b1a5 | 1299 | CMPX.B\t%2, %1 { J%0\t%l3" |
f6a83b4a DD |
1300 | ) |
1301 | ||
1302 | (define_insn "cbranchhi4_real" | |
1303 | [(set (pc) (if_then_else | |
1304 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1305 | [(match_operand:HI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm") |
8682b1a5 | 1306 | (match_operand:HI 2 "general_operand" "rYsYxi,rmi")]) |
f6a83b4a DD |
1307 | (label_ref (match_operand 3 "" "")) |
1308 | (pc))) | |
1309 | (clobber (reg:BI CARRY)) | |
1310 | ] | |
1311 | "" | |
d7edde11 NC |
1312 | "* |
1313 | /* This is nasty. If we are splitting code between low and high memory | |
1314 | then we do not want the linker to increase the size of sections by | |
1315 | relaxing out of range jump instructions. (Since relaxation occurs | |
1316 | after section placement). So we have to generate pessimal branches | |
1317 | here. But we only want to do this when really necessary. | |
1318 | ||
1319 | FIXME: Do we need code in the other cbranch patterns ? */ | |
1320 | if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6) | |
1321 | { | |
1322 | return which_alternative == 0 ? | |
1323 | \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" : | |
8682b1a5 | 1324 | \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\"; |
d7edde11 NC |
1325 | } |
1326 | ||
1327 | return which_alternative == 0 ? | |
1328 | \"CMP.W\t%2, %1 { J%0\t%l3\" : | |
8682b1a5 | 1329 | \"CMPX.W\t%2, %1 { J%0\t%l3\"; |
d7edde11 NC |
1330 | " |
1331 | [(set (attr "length") | |
1332 | (if_then_else | |
1333 | (and (ge (minus (match_dup 3) (pc)) (const_int -510)) | |
1334 | (le (minus (match_dup 3) (pc)) (const_int 510))) | |
1335 | (const_int 6) | |
1336 | (const_int 10)) | |
1337 | )] | |
f6a83b4a DD |
1338 | ) |
1339 | ||
1340 | (define_insn "cbranchpsi4_reversed" | |
1341 | [(set (pc) (if_then_else | |
1342 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1343 | [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi") | |
6ff8ab6a | 1344 | (match_operand:PSI 2 "msp430_general_dst_nonv_operand" "r,rYs,rm")]) |
f6a83b4a DD |
1345 | (label_ref (match_operand 3 "" "")) |
1346 | (pc))) | |
1347 | (clobber (reg:BI CARRY)) | |
1348 | ] | |
1349 | "" | |
1350 | "@ | |
51ac3042 | 1351 | CMP%Q0\t%1, %2 { J%R0\t%l3 |
f6a83b4a DD |
1352 | CMPX.A\t%1, %2 { J%R0\t%l3 |
1353 | CMPX.A\t%1, %2 { J%R0\t%l3" | |
1354 | ) | |
1355 | ||
1356 | (define_insn "cbranchqi4_reversed" | |
1357 | [(set (pc) (if_then_else | |
1358 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 | 1359 | [(match_operand:QI 1 "general_operand" "rYsYxi,rmi") |
6ff8ab6a | 1360 | (match_operand:QI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")]) |
f6a83b4a DD |
1361 | (label_ref (match_operand 3 "" "")) |
1362 | (pc))) | |
1363 | (clobber (reg:BI CARRY)) | |
1364 | ] | |
1365 | "" | |
1366 | "@ | |
1367 | CMP.B\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1368 | CMPX.B\t%1, %2 { J%R0\t%l3" |
f6a83b4a DD |
1369 | ) |
1370 | ||
1371 | (define_insn "cbranchhi4_reversed" | |
1372 | [(set (pc) (if_then_else | |
1373 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 | 1374 | [(match_operand:HI 1 "general_operand" "rYsYxi,rmi") |
6ff8ab6a | 1375 | (match_operand:HI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")]) |
f6a83b4a DD |
1376 | (label_ref (match_operand 3 "" "")) |
1377 | (pc))) | |
1378 | (clobber (reg:BI CARRY)) | |
1379 | ] | |
1380 | "" | |
1381 | "@ | |
1382 | CMP.W\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1383 | CMPX.W\t%1, %2 { J%R0\t%l3" |
f6a83b4a DD |
1384 | ) |
1385 | ||
f6a83b4a DD |
1386 | (define_insn "*bitbranch<mode>4" |
1387 | [(set (pc) (if_then_else | |
28987d8b | 1388 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1389 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1390 | (const_int 0)) |
1391 | (label_ref (match_operand 2 "" "")) | |
1392 | (pc))) | |
1393 | (clobber (reg:BI CARRY)) | |
1394 | ] | |
1395 | "" | |
1396 | "@ | |
51ac3042 | 1397 | BIT%x0%b0\t%1, %0 { JNE\t%l2 |
8682b1a5 | 1398 | BITX%b0\t%1, %0 { JNE\t%l2" |
f6a83b4a DD |
1399 | ) |
1400 | ||
1401 | (define_insn "*bitbranch<mode>4" | |
1402 | [(set (pc) (if_then_else | |
28987d8b | 1403 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1404 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1405 | (const_int 0)) |
1406 | (label_ref (match_operand 2 "" "")) | |
1407 | (pc))) | |
1408 | (clobber (reg:BI CARRY)) | |
1409 | ] | |
1410 | "" | |
8682b1a5 JL |
1411 | "@ |
1412 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1413 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
f6a83b4a DD |
1414 | ) |
1415 | ||
1416 | (define_insn "*bitbranch<mode>4" | |
1417 | [(set (pc) (if_then_else | |
28987d8b | 1418 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1419 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1420 | (const_int 0)) |
1421 | (pc) | |
1422 | (label_ref (match_operand 2 "" "")))) | |
1423 | (clobber (reg:BI CARRY)) | |
1424 | ] | |
1425 | "" | |
8682b1a5 JL |
1426 | "@ |
1427 | BIT%x0%b0\t%1, %0 { JNE\t%l2 | |
1428 | BITX%b0\t%1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1429 | ) |
1430 | ||
1431 | (define_insn "*bitbranch<mode>4" | |
1432 | [(set (pc) (if_then_else | |
28987d8b | 1433 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1434 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a DD |
1435 | (const_int 0)) |
1436 | (pc) | |
1437 | (label_ref (match_operand 2 "" "")))) | |
1438 | (clobber (reg:BI CARRY)) | |
1439 | ] | |
1440 | "" | |
8682b1a5 JL |
1441 | "@ |
1442 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1443 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
f6a83b4a DD |
1444 | ) |
1445 | ||
1446 | ;;------------------------------------------------------------ | |
cad055a4 | 1447 | ;; zero-extract versions of the above |
f6a83b4a DD |
1448 | |
1449 | (define_insn "*bitbranch<mode>4_z" | |
1450 | [(set (pc) (if_then_else | |
28987d8b | 1451 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm") |
f6a83b4a DD |
1452 | (const_int 1) |
1453 | (match_operand 1 "msp430_bitpos" "i,i")) | |
1454 | (const_int 0)) | |
1455 | (label_ref (match_operand 2 "" "")) | |
1456 | (pc))) | |
1457 | (clobber (reg:BI CARRY)) | |
1458 | ] | |
1459 | "" | |
1460 | "@ | |
51ac3042 NC |
1461 | BIT%x0%b0\t%p1, %0 { JNE\t%l2 |
1462 | BIT%X0%b0\t%p1, %0 { JNE\t%l2" | |
f6a83b4a DD |
1463 | ) |
1464 | ||
1465 | (define_insn "*bitbranch<mode>4_z" | |
1466 | [(set (pc) (if_then_else | |
28987d8b | 1467 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1468 | (const_int 1) |
1469 | (match_operand 1 "msp430_bitpos" "i")) | |
1470 | (const_int 0)) | |
1471 | (label_ref (match_operand 2 "" "")) | |
1472 | (pc))) | |
1473 | (clobber (reg:BI CARRY)) | |
1474 | ] | |
1475 | "" | |
8682b1a5 | 1476 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1477 | ) |
1478 | ||
1479 | (define_insn "*bitbranch<mode>4_z" | |
1480 | [(set (pc) (if_then_else | |
28987d8b | 1481 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1482 | (const_int 1) |
1483 | (match_operand 1 "msp430_bitpos" "i")) | |
1484 | (const_int 0)) | |
1485 | (pc) | |
1486 | (label_ref (match_operand 2 "" "")))) | |
1487 | (clobber (reg:BI CARRY)) | |
1488 | ] | |
1489 | "" | |
51ac3042 | 1490 | "BIT%X0%b0\t%p1, %0 { JNE\t%l2" |
f6a83b4a DD |
1491 | ) |
1492 | ||
1493 | (define_insn "*bitbranch<mode>4_z" | |
1494 | [(set (pc) (if_then_else | |
28987d8b | 1495 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a DD |
1496 | (const_int 1) |
1497 | (match_operand 1 "msp430_bitpos" "i")) | |
1498 | (const_int 0)) | |
1499 | (pc) | |
1500 | (label_ref (match_operand 2 "" "")))) | |
1501 | (clobber (reg:BI CARRY)) | |
1502 | ] | |
1503 | "" | |
51ac3042 | 1504 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
f6a83b4a DD |
1505 | ) |
1506 | ||
1507 | ;;------------------------------------------------------------ | |
1508 | ;; Misc | |
1509 | ||
1510 | (define_insn "nop" | |
1511 | [(const_int 0)] | |
1512 | "1" | |
1513 | "NOP" | |
1514 | ) | |
a005b5be | 1515 | |
cad055a4 NC |
1516 | (define_insn "disable_interrupts" |
1517 | [(unspec_volatile [(const_int 0)] UNS_DINT)] | |
1518 | "" | |
a005b5be | 1519 | "DINT \; NOP" |
cad055a4 NC |
1520 | ) |
1521 | ||
1522 | (define_insn "enable_interrupts" | |
1523 | [(unspec_volatile [(const_int 0)] UNS_EINT)] | |
1524 | "" | |
1525 | "EINT" | |
1526 | ) | |
1527 | ||
1528 | (define_insn "push_intr_state" | |
1529 | [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] | |
1530 | "" | |
1531 | "PUSH\tSR" | |
1532 | ) | |
1533 | ||
1534 | (define_insn "pop_intr_state" | |
1535 | [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] | |
1536 | "" | |
1537 | "POP\tSR" | |
1538 | ) | |
1539 | ||
1540 | ;; Clear bits in the copy of the status register that is currently | |
1541 | ;; saved on the stack at the top of the interrupt handler. | |
1542 | (define_insn "bic_SR" | |
1543 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] | |
1544 | "" | |
1545 | "BIC.W\t%0, %O0(SP)" | |
1546 | ) | |
1547 | ||
1548 | ;; Set bits in the copy of the status register that is currently | |
1549 | ;; saved on the stack at the top of the interrupt handler. | |
1550 | (define_insn "bis_SR" | |
1551 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] | |
1552 | "" | |
1553 | "BIS.W\t%0, %O0(SP)" | |
1554 | ) | |
40ada30a NC |
1555 | |
1556 | ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) | |
1557 | ;; very late on in the compilation and not splitting it into separate | |
1558 | ;; instructions, so we provide a pattern to support it here. | |
1559 | (define_insn "andneghi3" | |
1560 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1561 | (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r")) | |
1562 | (match_operand 2 "immediate_operand" "n")))] | |
1563 | "" | |
1564 | "* | |
1565 | if (REGNO (operands[0]) != REGNO (operands[1])) | |
9c5f6203 | 1566 | return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a | 1567 | else |
9c5f6203 | 1568 | return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; |
40ada30a NC |
1569 | " |
1570 | ) | |
c6f709ec | 1571 | |
5f35dde5 DD |
1572 | (define_insn "delay_cycles_start" |
1573 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1574 | UNS_DELAY_START)] | |
1575 | "" | |
1576 | "; Begin %J0 cycle delay" | |
1577 | ) | |
1578 | ||
1579 | (define_insn "delay_cycles_end" | |
1580 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1581 | UNS_DELAY_END)] | |
1582 | "" | |
1583 | "; End %J0 cycle delay" | |
1584 | ) | |
1585 | ||
1586 | (define_insn "delay_cycles_32" | |
1587 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1588 | (match_operand 1 "immediate_operand" "i") | |
1589 | ] UNS_DELAY_32)] | |
1590 | "" | |
1591 | "PUSH r13 | |
1592 | PUSH r14 | |
1593 | MOV.W %A0, r13 | |
1594 | MOV.W %B0, r14 | |
1595 | 1: SUB.W #1, r13 | |
1596 | SUBC.W #0, r14 | |
1597 | JNE 1b | |
1598 | TST.W r13 | |
1599 | JNE 1b | |
1600 | POP r14 | |
1601 | POP r13" | |
1602 | ) | |
1603 | ||
1604 | (define_insn "delay_cycles_32x" | |
1605 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1606 | (match_operand 1 "immediate_operand" "i") | |
1607 | ] UNS_DELAY_32X)] | |
1608 | "" | |
47f138d1 | 1609 | "PUSHM.A #2,r14 |
5f35dde5 DD |
1610 | MOV.W %A0, r13 |
1611 | MOV.W %B0, r14 | |
1612 | 1: SUB.W #1, r13 | |
1613 | SUBC.W #0, r14 | |
1614 | JNE 1b | |
1615 | TST.W r13 | |
1616 | JNE 1b | |
47f138d1 | 1617 | POPM.A #2,r14" |
5f35dde5 DD |
1618 | ) |
1619 | ||
1620 | (define_insn "delay_cycles_16" | |
1621 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1622 | (match_operand 1 "immediate_operand" "i") | |
1623 | ] UNS_DELAY_16)] | |
1624 | "" | |
1625 | "PUSH r13 | |
1626 | MOV.W %0, r13 | |
1627 | 1: SUB.W #1, r13 | |
1628 | JNE 1b | |
1629 | POP r13" | |
1630 | ) | |
1631 | ||
1632 | (define_insn "delay_cycles_16x" | |
1633 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1634 | (match_operand 1 "immediate_operand" "i") | |
1635 | ] UNS_DELAY_16X)] | |
1636 | "" | |
1637 | "PUSHM.A #1,r13 | |
1638 | MOV.W %0, r13 | |
1639 | 1: SUB.W #1, r13 | |
1640 | JNE 1b | |
1641 | POPM.A #1,r13" | |
1642 | ) | |
1643 | ||
1644 | (define_insn "delay_cycles_2" | |
1645 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] | |
1646 | "" | |
1647 | "JMP .+2" | |
1648 | ) | |
1649 | ||
1650 | (define_insn "delay_cycles_1" | |
1651 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] | |
1652 | "" | |
1653 | "NOP" | |
1654 | ) | |
1655 | ||
499a39af JL |
1656 | ; libgcc helper functions for widening multiplication aren't currently |
1657 | ; generated by gcc, so we can't catch them later and map them to the mspabi | |
1658 | ; functions. | |
1659 | ; We catch the patterns here and either generate a call to the helper function, | |
1660 | ; or emit the hardware multiply instruction sequence inline. | |
1661 | ; | |
1662 | ; If we don't have hardware multiply support, it will generally be slower and | |
1663 | ; result in larger code to call the mspabi library function to perform the | |
1664 | ; widening multiplication than just leaving GCC to widen the arguments itself. | |
1665 | ; | |
1666 | ; We don't use library functions for SImode->DImode widening since its always | |
1667 | ; larger and slower than letting GCC widen the arguments inline. | |
1668 | (define_expand "mulhisi3" | |
1669 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1670 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1671 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
1672 | "msp430_has_hwmult ()" | |
1673 | { | |
1674 | /* Leave the other case for the inline insn. */ | |
1675 | if (!(optimize > 2 && msp430_has_hwmult ())) | |
1676 | { | |
1677 | msp430_expand_helper (operands, "__mspabi_mpysl", false); | |
1678 | DONE; | |
1679 | } | |
1680 | } | |
1681 | ) | |
1682 | ||
1683 | (define_expand "umulhisi3" | |
1684 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1685 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1686 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
1687 | "msp430_has_hwmult ()" | |
1688 | { | |
1689 | /* Leave the other case for the inline insn. */ | |
1690 | if (!(optimize > 2 && msp430_has_hwmult ())) | |
1691 | { | |
1692 | msp430_expand_helper (operands, "__mspabi_mpyul", false); | |
1693 | DONE; | |
1694 | } | |
1695 | } | |
1696 | ) | |
1697 | ||
1698 | (define_insn "*mulhisi3_inline" | |
c6f709ec NC |
1699 | [(set (match_operand:SI 0 "register_operand" "=r") |
1700 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1701 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
0744333e | 1702 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1703 | "* |
f7961364 | 1704 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1705 | 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 | 1706 | else |
ba3cf9f1 | 1707 | 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 |
1708 | " |
1709 | ) | |
1710 | ||
499a39af | 1711 | (define_insn "*umulhisi3_inline" |
c6f709ec NC |
1712 | [(set (match_operand:SI 0 "register_operand" "=r") |
1713 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1714 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
0744333e | 1715 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1716 | "* |
f7961364 | 1717 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1718 | 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 | 1719 | else |
ba3cf9f1 | 1720 | 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 |
1721 | " |
1722 | ) | |
1723 | ||
1724 | (define_insn "mulsidi3" | |
1725 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1726 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1727 | (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
0744333e | 1728 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1729 | "* |
f7961364 | 1730 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1731 | 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 | 1732 | else |
ba3cf9f1 | 1733 | 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 |
1734 | " |
1735 | ) | |
1736 | ||
1737 | (define_insn "umulsidi3" | |
1738 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1739 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1740 | (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
0744333e | 1741 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1742 | "* |
f7961364 | 1743 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1744 | 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 | 1745 | else |
ba3cf9f1 | 1746 | 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 |
1747 | " |
1748 | ) |